From b0ff73f48a73e8e0db8570c47887ad2f648fd5ea Mon Sep 17 00:00:00 2001 From: Richard Diamond Date: Sat, 7 Jul 2018 11:47:02 -0500 Subject: [PATCH] Plugin provided "intrinsics". Allows plugins to define functions which are only expanded by the plugin after all type checking, inference, etc etc, ie only once codegen encounters a call to the intrinsic. In this initial version, the codegen crate is reponsible for calling the plugin intrinsic codgen trait and codegening the resulting extra MIR statements. Plugins are limited to `mir::StatementKind` and those contained therein, so they can't insert extra basic blocks, or insert calls to arbitraty functions. This means the compiler can still reason about what is reachable. The form of the interface with the plugins is slightly different than what was proposed in https://github.com/rust-lang/rust/issues/51623. Additionally, signature checking is added. --- src/librustc/mir/mod.rs | 37 ++++++++ src/librustc/session/mod.rs | 7 +- src/librustc_codegen_llvm/context.rs | 3 + src/librustc_codegen_llvm/mir/block.rs | 32 +++++++ src/librustc_data_structures/sync.rs | 53 ++++++++++++ src/librustc_driver/driver.rs | 4 +- src/librustc_plugin/registry.rs | 16 ++++ src/librustc_typeck/check/intrinsic.rs | 12 ++- .../auxiliary/plugin_intrinsic_codegen.rs | 84 +++++++++++++++++++ .../plugin-intrinsic-arg.rs | 25 ++++++ .../plugin-intrinsic-generic.rs | 25 ++++++ .../plugin-intrinsic-ret.rs | 25 ++++++ .../auxiliary/plugin_intrinsic_codegen.rs | 73 ++++++++++++++++ .../run-pass-fulldeps/plugin-intrinsic.rs | 25 ++++++ 14 files changed, 417 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail-fulldeps/auxiliary/plugin_intrinsic_codegen.rs create mode 100644 src/test/compile-fail-fulldeps/plugin-intrinsic-arg.rs create mode 100644 src/test/compile-fail-fulldeps/plugin-intrinsic-generic.rs create mode 100644 src/test/compile-fail-fulldeps/plugin-intrinsic-ret.rs create mode 100644 src/test/run-pass-fulldeps/auxiliary/plugin_intrinsic_codegen.rs create mode 100644 src/test/run-pass-fulldeps/plugin-intrinsic.rs diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index cd4b32735e57a..d63ff148ccece 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -29,6 +29,7 @@ use rustc_data_structures::small_vec::SmallVec; use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::ReadGuard; use rustc_serialize as serialize; +use std::collections::HashMap; use std::borrow::Cow; use std::fmt::{self, Debug, Formatter, Write}; use std::ops::{Index, IndexMut}; @@ -2923,3 +2924,39 @@ impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> { } } } +pub type PluginIntrinsics = HashMap>; +pub trait PluginIntrinsicCodegen: 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 codegen_simple_intrinsic<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + source_info: SourceInfo, + sig: &ty::FnSig<'tcx>, + parent_mir: &Mir<'tcx>, + parent_param_substs: &'tcx Substs<'tcx>, + args: &Vec>, + dest: Place<'tcx>, + extra_stmts: &mut Vec>) + where 'tcx: 'a; + + /// The following are used for during typeck: + + /// The number of generic parameters expected. + fn generic_parameter_count<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> usize; + /// The types of the input args. + fn inputs<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec>; + /// The return type. + fn output<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx>; +} diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 076d56fb80842..86f84c4c2c6e8 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -19,6 +19,7 @@ use lint; use lint::builtin::BuiltinLintDiagnostics; use middle::allocator::AllocatorKind; use middle::dependency_format; +use mir::PluginIntrinsics; use session::search_paths::PathKind; use session::config::{OutputType}; use ty::tls; @@ -26,7 +27,8 @@ use util::nodemap::{FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; use util::common::ProfileQueriesMsg; -use rustc_data_structures::sync::{self, Lrc, Lock, LockCell, OneThread, Once, RwLock}; +use rustc_data_structures::sync::{self, Lrc, Lock, LockCell, OneThread, Once, + RwLock, ArcCell, }; use syntax::ast::NodeId; use errors::{self, DiagnosticBuilder, DiagnosticId}; @@ -54,6 +56,7 @@ use std::fmt; use std::io::Write; use std::path::{Path, PathBuf}; use std::time::Duration; +use std::sync::Arc; use std::sync::mpsc; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -92,6 +95,7 @@ pub struct Session { pub one_time_diagnostics: Lock, String)>>, pub plugin_llvm_passes: OneThread>>, pub plugin_attributes: OneThread>>, + pub plugin_intrinsics: ArcCell, pub crate_types: Once>, pub dependency_formats: Once, /// The crate_disambiguator is constructed out of all the `-C metadata` @@ -1109,6 +1113,7 @@ pub fn build_session_( one_time_diagnostics: Lock::new(FxHashSet()), plugin_llvm_passes: OneThread::new(RefCell::new(Vec::new())), plugin_attributes: OneThread::new(RefCell::new(Vec::new())), + plugin_intrinsics: ArcCell::new(Arc::new(HashMap::new())), crate_types: Once::new(), dependency_formats: Once::new(), crate_disambiguator: Once::new(), diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index b774d7c5def21..7180f5b8d88db 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -26,6 +26,7 @@ use type_of::PointeeInfo; use rustc_data_structures::base_n; use rustc::mir::mono::Stats; +use rustc::mir::PluginIntrinsics; use rustc::session::config::{self, NoDebugInfo}; use rustc::session::Session; use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout}; @@ -102,6 +103,7 @@ pub struct CodegenCx<'a, 'tcx: 'a> { pub rust_try_fn: Cell>, intrinsics: RefCell>, + pub plugin_intrinsics: Arc, /// A counter that is used for generating local symbol names local_gen_sym_counter: Cell, @@ -306,6 +308,7 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> { eh_unwind_resume: Cell::new(None), rust_try_fn: Cell::new(None), intrinsics: RefCell::new(FxHashMap()), + plugin_intrinsics: tcx.sess.plugin_intrinsics.get(), local_gen_sym_counter: Cell::new(0), }; cx.isize_ty = Type::isize(&cx); diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs index 14d20b6dbe297..d074868654576 100644 --- a/src/librustc_codegen_llvm/mir/block.rs +++ b/src/librustc_codegen_llvm/mir/block.rs @@ -454,6 +454,38 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { return; } + if let Some(intrinsic) = intrinsic { + if let Some(trans) = bx.cx.plugin_intrinsics.get(intrinsic) { + // Get the extra statements from the plugin: + let &(ref dest, target) = destination + .as_ref() + .unwrap(); + + let mut extra_stmts = Vec::new(); + trans.codegen_simple_intrinsic(bx.tcx(), + terminator.source_info, + &sig, + self.mir, + self.param_substs, + args, + dest.clone(), + &mut extra_stmts); + + // Now, codegen: + for stmt_kind in extra_stmts.into_iter() { + let stmt = mir::Statement { + source_info: terminator.source_info, + kind: stmt_kind, + }; + bx = self.codegen_statement(bx, &stmt); + } + + // Lastly, jump to the target block: + funclet_br(self, bx, target); + return; + } + } + let extra_args = &args[sig.inputs().len()..]; let extra_args = extra_args.iter().map(|op_arg| { let op_ty = op_arg.ty(self.mir, bx.tcx()); diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index b82fe3ec60c3b..e3879c1372ddc 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -39,6 +39,7 @@ use std::fmt::Debug; use std::fmt::Formatter; use std::fmt; use std::ops::{Deref, DerefMut}; +use std::sync::{Arc, atomic::AtomicPtr, atomic, }; use owning_ref::{Erased, OwningRef}; pub fn serial_join(oper_a: A, oper_b: B) -> (RA, RB) @@ -751,3 +752,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_driver/driver.rs b/src/librustc_driver/driver.rs index 96e9616699d37..5fcc48f063ac4 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -50,7 +50,7 @@ use std::io::{self, Write}; use std::iter; use std::path::{Path, PathBuf}; use rustc_data_structures::sync::{self, Lrc, Lock}; -use std::sync::mpsc; +use std::sync::{mpsc, Arc, }; use syntax::{self, ast, attr, diagnostics, visit}; use syntax::ext::base::ExtCtxt; use syntax::fold::Folder; @@ -896,6 +896,7 @@ where lint_groups, llvm_passes, attributes, + intrinsics, .. } = registry; @@ -914,6 +915,7 @@ where *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; *sess.plugin_attributes.borrow_mut() = attributes.clone(); + sess.plugin_intrinsics.set(Arc::new(intrinsics)); })?; // Lint plugins are registered; now we can process command line flags. diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index b1ab86674cf90..879aa658b5840 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -11,6 +11,7 @@ //! Used by plugin crates to tell `rustc` about the plugins they provide. use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint}; +use rustc::mir::{PluginIntrinsics, PluginIntrinsicCodegen}; use rustc::session::Session; use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT}; @@ -61,6 +62,9 @@ pub struct Registry<'a> { #[doc(hidden)] pub attributes: Vec<(String, AttributeType)>, + #[doc(hidden)] + pub intrinsics: PluginIntrinsics, + whitelisted_custom_derives: Vec, } @@ -77,6 +81,7 @@ impl<'a> Registry<'a> { lint_groups: HashMap::new(), llvm_passes: vec![], attributes: vec![], + intrinsics: HashMap::new(), whitelisted_custom_derives: Vec::new(), } } @@ -95,6 +100,17 @@ impl<'a> Registry<'a> { self.args_hidden.as_ref().map(|v| &v[..]).unwrap_or(&[]) } + /// Register a plugin intrinsic. Ignored if `name` is a normal Rust intrinsic. + /// + /// When a function call to the named intrinsic is made, codegen (only LLVM, currently) + /// will replace the usual function call with the extra statements provided by the passed + /// trait object. It will then branch directly to the exit block. It is highly unsafe. Do not + /// use lightly. + pub fn register_intrinsic(&mut self, name: String, + codegen: Box) { + self.intrinsics.insert(name, codegen); + } + /// Register a syntax extension of any kind. /// /// This is the most general hook into `libsyntax`'s expansion behavior. diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index c93023edcea08..639d85f49d6d0 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -319,12 +319,20 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } ref other => { - struct_span_err!(tcx.sess, it.span, E0093, + let plugin_intrinsics = tcx.sess.plugin_intrinsics.get(); + if let Some(plugin) = plugin_intrinsics.get(*other) { + (plugin.generic_parameter_count(tcx), + plugin.inputs(tcx), + plugin.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) 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); +}