diff --git a/Cargo.lock b/Cargo.lock index bdc746c0bb0..89932546278 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2751,20 +2751,6 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc_allocator" -version = "0.0.0" -dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_target 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - [[package]] name = "rustc_apfloat" version = "0.0.0" @@ -2822,7 +2808,6 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", "rustc_codegen_utils 0.0.0", "rustc_data_structures 0.0.0", @@ -2883,7 +2868,6 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_allocator 0.0.0", "rustc_ast_borrowck 0.0.0", "rustc_codegen_utils 0.0.0", "rustc_data_structures 0.0.0", @@ -2904,7 +2888,6 @@ dependencies = [ "serialize 0.0.0", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", - "syntax_ext 0.0.0", "syntax_pos 0.0.0", ] @@ -2948,7 +2931,6 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_allocator 0.0.0", "rustc_ast_borrowck 0.0.0", "rustc_codegen_ssa 0.0.0", "rustc_codegen_utils 0.0.0", diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 296bb43f9fa..17781798946 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -1281,6 +1281,13 @@ mod builtin { #[rustc_macro_transparency = "semitransparent"] pub macro test_case($item:item) { /* compiler built-in */ } + /// Attribute macro applied to a static to register it as a global allocator. + #[stable(feature = "global_allocator", since = "1.28.0")] + #[allow_internal_unstable(rustc_attrs)] + #[rustc_builtin_macro] + #[rustc_macro_transparency = "semitransparent"] + pub macro global_allocator($item:item) { /* compiler built-in */ } + /// Derive macro generating an impl of the trait `Clone`. #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c7d4fa3aec6..79f60778d3c 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -104,7 +104,6 @@ pub mod infer; pub mod lint; pub mod middle { - pub mod allocator; pub mod borrowck; pub mod expr_use_visitor; pub mod cstore; diff --git a/src/librustc/middle/allocator.rs b/src/librustc/middle/allocator.rs deleted file mode 100644 index bb2e3b4ec19..00000000000 --- a/src/librustc/middle/allocator.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[derive(Clone, Copy)] -pub enum AllocatorKind { - Global, - DefaultLib, - DefaultExe, -} - -impl AllocatorKind { - pub fn fn_name(&self, base: &str) -> String { - match *self { - AllocatorKind::Global => format!("__rg_{}", base), - AllocatorKind::DefaultLib => format!("__rdl_{}", base), - AllocatorKind::DefaultExe => format!("__rde_{}", base), - } - } -} diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 4c27318c3e1..88de77829a6 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -320,11 +320,6 @@ fn has_allow_dead_code_or_lang_attr( return true; } - // Don't lint about global allocators - if attr::contains_name(attrs, sym::global_allocator) { - return true; - } - let def_id = tcx.hir().local_def_id(id); let cg_attrs = tcx.codegen_fn_attrs(def_id); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index c88ca132184..61dac678912 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -7,7 +7,6 @@ use rustc_data_structures::fingerprint::Fingerprint; use crate::lint; use crate::lint::builtin::BuiltinLintDiagnostics; -use crate::middle::allocator::AllocatorKind; use crate::middle::dependency_format; use crate::session::config::{OutputType, PrintRequest, SwitchWithOptPath}; use crate::session::search_paths::{PathKind, SearchPath}; @@ -27,6 +26,7 @@ use errors::emitter::HumanReadableErrorType; use errors::annotate_snippet_emitter_writer::{AnnotateSnippetEmitterWriter}; use syntax::ast::{self, NodeId}; use syntax::edition::Edition; +use syntax::ext::allocator::AllocatorKind; use syntax::feature_gate::{self, AttributeType}; use syntax::json::JsonEmitter; use syntax::source_map; diff --git a/src/librustc_allocator/Cargo.toml b/src/librustc_allocator/Cargo.toml deleted file mode 100644 index a964f323c9e..00000000000 --- a/src/librustc_allocator/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_allocator" -version = "0.0.0" -edition = "2018" - -[lib] -path = "lib.rs" -test = false - -[dependencies] -rustc = { path = "../librustc" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_target = { path = "../librustc_target" } -syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } -log = "0.4" -smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs deleted file mode 100644 index af63fffc0f9..00000000000 --- a/src/librustc_allocator/expand.rs +++ /dev/null @@ -1,298 +0,0 @@ -use log::debug; -use rustc::middle::allocator::AllocatorKind; -use smallvec::{smallvec, SmallVec}; -use syntax::{ - ast::{ - self, Arg, Attribute, Crate, Expr, FnHeader, Generics, Ident, Item, ItemKind, - Mac, Mod, Mutability, Ty, TyKind, Unsafety, VisibilityKind, - }, - attr, - source_map::{ - respan, ExpnInfo, ExpnKind, - }, - ext::{ - base::{ExtCtxt, MacroKind, Resolver}, - build::AstBuilder, - expand::ExpansionConfig, - hygiene::ExpnId, - }, - mut_visit::{self, MutVisitor}, - parse::ParseSess, - ptr::P, - symbol::{kw, sym} -}; -use syntax_pos::Span; - -use crate::{AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; - -pub fn modify( - sess: &ParseSess, - resolver: &mut dyn Resolver, - krate: &mut Crate, - crate_name: String, - handler: &rustc_errors::Handler, -) { - ExpandAllocatorDirectives { - handler, - sess, - resolver, - found: false, - crate_name: Some(crate_name), - in_submod: -1, // -1 to account for the "root" module - }.visit_crate(krate); -} - -struct ExpandAllocatorDirectives<'a> { - found: bool, - handler: &'a rustc_errors::Handler, - sess: &'a ParseSess, - resolver: &'a mut dyn Resolver, - crate_name: Option, - - // For now, we disallow `global_allocator` in submodules because hygiene is hard. Keep track of - // whether we are in a submodule or not. If `in_submod > 0` we are in a submodule. - in_submod: isize, -} - -impl MutVisitor for ExpandAllocatorDirectives<'_> { - fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { - debug!("in submodule {}", self.in_submod); - - if !attr::contains_name(&item.attrs, sym::global_allocator) { - return mut_visit::noop_flat_map_item(item, self); - } - - match item.node { - ItemKind::Static(..) => {} - _ => { - self.handler - .span_err(item.span, "allocators must be statics"); - return smallvec![item]; - } - } - - if self.in_submod > 0 { - self.handler - .span_err(item.span, "`global_allocator` cannot be used in submodules"); - return smallvec![item]; - } - - if self.found { - self.handler - .span_err(item.span, "cannot define more than one `#[global_allocator]`"); - return smallvec![item]; - } - self.found = true; - - // Create a new expansion for the generated allocator code. - let span = item.span.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::global_allocator), item.span, self.sess.edition, - [sym::rustc_attrs][..].into(), - )); - - // Create an expansion config - let ecfg = ExpansionConfig::default(self.crate_name.take().unwrap()); - - // Generate a bunch of new items using the AllocFnFactory - let mut f = AllocFnFactory { - span, - kind: AllocatorKind::Global, - global: item.ident, - core: Ident::with_empty_ctxt(sym::core), - cx: ExtCtxt::new(self.sess, ecfg, self.resolver), - }; - - // We will generate a new submodule. To `use` the static from that module, we need to get - // the `super::...` path. - let super_path = f.cx.path(f.span, vec![Ident::with_empty_ctxt(kw::Super), f.global]); - - // Generate the items in the submodule - let mut items = vec![ - // import `core` to use allocators - f.cx.item_extern_crate(f.span, f.core), - // `use` the `global_allocator` in `super` - f.cx.item_use_simple( - f.span, - respan(f.span.shrink_to_lo(), VisibilityKind::Inherited), - super_path, - ), - ]; - - // Add the allocator methods to the submodule - items.extend( - ALLOCATOR_METHODS - .iter() - .map(|method| f.allocator_fn(method)), - ); - - // Generate the submodule itself - let name = f.kind.fn_name("allocator_abi"); - let allocator_abi = Ident::from_str(&name).gensym(); - let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items); - let module = f.cx.monotonic_expander().flat_map_item(module).pop().unwrap(); - - // Return the item and new submodule - smallvec![item, module] - } - - // If we enter a submodule, take note. - fn visit_mod(&mut self, m: &mut Mod) { - debug!("enter submodule"); - self.in_submod += 1; - mut_visit::noop_visit_mod(m, self); - self.in_submod -= 1; - debug!("exit submodule"); - } - - // `visit_mac` is disabled by default. Enable it here. - fn visit_mac(&mut self, mac: &mut Mac) { - mut_visit::noop_visit_mac(mac, self) - } -} - -struct AllocFnFactory<'a> { - span: Span, - kind: AllocatorKind, - global: Ident, - core: Ident, - cx: ExtCtxt<'a>, -} - -impl AllocFnFactory<'_> { - fn allocator_fn(&self, method: &AllocatorMethod) -> P { - let mut abi_args = Vec::new(); - let mut i = 0; - let ref mut mk = || { - let name = Ident::from_str(&format!("arg{}", i)); - i += 1; - name - }; - let args = method - .inputs - .iter() - .map(|ty| self.arg_ty(ty, &mut abi_args, mk)) - .collect(); - let result = self.call_allocator(method.name, args); - let (output_ty, output_expr) = self.ret_ty(&method.output, result); - let kind = ItemKind::Fn( - self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)), - FnHeader { - unsafety: Unsafety::Unsafe, - ..FnHeader::default() - }, - Generics::default(), - self.cx.block_expr(output_expr), - ); - self.cx.item( - self.span, - Ident::from_str(&self.kind.fn_name(method.name)), - self.attrs(), - kind, - ) - } - - fn call_allocator(&self, method: &str, mut args: Vec>) -> P { - let method = self.cx.path( - self.span, - vec![ - self.core, - Ident::from_str("alloc"), - Ident::from_str("GlobalAlloc"), - Ident::from_str(method), - ], - ); - let method = self.cx.expr_path(method); - let allocator = self.cx.path_ident(self.span, self.global); - let allocator = self.cx.expr_path(allocator); - let allocator = self.cx.expr_addr_of(self.span, allocator); - args.insert(0, allocator); - - self.cx.expr_call(self.span, method, args) - } - - fn attrs(&self) -> Vec { - let special = sym::rustc_std_internal_symbol; - let special = self.cx.meta_word(self.span, special); - vec![self.cx.attribute(self.span, special)] - } - - fn arg_ty( - &self, - ty: &AllocatorTy, - args: &mut Vec, - ident: &mut dyn FnMut() -> Ident, - ) -> P { - match *ty { - AllocatorTy::Layout => { - let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize)); - let ty_usize = self.cx.ty_path(usize); - let size = ident(); - let align = ident(); - args.push(self.cx.arg(self.span, size, ty_usize.clone())); - args.push(self.cx.arg(self.span, align, ty_usize)); - - let layout_new = self.cx.path( - self.span, - vec![ - self.core, - Ident::from_str("alloc"), - Ident::from_str("Layout"), - Ident::from_str("from_size_align_unchecked"), - ], - ); - let layout_new = self.cx.expr_path(layout_new); - let size = self.cx.expr_ident(self.span, size); - let align = self.cx.expr_ident(self.span, align); - let layout = self.cx.expr_call(self.span, layout_new, vec![size, align]); - layout - } - - AllocatorTy::Ptr => { - let ident = ident(); - args.push(self.cx.arg(self.span, ident, self.ptr_u8())); - let arg = self.cx.expr_ident(self.span, ident); - self.cx.expr_cast(self.span, arg, self.ptr_u8()) - } - - AllocatorTy::Usize => { - let ident = ident(); - args.push(self.cx.arg(self.span, ident, self.usize())); - self.cx.expr_ident(self.span, ident) - } - - AllocatorTy::ResultPtr | AllocatorTy::Unit => { - panic!("can't convert AllocatorTy to an argument") - } - } - } - - fn ret_ty(&self, ty: &AllocatorTy, expr: P) -> (P, P) { - match *ty { - AllocatorTy::ResultPtr => { - // We're creating: - // - // #expr as *mut u8 - - let expr = self.cx.expr_cast(self.span, expr, self.ptr_u8()); - (self.ptr_u8(), expr) - } - - AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr), - - AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { - panic!("can't convert `AllocatorTy` to an output") - } - } - } - - fn usize(&self) -> P { - let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize)); - self.cx.ty_path(usize) - } - - fn ptr_u8(&self) -> P { - let u8 = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::u8)); - let ty_u8 = self.cx.ty_path(u8); - self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) - } -} diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs deleted file mode 100644 index 8d380c47bc4..00000000000 --- a/src/librustc_allocator/lib.rs +++ /dev/null @@ -1,44 +0,0 @@ -#![feature(nll)] -#![feature(rustc_private)] - -#![deny(rust_2018_idioms)] -#![deny(unused_lifetimes)] - -pub mod expand; - -pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ - AllocatorMethod { - name: "alloc", - inputs: &[AllocatorTy::Layout], - output: AllocatorTy::ResultPtr, - }, - AllocatorMethod { - name: "dealloc", - inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout], - output: AllocatorTy::Unit, - }, - AllocatorMethod { - name: "realloc", - inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize], - output: AllocatorTy::ResultPtr, - }, - AllocatorMethod { - name: "alloc_zeroed", - inputs: &[AllocatorTy::Layout], - output: AllocatorTy::ResultPtr, - }, -]; - -pub struct AllocatorMethod { - pub name: &'static str, - pub inputs: &'static [AllocatorTy], - pub output: AllocatorTy, -} - -pub enum AllocatorTy { - Layout, - Ptr, - ResultPtr, - Unit, - Usize, -} diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs index 02a05fd1102..5d43bf6ae28 100644 --- a/src/librustc_codegen_llvm/allocator.rs +++ b/src/librustc_codegen_llvm/allocator.rs @@ -2,9 +2,8 @@ use std::ffi::CString; use crate::attributes; use libc::c_uint; -use rustc::middle::allocator::AllocatorKind; use rustc::ty::TyCtxt; -use rustc_allocator::{ALLOCATOR_METHODS, AllocatorTy}; +use syntax::ext::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; use crate::ModuleLlvm; use crate::llvm::{self, False, True}; diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 0f0b9f27917..8dd241bd81a 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -32,7 +32,6 @@ extern crate flate2; #[macro_use] extern crate bitflags; extern crate libc; #[macro_use] extern crate rustc; -extern crate rustc_allocator; extern crate rustc_target; #[macro_use] extern crate rustc_data_structures; extern crate rustc_incremental; @@ -52,13 +51,13 @@ use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModul use rustc_codegen_ssa::CompiledModule; use errors::{FatalError, Handler}; use rustc::dep_graph::WorkProduct; +use syntax::ext::allocator::AllocatorKind; use syntax_pos::symbol::InternedString; pub use llvm_util::target_features; use std::any::Any; use std::sync::{mpsc, Arc}; use rustc::dep_graph::DepGraph; -use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; use rustc::session::Session; use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel}; diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml index 90d7320987c..89a6ec27fe5 100644 --- a/src/librustc_codegen_ssa/Cargo.toml +++ b/src/librustc_codegen_ssa/Cargo.toml @@ -24,7 +24,6 @@ rustc_serialize = { path = "../libserialize", package = "serialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } rustc = { path = "../librustc" } -rustc_allocator = { path = "../librustc_allocator" } rustc_apfloat = { path = "../librustc_apfloat" } rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_data_structures = { path = "../librustc_data_structures"} diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index c5553fa93cf..2d9220f897c 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -1,3 +1,4 @@ +use std::collections::hash_map::Entry::*; use std::sync::Arc; use rustc::ty::Instance; @@ -12,9 +13,8 @@ use rustc::ty::{TyCtxt, SymbolName}; use rustc::ty::query::Providers; use rustc::ty::subst::SubstsRef; use rustc::util::nodemap::{FxHashMap, DefIdMap}; -use rustc_allocator::ALLOCATOR_METHODS; use rustc_data_structures::indexed_vec::IndexVec; -use std::collections::hash_map::Entry::*; +use syntax::ext::allocator::ALLOCATOR_METHODS; pub type ExportedSymbols = FxHashMap< CrateNum, diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/src/librustc_codegen_ssa/traits/backend.rs index 9d5aaa7655d..9fbb44dcc99 100644 --- a/src/librustc_codegen_ssa/traits/backend.rs +++ b/src/librustc_codegen_ssa/traits/backend.rs @@ -3,12 +3,12 @@ use rustc::ty::Ty; use super::write::WriteBackendMethods; use super::CodegenObject; -use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::EncodedMetadata; use rustc::session::{Session, config}; use rustc::ty::TyCtxt; use rustc_codegen_utils::codegen_backend::CodegenBackend; use std::sync::Arc; +use syntax::ext::allocator::AllocatorKind; use syntax_pos::symbol::InternedString; pub trait BackendTypes { diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 3162af5086d..e8c9828a202 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -16,7 +16,6 @@ log = "0.4" env_logger = { version = "0.5", default-features = false } rayon = { version = "0.2.0", package = "rustc-rayon" } rustc = { path = "../librustc" } -rustc_allocator = { path = "../librustc_allocator" } rustc_target = { path = "../librustc_target" } rustc_ast_borrowck = { path = "../librustc_ast_borrowck" } rustc_data_structures = { path = "../librustc_data_structures" } @@ -37,5 +36,4 @@ rustc_interface = { path = "../librustc_interface" } rustc_serialize = { path = "../libserialize", package = "serialize" } syntax = { path = "../libsyntax" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } -syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index a90254e7e18..4937801d311 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -18,7 +18,6 @@ syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" } rustc_serialize = { path = "../libserialize", package = "serialize" } rustc = { path = "../librustc" } -rustc_allocator = { path = "../librustc_allocator" } rustc_ast_borrowck = { path = "../librustc_ast_borrowck" } rustc_incremental = { path = "../librustc_incremental" } rustc_traits = { path = "../librustc_traits" } diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index b334971353c..1cc7cfda012 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -469,7 +469,7 @@ fn configure_and_expand_inner<'a>( util::ReplaceBodyWithLoop::new(sess).visit_crate(&mut krate); } - let (has_proc_macro_decls, has_global_allocator) = time(sess, "AST validation", || { + let has_proc_macro_decls = time(sess, "AST validation", || { ast_validation::check_crate(sess, &krate) }); @@ -495,19 +495,6 @@ fn configure_and_expand_inner<'a>( }); } - if has_global_allocator { - // Expand global allocators, which are treated as an in-tree proc macro - time(sess, "creating allocators", || { - allocator::expand::modify( - &sess.parse_sess, - &mut resolver, - &mut krate, - crate_name.to_string(), - sess.diagnostic(), - ) - }); - } - // Done with macro expansion! if sess.opts.debugging_opts.input_stats { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 4105e030477..b63d14ca949 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -36,10 +36,10 @@ use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::ast; use syntax::ptr::P; use syntax::ast::Expr; -use syntax::attr::{self, HasAttrs}; +use syntax::attr::{self, HasAttrs, AttributeTemplate}; use syntax::source_map::Spanned; use syntax::edition::Edition; -use syntax::feature_gate::{AttributeGate, AttributeTemplate, AttributeType}; +use syntax::feature_gate::{AttributeGate, AttributeType}; use syntax::feature_gate::{Stability, deprecated_attributes}; use syntax_pos::{BytePos, Span, SyntaxContext}; use syntax::symbol::{Symbol, kw, sym}; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 126cfec157f..3404ec5e173 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -8,7 +8,6 @@ use rustc_data_structures::sync::{Lrc, RwLock, Lock}; use rustc::hir::def_id::CrateNum; use rustc_data_structures::svh::Svh; -use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::DepKind; use rustc::mir::interpret::AllocDecodingState; use rustc::session::{Session, CrateDisambiguator}; @@ -26,9 +25,9 @@ use std::{cmp, fs}; use syntax::ast; use syntax::attr; +use syntax::ext::allocator::{global_allocator_spans, AllocatorKind}; use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind}; use syntax::symbol::{Symbol, sym}; -use syntax::visit; use syntax::{span_err, span_fatal}; use syntax_pos::{Span, DUMMY_SP}; use log::{debug, info, log_enabled}; @@ -888,7 +887,14 @@ impl<'a> CrateLoader<'a> { } fn inject_allocator_crate(&mut self, krate: &ast::Crate) { - let has_global_allocator = has_global_allocator(krate); + let has_global_allocator = match &*global_allocator_spans(krate) { + [span1, span2, ..] => { + self.sess.struct_span_err(*span2, "cannot define multiple global allocators") + .span_note(*span1, "the previous global allocator is defined here").emit(); + true + } + spans => !spans.is_empty() + }; self.sess.has_global_allocator.set(has_global_allocator); // Check to see if we actually need an allocator. This desire comes @@ -975,25 +981,8 @@ impl<'a> CrateLoader<'a> { that implements the GlobalAlloc trait."); } self.sess.allocator_kind.set(Some(AllocatorKind::DefaultLib)); - - fn has_global_allocator(krate: &ast::Crate) -> bool { - struct Finder(bool); - let mut f = Finder(false); - visit::walk_crate(&mut f, krate); - return f.0; - - impl<'ast> visit::Visitor<'ast> for Finder { - fn visit_item(&mut self, i: &'ast ast::Item) { - if attr::contains_name(&i.attrs, sym::global_allocator) { - self.0 = true; - } - visit::walk_item(self, i) - } - } - } } - fn inject_dependency_if(&self, krate: CrateNum, what: &str, diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index b0fe06039f4..8db3ec491df 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -1,6 +1,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_patterns)] +#![feature(crate_visibility_modifier)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] #![feature(libc)] @@ -8,9 +9,9 @@ #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![feature(rustc_diagnostic_macros)] -#![feature(crate_visibility_modifier)] -#![feature(specialization)] #![feature(rustc_private)] +#![feature(slice_patterns)] +#![feature(specialization)] #![recursion_limit="256"] diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 56063596299..b550029d978 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -51,7 +51,6 @@ impl OuterImplTrait { struct AstValidator<'a> { session: &'a Session, has_proc_macro_decls: bool, - has_global_allocator: bool, /// Used to ban nested `impl Trait`, e.g., `impl Into`. /// Nested `impl Trait` _is_ allowed in associated type position, @@ -539,10 +538,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.has_proc_macro_decls = true; } - if attr::contains_name(&item.attrs, sym::global_allocator) { - self.has_global_allocator = true; - } - match item.node { ItemKind::Impl(unsafety, polarity, _, _, Some(..), ref ty, ref impl_items) => { self.invalid_visibility(&item.vis, None); @@ -848,11 +843,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } -pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) { +pub fn check_crate(session: &Session, krate: &Crate) -> bool { let mut validator = AstValidator { session, has_proc_macro_decls: false, - has_global_allocator: false, outer_impl_trait: None, is_impl_trait_banned: false, is_assoc_ty_bound_banned: false, @@ -861,5 +855,5 @@ pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) { }; visit::walk_crate(&mut validator, krate); - (validator.has_proc_macro_decls, validator.has_global_allocator) + validator.has_proc_macro_decls } diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index b41f1047fcb..dbf31ad0148 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -1,6 +1,9 @@ //! Parsing and validation of builtin attributes use crate::ast::{self, Attribute, MetaItem, NestedMetaItem}; +use crate::early_buffered_lints::BufferedEarlyLintId; +use crate::ext::base::ExtCtxt; +use crate::ext::build::AstBuilder; use crate::feature_gate::{Features, GatedCfg}; use crate::parse::ParseSess; @@ -19,6 +22,27 @@ enum AttrError { UnsupportedLiteral(&'static str, /* is_bytestr */ bool), } +/// A template that the attribute input must match. +/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. +#[derive(Clone, Copy)] +pub struct AttributeTemplate { + crate word: bool, + crate list: Option<&'static str>, + crate name_value_str: Option<&'static str>, +} + +impl AttributeTemplate { + /// Checks that the given meta-item is compatible with this template. + fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool { + match meta_item_kind { + ast::MetaItemKind::Word => self.word, + ast::MetaItemKind::List(..) => self.list.is_some(), + ast::MetaItemKind::NameValue(lit) if lit.node.is_str() => self.name_value_str.is_some(), + ast::MetaItemKind::NameValue(..) => false, + } + } +} + fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { let diag = &sess.span_diagnostic; match error { @@ -901,3 +925,76 @@ pub fn find_transparency( let fallback = if is_legacy { Transparency::SemiTransparent } else { Transparency::Opaque }; (transparency.map_or(fallback, |t| t.0), error) } + +pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) { + // All the built-in macro attributes are "words" at the moment. + let template = AttributeTemplate { word: true, list: None, name_value_str: None }; + let attr = ecx.attribute(meta_item.span, meta_item.clone()); + check_builtin_attribute(ecx.parse_sess, &attr, name, template); +} + +crate fn check_builtin_attribute( + sess: &ParseSess, attr: &ast::Attribute, name: Symbol, template: AttributeTemplate +) { + // Some special attributes like `cfg` must be checked + // before the generic check, so we skip them here. + let should_skip = |name| name == sym::cfg; + // Some of previously accepted forms were used in practice, + // report them as warnings for now. + let should_warn = |name| name == sym::doc || name == sym::ignore || + name == sym::inline || name == sym::link || + name == sym::test || name == sym::bench; + + match attr.parse_meta(sess) { + Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) { + let error_msg = format!("malformed `{}` attribute input", name); + let mut msg = "attribute must be of the form ".to_owned(); + let mut suggestions = vec![]; + let mut first = true; + if template.word { + first = false; + let code = format!("#[{}]", name); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.list { + if !first { + msg.push_str(" or "); + } + first = false; + let code = format!("#[{}({})]", name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.name_value_str { + if !first { + msg.push_str(" or "); + } + let code = format!("#[{} = \"{}\"]", name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if should_warn(name) { + sess.buffer_lint( + BufferedEarlyLintId::IllFormedAttributeInput, + meta.span, + ast::CRATE_NODE_ID, + &msg, + ); + } else { + sess.span_diagnostic.struct_span_err(meta.span, &error_msg) + .span_suggestions( + meta.span, + if suggestions.len() == 1 { + "must be of the form" + } else { + "the following are the possible correct uses" + }, + suggestions.into_iter(), + Applicability::HasPlaceholders, + ).emit(); + } + } + Err(mut err) => err.emit(), + } +} diff --git a/src/libsyntax/ext/allocator.rs b/src/libsyntax/ext/allocator.rs new file mode 100644 index 00000000000..99aeb5414c5 --- /dev/null +++ b/src/libsyntax/ext/allocator.rs @@ -0,0 +1,75 @@ +use crate::{ast, attr, visit}; +use crate::symbol::{sym, Symbol}; +use syntax_pos::Span; + +#[derive(Clone, Copy)] +pub enum AllocatorKind { + Global, + DefaultLib, + DefaultExe, +} + +impl AllocatorKind { + pub fn fn_name(&self, base: &str) -> String { + match *self { + AllocatorKind::Global => format!("__rg_{}", base), + AllocatorKind::DefaultLib => format!("__rdl_{}", base), + AllocatorKind::DefaultExe => format!("__rde_{}", base), + } + } +} + +pub enum AllocatorTy { + Layout, + Ptr, + ResultPtr, + Unit, + Usize, +} + +pub struct AllocatorMethod { + pub name: &'static str, + pub inputs: &'static [AllocatorTy], + pub output: AllocatorTy, +} + +pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ + AllocatorMethod { + name: "alloc", + inputs: &[AllocatorTy::Layout], + output: AllocatorTy::ResultPtr, + }, + AllocatorMethod { + name: "dealloc", + inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout], + output: AllocatorTy::Unit, + }, + AllocatorMethod { + name: "realloc", + inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize], + output: AllocatorTy::ResultPtr, + }, + AllocatorMethod { + name: "alloc_zeroed", + inputs: &[AllocatorTy::Layout], + output: AllocatorTy::ResultPtr, + }, +]; + +pub fn global_allocator_spans(krate: &ast::Crate) -> Vec { + struct Finder { name: Symbol, spans: Vec } + impl<'ast> visit::Visitor<'ast> for Finder { + fn visit_item(&mut self, item: &'ast ast::Item) { + if item.ident.name == self.name && + attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol) { + self.spans.push(item.span); + } + visit::walk_item(self, item) + } + } + + let name = Symbol::intern(&AllocatorKind::Global.fn_name("alloc")); + let mut f = Finder { name, spans: Vec::new() }; + visit::walk_crate(&mut f, krate); + f.spans +} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 43f0eaae7c9..72184b0bd64 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -19,8 +19,7 @@ use crate::ast::{ self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd, }; -use crate::attr; -use crate::early_buffered_lints::BufferedEarlyLintId; +use crate::attr::{self, check_builtin_attribute, AttributeTemplate}; use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; use crate::visit::{self, FnKind, Visitor}; @@ -906,27 +905,6 @@ pub enum AttributeGate { Ungated, } -/// A template that the attribute input must match. -/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. -#[derive(Clone, Copy)] -pub struct AttributeTemplate { - word: bool, - list: Option<&'static str>, - name_value_str: Option<&'static str>, -} - -impl AttributeTemplate { - /// Checks that the given meta-item is compatible with this template. - fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool { - match meta_item_kind { - ast::MetaItemKind::Word => self.word, - ast::MetaItemKind::List(..) => self.list.is_some(), - ast::MetaItemKind::NameValue(lit) if lit.node.is_str() => self.name_value_str.is_some(), - ast::MetaItemKind::NameValue(..) => false, - } - } -} - /// A convenience macro for constructing attribute templates. /// E.g., `template!(Word, List: "description")` means that the attribute /// supports forms `#[attr]` and `#[attr(description)]`. @@ -1117,7 +1095,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "the `#[rustc_const_unstable]` attribute \ is an internal feature", cfg_fn!(rustc_const_unstable))), - (sym::global_allocator, Normal, template!(Word), Ungated), (sym::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, sym::allocator_internals, "the `#[default_lib_allocator]` \ @@ -1902,70 +1879,6 @@ impl<'a> PostExpansionVisitor<'a> { Abi::System => {} } } - - fn check_builtin_attribute(&mut self, attr: &ast::Attribute, name: Symbol, - template: AttributeTemplate) { - // Some special attributes like `cfg` must be checked - // before the generic check, so we skip them here. - let should_skip = |name| name == sym::cfg; - // Some of previously accepted forms were used in practice, - // report them as warnings for now. - let should_warn = |name| name == sym::doc || name == sym::ignore || - name == sym::inline || name == sym::link; - - match attr.parse_meta(self.context.parse_sess) { - Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) { - let error_msg = format!("malformed `{}` attribute input", name); - let mut msg = "attribute must be of the form ".to_owned(); - let mut suggestions = vec![]; - let mut first = true; - if template.word { - first = false; - let code = format!("#[{}]", name); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.list { - if !first { - msg.push_str(" or "); - } - first = false; - let code = format!("#[{}({})]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.name_value_str { - if !first { - msg.push_str(" or "); - } - let code = format!("#[{} = \"{}\"]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if should_warn(name) { - self.context.parse_sess.buffer_lint( - BufferedEarlyLintId::IllFormedAttributeInput, - meta.span, - ast::CRATE_NODE_ID, - &msg, - ); - } else { - self.context.parse_sess.span_diagnostic.struct_span_err(meta.span, &error_msg) - .span_suggestions( - meta.span, - if suggestions.len() == 1 { - "must be of the form" - } else { - "the following are the possible correct uses" - }, - suggestions.into_iter(), - Applicability::HasPlaceholders, - ).emit(); - } - } - Err(mut err) => err.emit(), - } - } } impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { @@ -2006,7 +1919,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match attr_info { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some(&(name, _, template, _)) if name != sym::rustc_dummy => - self.check_builtin_attribute(attr, name, template), + check_builtin_attribute(self.context.parse_sess, attr, name, template), _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() { if token == token::Eq { // All key-value attributes are restricted to meta-item syntax. diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 0507a322a5f..75b4e89ec01 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -162,6 +162,7 @@ pub mod print { pub mod ext { pub use syntax_pos::hygiene; + pub mod allocator; pub mod base; pub mod build; pub mod derive; diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs new file mode 100644 index 00000000000..33072487e19 --- /dev/null +++ b/src/libsyntax_ext/global_allocator.rs @@ -0,0 +1,191 @@ +use syntax::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafety}; +use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident}; +use syntax::attr::check_builtin_macro_attribute; +use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; +use syntax::ext::base::{Annotatable, ExtCtxt}; +use syntax::ext::build::AstBuilder; +use syntax::ext::hygiene::SyntaxContext; +use syntax::ptr::P; +use syntax::symbol::{kw, sym, Symbol}; +use syntax_pos::Span; + +pub fn expand( + ecx: &mut ExtCtxt<'_>, + _span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec { + check_builtin_macro_attribute(ecx, meta_item, sym::global_allocator); + + let not_static = |item: Annotatable| { + ecx.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics"); + vec![item] + }; + let item = match item { + Annotatable::Item(item) => match item.node { + ItemKind::Static(..) => item, + _ => return not_static(Annotatable::Item(item)), + } + _ => return not_static(item), + }; + + // Generate a bunch of new items using the AllocFnFactory + let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id)); + let f = AllocFnFactory { + span, + kind: AllocatorKind::Global, + global: item.ident, + cx: ecx, + }; + + // Generate item statements for the allocator methods. + let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect(); + + // Generate anonymous constant serving as container for the allocator methods. + let const_ty = ecx.ty(span, TyKind::Tup(Vec::new())); + let const_body = ecx.expr_block(ecx.block(span, stmts)); + let const_item = + ecx.item_const(span, Ident::with_empty_ctxt(kw::Underscore), const_ty, const_body); + + // Return the original item and the new methods. + vec![Annotatable::Item(item), Annotatable::Item(const_item)] +} + +struct AllocFnFactory<'a, 'b> { + span: Span, + kind: AllocatorKind, + global: Ident, + cx: &'b ExtCtxt<'a>, +} + +impl AllocFnFactory<'_, '_> { + fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt { + let mut abi_args = Vec::new(); + let mut i = 0; + let ref mut mk = || { + let name = Ident::from_str(&format!("arg{}", i)); + i += 1; + name + }; + let args = method + .inputs + .iter() + .map(|ty| self.arg_ty(ty, &mut abi_args, mk)) + .collect(); + let result = self.call_allocator(method.name, args); + let (output_ty, output_expr) = self.ret_ty(&method.output, result); + let kind = ItemKind::Fn( + self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)), + FnHeader { + unsafety: Unsafety::Unsafe, + ..FnHeader::default() + }, + Generics::default(), + self.cx.block_expr(output_expr), + ); + let item = self.cx.item( + self.span, + Ident::from_str(&self.kind.fn_name(method.name)), + self.attrs(), + kind, + ); + self.cx.stmt_item(self.span, item) + } + + fn call_allocator(&self, method: &str, mut args: Vec>) -> P { + let method = self.cx.std_path(&[ + Symbol::intern("alloc"), + Symbol::intern("GlobalAlloc"), + Symbol::intern(method), + ]); + let method = self.cx.expr_path(self.cx.path(self.span, method)); + let allocator = self.cx.path_ident(self.span, self.global); + let allocator = self.cx.expr_path(allocator); + let allocator = self.cx.expr_addr_of(self.span, allocator); + args.insert(0, allocator); + + self.cx.expr_call(self.span, method, args) + } + + fn attrs(&self) -> Vec { + let special = sym::rustc_std_internal_symbol; + let special = self.cx.meta_word(self.span, special); + vec![self.cx.attribute(self.span, special)] + } + + fn arg_ty( + &self, + ty: &AllocatorTy, + args: &mut Vec, + ident: &mut dyn FnMut() -> Ident, + ) -> P { + match *ty { + AllocatorTy::Layout => { + let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize)); + let ty_usize = self.cx.ty_path(usize); + let size = ident(); + let align = ident(); + args.push(self.cx.arg(self.span, size, ty_usize.clone())); + args.push(self.cx.arg(self.span, align, ty_usize)); + + let layout_new = self.cx.std_path(&[ + Symbol::intern("alloc"), + Symbol::intern("Layout"), + Symbol::intern("from_size_align_unchecked"), + ]); + let layout_new = self.cx.expr_path(self.cx.path(self.span, layout_new)); + let size = self.cx.expr_ident(self.span, size); + let align = self.cx.expr_ident(self.span, align); + let layout = self.cx.expr_call(self.span, layout_new, vec![size, align]); + layout + } + + AllocatorTy::Ptr => { + let ident = ident(); + args.push(self.cx.arg(self.span, ident, self.ptr_u8())); + let arg = self.cx.expr_ident(self.span, ident); + self.cx.expr_cast(self.span, arg, self.ptr_u8()) + } + + AllocatorTy::Usize => { + let ident = ident(); + args.push(self.cx.arg(self.span, ident, self.usize())); + self.cx.expr_ident(self.span, ident) + } + + AllocatorTy::ResultPtr | AllocatorTy::Unit => { + panic!("can't convert AllocatorTy to an argument") + } + } + } + + fn ret_ty(&self, ty: &AllocatorTy, expr: P) -> (P, P) { + match *ty { + AllocatorTy::ResultPtr => { + // We're creating: + // + // #expr as *mut u8 + + let expr = self.cx.expr_cast(self.span, expr, self.ptr_u8()); + (self.ptr_u8(), expr) + } + + AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr), + + AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { + panic!("can't convert `AllocatorTy` to an output") + } + } + } + + fn usize(&self) -> P { + let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize)); + self.cx.ty_path(usize) + } + + fn ptr_u8(&self) -> P { + let u8 = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::u8)); + let ty_u8 = self.cx.ty_path(u8); + self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) + } +} diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 7de90278ed7..400bfe796bb 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -29,6 +29,7 @@ mod concat_idents; mod env; mod format; mod format_foreign; +mod global_allocator; mod global_asm; mod log_syntax; mod proc_macro_server; @@ -151,6 +152,12 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, SyntaxExtensionKind::LegacyAttr(Box::new(test::expand_bench)), edition ) }); + register(sym::global_allocator, SyntaxExtension { + allow_internal_unstable: Some([sym::rustc_attrs][..].into()), + ..SyntaxExtension::default( + SyntaxExtensionKind::LegacyAttr(Box::new(global_allocator::expand)), edition + ) + }); let allow_internal_unstable = Some([sym::fmt_internals][..].into()); register(sym::format_args, SyntaxExtension { diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index f8755a1d1d7..d381c42f9ce 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -1,31 +1,34 @@ /// The expansion from a test function to the appropriate test struct for libtest /// Ideally, this code would be in libtest but for efficiency and error messages it lives here. +use syntax::ast; +use syntax::attr::{self, check_builtin_macro_attribute}; use syntax::ext::base::*; use syntax::ext::build::AstBuilder; use syntax::ext::hygiene::SyntaxContext; -use syntax::attr; -use syntax::ast; use syntax::print::pprust; use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; + use std::iter; pub fn expand_test( cx: &mut ExtCtxt<'_>, attr_sp: Span, - _meta_item: &ast::MetaItem, + meta_item: &ast::MetaItem, item: Annotatable, ) -> Vec { + check_builtin_macro_attribute(cx, meta_item, sym::test); expand_test_or_bench(cx, attr_sp, item, false) } pub fn expand_bench( cx: &mut ExtCtxt<'_>, attr_sp: Span, - _meta_item: &ast::MetaItem, + meta_item: &ast::MetaItem, item: Annotatable, ) -> Vec { + check_builtin_macro_attribute(cx, meta_item, sym::bench); expand_test_or_bench(cx, attr_sp, item, true) } diff --git a/src/libsyntax_ext/test_case.rs b/src/libsyntax_ext/test_case.rs index 355f2428e08..ea4a8d541ab 100644 --- a/src/libsyntax_ext/test_case.rs +++ b/src/libsyntax_ext/test_case.rs @@ -9,10 +9,11 @@ // We mark item with an inert attribute "rustc_test_marker" which the test generation // logic will pick up on. +use syntax::ast; +use syntax::attr::check_builtin_macro_attribute; use syntax::ext::base::*; use syntax::ext::build::AstBuilder; use syntax::ext::hygiene::SyntaxContext; -use syntax::ast; use syntax::source_map::respan; use syntax::symbol::sym; use syntax_pos::Span; @@ -20,9 +21,11 @@ use syntax_pos::Span; pub fn expand( ecx: &mut ExtCtxt<'_>, attr_sp: Span, - _meta_item: &ast::MetaItem, + meta_item: &ast::MetaItem, anno_item: Annotatable ) -> Vec { + check_builtin_macro_attribute(ecx, meta_item, sym::test_case); + if !ecx.ecfg.should_test { return vec![]; } let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id)); diff --git a/src/test/run-pass/allocator/custom-in-block.rs b/src/test/run-pass/allocator/custom-in-block.rs new file mode 100644 index 00000000000..12813a1fc8b --- /dev/null +++ b/src/test/run-pass/allocator/custom-in-block.rs @@ -0,0 +1,22 @@ +// run-pass +// no-prefer-dynamic +// aux-build:custom.rs +// aux-build:helper.rs + +extern crate custom; +extern crate helper; + +use custom::A; +use std::sync::atomic::{AtomicUsize, Ordering}; + +fn main() { + #[global_allocator] + pub static GLOBAL: A = A(AtomicUsize::new(0)); + + let n = GLOBAL.0.load(Ordering::SeqCst); + let s = Box::new(0); + helper::work_with(&s); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1); + drop(s); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); +} diff --git a/src/test/run-pass/allocator/custom-in-submodule.rs b/src/test/run-pass/allocator/custom-in-submodule.rs new file mode 100644 index 00000000000..ea341b1ac14 --- /dev/null +++ b/src/test/run-pass/allocator/custom-in-submodule.rs @@ -0,0 +1,26 @@ +// run-pass +// no-prefer-dynamic +// aux-build:custom.rs +// aux-build:helper.rs + +extern crate custom; +extern crate helper; + +use custom::A; +use std::sync::atomic::{AtomicUsize, Ordering}; + +mod submodule { + use super::*; + + #[global_allocator] + pub static GLOBAL: A = A(AtomicUsize::new(0)); +} + +fn main() { + let n = submodule::GLOBAL.0.load(Ordering::SeqCst); + let s = Box::new(0); + helper::work_with(&s); + assert_eq!(submodule::GLOBAL.0.load(Ordering::SeqCst), n + 1); + drop(s); + assert_eq!(submodule::GLOBAL.0.load(Ordering::SeqCst), n + 2); +} diff --git a/src/test/ui/allocator-submodule.rs b/src/test/ui/allocator-submodule.rs deleted file mode 100644 index 7a8d86b8da1..00000000000 --- a/src/test/ui/allocator-submodule.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Tests that it is possible to create a global allocator in a submodule, rather than in the crate -// root. - -extern crate alloc; - -use std::{ - alloc::{GlobalAlloc, Layout}, - ptr, -}; - -struct MyAlloc; - -unsafe impl GlobalAlloc for MyAlloc { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - ptr::null_mut() - } - - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {} -} - -mod submod { - use super::MyAlloc; - - #[global_allocator] - static MY_HEAP: MyAlloc = MyAlloc; //~ ERROR global_allocator -} - -fn main() {} diff --git a/src/test/ui/allocator-submodule.stderr b/src/test/ui/allocator-submodule.stderr deleted file mode 100644 index 91c7c0f6b8e..00000000000 --- a/src/test/ui/allocator-submodule.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: `global_allocator` cannot be used in submodules - --> $DIR/allocator-submodule.rs:25:5 - | -LL | static MY_HEAP: MyAlloc = MyAlloc; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/allocator/allocator-args.rs b/src/test/ui/allocator/allocator-args.rs new file mode 100644 index 00000000000..1033f947c5f --- /dev/null +++ b/src/test/ui/allocator/allocator-args.rs @@ -0,0 +1,13 @@ +use std::alloc::{GlobalAlloc, Layout}; + +struct A; + +unsafe impl GlobalAlloc for A { + unsafe fn alloc(&self, _: Layout) -> *mut u8 { panic!() } + unsafe fn dealloc(&self, _: *mut u8, _: Layout) { panic!() } +} + +#[global_allocator(malloc)] //~ ERROR malformed `global_allocator` attribute input +static S: A = A; + +fn main() {} diff --git a/src/test/ui/allocator/allocator-args.stderr b/src/test/ui/allocator/allocator-args.stderr new file mode 100644 index 00000000000..dfff2a7e709 --- /dev/null +++ b/src/test/ui/allocator/allocator-args.stderr @@ -0,0 +1,8 @@ +error: malformed `global_allocator` attribute input + --> $DIR/allocator-args.rs:10:1 + | +LL | #[global_allocator(malloc)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[global_allocator]` + +error: aborting due to previous error + diff --git a/src/test/ui/allocator/two-allocators.rs b/src/test/ui/allocator/two-allocators.rs index 0f81fc41823..aa1291e77ae 100644 --- a/src/test/ui/allocator/two-allocators.rs +++ b/src/test/ui/allocator/two-allocators.rs @@ -4,6 +4,6 @@ use std::alloc::System; static A: System = System; #[global_allocator] static B: System = System; -//~^ ERROR: cannot define more than one `#[global_allocator]` +//~^ ERROR: cannot define multiple global allocators fn main() {} diff --git a/src/test/ui/allocator/two-allocators.stderr b/src/test/ui/allocator/two-allocators.stderr index 6b0c2b2a25d..ed0aa13eb80 100644 --- a/src/test/ui/allocator/two-allocators.stderr +++ b/src/test/ui/allocator/two-allocators.stderr @@ -1,8 +1,14 @@ -error: cannot define more than one `#[global_allocator]` +error: cannot define multiple global allocators --> $DIR/two-allocators.rs:6:1 | LL | static B: System = System; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the previous global allocator is defined here + --> $DIR/two-allocators.rs:4:1 + | +LL | static A: System = System; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-bench.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-bench.stderr index 503ef020d96..37b5e792dc2 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-bench.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-bench.stderr @@ -1,3 +1,13 @@ +warning: attribute must be of the form `#[bench]` + --> $DIR/issue-43106-gating-of-bench.rs:15:1 + | +LL | #![bench = "4100"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(ill_formed_attribute_input)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + error[E0601]: `main` function not found in crate `issue_43106_gating_of_bench` | = note: consider adding a `main` function to `$DIR/issue-43106-gating-of-bench.rs` diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr index 2ab35be43c5..dbffabf3e02 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr @@ -1,3 +1,13 @@ +warning: attribute must be of the form `#[test]` + --> $DIR/issue-43106-gating-of-test.rs:10:1 + | +LL | #![test = "4200"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(ill_formed_attribute_input)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + error[E0601]: `main` function not found in crate `issue_43106_gating_of_test` | = note: consider adding a `main` function to `$DIR/issue-43106-gating-of-test.rs` diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 6a728b02f92..335c1aa0175 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -344,7 +344,7 @@ fn get_and_check_lib_features(base_src_path: &Path, Ok((name, f)) => { let mut check_features = |f: &Feature, list: &Features, display: &str| { if let Some(ref s) = list.get(name) { - if f.tracking_issue != s.tracking_issue { + if f.tracking_issue != s.tracking_issue && f.level != Status::Stable { tidy_error!(bad, "{}:{}: mismatches the `issue` in {}", file.display(),