diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs index c1dfe1ef85600..e098c9039ee2f 100644 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs +++ b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs @@ -50,7 +50,7 @@ impl<'tcx> FunctionCoverage<'tcx> { } fn create(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, is_used: bool) -> Self { - let coverageinfo = tcx.coverageinfo(instance.def); + let coverageinfo = tcx.coverageinfo(instance); debug!( "FunctionCoverage::create(instance={:?}) has coverageinfo={:?}. is_used={}", instance, coverageinfo, is_used diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 2cb28d7361c33..233262ed91d1f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -611,9 +611,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize; let mut llargs = Vec::with_capacity(arg_count); + // Custom intrinsics are treated as-if they were normal functions here. + let is_custom_intrinsic = intrinsic.and_then(|_| instance ) + .map(|instance| bx.tcx().custom_intrinsic_mir(instance).is_some() ) + .unwrap_or_default(); + // Prepare the return value destination let ret_dest = if let Some((dest, _)) = *destination { - let is_intrinsic = intrinsic.is_some(); + let is_intrinsic = intrinsic.is_some() && !is_custom_intrinsic; self.make_return_dest(&mut bx, dest, &fn_abi.ret, &mut llargs, is_intrinsic) } else { ReturnDest::Nothing @@ -636,6 +641,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match intrinsic { None | Some(sym::drop_in_place) => {} Some(sym::copy_nonoverlapping) => unreachable!(), + Some(_intrinsic) if is_custom_intrinsic => { }, Some(intrinsic) => { let dest = match ret_dest { _ if fn_abi.ret.is_indirect() => llargs[0], diff --git a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs index a283bf1de763a..5b2e7f07daaf2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs @@ -31,7 +31,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.add_coverage_counter(instance, id, code_region); } - let coverageinfo = bx.tcx().coverageinfo(instance.def); + let coverageinfo = bx.tcx().coverageinfo(instance); let fn_name = bx.get_pgo_func_name_var(instance); let hash = bx.const_u64(function_source_hash); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 3bbc481b61093..fcc010fbcf9b1 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -137,7 +137,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let llfn = cx.get_fn(instance); - let mir = cx.tcx().instance_mir(instance.def); + let mir = cx.tcx().instance_mir(instance); let fn_abi = FnAbi::of_instance(cx, instance, &[]); debug!("fn_abi: {:?}", fn_abi); diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 722ce6b636726..cf33fd707cf1d 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -21,6 +21,7 @@ use crate::owning_ref::{Erased, OwningRef}; use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; use std::ops::{Deref, DerefMut}; +use std::sync::{Arc, atomic::AtomicPtr, atomic, }; pub use std::sync::atomic::Ordering; pub use std::sync::atomic::Ordering::SeqCst; @@ -598,3 +599,55 @@ impl DerefMut for OneThread { &mut self.inner } } + +/// Provides atomic mutability by replacing the value inside this `ArcCell`. +/// Similar to the `crossbeam` structure of the same name. +#[derive(Debug)] +pub struct ArcCell(AtomicPtr); +impl ArcCell { + pub fn new(v: Arc) -> Self { + ArcCell(AtomicPtr::new(Arc::into_raw(v) as *mut _)) + } + pub fn get(&self) -> Arc { + let ptr = self.0.load(atomic::Ordering::Acquire); + let arc = unsafe { Arc::from_raw(ptr as *const T) }; + let ret = arc.clone(); + // don't drop our copy: + ::std::mem::forget(arc); + ret + } + /// Update the value, returning the previous value. + pub fn set(&self, v: Arc) -> Arc { + let new = Arc::into_raw(v) as *mut _; + let mut expected = self.0.load(atomic::Ordering::Acquire); + loop { + match self.0.compare_exchange_weak(expected, new, + atomic::Ordering::SeqCst, + atomic::Ordering::Acquire) { + Ok(old) => { + return unsafe { Arc::from_raw(old as *const T) }; + }, + Err(v) => { + expected = v; + }, + } + } + } +} +impl Drop for ArcCell { + fn drop(&mut self) { + let ptr = self.0.load(atomic::Ordering::Acquire); + // drop our copy of the arc: + unsafe { Arc::from_raw(ptr as *const _) }; + } +} +impl Clone for ArcCell { + fn clone(&self) -> Self { + ArcCell::new(self.get()) + } +} +impl From> for ArcCell { + fn from(v: Arc) -> Self { + Self::new(v) + } +} diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index aa54d1ae7b9d1..9f0af8ffc961f 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -285,10 +285,10 @@ pub type DepNode = rustc_query_system::dep_graph::DepNode; // required that their size stay the same, but we don't want to change // it inadvertently. This assert just ensures we're aware of any change. #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -static_assert_size!(DepNode, 17); +static_assert_size!(DepNode, 18); #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -static_assert_size!(DepNode, 24); +static_assert_size!(DepNode, 25); pub trait DepNodeExt: Sized { /// Construct a DepNode from the given DepKind and DefPathHash. This diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0daaec272fd90..ae1ed7eb8c63f 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2900,3 +2900,33 @@ impl Location { } } } + +pub trait CustomIntrinsicMirGen: Sync + Send + fmt::Debug { + /// Codegen a plugin-defined intrinsic. This is intended to be used to + /// "return" values based on the monomorphized and erased types of the + /// function call. Codegen will codegen the `extra_stmts` and then insert + /// an unconditional branch to the exit block. + /// + /// Consider this to be highly unstable; it will likely change without + /// warning. There is also no spec for this, it is 100% implementation + /// defined, and may not be implemented at all for some codegen backends. + /// + /// If the codegen backend is multithreaded, this will be called from + /// any number of threads, hence `Sync + Send`. + /// + /// YOU ARE RESPONSIBLE FOR THE SAFETY OF THE EXTRA STATEMENTS. + /// You have been warned. Good luck, have fun. + fn mirgen_simple_intrinsic<'tcx>(&self, + tcx: TyCtxt<'tcx>, + instance: ty::Instance<'tcx>, + mir: &mut Body<'tcx>); + + /// The following are used for typeck-ing: + + /// The number of generic parameters expected. + fn generic_parameter_count<'tcx>(&self, tcx: TyCtxt<'tcx>) -> usize; + /// The types of the input args. + fn inputs<'tcx>(&self, tcx: TyCtxt<'tcx>) -> &'tcx List>; + /// The return type. + fn output<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; +} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index dda407940e3c3..93a9870468b72 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -338,7 +338,7 @@ rustc_queries! { /// Returns coverage summary info for a function, after executing the `InstrumentCoverage` /// MIR pass (assuming the -Zinstrument-coverage option is enabled). - query coverageinfo(key: ty::InstanceDef<'tcx>) -> mir::CoverageInfo { + query coverageinfo(key: ty::Instance<'tcx>) -> mir::CoverageInfo { desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) } storage(ArenaCacheSelector<'tcx>) } @@ -363,6 +363,20 @@ rustc_queries! { storage(ArenaCacheSelector<'tcx>) cache_on_disk_if { key.is_local() } } + /// If defined by the driver, returns the extra mir statements to codegen, + /// else returns `None`. + query custom_intrinsic_mirgen(key: DefId) -> Option> { + anon + no_hash + + desc { |tcx| "asking for the custom MIR generator of `{}`", tcx.def_path_str(key) } + } + /// The monomorphized MIR for a custom intrinsic instance. + query custom_intrinsic_mir(inst: ty::Instance<'tcx>) -> Option<&'tcx mir::Body<'tcx>> { + anon + + desc { |tcx| "asking for the custom MIR of `{}`", tcx.def_path_str(inst.def_id()) } + } /// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own /// `DefId`. This function returns all promoteds in the specified body. The body references @@ -782,7 +796,7 @@ rustc_queries! { } /// Obtain all the calls into other local functions - query mir_inliner_callees(key: ty::InstanceDef<'tcx>) -> &'tcx [(DefId, SubstsRef<'tcx>)] { + query mir_inliner_callees(key: ty::Instance<'tcx>) -> &'tcx [(DefId, SubstsRef<'tcx>)] { fatal_cycle desc { |tcx| "computing all local function calls in `{}`", diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a2abbec74927c..b0c8352a82a47 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1779,8 +1779,8 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair. - pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> { - match instance { + pub fn instance_mir(self, instance: ty::Instance<'tcx>) -> &'tcx Body<'tcx> { + match instance.def { ty::InstanceDef::Item(def) => match self.def_kind(def.did) { DefKind::Const | DefKind::Static @@ -1794,14 +1794,20 @@ impl<'tcx> TyCtxt<'tcx> { self.optimized_mir(def.did) } }, + ty::InstanceDef::Intrinsic(..) => { + if let Some(mir) = self.custom_intrinsic_mir(instance) { + mir + } else { + self.mir_shims(instance.def) + } + }, ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::Virtual(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::CloneShim(..) => self.mir_shims(instance), + | ty::InstanceDef::CloneShim(..) => self.mir_shims(instance.def), } } diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 536dbad4f764d..c646ce992e91b 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -306,7 +306,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( MemoryExtra { can_access_statics: is_static }, ); - let res = ecx.load_mir(cid.instance.def, cid.promoted); + let res = ecx.load_mir(cid.instance, cid.promoted); match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) { Err(error) => { let err = ConstEvalErr::new(&ecx, error, None); diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 773df7d7b60c1..cf8073f8e7e09 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -203,9 +203,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, fn load_mir( ecx: &InterpCx<'mir, 'tcx, Self>, - instance: ty::InstanceDef<'tcx>, + instance: ty::Instance<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { - match instance { + match instance.def { ty::InstanceDef::Item(def) => { if ecx.tcx.is_ctfe_mir_available(def.did) { Ok(ecx.tcx.mir_for_ctfe_opt_const_arg(def)) @@ -242,7 +242,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } } // This is a const fn. Call it. - Ok(Some(match ecx.load_mir(instance.def, None) { + Ok(Some(match ecx.load_mir(instance, None) { Ok(body) => body, Err(err) => { if let err_unsup!(NoMirFor(did)) = err.kind() { diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 6f7519e61561b..433e13cf700b7 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -485,11 +485,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn load_mir( &self, - instance: ty::InstanceDef<'tcx>, + instance: ty::Instance<'tcx>, promoted: Option, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { // do not continue if typeck errors occurred (can only occur in local crate) - let def = instance.with_opt_param(); + let def = instance.def.with_opt_param(); if let Some(def) = def.as_local() { if self.tcx.has_typeck_results(def.did) { if let Some(error_reported) = self.tcx.typeck_opt_const_arg(def).tainted_by_errors { diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 0d01dc3c219bc..cfcb3b70a72c4 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -142,7 +142,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// constants, ... fn load_mir( ecx: &InterpCx<'mir, 'tcx, Self>, - instance: ty::InstanceDef<'tcx>, + instance: ty::Instance<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { Ok(ecx.tcx.instance_mir(instance)) } diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index a5bdeb55e7814..97751b8c9a5ed 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -256,6 +256,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } }; + let custom = self.tcx.custom_intrinsic_mir(instance); + let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() { ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(), ty::Closure(..) => Abi::RustCall, @@ -355,6 +357,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The Rust ABI is special: ZST get skipped. let rust_abi = match caller_abi { Abi::Rust | Abi::RustCall => true, + Abi::RustIntrinsic if custom.is_some() => true, _ => false, }; // We have two iterators: Where the arguments come from, diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 1da17bddcb777..af95003ca4507 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -52,6 +52,7 @@ pub fn provide(providers: &mut Providers) { const_eval::provide(providers); shim::provide(providers); transform::provide(providers); + monomorphize::provide(providers); monomorphize::partitioning::provide(providers); monomorphize::polymorphize::provide(providers); providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 0ab9aa8e1bfd4..5736f95052593 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -907,6 +907,10 @@ fn visit_instance_use<'tcx>( if !is_direct_call { bug!("{:?} being reified", instance); } + + if let Some(_mir) = tcx.custom_intrinsic_mir(instance) { + output.push(create_fn_mono_item(tcx, instance, source)); + } } ty::InstanceDef::DropGlue(_, None) => { // Don't need to emit noop drop glue if we are calling directly. @@ -1374,7 +1378,7 @@ fn collect_neighbours<'tcx>( output: &mut Vec>>, ) { debug!("collect_neighbours: {:?}", instance.def_id()); - let body = tcx.instance_mir(instance.def); + let body = tcx.instance_mir(instance); MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(&body); } diff --git a/compiler/rustc_mir/src/monomorphize/mod.rs b/compiler/rustc_mir/src/monomorphize/mod.rs index 9ca4b6687f1b5..6a11d9203aa1d 100644 --- a/compiler/rustc_mir/src/monomorphize/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/mod.rs @@ -1,6 +1,9 @@ -use rustc_middle::traits; +use rustc_index::vec::IndexVec; +use rustc_middle::{traits, mir}; use rustc_middle::ty::adjustment::CustomCoerceUnsized; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, Instance}; +use rustc_middle::ty::query::Providers; +use rustc_span::DUMMY_SP; use rustc_hir::lang_items::LangItem; @@ -8,6 +11,74 @@ pub mod collector; pub mod partitioning; pub mod polymorphize; +pub fn provide(providers: &mut Providers) { + providers.custom_intrinsic_mirgen = |_, _| { None }; + providers.custom_intrinsic_mir = custom_intrinsic_mir; +} + +fn custom_intrinsic_mir<'tcx>(tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>) + -> Option<&'tcx mir::Body<'tcx>> +{ + let mirgen = tcx.custom_intrinsic_mirgen(instance.def_id())?; + + let ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + let sig = ty.fn_sig(tcx); + let sig = tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + sig, + ); + + // no var arg calls, so we can skip monomorphizing extra arguments. + assert!(!sig.c_variadic); + + let source_scope_local_data = mir::ClearCrossCrate::Clear; + let source_scope = mir::SourceScopeData { + span: DUMMY_SP, + parent_scope: None, + local_data: source_scope_local_data, + inlined: None, + inlined_parent_scope: None, + }; + let source_info = mir::SourceInfo { + span: DUMMY_SP, + scope: mir::OUTERMOST_SOURCE_SCOPE, + }; + + let mut source_scopes = IndexVec::new(); + source_scopes.push(source_scope.clone()); + + let ret_decl = mir::LocalDecl::new(sig.output(), DUMMY_SP); + let mut local_decls = IndexVec::from_elem_n(ret_decl, 1); + for &arg in sig.inputs().iter() { + local_decls.push(mir::LocalDecl { + mutability: mir::Mutability::Mut, + local_info: None, + ty: arg, + source_info, + internal: false, + user_ty: None, + is_block_tail: None, + }); + } + + let source = mir::MirSource::from_instance(instance.def); + + let mut gen = mir::Body::new(source, + IndexVec::new(), + source_scopes, + local_decls, + Default::default(), + sig.inputs().len(), + Vec::new(), + source_scope.span, + None); + + mirgen.mirgen_simple_intrinsic(tcx, instance, &mut gen); + + Some(tcx.arena.alloc(gen)) +} + fn custom_coerce_unsize_info<'tcx>( tcx: TyCtxt<'tcx>, source_ty: Ty<'tcx>, diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index 6ed0ab8be41ee..aa0c7179d3409 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -436,7 +436,7 @@ fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSe if !visited.insert(did) { continue; } - for scope in &tcx.instance_mir(instance.def).source_scopes { + for scope in &tcx.instance_mir(*instance).source_scopes { if let Some((ref inlined, _)) = scope.inlined { result.insert(inlined.def_id()); } diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index b56c247127ce4..929c6d0695ecd 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -188,7 +188,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> fn load_mir( _ecx: &InterpCx<'mir, 'tcx, Self>, - _instance: ty::InstanceDef<'tcx>, + _instance: ty::Instance<'tcx>, ) -> InterpResult<'tcx, &'tcx Body<'tcx>> { throw_machine_stop_str!("calling functions isn't supported in ConstProp") } diff --git a/compiler/rustc_mir/src/transform/coverage/query.rs b/compiler/rustc_mir/src/transform/coverage/query.rs index 760f16eae6b1f..769da1b3e4e29 100644 --- a/compiler/rustc_mir/src/transform/coverage/query.rs +++ b/compiler/rustc_mir/src/transform/coverage/query.rs @@ -120,8 +120,8 @@ impl CoverageVisitor { } } -fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) -> CoverageInfo { - let mir_body = tcx.instance_mir(instance_def); +fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> CoverageInfo { + let mir_body = tcx.instance_mir(instance); let mut coverage_visitor = CoverageVisitor { // num_counters always has at least the `ZERO` counter. @@ -187,5 +187,8 @@ fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool { fn mir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx mir::Body<'tcx> { let id = ty::WithOptConstParam::unknown(def_id); let def = ty::InstanceDef::Item(id); - tcx.instance_mir(def) + tcx.instance_mir(ty::Instance { + def, + substs: ty::subst::InternalSubsts::identity_for_item(tcx, def_id), + }) } diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index f1c95a84ade85..83a1e93d59127 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -143,7 +143,7 @@ impl Inliner<'tcx> { let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id()); self.check_codegen_attributes(callsite, callee_attrs)?; self.check_mir_is_available(caller_body, &callsite.callee)?; - let callee_body = self.tcx.instance_mir(callsite.callee.def); + let callee_body = self.tcx.instance_mir(callsite.callee); self.check_mir_body(callsite, callee_body, callee_attrs)?; if !self.tcx.consider_optimizing(|| { diff --git a/compiler/rustc_mir/src/transform/inline/cycle.rs b/compiler/rustc_mir/src/transform/inline/cycle.rs index 295f3ec70dc78..40a776dd5e3c1 100644 --- a/compiler/rustc_mir/src/transform/inline/cycle.rs +++ b/compiler/rustc_mir/src/transform/inline/cycle.rs @@ -42,7 +42,7 @@ crate fn mir_callgraph_reachable( recursion_limiter: &mut FxHashMap, ) -> bool { trace!(%caller); - for &(callee, substs) in tcx.mir_inliner_callees(caller.def) { + for &(callee, substs) in tcx.mir_inliner_callees(caller) { let substs = caller.subst_mir_and_normalize_erasing_regions(tcx, param_env, substs); let callee = match ty::Instance::resolve(tcx, param_env, callee, substs).unwrap() { Some(callee) => callee, @@ -127,11 +127,11 @@ crate fn mir_callgraph_reachable( crate fn mir_inliner_callees<'tcx>( tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, + instance: ty::Instance<'tcx>, ) -> &'tcx [(DefId, SubstsRef<'tcx>)] { let steal; let guard; - let body = match (instance, instance.def_id().as_local()) { + let body = match (instance.def, instance.def_id().as_local()) { (InstanceDef::Item(_), Some(def_id)) => { let def = ty::WithOptConstParam::unknown(def_id); steal = tcx.mir_promoted(def).0; diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 2201223e13eab..257c545dd9316 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -429,7 +429,10 @@ fn mir_drops_elaborated_and_const_checked<'tcx>( // Do not compute the mir call graph without said call graph actually being used. if inline::is_enabled(tcx) { - let _ = tcx.mir_inliner_callees(ty::InstanceDef::Item(def)); + let _ = tcx.mir_inliner_callees(ty::Instance { + def: ty::InstanceDef::Item(def), + substs: ty::subst::InternalSubsts::identity_for_item(tcx, did), + }); } } diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs index 92c7a358c0a41..6d51071ced327 100644 --- a/compiler/rustc_mir/src/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -23,9 +23,12 @@ where if tcx.is_const_fn_raw(*def_id) { vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)] } else { - vec![tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown( - *def_id, - )))] + vec![tcx.instance_mir(ty::Instance { + def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown( + *def_id, + )), + substs: ty::subst::InternalSubsts::identity_for_item(tcx, *def_id), + })] } }) .collect::>(); diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index f8325a3646ff4..484fa81c3af0b 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -302,8 +302,12 @@ pub fn write_mir_pretty<'tcx>( // are shared between mir_for_ctfe and optimized_mir write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?; } else { - let instance_mir = - tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id))); + let instance_mir = tcx.instance_mir(ty::Instance { + def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown( + def_id, + )), + substs: ty::subst::InternalSubsts::identity_for_item(tcx, def_id), + }); render_body(w, instance_mir)?; } } diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index f716ce1efce86..da941f40ec5b1 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -174,6 +174,10 @@ fn compute_symbol_name( } let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); matches!(tcx.hir().get(hir_id), Node::ForeignItem(_)) + } else if let ty::InstanceDef::Intrinsic(_) = instance.def { + // custom intrinsics should never be foreign, otherwise + // generic parameters will cause duplicate symbols names. + tcx.custom_intrinsic_mir(instance).is_none() } else { tcx.is_foreign_item(def_id) }; diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index ebc7b0d0d99cf..fd74c2a97fb5c 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -401,7 +401,10 @@ fn instance_def_size_estimate<'tcx>( match instance_def { InstanceDef::Item(..) | InstanceDef::DropGlue(..) => { - let mir = tcx.instance_mir(instance_def); + let mir = tcx.instance_mir(ty::Instance { + def: instance_def, + substs: tcx.intern_substs(&[]), + }); mir.basic_blocks().iter().map(|bb| bb.statements.len()).sum() } // Estimate the size of other compiler-generated shims to be 1. diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 51904a5dd865e..a8ff2bddd4ca6 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -375,8 +375,14 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { } other => { - tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other }); - return; + if let Some(mirgen) = tcx.custom_intrinsic_mirgen(it.def_id.to_def_id()) { + (mirgen.generic_parameter_count(tcx), + mirgen.inputs(tcx).iter().collect(), + mirgen.output(tcx)) + } else { + tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other }); + return; + } } }; (n_tps, inputs, output, unsafety) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/test/compile-fail-fulldeps/auxiliary/plugin_intrinsic_codegen.rs b/src/test/compile-fail-fulldeps/auxiliary/plugin_intrinsic_codegen.rs new file mode 100644 index 0000000000000..ad435326779b3 --- /dev/null +++ b/src/test/compile-fail-fulldeps/auxiliary/plugin_intrinsic_codegen.rs @@ -0,0 +1,84 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host + +#![feature(plugin_registrar, rustc_private)] +#![deny(plugin_as_library)] // should have no effect in a plugin crate + +extern crate rustc; +extern crate rustc_plugin; + + +use rustc::mir::*; +use rustc::ty::{Ty, TyCtxt, FnSig, subst::Substs, }; +use rustc_plugin::Registry; + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + let codegen = Box::new(GenericCountMismatch) as Box<_>; + reg.register_intrinsic("generic_count_mismatch".into(), codegen); + let codegen = Box::new(InputOutputMismatch) as Box<_>; + reg.register_intrinsic("type_mismatch".into(), codegen); +} + +struct GenericCountMismatch; +impl PluginIntrinsicCodegen for GenericCountMismatch { + fn codegen_simple_intrinsic<'a, 'tcx>(&self, + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + _source_info: SourceInfo, + _sig: &FnSig<'tcx>, + _parent_mir: &Mir<'tcx>, + _parent_param_substs: &'tcx Substs<'tcx>, + _args: &Vec>, + _dest: Place<'tcx>, + _extra_stmts: &mut Vec>) + where 'tcx: 'a, + { + unreachable!() + } + + /// The number of generic parameters expected. + fn generic_parameter_count<'a, 'tcx>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>) -> usize { 5 } + /// The types of the input args. + fn inputs<'a, 'tcx>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec> { vec![] } + /// The return type. + fn output<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { + tcx.mk_nil() + } +} + +struct InputOutputMismatch; +impl PluginIntrinsicCodegen for InputOutputMismatch { + fn codegen_simple_intrinsic<'a, 'tcx>(&self, + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + _source_info: SourceInfo, + _sig: &FnSig<'tcx>, + _parent_mir: &Mir<'tcx>, + _parent_param_substs: &'tcx Substs<'tcx>, + _args: &Vec>, + _dest: Place<'tcx>, + _extra_stmts: &mut Vec>) + where 'tcx: 'a, + { + unreachable!() + } + + /// The number of generic parameters expected. + fn generic_parameter_count<'a, 'tcx>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>) -> usize { 0 } + /// The types of the input args. + fn inputs<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec> { + vec![tcx.types.u64] + } + /// The return type. + fn output<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { + tcx.types.u64 + } +} diff --git a/src/test/compile-fail-fulldeps/plugin-intrinsic-arg.rs b/src/test/compile-fail-fulldeps/plugin-intrinsic-arg.rs new file mode 100644 index 0000000000000..4368f55c65e69 --- /dev/null +++ b/src/test/compile-fail-fulldeps/plugin-intrinsic-arg.rs @@ -0,0 +1,25 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:plugin_intrinsic_codegen.rs +// ignore-stage1 + +#![feature(plugin, intrinsics)] +#![plugin(plugin_intrinsic_codegen)] + +extern "rust-intrinsic" { + /// The plugin expects `arg1` to be `u64`. + fn type_mismatch(arg1: i64) -> u64; + //~^ ERROR intrinsic has wrong type +} + +fn main() { + unreachable!(); +} diff --git a/src/test/compile-fail-fulldeps/plugin-intrinsic-generic.rs b/src/test/compile-fail-fulldeps/plugin-intrinsic-generic.rs new file mode 100644 index 0000000000000..308a050dbc61c --- /dev/null +++ b/src/test/compile-fail-fulldeps/plugin-intrinsic-generic.rs @@ -0,0 +1,25 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:plugin_intrinsic_codegen.rs +// ignore-stage1 + +#![feature(plugin, intrinsics)] +#![plugin(plugin_intrinsic_codegen)] + +extern "rust-intrinsic" { + /// The plugin expects 5 generic params + fn generic_count_mismatch(); + //~^ ERROR intrinsic has wrong number of type parameters: found 1, expected 5 +} + +fn main() { + unreachable!(); +} diff --git a/src/test/compile-fail-fulldeps/plugin-intrinsic-ret.rs b/src/test/compile-fail-fulldeps/plugin-intrinsic-ret.rs new file mode 100644 index 0000000000000..9cfa1ab93c24e --- /dev/null +++ b/src/test/compile-fail-fulldeps/plugin-intrinsic-ret.rs @@ -0,0 +1,25 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:plugin_intrinsic_codegen.rs +// ignore-stage1 + +#![feature(plugin, intrinsics)] +#![plugin(plugin_intrinsic_codegen)] + +extern "rust-intrinsic" { + /// The plugin expects the return to be `u64`. + fn type_mismatch(arg1: u64) -> i64; + //~^ ERROR intrinsic has wrong type +} + +fn main() { + unreachable!(); +} diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin_intrinsic_codegen.rs b/src/test/run-pass-fulldeps/auxiliary/plugin_intrinsic_codegen.rs new file mode 100644 index 0000000000000..794ead31040f2 --- /dev/null +++ b/src/test/run-pass-fulldeps/auxiliary/plugin_intrinsic_codegen.rs @@ -0,0 +1,73 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host + +#![feature(plugin_registrar, rustc_private)] +#![deny(plugin_as_library)] // should have no effect in a plugin crate + +extern crate rustc; +extern crate rustc_plugin; + +use rustc::mir::*; +use rustc::ty::{Ty, TyCtxt, FnSig, Const, subst::Substs, ParamEnv, }; +use rustc_plugin::Registry; + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + let codegen = Box::new(GetSecretValueCodegen) as Box<_>; + reg.register_intrinsic("get_secret_value".into(), codegen); +} + +struct GetSecretValueCodegen; +impl PluginIntrinsicCodegen for GetSecretValueCodegen { + fn codegen_simple_intrinsic<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + source_info: SourceInfo, + _sig: &FnSig<'tcx>, + _parent_mir: &Mir<'tcx>, + _parent_param_substs: &'tcx Substs<'tcx>, + _args: &Vec>, + dest: Place<'tcx>, + extra_stmts: &mut Vec>) + where 'tcx: 'a, + { + // chosen by fair dice roll. + // guaranteed to be random. + const SECRET_VALUE: u64 = 4; + + let v = Const::from_bits(tcx, SECRET_VALUE as u128, + ParamEnv::empty().and(tcx.types.u64)); + let v = tcx.mk_const(*v); + let v = Literal::Value { + value: v, + }; + let v = Constant { + span: source_info.span, + ty: tcx.types.u64, + literal: v, + }; + let v = Box::new(v); + let v = Operand::Constant(v); + let ret = Rvalue::Use(v); + + let stmt = StatementKind::Assign(dest, ret); + extra_stmts.push(stmt); + } + + /// The number of generic parameters expected. + fn generic_parameter_count<'a, 'tcx>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>) -> usize { 0 } + /// The types of the input args. + fn inputs<'a, 'tcx>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec> { vec![] } + /// The return type. + fn output<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { + tcx.types.u64 + } +} diff --git a/src/test/run-pass-fulldeps/plugin-intrinsic.rs b/src/test/run-pass-fulldeps/plugin-intrinsic.rs new file mode 100644 index 0000000000000..a977bb0acf4ea --- /dev/null +++ b/src/test/run-pass-fulldeps/plugin-intrinsic.rs @@ -0,0 +1,25 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:plugin_intrinsic_codegen.rs +// ignore-stage1 + +#![feature(plugin, intrinsics)] +#![plugin(plugin_intrinsic_codegen)] + +extern "rust-intrinsic" { + /// Returns the secret value. + fn get_secret_value() -> u64; +} + +fn main() { + const SECRET_VALUE: u64 = 4; + assert_eq!(unsafe { get_secret_value() }, SECRET_VALUE); +}