diff --git a/src/doc/unstable-book/src/language-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md similarity index 100% rename from src/doc/unstable-book/src/language-features/asm.md rename to src/doc/unstable-book/src/library-features/asm.md diff --git a/src/doc/unstable-book/src/language-features/concat-idents.md b/src/doc/unstable-book/src/library-features/concat-idents.md similarity index 100% rename from src/doc/unstable-book/src/language-features/concat-idents.md rename to src/doc/unstable-book/src/library-features/concat-idents.md diff --git a/src/doc/unstable-book/src/language-features/global-asm.md b/src/doc/unstable-book/src/library-features/global-asm.md similarity index 100% rename from src/doc/unstable-book/src/language-features/global-asm.md rename to src/doc/unstable-book/src/library-features/global-asm.md diff --git a/src/doc/unstable-book/src/language-features/trace-macros.md b/src/doc/unstable-book/src/library-features/trace-macros.md similarity index 100% rename from src/doc/unstable-book/src/language-features/trace-macros.md rename to src/doc/unstable-book/src/library-features/trace-macros.md diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index fbeda43af42b0..f0bdb0018efe7 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -913,9 +913,12 @@ pub fn compile_unit_metadata( } debug!("compile_unit_metadata: {:?}", name_in_debuginfo); + let rustc_producer = format!( + "rustc version {}", + option_env!("CFG_VERSION").expect("CFG_VERSION"), + ); // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice. - let producer = format!("clang LLVM (rustc version {})", - (option_env!("CFG_VERSION")).expect("CFG_VERSION")); + let producer = format!("clang LLVM ({})", rustc_producer); let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); let name_in_debuginfo = SmallCStr::new(&name_in_debuginfo); @@ -980,6 +983,21 @@ pub fn compile_unit_metadata( gcov_metadata); } + // Insert `llvm.ident` metadata on the wasm32 targets since that will + // get hooked up to the "producer" sections `processed-by` information. + if tcx.sess.opts.target_triple.triple().starts_with("wasm32") { + let name_metadata = llvm::LLVMMDStringInContext( + debug_context.llcontext, + rustc_producer.as_ptr() as *const _, + rustc_producer.as_bytes().len() as c_uint, + ); + llvm::LLVMAddNamedMetadataOperand( + debug_context.llmod, + const_cstr!("llvm.ident").as_ptr(), + llvm::LLVMMDNodeInContext(debug_context.llcontext, &name_metadata, 1), + ); + } + return unit_metadata; }; diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 707b7cae16ce7..3f6a1a72ea61e 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -678,14 +678,6 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, sess.fatal(&format!("failed to run dsymutil: {}", e)) } } - - if sess.opts.target_triple.triple() == "wasm32-unknown-unknown" { - super::wasm::add_producer_section( - &out_filename, - &sess.edition().to_string(), - option_env!("CFG_VERSION").unwrap_or("unknown"), - ); - } } /// Returns a boolean indicating whether the specified crate should be ignored diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index cb8870d0be90c..26091005f25aa 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -901,7 +901,45 @@ pub struct WasmLd<'a> { } impl<'a> WasmLd<'a> { - fn new(cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> { + fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> { + // If the atomics feature is enabled for wasm then we need a whole bunch + // of flags: + // + // * `--shared-memory` - the link won't even succeed without this, flags + // the one linear memory as `shared` + // + // * `--max-memory=1G` - when specifying a shared memory this must also + // be specified. We conservatively choose 1GB but users should be able + // to override this with `-C link-arg`. + // + // * `--import-memory` - it doesn't make much sense for memory to be + // exported in a threaded module because typically you're + // sharing memory and instantiating the module multiple times. As a + // result if it were exported then we'd just have no sharing. + // + // * `--passive-segments` - all memory segments should be passive to + // prevent each module instantiation from reinitializing memory. + // + // * `--export=__wasm_init_memory` - when using `--passive-segments` the + // linker will synthesize this function, and so we need to make sure + // that our usage of `--export` below won't accidentally cause this + // function to get deleted. + // + // * `--export=*tls*` - when `#[thread_local]` symbols are used these + // symbols are how the TLS segments are initialized and configured. + let atomics = sess.opts.cg.target_feature.contains("+atomics") || + sess.target.target.options.features.contains("+atomics"); + if atomics { + cmd.arg("--shared-memory"); + cmd.arg("--max-memory=1073741824"); + cmd.arg("--import-memory"); + cmd.arg("--passive-segments"); + cmd.arg("--export=__wasm_init_memory"); + cmd.arg("--export=__wasm_init_tls"); + cmd.arg("--export=__tls_size"); + cmd.arg("--export=__tls_align"); + cmd.arg("--export=__tls_base"); + } WasmLd { cmd, sess, info } } } @@ -1004,6 +1042,13 @@ impl<'a> Linker for WasmLd<'a> { for sym in self.info.exports[&crate_type].iter() { self.cmd.arg("--export").arg(&sym); } + + // LLD will hide these otherwise-internal symbols since our `--export` + // list above is a whitelist of what to export. Various bits and pieces + // of tooling use this, so be sure these symbols make their way out of + // the linker as well. + self.cmd.arg("--export=__heap_base"); + self.cmd.arg("--export=__data_end"); } fn subsystem(&mut self, _subsystem: &str) { diff --git a/src/librustc_codegen_ssa/back/mod.rs b/src/librustc_codegen_ssa/back/mod.rs index a16d099ee3e4d..901891d85a465 100644 --- a/src/librustc_codegen_ssa/back/mod.rs +++ b/src/librustc_codegen_ssa/back/mod.rs @@ -6,4 +6,3 @@ pub mod command; pub mod symbol_export; pub mod archive; pub mod rpath; -pub mod wasm; diff --git a/src/librustc_codegen_ssa/back/wasm.rs b/src/librustc_codegen_ssa/back/wasm.rs deleted file mode 100644 index 2a9e81a788e52..0000000000000 --- a/src/librustc_codegen_ssa/back/wasm.rs +++ /dev/null @@ -1,191 +0,0 @@ -use std::fs; -use std::path::Path; -use std::str; - -use rustc_serialize::leb128; - -// https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec -const WASM_CUSTOM_SECTION_ID: u8 = 0; - -/// Adds or augment the existing `producers` section to encode information about -/// the Rust compiler used to produce the wasm file. -pub fn add_producer_section( - path: &Path, - rust_version: &str, - rustc_version: &str, -) { - struct Field<'a> { - name: &'a str, - values: Vec>, - } - - #[derive(Copy, Clone)] - struct FieldValue<'a> { - name: &'a str, - version: &'a str, - } - - let wasm = fs::read(path).expect("failed to read wasm output"); - let mut ret = WasmEncoder::new(); - ret.data.extend(&wasm[..8]); - - // skip the 8 byte wasm/version header - let rustc_value = FieldValue { - name: "rustc", - version: rustc_version, - }; - let rust_value = FieldValue { - name: "Rust", - version: rust_version, - }; - let mut fields = Vec::new(); - let mut wrote_rustc = false; - let mut wrote_rust = false; - - // Move all sections from the original wasm file to our output, skipping - // everything except the producers section - for (id, raw) in WasmSections(WasmDecoder::new(&wasm[8..])) { - if id != WASM_CUSTOM_SECTION_ID { - ret.byte(id); - ret.bytes(raw); - continue - } - let mut decoder = WasmDecoder::new(raw); - if decoder.str() != "producers" { - ret.byte(id); - ret.bytes(raw); - continue - } - - // Read off the producers section into our fields outside the loop, - // we'll re-encode the producers section when we're done (to handle an - // entirely missing producers section as well). - info!("rewriting existing producers section"); - - for _ in 0..decoder.u32() { - let name = decoder.str(); - let mut values = Vec::new(); - for _ in 0..decoder.u32() { - let name = decoder.str(); - let version = decoder.str(); - values.push(FieldValue { name, version }); - } - - if name == "language" { - values.push(rust_value); - wrote_rust = true; - } else if name == "processed-by" { - values.push(rustc_value); - wrote_rustc = true; - } - fields.push(Field { name, values }); - } - } - - if !wrote_rust { - fields.push(Field { - name: "language", - values: vec![rust_value], - }); - } - if !wrote_rustc { - fields.push(Field { - name: "processed-by", - values: vec![rustc_value], - }); - } - - // Append the producers section to the end of the wasm file. - let mut section = WasmEncoder::new(); - section.str("producers"); - section.u32(fields.len() as u32); - for field in fields { - section.str(field.name); - section.u32(field.values.len() as u32); - for value in field.values { - section.str(value.name); - section.str(value.version); - } - } - ret.byte(WASM_CUSTOM_SECTION_ID); - ret.bytes(§ion.data); - - fs::write(path, &ret.data).expect("failed to write wasm output"); -} - -struct WasmSections<'a>(WasmDecoder<'a>); - -impl<'a> Iterator for WasmSections<'a> { - type Item = (u8, &'a [u8]); - - fn next(&mut self) -> Option<(u8, &'a [u8])> { - if self.0.data.is_empty() { - return None - } - - // see https://webassembly.github.io/spec/core/binary/modules.html#sections - let id = self.0.byte(); - let section_len = self.0.u32(); - info!("new section {} / {} bytes", id, section_len); - let section = self.0.skip(section_len as usize); - Some((id, section)) - } -} - -struct WasmDecoder<'a> { - data: &'a [u8], -} - -impl<'a> WasmDecoder<'a> { - fn new(data: &'a [u8]) -> WasmDecoder<'a> { - WasmDecoder { data } - } - - fn byte(&mut self) -> u8 { - self.skip(1)[0] - } - - fn u32(&mut self) -> u32 { - let (n, l1) = leb128::read_u32_leb128(self.data); - self.data = &self.data[l1..]; - return n - } - - fn skip(&mut self, amt: usize) -> &'a [u8] { - let (data, rest) = self.data.split_at(amt); - self.data = rest; - data - } - - fn str(&mut self) -> &'a str { - let len = self.u32(); - str::from_utf8(self.skip(len as usize)).unwrap() - } -} - -struct WasmEncoder { - data: Vec, -} - -impl WasmEncoder { - fn new() -> WasmEncoder { - WasmEncoder { data: Vec::new() } - } - - fn u32(&mut self, val: u32) { - leb128::write_u32_leb128(&mut self.data, val); - } - - fn byte(&mut self, val: u8) { - self.data.push(val); - } - - fn bytes(&mut self, val: &[u8]) { - self.u32(val.len() as u32); - self.data.extend_from_slice(val); - } - - fn str(&mut self, val: &str) { - self.bytes(val.as_bytes()) - } -} diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index f37c474fa4fff..e3f16a3c9ea45 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -54,6 +54,16 @@ pub trait AllocMap { k: K, vacant: impl FnOnce() -> Result ) -> Result<&mut V, E>; + + /// Read-only lookup. + fn get(&self, k: K) -> Option<&V> { + self.get_or(k, || Err(())).ok() + } + + /// Mutable lookup. + fn get_mut(&mut self, k: K) -> Option<&mut V> { + self.get_mut_or(k, || Err(())).ok() + } } /// Methods of this trait signifies a point where CTFE evaluation would fail diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 4575784ac3703..87dd7738410ee 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -535,48 +535,52 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { id: AllocId, liveness: AllocCheck, ) -> InterpResult<'static, (Size, Align)> { + // # Regular allocations // Don't use `self.get` here as that will // a) cause cycles in case `id` refers to a static // b) duplicate a static's allocation in miri - match self.alloc_map.get_or(id, || Err(())) { - Ok((_, alloc)) => Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)), - Err(()) => { - // Not a local allocation, check the global `tcx.alloc_map`. - - // Can't do this in the match argument, we may get cycle errors since the lock would - // be held throughout the match. - let alloc = self.tcx.alloc_map.lock().get(id); - match alloc { - Some(GlobalAlloc::Static(did)) => { - // Use size and align of the type. - let ty = self.tcx.type_of(did); - let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); - Ok((layout.size, layout.align.abi)) - }, - Some(GlobalAlloc::Memory(alloc)) => - // Need to duplicate the logic here, because the global allocations have - // different associated types than the interpreter-local ones. - Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)), - Some(GlobalAlloc::Function(_)) => { - if let AllocCheck::Dereferencable = liveness { - // The caller requested no function pointers. - err!(DerefFunctionPointer) - } else { - Ok((Size::ZERO, Align::from_bytes(1).unwrap())) - } - }, - // The rest must be dead. - None => if let AllocCheck::MaybeDead = liveness { - // Deallocated pointers are allowed, we should be able to find - // them in the map. - Ok(*self.dead_alloc_map.get(&id) - .expect("deallocated pointers should all be recorded in \ - `dead_alloc_map`")) - } else { - err!(DanglingPointerDeref) - }, - } - } + if let Some((_, alloc)) = self.alloc_map.get(id) { + return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)); + } + + // # Function pointers + // (both global from `alloc_map` and local from `extra_fn_ptr_map`) + if let Ok(_) = self.get_fn_alloc(id) { + return if let AllocCheck::Dereferencable = liveness { + // The caller requested no function pointers. + err!(DerefFunctionPointer) + } else { + Ok((Size::ZERO, Align::from_bytes(1).unwrap())) + }; + } + + // # Statics + // Can't do this in the match argument, we may get cycle errors since the lock would + // be held throughout the match. + let alloc = self.tcx.alloc_map.lock().get(id); + match alloc { + Some(GlobalAlloc::Static(did)) => { + // Use size and align of the type. + let ty = self.tcx.type_of(did); + let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); + Ok((layout.size, layout.align.abi)) + }, + Some(GlobalAlloc::Memory(alloc)) => + // Need to duplicate the logic here, because the global allocations have + // different associated types than the interpreter-local ones. + Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)), + Some(GlobalAlloc::Function(_)) => + bug!("We already checked function pointers above"), + // The rest must be dead. + None => if let AllocCheck::MaybeDead = liveness { + // Deallocated pointers are allowed, we should be able to find + // them in the map. + Ok(*self.dead_alloc_map.get(&id) + .expect("deallocated pointers should all be recorded in \ + `dead_alloc_map`")) + } else { + err!(DanglingPointerDeref) + }, } } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 2b349613dc54f..6fce7ca1f33fb 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -23,7 +23,7 @@ use rustc_data_structures::fx::FxHashSet; use std::path::Path; use std::env; -use syntax::ast::{self, Attribute, NodeId, PatKind, CRATE_NODE_ID}; +use syntax::ast::{self, Attribute, NodeId, PatKind}; use syntax::parse::token; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{ @@ -75,15 +75,13 @@ macro_rules! access_from_vis { }; } -pub struct DumpVisitor<'l, 'tcx, 'll> { - save_ctxt: SaveContext<'l, 'tcx>, +pub struct DumpVisitor<'l, 'tcx> { + pub save_ctxt: SaveContext<'l, 'tcx>, tcx: TyCtxt<'tcx>, - dumper: &'ll mut Dumper, + dumper: Dumper, span: SpanUtils<'l>, - cur_scope: NodeId, - // Set of macro definition (callee) spans, and the set // of macro use (callsite) spans. We store these to ensure // we only write one macro def per unique macro definition, and @@ -92,36 +90,29 @@ pub struct DumpVisitor<'l, 'tcx, 'll> { // macro_calls: FxHashSet, } -impl<'l, 'tcx, 'll> DumpVisitor<'l, 'tcx, 'll> { +impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { pub fn new( save_ctxt: SaveContext<'l, 'tcx>, - dumper: &'ll mut Dumper, - ) -> DumpVisitor<'l, 'tcx, 'll> { + ) -> DumpVisitor<'l, 'tcx> { let span_utils = SpanUtils::new(&save_ctxt.tcx.sess); + let dumper = Dumper::new(save_ctxt.config.clone()); DumpVisitor { tcx: save_ctxt.tcx, save_ctxt, dumper, span: span_utils, - cur_scope: CRATE_NODE_ID, // mac_defs: FxHashSet::default(), // macro_calls: FxHashSet::default(), } } - fn nest_scope(&mut self, scope_id: NodeId, f: F) - where - F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll>), - { - let parent_scope = self.cur_scope; - self.cur_scope = scope_id; - f(self); - self.cur_scope = parent_scope; + pub fn analysis(&self) -> &rls_data::Analysis { + self.dumper.analysis() } fn nest_tables(&mut self, item_id: NodeId, f: F) where - F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll>), + F: FnOnce(&mut Self), { let item_def_id = self.tcx.hir().local_def_id_from_node_id(item_id); if self.tcx.has_typeck_tables(item_def_id) { @@ -320,7 +311,7 @@ impl<'l, 'tcx, 'll> DumpVisitor<'l, 'tcx, 'll> { // walk the fn body if let Some(body) = body { - self.nest_tables(id, |v| v.nest_scope(id, |v| v.visit_block(body))); + self.nest_tables(id, |v| v.visit_block(body)); } } @@ -405,7 +396,7 @@ impl<'l, 'tcx, 'll> DumpVisitor<'l, 'tcx, 'll> { self.visit_ty(&ret_ty); } - self.nest_tables(item.id, |v| v.nest_scope(item.id, |v| v.visit_block(&body))); + self.nest_tables(item.id, |v| v.visit_block(&body)); } fn process_static_or_const_item( @@ -1311,7 +1302,7 @@ impl<'l, 'tcx, 'll> DumpVisitor<'l, 'tcx, 'll> { } } -impl<'l, 'tcx, 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll> { +impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { fn visit_mod(&mut self, m: &'l ast::Mod, span: Span, attrs: &[ast::Attribute], id: NodeId) { // Since we handle explicit modules ourselves in visit_item, this should // only get called for the root module of a crate. @@ -1349,7 +1340,7 @@ impl<'l, 'tcx, 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll> { attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt), }, ); - self.nest_scope(id, |v| visit::walk_mod(v, m)); + visit::walk_mod(self, m); } fn visit_item(&mut self, item: &'l ast::Item) { @@ -1404,7 +1395,7 @@ impl<'l, 'tcx, 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll> { } Mod(ref m) => { self.process_mod(item); - self.nest_scope(item.id, |v| visit::walk_mod(v, m)); + visit::walk_mod(self, m); } Ty(ref ty, ref ty_params) => { let qualname = format!("::{}", @@ -1570,7 +1561,7 @@ impl<'l, 'tcx, 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll> { // walk the body self.nest_tables(ex.id, |v| { v.process_formals(&decl.inputs, &id); - v.nest_scope(ex.id, |v| v.visit_expr(body)) + v.visit_expr(body) }); } ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) => { diff --git a/src/librustc_save_analysis/dumper.rs b/src/librustc_save_analysis/dumper.rs index 6fb55e6c99055..b80778c8fec7e 100644 --- a/src/librustc_save_analysis/dumper.rs +++ b/src/librustc_save_analysis/dumper.rs @@ -22,8 +22,8 @@ impl Dumper { } } - pub fn to_output(self, f: impl FnOnce(&Analysis)) { - f(&self.result) + pub fn analysis(&self) -> &Analysis { + &self.result } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 9edb4c0fa6748..25dcd4664a624 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -35,12 +35,11 @@ use syntax::visit::{self, Visitor}; use syntax::print::pprust::{arg_to_string, ty_to_string}; use syntax_pos::*; -use dumper::Dumper; use dump_visitor::DumpVisitor; use span_utils::SpanUtils; use rls_data::{Def, DefKind, ExternalCrateData, GlobalCrateId, MacroRef, Ref, RefKind, Relation, - RelationKind, SpanData, Impl, ImplKind}; + RelationKind, SpanData, Impl, ImplKind, Analysis}; use rls_data::config::Config; use log::{debug, error, info}; @@ -997,12 +996,10 @@ impl<'l> Visitor<'l> for PathCollector<'l> { /// Defines what to do with the results of saving the analysis. pub trait SaveHandler { - fn save<'l, 'tcx>( + fn save( &mut self, - save_ctxt: SaveContext<'l, 'tcx>, - krate: &ast::Crate, - cratename: &str, - input: &'l Input, + save_ctxt: &SaveContext<'_, '_>, + analysis: &Analysis, ); } @@ -1062,28 +1059,17 @@ impl<'a> DumpHandler<'a> { } } -impl<'a> SaveHandler for DumpHandler<'a> { - fn save<'l, 'tcx>( +impl SaveHandler for DumpHandler<'_> { + fn save( &mut self, - save_ctxt: SaveContext<'l, 'tcx>, - krate: &ast::Crate, - cratename: &str, - input: &'l Input, + save_ctxt: &SaveContext<'_, '_>, + analysis: &Analysis, ) { let sess = &save_ctxt.tcx.sess; let (output, file_name) = self.output_file(&save_ctxt); - let mut dumper = Dumper::new(save_ctxt.config.clone()); - let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper); - - visitor.dump_crate_info(cratename, krate); - visitor.dump_compilation_options(input, cratename); - visit::walk_crate(&mut visitor, krate); - - dumper.to_output(|analysis| { - if let Err(e) = serde_json::to_writer(output, analysis) { - error!("Can't serialize save-analysis: {:?}", e); - } - }); + if let Err(e) = serde_json::to_writer(output, &analysis) { + error!("Can't serialize save-analysis: {:?}", e); + } if sess.opts.debugging_opts.emit_artifact_notifications { sess.parse_sess.span_diagnostic @@ -1097,27 +1083,13 @@ pub struct CallbackHandler<'b> { pub callback: &'b mut dyn FnMut(&rls_data::Analysis), } -impl<'b> SaveHandler for CallbackHandler<'b> { - fn save<'l, 'tcx>( +impl SaveHandler for CallbackHandler<'_> { + fn save( &mut self, - save_ctxt: SaveContext<'l, 'tcx>, - krate: &ast::Crate, - cratename: &str, - input: &'l Input, + _: &SaveContext<'_, '_>, + analysis: &Analysis, ) { - // We're using the Dumper here because it has the format of the - // save-analysis results that we will pass to the callback. IOW, we are - // using the Dumper to collect the save-analysis results, but not - // actually to dump them to a file. This is all a bit convoluted and - // there is certainly a simpler design here trying to get out (FIXME). - let mut dumper = Dumper::new(save_ctxt.config.clone()); - let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper); - - visitor.dump_crate_info(cratename, krate); - visitor.dump_compilation_options(input, cratename); - visit::walk_crate(&mut visitor, krate); - - dumper.to_output(|a| (self.callback)(a)) + (self.callback)(analysis) } } @@ -1148,7 +1120,13 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>( impl_counter: Cell::new(0), }; - handler.save(save_ctxt, krate, cratename, input) + let mut visitor = DumpVisitor::new(save_ctxt); + + visitor.dump_crate_info(cratename, krate); + visitor.dump_compilation_options(input, cratename); + visit::walk_crate(&mut visitor, krate); + + handler.save(&visitor.save_ctxt, &visitor.analysis()) }) } diff --git a/src/librustc_target/spec/wasm32_base.rs b/src/librustc_target/spec/wasm32_base.rs index 39a8ce9282573..6f00245b00941 100644 --- a/src/librustc_target/spec/wasm32_base.rs +++ b/src/librustc_target/spec/wasm32_base.rs @@ -132,6 +132,14 @@ pub fn options() -> TargetOptions { // non-relative calls and such later on). relocation_model: "static".to_string(), + // When the atomics feature is activated then these two keys matter, + // otherwise they're basically ignored by the standard library. In this + // mode, however, the `#[thread_local]` attribute works (i.e. + // `has_elf_tls`) and we need to get it to work by specifying + // `local-exec` as that's all that's implemented in LLVM today for wasm. + has_elf_tls: true, + tls_model: "local-exec".to_string(), + .. Default::default() } } diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 6da77ab57d11e..2e0da0409eb09 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -75,11 +75,6 @@ panic_immediate_abort = ["core/panic_immediate_abort"] # requires rebuilding the standard library to use it. wasm_syscall = [] -# An off-by-default features to enable libstd to assume that wasm-bindgen is in -# the environment for hooking up some thread-related information like the -# current thread id and accessing/getting the current thread's TCB -wasm-bindgen-threads = [] - # Enable std_detect default features for stdarch/crates/std_detect: # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml std_detect_file_io = [] diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs index e22434439f5bb..f842869e08ee6 100644 --- a/src/libstd/sys/wasi/mod.rs +++ b/src/libstd/sys/wasi/mod.rs @@ -47,6 +47,8 @@ pub mod stdio; pub mod thread; #[path = "../wasm/thread_local.rs"] pub mod thread_local; +#[path = "../wasm/fast_thread_local.rs"] +pub mod fast_thread_local; pub mod time; pub mod ext; diff --git a/src/libstd/sys/wasm/fast_thread_local.rs b/src/libstd/sys/wasm/fast_thread_local.rs new file mode 100644 index 0000000000000..ff2198175f0a9 --- /dev/null +++ b/src/libstd/sys/wasm/fast_thread_local.rs @@ -0,0 +1,9 @@ +#![unstable(feature = "thread_local_internals", issue = "0")] + +pub unsafe fn register_dtor(_t: *mut u8, _dtor: unsafe extern fn(*mut u8)) { + // FIXME: right now there is no concept of "thread exit", but this is likely + // going to show up at some point in the form of an exported symbol that the + // wasm runtime is oging to be expected to call. For now we basically just + // ignore the arguments, but if such a function starts to exist it will + // likely look like the OSX implementation in `unix/fast_thread_local.rs` +} diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs index 7d157709eb6bf..56cbafcfdb8a2 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -37,6 +37,8 @@ pub mod stack_overflow; pub mod thread; pub mod time; pub mod stdio; +pub mod thread_local; +pub mod fast_thread_local; pub use crate::sys_common::os_str_bytes as os_str; @@ -48,13 +50,10 @@ cfg_if::cfg_if! { pub mod mutex; #[path = "rwlock_atomics.rs"] pub mod rwlock; - #[path = "thread_local_atomics.rs"] - pub mod thread_local; } else { pub mod condvar; pub mod mutex; pub mod rwlock; - pub mod thread_local; } } diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index 61b4003cd3d14..d06965f327849 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -59,48 +59,40 @@ pub mod guard { pub unsafe fn init() -> Option { None } } -cfg_if::cfg_if! { - if #[cfg(all(target_feature = "atomics", feature = "wasm-bindgen-threads"))] { - #[link(wasm_import_module = "__wbindgen_thread_xform__")] - extern { - fn __wbindgen_current_id() -> u32; - fn __wbindgen_tcb_get() -> u32; - fn __wbindgen_tcb_set(ptr: u32); +// This is only used by atomics primitives when the `atomics` feature is +// enabled. In that mode we currently just use our own thread-local to store our +// current thread's ID, and then we lazily initialize it to something allocated +// from a global counter. +#[cfg(target_feature = "atomics")] +pub fn my_id() -> u32 { + use crate::sync::atomic::{AtomicU32, Ordering::SeqCst}; + + static NEXT_ID: AtomicU32 = AtomicU32::new(0); + + #[thread_local] + static mut MY_ID: u32 = 0; + + unsafe { + // If our thread ID isn't set yet then we need to allocate one. Do so + // with with a simple "atomically add to a global counter" strategy. + // This strategy doesn't handled what happens when the counter + // overflows, however, so just abort everything once the counter + // overflows and eventually we could have some sort of recycling scheme + // (or maybe this is all totally irrelevant by that point!). In any case + // though we're using a CAS loop instead of a `fetch_add` to ensure that + // the global counter never overflows. + if MY_ID == 0 { + let mut cur = NEXT_ID.load(SeqCst); + MY_ID = loop { + let next = cur.checked_add(1).unwrap_or_else(|| { + crate::arch::wasm32::unreachable() + }); + match NEXT_ID.compare_exchange(cur, next, SeqCst, SeqCst) { + Ok(_) => break next, + Err(i) => cur = i, + } + }; } - pub fn my_id() -> u32 { - unsafe { __wbindgen_current_id() } - } - - // These are currently only ever used in `thread_local_atomics.rs`, if - // you'd like to use them be sure to update that and make sure everyone - // agrees what's what. - pub fn tcb_get() -> *mut u8 { - use crate::mem; - assert_eq!(mem::size_of::<*mut u8>(), mem::size_of::()); - unsafe { __wbindgen_tcb_get() as *mut u8 } - } - - pub fn tcb_set(ptr: *mut u8) { - unsafe { __wbindgen_tcb_set(ptr as u32); } - } - - // FIXME: still need something for hooking exiting a thread to free - // data... - - } else if #[cfg(target_feature = "atomics")] { - pub fn my_id() -> u32 { - panic!("thread ids not implemented on wasm with atomics yet") - } - - pub fn tcb_get() -> *mut u8 { - panic!("thread local data not implemented on wasm with atomics yet") - } - - pub fn tcb_set(_ptr: *mut u8) { - panic!("thread local data not implemented on wasm with atomics yet") - } - } else { - // stubbed out because no functions actually access these intrinsics - // unless atomics are enabled + MY_ID } } diff --git a/src/libstd/sys/wasm/thread_local.rs b/src/libstd/sys/wasm/thread_local.rs index 29e9854bcfccb..8a0ca6f3d25a8 100644 --- a/src/libstd/sys/wasm/thread_local.rs +++ b/src/libstd/sys/wasm/thread_local.rs @@ -1,40 +1,26 @@ -use crate::boxed::Box; -use crate::ptr; - pub type Key = usize; -struct Allocated { - value: *mut u8, - dtor: Option, -} - #[inline] -pub unsafe fn create(dtor: Option) -> Key { - Box::into_raw(Box::new(Allocated { - value: ptr::null_mut(), - dtor, - })) as usize +pub unsafe fn create(_dtor: Option) -> Key { + panic!("should not be used on the wasm target"); } #[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - (*(key as *mut Allocated)).value = value; +pub unsafe fn set(_key: Key, _value: *mut u8) { + panic!("should not be used on the wasm target"); } #[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - (*(key as *mut Allocated)).value +pub unsafe fn get(_key: Key) -> *mut u8 { + panic!("should not be used on the wasm target"); } #[inline] -pub unsafe fn destroy(key: Key) { - let key = Box::from_raw(key as *mut Allocated); - if let Some(f) = key.dtor { - f(key.value); - } +pub unsafe fn destroy(_key: Key) { + panic!("should not be used on the wasm target"); } #[inline] pub fn requires_synchronized_create() -> bool { - false + panic!("should not be used on the wasm target"); } diff --git a/src/libstd/sys/wasm/thread_local_atomics.rs b/src/libstd/sys/wasm/thread_local_atomics.rs deleted file mode 100644 index 3dc0bb24553fd..0000000000000 --- a/src/libstd/sys/wasm/thread_local_atomics.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::sys::thread; -use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; - -const MAX_KEYS: usize = 128; -static NEXT_KEY: AtomicUsize = AtomicUsize::new(0); - -struct ThreadControlBlock { - keys: [*mut u8; MAX_KEYS], -} - -impl ThreadControlBlock { - fn new() -> ThreadControlBlock { - ThreadControlBlock { - keys: [core::ptr::null_mut(); MAX_KEYS], - } - } - - fn get() -> *mut ThreadControlBlock { - let ptr = thread::tcb_get(); - if !ptr.is_null() { - return ptr as *mut ThreadControlBlock - } - let tcb = Box::into_raw(Box::new(ThreadControlBlock::new())); - thread::tcb_set(tcb as *mut u8); - tcb - } -} - -pub type Key = usize; - -pub unsafe fn create(dtor: Option) -> Key { - drop(dtor); // FIXME: need to figure out how to hook thread exit to run this - let key = NEXT_KEY.fetch_add(1, SeqCst); - if key >= MAX_KEYS { - NEXT_KEY.store(MAX_KEYS, SeqCst); - panic!("cannot allocate space for more TLS keys"); - } - // offset by 1 so we never hand out 0. This is currently required by - // `sys_common/thread_local.rs` where it can't cope with keys of value 0 - // because it messes up the atomic management. - return key + 1 -} - -pub unsafe fn set(key: Key, value: *mut u8) { - (*ThreadControlBlock::get()).keys[key - 1] = value; -} - -pub unsafe fn get(key: Key) -> *mut u8 { - (*ThreadControlBlock::get()).keys[key - 1] -} - -pub unsafe fn destroy(_key: Key) { - // FIXME: should implement this somehow, this isn't typically called but it - // can be called if two threads race to initialize a TLS slot and one ends - // up not being needed. -} - -#[inline] -pub fn requires_synchronized_create() -> bool { - false -} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 384474b08f6ee..34e4d7d5a1993 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -243,9 +243,6 @@ declare_features! ( // Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. (active, allocator_internals, "1.20.0", None, None), - // Allows using the `format_args_nl` macro. - (active, format_args_nl, "1.29.0", Some(0), None), - // no-tracking-issue-end // Added for testing E0705; perma-unstable. @@ -286,12 +283,6 @@ declare_features! ( // feature-group-start: actual feature gates // ------------------------------------------------------------------------- - // Allows using `asm!` macro with which inline assembly can be embedded. - (active, asm, "1.0.0", Some(29722), None), - - // Allows using the `concat_idents!` macro with which identifiers can be concatenated. - (active, concat_idents, "1.0.0", Some(29599), None), - // Allows using the `#[link_args]` attribute. (active, link_args, "1.0.0", Some(29596), None), @@ -307,12 +298,6 @@ declare_features! ( // Allows using `#[thread_local]` on `static` items. (active, thread_local, "1.0.0", Some(29594), None), - // Allows using the `log_syntax!` macro. - (active, log_syntax, "1.0.0", Some(29598), None), - - // Allows using the `trace_macros!` macro. - (active, trace_macros, "1.0.0", Some(29598), None), - // Allows the use of SIMD types in functions declared in `extern` blocks. (active, simd_ffi, "1.0.0", Some(27731), None), @@ -402,9 +387,6 @@ declare_features! ( // Allows `extern "x86-interrupt" fn()`. (active, abi_x86_interrupt, "1.17.0", Some(40180), None), - // Allows module-level inline assembly by way of `global_asm!()`. - (active, global_asm, "1.18.0", Some(35119), None), - // Allows overlapping impls of marker traits. (active, overlapping_marker_traits, "1.18.0", Some(29864), None), @@ -472,7 +454,7 @@ declare_features! ( (active, doc_alias, "1.27.0", Some(50146), None), // Allows defining `existential type`s. - (active, existential_type, "1.28.0", Some(34511), None), + (active, existential_type, "1.28.0", Some(63063), None), // Allows inconsistent bounds in where clauses. (active, trivial_bounds, "1.28.0", Some(48214), None), @@ -525,7 +507,7 @@ declare_features! ( (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None), // Allows `impl Trait` in bindings (`let`, `const`, `static`). - (active, impl_trait_in_bindings, "1.30.0", Some(34511), None), + (active, impl_trait_in_bindings, "1.30.0", Some(63065), None), // Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. (active, lint_reasons, "1.31.0", Some(54503), None), diff --git a/src/llvm-project b/src/llvm-project index f6446fa8e9629..9b64ca5b7e1e3 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit f6446fa8e9629ffb1861303f17930c3aa83ef660 +Subproject commit 9b64ca5b7e1e3583978f9ac8af6d93b220a13d90 diff --git a/src/test/ui/core-run-destroy.rs b/src/test/ui/core-run-destroy.rs index 225b2ca8f4d2a..b3614bfd5b6e5 100644 --- a/src/test/ui/core-run-destroy.rs +++ b/src/test/ui/core-run-destroy.rs @@ -8,6 +8,7 @@ // ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes +// ignore-vxworks no 'cat' and 'sleep' // N.B., these tests kill child processes. Valgrind sees these children as leaking // memory, which makes for some *confusing* logs. That's why these are here diff --git a/src/test/ui/existential-type/issue-60371.stderr b/src/test/ui/existential-type/issue-60371.stderr index 6349b92f3e692..092cb31f97d5b 100644 --- a/src/test/ui/existential-type/issue-60371.stderr +++ b/src/test/ui/existential-type/issue-60371.stderr @@ -4,7 +4,7 @@ error[E0658]: existential types are unstable LL | existential type Item: Bug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: for more information, see https://github.com/rust-lang/rust/issues/34511 + = note: for more information, see https://github.com/rust-lang/rust/issues/63063 = help: add `#![feature(existential_type)]` to the crate attributes to enable error[E0277]: the trait bound `(): Bug` is not satisfied diff --git a/src/test/ui/feature-gates/feature-gate-asm2.rs b/src/test/ui/feature-gates/feature-gate-asm2.rs index 82900eb7e6c47..4f56aa7234464 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.rs +++ b/src/test/ui/feature-gates/feature-gate-asm2.rs @@ -1,4 +1,3 @@ -// gate-test-asm // ignore-emscripten fn main() { diff --git a/src/test/ui/feature-gates/feature-gate-asm2.stderr b/src/test/ui/feature-gates/feature-gate-asm2.stderr index e985818f30e5f..7519cad9a96ad 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm2.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'asm': inline assembly is not stable enough for use and is subject to change - --> $DIR/feature-gate-asm2.rs:6:26 + --> $DIR/feature-gate-asm2.rs:5:26 | LL | println!("{:?}", asm!("")); | ^^^ diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents2.rs b/src/test/ui/feature-gates/feature-gate-concat_idents2.rs index 0cc6c577e8d5e..9660ffeafa518 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents2.rs +++ b/src/test/ui/feature-gates/feature-gate-concat_idents2.rs @@ -1,5 +1,3 @@ -// gate-test-concat_idents - fn main() { concat_idents!(a, b); //~ ERROR `concat_idents` is not stable enough //~| ERROR cannot find value `ab` in this scope diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr index 4ae5e3e73087b..14519622c05ad 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr +++ b/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents2.rs:4:5 + --> $DIR/feature-gate-concat_idents2.rs:2:5 | LL | concat_idents!(a, b); | ^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | concat_idents!(a, b); = help: add `#![feature(concat_idents)]` to the crate attributes to enable error[E0425]: cannot find value `ab` in this scope - --> $DIR/feature-gate-concat_idents2.rs:4:5 + --> $DIR/feature-gate-concat_idents2.rs:2:5 | LL | concat_idents!(a, b); | ^^^^^^^^^^^^^^^^^^^^^ not found in this scope diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents3.rs b/src/test/ui/feature-gates/feature-gate-concat_idents3.rs index 2882e7a800836..81710fd9fb041 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents3.rs +++ b/src/test/ui/feature-gates/feature-gate-concat_idents3.rs @@ -1,5 +1,3 @@ -// gate-test-concat_idents - const XY_1: i32 = 10; fn main() { diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr index 367638693d70a..afe6acb253594 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr +++ b/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents3.rs:7:20 + --> $DIR/feature-gate-concat_idents3.rs:5:20 | LL | assert_eq!(10, concat_idents!(X, Y_1)); | ^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | assert_eq!(10, concat_idents!(X, Y_1)); = help: add `#![feature(concat_idents)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents3.rs:8:20 + --> $DIR/feature-gate-concat_idents3.rs:6:20 | LL | assert_eq!(20, concat_idents!(X, Y_2)); | ^^^^^^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-existential-type.stderr b/src/test/ui/feature-gates/feature-gate-existential-type.stderr index 29d047d22e127..30e25e55aff12 100644 --- a/src/test/ui/feature-gates/feature-gate-existential-type.stderr +++ b/src/test/ui/feature-gates/feature-gate-existential-type.stderr @@ -4,7 +4,7 @@ error[E0658]: existential types are unstable LL | existential type Foo: std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: for more information, see https://github.com/rust-lang/rust/issues/34511 + = note: for more information, see https://github.com/rust-lang/rust/issues/63063 = help: add `#![feature(existential_type)]` to the crate attributes to enable error[E0658]: existential types are unstable @@ -13,7 +13,7 @@ error[E0658]: existential types are unstable LL | existential type Baa: std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: for more information, see https://github.com/rust-lang/rust/issues/34511 + = note: for more information, see https://github.com/rust-lang/rust/issues/63063 = help: add `#![feature(existential_type)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-log_syntax2.rs b/src/test/ui/feature-gates/feature-gate-log_syntax2.rs index a3906dcc16e1c..db1a96f1f23ea 100644 --- a/src/test/ui/feature-gates/feature-gate-log_syntax2.rs +++ b/src/test/ui/feature-gates/feature-gate-log_syntax2.rs @@ -1,5 +1,3 @@ -// gate-test-log_syntax - fn main() { println!("{:?}", log_syntax!()); //~ ERROR `log_syntax!` is not stable } diff --git a/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr b/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr index 0443b988b41dc..81daee0b49f34 100644 --- a/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr +++ b/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'log_syntax': `log_syntax!` is not stable enough for use and is subject to change - --> $DIR/feature-gate-log_syntax2.rs:4:22 + --> $DIR/feature-gate-log_syntax2.rs:2:22 | LL | println!("{:?}", log_syntax!()); | ^^^^^^^^^^ diff --git a/src/test/ui/process/process-sigpipe.rs b/src/test/ui/process/process-sigpipe.rs index bf589096006f5..36303440ee9d0 100644 --- a/src/test/ui/process/process-sigpipe.rs +++ b/src/test/ui/process/process-sigpipe.rs @@ -14,6 +14,7 @@ // ignore-cloudabi no subprocesses support // ignore-emscripten no threads support +// ignore-vxworks no 'sh' use std::process; use std::thread; diff --git a/src/test/ui/wait-forked-but-failed-child.rs b/src/test/ui/wait-forked-but-failed-child.rs index 434361b40de6d..08b16c0e9ca3e 100644 --- a/src/test/ui/wait-forked-but-failed-child.rs +++ b/src/test/ui/wait-forked-but-failed-child.rs @@ -2,6 +2,7 @@ // ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes +// ignore-vxworks no 'ps' #![feature(rustc_private)] diff --git a/src/test/ui/x86stdcall.rs b/src/test/ui/x86stdcall.rs index fc67ccdc8c41f..32a4df87fbe12 100644 --- a/src/test/ui/x86stdcall.rs +++ b/src/test/ui/x86stdcall.rs @@ -32,5 +32,6 @@ pub fn main() { target_os = "macos", target_os = "netbsd", target_os = "openbsd", + target_os = "vxworks", target_os = "solaris"))] pub fn main() { }