From 3f2ca47a79911d422fd47ee2a23dd08a9fa42aa9 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 30 Jun 2020 20:17:07 +0200 Subject: Gate the printing on --json=unused-externs --- compiler/rustc_session/src/config.rs | 18 +++++++++++++++--- compiler/rustc_session/src/options.rs | 3 +++ 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'compiler/rustc_session') diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f25828e2161..a66201953d6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -734,6 +734,7 @@ impl Default for Options { remap_path_prefix: Vec::new(), edition: DEFAULT_EDITION, json_artifact_notifications: false, + json_unused_externs: false, pretty: None, } } @@ -1254,11 +1255,12 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { /// /// The first value returned is how to render JSON diagnostics, and the second /// is whether or not artifact notifications are enabled. -pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) { +pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool, bool) { let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType = HumanReadableErrorType::Default; let mut json_color = ColorConfig::Never; let mut json_artifact_notifications = false; + let mut json_unused_externs = false; for option in matches.opt_strs("json") { // For now conservatively forbid `--color` with `--json` since `--json` // won't actually be emitting any colors and anything colorized is @@ -1275,6 +1277,7 @@ pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) "diagnostic-short" => json_rendered = HumanReadableErrorType::Short, "diagnostic-rendered-ansi" => json_color = ColorConfig::Always, "artifacts" => json_artifact_notifications = true, + "unused-externs" => json_unused_externs = true, s => early_error( ErrorOutputType::default(), &format!("unknown `--json` option `{}`", s), @@ -1282,7 +1285,7 @@ pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) } } } - (json_rendered(json_color), json_artifact_notifications) + (json_rendered(json_color), json_artifact_notifications, json_unused_externs) } /// Parses the `--error-format` flag. @@ -1860,7 +1863,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let edition = parse_crate_edition(matches); - let (json_rendered, json_artifact_notifications) = parse_json(matches); + let (json_rendered, json_artifact_notifications, json_unused_externs) = parse_json(matches); let error_format = parse_error_format(matches, color, json_rendered); @@ -1873,6 +1876,14 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let mut debugging_opts = build_debugging_options(matches, error_format); check_debug_option_stability(&debugging_opts, error_format, json_rendered); + if !debugging_opts.unstable_options && json_unused_externs { + early_error( + error_format, + "the `-Z unstable-options` flag must also be passed to enable \ + the flag `--json=unused-externs`", + ); + } + let output_types = parse_output_types(&debugging_opts, matches, error_format); let mut cg = build_codegen_options(matches, error_format); @@ -2050,6 +2061,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { remap_path_prefix, edition, json_artifact_notifications, + json_unused_externs, pretty, } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 79bbad8307b..cfe29d40b74 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -147,6 +147,9 @@ top_level_options!( // by the compiler. json_artifact_notifications: bool [TRACKED], + // `true` if we're emitting a JSON blob containing the unused externs + json_unused_externs: bool [UNTRACKED], + pretty: Option [UNTRACKED], } ); -- cgit 1.4.1-3-g733a5 From 2d5200605f18717efcb5483cfd2aece167cab7ce Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 5 Jul 2020 19:35:46 +0200 Subject: Make parse_json return JsonConfig --- compiler/rustc_session/src/config.rs | 19 ++++++++++++++++--- src/librustdoc/config.rs | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'compiler/rustc_session') diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a66201953d6..433b87aa3c6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1251,11 +1251,18 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { } } +/// Possible json config files +pub struct JsonConfig { + pub json_rendered: HumanReadableErrorType, + pub json_artifact_notifications: bool, + pub json_unused_externs: bool, +} + /// Parse the `--json` flag. /// /// The first value returned is how to render JSON diagnostics, and the second /// is whether or not artifact notifications are enabled. -pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool, bool) { +pub fn parse_json(matches: &getopts::Matches) -> JsonConfig { let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType = HumanReadableErrorType::Default; let mut json_color = ColorConfig::Never; @@ -1285,7 +1292,12 @@ pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool, } } } - (json_rendered(json_color), json_artifact_notifications, json_unused_externs) + + JsonConfig { + json_rendered: json_rendered(json_color), + json_artifact_notifications, + json_unused_externs, + } } /// Parses the `--error-format` flag. @@ -1863,7 +1875,8 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let edition = parse_crate_edition(matches); - let (json_rendered, json_artifact_notifications, json_unused_externs) = parse_json(matches); + let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } = + parse_json(matches); let error_format = parse_error_format(matches, color, json_rendered); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 5d6d5aaec14..112fe230916 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -323,7 +323,7 @@ impl Options { } let color = config::parse_color(&matches); - let (json_rendered, ..) = config::parse_json(&matches); + let config::JsonConfig { json_rendered, .. } = config::parse_json(&matches); let error_format = config::parse_error_format(&matches, color, json_rendered); let codegen_options = build_codegen_options(matches, error_format); -- cgit 1.4.1-3-g733a5 From 13371b59ee918445ede03cebb741539db807e0e7 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 1 Aug 2020 12:57:35 +0200 Subject: Make doctests collect and emit the unused externs --- compiler/rustc_session/src/config.rs | 4 ++ src/librustdoc/config.rs | 6 ++- src/librustdoc/doctest.rs | 85 +++++++++++++++++++++++++++++++++--- 3 files changed, 88 insertions(+), 7 deletions(-) (limited to 'compiler/rustc_session') diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 433b87aa3c6..2965fe8e1e8 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -485,6 +485,10 @@ impl Externs { pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> { self.0.iter() } + + pub fn len(&self) -> usize { + self.0.len() + } } impl ExternEntry { diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 112fe230916..61035684ef3 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -153,6 +153,8 @@ crate struct Options { /// If this option is set to `true`, rustdoc will only run checks and not generate /// documentation. crate run_check: bool, + /// Whether doctests should emit unused externs + crate json_unused_externs: bool, } impl fmt::Debug for Options { @@ -323,7 +325,8 @@ impl Options { } let color = config::parse_color(&matches); - let config::JsonConfig { json_rendered, .. } = config::parse_json(&matches); + let config::JsonConfig { json_rendered, json_unused_externs, .. } = + config::parse_json(&matches); let error_format = config::parse_error_format(&matches, color, json_rendered); let codegen_options = build_codegen_options(matches, error_format); @@ -644,6 +647,7 @@ impl Options { }, crate_name, output_format, + json_unused_externs, }) } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 27ce064669d..50cdf46ce4f 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1,5 +1,5 @@ use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_errors::{ColorConfig, ErrorReported}; use rustc_hir as hir; @@ -23,6 +23,8 @@ use std::panic; use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::str; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{Arc, Mutex}; use crate::clean::Attributes; use crate::config::Options; @@ -103,8 +105,10 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { let mut test_args = options.test_args.clone(); let display_warnings = options.display_warnings; + let externs = options.externs.clone(); + let json_unused_externs = options.json_unused_externs; - let tests = interface::run_compiler(config, |compiler| { + let res = interface::run_compiler(config, |compiler| { compiler.enter(|queries| { let lower_to_hir = queries.lower_to_hir()?; @@ -147,12 +151,15 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { }); compiler.session().abort_if_errors(); - let ret: Result<_, ErrorReported> = Ok(collector.tests); + let unused_extern_reports = collector.unused_extern_reports.clone(); + let compiling_test_count = collector.compiling_test_count.load(Ordering::SeqCst); + let ret: Result<_, ErrorReported> = + Ok((collector.tests, unused_extern_reports, compiling_test_count)); ret }) }); - let tests = match tests { - Ok(tests) => tests, + let (tests, unused_extern_reports, compiling_test_count) = match res { + Ok(res) => res, Err(ErrorReported) => return Err(ErrorReported), }; @@ -164,6 +171,29 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { Some(testing::Options::new().display_output(display_warnings)), ); + // Collect and warn about unused externs, but only if we've gotten + // reports for each doctest + if json_unused_externs { + let unused_extern_reports: Vec<_> = + std::mem::take(&mut unused_extern_reports.lock().unwrap()); + if unused_extern_reports.len() == compiling_test_count { + let extern_names = externs.iter().map(|(name, _)| name).collect::>(); + let mut unused_extern_names = unused_extern_reports + .iter() + .map(|uexts| uexts.unused_extern_names.iter().collect::>()) + .fold(extern_names, |uextsa, uextsb| { + uextsa.intersection(&uextsb).map(|v| *v).collect::>() + }) + .iter() + .map(|v| (*v).clone()) + .collect::>(); + unused_extern_names.sort(); + let unused_extern_json = + serde_json::to_string(&UnusedExterns { unused_extern_names }).unwrap(); + eprintln!("{}", unused_extern_json); + } + } + Ok(()) } @@ -233,6 +263,12 @@ impl DirState { } } +#[derive(serde::Serialize, serde::Deserialize)] +struct UnusedExterns { + /// List of unused externs by their names. + unused_extern_names: Vec, +} + fn run_test( test: &str, cratename: &str, @@ -251,6 +287,7 @@ fn run_test( outdir: DirState, path: PathBuf, test_id: &str, + report_unused_externs: impl Fn(UnusedExterns), ) -> Result<(), TestFailure> { let (test, line_offset, supports_color) = make_test(test, Some(cratename), as_test_harness, opts, edition, Some(test_id)); @@ -276,6 +313,11 @@ fn run_test( if as_test_harness { compiler.arg("--test"); } + if options.json_unused_externs && !compile_fail { + compiler.arg("--error-format=json"); + compiler.arg("--json").arg("unused-externs"); + compiler.arg("-Z").arg("unstable-options"); + } for lib_str in &options.lib_strs { compiler.arg("-L").arg(&lib_str); } @@ -335,7 +377,26 @@ fn run_test( eprint!("{}", self.0); } } - let out = str::from_utf8(&output.stderr).unwrap(); + let mut out_lines = str::from_utf8(&output.stderr) + .unwrap() + .lines() + .filter(|l| { + if let Ok(uext) = serde_json::from_str::(l) { + report_unused_externs(uext); + false + } else { + true + } + }) + .collect::>(); + + // Add a \n to the end to properly terminate the last line, + // but only if there was output to be printed + if out_lines.len() > 0 { + out_lines.push(""); + } + + let out = out_lines.join("\n"); let _bomb = Bomb(&out); match (output.status.success(), compile_fail) { (true, true) => { @@ -719,6 +780,8 @@ crate struct Collector { source_map: Option>, filename: Option, visited_tests: FxHashMap<(String, usize), usize>, + unused_extern_reports: Arc>>, + compiling_test_count: AtomicUsize, } impl Collector { @@ -743,6 +806,8 @@ impl Collector { source_map, filename, visited_tests: FxHashMap::default(), + unused_extern_reports: Default::default(), + compiling_test_count: AtomicUsize::new(0), } } @@ -789,6 +854,10 @@ impl Tester for Collector { let runtool_args = self.options.runtool_args.clone(); let target = self.options.target.clone(); let target_str = target.to_string(); + let unused_externs = self.unused_extern_reports.clone(); + if !config.compile_fail { + self.compiling_test_count.fetch_add(1, Ordering::SeqCst); + } // FIXME(#44940): if doctests ever support path remapping, then this filename // needs to be the result of `SourceMap::span_to_unmapped_path`. @@ -844,6 +913,9 @@ impl Tester for Collector { test_type: testing::TestType::DocTest, }, testfn: testing::DynTestFn(box move || { + let report_unused_externs = |uext| { + unused_externs.lock().unwrap().push(uext); + }; let res = run_test( &test, &cratename, @@ -862,6 +934,7 @@ impl Tester for Collector { outdir, path, &test_id, + report_unused_externs, ); if let Err(err) = res { -- cgit 1.4.1-3-g733a5 From 1ec905766d0c8b76ecef22d1948fe87a490da3fd Mon Sep 17 00:00:00 2001 From: Tomasz Miąsko Date: Wed, 24 Feb 2021 00:00:00 +0000 Subject: Use FromStr trait for number option parsing Replace `parse_uint` with generic `parse_number` based on `FromStr`. Use it for parsing inlining threshold to avoid casting later. --- compiler/rustc_codegen_llvm/src/back/write.rs | 2 +- compiler/rustc_codegen_ssa/src/back/write.rs | 2 +- compiler/rustc_session/src/config.rs | 1 + compiler/rustc_session/src/options.rs | 28 +++++++++++++-------------- 4 files changed, 17 insertions(+), 16 deletions(-) (limited to 'compiler/rustc_session') diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index c224da7885b..36e22f260a7 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1044,7 +1044,7 @@ pub unsafe fn with_llvm_pmb( // thresholds copied from clang. match (opt_level, opt_size, inline_threshold) { (.., Some(t)) => { - llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32); + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t); } (llvm::CodeGenOptLevel::Aggressive, ..) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 7b8ce157fc2..9afb0ccd706 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -106,7 +106,7 @@ pub struct ModuleConfig { pub vectorize_loop: bool, pub vectorize_slp: bool, pub merge_functions: bool, - pub inline_threshold: Option, + pub inline_threshold: Option, pub new_llvm_pass_manager: bool, pub emit_lifetime_markers: bool, } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f25828e2161..12ada53c2fa 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2367,6 +2367,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(PathBuf); impl_dep_tracking_hash_via_hash!(lint::Level); impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 79bbad8307b..67af17bafcc 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -248,9 +248,9 @@ macro_rules! options { pub const parse_list: &str = "a space-separated list of strings"; pub const parse_opt_list: &str = parse_list; pub const parse_opt_comma_list: &str = "a comma-separated list of strings"; - pub const parse_uint: &str = "a number"; - pub const parse_opt_uint: &str = parse_uint; - pub const parse_threads: &str = parse_uint; + pub const parse_number: &str = "a number"; + pub const parse_opt_number: &str = parse_number; + pub const parse_threads: &str = parse_number; pub const parse_passes: &str = "a space-separated list of passes, or `all`"; pub const parse_panic_strategy: &str = "either `unwind` or `abort`"; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; @@ -413,16 +413,16 @@ macro_rules! options { } } - /// Use this for any uint option that has a static default. - fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool { + /// Use this for any numeric option that has a static default. + fn parse_number(slot: &mut T, v: Option<&str>) -> bool { match v.and_then(|s| s.parse().ok()) { Some(i) => { *slot = i; true }, None => false } } - /// Use this for any uint option that lacks a static default. - fn parse_opt_uint(slot: &mut Option, v: Option<&str>) -> bool { + /// Use this for any numeric option that lacks a static default. + fn parse_opt_number(slot: &mut Option, v: Option<&str>) -> bool { match v { Some(s) => { *slot = s.parse().ok(); slot.is_some() } None => false @@ -748,13 +748,13 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "this option is deprecated and does nothing"), code_model: Option = (None, parse_code_model, [TRACKED], "choose the code model to use (`rustc --print code-models` for details)"), - codegen_units: Option = (None, parse_opt_uint, [UNTRACKED], + codegen_units: Option = (None, parse_opt_number, [UNTRACKED], "divide crate into N units to optimize in parallel"), control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED], "use Windows Control Flow Guard (default: no)"), debug_assertions: Option = (None, parse_opt_bool, [TRACKED], "explicitly enable the `cfg(debug_assertions)` directive"), - debuginfo: usize = (0, parse_uint, [TRACKED], + debuginfo: usize = (0, parse_number, [TRACKED], "debug info emission level (0 = no debug info, 1 = line tables only, \ 2 = full debug info with variable and type information; default: 0)"), default_linker_libraries: bool = (false, parse_bool, [UNTRACKED], @@ -769,7 +769,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "force use of unwind tables"), incremental: Option = (None, parse_opt_string, [UNTRACKED], "enable incremental compilation"), - inline_threshold: Option = (None, parse_opt_uint, [TRACKED], + inline_threshold: Option = (None, parse_opt_number, [TRACKED], "set the threshold for inlining a function"), link_arg: (/* redirected to link_args */) = ((), parse_string_push, [UNTRACKED], "a single extra argument to append to the linker invocation (can be used several times)"), @@ -959,9 +959,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "verify incr. comp. hashes of green query instances (default: no)"), inline_mir: Option = (None, parse_opt_bool, [TRACKED], "enable MIR inlining (default: no)"), - inline_mir_threshold: Option = (None, parse_opt_uint, [TRACKED], + inline_mir_threshold: Option = (None, parse_opt_number, [TRACKED], "a default MIR inlining threshold (default: 50)"), - inline_mir_hint_threshold: Option = (None, parse_opt_uint, [TRACKED], + inline_mir_hint_threshold: Option = (None, parse_opt_number, [TRACKED], "inlining threshold for functions with inline hint (default: 100)"), inline_in_all_cgus: Option = (None, parse_opt_bool, [TRACKED], "control whether `#[inline]` functions are in all CGUs"), @@ -999,7 +999,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, mir_emit_retag: bool = (false, parse_bool, [TRACKED], "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ (default: no)"), - mir_opt_level: Option = (None, parse_opt_uint, [TRACKED], + mir_opt_level: Option = (None, parse_opt_number, [TRACKED], "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"), mutable_noalias: bool = (false, parse_bool, [TRACKED], "emit noalias metadata for mutable references (default: no)"), @@ -1120,7 +1120,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help (default: no)"), - terminal_width: Option = (None, parse_opt_uint, [UNTRACKED], + terminal_width: Option = (None, parse_opt_number, [UNTRACKED], "set the current terminal width"), tune_cpu: Option = (None, parse_opt_string, [TRACKED], "select processor to schedule for (`rustc --print target-cpus` for details)"), -- cgit 1.4.1-3-g733a5 From da66a31572e0f49981d6b958ecdd95397ecf2d3f Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Wed, 30 Dec 2020 12:52:21 -0600 Subject: wasm64 --- compiler/rustc_codegen_llvm/src/attributes.rs | 2 +- compiler/rustc_codegen_llvm/src/back/write.rs | 5 +- .../rustc_codegen_llvm/src/debuginfo/metadata.rs | 4 +- compiler/rustc_codegen_ssa/src/back/linker.rs | 2 +- compiler/rustc_codegen_ssa/src/target_features.rs | 2 +- compiler/rustc_session/src/config.rs | 3 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_symbol_mangling/src/lib.rs | 2 +- compiler/rustc_target/src/abi/call/mod.rs | 2 + compiler/rustc_target/src/abi/call/wasm64.rs | 58 +++++++++ compiler/rustc_target/src/spec/mod.rs | 8 +- compiler/rustc_target/src/spec/tests/tests_impl.rs | 1 + compiler/rustc_target/src/spec/wasm32_base.rs | 136 -------------------- .../src/spec/wasm32_unknown_emscripten.rs | 4 +- .../src/spec/wasm32_unknown_unknown.rs | 4 +- compiler/rustc_target/src/spec/wasm32_wasi.rs | 4 +- .../src/spec/wasm64_unknown_unknown.rs | 39 ++++++ compiler/rustc_target/src/spec/wasm_base.rs | 138 +++++++++++++++++++++ src/doc/rustc/src/platform-support.md | 1 + src/librustdoc/clean/cfg.rs | 3 +- 20 files changed, 265 insertions(+), 154 deletions(-) create mode 100644 compiler/rustc_target/src/abi/call/wasm64.rs delete mode 100644 compiler/rustc_target/src/spec/wasm32_base.rs create mode 100644 compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs create mode 100644 compiler/rustc_target/src/spec/wasm_base.rs (limited to 'compiler/rustc_session') diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 64ebe585dd8..531847c7a0e 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -317,7 +317,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: // Note that currently the `wasm-import-module` doesn't do anything, but // eventually LLVM 7 should read this and ferry the appropriate import // module to the output file. - if cx.tcx.sess.target.arch == "wasm32" { + if cx.tcx.sess.target.is_like_wasm { if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) { llvm::AddFunctionAttrStringValue( llfn, diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 388dd7ce81b..b354b97b2d5 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -170,10 +170,7 @@ pub fn target_machine_factory( // On the wasm target once the `atomics` feature is enabled that means that // we're no longer single-threaded, or otherwise we don't want LLVM to // lower atomic operations to single-threaded operations. - if singlethread - && sess.target.llvm_target.contains("wasm32") - && sess.target_features.contains(&sym::atomics) - { + if singlethread && sess.target.is_like_wasm && sess.target_features.contains(&sym::atomics) { singlethread = false; } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index d5b32e58cc3..a6a7f6e0f5b 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1083,9 +1083,9 @@ pub fn compile_unit_metadata( ); } - // Insert `llvm.ident` metadata on the wasm32 targets since that will + // Insert `llvm.ident` metadata on the wasm targets since that will // get hooked up to the "producer" sections `processed-by` information. - if tcx.sess.opts.target_triple.triple().starts_with("wasm32") { + if tcx.sess.target.is_like_wasm { let name_metadata = llvm::LLVMMDStringInContext( debug_context.llcontext, rustc_producer.as_ptr().cast(), diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index bb35e7ec894..911bdad314d 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -184,7 +184,7 @@ impl<'a> GccLinker<'a> { // * On OSX they have their own linker, not binutils' // * For WebAssembly the only functional linker is LLD, which doesn't // support hint flags - !self.sess.target.is_like_osx && self.sess.target.arch != "wasm32" + !self.sess.target.is_like_osx && !self.sess.target.is_like_wasm } // Some platforms take hints about whether a library is static or dynamic. diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index fd18f42f2dd..3254b555ada 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -160,7 +160,7 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt "mips" | "mips64" => MIPS_ALLOWED_FEATURES, "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES, "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES, - "wasm32" => WASM_ALLOWED_FEATURES, + "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES, _ => &[], } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 75078a12311..724e32bc495 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -859,6 +859,9 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { } } ret.insert((sym::target_arch, Some(Symbol::intern(arch)))); + if sess.target.is_like_wasm { + ret.insert((sym::wasm, None)); + } ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str())))); ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz)))); ret.insert((sym::target_env, Some(Symbol::intern(env)))); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cd3dabb6795..47b5e90cf9a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1291,6 +1291,7 @@ symbols! { vreg, vreg_low16, warn, + wasm, wasm_import_module, wasm_target_feature, while_let, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 3dd7ce93deb..c050bbc9b9d 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -198,7 +198,7 @@ fn compute_symbol_name( // // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316 if is_foreign - && (tcx.sess.target.arch != "wasm32" + && (!tcx.sess.target.is_like_wasm || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id)) { if let Some(name) = attrs.link_name { diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 2c3f7762759..395235399ea 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -20,6 +20,7 @@ mod sparc; mod sparc64; mod wasm32; mod wasm32_bindgen_compat; +mod wasm64; mod x86; mod x86_64; mod x86_win64; @@ -652,6 +653,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { _ => wasm32_bindgen_compat::compute_abi_info(self), }, "asmjs" => wasm32::compute_abi_info(cx, self), + "wasm64" => wasm64::compute_abi_info(cx, self), a => return Err(format!("unrecognized arch \"{}\" in target specification", a)), } diff --git a/compiler/rustc_target/src/abi/call/wasm64.rs b/compiler/rustc_target/src/abi/call/wasm64.rs new file mode 100644 index 00000000000..46d670d1689 --- /dev/null +++ b/compiler/rustc_target/src/abi/call/wasm64.rs @@ -0,0 +1,58 @@ +use crate::abi::call::{ArgAbi, FnAbi, Uniform}; +use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods}; + +fn unwrap_trivial_aggregate<'a, Ty, C>(cx: &C, val: &mut ArgAbi<'a, Ty>) -> bool +where + Ty: TyAndLayoutMethods<'a, C> + Copy, + C: LayoutOf> + HasDataLayout, +{ + if val.layout.is_aggregate() { + if let Some(unit) = val.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()) { + let size = val.layout.size; + if unit.size == size { + val.cast_to(Uniform { unit, total: size }); + return true; + } + } + } + false +} + +fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>) +where + Ty: TyAndLayoutMethods<'a, C> + Copy, + C: LayoutOf> + HasDataLayout, +{ + ret.extend_integer_width_to(64); + if ret.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, ret) { + ret.make_indirect(); + } +} + +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAndLayoutMethods<'a, C> + Copy, + C: LayoutOf> + HasDataLayout, +{ + arg.extend_integer_width_to(64); + if arg.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, arg) { + arg.make_indirect_byval(); + } +} + +pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAndLayoutMethods<'a, C> + Copy, + C: LayoutOf> + HasDataLayout, +{ + if !fn_abi.ret.is_ignore() { + classify_ret(cx, &mut fn_abi.ret); + } + + for arg in &mut fn_abi.args { + if arg.is_ignore() { + continue; + } + classify_arg(cx, arg); + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index c9fffd213d7..23d86d6874f 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -78,7 +78,7 @@ mod solaris_base; mod thumb_base; mod uefi_msvc_base; mod vxworks_base; -mod wasm32_base; +mod wasm_base; mod windows_gnu_base; mod windows_msvc_base; mod windows_uwp_gnu_base; @@ -762,6 +762,7 @@ supported_targets! { ("wasm32-unknown-emscripten", wasm32_unknown_emscripten), ("wasm32-unknown-unknown", wasm32_unknown_unknown), ("wasm32-wasi", wasm32_wasi), + ("wasm64-unknown-unknown", wasm64_unknown_unknown), ("thumbv6m-none-eabi", thumbv6m_none_eabi), ("thumbv7m-none-eabi", thumbv7m_none_eabi), @@ -996,6 +997,8 @@ pub struct TargetOptions { pub is_like_emscripten: bool, /// Whether the target toolchain is like Fuchsia's. pub is_like_fuchsia: bool, + /// Whether a target toolchain is like WASM. + pub is_like_wasm: bool, /// Version of DWARF to use if not using the default. /// Useful because some platforms (osx, bsd) only want up to DWARF2. pub dwarf_version: Option, @@ -1204,6 +1207,7 @@ impl Default for TargetOptions { is_like_emscripten: false, is_like_msvc: false, is_like_fuchsia: false, + is_like_wasm: false, dwarf_version: None, linker_is_gnu: false, allows_weak_linkage: true, @@ -1678,6 +1682,7 @@ impl Target { key!(is_like_msvc, bool); key!(is_like_emscripten, bool); key!(is_like_fuchsia, bool); + key!(is_like_wasm, bool); key!(dwarf_version, Option); key!(linker_is_gnu, bool); key!(allows_weak_linkage, bool); @@ -1914,6 +1919,7 @@ impl ToJson for Target { target_option_val!(is_like_msvc); target_option_val!(is_like_emscripten); target_option_val!(is_like_fuchsia); + target_option_val!(is_like_wasm); target_option_val!(dwarf_version); target_option_val!(linker_is_gnu); target_option_val!(allows_weak_linkage); diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index 9ec8467e0ac..f4de8bc0a58 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -50,6 +50,7 @@ impl Target { // and you certainly want "unknown" for the OS name. fn can_use_os_unknown(&self) -> bool { self.llvm_target == "wasm32-unknown-unknown" + || self.llvm_target == "wasm64-unknown-unknown" || (self.env == "sgx" && self.vendor == "fortanix") } } diff --git a/compiler/rustc_target/src/spec/wasm32_base.rs b/compiler/rustc_target/src/spec/wasm32_base.rs deleted file mode 100644 index bfef3d37228..00000000000 --- a/compiler/rustc_target/src/spec/wasm32_base.rs +++ /dev/null @@ -1,136 +0,0 @@ -use super::crt_objects::CrtObjectsFallback; -use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel}; -use std::collections::BTreeMap; - -pub fn options() -> TargetOptions { - let mut lld_args = Vec::new(); - let mut clang_args = Vec::new(); - let mut arg = |arg: &str| { - lld_args.push(arg.to_string()); - clang_args.push(format!("-Wl,{}", arg)); - }; - - // By default LLD only gives us one page of stack (64k) which is a - // little small. Default to a larger stack closer to other PC platforms - // (1MB) and users can always inject their own link-args to override this. - arg("-z"); - arg("stack-size=1048576"); - - // By default LLD's memory layout is: - // - // 1. First, a blank page - // 2. Next, all static data - // 3. Finally, the main stack (which grows down) - // - // This has the unfortunate consequence that on stack overflows you - // corrupt static data and can cause some exceedingly weird bugs. To - // help detect this a little sooner we instead request that the stack is - // placed before static data. - // - // This means that we'll generate slightly larger binaries as references - // to static data will take more bytes in the ULEB128 encoding, but - // stack overflow will be guaranteed to trap as it underflows instead of - // corrupting static data. - arg("--stack-first"); - - // FIXME we probably shouldn't pass this but instead pass an explicit list - // of symbols we'll allow to be undefined. We don't currently have a - // mechanism of knowing, however, which symbols are intended to be imported - // from the environment and which are intended to be imported from other - // objects linked elsewhere. This is a coarse approximation but is sure to - // hide some bugs and frustrate someone at some point, so we should ideally - // work towards a world where we can explicitly list symbols that are - // supposed to be imported and have all other symbols generate errors if - // they remain undefined. - arg("--allow-undefined"); - - // Rust code should never have warnings, and warnings are often - // indicative of bugs, let's prevent them. - arg("--fatal-warnings"); - - // LLD only implements C++-like demangling, which doesn't match our own - // mangling scheme. Tell LLD to not demangle anything and leave it up to - // us to demangle these symbols later. Currently rustc does not perform - // further demangling, but tools like twiggy and wasm-bindgen are intended - // to do so. - arg("--no-demangle"); - - let mut pre_link_args = BTreeMap::new(); - pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args); - pre_link_args.insert(LinkerFlavor::Gcc, clang_args); - - TargetOptions { - // we allow dynamic linking, but only cdylibs. Basically we allow a - // final library artifact that exports some symbols (a wasm module) but - // we don't allow intermediate `dylib` crate types - dynamic_linking: true, - only_cdylib: true, - - // This means we'll just embed a `#[start]` function in the wasm module - executables: true, - - // relatively self-explanatory! - exe_suffix: ".wasm".to_string(), - dll_prefix: String::new(), - dll_suffix: ".wasm".to_string(), - linker_is_gnu: false, - eh_frame_header: false, - - max_atomic_width: Some(64), - - // Unwinding doesn't work right now, so the whole target unconditionally - // defaults to panic=abort. Note that this is guaranteed to change in - // the future once unwinding is implemented. Don't rely on this as we're - // basically guaranteed to change it once WebAssembly supports - // exceptions. - panic_strategy: PanicStrategy::Abort, - - // Wasm doesn't have atomics yet, so tell LLVM that we're in a single - // threaded model which will legalize atomics to normal operations. - singlethread: true, - - // no dynamic linking, no need for default visibility! - default_hidden_visibility: true, - - // Symbol visibility takes care of this for the WebAssembly. - // Additionally the only known linker, LLD, doesn't support the script - // arguments just yet - limit_rdylib_exports: false, - - // we use the LLD shipped with the Rust toolchain by default - linker: Some("rust-lld".to_owned()), - lld_flavor: LldFlavor::Wasm, - - // No need for indirection here, simd types can always be passed by - // value as the whole module either has simd or not, which is different - // from x86 (for example) where programs can have functions that don't - // enable simd features. - simd_types_indirect: false, - - pre_link_args, - - crt_objects_fallback: Some(CrtObjectsFallback::Wasm), - - // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when - // PIC code is implemented this has quite a drastric effect if it stays - // at the default, `pic`. In an effort to keep wasm binaries as minimal - // as possible we're defaulting to `static` for now, but the hope is - // that eventually we can ship a `pic`-compatible standard library which - // works with `static` as well (or works with some method of generating - // non-relative calls and such later on). - relocation_model: RelocModel::Static, - - // 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: TlsModel::LocalExec, - - // gdb scripts don't work on wasm blobs - emit_debug_gdb_scripts: false, - - ..Default::default() - } -} diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index 9f69ce16c21..dee06753f97 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -1,8 +1,8 @@ -use super::wasm32_base; +use super::wasm_base; use super::{LinkArgs, LinkerFlavor, PanicStrategy, Target, TargetOptions}; pub fn target() -> Target { - let mut options = wasm32_base::options(); + let mut options = wasm_base::options(); let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs index 5e89ba2520b..597146275a8 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs @@ -10,11 +10,11 @@ //! This target is more or less managed by the Rust and WebAssembly Working //! Group nowadays at . -use super::wasm32_base; +use super::wasm_base; use super::{LinkerFlavor, LldFlavor, Target}; pub fn target() -> Target { - let mut options = wasm32_base::options(); + let mut options = wasm_base::options(); options.os = "unknown".to_string(); options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm); let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs index 3f44acdc36b..a6b12d2ee8f 100644 --- a/compiler/rustc_target/src/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -72,11 +72,11 @@ //! best we can with this target. Don't start relying on too much here unless //! you know what you're getting in to! -use super::wasm32_base; +use super::wasm_base; use super::{crt_objects, LinkerFlavor, LldFlavor, Target}; pub fn target() -> Target { - let mut options = wasm32_base::options(); + let mut options = wasm_base::options(); options.os = "wasi".to_string(); options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm); diff --git a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs new file mode 100644 index 00000000000..8bfb229d77f --- /dev/null +++ b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs @@ -0,0 +1,39 @@ +//! A "bare wasm" target representing a WebAssembly output that makes zero +//! assumptions about its environment. +//! +//! The `wasm64-unknown-unknown` target is intended to encapsulate use cases +//! that do not rely on any imported functionality. The binaries generated are +//! entirely self-contained by default when using the standard library. Although +//! the standard library is available, most of it returns an error immediately +//! (e.g. trying to create a TCP stream or something like that). + +use super::wasm_base; +use super::{LinkerFlavor, LldFlavor, Target}; + +pub fn target() -> Target { + let mut options = wasm_base::options(); + options.os = "unknown".to_string(); + options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm); + let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + + // Make sure clang uses LLD as its linker and is configured appropriately + // otherwise + clang_args.push("--target=wasm64-unknown-unknown".to_string()); + + // For now this target just never has an entry symbol no matter the output + // type, so unconditionally pass this. + clang_args.push("-Wl,--no-entry".to_string()); + options + .pre_link_args + .get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm)) + .unwrap() + .push("--no-entry".to_string()); + + Target { + llvm_target: "wasm64-unknown-unknown".to_string(), + pointer_width: 64, + data_layout: "e-m:e-p:64:64-i64:64-n32:64-S128".to_string(), + arch: "wasm64".to_string(), + options, + } +} diff --git a/compiler/rustc_target/src/spec/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs new file mode 100644 index 00000000000..c93ad24225a --- /dev/null +++ b/compiler/rustc_target/src/spec/wasm_base.rs @@ -0,0 +1,138 @@ +use super::crt_objects::CrtObjectsFallback; +use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel}; +use std::collections::BTreeMap; + +pub fn options() -> TargetOptions { + let mut lld_args = Vec::new(); + let mut clang_args = Vec::new(); + let mut arg = |arg: &str| { + lld_args.push(arg.to_string()); + clang_args.push(format!("-Wl,{}", arg)); + }; + + // By default LLD only gives us one page of stack (64k) which is a + // little small. Default to a larger stack closer to other PC platforms + // (1MB) and users can always inject their own link-args to override this. + arg("-z"); + arg("stack-size=1048576"); + + // By default LLD's memory layout is: + // + // 1. First, a blank page + // 2. Next, all static data + // 3. Finally, the main stack (which grows down) + // + // This has the unfortunate consequence that on stack overflows you + // corrupt static data and can cause some exceedingly weird bugs. To + // help detect this a little sooner we instead request that the stack is + // placed before static data. + // + // This means that we'll generate slightly larger binaries as references + // to static data will take more bytes in the ULEB128 encoding, but + // stack overflow will be guaranteed to trap as it underflows instead of + // corrupting static data. + arg("--stack-first"); + + // FIXME we probably shouldn't pass this but instead pass an explicit list + // of symbols we'll allow to be undefined. We don't currently have a + // mechanism of knowing, however, which symbols are intended to be imported + // from the environment and which are intended to be imported from other + // objects linked elsewhere. This is a coarse approximation but is sure to + // hide some bugs and frustrate someone at some point, so we should ideally + // work towards a world where we can explicitly list symbols that are + // supposed to be imported and have all other symbols generate errors if + // they remain undefined. + arg("--allow-undefined"); + + // Rust code should never have warnings, and warnings are often + // indicative of bugs, let's prevent them. + arg("--fatal-warnings"); + + // LLD only implements C++-like demangling, which doesn't match our own + // mangling scheme. Tell LLD to not demangle anything and leave it up to + // us to demangle these symbols later. Currently rustc does not perform + // further demangling, but tools like twiggy and wasm-bindgen are intended + // to do so. + arg("--no-demangle"); + + let mut pre_link_args = BTreeMap::new(); + pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args); + pre_link_args.insert(LinkerFlavor::Gcc, clang_args); + + TargetOptions { + is_like_wasm: true, + + // we allow dynamic linking, but only cdylibs. Basically we allow a + // final library artifact that exports some symbols (a wasm module) but + // we don't allow intermediate `dylib` crate types + dynamic_linking: true, + only_cdylib: true, + + // This means we'll just embed a `#[start]` function in the wasm module + executables: true, + + // relatively self-explanatory! + exe_suffix: ".wasm".to_string(), + dll_prefix: String::new(), + dll_suffix: ".wasm".to_string(), + linker_is_gnu: false, + eh_frame_header: false, + + max_atomic_width: Some(64), + + // Unwinding doesn't work right now, so the whole target unconditionally + // defaults to panic=abort. Note that this is guaranteed to change in + // the future once unwinding is implemented. Don't rely on this as we're + // basically guaranteed to change it once WebAssembly supports + // exceptions. + panic_strategy: PanicStrategy::Abort, + + // Wasm doesn't have atomics yet, so tell LLVM that we're in a single + // threaded model which will legalize atomics to normal operations. + singlethread: true, + + // no dynamic linking, no need for default visibility! + default_hidden_visibility: true, + + // Symbol visibility takes care of this for the WebAssembly. + // Additionally the only known linker, LLD, doesn't support the script + // arguments just yet + limit_rdylib_exports: false, + + // we use the LLD shipped with the Rust toolchain by default + linker: Some("rust-lld".to_owned()), + lld_flavor: LldFlavor::Wasm, + + // No need for indirection here, simd types can always be passed by + // value as the whole module either has simd or not, which is different + // from x86 (for example) where programs can have functions that don't + // enable simd features. + simd_types_indirect: false, + + pre_link_args, + + crt_objects_fallback: Some(CrtObjectsFallback::Wasm), + + // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when + // PIC code is implemented this has quite a drastric effect if it stays + // at the default, `pic`. In an effort to keep wasm binaries as minimal + // as possible we're defaulting to `static` for now, but the hope is + // that eventually we can ship a `pic`-compatible standard library which + // works with `static` as well (or works with some method of generating + // non-relative calls and such later on). + relocation_model: RelocModel::Static, + + // 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: TlsModel::LocalExec, + + // gdb scripts don't work on wasm blobs + emit_debug_gdb_scripts: false, + + ..Default::default() + } +} diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index ee17fcac45c..f352746d3fb 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -216,6 +216,7 @@ target | std | host | notes `thumbv7a-uwp-windows-msvc` | ✓ | | `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7a Linux with NEON, MUSL `thumbv4t-none-eabi` | * | | ARMv4T T32 +`wasm64-unknown-unknown` | * | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 `x86_64-apple-tvos` | * | | x86 64-bit tvOS `x86_64-unknown-none-linuxkernel` | * | | Linux kernel modules diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 02adccef594..e93803e2761 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -487,6 +487,7 @@ impl<'a> fmt::Display for Display<'a> { "windows" => "Windows", _ => "", }, + (sym::wasm, None) => "WebAssembly", (sym::target_arch, Some(arch)) => match &*arch.as_str() { "aarch64" => "AArch64", "arm" => "ARM", @@ -498,7 +499,7 @@ impl<'a> fmt::Display for Display<'a> { "powerpc64" => "PowerPC-64", "s390x" => "s390x", "sparc64" => "SPARC64", - "wasm32" => "WebAssembly", + "wasm32" | "wasm64" => "WebAssembly", "x86" => "x86", "x86_64" => "x86-64", _ => "", -- cgit 1.4.1-3-g733a5