diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index d7ea8e1bcc2cc..2bd067d416142 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -124,6 +124,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( borrow_set, move_data, &universal_region_relations, + &constraints, ); let mut regioncx = RegionInferenceContext::new( diff --git a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs new file mode 100644 index 0000000000000..9c4aa8ea1edb7 --- /dev/null +++ b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs @@ -0,0 +1,85 @@ +use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::{Body, Local, Location, Place}; +use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::move_paths::{LookupResult, MoveData}; +use tracing::debug; + +use crate::def_use::{self, DefUse}; +use crate::facts::AllFacts; +use crate::location::{LocationIndex, LocationTable}; +use crate::universal_regions::UniversalRegions; + +/// Emit polonius facts for variable defs, uses, drops, and path accesses. +pub(crate) fn emit_access_facts<'tcx>( + tcx: TyCtxt<'tcx>, + facts: &mut AllFacts, + body: &Body<'tcx>, + location_table: &LocationTable, + move_data: &MoveData<'tcx>, + universal_regions: &UniversalRegions<'tcx>, +) { + let mut extractor = AccessFactsExtractor { facts, move_data, location_table }; + extractor.visit_body(body); + + for (local, local_decl) in body.local_decls.iter_enumerated() { + debug!("add use_of_var_derefs_origin facts - local={:?}, type={:?}", local, local_decl.ty); + tcx.for_each_free_region(&local_decl.ty, |region| { + let region_vid = universal_regions.to_region_vid(region); + facts.use_of_var_derefs_origin.push((local, region_vid.into())); + }); + } +} + +/// MIR visitor extracting point-wise facts about accesses. +struct AccessFactsExtractor<'a, 'tcx> { + facts: &'a mut AllFacts, + move_data: &'a MoveData<'tcx>, + location_table: &'a LocationTable, +} + +impl<'tcx> AccessFactsExtractor<'_, 'tcx> { + fn location_to_index(&self, location: Location) -> LocationIndex { + self.location_table.mid_index(location) + } +} + +impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> { + fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { + match def_use::categorize(context) { + Some(DefUse::Def) => { + debug!("AccessFactsExtractor - emit def"); + self.facts.var_defined_at.push((local, self.location_to_index(location))); + } + Some(DefUse::Use) => { + debug!("AccessFactsExtractor - emit use"); + self.facts.var_used_at.push((local, self.location_to_index(location))); + } + Some(DefUse::Drop) => { + debug!("AccessFactsExtractor - emit drop"); + self.facts.var_dropped_at.push((local, self.location_to_index(location))); + } + _ => (), + } + } + + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { + self.super_place(place, context, location); + + match context { + PlaceContext::NonMutatingUse(_) + | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => { + let path = match self.move_data.rev_lookup.find(place.as_ref()) { + LookupResult::Exact(path) | LookupResult::Parent(Some(path)) => path, + _ => { + // There's no path access to emit. + return; + } + }; + debug!("AccessFactsExtractor - emit path access ({path:?}, {location:?})"); + self.facts.path_accessed_at_base.push((path, self.location_to_index(location))); + } + + _ => {} + } + } +} diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index f646beeecf7b3..0d5b6f3a2c8c2 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -21,22 +21,22 @@ use crate::{ /// Emit `loan_invalidated_at` facts. pub(super) fn emit_loan_invalidations<'tcx>( tcx: TyCtxt<'tcx>, - all_facts: &mut AllFacts, - location_table: &LocationTable, + facts: &mut AllFacts, body: &Body<'tcx>, + location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, ) { let dominators = body.basic_blocks.dominators(); let mut visitor = - LoanInvalidationsGenerator { all_facts, borrow_set, tcx, location_table, body, dominators }; + LoanInvalidationsGenerator { facts, borrow_set, tcx, location_table, body, dominators }; visitor.visit_body(body); } struct LoanInvalidationsGenerator<'a, 'tcx> { tcx: TyCtxt<'tcx>, - all_facts: &'a mut AllFacts, - location_table: &'a LocationTable, + facts: &'a mut AllFacts, body: &'a Body<'tcx>, + location_table: &'a LocationTable, dominators: &'a Dominators, borrow_set: &'a BorrowSet<'tcx>, } @@ -151,7 +151,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { let resume = self.location_table.start_index(resume.start_location()); for (i, data) in borrow_set.iter_enumerated() { if borrow_of_local_data(data.borrowed_place) { - self.all_facts.loan_invalidated_at.push((resume, i)); + self.facts.loan_invalidated_at.push((resume, i)); } } @@ -165,7 +165,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { let start = self.location_table.start_index(location); for (i, data) in borrow_set.iter_enumerated() { if borrow_of_local_data(data.borrowed_place) { - self.all_facts.loan_invalidated_at.push((start, i)); + self.facts.loan_invalidated_at.push((start, i)); } } } @@ -409,7 +409,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { /// Generates a new `loan_invalidated_at(L, B)` fact. fn emit_loan_invalidated_at(&mut self, b: BorrowIndex, l: Location) { let lidx = self.location_table.start_index(l); - self.all_facts.loan_invalidated_at.push((lidx, b)); + self.facts.loan_invalidated_at.push((lidx, b)); } fn check_activations(&mut self, location: Location) { diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs index 68e0865ab82c9..fdde9fa047621 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs @@ -14,12 +14,12 @@ use crate::places_conflict; /// Emit `loan_killed_at` and `cfg_edge` facts at the same time. pub(super) fn emit_loan_kills<'tcx>( tcx: TyCtxt<'tcx>, - all_facts: &mut AllFacts, - location_table: &LocationTable, + facts: &mut AllFacts, body: &Body<'tcx>, + location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, ) { - let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, all_facts, body }; + let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, facts, body }; for (bb, data) in body.basic_blocks.iter_enumerated() { visitor.visit_basic_block_data(bb, data); } @@ -27,7 +27,7 @@ pub(super) fn emit_loan_kills<'tcx>( struct LoanKillsGenerator<'a, 'tcx> { tcx: TyCtxt<'tcx>, - all_facts: &'a mut AllFacts, + facts: &'a mut AllFacts, location_table: &'a LocationTable, borrow_set: &'a BorrowSet<'tcx>, body: &'a Body<'tcx>, @@ -36,12 +36,12 @@ struct LoanKillsGenerator<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'a, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { // Also record CFG facts here. - self.all_facts.cfg_edge.push(( + self.facts.cfg_edge.push(( self.location_table.start_index(location), self.location_table.mid_index(location), )); - self.all_facts.cfg_edge.push(( + self.facts.cfg_edge.push(( self.location_table.mid_index(location), self.location_table.start_index(location.successor_within_block()), )); @@ -63,15 +63,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'a, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { // Also record CFG facts here. - self.all_facts.cfg_edge.push(( + self.facts.cfg_edge.push(( self.location_table.start_index(location), self.location_table.mid_index(location), )); let successor_blocks = terminator.successors(); - self.all_facts.cfg_edge.reserve(successor_blocks.size_hint().0); + self.facts.cfg_edge.reserve(successor_blocks.size_hint().0); for successor_block in successor_blocks { - self.all_facts.cfg_edge.push(( + self.facts.cfg_edge.push(( self.location_table.mid_index(location), self.location_table.start_index(successor_block.start_location()), )); @@ -128,7 +128,7 @@ impl<'tcx> LoanKillsGenerator<'_, 'tcx> { if places_conflict { let location_index = self.location_table.mid_index(location); - self.all_facts.loan_killed_at.push((borrow_index, location_index)); + self.facts.loan_killed_at.push((borrow_index, location_index)); } } } @@ -140,9 +140,9 @@ impl<'tcx> LoanKillsGenerator<'_, 'tcx> { fn record_killed_borrows_for_local(&mut self, local: Local, location: Location) { if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { let location_index = self.location_table.mid_index(location); - self.all_facts.loan_killed_at.reserve(borrow_indices.len()); + self.facts.loan_killed_at.reserve(borrow_indices.len()); for &borrow_index in borrow_indices { - self.all_facts.loan_killed_at.push((borrow_index, location_index)); + self.facts.loan_killed_at.push((borrow_index, location_index)); } } } diff --git a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs index 9fccc00bdaf0e..60fd2afe63e1c 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs @@ -3,16 +3,23 @@ //! Will be removed in the future, once the in-tree `-Zpolonius=next` implementation reaches feature //! parity. -use rustc_middle::mir::{Body, LocalKind, Location, START_BLOCK}; -use rustc_middle::ty::TyCtxt; +use std::iter; + +use either::Either; +use rustc_middle::mir::{Body, Local, LocalKind, Location, START_BLOCK}; +use rustc_middle::ty::{GenericArg, TyCtxt}; use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData}; use tracing::debug; use crate::borrow_set::BorrowSet; +use crate::constraints::OutlivesConstraint; use crate::facts::{AllFacts, PoloniusRegionVid}; use crate::location::LocationTable; +use crate::type_check::MirTypeckRegionConstraints; use crate::type_check::free_region_relations::UniversalRegionRelations; +use crate::universal_regions::UniversalRegions; +mod accesses; mod loan_invalidations; mod loan_kills; @@ -22,6 +29,8 @@ mod loan_kills; /// - CFG points and edges /// - loan kills /// - loan invalidations +/// - access facts such as variable definitions, uses, drops, and path accesses +/// - outlives constraints /// /// The rest of the facts are emitted during typeck and liveness. pub(crate) fn emit_facts<'tcx>( @@ -30,34 +39,42 @@ pub(crate) fn emit_facts<'tcx>( location_table: &LocationTable, body: &Body<'tcx>, borrow_set: &BorrowSet<'tcx>, - move_data: &MoveData<'_>, - universal_region_relations: &UniversalRegionRelations<'_>, + move_data: &MoveData<'tcx>, + universal_region_relations: &UniversalRegionRelations<'tcx>, + constraints: &MirTypeckRegionConstraints<'tcx>, ) { - let Some(all_facts) = all_facts else { + let Some(facts) = all_facts else { // We don't do anything if there are no facts to fill. return; }; let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); - emit_move_facts(all_facts, move_data, location_table, body); - emit_universal_region_facts(all_facts, borrow_set, universal_region_relations); - emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set); - emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set); + emit_move_facts(facts, body, location_table, move_data); + emit_universal_region_facts(facts, borrow_set, universal_region_relations); + loan_kills::emit_loan_kills(tcx, facts, body, location_table, borrow_set); + loan_invalidations::emit_loan_invalidations(tcx, facts, body, location_table, borrow_set); + accesses::emit_access_facts( + tcx, + facts, + body, + location_table, + move_data, + &universal_region_relations.universal_regions, + ); + emit_outlives_facts(facts, location_table, constraints); } /// Emit facts needed for move/init analysis: moves and assignments. fn emit_move_facts( - all_facts: &mut AllFacts, - move_data: &MoveData<'_>, - location_table: &LocationTable, + facts: &mut AllFacts, body: &Body<'_>, + location_table: &LocationTable, + move_data: &MoveData<'_>, ) { - all_facts - .path_is_var - .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l))); + facts.path_is_var.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l))); for (child, move_path) in move_data.move_paths.iter_enumerated() { if let Some(parent) = move_path.parent { - all_facts.child_path.push((child, parent)); + facts.child_path.push((child, parent)); } } @@ -83,14 +100,14 @@ fn emit_move_facts( // The initialization happened in (or rather, when arriving at) // the successors, but not in the unwind block. let first_statement = Location { block: successor, statement_index: 0 }; - all_facts + facts .path_assigned_at_base .push((init.path, location_table.start_index(first_statement))); } } else { // In all other cases, the initialization just happens at the // midpoint, like any other effect. - all_facts + facts .path_assigned_at_base .push((init.path, location_table.mid_index(location))); } @@ -98,7 +115,7 @@ fn emit_move_facts( // Arguments are initialized on function entry InitLocation::Argument(local) => { assert!(body.local_kind(local) == LocalKind::Arg); - all_facts.path_assigned_at_base.push((init.path, fn_entry_start)); + facts.path_assigned_at_base.push((init.path, fn_entry_start)); } } } @@ -107,20 +124,20 @@ fn emit_move_facts( if body.local_kind(local) != LocalKind::Arg { // Non-arguments start out deinitialised; we simulate this with an // initial move: - all_facts.path_moved_at_base.push((path, fn_entry_start)); + facts.path_moved_at_base.push((path, fn_entry_start)); } } // moved_out_at // deinitialisation is assumed to always happen! - all_facts + facts .path_moved_at_base .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source)))); } /// Emit universal regions facts, and their relations. fn emit_universal_region_facts( - all_facts: &mut AllFacts, + facts: &mut AllFacts, borrow_set: &BorrowSet<'_>, universal_region_relations: &UniversalRegionRelations<'_>, ) { @@ -131,7 +148,7 @@ fn emit_universal_region_facts( // added to the existing number of loans, as if they succeeded them in the set. // let universal_regions = &universal_region_relations.universal_regions; - all_facts + facts .universal_region .extend(universal_regions.universal_regions_iter().map(PoloniusRegionVid::from)); let borrow_count = borrow_set.len(); @@ -144,7 +161,7 @@ fn emit_universal_region_facts( for universal_region in universal_regions.universal_regions_iter() { let universal_region_idx = universal_region.index(); let placeholder_loan_idx = borrow_count + universal_region_idx; - all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into())); + facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into())); } // 2: the universal region relations `outlives` constraints are emitted as @@ -156,29 +173,51 @@ fn emit_universal_region_facts( fr1={:?}, fr2={:?}", fr1, fr2 ); - all_facts.known_placeholder_subset.push((fr1.into(), fr2.into())); + facts.known_placeholder_subset.push((fr1.into(), fr2.into())); } } } -/// Emit facts about loan invalidations. -fn emit_loan_invalidations_facts<'tcx>( - all_facts: &mut AllFacts, +/// For every potentially drop()-touched region `region` in `local`'s type +/// (`kind`), emit a `drop_of_var_derefs_origin(local, origin)` fact. +pub(crate) fn emit_drop_facts<'tcx>( tcx: TyCtxt<'tcx>, - location_table: &LocationTable, - body: &Body<'tcx>, - borrow_set: &BorrowSet<'tcx>, + local: Local, + kind: &GenericArg<'tcx>, + universal_regions: &UniversalRegions<'tcx>, + all_facts: &mut Option, ) { - loan_invalidations::emit_loan_invalidations(tcx, all_facts, location_table, body, borrow_set); + debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind); + let Some(facts) = all_facts.as_mut() else { return }; + let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); + tcx.for_each_free_region(kind, |drop_live_region| { + let region_vid = universal_regions.to_region_vid(drop_live_region); + facts.drop_of_var_derefs_origin.push((local, region_vid.into())); + }); } -/// Emit facts about CFG points and edges, as well as locations where loans are killed. -fn emit_cfg_and_loan_kills_facts<'tcx>( - all_facts: &mut AllFacts, - tcx: TyCtxt<'tcx>, +/// Emit facts about the outlives constraints: the `subset` base relation, i.e. not a transitive +/// closure. +fn emit_outlives_facts<'tcx>( + facts: &mut AllFacts, location_table: &LocationTable, - body: &Body<'tcx>, - borrow_set: &BorrowSet<'tcx>, + constraints: &MirTypeckRegionConstraints<'tcx>, ) { - loan_kills::emit_loan_kills(tcx, all_facts, location_table, body, borrow_set); + facts.subset_base.extend(constraints.outlives_constraints.outlives().iter().flat_map( + |constraint: &OutlivesConstraint<'_>| { + if let Some(from_location) = constraint.locations.from_location() { + Either::Left(iter::once(( + constraint.sup.into(), + constraint.sub.into(), + location_table.mid_index(from_location), + ))) + } else { + Either::Right( + location_table.all_points().map(move |location| { + (constraint.sup.into(), constraint.sub.into(), location) + }), + ) + } + }, + )); } diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index 05e4a176a6d19..683293bf82863 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -17,7 +17,6 @@ use crate::region_infer::values::LivenessValues; use crate::universal_regions::UniversalRegions; mod local_use_map; -mod polonius; mod trace; /// Combines liveness analysis with initialization analysis to @@ -45,8 +44,6 @@ pub(super) fn generate<'a, 'tcx>( let (relevant_live_locals, boring_locals) = compute_relevant_live_locals(typeck.tcx(), &free_regions, body); - polonius::emit_access_facts(typeck, body, move_data); - trace::trace( typeck, body, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs deleted file mode 100644 index 5ffba94ee6821..0000000000000 --- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs +++ /dev/null @@ -1,123 +0,0 @@ -use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location, Place}; -use rustc_middle::ty::GenericArg; -use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; -use tracing::debug; - -use super::TypeChecker; -use crate::def_use::{self, DefUse}; -use crate::location::{LocationIndex, LocationTable}; - -type VarPointRelation = Vec<(Local, LocationIndex)>; -type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>; - -/// Emit polonius facts for variable defs, uses, drops, and path accesses. -pub(super) fn emit_access_facts<'a, 'tcx>( - typeck: &mut TypeChecker<'a, 'tcx>, - body: &Body<'tcx>, - move_data: &MoveData<'tcx>, -) { - if let Some(facts) = typeck.all_facts.as_mut() { - debug!("emit_access_facts()"); - - let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - let location_table = typeck.location_table; - - let mut extractor = AccessFactsExtractor { - var_defined_at: &mut facts.var_defined_at, - var_used_at: &mut facts.var_used_at, - var_dropped_at: &mut facts.var_dropped_at, - path_accessed_at_base: &mut facts.path_accessed_at_base, - location_table, - move_data, - }; - extractor.visit_body(body); - - for (local, local_decl) in body.local_decls.iter_enumerated() { - debug!( - "add use_of_var_derefs_origin facts - local={:?}, type={:?}", - local, local_decl.ty - ); - let universal_regions = &typeck.universal_regions; - typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| { - let region_vid = universal_regions.to_region_vid(region); - facts.use_of_var_derefs_origin.push((local, region_vid.into())); - }); - } - } -} - -/// For every potentially drop()-touched region `region` in `local`'s type -/// (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact. -pub(super) fn emit_drop_facts<'tcx>( - typeck: &mut TypeChecker<'_, 'tcx>, - local: Local, - kind: &GenericArg<'tcx>, -) { - debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind); - if let Some(facts) = typeck.all_facts.as_mut() { - let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - let universal_regions = &typeck.universal_regions; - typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| { - let region_vid = universal_regions.to_region_vid(drop_live_region); - facts.drop_of_var_derefs_origin.push((local, region_vid.into())); - }); - } -} - -/// MIR visitor extracting point-wise facts about accesses. -struct AccessFactsExtractor<'a, 'tcx> { - var_defined_at: &'a mut VarPointRelation, - var_used_at: &'a mut VarPointRelation, - location_table: &'a LocationTable, - var_dropped_at: &'a mut VarPointRelation, - move_data: &'a MoveData<'tcx>, - path_accessed_at_base: &'a mut PathPointRelation, -} - -impl<'tcx> AccessFactsExtractor<'_, 'tcx> { - fn location_to_index(&self, location: Location) -> LocationIndex { - self.location_table.mid_index(location) - } -} - -impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> { - fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { - match def_use::categorize(context) { - Some(DefUse::Def) => { - debug!("AccessFactsExtractor - emit def"); - self.var_defined_at.push((local, self.location_to_index(location))); - } - Some(DefUse::Use) => { - debug!("AccessFactsExtractor - emit use"); - self.var_used_at.push((local, self.location_to_index(location))); - } - Some(DefUse::Drop) => { - debug!("AccessFactsExtractor - emit drop"); - self.var_dropped_at.push((local, self.location_to_index(location))); - } - _ => (), - } - } - - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { - self.super_place(place, context, location); - - match context { - PlaceContext::NonMutatingUse(_) - | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => { - let path = match self.move_data.rev_lookup.find(place.as_ref()) { - LookupResult::Exact(path) | LookupResult::Parent(Some(path)) => path, - _ => { - // There's no path access to emit. - return; - } - }; - debug!("AccessFactsExtractor - emit path access ({path:?}, {location:?})"); - self.path_accessed_at_base.push((path, self.location_to_index(location))); - } - - _ => {} - } - } -} diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 539d3f97a6387..f510d193dd9f1 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -15,9 +15,9 @@ use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOp, Type use tracing::debug; use crate::location::RichLocation; +use crate::polonius; use crate::region_infer::values::{self, LiveLoans}; use crate::type_check::liveness::local_use_map::LocalUseMap; -use crate::type_check::liveness::polonius; use crate::type_check::{NormalizeLocation, TypeChecker}; /// This is the heart of the liveness computation. For each variable X @@ -590,7 +590,13 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { // the destructor and must be live at this point. for &kind in &drop_data.dropck_result.kinds { Self::make_all_regions_live(self.elements, self.typeck, kind, live_at); - polonius::emit_drop_facts(self.typeck, dropped_local, &kind); + polonius::legacy::emit_drop_facts( + self.typeck.tcx(), + dropped_local, + &kind, + self.typeck.universal_regions, + self.typeck.all_facts, + ); } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 90d327b0ad20d..de0804b01895a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -3,7 +3,6 @@ use std::rc::Rc; use std::{fmt, iter, mem}; -use either::Either; use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -107,7 +106,6 @@ mod relate_tys; /// # Parameters /// /// - `infcx` -- inference context to use -/// - `param_env` -- parameter environment to use for trait solving /// - `body` -- MIR body to type-check /// - `promoted` -- map of promoted constants within `body` /// - `universal_regions` -- the universal regions from `body`s function signature @@ -155,7 +153,7 @@ pub(crate) fn type_check<'a, 'tcx>( debug!(?normalized_inputs_and_output); - let mut checker = TypeChecker { + let mut typeck = TypeChecker { infcx, last_span: body.span, body, @@ -171,24 +169,22 @@ pub(crate) fn type_check<'a, 'tcx>( constraints: &mut constraints, }; - checker.check_user_type_annotations(); + typeck.check_user_type_annotations(); - let mut verifier = TypeVerifier { cx: &mut checker, promoted, last_span: body.span }; + let mut verifier = TypeVerifier { typeck: &mut typeck, promoted, last_span: body.span }; verifier.visit_body(body); - checker.typeck_mir(body); - checker.equate_inputs_and_outputs(body, &normalized_inputs_and_output); - checker.check_signature_annotation(body); + typeck.typeck_mir(body); + typeck.equate_inputs_and_outputs(body, &normalized_inputs_and_output); + typeck.check_signature_annotation(body); - liveness::generate(&mut checker, body, &elements, flow_inits, move_data); + liveness::generate(&mut typeck, body, &elements, flow_inits, move_data); - translate_outlives_facts(&mut checker); - let opaque_type_values = infcx.take_opaque_types(); - - let opaque_type_values = opaque_type_values + let opaque_type_values = infcx + .take_opaque_types() .into_iter() .map(|(opaque_type_key, decl)| { - let _: Result<_, ErrorGuaranteed> = checker.fully_perform_op( + let _: Result<_, ErrorGuaranteed> = typeck.fully_perform_op( Locations::All(body.span), ConstraintCategory::OpaqueType, CustomTypeOp::new( @@ -218,11 +214,11 @@ pub(crate) fn type_check<'a, 'tcx>( match region.kind() { ty::ReVar(_) => region, ty::RePlaceholder(placeholder) => { - checker.constraints.placeholder_region(infcx, placeholder) + typeck.constraints.placeholder_region(infcx, placeholder) } _ => ty::Region::new_var( infcx.tcx, - checker.universal_regions.to_region_vid(region), + typeck.universal_regions.to_region_vid(region), ), } }); @@ -234,30 +230,6 @@ pub(crate) fn type_check<'a, 'tcx>( MirTypeckResults { constraints, universal_region_relations, opaque_type_values } } -fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { - if let Some(facts) = typeck.all_facts { - let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - let location_table = typeck.location_table; - facts.subset_base.extend( - typeck.constraints.outlives_constraints.outlives().iter().flat_map( - |constraint: &OutlivesConstraint<'_>| { - if let Some(from_location) = constraint.locations.from_location() { - Either::Left(iter::once(( - constraint.sup.into(), - constraint.sub.into(), - location_table.mid_index(from_location), - ))) - } else { - Either::Right(location_table.all_points().map(move |location| { - (constraint.sup.into(), constraint.sub.into(), location) - })) - } - }, - ), - ); - } -} - #[track_caller] fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: String) { // We sometimes see MIR failures (notably predicate failures) due to @@ -276,7 +248,7 @@ enum FieldAccessError { /// type, calling `span_mirbug` and returning an error type if there /// is a problem. struct TypeVerifier<'a, 'b, 'tcx> { - cx: &'a mut TypeChecker<'b, 'tcx>, + typeck: &'a mut TypeChecker<'b, 'tcx>, promoted: &'b IndexSlice>, last_span: Span, } @@ -298,9 +270,9 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { self.super_const_operand(constant, location); let ty = self.sanitize_type(constant, constant.const_.ty()); - self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { - let live_region_vid = self.cx.universal_regions.to_region_vid(live_region); - self.cx.constraints.liveness_constraints.add_location(live_region_vid, location); + self.typeck.infcx.tcx.for_each_free_region(&ty, |live_region| { + let live_region_vid = self.typeck.universal_regions.to_region_vid(live_region); + self.typeck.constraints.liveness_constraints.add_location(live_region_vid, location); }); // HACK(compiler-errors): Constants that are gathered into Body.required_consts @@ -312,14 +284,14 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { }; if let Some(annotation_index) = constant.user_ty { - if let Err(terr) = self.cx.relate_type_and_user_type( + if let Err(terr) = self.typeck.relate_type_and_user_type( constant.const_.ty(), ty::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, locations, ConstraintCategory::Boring, ) { - let annotation = &self.cx.user_type_annotations[annotation_index]; + let annotation = &self.typeck.user_type_annotations[annotation_index]; span_mirbug!( self, constant, @@ -348,9 +320,12 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { promoted: &Body<'tcx>, ty, san_ty| { - if let Err(terr) = - verifier.cx.eq_types(ty, san_ty, locations, ConstraintCategory::Boring) - { + if let Err(terr) = verifier.typeck.eq_types( + ty, + san_ty, + locations, + ConstraintCategory::Boring, + ) { span_mirbug!( verifier, promoted, @@ -368,21 +343,21 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { let promoted_ty = promoted_body.return_ty(); check_err(self, promoted_body, ty, promoted_ty); } else { - self.cx.ascribe_user_type( + self.typeck.ascribe_user_type( constant.const_.ty(), ty::UserType::new(ty::UserTypeKind::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None, })), - locations.span(self.cx.body), + locations.span(self.typeck.body), ); } } 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 normalized_ty = self.typeck.normalize(unnormalized_ty, locations); let literal_ty = constant.const_.ty().builtin_deref(true).unwrap(); - if let Err(terr) = self.cx.eq_types( + if let Err(terr) = self.typeck.eq_types( literal_ty, normalized_ty, locations, @@ -394,7 +369,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args); - self.cx.normalize_and_prove_instantiated_predicates( + self.typeck.normalize_and_prove_instantiated_predicates( def_id, instantiated_predicates, locations, @@ -404,7 +379,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { tcx.impl_of_method(def_id).map(|imp| tcx.def_kind(imp)), Some(DefKind::Impl { of_trait: true }) )); - self.cx.prove_predicates( + self.typeck.prove_predicates( args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())), locations, ConstraintCategory::Boring, @@ -438,7 +413,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { local_decl.ty }; - if let Err(terr) = self.cx.relate_type_and_user_type( + if let Err(terr) = self.typeck.relate_type_and_user_type( ty, ty::Invariant, user_ty, @@ -468,11 +443,11 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { fn body(&self) -> &Body<'tcx> { - self.cx.body + self.typeck.body } fn tcx(&self) -> TyCtxt<'tcx> { - self.cx.infcx.tcx + self.typeck.infcx.tcx } fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -522,7 +497,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // whether the bounds fully apply: in effect, the rule is // that if a value of some type could implement `Copy`, then // it must. - self.cx.prove_trait_ref( + self.typeck.prove_trait_ref( trait_ref, location.to_locations(), ConstraintCategory::CopyBound, @@ -537,7 +512,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // checker on the promoted MIR, then transfer the constraints back to // the main MIR, changing the locations to the provided location. - let parent_body = mem::replace(&mut self.cx.body, promoted_body); + let parent_body = mem::replace(&mut self.typeck.body, promoted_body); // Use new sets of constraints and closure bounds so that we can // modify their locations. @@ -548,18 +523,18 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // Don't try to add borrow_region facts for the promoted MIR let mut swap_constraints = |this: &mut Self| { - mem::swap(this.cx.all_facts, all_facts); - mem::swap(&mut this.cx.constraints.outlives_constraints, &mut constraints); - mem::swap(&mut this.cx.constraints.liveness_constraints, &mut liveness_constraints); + mem::swap(this.typeck.all_facts, all_facts); + mem::swap(&mut this.typeck.constraints.outlives_constraints, &mut constraints); + mem::swap(&mut this.typeck.constraints.liveness_constraints, &mut liveness_constraints); }; swap_constraints(self); self.visit_body(promoted_body); - self.cx.typeck_mir(promoted_body); + self.typeck.typeck_mir(promoted_body); - self.cx.body = parent_body; + self.typeck.body = parent_body; // Merge the outlives constraints back in, at the given location. swap_constraints(self); @@ -575,7 +550,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // temporary from the user's point of view. constraint.category = ConstraintCategory::Boring; } - self.cx.constraints.outlives_constraints.push(constraint) + self.typeck.constraints.outlives_constraints.push(constraint) } // If the region is live at least one location in the promoted MIR, // then add a liveness constraint to the main MIR for this region @@ -585,7 +560,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // unordered. #[allow(rustc::potential_query_instability)] for region in liveness_constraints.live_regions_unordered() { - self.cx.constraints.liveness_constraints.add_location(region, location); + self.typeck.constraints.liveness_constraints.add_location(region, location); } } @@ -669,13 +644,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { }, ProjectionElem::Field(field, fty) => { let fty = self.sanitize_type(place, fty); - let fty = self.cx.normalize(fty, location); + let fty = self.typeck.normalize(fty, location); match self.field_ty(place, base, field, location) { Ok(ty) => { - let ty = self.cx.normalize(ty, location); + let ty = self.typeck.normalize(ty, location); debug!(?fty, ?ty); - if let Err(terr) = self.cx.relate_types( + if let Err(terr) = self.typeck.relate_types( ty, self.get_ambient_variance(context), fty, @@ -707,8 +682,8 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } ProjectionElem::OpaqueCast(ty) => { let ty = self.sanitize_type(place, ty); - let ty = self.cx.normalize(ty, location); - self.cx + let ty = self.typeck.normalize(ty, location); + self.typeck .relate_types( ty, self.get_ambient_variance(context), @@ -817,7 +792,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { }; if let Some(field) = variant.fields.get(field) { - Ok(self.cx.normalize(field.ty(tcx, args), location)) + Ok(self.typeck.normalize(field.ty(tcx, args), location)) } else { Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs deleted file mode 100644 index c5d1ebdfe7c5f..0000000000000 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ /dev/null @@ -1,84 +0,0 @@ -use rustc_data_structures::captures::Captures; -use rustc_middle::mir::coverage::{ - CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, MappingKind, Op, - SourceRegion, -}; - -use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind}; - -pub(crate) struct FunctionCoverage<'tcx> { - pub(crate) function_coverage_info: &'tcx FunctionCoverageInfo, - /// If `None`, the corresponding function is unused. - ids_info: Option<&'tcx CoverageIdsInfo>, -} - -impl<'tcx> FunctionCoverage<'tcx> { - pub(crate) fn new_used( - function_coverage_info: &'tcx FunctionCoverageInfo, - ids_info: &'tcx CoverageIdsInfo, - ) -> Self { - Self { function_coverage_info, ids_info: Some(ids_info) } - } - - pub(crate) fn new_unused(function_coverage_info: &'tcx FunctionCoverageInfo) -> Self { - Self { function_coverage_info, ids_info: None } - } - - /// Returns true for a used (called) function, and false for an unused function. - pub(crate) fn is_used(&self) -> bool { - self.ids_info.is_some() - } - - /// Return the source hash, generated from the HIR node structure, and used to indicate whether - /// or not the source code structure changed between different compilations. - pub(crate) fn source_hash(&self) -> u64 { - if self.is_used() { self.function_coverage_info.function_source_hash } else { 0 } - } - - /// Convert this function's coverage expression data into a form that can be - /// passed through FFI to LLVM. - pub(crate) fn counter_expressions( - &self, - ) -> impl Iterator + ExactSizeIterator + Captures<'_> { - // We know that LLVM will optimize out any unused expressions before - // producing the final coverage map, so there's no need to do the same - // thing on the Rust side unless we're confident we can do much better. - // (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.) - - self.function_coverage_info.expressions.iter().map(move |&Expression { lhs, op, rhs }| { - CounterExpression { - lhs: self.counter_for_term(lhs), - kind: match op { - Op::Add => ExprKind::Add, - Op::Subtract => ExprKind::Subtract, - }, - rhs: self.counter_for_term(rhs), - } - }) - } - - /// Converts this function's coverage mappings into an intermediate form - /// that will be used by `mapgen` when preparing for FFI. - pub(crate) fn counter_regions( - &self, - ) -> impl Iterator + ExactSizeIterator { - self.function_coverage_info.mappings.iter().map(move |mapping| { - let Mapping { kind, source_region } = mapping; - let kind = - kind.map_terms(|term| if self.is_zero_term(term) { CovTerm::Zero } else { term }); - (kind, source_region) - }) - } - - fn counter_for_term(&self, term: CovTerm) -> Counter { - if self.is_zero_term(term) { Counter::ZERO } else { Counter::from_term(term) } - } - - fn is_zero_term(&self, term: CovTerm) -> bool { - match self.ids_info { - Some(ids_info) => ids_info.is_zero_term(term), - // This function is unused, so all coverage counters/expressions are zero. - None => true, - } - } -} diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 4f2af73252751..ca33428620052 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -1,6 +1,6 @@ use std::iter; -use itertools::Itertools as _; +use itertools::Itertools; use rustc_abi::Align; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, @@ -8,8 +8,8 @@ use rustc_codegen_ssa::traits::{ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::IndexVec; +use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; -use rustc_middle::{bug, mir}; use rustc_session::RemapFileNameExt; use rustc_session::config::RemapPathScopeComponents; use rustc_span::def_id::DefIdSet; @@ -18,7 +18,6 @@ use tracing::debug; use crate::common::CodegenCx; use crate::coverageinfo::llvm_cov; -use crate::coverageinfo::map_data::FunctionCoverage; use crate::coverageinfo::mapgen::covfun::prepare_covfun_record; use crate::llvm; @@ -49,46 +48,40 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name()); - // In order to show that unused functions have coverage counts of zero (0), LLVM requires the - // functions exist. Generate synthetic functions with a (required) single counter, and add the - // MIR `Coverage` code regions to the `function_coverage_map`, before calling - // `ctx.take_function_coverage_map()`. - if cx.codegen_unit.is_code_coverage_dead_code_cgu() { - add_unused_functions(cx); - } - // FIXME(#132395): Can this be none even when coverage is enabled? - let function_coverage_map = match cx.coverage_cx { - Some(ref cx) => cx.take_function_coverage_map(), + let instances_used = match cx.coverage_cx { + Some(ref cx) => cx.instances_used.borrow(), None => return, }; - if function_coverage_map.is_empty() { - // This CGU has no functions with coverage instrumentation. - return; - } - let all_file_names = function_coverage_map - .iter() - .map(|(_, fn_cov)| fn_cov.function_coverage_info.body_span) - .map(|span| span_file_name(tcx, span)); - let global_file_table = GlobalFileTable::new(all_file_names); + // The order of entries in this global file table needs to be deterministic, + // and ideally should also be independent of the details of stable-hashing, + // because coverage tests snapshots (`.cov-map`) can observe the order and + // would need to be re-blessed if it changes. As long as those requirements + // are satisfied, the order can be arbitrary. + let mut global_file_table = GlobalFileTable::new(); - // Encode all filenames referenced by coverage mappings in this CGU. - let filenames_buffer = global_file_table.make_filenames_buffer(tcx); - // The `llvm-cov` tool uses this hash to associate each covfun record with - // its corresponding filenames table, since the final binary will typically - // contain multiple covmap records from different compilation units. - let filenames_hash = llvm_cov::hash_bytes(&filenames_buffer); - - let mut unused_function_names = Vec::new(); - - let covfun_records = function_coverage_map - .into_iter() - .filter_map(|(instance, function_coverage)| { - prepare_covfun_record(tcx, &global_file_table, instance, &function_coverage) - }) + let mut covfun_records = instances_used + .iter() + .copied() + // Sort by symbol name, so that the global file table is built in an + // order that doesn't depend on the stable-hash-based order in which + // instances were visited during codegen. + .sorted_by_cached_key(|&instance| tcx.symbol_name(instance).name) + .filter_map(|instance| prepare_covfun_record(tcx, &mut global_file_table, instance, true)) .collect::>(); + // In a single designated CGU, also prepare covfun records for functions + // in this crate that were instrumented for coverage, but are unused. + if cx.codegen_unit.is_code_coverage_dead_code_cgu() { + let mut unused_instances = gather_unused_function_instances(cx); + // Sort the unused instances by symbol name, for the same reason as the used ones. + unused_instances.sort_by_cached_key(|&instance| tcx.symbol_name(instance).name); + covfun_records.extend(unused_instances.into_iter().filter_map(|instance| { + prepare_covfun_record(tcx, &mut global_file_table, instance, false) + })); + } + // If there are no covfun records for this CGU, don't generate a covmap record. // Emitting a covmap record without any covfun records causes `llvm-cov` to // fail when generating coverage reports, and if there are no covfun records @@ -98,6 +91,15 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { return; } + // Encode all filenames referenced by coverage mappings in this CGU. + let filenames_buffer = global_file_table.make_filenames_buffer(tcx); + // The `llvm-cov` tool uses this hash to associate each covfun record with + // its corresponding filenames table, since the final binary will typically + // contain multiple covmap records from different compilation units. + let filenames_hash = llvm_cov::hash_bytes(&filenames_buffer); + + let mut unused_function_names = vec![]; + for covfun in &covfun_records { unused_function_names.extend(covfun.mangled_function_name_if_unused()); @@ -137,22 +139,13 @@ struct GlobalFileTable { } impl GlobalFileTable { - fn new(all_file_names: impl IntoIterator) -> Self { - // Collect all of the filenames into a set. Filenames usually come in - // contiguous runs, so we can dedup adjacent ones to save work. - let mut raw_file_table = all_file_names.into_iter().dedup().collect::>(); - - // Sort the file table by its actual string values, not the arbitrary - // ordering of its symbols. - raw_file_table.sort_unstable_by(|a, b| a.as_str().cmp(b.as_str())); - - Self { raw_file_table } + fn new() -> Self { + Self { raw_file_table: FxIndexSet::default() } } - fn global_file_id_for_file_name(&self, file_name: Symbol) -> GlobalFileId { - let raw_id = self.raw_file_table.get_index_of(&file_name).unwrap_or_else(|| { - bug!("file name not found in prepared global file table: {file_name}"); - }); + fn global_file_id_for_file_name(&mut self, file_name: Symbol) -> GlobalFileId { + // Ensure the given file has a table entry, and get its index. + let (raw_id, _) = self.raw_file_table.insert_full(file_name); // The raw file table doesn't include an entry for the working dir // (which has ID 0), so add 1 to get the correct ID. GlobalFileId::from_usize(raw_id + 1) @@ -264,39 +257,35 @@ fn generate_covmap_record<'ll>(cx: &CodegenCx<'ll, '_>, version: u32, filenames_ /// coverage map (in a single designated CGU) so that we still emit coverage mappings for them. /// We also end up adding their symbol names to a special global array that LLVM will include in /// its embedded coverage data. -fn add_unused_functions(cx: &CodegenCx<'_, '_>) { +fn gather_unused_function_instances<'tcx>(cx: &CodegenCx<'_, 'tcx>) -> Vec> { assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu()); let tcx = cx.tcx; let usage = prepare_usage_sets(tcx); let is_unused_fn = |def_id: LocalDefId| -> bool { - let def_id = def_id.to_def_id(); - - // To be eligible for "unused function" mappings, a definition must: - // - Be function-like + // Usage sets expect `DefId`, so convert from `LocalDefId`. + let d: DefId = LocalDefId::to_def_id(def_id); + // To be potentially eligible for "unused function" mappings, a definition must: + // - Be eligible for coverage instrumentation // - Not participate directly in codegen (or have lost all its coverage statements) // - Not have any coverage statements inlined into codegenned functions - tcx.def_kind(def_id).is_fn_like() - && (!usage.all_mono_items.contains(&def_id) - || usage.missing_own_coverage.contains(&def_id)) - && !usage.used_via_inlining.contains(&def_id) + tcx.is_eligible_for_coverage(def_id) + && (!usage.all_mono_items.contains(&d) || usage.missing_own_coverage.contains(&d)) + && !usage.used_via_inlining.contains(&d) }; - // Scan for unused functions that were instrumented for coverage. - for def_id in tcx.mir_keys(()).iter().copied().filter(|&def_id| is_unused_fn(def_id)) { - // Get the coverage info from MIR, skipping functions that were never instrumented. - let body = tcx.optimized_mir(def_id); - let Some(function_coverage_info) = body.function_coverage_info.as_deref() else { continue }; + // FIXME(#79651): Consider trying to filter out dummy instantiations of + // unused generic functions from library crates, because they can produce + // "unused instantiation" in coverage reports even when they are actually + // used by some downstream crate in the same binary. - // FIXME(79651): Consider trying to filter out dummy instantiations of - // unused generic functions from library crates, because they can produce - // "unused instantiation" in coverage reports even when they are actually - // used by some downstream crate in the same binary. - - debug!("generating unused fn: {def_id:?}"); - add_unused_function_coverage(cx, def_id, function_coverage_info); - } + tcx.mir_keys(()) + .iter() + .copied() + .filter(|&def_id| is_unused_fn(def_id)) + .map(|def_id| make_dummy_instance(tcx, def_id)) + .collect::>() } struct UsageSets<'tcx> { @@ -361,16 +350,11 @@ fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> { UsageSets { all_mono_items, used_via_inlining, missing_own_coverage } } -fn add_unused_function_coverage<'tcx>( - cx: &CodegenCx<'_, 'tcx>, - def_id: LocalDefId, - function_coverage_info: &'tcx mir::coverage::FunctionCoverageInfo, -) { - let tcx = cx.tcx; - let def_id = def_id.to_def_id(); +fn make_dummy_instance<'tcx>(tcx: TyCtxt<'tcx>, local_def_id: LocalDefId) -> ty::Instance<'tcx> { + let def_id = local_def_id.to_def_id(); // Make a dummy instance that fills in all generics with placeholders. - let instance = ty::Instance::new( + ty::Instance::new( def_id, ty::GenericArgs::for_item(tcx, def_id, |param, _| { if let ty::GenericParamDefKind::Lifetime = param.kind { @@ -379,9 +363,5 @@ fn add_unused_function_coverage<'tcx>( tcx.mk_param_from_def(param) } }), - ); - - // An unused function's mappings will all be rewritten to map to zero. - let function_coverage = FunctionCoverage::new_unused(function_coverage_info); - cx.coverage_cx().function_coverage_map.borrow_mut().insert(instance, function_coverage); + ) } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs index 33e7a0f2f201b..8e853f057bedf 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs @@ -11,13 +11,14 @@ use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, }; use rustc_middle::bug; -use rustc_middle::mir::coverage::MappingKind; +use rustc_middle::mir::coverage::{ + CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, MappingKind, Op, +}; use rustc_middle::ty::{Instance, TyCtxt}; use rustc_target::spec::HasTargetSpec; use tracing::debug; use crate::common::CodegenCx; -use crate::coverageinfo::map_data::FunctionCoverage; use crate::coverageinfo::mapgen::{GlobalFileTable, VirtualFileMapping, span_file_name}; use crate::coverageinfo::{ffi, llvm_cov}; use crate::llvm; @@ -45,20 +46,25 @@ impl<'tcx> CovfunRecord<'tcx> { pub(crate) fn prepare_covfun_record<'tcx>( tcx: TyCtxt<'tcx>, - global_file_table: &GlobalFileTable, + global_file_table: &mut GlobalFileTable, instance: Instance<'tcx>, - function_coverage: &FunctionCoverage<'tcx>, + is_used: bool, ) -> Option> { + let fn_cov_info = tcx.instance_mir(instance.def).function_coverage_info.as_deref()?; + let ids_info = tcx.coverage_ids_info(instance.def); + + let expressions = prepare_expressions(fn_cov_info, ids_info, is_used); + let mut covfun = CovfunRecord { mangled_function_name: tcx.symbol_name(instance).name, - source_hash: function_coverage.source_hash(), - is_used: function_coverage.is_used(), + source_hash: if is_used { fn_cov_info.function_source_hash } else { 0 }, + is_used, virtual_file_mapping: VirtualFileMapping::default(), - expressions: function_coverage.counter_expressions().collect::>(), + expressions, regions: ffi::Regions::default(), }; - fill_region_tables(tcx, global_file_table, function_coverage, &mut covfun); + fill_region_tables(tcx, global_file_table, fn_cov_info, ids_info, &mut covfun); if covfun.regions.has_no_regions() { if covfun.is_used { @@ -72,20 +78,50 @@ pub(crate) fn prepare_covfun_record<'tcx>( Some(covfun) } +/// Convert the function's coverage-counter expressions into a form suitable for FFI. +fn prepare_expressions( + fn_cov_info: &FunctionCoverageInfo, + ids_info: &CoverageIdsInfo, + is_used: bool, +) -> Vec { + // If any counters or expressions were removed by MIR opts, replace their + // terms with zero. + let counter_for_term = |term| { + if !is_used || ids_info.is_zero_term(term) { + ffi::Counter::ZERO + } else { + ffi::Counter::from_term(term) + } + }; + + // We know that LLVM will optimize out any unused expressions before + // producing the final coverage map, so there's no need to do the same + // thing on the Rust side unless we're confident we can do much better. + // (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.) + fn_cov_info + .expressions + .iter() + .map(move |&Expression { lhs, op, rhs }| ffi::CounterExpression { + lhs: counter_for_term(lhs), + kind: match op { + Op::Add => ffi::ExprKind::Add, + Op::Subtract => ffi::ExprKind::Subtract, + }, + rhs: counter_for_term(rhs), + }) + .collect::>() +} + /// Populates the mapping region tables in the current function's covfun record. fn fill_region_tables<'tcx>( tcx: TyCtxt<'tcx>, - global_file_table: &GlobalFileTable, - function_coverage: &FunctionCoverage<'tcx>, + global_file_table: &mut GlobalFileTable, + fn_cov_info: &'tcx FunctionCoverageInfo, + ids_info: &'tcx CoverageIdsInfo, covfun: &mut CovfunRecord<'tcx>, ) { - let counter_regions = function_coverage.counter_regions(); - if counter_regions.is_empty() { - return; - } - // Currently a function's mappings must all be in the same file as its body span. - let file_name = span_file_name(tcx, function_coverage.function_coverage_info.body_span); + let file_name = span_file_name(tcx, fn_cov_info.body_span); // Look up the global file ID for that filename. let global_file_id = global_file_table.global_file_id_for_file_name(file_name); @@ -99,10 +135,14 @@ fn fill_region_tables<'tcx>( // For each counter/region pair in this function+file, convert it to a // form suitable for FFI. - for (mapping_kind, region) in counter_regions { - debug!("Adding counter {mapping_kind:?} to map for {region:?}"); - let span = ffi::CoverageSpan::from_source_region(local_file_id, region); - match mapping_kind { + let is_zero_term = |term| !covfun.is_used || ids_info.is_zero_term(term); + for Mapping { kind, ref source_region } in &fn_cov_info.mappings { + // If the mapping refers to counters/expressions that were removed by + // MIR opts, replace those occurrences with zero. + let kind = kind.map_terms(|term| if is_zero_term(term) { CovTerm::Zero } else { term }); + + let span = ffi::CoverageSpan::from_source_region(local_file_id, source_region); + match kind { MappingKind::Code(term) => { code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) }); } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 82b6677e2038f..7311cd9d230c6 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -5,7 +5,7 @@ use rustc_abi::Size; use rustc_codegen_ssa::traits::{ BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods, }; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::ty::Instance; use rustc_middle::ty::layout::HasTyCtxt; @@ -13,18 +13,16 @@ use tracing::{debug, instrument}; use crate::builder::Builder; use crate::common::CodegenCx; -use crate::coverageinfo::map_data::FunctionCoverage; use crate::llvm; pub(crate) mod ffi; mod llvm_cov; -pub(crate) mod map_data; mod mapgen; /// Extra per-CGU context/state needed for coverage instrumentation. pub(crate) struct CguCoverageContext<'ll, 'tcx> { /// Coverage data for each instrumented function identified by DefId. - pub(crate) function_coverage_map: RefCell, FunctionCoverage<'tcx>>>, + pub(crate) instances_used: RefCell>>, pub(crate) pgo_func_name_var_map: RefCell, &'ll llvm::Value>>, pub(crate) mcdc_condition_bitmap_map: RefCell, Vec<&'ll llvm::Value>>>, @@ -34,17 +32,13 @@ pub(crate) struct CguCoverageContext<'ll, 'tcx> { impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> { pub(crate) fn new() -> Self { Self { - function_coverage_map: Default::default(), + instances_used: RefCell::>::default(), pgo_func_name_var_map: Default::default(), mcdc_condition_bitmap_map: Default::default(), covfun_section_name: Default::default(), } } - fn take_function_coverage_map(&self) -> FxIndexMap, FunctionCoverage<'tcx>> { - self.function_coverage_map.replace(FxIndexMap::default()) - } - /// LLVM use a temp value to record evaluated mcdc test vector of each decision, which is /// called condition bitmap. In order to handle nested decisions, several condition bitmaps can /// be allocated for a function body. These values are named `mcdc.addr.{i}` and are a 32-bit @@ -157,12 +151,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { // Mark the instance as used in this CGU, for coverage purposes. // This includes functions that were not partitioned into this CGU, // but were MIR-inlined into one of this CGU's functions. - coverage_cx.function_coverage_map.borrow_mut().entry(instance).or_insert_with(|| { - FunctionCoverage::new_used( - function_coverage_info, - bx.tcx.coverage_ids_info(instance.def), - ) - }); + coverage_cx.instances_used.borrow_mut().insert(instance); match *kind { CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!( diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index 817acfcca74bc..46dcebc46e9c8 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -1,9 +1,11 @@ use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult}; use rustc_middle::mir::*; use rustc_middle::query::TyCtxtAt; +use rustc_middle::ty::Ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, span_bug, ty}; use rustc_span::def_id::DefId; +use rustc_target::callconv::FnAbi; use crate::interpret::{ self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, interp_ok, @@ -86,7 +88,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { fn find_mir_or_eval_fn( _ecx: &mut InterpCx<'tcx, Self>, _instance: ty::Instance<'tcx>, - _abi: rustc_abi::ExternAbi, + _abi: &FnAbi<'tcx, Ty<'tcx>>, _args: &[interpret::FnArg<'tcx, Self::Provenance>], _destination: &interpret::MPlaceTy<'tcx, Self::Provenance>, _target: Option, diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 2368385179967..730876ce5abb9 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -2,7 +2,7 @@ use std::borrow::{Borrow, Cow}; use std::fmt; use std::hash::Hash; -use rustc_abi::{Align, ExternAbi, Size}; +use rustc_abi::{Align, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -15,6 +15,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::Span; use rustc_span::symbol::{Symbol, sym}; +use rustc_target::callconv::FnAbi; use tracing::debug; use super::error::*; @@ -340,7 +341,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { fn find_mir_or_eval_fn( ecx: &mut InterpCx<'tcx, Self>, orig_instance: ty::Instance<'tcx>, - _abi: ExternAbi, + _abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[FnArg<'tcx>], dest: &MPlaceTy<'tcx>, ret: Option, diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index ed4a1a9e6478b..46720328ea473 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -519,7 +519,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return M::call_extra_fn( self, extra, - caller_abi, + caller_fn_abi, args, destination, target, @@ -570,7 +570,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let Some((body, instance)) = M::find_mir_or_eval_fn( self, instance, - caller_abi, + caller_fn_abi, args, destination, target, diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 9ac2a024ccf37..36e5a2ff750ae 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -6,7 +6,7 @@ use std::borrow::{Borrow, Cow}; use std::fmt::Debug; use std::hash::Hash; -use rustc_abi::{Align, ExternAbi, Size}; +use rustc_abi::{Align, Size}; use rustc_apfloat::{Float, FloatConvert}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::query::TyCtxtAt; @@ -15,6 +15,7 @@ use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{mir, ty}; use rustc_span::Span; use rustc_span::def_id::DefId; +use rustc_target::callconv::FnAbi; use super::{ AllocBytes, AllocId, AllocKind, AllocRange, Allocation, CTFE_ALLOC_SALT, ConstAllocation, @@ -201,7 +202,7 @@ pub trait Machine<'tcx>: Sized { fn find_mir_or_eval_fn( ecx: &mut InterpCx<'tcx, Self>, instance: ty::Instance<'tcx>, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[FnArg<'tcx, Self::Provenance>], destination: &MPlaceTy<'tcx, Self::Provenance>, target: Option, @@ -213,7 +214,7 @@ pub trait Machine<'tcx>: Sized { fn call_extra_fn( ecx: &mut InterpCx<'tcx, Self>, fn_val: Self::ExtraFnVal, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[FnArg<'tcx, Self::Provenance>], destination: &MPlaceTy<'tcx, Self::Provenance>, target: Option, @@ -656,7 +657,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { fn call_extra_fn( _ecx: &mut InterpCx<$tcx, Self>, fn_val: !, - _abi: ExternAbi, + _abi: &FnAbi<$tcx, Ty<$tcx>>, _args: &[FnArg<$tcx>], _destination: &MPlaceTy<$tcx, Self::Provenance>, _target: Option, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 25d4146255647..58fe3ec4b8580 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1569,18 +1569,18 @@ impl DiagCtxtInner { debug!(?diagnostic); debug!(?self.emitted_diagnostics); - let already_emitted_sub = |sub: &mut Subdiag| { + let not_yet_emitted = |sub: &mut Subdiag| { debug!(?sub); if sub.level != OnceNote && sub.level != OnceHelp { - return false; + return true; } let mut hasher = StableHasher::new(); sub.hash(&mut hasher); let diagnostic_hash = hasher.finish(); debug!(?diagnostic_hash); - !self.emitted_diagnostics.insert(diagnostic_hash) + self.emitted_diagnostics.insert(diagnostic_hash) }; - diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {}); + diagnostic.children.retain_mut(not_yet_emitted); if already_emitted { let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`"; diagnostic.sub(Note, msg, MultiSpan::new()); diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 9b495c19990c1..50c64a9c94757 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -205,7 +205,7 @@ impl EarlyLintPass for NonAsciiIdents { (IdentifierType::Not_NFKC, "Not_NFKC"), ] { let codepoints: Vec<_> = - chars.extract_if(|(_, ty)| *ty == Some(id_ty)).collect(); + chars.extract_if(.., |(_, ty)| *ty == Some(id_ty)).collect(); if codepoints.is_empty() { continue; } @@ -217,7 +217,7 @@ impl EarlyLintPass for NonAsciiIdents { } let remaining = chars - .extract_if(|(c, _)| !GeneralSecurityProfile::identifier_allowed(*c)) + .extract_if(.., |(c, _)| !GeneralSecurityProfile::identifier_allowed(*c)) .collect::>(); if !remaining.is_empty() { cx.emit_span_lint(UNCOMMON_CODEPOINTS, sp, IdentifierUncommonCodepoints { diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 8bd2281981b4b..4829befda612d 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -544,7 +544,7 @@ impl<'tcx> Collector<'tcx> { // can move them to the end of the list below. let mut existing = self .libs - .extract_if(|lib| { + .extract_if(.., |lib| { if lib.name.as_str() == passed_lib.name { // FIXME: This whole logic is questionable, whether modifiers are // involved or not, library reordering and kind overriding without diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 604f1da26c648..406e732744bbb 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -309,7 +309,7 @@ pub fn suggest_constraining_type_params<'a>( let Some(param) = param else { return false }; { - let mut sized_constraints = constraints.extract_if(|(_, def_id, _)| { + let mut sized_constraints = constraints.extract_if(.., |(_, def_id, _)| { def_id.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Sized)) }); if let Some((_, def_id, _)) = sized_constraints.next() { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 368eb3c26c7b3..7cd56a8fb950e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2817,11 +2817,11 @@ fn show_candidates( path_strings.sort_by(|a, b| a.0.cmp(&b.0)); path_strings.dedup_by(|a, b| a.0 == b.0); let core_path_strings = - path_strings.extract_if(|p| p.0.starts_with("core::")).collect::>(); + path_strings.extract_if(.., |p| p.0.starts_with("core::")).collect::>(); let std_path_strings = - path_strings.extract_if(|p| p.0.starts_with("std::")).collect::>(); + path_strings.extract_if(.., |p| p.0.starts_with("std::")).collect::>(); let foreign_crate_path_strings = - path_strings.extract_if(|p| !p.0.starts_with("crate::")).collect::>(); + path_strings.extract_if(.., |p| !p.0.starts_with("crate::")).collect::>(); // We list the `crate` local paths first. // Then we list the `std`/`core` paths. diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 85ea6a74d3cfc..1625f69158fbf 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -629,7 +629,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // Try to filter out intrinsics candidates, as long as we have // some other candidates to suggest. let intrinsic_candidates: Vec<_> = candidates - .extract_if(|sugg| { + .extract_if(.., |sugg| { let path = path_names_to_string(&sugg.path); path.starts_with("core::intrinsics::") || path.starts_with("std::intrinsics::") }) diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs index 952a00c52a258..f763c37f535e3 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs @@ -13,8 +13,8 @@ pub(crate) fn target() -> Target { llvm_target: "powerpc64le-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { description: Some("64-bit PowerPC Linux with musl 1.2.3, Little Endian".into()), - tier: Some(3), - host_tools: Some(false), + tier: Some(2), + host_tools: Some(true), std: Some(true), }, pointer_width: 64, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 069fab6a6e6b9..069d42d4018c0 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -447,7 +447,7 @@ pub fn normalize_param_env_or_error<'tcx>( // This works fairly well because trait matching does not actually care about param-env // TypeOutlives predicates - these are normally used by regionck. let outlives_predicates: Vec<_> = predicates - .extract_if(|predicate| { + .extract_if(.., |predicate| { matches!(predicate.kind().skip_binder(), ty::ClauseKind::TypeOutlives(..)) }) .collect(); diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index ca0ea1ec8b2ba..13168b7a39fe4 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1939,9 +1939,7 @@ pub struct ExtractIf< T: 'a, F: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> where - F: FnMut(&mut T) -> bool, -{ +> { list: &'a mut LinkedList, it: Option>>, pred: F, @@ -1979,10 +1977,7 @@ where } #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] -impl fmt::Debug for ExtractIf<'_, T, F> -where - F: FnMut(&mut T) -> bool, -{ +impl fmt::Debug for ExtractIf<'_, T, F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("ExtractIf").field(&self.list).finish() } diff --git a/library/alloc/src/vec/extract_if.rs b/library/alloc/src/vec/extract_if.rs index 72d51e8904488..4db13981596bc 100644 --- a/library/alloc/src/vec/extract_if.rs +++ b/library/alloc/src/vec/extract_if.rs @@ -1,3 +1,4 @@ +use core::ops::{Range, RangeBounds}; use core::{ptr, slice}; use super::Vec; @@ -14,7 +15,7 @@ use crate::alloc::{Allocator, Global}; /// #![feature(extract_if)] /// /// let mut v = vec![0, 1, 2]; -/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(|x| *x % 2 == 0); +/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0); /// ``` #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] #[derive(Debug)] @@ -24,24 +25,32 @@ pub struct ExtractIf< T, F, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> where - F: FnMut(&mut T) -> bool, -{ - pub(super) vec: &'a mut Vec, +> { + vec: &'a mut Vec, /// The index of the item that will be inspected by the next call to `next`. - pub(super) idx: usize, + idx: usize, + /// Elements at and beyond this point will be retained. Must be equal or smaller than `old_len`. + end: usize, /// The number of items that have been drained (removed) thus far. - pub(super) del: usize, + del: usize, /// The original length of `vec` prior to draining. - pub(super) old_len: usize, + old_len: usize, /// The filter test predicate. - pub(super) pred: F, + pred: F, } -impl ExtractIf<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ +impl<'a, T, F, A: Allocator> ExtractIf<'a, T, F, A> { + pub(super) fn new>(vec: &'a mut Vec, pred: F, range: R) -> Self { + let old_len = vec.len(); + let Range { start, end } = slice::range(range, ..old_len); + + // Guard against the vec getting leaked (leak amplification) + unsafe { + vec.set_len(0); + } + ExtractIf { vec, idx: start, del: 0, end, old_len, pred } + } + /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] @@ -59,7 +68,7 @@ where fn next(&mut self) -> Option { unsafe { - while self.idx < self.old_len { + while self.idx < self.end { let i = self.idx; let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); let drained = (self.pred)(&mut v[i]); @@ -82,24 +91,15 @@ where } fn size_hint(&self) -> (usize, Option) { - (0, Some(self.old_len - self.idx)) + (0, Some(self.end - self.idx)) } } #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] -impl Drop for ExtractIf<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ +impl Drop for ExtractIf<'_, T, F, A> { fn drop(&mut self) { unsafe { if self.idx < self.old_len && self.del > 0 { - // This is a pretty messed up state, and there isn't really an - // obviously right thing to do. We don't want to keep trying - // to execute `pred`, so we just backshift all the unprocessed - // elements and tell the vec that they still exist. The backshift - // is required to prevent a double-drop of the last successfully - // drained item prior to a panic in the predicate. let ptr = self.vec.as_mut_ptr(); let src = ptr.add(self.idx); let dst = src.sub(self.del); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 7e7a8ff72c7b1..5f4b85b58a98c 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3615,12 +3615,15 @@ impl Vec { Splice { drain: self.drain(range), replace_with: replace_with.into_iter() } } - /// Creates an iterator which uses a closure to determine if an element should be removed. + /// Creates an iterator which uses a closure to determine if element in the range should be removed. /// /// If the closure returns true, then the element is removed and yielded. /// If the closure returns false, the element will remain in the vector and will not be yielded /// by the iterator. /// + /// Only elements that fall in the provided range are considered for extraction, but any elements + /// after the range will still have to be moved if any element has been extracted. + /// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating /// or the iteration short-circuits, then the remaining elements will be retained. /// Use [`retain`] with a negated predicate if you do not need the returned iterator. @@ -3630,10 +3633,12 @@ impl Vec { /// Using this method is equivalent to the following code: /// /// ``` + /// # use std::cmp::min; /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 }; /// # let mut vec = vec![1, 2, 3, 4, 5, 6]; - /// let mut i = 0; - /// while i < vec.len() { + /// # let range = 1..4; + /// let mut i = range.start; + /// while i < min(vec.len(), range.end) { /// if some_predicate(&mut vec[i]) { /// let val = vec.remove(i); /// // your code here @@ -3648,8 +3653,12 @@ impl Vec { /// But `extract_if` is easier to use. `extract_if` is also more efficient, /// because it can backshift the elements of the array in bulk. /// - /// Note that `extract_if` also lets you mutate every element in the filter closure, - /// regardless of whether you choose to keep or remove it. + /// Note that `extract_if` also lets you mutate the elements passed to the filter closure, + /// regardless of whether you choose to keep or remove them. + /// + /// # Panics + /// + /// If `range` is out of bounds. /// /// # Examples /// @@ -3659,25 +3668,29 @@ impl Vec { /// #![feature(extract_if)] /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]; /// - /// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::>(); + /// let evens = numbers.extract_if(.., |x| *x % 2 == 0).collect::>(); /// let odds = numbers; /// /// assert_eq!(evens, vec![2, 4, 6, 8, 14]); /// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]); /// ``` + /// + /// Using the range argument to only process a part of the vector: + /// + /// ``` + /// #![feature(extract_if)] + /// let mut items = vec![0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2]; + /// let ones = items.extract_if(7.., |x| *x == 1).collect::>(); + /// assert_eq!(items, vec![0, 0, 0, 0, 0, 0, 0, 2, 2, 2]); + /// assert_eq!(ones.len(), 3); + /// ``` #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] - pub fn extract_if(&mut self, filter: F) -> ExtractIf<'_, T, F, A> + pub fn extract_if(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, + R: RangeBounds, { - let old_len = self.len(); - - // Guard against us getting leaked (leak amplification) - unsafe { - self.set_len(0); - } - - ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter } + ExtractIf::new(self, filter, range) } } diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 0f27fdff3e182..84679827ba1c0 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1414,7 +1414,7 @@ fn extract_if_empty() { let mut vec: Vec = vec![]; { - let mut iter = vec.extract_if(|_| true); + let mut iter = vec.extract_if(.., |_| true); assert_eq!(iter.size_hint(), (0, Some(0))); assert_eq!(iter.next(), None); assert_eq!(iter.size_hint(), (0, Some(0))); @@ -1431,7 +1431,7 @@ fn extract_if_zst() { let initial_len = vec.len(); let mut count = 0; { - let mut iter = vec.extract_if(|_| true); + let mut iter = vec.extract_if(.., |_| true); assert_eq!(iter.size_hint(), (0, Some(initial_len))); while let Some(_) = iter.next() { count += 1; @@ -1454,7 +1454,7 @@ fn extract_if_false() { let initial_len = vec.len(); let mut count = 0; { - let mut iter = vec.extract_if(|_| false); + let mut iter = vec.extract_if(.., |_| false); assert_eq!(iter.size_hint(), (0, Some(initial_len))); for _ in iter.by_ref() { count += 1; @@ -1476,7 +1476,7 @@ fn extract_if_true() { let initial_len = vec.len(); let mut count = 0; { - let mut iter = vec.extract_if(|_| true); + let mut iter = vec.extract_if(.., |_| true); assert_eq!(iter.size_hint(), (0, Some(initial_len))); while let Some(_) = iter.next() { count += 1; @@ -1492,6 +1492,31 @@ fn extract_if_true() { assert_eq!(vec, vec![]); } +#[test] +fn extract_if_ranges() { + let mut vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + let mut count = 0; + let it = vec.extract_if(1..=3, |_| { + count += 1; + true + }); + assert_eq!(it.collect::>(), vec![1, 2, 3]); + assert_eq!(vec, vec![0, 4, 5, 6, 7, 8, 9, 10]); + assert_eq!(count, 3); + + let it = vec.extract_if(1..=3, |_| false); + assert_eq!(it.collect::>(), vec![]); + assert_eq!(vec, vec![0, 4, 5, 6, 7, 8, 9, 10]); +} + +#[test] +#[should_panic] +fn extract_if_out_of_bounds() { + let mut vec = vec![0, 1]; + let _ = vec.extract_if(5.., |_| true).for_each(drop); +} + #[test] fn extract_if_complex() { { @@ -1501,7 +1526,7 @@ fn extract_if_complex() { 39, ]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); @@ -1515,7 +1540,7 @@ fn extract_if_complex() { 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39, ]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); @@ -1528,7 +1553,7 @@ fn extract_if_complex() { let mut vec = vec![2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); @@ -1540,7 +1565,7 @@ fn extract_if_complex() { // [xxxxxxxxxx+++++++++++] let mut vec = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]); @@ -1552,7 +1577,7 @@ fn extract_if_complex() { // [+++++++++++xxxxxxxxxx] let mut vec = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]); @@ -1600,7 +1625,7 @@ fn extract_if_consumed_panic() { } c.index < 6 }; - let drain = data.extract_if(filter); + let drain = data.extract_if(.., filter); // NOTE: The ExtractIf is explicitly consumed drain.for_each(drop); @@ -1653,7 +1678,7 @@ fn extract_if_unconsumed_panic() { } c.index < 6 }; - let _drain = data.extract_if(filter); + let _drain = data.extract_if(.., filter); // NOTE: The ExtractIf is dropped without being consumed }); @@ -1669,7 +1694,7 @@ fn extract_if_unconsumed_panic() { #[test] fn extract_if_unconsumed() { let mut vec = vec![1, 2, 3, 4]; - let drain = vec.extract_if(|&mut x| x % 2 != 0); + let drain = vec.extract_if(.., |&mut x| x % 2 != 0); drop(drain); assert_eq!(vec, [1, 2, 3, 4]); } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index c79b2f7ad8ed3..151d879fabeed 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -4,7 +4,7 @@ macro_rules! uint_impl { ActualT = $ActualT:ident, SignedT = $SignedT:ident, - // There are all for use *only* in doc comments. + // These are all for use *only* in doc comments. // As such, they're all passed as literals -- passing them as a string // literal is fine if they need to be multiple code tokens. // In non-comments, use the associated constants rather than these. diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 717500221454a..a86c20d46bda5 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -245,6 +245,11 @@ def v(*args): "target.mips64el-unknown-linux-muslabi64.musl-root", "mips64el-unknown-linux-muslabi64 install directory", ) +v( + "musl-root-powerpc64le", + "target.powerpc64le-unknown-linux-musl.musl-root", + "powerpc64le-unknown-linux-musl install directory", +) v( "musl-root-riscv32gc", "target.riscv32gc-unknown-linux-musl.musl-root", diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index ffb7d9a9e0e74..be5b405705162 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -217,6 +217,7 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { ("powerpc-unknown-linux-gnu", false), ("powerpc64-unknown-linux-gnu", false), ("powerpc64le-unknown-linux-gnu", false), + ("powerpc64le-unknown-linux-musl", false), ("riscv64gc-unknown-linux-gnu", false), ("s390x-unknown-linux-gnu", false), ("x86_64-unknown-freebsd", false), diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index b2ffbd9c70f6a..819a552093be4 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -91,7 +91,7 @@ macro_rules! rustc { #[test] fn test_valid() { // make sure multi suite paths are accepted - check_cli(["test", "tests/ui/attr-start.rs", "tests/ui/attr-shebang.rs"]); + check_cli(["test", "tests/ui/bootstrap/self-test/a.rs", "tests/ui/bootstrap/self-test/b.rs"]); } #[test] diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile index 5dc282403be9c..9ef391892497f 100644 --- a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile @@ -3,23 +3,46 @@ FROM ubuntu:22.04 COPY scripts/cross-apt-packages.sh /scripts/ RUN sh /scripts/cross-apt-packages.sh +COPY scripts/crosstool-ng-git.sh /scripts/ +RUN sh /scripts/crosstool-ng-git.sh + COPY scripts/rustbuild-setup.sh /scripts/ RUN sh /scripts/rustbuild-setup.sh + WORKDIR /tmp +COPY scripts/crosstool-ng-build.sh /scripts/ +COPY host-x86_64/dist-powerpc64le-linux/powerpc64le-unknown-linux-musl.defconfig /tmp/crosstool.defconfig +RUN /scripts/crosstool-ng-build.sh + +WORKDIR /build + RUN apt-get install -y --no-install-recommends rpm2cpio cpio -COPY host-x86_64/dist-powerpc64le-linux/shared.sh host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh /tmp/ +COPY host-x86_64/dist-powerpc64le-linux/shared.sh host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh /build/ RUN ./build-powerpc64le-toolchain.sh COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +ENV PATH=$PATH:/x-tools/powerpc64le-unknown-linux-musl/bin + ENV \ AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ - CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ + CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ \ + AR_powerpc64le_unknown_linux_musl=powerpc64le-unknown-linux-musl-ar \ + CC_powerpc64le_unknown_linux_musl=powerpc64le-unknown-linux-musl-gcc \ + CXX_powerpc64le_unknown_linux_musl=powerpc64le-unknown-linux-musl-g++ + +ENV HOSTS=powerpc64le-unknown-linux-gnu,powerpc64le-unknown-linux-musl -ENV HOSTS=powerpc64le-unknown-linux-gnu +ENV RUST_CONFIGURE_ARGS \ + --enable-extended \ + --enable-full-tools \ + --enable-profiler \ + --enable-sanitizers \ + --disable-docs \ + --set target.powerpc64le-unknown-linux-musl.crt-static=false \ + --musl-root-powerpc64le=/x-tools/powerpc64le-unknown-linux-musl/powerpc64le-unknown-linux-musl/sysroot/usr -ENV RUST_CONFIGURE_ARGS --enable-extended --enable-profiler --disable-docs ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/powerpc64le-unknown-linux-musl.defconfig b/src/ci/docker/host-x86_64/dist-powerpc64le-linux/powerpc64le-unknown-linux-musl.defconfig new file mode 100644 index 0000000000000..c6cde30b2a4e5 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux/powerpc64le-unknown-linux-musl.defconfig @@ -0,0 +1,16 @@ +CT_CONFIG_VERSION="4" +CT_EXPERIMENTAL=y +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_USE_MIRROR=y +CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" +CT_ARCH_POWERPC=y +CT_ARCH_LE=y +CT_ARCH_64=y +# CT_DEMULTILIB is not set +CT_ARCH_ARCH="powerpc64le" +CT_KERNEL_LINUX=y +CT_LINUX_V_4_19=y +CT_LIBC_MUSL=y +CT_MUSL_V_1_2_3=y +CT_CC_LANG_CXX=y +CT_GETTEXT_NEEDED=y diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index fe0fdde39d0ff..24a9f843f3368 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -190,7 +190,7 @@ auto: <<: *job-linux-4c - image: dist-powerpc64le-linux - <<: *job-linux-4c + <<: *job-linux-4c-largedisk - image: dist-riscv64-linux <<: *job-linux-4c diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 2341d25ff096c..1e9f5a33fc792 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -66,6 +66,7 @@ - [powerpc-unknown-openbsd](platform-support/powerpc-unknown-openbsd.md) - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md) - [powerpc64-ibm-aix](platform-support/aix.md) + - [powerpc64le-unknown-linux-musl](platform-support/powerpc64le-unknown-linux-musl.md) - [riscv32e*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md) - [riscv32i*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index c4efe27efc230..db6612f9fff27 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -97,6 +97,7 @@ target | notes `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17) `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17) `powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17) +[`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19, musl 1.2.3) [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29) [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3) [`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2, glibc 2.17) @@ -348,7 +349,6 @@ target | std | host | notes `powerpc-unknown-freebsd` | ? | | PowerPC FreeBSD `powerpc64-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3 [`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | -`powerpc64le-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3, Little Endian [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64 [`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer) `riscv32gc-unknown-linux-gnu` | ✓ | | RISC-V Linux (kernel 5.4, glibc 2.33) diff --git a/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-musl.md new file mode 100644 index 0000000000000..3bd3f5d8b7f78 --- /dev/null +++ b/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-musl.md @@ -0,0 +1,48 @@ +# powerpc64le-unknown-linux-musl + +**Tier: 2** + +Target for 64-bit little endian PowerPC Linux programs using musl libc. + +## Target maintainers + +- [@Gelbpunkt](https://github.com/Gelbpunkt) +- [@famfo](https://github.com/famfo) +- [@neuschaefer](https://github.com/neuschaefer) + +## Requirements + +Building the target itself requires a 64-bit little endian PowerPC compiler that is supported by `cc-rs`. + +## Building the target + +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["powerpc64le-unknown-linux-musl"] +``` + +Make sure your C compiler is included in `$PATH`, then add it to the `config.toml`: + +```toml +[target.powerpc64le-unknown-linux-musl] +cc = "powerpc64le-linux-musl-gcc" +cxx = "powerpc64le-linux-musl-g++" +ar = "powerpc64le-linux-musl-ar" +linker = "powerpc64le-linux-musl-gcc" +``` + +## Building Rust programs + +This target are distributed through `rustup`, and otherwise require no +special configuration. + +## Cross-compilation + +This target can be cross-compiled from any host. + +## Testing + +This target can be tested as normal with `x.py` on a 64-bit little endian +PowerPC host or via QEMU emulation. diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 39d9158a1ffa7..561b611148a20 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -37,6 +37,7 @@ static HOSTS: &[&str] = &[ "powerpc-unknown-linux-gnu", "powerpc64-unknown-linux-gnu", "powerpc64le-unknown-linux-gnu", + "powerpc64le-unknown-linux-musl", "riscv64gc-unknown-linux-gnu", "s390x-unknown-linux-gnu", "x86_64-apple-darwin", @@ -131,6 +132,7 @@ static TARGETS: &[&str] = &[ "powerpc-unknown-linux-gnu", "powerpc64-unknown-linux-gnu", "powerpc64le-unknown-linux-gnu", + "powerpc64le-unknown-linux-musl", "riscv32i-unknown-none-elf", "riscv32im-risc0-zkvm-elf", "riscv32im-unknown-none-elf", diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 1f7c60ad1bdfe..412efd0296e47 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -19,6 +19,7 @@ use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, MaybeResult, TyAndLayout}; use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, UintTy}; use rustc_session::config::CrateType; use rustc_span::{Span, Symbol}; +use rustc_target::callconv::{Conv, FnAbi}; use crate::*; @@ -914,13 +915,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Check that the ABI is what we expect. - fn check_abi<'a>(&self, abi: ExternAbi, exp_abi: ExternAbi) -> InterpResult<'a, ()> { - if abi != exp_abi { + fn check_abi<'a>(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, exp_abi: Conv) -> InterpResult<'a, ()> { + if fn_abi.conv != exp_abi { throw_ub_format!( - "calling a function with ABI {} using caller ABI {}", - exp_abi.name(), - abi.name() - ) + "calling a function with ABI {:?} using caller ABI {:?}", + exp_abi, fn_abi.conv); } interp_ok(()) } @@ -950,8 +949,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn check_abi_and_shim_symbol_clash( &mut self, - abi: ExternAbi, - exp_abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, + exp_abi: Conv, link_name: Symbol, ) -> InterpResult<'tcx, ()> { self.check_abi(abi, exp_abi)?; @@ -975,8 +974,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn check_shim<'a, const N: usize>( &mut self, - abi: ExternAbi, - exp_abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, + exp_abi: Conv, link_name: Symbol, args: &'a [OpTy<'tcx>], ) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index ac26feb345c18..e7d065d7aca83 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -11,6 +11,7 @@ use std::{fmt, process}; use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; use rustc_abi::{Align, ExternAbi, Size}; +use rustc_target::callconv::FnAbi; use rustc_attr::InlineAttr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; #[allow(unused)] @@ -1010,7 +1011,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn find_mir_or_eval_fn( ecx: &mut MiriInterpCx<'tcx>, instance: ty::Instance<'tcx>, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[FnArg<'tcx, Provenance>], dest: &MPlaceTy<'tcx>, ret: Option, @@ -1037,7 +1038,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn call_extra_fn( ecx: &mut MiriInterpCx<'tcx>, fn_val: DynSym, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[FnArg<'tcx, Provenance>], dest: &MPlaceTy<'tcx>, ret: Option, diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index c7b399228bfb4..1622ef280d25c 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -1,7 +1,8 @@ -use rustc_abi::{ExternAbi, Size}; +use rustc_abi::Size; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{BytePos, Loc, Symbol, hygiene}; +use rustc_target::callconv::{Conv, FnAbi}; use crate::helpers::check_min_arg_count; use crate::*; @@ -10,13 +11,13 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn handle_miri_backtrace_size( &mut self, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, link_name: Symbol, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let [flags] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [flags] = this.check_shim(abi, Conv::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { @@ -30,7 +31,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn handle_miri_get_backtrace( &mut self, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, link_name: Symbol, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, @@ -71,7 +72,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // storage for pointers is allocated by miri // deallocating the slice is undefined behavior with a custom global allocator 0 => { - let [_flags] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [_flags] = this.check_shim(abi, Conv::Rust, link_name, args)?; let alloc = this.allocate(array_layout, MiriMemoryKind::Rust.into())?; @@ -86,7 +87,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // storage for pointers is allocated by the caller 1 => { - let [_flags, buf] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [_flags, buf] = this.check_shim(abi, Conv::Rust, link_name, args)?; let buf_place = this.deref_pointer(buf)?; @@ -136,13 +137,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn handle_miri_resolve_frame( &mut self, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, link_name: Symbol, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let [ptr, flags] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [ptr, flags] = this.check_shim(abi, Conv::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; @@ -207,14 +208,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn handle_miri_resolve_frame_names( &mut self, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, link_name: Symbol, args: &[OpTy<'tcx>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [ptr, flags, name_ptr, filename_ptr] = - this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + this.check_shim(abi, Conv::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 4dc857ef30b49..7b2a0d6f4d641 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -3,14 +3,17 @@ use std::io::Write; use std::iter; use std::path::Path; -use rustc_abi::{Align, AlignFromBytesError, ExternAbi, Size}; +use rustc_abi::{Align, AlignFromBytesError, Size}; use rustc_apfloat::Float; use rustc_ast::expand::allocator::alloc_error_handler_name; use rustc_hir::def::DefKind; use rustc_hir::def_id::CrateNum; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::{mir, ty}; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; + use self::helpers::{ToHost, ToSoft}; use super::alloc::EvalContextExt as _; @@ -39,7 +42,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_foreign_item( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ret: Option, @@ -106,7 +109,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_dyn_sym( &mut self, sym: DynSym, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ret: Option, @@ -218,7 +221,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_foreign_item_inner( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -235,11 +238,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(EmulateItemResult::NeedsReturn); } } - // When adding a new shim, you should follow the following pattern: // ``` // "shim_name" => { - // let [arg1, arg2, arg3] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + // let [arg1, arg2, arg3] = this.check_shim(abi, Conv::::C , link_name, args)?; // let result = this.shim_name(arg1, arg2, arg3)?; // this.write_scalar(result, dest)?; // } @@ -277,16 +279,16 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Miri-specific extern functions "miri_start_unwind" => { - let [payload] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [payload] = this.check_shim(abi, Conv::Rust, link_name, args)?; this.handle_miri_start_unwind(payload)?; return interp_ok(EmulateItemResult::NeedsUnwind); } "miri_run_provenance_gc" => { - let [] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [] = this.check_shim(abi, Conv::Rust, link_name, args)?; this.run_provenance_gc(); } "miri_get_alloc_id" => { - let [ptr] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [ptr] = this.check_shim(abi, Conv::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr, 0).map_err_kind(|_e| { err_machine_stop!(TerminationInfo::Abort(format!( @@ -296,7 +298,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?; } "miri_print_borrow_state" => { - let [id, show_unnamed] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [id, show_unnamed] = this.check_shim(abi, Conv::Rust, link_name, args)?; let id = this.read_scalar(id)?.to_u64()?; let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?; if let Some(id) = std::num::NonZero::new(id).map(AllocId) @@ -311,7 +313,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // This associates a name to a tag. Very useful for debugging, and also makes // tests more strict. let [ptr, nth_parent, name] = - this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + this.check_shim(abi, Conv::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let nth_parent = this.read_scalar(nth_parent)?.to_u8()?; let name = this.read_immediate(name)?; @@ -324,7 +326,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.give_pointer_debug_name(ptr, nth_parent, &name)?; } "miri_static_root" => { - let [ptr] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [ptr] = this.check_shim(abi, Conv::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr, 0)?; if offset != Size::ZERO { @@ -336,7 +338,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "miri_host_to_target_path" => { let [ptr, out, out_size] = - this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + this.check_shim(abi, Conv::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let out = this.read_pointer(out)?; let out_size = this.read_scalar(out_size)?.to_target_usize(this)?; @@ -372,7 +374,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Writes some bytes to the interpreter's stdout/stderr. See the // README for details. "miri_write_to_stdout" | "miri_write_to_stderr" => { - let [msg] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [msg] = this.check_shim(abi, Conv::Rust, link_name, args)?; let msg = this.read_immediate(msg)?; let msg = this.read_byte_slice(&msg)?; // Note: we're ignoring errors writing to host stdout/stderr. @@ -386,7 +388,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "miri_promise_symbolic_alignment" => { use rustc_abi::AlignFromBytesError; - let [ptr, align] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [ptr, align] = this.check_shim(abi, Conv::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let align = this.read_target_usize(align)?; if !align.is_power_of_two() { @@ -428,12 +430,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Aborting the process. "exit" => { let [code] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false }); } "abort" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C , link_name, args)?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) @@ -442,7 +444,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Standard C allocation "malloc" => { let [size] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let size = this.read_target_usize(size)?; if size <= this.max_size_of_val().bytes() { let res = this.malloc(size, /*zero_init:*/ false)?; @@ -457,7 +459,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "calloc" => { let [items, elem_size] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let items = this.read_target_usize(items)?; let elem_size = this.read_target_usize(elem_size)?; if let Some(size) = this.compute_size_in_bytes(Size::from_bytes(elem_size), items) { @@ -473,13 +475,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "free" => { let [ptr] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let ptr = this.read_pointer(ptr)?; this.free(ptr)?; } "realloc" => { let [old_ptr, new_size] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let old_ptr = this.read_pointer(old_ptr)?; let new_size = this.read_target_usize(new_size)?; if new_size <= this.max_size_of_val().bytes() { @@ -499,7 +501,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let default = |ecx: &mut MiriInterpCx<'tcx>| { // Only call `check_shim` when `#[global_allocator]` isn't used. When that // macro is used, we act like no shim exists, so that the exported function can run. - let [size, align] = ecx.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [size, align] = ecx.check_shim(abi, Conv::Rust, link_name, args)?; let size = ecx.read_target_usize(size)?; let align = ecx.read_target_usize(align)?; @@ -533,7 +535,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { return this.emulate_allocator(|this| { // See the comment for `__rust_alloc` why `check_shim` is only called in the // default case. - let [size, align] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + let [size, align] = this.check_shim(abi, Conv::Rust, link_name, args)?; let size = this.read_target_usize(size)?; let align = this.read_target_usize(align)?; @@ -559,7 +561,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // See the comment for `__rust_alloc` why `check_shim` is only called in the // default case. let [ptr, old_size, align] = - ecx.check_shim(abi, ExternAbi::Rust, link_name, args)?; + ecx.check_shim(abi, Conv::Rust, link_name, args)?; let ptr = ecx.read_pointer(ptr)?; let old_size = ecx.read_target_usize(old_size)?; let align = ecx.read_target_usize(align)?; @@ -594,7 +596,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // See the comment for `__rust_alloc` why `check_shim` is only called in the // default case. let [ptr, old_size, align, new_size] = - this.check_shim(abi, ExternAbi::Rust, link_name, args)?; + this.check_shim(abi, Conv::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let old_size = this.read_target_usize(old_size)?; let align = this.read_target_usize(align)?; @@ -618,7 +620,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // C memory handling functions "memcmp" => { let [left, right, n] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let left = this.read_pointer(left)?; let right = this.read_pointer(right)?; let n = Size::from_bytes(this.read_target_usize(n)?); @@ -643,7 +645,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "memrchr" => { let [ptr, val, num] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()?; let num = this.read_target_usize(num)?; @@ -670,7 +672,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "memchr" => { let [ptr, val, num] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()?; let num = this.read_target_usize(num)?; @@ -694,7 +696,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "strlen" => { let [ptr] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let ptr = this.read_pointer(ptr)?; // This reads at least 1 byte, so we are already enforcing that this is a valid pointer. let n = this.read_c_str(ptr)?.len(); @@ -705,7 +707,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "wcslen" => { let [ptr] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let ptr = this.read_pointer(ptr)?; // This reads at least 1 byte, so we are already enforcing that this is a valid pointer. let n = this.read_wchar_t_str(ptr)?.len(); @@ -716,7 +718,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "memcpy" => { let [ptr_dest, ptr_src, n] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let ptr_dest = this.read_pointer(ptr_dest)?; let ptr_src = this.read_pointer(ptr_src)?; let n = this.read_target_usize(n)?; @@ -731,7 +733,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "strcpy" => { let [ptr_dest, ptr_src] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let ptr_dest = this.read_pointer(ptr_dest)?; let ptr_src = this.read_pointer(ptr_src)?; @@ -760,7 +762,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { | "expm1f" | "tgammaf" => { - let [f] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [f] = this.check_shim(abi, Conv::C , link_name, args)?; let f = this.read_scalar(f)?.to_f32()?; // Using host floats (but it's fine, these operations do not have guaranteed precision). let f_host = f.to_host(); @@ -788,7 +790,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { | "atan2f" | "fdimf" => { - let [f1, f2] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [f1, f2] = this.check_shim(abi, Conv::C , link_name, args)?; let f1 = this.read_scalar(f1)?.to_f32()?; let f2 = this.read_scalar(f2)?.to_f32()?; // underscore case for windows, here and below @@ -817,7 +819,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { | "expm1" | "tgamma" => { - let [f] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [f] = this.check_shim(abi, Conv::C , link_name, args)?; let f = this.read_scalar(f)?.to_f64()?; // Using host floats (but it's fine, these operations do not have guaranteed precision). let f_host = f.to_host(); @@ -845,7 +847,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { | "atan2" | "fdim" => { - let [f1, f2] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [f1, f2] = this.check_shim(abi, Conv::C , link_name, args)?; let f1 = this.read_scalar(f1)?.to_f64()?; let f2 = this.read_scalar(f2)?.to_f64()?; // underscore case for windows, here and below @@ -866,7 +868,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { | "ldexp" | "scalbn" => { - let [x, exp] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [x, exp] = this.check_shim(abi, Conv::C , link_name, args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; @@ -877,7 +879,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "lgammaf_r" => { let [x, signp] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let x = this.read_scalar(x)?.to_f32()?; let signp = this.deref_pointer(signp)?; @@ -889,7 +891,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "lgamma_r" => { let [x, signp] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let x = this.read_scalar(x)?.to_f64()?; let signp = this.deref_pointer(signp)?; @@ -903,7 +905,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // LLVM intrinsics "llvm.prefetch" => { let [p, rw, loc, ty] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let _ = this.read_pointer(p)?; let rw = this.read_scalar(rw)?.to_i32()?; @@ -930,7 +932,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the x86 `_mm{,256,512}_popcnt_epi{8,16,32,64}` and wasm // `{i,u}8x16_popcnt` functions. name if name.starts_with("llvm.ctpop.v") => { - let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [op] = this.check_shim(abi, Conv::C , link_name, args)?; let (op, op_len) = this.project_to_simd(op)?; let (dest, dest_len) = this.project_to_simd(dest)?; @@ -961,7 +963,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } // FIXME: Move these to an `arm` submodule. "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - let [arg] = this.check_shim(abi, ExternAbi::Unadjusted, link_name, args)?; + let [arg] = this.check_shim(abi, Conv::C, link_name, args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { // SY ("full system scope") @@ -974,7 +976,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => { - let [arg] = this.check_shim(abi, ExternAbi::Unadjusted, link_name, args)?; + let [arg] = this.check_shim(abi, Conv::C, link_name, args)?; let arg = this.read_scalar(arg)?.to_i32()?; // Note that different arguments might have different target feature requirements. match arg { diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index f9003885450c8..1a2fa7cfc0f68 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -1,5 +1,8 @@ -use rustc_abi::ExternAbi; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; + + use crate::shims::unix::android::thread::prctl; use crate::shims::unix::linux_like::epoll::EvalContextExt as _; @@ -16,7 +19,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_foreign_item_inner( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -25,31 +28,31 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // epoll, eventfd "epoll_create1" => { let [flag] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.epoll_create1(flag)?; this.write_scalar(result, dest)?; } "epoll_ctl" => { let [epfd, op, fd, event] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.epoll_ctl(epfd, op, fd, event)?; this.write_scalar(result, dest)?; } "epoll_wait" => { let [epfd, events, maxevents, timeout] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.epoll_wait(epfd, events, maxevents, timeout, dest)?; } "eventfd" => { let [val, flag] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.eventfd(val, flag)?; this.write_scalar(result, dest)?; } // Miscellaneous "__errno" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs index f8a0b3a85a2f2..8d5d4a52b6efe 100644 --- a/src/tools/miri/src/shims/unix/android/thread.rs +++ b/src/tools/miri/src/shims/unix/android/thread.rs @@ -1,5 +1,7 @@ -use rustc_abi::{ExternAbi, Size}; +use rustc_abi::Size; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use crate::helpers::check_min_arg_count; use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult}; @@ -10,13 +12,13 @@ const TASK_COMM_LEN: usize = 16; pub fn prctl<'tcx>( ecx: &mut MiriInterpCx<'tcx>, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { // We do not use `check_shim` here because `prctl` is variadic. The argument // count is checked bellow. - ecx.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?; + ecx.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?; // FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch. let pr_set_name = 15; diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 88ec32808b1c7..ff316e782b0b1 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -1,9 +1,11 @@ use std::ffi::OsStr; use std::str; -use rustc_abi::{ExternAbi, Size}; +use rustc_abi::Size; use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use self::shims::unix::android::foreign_items as android; use self::shims::unix::freebsd::foreign_items as freebsd; @@ -100,7 +102,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_foreign_item_inner( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -111,54 +113,52 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Environment related shims "getenv" => { - let [name] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.getenv(name)?; this.write_pointer(result, dest)?; } "unsetenv" => { - let [name] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.unsetenv(name)?; this.write_scalar(result, dest)?; } "setenv" => { - let [name, value, overwrite] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [name, value, overwrite] = this.check_shim(abi, Conv::C , link_name, args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(result, dest)?; } "getcwd" => { - let [buf, size] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [buf, size] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.getcwd(buf, size)?; this.write_pointer(result, dest)?; } "chdir" => { - let [path] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [path] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.chdir(path)?; this.write_scalar(result, dest)?; } "getpid" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false}, link_name, args)?; + let [] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.getpid()?; this.write_scalar(result, dest)?; } - "sysconf" => { let [val] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.sysconf(val)?; this.write_scalar(result, dest)?; } - // File descriptors "read" => { - let [fd, buf, count] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd, buf, count] = this.check_shim(abi, Conv::C , link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; this.read(fd, buf, count, None, dest)?; } "write" => { - let [fd, buf, n] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd, buf, n] = this.check_shim(abi, Conv::C , link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(n)?; @@ -166,7 +166,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write(fd, buf, count, None, dest)?; } "pread" => { - let [fd, buf, count, offset] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd, buf, count, offset] = this.check_shim(abi, Conv::C , link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; @@ -174,7 +174,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read(fd, buf, count, Some(offset), dest)?; } "pwrite" => { - let [fd, buf, n, offset] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd, buf, n, offset] = this.check_shim(abi, Conv::C , link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(n)?; @@ -183,7 +183,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write(fd, buf, count, Some(offset), dest)?; } "pread64" => { - let [fd, buf, count, offset] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd, buf, count, offset] = this.check_shim(abi, Conv::C , link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; @@ -191,7 +191,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read(fd, buf, count, Some(offset), dest)?; } "pwrite64" => { - let [fd, buf, n, offset] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd, buf, n, offset] = this.check_shim(abi, Conv::C , link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(n)?; @@ -200,32 +200,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write(fd, buf, count, Some(offset), dest)?; } "close" => { - let [fd] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.close(fd)?; this.write_scalar(result, dest)?; } "fcntl" => { // `fcntl` is variadic. The argument count is checked based on the first argument // in `this.fcntl()`, so we do not use `check_shim` here. - this.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?; + this.check_abi_and_shim_symbol_clash(abi, Conv::C , link_name)?; let result = this.fcntl(args)?; this.write_scalar(result, dest)?; } "dup" => { - let [old_fd] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [old_fd] = this.check_shim(abi, Conv::C , link_name, args)?; let old_fd = this.read_scalar(old_fd)?.to_i32()?; let new_fd = this.dup(old_fd)?; this.write_scalar(new_fd, dest)?; } "dup2" => { - let [old_fd, new_fd] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [old_fd, new_fd] = this.check_shim(abi, Conv::C , link_name, args)?; let old_fd = this.read_scalar(old_fd)?.to_i32()?; let new_fd = this.read_scalar(new_fd)?.to_i32()?; let result = this.dup2(old_fd, new_fd)?; this.write_scalar(result, dest)?; } "flock" => { - let [fd, op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd, op] = this.check_shim(abi, Conv::C , link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let op = this.read_scalar(op)?.to_i32()?; let result = this.flock(fd, op)?; @@ -235,47 +235,47 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File and file system access "open" | "open64" => { // `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set - this.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?; + this.check_abi_and_shim_symbol_clash(abi, Conv::C , link_name)?; let result = this.open(args)?; this.write_scalar(result, dest)?; } "unlink" => { - let [path] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [path] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.unlink(path)?; this.write_scalar(result, dest)?; } "symlink" => { - let [target, linkpath] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [target, linkpath] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(result, dest)?; } "rename" => { - let [oldpath, newpath] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [oldpath, newpath] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(result, dest)?; } "mkdir" => { - let [path, mode] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [path, mode] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.mkdir(path, mode)?; this.write_scalar(result, dest)?; } "rmdir" => { - let [path] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [path] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.rmdir(path)?; this.write_scalar(result, dest)?; } "opendir" => { - let [name] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "closedir" => { - let [dirp] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [dirp] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.closedir(dirp)?; this.write_scalar(result, dest)?; } "lseek64" => { - let [fd, offset, whence] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd, offset, whence] = this.check_shim(abi, Conv::C , link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let offset = this.read_scalar(offset)?.to_i64()?; let whence = this.read_scalar(whence)?.to_i32()?; @@ -283,7 +283,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "lseek" => { - let [fd, offset, whence] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd, offset, whence] = this.check_shim(abi, Conv::C , link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; let whence = this.read_scalar(whence)?.to_i32()?; @@ -292,7 +292,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "ftruncate64" => { let [fd, length] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let length = this.read_scalar(length)?.to_i64()?; let result = this.ftruncate64(fd, length.into())?; @@ -300,30 +300,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "ftruncate" => { let [fd, length] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let length = this.read_scalar(length)?.to_int(this.libc_ty_layout("off_t").size)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(result, dest)?; } "fsync" => { - let [fd] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.fsync(fd)?; this.write_scalar(result, dest)?; } "fdatasync" => { - let [fd] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.fdatasync(fd)?; this.write_scalar(result, dest)?; } "readlink" => { - let [pathname, buf, bufsize] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [pathname, buf, bufsize] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_target_isize(result, this), dest)?; } "posix_fadvise" => { let [fd, offset, len, advice] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; this.read_scalar(fd)?.to_i32()?; this.read_target_isize(offset)?; this.read_target_isize(len)?; @@ -332,12 +332,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } "realpath" => { - let [path, resolved_path] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [path, resolved_path] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.realpath(path, resolved_path)?; this.write_scalar(result, dest)?; } "mkstemp" => { - let [template] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [template] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.mkstemp(template)?; this.write_scalar(result, dest)?; } @@ -345,13 +345,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Unnamed sockets and pipes "socketpair" => { let [domain, type_, protocol, sv] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let result = this.socketpair(domain, type_, protocol, sv)?; this.write_scalar(result, dest)?; } "pipe" => { let [pipefd] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let result = this.pipe2(pipefd, /*flags*/ None)?; this.write_scalar(result, dest)?; } @@ -364,44 +364,44 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } let [pipefd, flags] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let result = this.pipe2(pipefd, Some(flags))?; this.write_scalar(result, dest)?; } // Time "gettimeofday" => { - let [tv, tz] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [tv, tz] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(result, dest)?; } "localtime_r" => { - let [timep, result_op] = this.check_shim(abi, ExternAbi::C {unwind: false}, link_name, args)?; + let [timep, result_op] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.localtime_r(timep, result_op)?; this.write_pointer(result, dest)?; } "clock_gettime" => { let [clk_id, tp] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(result, dest)?; } // Allocation "posix_memalign" => { - let [memptr, align, size] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [memptr, align, size] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.posix_memalign(memptr, align, size)?; this.write_scalar(result, dest)?; } "mmap" => { - let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, ExternAbi::C {unwind: false}, link_name, args)?; + let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, Conv::C , link_name, args)?; let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; let ptr = this.mmap(addr, length, prot, flags, fd, offset)?; this.write_scalar(ptr, dest)?; } "munmap" => { - let [addr, length] = this.check_shim(abi, ExternAbi::C {unwind: false}, link_name, args)?; + let [addr, length] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.munmap(addr, length)?; this.write_scalar(result, dest)?; } @@ -415,7 +415,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } let [ptr, nmemb, size] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let ptr = this.read_pointer(ptr)?; let nmemb = this.read_target_usize(nmemb)?; let size = this.read_target_usize(size)?; @@ -439,14 +439,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This is a C11 function, we assume all Unixes have it. // (MSVC explicitly does not support this.) let [align, size] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let res = this.aligned_alloc(align, size)?; this.write_pointer(res, dest)?; } // Dynamic symbol loading "dlsym" => { - let [handle, symbol] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [handle, symbol] = this.check_shim(abi, Conv::C , link_name, args)?; this.read_target_usize(handle)?; let symbol = this.read_pointer(symbol)?; let name = this.read_c_str(symbol)?; @@ -460,7 +460,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Thread-local storage "pthread_key_create" => { - let [key, dtor] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [key, dtor] = this.check_shim(abi, Conv::C , link_name, args)?; let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?; let dtor = this.read_pointer(dtor)?; @@ -488,21 +488,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } "pthread_key_delete" => { - let [key] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [key] = this.check_shim(abi, Conv::C , link_name, args)?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let [key] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [key] = this.check_shim(abi, Conv::C , link_name, args)?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; let active_thread = this.active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let [key, new_ptr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [key, new_ptr] = this.check_shim(abi, Conv::C , link_name, args)?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; let active_thread = this.active_thread(); let new_data = this.read_scalar(new_ptr)?; @@ -514,151 +514,151 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Synchronization primitives "pthread_mutexattr_init" => { - let [attr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [attr] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_mutexattr_init(attr)?; this.write_null(dest)?; } "pthread_mutexattr_settype" => { - let [attr, kind] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [attr, kind] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(result, dest)?; } "pthread_mutexattr_destroy" => { - let [attr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [attr] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_mutexattr_destroy(attr)?; this.write_null(dest)?; } "pthread_mutex_init" => { - let [mutex, attr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [mutex, attr] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_mutex_init(mutex, attr)?; this.write_null(dest)?; } "pthread_mutex_lock" => { - let [mutex] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_mutex_lock(mutex, dest)?; } "pthread_mutex_trylock" => { - let [mutex] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(result, dest)?; } "pthread_mutex_unlock" => { - let [mutex] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(result, dest)?; } "pthread_mutex_destroy" => { - let [mutex] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_mutex_destroy(mutex)?; this.write_int(0, dest)?; } "pthread_rwlock_rdlock" => { - let [rwlock] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_rwlock_rdlock(rwlock, dest)?; } "pthread_rwlock_tryrdlock" => { - let [rwlock] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(result, dest)?; } "pthread_rwlock_wrlock" => { - let [rwlock] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_rwlock_wrlock(rwlock, dest)?; } "pthread_rwlock_trywrlock" => { - let [rwlock] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(result, dest)?; } "pthread_rwlock_unlock" => { - let [rwlock] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_rwlock_unlock(rwlock)?; this.write_null(dest)?; } "pthread_rwlock_destroy" => { - let [rwlock] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_rwlock_destroy(rwlock)?; this.write_null(dest)?; } "pthread_condattr_init" => { - let [attr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [attr] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_condattr_init(attr)?; this.write_null(dest)?; } "pthread_condattr_setclock" => { let [attr, clock_id] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(result, dest)?; } "pthread_condattr_getclock" => { let [attr, clock_id] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_condattr_getclock(attr, clock_id)?; this.write_null(dest)?; } "pthread_condattr_destroy" => { - let [attr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [attr] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_condattr_destroy(attr)?; this.write_null(dest)?; } "pthread_cond_init" => { - let [cond, attr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [cond, attr] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_cond_init(cond, attr)?; this.write_null(dest)?; } "pthread_cond_signal" => { - let [cond] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [cond] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_cond_signal(cond)?; this.write_null(dest)?; } "pthread_cond_broadcast" => { - let [cond] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [cond] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_cond_broadcast(cond)?; this.write_null(dest)?; } "pthread_cond_wait" => { - let [cond, mutex] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [cond, mutex] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_cond_wait(cond, mutex, dest)?; } "pthread_cond_timedwait" => { - let [cond, mutex, abstime] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [cond, mutex, abstime] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - let [cond] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [cond] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_cond_destroy(cond)?; this.write_null(dest)?; } // Threading "pthread_create" => { - let [thread, attr, start, arg] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [thread, attr, start, arg] = this.check_shim(abi, Conv::C , link_name, args)?; this.pthread_create(thread, attr, start, arg)?; this.write_null(dest)?; } "pthread_join" => { - let [thread, retval] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [thread, retval] = this.check_shim(abi, Conv::C , link_name, args)?; let res = this.pthread_join(thread, retval)?; this.write_scalar(res, dest)?; } "pthread_detach" => { - let [thread] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [thread] = this.check_shim(abi, Conv::C , link_name, args)?; let res = this.pthread_detach(thread)?; this.write_scalar(res, dest)?; } "pthread_self" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C , link_name, args)?; let res = this.pthread_self()?; this.write_scalar(res, dest)?; } "sched_yield" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C , link_name, args)?; this.sched_yield()?; this.write_null(dest)?; } "nanosleep" => { - let [req, rem] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [req, rem] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(result, dest)?; } @@ -672,7 +672,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let [pid, cpusetsize, mask] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let pid = this.read_scalar(pid)?.to_u32()?; let cpusetsize = this.read_target_usize(cpusetsize)?; let mask = this.read_pointer(mask)?; @@ -712,7 +712,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let [pid, cpusetsize, mask] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let pid = this.read_scalar(pid)?.to_u32()?; let cpusetsize = this.read_target_usize(cpusetsize)?; let mask = this.read_pointer(mask)?; @@ -748,12 +748,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miscellaneous "isatty" => { - let [fd] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [fd] = this.check_shim(abi, Conv::C , link_name, args)?; let result = this.isatty(fd)?; this.write_scalar(result, dest)?; } "pthread_atfork" => { - let [prepare, parent, child] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [prepare, parent, child] = this.check_shim(abi, Conv::C , link_name, args)?; this.read_pointer(prepare)?; this.read_pointer(parent)?; this.read_pointer(child)?; @@ -771,7 +771,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let [buf, bufsize] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let buf = this.read_pointer(buf)?; let bufsize = this.read_target_usize(bufsize)?; @@ -790,7 +790,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "strerror_r" => { let [errnum, buf, buflen] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.strerror_r(errnum, buf, buflen)?; this.write_scalar(result, dest)?; } @@ -805,7 +805,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } let [ptr, len, flags] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; let _flags = this.read_scalar(flags)?.to_i32()?; @@ -822,7 +822,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.tcx.sess.target.os ); } - let [ptr, len] = this.check_shim(abi, ExternAbi::C { unwind: false}, link_name, args)?; + let [ptr, len] = this.check_shim(abi, Conv::C , link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; this.gen_random(ptr, len)?; @@ -848,12 +848,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } // This function looks and behaves excatly like miri_start_unwind. - let [payload] = this.check_shim(abi, ExternAbi::C { unwind: true }, link_name, args)?; + let [payload] = this.check_shim(abi, Conv::C, link_name, args)?; this.handle_miri_start_unwind(payload)?; return interp_ok(EmulateItemResult::NeedsUnwind); } "getuid" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C , link_name, args)?; // For now, just pretend we always have this fixed UID. this.write_int(UID, dest)?; } @@ -862,7 +862,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame_in_std() => { - let [_attr, guard_size] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [_attr, guard_size] = this.check_shim(abi, Conv::C , link_name, args)?; let guard_size = this.deref_pointer(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t"); this.write_scalar(Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size)?; @@ -874,12 +874,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => { - let [_] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [_] = this.check_shim(abi, Conv::C , link_name, args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame_in_std() => { - let [_, _] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [_, _] = this.check_shim(abi, Conv::C , link_name, args)?; this.write_null(dest)?; } @@ -888,7 +888,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. // Hence we can mostly ignore the input `attr_place`. let [attr_place, addr_place, size_place] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; let _attr_place = this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?; let addr_place = this.deref_pointer(addr_place)?; let size_place = this.deref_pointer(size_place)?; @@ -909,13 +909,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "signal" | "sigaltstack" if this.frame_in_std() => { - let [_, _] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [_, _] = this.check_shim(abi, Conv::C , link_name, args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame_in_std() => { - let [_, _, _] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [_, _, _] = this.check_shim(abi, Conv::C , link_name, args)?; this.write_null(dest)?; } @@ -923,7 +923,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if this.frame_in_std() => { // getpwuid_r is the standard name, __posix_getpwuid_r is used on solarish let [uid, pwd, buf, buflen, result] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C , link_name, args)?; this.check_no_isolation("`getpwuid_r`")?; let uid = this.read_scalar(uid)?.to_u32()?; diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 0c9bc005ece47..b617e00e5d5ef 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -1,5 +1,6 @@ -use rustc_abi::ExternAbi; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use crate::shims::unix::*; use crate::*; @@ -13,7 +14,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_foreign_item_inner( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -22,7 +23,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "pthread_set_name_np" => { let [thread, name] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let max_len = usize::MAX; // FreeBSD does not seem to have a limit. // FreeBSD's pthread_set_name_np does not return anything. this.pthread_setname_np( @@ -34,7 +35,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_get_name_np" => { let [thread, name, len] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; // FreeBSD's pthread_get_name_np does not return anything // and uses strlcpy, which truncates the resulting value, // but always adds a null terminator (except for zero-sized buffers). @@ -52,32 +53,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // since freebsd 12 the former form can be expected. "stat" | "stat@FBSD_1.0" => { let [path, buf] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat@FBSD_1.0" => { let [path, buf] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat@FBSD_1.0" => { let [fd, buf] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r@FBSD_1.0" => { let [dirp, entry, result] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; this.write_scalar(result, dest)?; } // Miscellaneous "__error" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } @@ -86,7 +87,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // These shims are enabled only when the caller is in the standard library. "pthread_attr_get_np" if this.frame_in_std() => { let [_thread, _attr] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.write_null(dest)?; } diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index bc3619090c087..d7fe909caff53 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -1,5 +1,6 @@ -use rustc_abi::ExternAbi; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use self::shims::unix::linux::mem::EvalContextExt as _; use self::shims::unix::linux_like::epoll::EvalContextExt as _; @@ -24,7 +25,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_foreign_item_inner( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -36,19 +37,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File related shims "readdir64" => { let [dirp] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.linux_readdir64(dirp)?; this.write_scalar(result, dest)?; } "sync_file_range" => { let [fd, offset, nbytes, flags] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(result, dest)?; } "statx" => { let [dirfd, pathname, flags, mask, statxbuf] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; this.write_scalar(result, dest)?; } @@ -56,24 +57,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // epoll, eventfd "epoll_create1" => { let [flag] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.epoll_create1(flag)?; this.write_scalar(result, dest)?; } "epoll_ctl" => { let [epfd, op, fd, event] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.epoll_ctl(epfd, op, fd, event)?; this.write_scalar(result, dest)?; } "epoll_wait" => { let [epfd, events, maxevents, timeout] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.epoll_wait(epfd, events, maxevents, timeout, dest)?; } "eventfd" => { let [val, flag] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.eventfd(val, flag)?; this.write_scalar(result, dest)?; } @@ -81,7 +82,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "pthread_setname_np" => { let [thread, name] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let res = match this.pthread_setname_np( this.read_scalar(thread)?, this.read_scalar(name)?, @@ -97,7 +98,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_getname_np" => { let [thread, name, len] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; // The function's behavior isn't portable between platforms. // In case of glibc, the length of the output buffer must // be not shorter than TASK_COMM_LEN. @@ -120,7 +121,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "gettid" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.linux_gettid()?; this.write_scalar(result, dest)?; } @@ -133,35 +134,35 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miscellaneous "mmap64" => { let [addr, length, prot, flags, fd, offset] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let offset = this.read_scalar(offset)?.to_i64()?; let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?; this.write_scalar(ptr, dest)?; } "mremap" => { let [old_address, old_size, new_size, flags] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let ptr = this.mremap(old_address, old_size, new_size, flags)?; this.write_scalar(ptr, dest)?; } "__xpg_strerror_r" => { let [errnum, buf, buflen] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.strerror_r(errnum, buf, buflen)?; this.write_scalar(result, dest)?; } "__errno_location" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } "__libc_current_sigrtmin" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; this.write_int(SIGRTMIN, dest)?; } "__libc_current_sigrtmax" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; this.write_int(SIGRTMAX, dest)?; } @@ -170,7 +171,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame_in_std() => { let [_thread, _attr] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.write_null(dest)?; } diff --git a/src/tools/miri/src/shims/unix/linux_like/syscall.rs b/src/tools/miri/src/shims/unix/linux_like/syscall.rs index e9a32a263263f..57f10ace6a78b 100644 --- a/src/tools/miri/src/shims/unix/linux_like/syscall.rs +++ b/src/tools/miri/src/shims/unix/linux_like/syscall.rs @@ -1,5 +1,7 @@ -use rustc_abi::ExternAbi; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; + use crate::helpers::check_min_arg_count; use crate::shims::unix::linux_like::eventfd::EvalContextExt as _; @@ -9,13 +11,13 @@ use crate::*; pub fn syscall<'tcx>( ecx: &mut MiriInterpCx<'tcx>, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { // We do not use `check_shim` here because `syscall` is variadic. The argument // count is checked bellow. - ecx.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?; + ecx.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. The important check is that when we use an // argument, we have to also check all arguments *before* it to ensure that they diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 103bea0862086..3be6967b7c2fc 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -1,5 +1,6 @@ -use rustc_abi::ExternAbi; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use super::sync::EvalContextExt as _; use crate::shims::unix::*; @@ -14,7 +15,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_foreign_item_inner( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -25,7 +26,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // errno "__error" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } @@ -33,50 +34,50 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File related shims "close$NOCANCEL" => { let [result] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.close(result)?; this.write_scalar(result, dest)?; } "stat" | "stat64" | "stat$INODE64" => { let [path, buf] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat64" | "lstat$INODE64" => { let [path, buf] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat64" | "fstat$INODE64" => { let [fd, buf] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "opendir$INODE64" => { let [name] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { let [dirp, entry, result] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; this.write_scalar(result, dest)?; } "realpath$DARWIN_EXTSN" => { let [path, resolved_path] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.realpath(path, resolved_path)?; this.write_scalar(result, dest)?; } // Environment related shims "_NSGetEnviron" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; let environ = this.machine.env_vars.unix().environ(); this.write_pointer(environ, dest)?; } @@ -84,7 +85,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Random data generation "CCRandomGenerateBytes" => { let [bytes, count] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let bytes = this.read_pointer(bytes)?; let count = this.read_target_usize(count)?; let success = this.eval_libc_i32("kCCSuccess"); @@ -94,30 +95,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Time related shims "mach_absolute_time" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.mach_absolute_time()?; this.write_scalar(result, dest)?; } "mach_timebase_info" => { let [info] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(result, dest)?; } // Access to command-line arguments "_NSGetArgc" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?; } "_NSGetExecutablePath" => { let [buf, bufsize] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.check_no_isolation("`_NSGetExecutablePath`")?; let buf_ptr = this.read_pointer(buf)?; @@ -143,7 +144,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Thread-local storage "_tlv_atexit" => { let [dtor, data] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let dtor = this.read_pointer(dtor)?; let dtor = this.get_ptr_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?; @@ -154,14 +155,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Querying system information "pthread_get_stackaddr_np" => { let [thread] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.read_target_usize(thread)?; let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { let [thread] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.read_target_usize(thread)?; let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -170,7 +171,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "pthread_setname_np" => { let [name] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; // The real implementation has logic in two places: // * in userland at https://github.com/apple-oss-distributions/libpthread/blob/c032e0b076700a0a47db75528a282b8d3a06531a/src/pthread.c#L1178-L1200, @@ -198,7 +199,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_getname_np" => { let [thread, name, len] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; // The function's behavior isn't portable between platforms. // In case of macOS, a truncated name (due to a too small buffer) @@ -224,27 +225,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "os_unfair_lock_lock" => { let [lock_op] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.os_unfair_lock_lock(lock_op)?; } "os_unfair_lock_trylock" => { let [lock_op] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.os_unfair_lock_trylock(lock_op, dest)?; } "os_unfair_lock_unlock" => { let [lock_op] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.os_unfair_lock_unlock(lock_op)?; } "os_unfair_lock_assert_owner" => { let [lock_op] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.os_unfair_lock_assert_owner(lock_op)?; } "os_unfair_lock_assert_not_owner" => { let [lock_op] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.os_unfair_lock_assert_not_owner(lock_op)?; } diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index e452917036840..fa67b6c939e25 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -1,5 +1,6 @@ -use rustc_abi::ExternAbi; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use crate::shims::unix::foreign_items::EvalContextExt as _; use crate::shims::unix::*; @@ -14,7 +15,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_foreign_item_inner( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -23,7 +24,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "pthread_setname_np" => { let [thread, name] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; // THREAD_NAME_MAX allows a thread name of 31+1 length // https://github.com/illumos/illumos-gate/blob/7671517e13b8123748eda4ef1ee165c6d9dba7fe/usr/src/uts/common/sys/thread.h#L613 let max_len = 32; @@ -42,7 +43,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_getname_np" => { let [thread, name, len] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; // See https://illumos.org/man/3C/pthread_getname_np for the error codes. let res = match this.pthread_getname_np( this.read_scalar(thread)?, @@ -60,33 +61,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File related shims "stat" | "stat64" => { let [path, buf] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat64" => { let [path, buf] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat64" => { let [fd, buf] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_fstat(fd, buf)?; this.write_scalar(result, dest)?; } // Miscellaneous "___errno" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } "stack_getbounds" => { let [stack] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let stack = this.deref_pointer_as(stack, this.libc_ty_layout("stack_t"))?; this.write_int_fields_named( @@ -105,7 +106,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "pset_info" => { let [pset, tpe, cpus, list] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; // We do not need to handle the current process cpu mask, available_parallelism // implementation pass null anyway. We only care for the number of // cpus. @@ -135,7 +136,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "__sysconf_xpg7" => { let [val] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.sysconf(val)?; this.write_scalar(result, dest)?; } diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs index 2c349203d465f..facb6f8ce3a9d 100644 --- a/src/tools/miri/src/shims/wasi/foreign_items.rs +++ b/src/tools/miri/src/shims/wasi/foreign_items.rs @@ -1,5 +1,6 @@ -use rustc_abi::ExternAbi; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use crate::shims::alloc::EvalContextExt as _; use crate::*; @@ -13,7 +14,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_foreign_item_inner( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -22,13 +23,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Allocation "posix_memalign" => { let [memptr, align, size] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.posix_memalign(memptr, align, size)?; this.write_scalar(result, dest)?; } "aligned_alloc" => { let [align, size] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let res = this.aligned_alloc(align, size)?; this.write_pointer(res, dest)?; } diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index d6a180451d7ad..dd531c5956f66 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -2,8 +2,10 @@ use std::ffi::OsStr; use std::path::{self, Path, PathBuf}; use std::{io, iter, str}; -use rustc_abi::{Align, ExternAbi, Size}; +use rustc_abi::{Align, Size}; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use self::shims::windows::handle::{Handle, PseudoHandle}; use crate::shims::os_str::bytes_to_os_str; @@ -83,12 +85,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_foreign_item_inner( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); + // According to + // https://github.com/rust-lang/rust/blob/fb00adbdb69266f10df95a4527b767b0ad35ea48/compiler/rustc_target/src/spec/mod.rs#L2766-L2768, + // x86-32 Windows uses a different calling convention than other Windows targets + // for the "system" ABI. + let sys_conv = if this.tcx.sess.target.arch == "x86" { Conv::X86Stdcall } else { Conv::C }; + // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. // Windows API stubs. @@ -101,49 +109,49 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Environment related shims "GetEnvironmentVariableW" => { let [name, buf, size] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(result, dest)?; } "SetEnvironmentVariableW" => { let [name, value] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(result, dest)?; } "GetEnvironmentStringsW" => { let [] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let result = this.GetEnvironmentStringsW()?; this.write_pointer(result, dest)?; } "FreeEnvironmentStringsW" => { let [env_block] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(result, dest)?; } "GetCurrentDirectoryW" => { let [size, buf] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(result, dest)?; } "SetCurrentDirectoryW" => { let [path] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(result, dest)?; } "GetUserProfileDirectoryW" => { let [token, buf, size] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let result = this.GetUserProfileDirectoryW(token, buf, size)?; this.write_scalar(result, dest)?; } "GetCurrentProcessId" => { let [] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let result = this.GetCurrentProcessId()?; this.write_scalar(result, dest)?; } @@ -166,7 +174,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { n, byte_offset, _key, - ] = this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + ] = this.check_shim(abi, sys_conv, link_name, args)?; let handle = this.read_target_isize(handle)?; let buf = this.read_pointer(buf)?; let n = this.read_scalar(n)?.to_u32()?; @@ -218,7 +226,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "GetFullPathNameW" => { let [filename, size, buffer, filepart] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.check_no_isolation("`GetFullPathNameW`")?; let filename = this.read_pointer(filename)?; @@ -250,7 +258,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Allocation "HeapAlloc" => { let [handle, flags, size] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.read_target_isize(handle)?; let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_target_usize(size)?; @@ -274,7 +282,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "HeapFree" => { let [handle, flags, ptr] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.read_target_isize(handle)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_pointer(ptr)?; @@ -287,7 +295,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "HeapReAlloc" => { let [handle, flags, old_ptr, size] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.read_target_isize(handle)?; this.read_scalar(flags)?.to_u32()?; let old_ptr = this.read_pointer(old_ptr)?; @@ -307,7 +315,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "LocalFree" => { let [ptr] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let ptr = this.read_pointer(ptr)?; // "If the hMem parameter is NULL, LocalFree ignores the parameter and returns NULL." // (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree) @@ -320,13 +328,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // errno "SetLastError" => { let [error] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let error = this.read_scalar(error)?; this.set_last_error(error)?; } "GetLastError" => { let [] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } @@ -335,7 +343,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetSystemInfo" => { // Also called from `page_size` crate. let [system_info] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let system_info = this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?; // Initialize with `0`. @@ -359,13 +367,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Create key and return it. let [] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { let [key] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; @@ -373,7 +381,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "TlsSetValue" => { let [key, new_ptr] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.active_thread(); let new_data = this.read_scalar(new_ptr)?; @@ -383,8 +391,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_int(1, dest)?; } "TlsFree" => { - let [key] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + let [key] = this.check_shim(abi, sys_conv, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); this.machine.tls.delete_tls_key(key)?; @@ -395,7 +402,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Access to command-line arguments "GetCommandLineW" => { let [] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.write_pointer( this.machine.cmd_line.expect("machine must be initialized"), dest, @@ -406,32 +413,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => { #[allow(non_snake_case)] let [LPFILETIME] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?; } "QueryPerformanceCounter" => { #[allow(non_snake_case)] let [lpPerformanceCount] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(result, dest)?; } "QueryPerformanceFrequency" => { #[allow(non_snake_case)] let [lpFrequency] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(result, dest)?; } "Sleep" => { let [timeout] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.Sleep(timeout)?; } "CreateWaitableTimerExW" => { let [attributes, name, flags, access] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.read_pointer(attributes)?; this.read_pointer(name)?; this.read_scalar(flags)?.to_u32()?; @@ -445,30 +452,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Synchronization primitives "InitOnceBeginInitialize" => { let [ptr, flags, pending, context] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?; } "InitOnceComplete" => { let [ptr, flags, context] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let result = this.InitOnceComplete(ptr, flags, context)?; this.write_scalar(result, dest)?; } "WaitOnAddress" => { let [ptr_op, compare_op, size_op, timeout_op] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?; } "WakeByAddressSingle" => { let [ptr_op] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.WakeByAddressSingle(ptr_op)?; } "WakeByAddressAll" => { let [ptr_op] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.WakeByAddressAll(ptr_op)?; } @@ -477,7 +484,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetProcAddress" => { #[allow(non_snake_case)] let [hModule, lpProcName] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.read_target_isize(hModule)?; let name = this.read_c_str(this.read_pointer(lpProcName)?)?; if let Ok(name) = str::from_utf8(name) @@ -493,7 +500,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "CreateThread" => { let [security, stacksize, start, arg, flags, thread] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let thread_id = this.CreateThread(security, stacksize, start, arg, flags, thread)?; @@ -502,14 +509,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "WaitForSingleObject" => { let [handle, timeout] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let ret = this.WaitForSingleObject(handle, timeout)?; this.write_scalar(ret, dest)?; } "GetCurrentThread" => { let [] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.write_scalar( Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this), @@ -518,7 +525,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "SetThreadDescription" => { let [handle, name] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let handle = this.read_scalar(handle)?; let name = this.read_wide_str(this.read_pointer(name)?)?; @@ -543,7 +550,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "GetThreadDescription" => { let [handle, name_ptr] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let handle = this.read_scalar(handle)?; let name_ptr = this.deref_pointer(name_ptr)?; // the pointer where we should store the ptr to the name @@ -575,7 +582,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miscellaneous "ExitProcess" => { let [code] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let code = this.read_scalar(code)?.to_u32()?; throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false }); } @@ -583,7 +590,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // used by getrandom 0.1 // This is really 'RtlGenRandom'. let [ptr, len] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; @@ -592,7 +599,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "ProcessPrng" => { // used by `std` let [ptr, len] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; this.gen_random(ptr, len)?; @@ -601,7 +608,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "BCryptGenRandom" => { // used by getrandom 0.2 let [algorithm, ptr, len, flags] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let algorithm = this.read_scalar(algorithm)?; let algorithm = algorithm.to_target_usize(this)?; let ptr = this.read_pointer(ptr)?; @@ -636,7 +643,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. let [console, buffer_info] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.read_target_isize(console)?; // FIXME: this should use deref_pointer_as, but CONSOLE_SCREEN_BUFFER_INFO is not in std this.deref_pointer(buffer_info)?; @@ -646,7 +653,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "GetStdHandle" => { let [which] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `NtWriteFile` which // one it is. This is very fake, but libtest needs it so we cannot make it a @@ -656,7 +663,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "CloseHandle" => { let [handle] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let ret = this.CloseHandle(handle)?; @@ -664,7 +671,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "GetModuleFileNameW" => { let [handle, filename, size] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.check_no_isolation("`GetModuleFileNameW`")?; let handle = this.read_target_usize(handle)?; @@ -698,7 +705,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "FormatMessageW" => { let [flags, module, message_id, language_id, buffer, size, arguments] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; let flags = this.read_scalar(flags)?.to_u32()?; let _module = this.read_pointer(module)?; // seems to contain a module name @@ -734,7 +741,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame_in_std() => { let [] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; // Just fake a HANDLE // It's fine to not use the Handle type here because its a stub this.write_int(1, dest)?; @@ -742,20 +749,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetModuleHandleA" if this.frame_in_std() => { #[allow(non_snake_case)] let [_lpModuleName] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; // We need to return something non-null here to make `compat_fn!` work. this.write_int(1, dest)?; } "SetConsoleTextAttribute" if this.frame_in_std() => { #[allow(non_snake_case)] let [_hConsoleOutput, _wAttribute] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "GetConsoleMode" if this.frame_in_std() => { let [console, mode] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.read_target_isize(console)?; this.deref_pointer(mode)?; // Indicate an error. @@ -764,28 +771,28 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetFileType" if this.frame_in_std() => { #[allow(non_snake_case)] let [_hFile] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; // Return unknown file type. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame_in_std() => { #[allow(non_snake_case)] let [_First, _Handler] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_int(1, dest)?; } "SetThreadStackGuarantee" if this.frame_in_std() => { #[allow(non_snake_case)] let [_StackSizeInBytes] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_int(1, dest)?; } // this is only callable from std because we know that std ignores the return value "SwitchToThread" if this.frame_in_std() => { let [] = - this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; + this.check_shim(abi, sys_conv, link_name, args)?; this.yield_active_thread(); @@ -805,7 +812,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // This function looks and behaves excatly like miri_start_unwind. let [payload] = - this.check_shim(abi, ExternAbi::C { unwind: true }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.handle_miri_start_unwind(payload)?; return interp_ok(EmulateItemResult::NeedsUnwind); } diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs index 4c6c1cefeb1df..a89a2bb0cd082 100644 --- a/src/tools/miri/src/shims/x86/aesni.rs +++ b/src/tools/miri/src/shims/x86/aesni.rs @@ -1,7 +1,7 @@ -use rustc_abi::ExternAbi; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf as _; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use crate::*; @@ -10,7 +10,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_aesni_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -27,8 +27,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec_si128 "aesdec" | "aesdec.256" | "aesdec.512" => { let [state, key] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - + this.check_shim(abi, Conv::C, link_name, args)?; aes_round(this, state, key, dest, |state, key| { let key = aes::Block::from(key.to_le_bytes()); let mut state = aes::Block::from(state.to_le_bytes()); @@ -45,7 +44,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdeclast_si128 "aesdeclast" | "aesdeclast.256" | "aesdeclast.512" => { let [state, key] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; aes_round(this, state, key, dest, |state, key| { let mut state = aes::Block::from(state.to_le_bytes()); @@ -70,8 +69,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc_si128 "aesenc" | "aesenc.256" | "aesenc.512" => { let [state, key] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - + this.check_shim(abi, Conv::C, link_name, args)?; aes_round(this, state, key, dest, |state, key| { let key = aes::Block::from(key.to_le_bytes()); let mut state = aes::Block::from(state.to_le_bytes()); @@ -88,8 +86,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128 "aesenclast" | "aesenclast.256" | "aesenclast.512" => { let [state, key] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - + this.check_shim(abi, Conv::C, link_name, args)?; aes_round(this, state, key, dest, |state, key| { let mut state = aes::Block::from(state.to_le_bytes()); // `aes::hazmat::cipher_round` does the following operations: @@ -109,8 +106,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm_aesimc_si128 function. // Performs the AES InvMixColumns operation on `op` "aesimc" => { - let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - + let [op] = this.check_shim(abi, Conv::C, link_name, args)?; // Transmute to `u128` let op = op.transmute(this.machine.layouts.u128, this)?; let dest = dest.transmute(this.machine.layouts.u128, this)?; diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs index 3971fa3b913f4..07bbd0731d81c 100644 --- a/src/tools/miri/src/shims/x86/avx.rs +++ b/src/tools/miri/src/shims/x86/avx.rs @@ -1,9 +1,9 @@ -use rustc_abi::ExternAbi; use rustc_apfloat::ieee::{Double, Single}; use rustc_middle::mir; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf as _; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use super::{ FloatBinOp, FloatUnaryOp, bin_op_simd_float_all, conditional_dot_product, convert_float_to_int, @@ -17,7 +17,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_avx_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -34,7 +34,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // semantics. "min.ps.256" | "max.ps.256" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "min.ps.256" => FloatBinOp::Min, @@ -47,7 +47,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement _mm256_min_pd and _mm256_max_pd functions. "min.pd.256" | "max.pd.256" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "min.pd.256" => FloatBinOp::Min, @@ -61,7 +61,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Rounds the elements of `op` according to `rounding`. "round.ps.256" => { let [op, rounding] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; round_all::(this, op, rounding, dest)?; } @@ -69,14 +69,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Rounds the elements of `op` according to `rounding`. "round.pd.256" => { let [op, rounding] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; round_all::(this, op, rounding, dest)?; } // Used to implement _mm256_{rcp,rsqrt}_ps functions. // Performs the operations on all components of `op`. "rcp.ps.256" | "rsqrt.ps.256" => { - let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [op] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "rcp.ps.256" => FloatUnaryOp::Rcp, @@ -89,7 +89,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm256_dp_ps function. "dp.ps.256" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; conditional_dot_product(this, left, right, imm, dest)?; } @@ -98,7 +98,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // in `left` and `right`. "hadd.ps.256" | "hadd.pd.256" | "hsub.ps.256" | "hsub.pd.256" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "hadd.ps.256" | "hadd.pd.256" => mir::BinOp::Add, @@ -114,7 +114,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // if true. "cmp.ps.256" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -127,7 +127,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // if true. "cmp.pd.256" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -138,7 +138,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // and _mm256_cvttpd_epi32 functions. // Converts packed f32/f64 to packed i32. "cvt.ps2dq.256" | "cvtt.ps2dq.256" | "cvt.pd2dq.256" | "cvtt.pd2dq.256" => { - let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [op] = this.check_shim(abi, Conv::C, link_name, args)?; let rnd = match unprefixed_name { // "current SSE rounding mode", assume nearest @@ -157,7 +157,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `control` determines which element of the current `data` array is written. "vpermilvar.ps" | "vpermilvar.ps.256" => { let [data, control] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (data, data_len) = this.project_to_simd(data)?; let (control, control_len) = this.project_to_simd(control)?; @@ -191,7 +191,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // written. "vpermilvar.pd" | "vpermilvar.pd.256" => { let [data, control] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (data, data_len) = this.project_to_simd(data)?; let (control, control_len) = this.project_to_simd(control)?; @@ -224,7 +224,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // zero, according to `imm`. "vperm2f128.ps.256" | "vperm2f128.pd.256" | "vperm2f128.si.256" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; assert_eq!(dest.layout, left.layout); assert_eq!(dest.layout, right.layout); @@ -268,7 +268,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // loaded. "maskload.ps" | "maskload.pd" | "maskload.ps.256" | "maskload.pd.256" => { let [ptr, mask] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; mask_load(this, ptr, mask, dest)?; } @@ -279,7 +279,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores. "maskstore.ps" | "maskstore.pd" | "maskstore.ps.256" | "maskstore.pd.256" => { let [ptr, mask, value] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; mask_store(this, ptr, mask, value)?; } @@ -290,7 +290,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // unaligned read. "ldu.dq.256" => { let [src_ptr] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let src_ptr = this.read_pointer(src_ptr)?; let dest = dest.force_mplace(this)?; @@ -303,7 +303,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `op & mask != 0 && op & mask != mask` "ptestz.256" | "ptestc.256" | "ptestnzc.256" => { let [op, mask] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (all_zero, masked_set) = test_bits_masked(this, op, mask)?; let res = match unprefixed_name { @@ -327,7 +327,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "vtestnzc.pd" | "vtestz.ps.256" | "vtestc.ps.256" | "vtestnzc.ps.256" | "vtestz.ps" | "vtestc.ps" | "vtestnzc.ps" => { let [op, mask] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (direct, negated) = test_high_bits_masked(this, op, mask)?; let res = match unprefixed_name { @@ -349,7 +349,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // compiler, making these functions no-ops. // The only thing that needs to be ensured is the correct calling convention. - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; } _ => return interp_ok(EmulateItemResult::NotSupported), } diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs index 6aefb87d4d0e1..76e4b06d5cfd2 100644 --- a/src/tools/miri/src/shims/x86/avx2.rs +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -1,8 +1,8 @@ -use rustc_abi::ExternAbi; use rustc_middle::mir; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf as _; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use super::{ ShiftOp, horizontal_bin_op, int_abs, mask_load, mask_store, mpsadbw, packssdw, packsswb, @@ -15,7 +15,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_avx2_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -28,7 +28,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm256_abs_epi{8,16,32} functions. // Calculates the absolute value of packed 8/16/32-bit integers. "pabs.b" | "pabs.w" | "pabs.d" => { - let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [op] = this.check_shim(abi, Conv::C, link_name, args)?; int_abs(this, op, dest)?; } @@ -37,7 +37,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // integer values in `left` and `right`. "phadd.w" | "phadd.sw" | "phadd.d" | "phsub.w" | "phsub.sw" | "phsub.d" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (which, saturating) = match unprefixed_name { "phadd.w" | "phadd.d" => (mir::BinOp::Add, false), @@ -58,7 +58,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "gather.d.pd.256" | "gather.q.pd" | "gather.q.pd.256" | "gather.d.ps" | "gather.d.ps.256" | "gather.q.ps" | "gather.q.ps.256" => { let [src, slice, offsets, mask, scale] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; assert_eq!(dest.layout, src.layout); @@ -116,7 +116,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // intermediate 32-bit integers, and pack the results in `dest`. "pmadd.wd" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -153,7 +153,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // produces the output at index `i`. "pmadd.ub.sw" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -188,7 +188,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // loaded. "maskload.d" | "maskload.q" | "maskload.d.256" | "maskload.q.256" => { let [ptr, mask] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; mask_load(this, ptr, mask, dest)?; } @@ -199,7 +199,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores. "maskstore.d" | "maskstore.q" | "maskstore.d.256" | "maskstore.q.256" => { let [ptr, mask, value] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; mask_store(this, ptr, mask, value)?; } @@ -211,7 +211,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mpsadbw_epu8 "mpsadbw" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; mpsadbw(this, left, right, imm, dest)?; } @@ -223,7 +223,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16 "pmul.hr.sw" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; pmulhrsw(this, left, right, dest)?; } @@ -232,7 +232,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // vector with signed saturation. "packsswb" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; packsswb(this, left, right, dest)?; } @@ -241,7 +241,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // vector with signed saturation. "packssdw" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; packssdw(this, left, right, dest)?; } @@ -250,7 +250,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // unsigned integer vector with saturation. "packuswb" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; packuswb(this, left, right, dest)?; } @@ -259,7 +259,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the result to a 16-bit unsigned integer vector with saturation. "packusdw" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; packusdw(this, left, right, dest)?; } @@ -269,7 +269,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // as indices. "permd" | "permps" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -290,7 +290,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Shuffles 128-bit blocks of `a` and `b` using `imm` as pattern. "vperm2i128" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; assert_eq!(left.layout.size.bits(), 256); assert_eq!(right.layout.size.bits(), 256); @@ -328,7 +328,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sad_epu8 "psad.bw" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -361,7 +361,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Each 128-bit block is shuffled independently. "pshuf.b" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -393,7 +393,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Basically, we multiply `left` with `right.signum()`. "psign.b" | "psign.w" | "psign.d" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; psign(this, left, right, dest)?; } @@ -408,7 +408,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q" | "psrl.q" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left, @@ -424,7 +424,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" | "psrlv.d" | "psrlv.d.256" | "psrlv.q" | "psrlv.q.256" | "psrav.d" | "psrav.d.256" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" => ShiftOp::Left, diff --git a/src/tools/miri/src/shims/x86/bmi.rs b/src/tools/miri/src/shims/x86/bmi.rs index 0f9e8d6f0258c..b528076473841 100644 --- a/src/tools/miri/src/shims/x86/bmi.rs +++ b/src/tools/miri/src/shims/x86/bmi.rs @@ -1,5 +1,6 @@ -use rustc_abi::ExternAbi; use rustc_span::Symbol; +use rustc_middle::ty::Ty; +use rustc_target::callconv::{Conv, FnAbi}; use crate::*; @@ -8,7 +9,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_bmi_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -34,7 +35,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let left = this.read_scalar(left)?; let right = this.read_scalar(right)?; diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs index 92010345f55dd..48718ea609c4f 100644 --- a/src/tools/miri/src/shims/x86/gfni.rs +++ b/src/tools/miri/src/shims/x86/gfni.rs @@ -1,5 +1,6 @@ -use rustc_abi::ExternAbi; use rustc_span::Symbol; +use rustc_middle::ty::Ty; +use rustc_target::callconv::{Conv, FnAbi}; use crate::*; @@ -8,7 +9,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_gfni_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -30,7 +31,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affine_ "vgf2p8affineqb.128" | "vgf2p8affineqb.256" | "vgf2p8affineqb.512" => { let [left, right, imm8] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; affine_transform(this, left, right, imm8, dest, /* inverse */ false)?; } // Used to implement the `_mm{, 256, 512}_gf2p8affineinv_epi64_epi8` functions. @@ -38,7 +39,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affineinv "vgf2p8affineinvqb.128" | "vgf2p8affineinvqb.256" | "vgf2p8affineinvqb.512" => { let [left, right, imm8] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; affine_transform(this, left, right, imm8, dest, /* inverse */ true)?; } // Used to implement the `_mm{, 256, 512}_gf2p8mul_epi8` functions. @@ -48,8 +49,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul "vgf2p8mulb.128" | "vgf2p8mulb.256" | "vgf2p8mulb.512" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; let (dest, dest_len) = this.project_to_simd(dest)?; diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 3e02a4b363769..13439f421286c 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1,10 +1,11 @@ -use rustc_abi::{ExternAbi, Size}; +use rustc_abi::Size; use rustc_apfloat::Float; use rustc_apfloat::ieee::Single; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::{mir, ty}; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use self::helpers::bool_to_simd_element; use crate::*; @@ -27,7 +28,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -45,8 +46,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(EmulateItemResult::NotSupported); } - let [cb_in, a, b] = this.check_shim(abi, ExternAbi::Unadjusted, link_name, args)?; - + let [cb_in, a, b] = this.check_shim(abi, Conv::C, link_name, args)?; let op = if unprefixed_name.starts_with("add") { mir::BinOp::AddWithOverflow } else { @@ -68,9 +68,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if is_u64 && this.tcx.sess.target.arch != "x86_64" { return interp_ok(EmulateItemResult::NotSupported); } - let [c_in, a, b, out] = - this.check_shim(abi, ExternAbi::Unadjusted, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let out = this.deref_pointer_as( out, if is_u64 { this.machine.layouts.u64 } else { this.machine.layouts.u32 }, @@ -87,7 +86,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the instruction behaves like a no-op, so it is always safe to call the // intrinsic. "sse2.pause" => { - let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; // Only exhibit the spin-loop hint behavior when SSE2 is enabled. if this.tcx.sess.unstable_target_features.contains(&Symbol::intern("sse2")) { this.yield_active_thread(); @@ -107,7 +106,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; pclmulqdq(this, left, right, imm, dest, len)?; } diff --git a/src/tools/miri/src/shims/x86/sha.rs b/src/tools/miri/src/shims/x86/sha.rs index f18ff1ec253b8..07cc87a35bf5c 100644 --- a/src/tools/miri/src/shims/x86/sha.rs +++ b/src/tools/miri/src/shims/x86/sha.rs @@ -4,8 +4,9 @@ //! //! [RustCrypto's sha256 module]: https://github.com/RustCrypto/hashes/blob/6be8466247e936c415d8aafb848697f39894a386/sha2/src/sha256/soft.rs -use rustc_abi::ExternAbi; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use crate::*; @@ -14,7 +15,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sha_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -52,7 +53,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm_sha256rnds2_epu32 function. "256rnds2" => { let [a, b, k] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (a_reg, a_len) = this.project_to_simd(a)?; let (b_reg, b_len) = this.project_to_simd(b)?; @@ -74,7 +75,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm_sha256msg1_epu32 function. "256msg1" => { let [a, b] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (a_reg, a_len) = this.project_to_simd(a)?; let (b_reg, b_len) = this.project_to_simd(b)?; @@ -93,7 +94,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm_sha256msg2_epu32 function. "256msg2" => { let [a, b] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (a_reg, a_len) = this.project_to_simd(a)?; let (b_reg, b_len) = this.project_to_simd(b)?; diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index 9432b40a80585..e13265fba4f0d 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -1,6 +1,7 @@ -use rustc_abi::ExternAbi; use rustc_apfloat::ieee::Single; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use super::{ FloatBinOp, FloatUnaryOp, bin_op_simd_float_all, bin_op_simd_float_first, unary_op_ps, @@ -13,7 +14,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -33,7 +34,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `right` and copies the remaining components from `left`. "min.ss" | "max.ss" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "min.ss" => FloatBinOp::Min, @@ -50,7 +51,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // semantics. "min.ps" | "max.ps" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "min.ps" => FloatBinOp::Min, @@ -64,7 +65,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Performs the operations on the first component of `op` and // copies the remaining components from `op`. "rcp.ss" | "rsqrt.ss" => { - let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [op] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "rcp.ss" => FloatUnaryOp::Rcp, @@ -77,7 +78,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement _mm_{sqrt,rcp,rsqrt}_ps functions. // Performs the operations on all components of `op`. "rcp.ps" | "rsqrt.ps" => { - let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [op] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "rcp.ps" => FloatUnaryOp::Rcp, @@ -97,7 +98,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // with hard-coded operations. "cmp.ss" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -114,7 +115,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // with hard-coded operations. "cmp.ps" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -128,7 +129,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "ucomieq.ss" | "ucomilt.ss" | "ucomile.ss" | "ucomigt.ss" | "ucomige.ss" | "ucomineq.ss" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -156,7 +157,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cvtss_si64 and _mm_cvttss_si64 functions. // Converts the first component of `op` from f32 to i32/i64. "cvtss2si" | "cvttss2si" | "cvtss2si64" | "cvttss2si64" => { - let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [op] = this.check_shim(abi, Conv::C, link_name, args)?; let (op, _) = this.project_to_simd(op)?; let op = this.read_immediate(&this.project_index(&op, 0)?)?; @@ -185,7 +186,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.felixcloutier.com/x86/cvtsi2ss "cvtsi2ss" | "cvtsi642ss" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (dest, dest_len) = this.project_to_simd(dest)?; diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index 4ff999be7cc91..959590e9791fd 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -1,6 +1,7 @@ -use rustc_abi::ExternAbi; use rustc_apfloat::ieee::Double; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use super::{ FloatBinOp, ShiftOp, bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, @@ -13,7 +14,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse2_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -40,7 +41,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // intermediate 32-bit integers, and pack the results in `dest`. "pmadd.wd" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -79,7 +80,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sad_epu8 "psad.bw" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -118,7 +119,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q" | "psrl.q" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left, @@ -133,7 +134,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // and _mm_cvttpd_epi32 functions. // Converts packed f32/f64 to packed i32. "cvtps2dq" | "cvttps2dq" | "cvtpd2dq" | "cvttpd2dq" => { - let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [op] = this.check_shim(abi, Conv::C, link_name, args)?; let (op_len, _) = op.layout.ty.simd_size_and_type(*this.tcx); let (dest_len, _) = dest.layout.ty.simd_size_and_type(*this.tcx); @@ -171,7 +172,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // vector with signed saturation. "packsswb.128" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; packsswb(this, left, right, dest)?; } @@ -180,7 +181,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // unsigned integer vector with saturation. "packuswb.128" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; packuswb(this, left, right, dest)?; } @@ -189,7 +190,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // vector with signed saturation. "packssdw.128" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; packssdw(this, left, right, dest)?; } @@ -200,7 +201,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // semantics. "min.sd" | "max.sd" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "min.sd" => FloatBinOp::Min, @@ -217,7 +218,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // semantics. "min.pd" | "max.pd" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "min.pd" => FloatBinOp::Min, @@ -237,7 +238,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // with hard-coded operations. "cmp.sd" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -254,7 +255,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // with hard-coded operations. "cmp.pd" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -268,7 +269,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "ucomieq.sd" | "ucomilt.sd" | "ucomile.sd" | "ucomigt.sd" | "ucomige.sd" | "ucomineq.sd" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -296,7 +297,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cvtsd_si64 and _mm_cvttsd_si64 functions. // Converts the first component of `op` from f64 to i32/i64. "cvtsd2si" | "cvttsd2si" | "cvtsd2si64" | "cvttsd2si64" => { - let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [op] = this.check_shim(abi, Conv::C, link_name, args)?; let (op, _) = this.project_to_simd(op)?; let op = this.read_immediate(&this.project_index(&op, 0)?)?; @@ -323,7 +324,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the remaining elements from `left` "cvtsd2ss" | "cvtss2sd" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, _) = this.project_to_simd(right)?; diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs index 86153d71b284c..4ebd0240b1d3e 100644 --- a/src/tools/miri/src/shims/x86/sse3.rs +++ b/src/tools/miri/src/shims/x86/sse3.rs @@ -1,6 +1,7 @@ -use rustc_abi::ExternAbi; use rustc_middle::mir; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use super::horizontal_bin_op; use crate::*; @@ -10,7 +11,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse3_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -25,7 +26,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // in `left` and `right`. "hadd.ps" | "hadd.pd" | "hsub.ps" | "hsub.pd" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "hadd.ps" | "hadd.pd" => mir::BinOp::Add, @@ -42,7 +43,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // unaligned read. "ldu.dq" => { let [src_ptr] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let src_ptr = this.read_pointer(src_ptr)?; let dest = dest.force_mplace(this)?; diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs index b81d6f24141bf..41b7feab857bb 100644 --- a/src/tools/miri/src/shims/x86/sse41.rs +++ b/src/tools/miri/src/shims/x86/sse41.rs @@ -1,5 +1,6 @@ -use rustc_abi::ExternAbi; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use super::{conditional_dot_product, mpsadbw, packusdw, round_all, round_first, test_bits_masked}; use crate::*; @@ -9,7 +10,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse41_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -27,7 +28,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `i` is zeroed. "insertps" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -63,7 +64,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the result to a 16-bit unsigned integer vector with saturation. "packusdw" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; packusdw(this, left, right, dest)?; } @@ -74,7 +75,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // 4 bits of `imm`. "dpps" | "dppd" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; conditional_dot_product(this, left, right, imm, dest)?; } @@ -83,7 +84,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // and copies the remaining elements from `left`. "round.ss" => { let [left, right, rounding] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; round_first::(this, left, right, rounding, dest)?; } @@ -91,7 +92,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // functions. Rounds the elements of `op` according to `rounding`. "round.ps" => { let [op, rounding] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; round_all::(this, op, rounding, dest)?; } @@ -100,7 +101,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // and copies the remaining elements from `left`. "round.sd" => { let [left, right, rounding] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; round_first::(this, left, right, rounding, dest)?; } @@ -108,7 +109,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // functions. Rounds the elements of `op` according to `rounding`. "round.pd" => { let [op, rounding] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; round_all::(this, op, rounding, dest)?; } @@ -116,7 +117,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Find the minimum unsinged 16-bit integer in `op` and // returns its value and position. "phminposuw" => { - let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [op] = this.check_shim(abi, Conv::C, link_name, args)?; let (op, op_len) = this.project_to_simd(op)?; let (dest, dest_len) = this.project_to_simd(dest)?; @@ -151,7 +152,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mpsadbw_epu8 "mpsadbw" => { let [left, right, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; mpsadbw(this, left, right, imm, dest)?; } @@ -161,7 +162,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `(op & mask) != 0 && (op & mask) != mask` "ptestz" | "ptestc" | "ptestnzc" => { let [op, mask] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (all_zero, masked_set) = test_bits_masked(this, op, mask)?; let res = match unprefixed_name { diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs index 0b058a9911e2a..6ac69d22a9340 100644 --- a/src/tools/miri/src/shims/x86/sse42.rs +++ b/src/tools/miri/src/shims/x86/sse42.rs @@ -1,8 +1,9 @@ -use rustc_abi::{ExternAbi, Size}; +use rustc_abi::Size; use rustc_middle::mir; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf as _; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use crate::*; @@ -200,7 +201,7 @@ fn deconstruct_args<'tcx>( unprefixed_name: &str, ecx: &mut MiriInterpCx<'tcx>, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], ) -> InterpResult<'tcx, (OpTy<'tcx>, OpTy<'tcx>, Option<(u64, u64)>, u8)> { let array_layout_fn = |ecx: &mut MiriInterpCx<'tcx>, imm: u8| { @@ -223,7 +224,7 @@ fn deconstruct_args<'tcx>( if is_explicit { let [str1, len1, str2, len2, imm] = - ecx.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + ecx.check_shim(abi, Conv::C, link_name, args)?; let imm = ecx.read_scalar(imm)?.to_u8()?; let default_len = default_len::(imm); @@ -237,7 +238,7 @@ fn deconstruct_args<'tcx>( interp_ok((str1, str2, Some((len1, len2)), imm)) } else { let [str1, str2, imm] = - ecx.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + ecx.check_shim(abi, Conv::C, link_name, args)?; let imm = ecx.read_scalar(imm)?.to_u8()?; let array_layout = array_layout_fn(ecx, imm)?; @@ -279,7 +280,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse42_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -388,7 +389,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=924,925 "pcmpistriz128" | "pcmpistris128" => { let [str1, str2, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let imm = this.read_scalar(imm)?.to_u8()?; let str = if unprefixed_name == "pcmpistris128" { str1 } else { str2 }; @@ -409,7 +410,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=1046,1047 "pcmpestriz128" | "pcmpestris128" => { let [_, len1, _, len2, imm] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let len = if unprefixed_name == "pcmpestris128" { len1 } else { len2 }; let len = this.read_scalar(len)?.to_i32()?; let imm = this.read_scalar(imm)?.to_u8()?; @@ -437,7 +438,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let left = this.read_scalar(left)?; let right = this.read_scalar(right)?; diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs index cdab78bc7427a..d3971d0c92f1d 100644 --- a/src/tools/miri/src/shims/x86/ssse3.rs +++ b/src/tools/miri/src/shims/x86/ssse3.rs @@ -1,6 +1,7 @@ -use rustc_abi::ExternAbi; use rustc_middle::mir; +use rustc_middle::ty::Ty; use rustc_span::Symbol; +use rustc_target::callconv::{Conv, FnAbi}; use super::{horizontal_bin_op, int_abs, pmulhrsw, psign}; use crate::*; @@ -10,7 +11,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_ssse3_intrinsic( &mut self, link_name: Symbol, - abi: ExternAbi, + abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { @@ -23,7 +24,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm_abs_epi{8,16,32} functions. // Calculates the absolute value of packed 8/16/32-bit integers. "pabs.b.128" | "pabs.w.128" | "pabs.d.128" => { - let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let [op] = this.check_shim(abi, Conv::C, link_name, args)?; int_abs(this, op, dest)?; } @@ -32,7 +33,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_epi8 "pshuf.b.128" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -62,7 +63,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "phadd.w.128" | "phadd.sw.128" | "phadd.d.128" | "phsub.w.128" | "phsub.sw.128" | "phsub.d.128" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (which, saturating) = match unprefixed_name { "phadd.w.128" | "phadd.d.128" => (mir::BinOp::Add, false), @@ -82,7 +83,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_maddubs_epi16 "pmadd.ub.sw.128" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -118,7 +119,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhrs_epi16 "pmul.hr.sw.128" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; pmulhrsw(this, left, right, dest)?; } @@ -129,7 +130,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Basically, we multiply `left` with `right.signum()`. "psign.b.128" | "psign.w.128" | "psign.d.128" => { let [left, right] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; psign(this, left, right, dest)?; } diff --git a/tests/coverage/unused_mod.cov-map b/tests/coverage/unused_mod.cov-map index af10906fa3c54..5e8b69fcdba9f 100644 --- a/tests/coverage/unused_mod.cov-map +++ b/tests/coverage/unused_mod.cov-map @@ -1,16 +1,16 @@ Function name: unused_mod::main -Raw bytes (9): 0x[01, 02, 00, 01, 01, 04, 01, 02, 02] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 01, 02, 02] Number of files: 1 -- file 0 => global file 2 +- file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 4, 1) to (start + 2, 2) Highest counter ID seen: c0 Function name: unused_mod::unused_module::never_called_function (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 02, 01, 02, 02] +Raw bytes (9): 0x[01, 02, 00, 01, 00, 02, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => global file 2 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 2, 1) to (start + 2, 2) diff --git a/tests/ui/bootstrap/self-test/a.rs b/tests/ui/bootstrap/self-test/a.rs new file mode 100644 index 0000000000000..64d2d6f11bbdd --- /dev/null +++ b/tests/ui/bootstrap/self-test/a.rs @@ -0,0 +1,2 @@ +//! Not used by compiler, this is used by bootstrap cli self-test. +//@ ignore-test diff --git a/tests/ui/bootstrap/self-test/b.rs b/tests/ui/bootstrap/self-test/b.rs new file mode 100644 index 0000000000000..91f92f67910b7 --- /dev/null +++ b/tests/ui/bootstrap/self-test/b.rs @@ -0,0 +1,2 @@ +//! Not used by compiler, used by bootstrap cli self-test. +//@ ignore-test diff --git a/tests/ui/impl-trait/rpit/inherits-lifetime.rs b/tests/ui/impl-trait/rpit/inherits-lifetime.rs new file mode 100644 index 0000000000000..60c2a96c8737b --- /dev/null +++ b/tests/ui/impl-trait/rpit/inherits-lifetime.rs @@ -0,0 +1,24 @@ +//! Check that lifetimes are inherited in RPIT. +//! Previously, the hidden lifetime of T::Bar would be overlooked +//! and would instead end up as >::Bar. +//! +//! Regression test for . + +//@ check-pass + +trait Foo<'a> { + type Bar; +} + +impl<'a> Foo<'a> for u32 { + type Bar = &'a (); +} + +fn baz<'a, T>() -> impl IntoIterator +where + T: Foo<'a>, +{ + None +} + +fn main() {}