diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9ac1465cb0ba9..6c7929e503c3b 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -16,7 +16,7 @@ use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{ self, AdtDef, CanonicalUserTypeAnnotations, Region, Ty, TyCtxt, - UserTypeAnnotationIndex, + UserTypeAnnotationIndex, List, }; use polonius_engine::Atom; @@ -50,7 +50,7 @@ pub mod traversal; pub mod visit; /// Types for locals -type LocalDecls<'tcx> = IndexVec>; +pub type LocalDecls<'tcx> = IndexVec>; pub trait HasLocalDecls<'tcx> { fn local_decls(&self) -> &LocalDecls<'tcx>; @@ -3367,3 +3367,41 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { self.literal.visit_with(visitor) } } + +pub trait CustomIntrinsicMirGen: Sync + Send { + /// 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>; +} + +/*impl<'a> HashStable> for dyn CustomIntrinsicMirGen { + fn hash_stable(&self, + _ctx: &mut StableHashingContext<'_>, + _hasher: &mut StableHasher) { + // TO DO + } +}*/ diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 2a012c5274191..1c63bdaa5cb0b 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -129,6 +129,24 @@ rustc_queries! { } } + /// If defined by the driver, returns the extra mir statements to codegen, + /// else returns `None`. + query custom_intrinsic_mirgen(key: DefId) -> Option> { + anon + fatal_cycle + 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 + fatal_cycle + no_force + + desc { |tcx| "asking for the custom MIR of `{}`", tcx.def_path_str(inst.def_id()) } + } + query promoted_mir(key: DefId) -> &'tcx IndexVec> { cache_on_disk_if { key.is_local() } load_cached(tcx, id) { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d5911a24de21a..9c01b6742713d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -3028,20 +3028,26 @@ 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(did) => { self.optimized_mir(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) + self.mir_shims(instance.def) } } } @@ -3324,7 +3330,12 @@ fn instance_def_size_estimate<'tcx>(tcx: TyCtxt<'tcx>, instance_def: InstanceDef match instance_def { InstanceDef::Item(..) | InstanceDef::DropGlue(..) => { - let mir = tcx.instance_mir(instance_def); + let instance = Instance { + def: instance_def, + // this field can be whatever because it won't be used in this case. + substs: tcx.intern_substs(&[]), + }; + let mir = tcx.instance_mir(instance); mir.basic_blocks().iter().map(|bb| bb.statements.len()).sum() }, // Estimate the size of other compiler-generated shims to be 1. diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 1c441ca7cbf2e..7b73d18d2f94d 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -378,7 +378,7 @@ pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( let lldecl = cx.get_fn(instance); - let mir = cx.tcx().instance_mir(instance.def); + let mir = cx.tcx().instance_mir(instance); mir::codegen_mir::(cx, lldecl, &mir, instance, sig); } diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index dc77d025c005f..0fcae8695d4a2 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -604,16 +604,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let arg_count = fn_ty.args.len() + fn_ty.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((ref 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_ty.ret, &mut llargs, is_intrinsic) } else { ReturnDest::Nothing }; - if intrinsic.is_some() && intrinsic != Some("drop_in_place") { + if intrinsic.is_some() && intrinsic != Some("drop_in_place") && + !is_custom_intrinsic { let dest = match ret_dest { _ if fn_ty.ret.is_indirect() => llargs[0], ReturnDest::Nothing => diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index 7ccd024769f75..a1edb70fa6598 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -139,6 +139,10 @@ fn symbol_name(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> InternedString { Node::ForeignItem(_) => true, _ => false, } + } 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/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 9622c290039d5..506ceba015851 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -21,6 +21,7 @@ use std::collections::HashMap; use std::hash::{Hash, BuildHasher}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; +use std::sync::{Arc, atomic::AtomicPtr, atomic, }; use crate::owning_ref::{Erased, OwningRef}; pub use std::sync::atomic::Ordering::SeqCst; @@ -788,3 +789,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/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index bb02b99dd8d87..a2300a77dc18d 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -330,8 +330,13 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ret: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { debug!("eval_fn_call: {:?}", instance); + // WIP: We assume all custom intrinsics are const. This is okay for now + // as these are generated in the provider/query system, which caches the + // resulting MIR. Effectively, this means for any specific set of generic + // params, the MIR is the same for each call (ie in user code). + let custom = ecx.tcx.custom_intrinsic_mir(instance); // Only check non-glue functions - if let ty::InstanceDef::Item(def_id) = instance.def { + if let (None, ty::InstanceDef::Item(def_id)) = (custom, instance.def) { // Execution might have wandered off into other crates, so we cannot do a stability- // sensitive check here. But we can at least rule out functions that are not const // at all. @@ -348,7 +353,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(ref path)) = err.kind { @@ -672,7 +677,7 @@ pub fn const_eval_raw_provider<'tcx>( Default::default() ); - let res = ecx.load_mir(cid.instance.def, cid.promoted); + let res = ecx.load_mir(cid.instance, cid.promoted); res.and_then( |body| eval_body_using_ecx(&mut ecx, cid, body) ).and_then(|place| { diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e1c45132103b4..97b77b8fa8708 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -292,7 +292,7 @@ impl<'mir, 'tcx, 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) @@ -307,7 +307,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Some(promoted) = promoted { return Ok(&self.tcx.promoted_mir(did)[promoted]); } - match instance { + match instance.def { ty::InstanceDef::Item(def_id) => if self.tcx.is_mir_available(did) { Ok(self.tcx.optimized_mir(did)) } else { diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 11c7cd0d901d0..c362752345a09 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -247,8 +247,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } }; + let custom = self.tcx.custom_intrinsic_mir(instance); + match instance.def { - ty::InstanceDef::Intrinsic(..) => { + ty::InstanceDef::Intrinsic(..) if custom.is_none() => { // The intrinsic itself cannot diverge, so if we got here without a return // place... (can happen e.g., for transmute returning `!`) let dest = match dest { @@ -262,6 +264,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.dump_place(*dest); Ok(()) } + ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | @@ -332,6 +335,7 @@ impl<'mir, 'tcx, 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/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index a837c34e8d474..874ec675dfe6b 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -57,6 +57,7 @@ pub fn provide(providers: &mut Providers<'_>) { providers.const_eval = const_eval::const_eval_provider; providers.const_eval_raw = const_eval::const_eval_raw_provider; providers.check_match = hair::pattern::check_match; + monomorphize::provide(providers); providers.const_field = |tcx, param_env_and_value| { let (param_env, (value, field)) = param_env_and_value.into_parts(); const_eval::const_field(tcx, param_env, None, field, value) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index ee7452d3e8b46..81b249140c7a0 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -747,6 +747,10 @@ fn visit_instance_use<'tcx>( if !is_direct_call { bug!("intrinsic {:?} being reified", def_id); } + + if let Some(_mir) = tcx.custom_intrinsic_mir(instance) { + output.push(create_fn_mono_item(instance)); + } } ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | @@ -1251,7 +1255,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, diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs index b36cf49ef1e45..34739bb795299 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/src/librustc_mir/monomorphize/mod.rs @@ -1,10 +1,85 @@ +use rustc_index::vec::IndexVec; +use rustc::mir; use rustc::traits; use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, Instance}; +use rustc::ty::query::Providers; + +use syntax_pos::DUMMY_SP; pub mod collector; pub mod partitioning; +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()); + if mirgen.is_none() { return None; } + let mirgen = mirgen.unwrap(); + + let ty = instance.ty(tcx); + 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 = mir::SourceScopeData { + span: DUMMY_SP, + 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 source_scope_local_data = mir::ClearCrossCrate::Set(Default::default()); + + let ret_decl = mir::LocalDecl::new_return_place(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, + ty: arg, + source_info, + visibility_scope: source_info.scope, + name: None, + internal: false, + is_user_variable: None, + user_ty: mir::UserTypeProjections::none(), + is_block_tail: None, + }); + } + + let mut gen = mir::Body::new(IndexVec::new(), + source_scopes, + source_scope_local_data, + None, + local_decls, + Default::default(), + sig.inputs().len(), + Vec::new(), + source_scope.span, + Vec::new()); + + mirgen.mirgen_simple_intrinsic(tcx, instance, &mut gen); + + // TO DO verify the generated MIR doesn't do anything Bad(TM). + Some(tcx.arena.alloc(gen)) +} + pub fn custom_coerce_unsize_info<'tcx>( tcx: TyCtxt<'tcx>, source_ty: Ty<'tcx>, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index fbcf9c8cb5eba..3f9da9f8f7c7b 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1411,6 +1411,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { Abi::RustIntrinsic | Abi::PlatformIntrinsic => { assert!(!self.tcx.is_const_fn(def_id)); + match &self.tcx.item_name(def_id).as_str()[..] { // special intrinsic that can be called diretly without an intrinsic // feature gate needs a language feature gate diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index cf0ee1bf09222..bdb04a4619588 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -402,6 +402,8 @@ fn check_terminator( /// /// Adding more intrinsics requires sign-off from @rust-lang/lang. fn is_intrinsic_whitelisted(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + if tcx.custom_intrinsic_mirgen(def_id).is_some() { return true; } + match &tcx.item_name(def_id).as_str()[..] { | "size_of" | "min_align_of" diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index aeb2c40e2ef83..71d6ff802b9ed 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -371,12 +371,20 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) { } ref other => { - struct_span_err!(tcx.sess, it.span, E0093, + let def_id = tcx.hir().local_def_id(it.hir_id); + if let Some(mirgen) = tcx.custom_intrinsic_mirgen(def_id) { + (mirgen.generic_parameter_count(tcx), + mirgen.inputs(tcx).iter().map(|&v| v ).collect(), + mirgen.output(tcx)) + } else { + struct_span_err!(tcx.sess, it.span, E0093, "unrecognized intrinsic function: `{}`", *other) .span_label(it.span, "unrecognized intrinsic") .emit(); - return; + return; + + } } }; (n_tps, inputs, output, unsafety) 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); +}