diff --git a/Cargo.lock b/Cargo.lock index 7cd07e3847282..760affd607e18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1900,9 +1900,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.106" +version = "0.2.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" +checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" dependencies = [ "rustc-std-workspace-core", ] diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f9e19d30fcc7e..abfe8360987c8 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2058,7 +2058,7 @@ pub struct InlineAsm { pub template: Vec, pub template_strs: Box<[(Symbol, Option, Span)]>, pub operands: Vec<(InlineAsmOperand, Span)>, - pub clobber_abi: Option<(Symbol, Span)>, + pub clobber_abis: Vec<(Symbol, Span)>, pub options: InlineAsmOptions, pub line_spans: Vec, } @@ -2715,7 +2715,7 @@ pub enum ItemKind { /// E.g., `extern {}` or `extern "C" {}`. ForeignMod(ForeignMod), /// Module-level inline assembly (from `global_asm!()`). - GlobalAsm(InlineAsm), + GlobalAsm(Box), /// A type alias (`type`). /// /// E.g., `type Foo = Bar;`. diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 95997a37d845b..cfa97ff84ec49 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -2,6 +2,7 @@ use super::LoweringContext; use rustc_ast::*; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_session::parse::feature_err; @@ -49,22 +50,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .emit(); } - let mut clobber_abi = None; + let mut clobber_abis = FxHashMap::default(); if let Some(asm_arch) = asm_arch { - if let Some((abi_name, abi_span)) = asm.clobber_abi { - match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, abi_name) { - Ok(abi) => clobber_abi = Some((abi, abi_span)), + for (abi_name, abi_span) in &asm.clobber_abis { + match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) { + Ok(abi) => { + // If the abi was already in the list, emit an error + match clobber_abis.get(&abi) { + Some((prev_name, prev_sp)) => { + let mut err = self.sess.struct_span_err( + *abi_span, + &format!("`{}` ABI specified multiple times", prev_name), + ); + err.span_label(*prev_sp, "previously specified here"); + + // Multiple different abi names may actually be the same ABI + // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI + let source_map = self.sess.source_map(); + if source_map.span_to_snippet(*prev_sp) + != source_map.span_to_snippet(*abi_span) + { + err.note("these ABIs are equivalent on the current target"); + } + + err.emit(); + } + None => { + clobber_abis.insert(abi, (abi_name, *abi_span)); + } + } + } Err(&[]) => { self.sess .struct_span_err( - abi_span, + *abi_span, "`clobber_abi` is not supported on this target", ) .emit(); } Err(supported_abis) => { let mut err = - self.sess.struct_span_err(abi_span, "invalid ABI for `clobber_abi`"); + self.sess.struct_span_err(*abi_span, "invalid ABI for `clobber_abi`"); let mut abis = format!("`{}`", supported_abis[0]); for m in &supported_abis[1..] { let _ = write!(abis, ", `{}`", m); @@ -348,8 +374,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // If a clobber_abi is specified, add the necessary clobbers to the // operands list. - if let Some((abi, abi_span)) = clobber_abi { + let mut clobbered = FxHashSet::default(); + for (abi, (_, abi_span)) in clobber_abis { for &clobber in abi.clobbered_regs() { + // Don't emit a clobber for a register already clobbered + if clobbered.contains(&clobber) { + continue; + } + let mut output_used = false; clobber.overlapping_regs(|reg| { if used_output_regs.contains_key(®) { @@ -366,6 +398,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }, self.lower_span(abi_span), )); + clobbered.insert(clobber); } } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index b59e49926add9..f1f2387866d0d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2235,8 +2235,8 @@ impl<'a> State<'a> { let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))]; args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o))); - if let Some((abi, _)) = asm.clobber_abi { - args.push(AsmArg::ClobberAbi(abi)); + for (abi, _) in &asm.clobber_abis { + args.push(AsmArg::ClobberAbi(*abi)); } if !asm.options.is_empty() { args.push(AsmArg::Options(asm.options)); diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 50127b5b15ce8..41662f46f1152 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -19,7 +19,7 @@ struct AsmArgs { operands: Vec<(ast::InlineAsmOperand, Span)>, named_args: FxHashMap, reg_args: FxHashSet, - clobber_abi: Option<(Symbol, Span)>, + clobber_abis: Vec<(Symbol, Span)>, options: ast::InlineAsmOptions, options_spans: Vec, } @@ -64,7 +64,7 @@ fn parse_args<'a>( operands: vec![], named_args: FxHashMap::default(), reg_args: FxHashSet::default(), - clobber_abi: None, + clobber_abis: Vec::new(), options: ast::InlineAsmOptions::empty(), options_spans: vec![], }; @@ -210,9 +210,9 @@ fn parse_args<'a>( .span_labels(args.options_spans.clone(), "previous options") .span_label(span, "argument") .emit(); - } else if let Some((_, abi_span)) = args.clobber_abi { + } else if let Some((_, abi_span)) = args.clobber_abis.last() { ecx.struct_span_err(span, "arguments are not allowed after clobber_abi") - .span_label(abi_span, "clobber_abi") + .span_label(*abi_span, "clobber_abi") .span_label(span, "argument") .emit(); } @@ -322,10 +322,13 @@ fn parse_args<'a>( // Bail out now since this is likely to confuse MIR return Err(err); } - if let Some((_, abi_span)) = args.clobber_abi { + + if args.clobber_abis.len() > 0 { if is_global_asm { - let err = - ecx.struct_span_err(abi_span, "`clobber_abi` cannot be used with `global_asm!`"); + let err = ecx.struct_span_err( + args.clobber_abis.iter().map(|(_, span)| *span).collect::>(), + "`clobber_abi` cannot be used with `global_asm!`", + ); // Bail out now since this is likely to confuse later stages return Err(err); @@ -335,7 +338,10 @@ fn parse_args<'a>( regclass_outputs.clone(), "asm with `clobber_abi` must specify explicit registers for outputs", ) - .span_label(abi_span, "clobber_abi") + .span_labels( + args.clobber_abis.iter().map(|(_, span)| *span).collect::>(), + "clobber_abi", + ) .span_labels(regclass_outputs, "generic outputs") .emit(); } @@ -439,37 +445,61 @@ fn parse_clobber_abi<'a>( p.expect(&token::OpenDelim(token::DelimToken::Paren))?; - let clobber_abi = match p.parse_str_lit() { - Ok(str_lit) => str_lit.symbol_unescaped, - Err(opt_lit) => { - let span = opt_lit.map_or(p.token.span, |lit| lit.span); - let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal"); - err.span_label(span, "not a string literal"); - return Err(err); - } - }; + if p.eat(&token::CloseDelim(token::DelimToken::Paren)) { + let err = p.sess.span_diagnostic.struct_span_err( + p.token.span, + "at least one abi must be provided as an argument to `clobber_abi`", + ); + return Err(err); + } - p.expect(&token::CloseDelim(token::DelimToken::Paren))?; + let mut new_abis = Vec::new(); + loop { + match p.parse_str_lit() { + Ok(str_lit) => { + new_abis.push((str_lit.symbol_unescaped, str_lit.span)); + } + Err(opt_lit) => { + // If the non-string literal is a closing paren then it's the end of the list and is fine + if p.eat(&token::CloseDelim(token::DelimToken::Paren)) { + break; + } + let span = opt_lit.map_or(p.token.span, |lit| lit.span); + let mut err = + p.sess.span_diagnostic.struct_span_err(span, "expected string literal"); + err.span_label(span, "not a string literal"); + return Err(err); + } + }; - let new_span = span_start.to(p.prev_token.span); + // Allow trailing commas + if p.eat(&token::CloseDelim(token::DelimToken::Paren)) { + break; + } + p.expect(&token::Comma)?; + } - if let Some((_, prev_span)) = args.clobber_abi { - let mut err = p - .sess - .span_diagnostic - .struct_span_err(new_span, "clobber_abi specified multiple times"); - err.span_label(prev_span, "clobber_abi previously specified here"); - return Err(err); - } else if !args.options_spans.is_empty() { + let full_span = span_start.to(p.prev_token.span); + + if !args.options_spans.is_empty() { let mut err = p .sess .span_diagnostic - .struct_span_err(new_span, "clobber_abi is not allowed after options"); + .struct_span_err(full_span, "clobber_abi is not allowed after options"); err.span_labels(args.options_spans.clone(), "options"); return Err(err); } - args.clobber_abi = Some((clobber_abi, new_span)); + match &new_abis[..] { + // should have errored above during parsing + [] => unreachable!(), + [(abi, _span)] => args.clobber_abis.push((*abi, full_span)), + [abis @ ..] => { + for (abi, span) in abis { + args.clobber_abis.push((*abi, *span)); + } + } + } Ok(()) } @@ -770,7 +800,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option( ident: Ident::empty(), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, - kind: ast::ItemKind::GlobalAsm(inline_asm), + kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), vis: ast::Visibility { span: sp.shrink_to_lo(), kind: ast::VisibilityKind::Inherited, diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 9a57ec991444a..09fe3a552a0a6 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -267,6 +267,7 @@ fn run_compiler( None, compiler.output_dir(), compiler.output_file(), + compiler.temps_dir(), ); if should_stop == Compilation::Stop { @@ -295,6 +296,7 @@ fn run_compiler( Some(compiler.input()), compiler.output_dir(), compiler.output_file(), + compiler.temps_dir(), ) .and_then(|| { RustcDefaultCalls::list_metadata( @@ -647,6 +649,7 @@ impl RustcDefaultCalls { input: Option<&Input>, odir: &Option, ofile: &Option, + temps_dir: &Option, ) -> Compilation { use rustc_session::config::PrintRequest::*; // PrintRequest::NativeStaticLibs is special - printed during linking @@ -685,7 +688,7 @@ impl RustcDefaultCalls { }); let attrs = attrs.as_ref().unwrap(); let t_outputs = rustc_interface::util::build_output_filenames( - input, odir, ofile, attrs, sess, + input, odir, ofile, temps_dir, attrs, sess, ); let id = rustc_session::output::find_crate_name(sess, attrs, input); if *req == PrintRequest::CrateName { diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 7a6a643e3d0bb..2904b3f5b7071 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -36,6 +36,7 @@ pub struct Compiler { pub(crate) input_path: Option, pub(crate) output_dir: Option, pub(crate) output_file: Option, + pub(crate) temps_dir: Option, pub(crate) register_lints: Option>, pub(crate) override_queries: Option, @@ -57,6 +58,9 @@ impl Compiler { pub fn output_file(&self) -> &Option { &self.output_file } + pub fn temps_dir(&self) -> &Option { + &self.temps_dir + } pub fn register_lints(&self) -> &Option> { &self.register_lints } @@ -65,7 +69,14 @@ impl Compiler { sess: &Session, attrs: &[ast::Attribute], ) -> OutputFilenames { - util::build_output_filenames(&self.input, &self.output_dir, &self.output_file, attrs, sess) + util::build_output_filenames( + &self.input, + &self.output_dir, + &self.output_file, + &self.temps_dir, + attrs, + sess, + ) } } @@ -186,6 +197,8 @@ pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R ); } + let temps_dir = sess.opts.debugging_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o)); + let compiler = Compiler { sess, codegen_backend, @@ -193,6 +206,7 @@ pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R input_path: config.input_path, output_dir: config.output_dir, output_file: config.output_file, + temps_dir, register_lints: config.register_lints, override_queries: config.override_queries, }; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 3f6e879e6e44b..b073ee9682fbd 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -692,6 +692,7 @@ pub fn prepare_outputs( &compiler.input, &compiler.output_dir, &compiler.output_file, + &compiler.temps_dir, &krate.attrs, sess, ); @@ -722,6 +723,13 @@ pub fn prepare_outputs( } } + if let Some(ref dir) = compiler.temps_dir { + if fs::create_dir_all(dir).is_err() { + sess.err("failed to find or create the directory specified by `--temps-dir`"); + return Err(ErrorReported); + } + } + write_out_deps(sess, boxed_resolver, &outputs, &output_paths); let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 2d3cb52f5fd47..eed2e07e890e7 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -685,6 +685,7 @@ fn test_debugging_options_tracking_hash() { untracked!(span_debug, true); untracked!(span_free_formats, true); untracked!(strip, Strip::Debuginfo); + untracked!(temps_dir, Some(String::from("abc"))); untracked!(terminal_width, Some(80)); untracked!(threads, 99); untracked!(time, true); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 946502378732a..04e183a9ba57e 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -604,6 +604,7 @@ pub fn build_output_filenames( input: &Input, odir: &Option, ofile: &Option, + temps_dir: &Option, attrs: &[ast::Attribute], sess: &Session, ) -> OutputFilenames { @@ -626,6 +627,7 @@ pub fn build_output_filenames( dirpath, stem, None, + temps_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) @@ -654,6 +656,7 @@ pub fn build_output_filenames( out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(), out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(), ofile, + temps_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 8a9e8739d037c..3afe094733928 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -578,6 +578,7 @@ pub struct OutputFilenames { pub out_directory: PathBuf, filestem: String, pub single_output_file: Option, + pub temps_directory: Option, pub outputs: OutputTypes, } @@ -592,12 +593,14 @@ impl OutputFilenames { out_directory: PathBuf, out_filestem: String, single_output_file: Option, + temps_directory: Option, extra: String, outputs: OutputTypes, ) -> Self { OutputFilenames { out_directory, single_output_file, + temps_directory, outputs, filestem: format!("{}{}", out_filestem, extra), } @@ -608,7 +611,14 @@ impl OutputFilenames { .get(&flavor) .and_then(|p| p.to_owned()) .or_else(|| self.single_output_file.clone()) - .unwrap_or_else(|| self.temp_path(flavor, None)) + .unwrap_or_else(|| self.output_path(flavor)) + } + + /// Gets the output path where a compilation artifact of the given type + /// should be placed on disk. + pub fn output_path(&self, flavor: OutputType) -> PathBuf { + let extension = flavor.extension(); + self.with_directory_and_extension(&self.out_directory, &extension) } /// Gets the path where a compilation artifact of the given type for the @@ -643,11 +653,17 @@ impl OutputFilenames { extension.push_str(ext); } - self.with_extension(&extension) + let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory); + + self.with_directory_and_extension(&temps_directory, &extension) } pub fn with_extension(&self, extension: &str) -> PathBuf { - let mut path = self.out_directory.join(&self.filestem); + self.with_directory_and_extension(&self.out_directory, extension) + } + + fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf { + let mut path = directory.join(&self.filestem); path.set_extension(extension); path } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 71464ad97145b..d1d8606a75a45 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1331,6 +1331,8 @@ 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)"), + temps_dir: Option = (None, parse_opt_string, [UNTRACKED], + "the directory the intermediate files are written to"), terminal_width: Option = (None, parse_opt_number, [UNTRACKED], "set the current terminal width"), tune_cpu: Option = (None, parse_opt_string, [TRACKED], diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 248ecdf4befce..abb17ceffcb32 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -15,7 +15,7 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.106", default-features = false, features = ['rustc-dep-of-std'] } +libc = { version = "0.2.107", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.44" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } diff --git a/src/doc/unstable-book/src/compiler-flags/temps-dir.md b/src/doc/unstable-book/src/compiler-flags/temps-dir.md new file mode 100644 index 0000000000000..e25011f71197b --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/temps-dir.md @@ -0,0 +1,10 @@ +# `temps-dir` + +-------------------- + +The `-Ztemps-dir` compiler flag specifies the directory to write the +intermediate files in. If not set, the output directory is used. This option is +useful if you are running more than one instance of `rustc` (e.g. with different +`--crate-type` settings), and you need to make sure they are not overwriting +each other's intermediate files. No files are kept unless `-C save-temps=yes` is +also set. diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 84fc6dcc33979..d318c0de91893 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -319,7 +319,7 @@ fn call_foo(arg: i32) -> i32 { Note that the `fn` or `static` item does not need to be public or `#[no_mangle]`: the compiler will automatically insert the appropriate mangled symbol name into the assembly code. -By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`](#abi-clobbers) argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered. +By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`](#abi-clobbers) argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered. Multiple `clobber_abi` arguments may be provided and all clobbers from all specified ABIs will be inserted. ## Register template modifiers @@ -453,10 +453,10 @@ reg_spec := / "" operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_" reg_operand := dir_spec "(" reg_spec ")" operand_expr operand := reg_operand / "const" const_expr / "sym" path -clobber_abi := "clobber_abi(" ")" +clobber_abi := "clobber_abi(" *["," ] [","] ")" option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw" options := "options(" option *["," option] [","] ")" -asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," clobber_abi] *("," options) [","] ")" +asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) *("," clobber_abi) *("," options) [","] ")" ``` Inline assembly is currently supported on the following architectures: @@ -799,6 +799,8 @@ As stated in the previous section, passing an input value smaller than the regis The `clobber_abi` keyword can be used to apply a default set of clobbers to an `asm` block. This will automatically insert the necessary clobber constraints as needed for calling a function with a particular calling convention: if the calling convention does not fully preserve the value of a register across a call then a `lateout("reg") _` is implicitly added to the operands list. +`clobber_abi` may be specified any number of times. It will insert a clobber for all unique registers in the union of all specified calling conventions. + Generic register class outputs are disallowed by the compiler when `clobber_abi` is used: all outputs must specify an explicit register. Explicit register outputs have precedence over the implicit clobbers inserted by `clobber_abi`: a clobber will only be inserted for a register if that register is not used as an output. The following ABIs can be used with `clobber_abi`: diff --git a/src/test/run-make/issue-10971-temps-dir/Makefile b/src/test/run-make/issue-10971-temps-dir/Makefile new file mode 100644 index 0000000000000..f062e652a04ec --- /dev/null +++ b/src/test/run-make/issue-10971-temps-dir/Makefile @@ -0,0 +1,13 @@ +-include ../../run-make-fulldeps/tools.mk + +# Regression test for issue #10971 +# Running two invocations in parallel would overwrite each other's temp files. + +## clean up unused env variables which might cause harm. +unexport RUSTC_LINKER + +all: + touch $(TMPDIR)/lib.rs + + $(RUSTC) --crate-type=lib -Z temps-dir=$(TMPDIR)/temp1 $(TMPDIR)/lib.rs & \ + $(RUSTC) --crate-type=cdylib -Z temps-dir=$(TMPDIR)/temp2 $(TMPDIR)/lib.rs diff --git a/src/test/ui/asm/aarch64/parse-error.rs b/src/test/ui/asm/aarch64/parse-error.rs index e19c5cd13d35a..8795f0ebce746 100644 --- a/src/test/ui/asm/aarch64/parse-error.rs +++ b/src/test/ui/asm/aarch64/parse-error.rs @@ -50,8 +50,6 @@ fn main() { //~^ ERROR clobber_abi is not allowed after options asm!("{}", options(), clobber_abi("C"), const foo); //~^ ERROR clobber_abi is not allowed after options - asm!("", clobber_abi("C"), clobber_abi("C")); - //~^ ERROR clobber_abi specified multiple times asm!("{a}", a = const foo, a = const bar); //~^ ERROR duplicate argument named `a` //~^^ ERROR argument never used @@ -120,8 +118,6 @@ global_asm!("", options(), clobber_abi("C")); //~^ ERROR clobber_abi is not allowed after options global_asm!("{}", options(), clobber_abi("C"), const FOO); //~^ ERROR clobber_abi is not allowed after options -global_asm!("", clobber_abi("C"), clobber_abi("C")); -//~^ ERROR clobber_abi specified multiple times global_asm!("{a}", a = const FOO, a = const BAR); //~^ ERROR duplicate argument named `a` //~^^ ERROR argument never used diff --git a/src/test/ui/asm/aarch64/parse-error.stderr b/src/test/ui/asm/aarch64/parse-error.stderr index 6f318c9b9c2a1..3d88cef5c7d71 100644 --- a/src/test/ui/asm/aarch64/parse-error.stderr +++ b/src/test/ui/asm/aarch64/parse-error.stderr @@ -96,17 +96,17 @@ error: expected string literal LL | asm!("", clobber_abi(foo)); | ^^^ not a string literal -error: expected `)`, found `foo` +error: expected one of `)` or `,`, found `foo` --> $DIR/parse-error.rs:42:34 | LL | asm!("", clobber_abi("C" foo)); - | ^^^ expected `)` + | ^^^ expected one of `)` or `,` -error: expected `)`, found `,` - --> $DIR/parse-error.rs:44:33 +error: expected string literal + --> $DIR/parse-error.rs:44:35 | LL | asm!("", clobber_abi("C", foo)); - | ^ expected `)` + | ^^^ not a string literal error: arguments are not allowed after clobber_abi --> $DIR/parse-error.rs:46:38 @@ -132,16 +132,8 @@ LL | asm!("{}", options(), clobber_abi("C"), const foo); | | | options -error: clobber_abi specified multiple times - --> $DIR/parse-error.rs:53:36 - | -LL | asm!("", clobber_abi("C"), clobber_abi("C")); - | ---------------- ^^^^^^^^^^^^^^^^ - | | - | clobber_abi previously specified here - error: duplicate argument named `a` - --> $DIR/parse-error.rs:55:36 + --> $DIR/parse-error.rs:53:36 | LL | asm!("{a}", a = const foo, a = const bar); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -149,7 +141,7 @@ LL | asm!("{a}", a = const foo, a = const bar); | previously here error: argument never used - --> $DIR/parse-error.rs:55:36 + --> $DIR/parse-error.rs:53:36 | LL | asm!("{a}", a = const foo, a = const bar); | ^^^^^^^^^^^^^ argument never used @@ -157,13 +149,13 @@ LL | asm!("{a}", a = const foo, a = const bar); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` error: explicit register arguments cannot have names - --> $DIR/parse-error.rs:60:18 + --> $DIR/parse-error.rs:58:18 | LL | asm!("", a = in("x0") foo); | ^^^^^^^^^^^^^^^^ error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:62:35 + --> $DIR/parse-error.rs:60:35 | LL | asm!("{a}", in("x0") foo, a = const bar); | ------------ ^^^^^^^^^^^^^ named argument @@ -171,7 +163,7 @@ LL | asm!("{a}", in("x0") foo, a = const bar); | explicit register argument error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:65:35 + --> $DIR/parse-error.rs:63:35 | LL | asm!("{a}", in("x0") foo, a = const bar); | ------------ ^^^^^^^^^^^^^ named argument @@ -179,7 +171,7 @@ LL | asm!("{a}", in("x0") foo, a = const bar); | explicit register argument error: positional arguments cannot follow named arguments or explicit register arguments - --> $DIR/parse-error.rs:68:35 + --> $DIR/parse-error.rs:66:35 | LL | asm!("{1}", in("x0") foo, const bar); | ------------ ^^^^^^^^^ positional argument @@ -187,19 +179,19 @@ LL | asm!("{1}", in("x0") foo, const bar); | explicit register argument error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` - --> $DIR/parse-error.rs:71:29 + --> $DIR/parse-error.rs:69:29 | LL | asm!("", options(), ""); | ^^ expected one of 9 possible tokens error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:73:33 + --> $DIR/parse-error.rs:71:33 | LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); | ^^^^ expected one of 9 possible tokens error: asm template must be a string literal - --> $DIR/parse-error.rs:75:14 + --> $DIR/parse-error.rs:73:14 | LL | asm!(format!("{{{}}}", 0), in(reg) foo); | ^^^^^^^^^^^^^^^^^^^^ @@ -207,7 +199,7 @@ LL | asm!(format!("{{{}}}", 0), in(reg) foo); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: asm template must be a string literal - --> $DIR/parse-error.rs:77:21 + --> $DIR/parse-error.rs:75:21 | LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); | ^^^^^^^^^^^^^^^^^^^^ @@ -215,79 +207,79 @@ LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: _ cannot be used for input operands - --> $DIR/parse-error.rs:79:28 + --> $DIR/parse-error.rs:77:28 | LL | asm!("{}", in(reg) _); | ^ error: _ cannot be used for input operands - --> $DIR/parse-error.rs:81:31 + --> $DIR/parse-error.rs:79:31 | LL | asm!("{}", inout(reg) _); | ^ error: _ cannot be used for input operands - --> $DIR/parse-error.rs:83:35 + --> $DIR/parse-error.rs:81:35 | LL | asm!("{}", inlateout(reg) _); | ^ error: requires at least a template string argument - --> $DIR/parse-error.rs:90:1 + --> $DIR/parse-error.rs:88:1 | LL | global_asm!(); | ^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/parse-error.rs:92:13 + --> $DIR/parse-error.rs:90:13 | LL | global_asm!(FOO); | ^^^ error: expected token: `,` - --> $DIR/parse-error.rs:94:18 + --> $DIR/parse-error.rs:92:18 | LL | global_asm!("{}" FOO); | ^^^ expected `,` error: expected operand, options, or additional template string - --> $DIR/parse-error.rs:96:19 + --> $DIR/parse-error.rs:94:19 | LL | global_asm!("{}", FOO); | ^^^ expected operand, options, or additional template string error: expected expression, found end of macro arguments - --> $DIR/parse-error.rs:98:24 + --> $DIR/parse-error.rs:96:24 | LL | global_asm!("{}", const); | ^ expected expression error: expected one of `,`, `.`, `?`, or an operator, found `FOO` - --> $DIR/parse-error.rs:100:30 + --> $DIR/parse-error.rs:98:30 | LL | global_asm!("{}", const(reg) FOO); | ^^^ expected one of `,`, `.`, `?`, or an operator error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` - --> $DIR/parse-error.rs:102:25 + --> $DIR/parse-error.rs:100:25 | LL | global_asm!("", options(FOO)); | ^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` - --> $DIR/parse-error.rs:104:25 + --> $DIR/parse-error.rs:102:25 | LL | global_asm!("", options(nomem FOO)); | ^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` - --> $DIR/parse-error.rs:106:25 + --> $DIR/parse-error.rs:104:25 | LL | global_asm!("", options(nomem, FOO)); | ^^^^^ expected one of `)`, `att_syntax`, or `raw` error: arguments are not allowed after options - --> $DIR/parse-error.rs:108:30 + --> $DIR/parse-error.rs:106:30 | LL | global_asm!("{}", options(), const FOO); | --------- ^^^^^^^^^ argument @@ -295,25 +287,25 @@ LL | global_asm!("{}", options(), const FOO); | previous options error: expected string literal - --> $DIR/parse-error.rs:110:29 + --> $DIR/parse-error.rs:108:29 | LL | global_asm!("", clobber_abi(FOO)); | ^^^ not a string literal -error: expected `)`, found `FOO` - --> $DIR/parse-error.rs:112:33 +error: expected one of `)` or `,`, found `FOO` + --> $DIR/parse-error.rs:110:33 | LL | global_asm!("", clobber_abi("C" FOO)); - | ^^^ expected `)` + | ^^^ expected one of `)` or `,` -error: expected `)`, found `,` - --> $DIR/parse-error.rs:114:32 +error: expected string literal + --> $DIR/parse-error.rs:112:34 | LL | global_asm!("", clobber_abi("C", FOO)); - | ^ expected `)` + | ^^^ not a string literal error: arguments are not allowed after clobber_abi - --> $DIR/parse-error.rs:116:37 + --> $DIR/parse-error.rs:114:37 | LL | global_asm!("{}", clobber_abi("C"), const FOO); | ---------------- ^^^^^^^^^ argument @@ -321,13 +313,13 @@ LL | global_asm!("{}", clobber_abi("C"), const FOO); | clobber_abi error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:116:19 + --> $DIR/parse-error.rs:114:19 | LL | global_asm!("{}", clobber_abi("C"), const FOO); | ^^^^^^^^^^^^^^^^ error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:119:28 + --> $DIR/parse-error.rs:117:28 | LL | global_asm!("", options(), clobber_abi("C")); | --------- ^^^^^^^^^^^^^^^^ @@ -335,23 +327,15 @@ LL | global_asm!("", options(), clobber_abi("C")); | options error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:121:30 + --> $DIR/parse-error.rs:119:30 | LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); | --------- ^^^^^^^^^^^^^^^^ | | | options -error: clobber_abi specified multiple times - --> $DIR/parse-error.rs:123:35 - | -LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); - | ---------------- ^^^^^^^^^^^^^^^^ - | | - | clobber_abi previously specified here - error: duplicate argument named `a` - --> $DIR/parse-error.rs:125:35 + --> $DIR/parse-error.rs:121:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -359,7 +343,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); | previously here error: argument never used - --> $DIR/parse-error.rs:125:35 + --> $DIR/parse-error.rs:121:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ^^^^^^^^^^^^^ argument never used @@ -367,19 +351,19 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` error: expected one of `clobber_abi`, `const`, or `options`, found `""` - --> $DIR/parse-error.rs:128:28 + --> $DIR/parse-error.rs:124:28 | LL | global_asm!("", options(), ""); | ^^ expected one of `clobber_abi`, `const`, or `options` error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"` - --> $DIR/parse-error.rs:130:30 + --> $DIR/parse-error.rs:126:30 | LL | global_asm!("{}", const FOO, "{}", const FOO); | ^^^^ expected one of `clobber_abi`, `const`, or `options` error: asm template must be a string literal - --> $DIR/parse-error.rs:132:13 + --> $DIR/parse-error.rs:128:13 | LL | global_asm!(format!("{{{}}}", 0), const FOO); | ^^^^^^^^^^^^^^^^^^^^ @@ -387,7 +371,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: asm template must be a string literal - --> $DIR/parse-error.rs:134:20 + --> $DIR/parse-error.rs:130:20 | LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); | ^^^^^^^^^^^^^^^^^^^^ @@ -413,7 +397,7 @@ LL | asm!("{}", clobber_abi("C"), const foo); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:55:31 + --> $DIR/parse-error.rs:53:31 | LL | let mut foo = 0; | ---------- help: consider using `const` instead of `let`: `const foo` @@ -422,7 +406,7 @@ LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:55:46 + --> $DIR/parse-error.rs:53:46 | LL | let mut bar = 0; | ---------- help: consider using `const` instead of `let`: `const bar` @@ -431,7 +415,7 @@ LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:62:45 + --> $DIR/parse-error.rs:60:45 | LL | let mut bar = 0; | ---------- help: consider using `const` instead of `let`: `const bar` @@ -440,7 +424,7 @@ LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:65:45 + --> $DIR/parse-error.rs:63:45 | LL | let mut bar = 0; | ---------- help: consider using `const` instead of `let`: `const bar` @@ -449,7 +433,7 @@ LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:68:41 + --> $DIR/parse-error.rs:66:41 | LL | let mut bar = 0; | ---------- help: consider using `const` instead of `let`: `const bar` @@ -457,6 +441,6 @@ LL | let mut bar = 0; LL | asm!("{1}", in("x0") foo, const bar); | ^^^ non-constant value -error: aborting due to 66 previous errors +error: aborting due to 64 previous errors For more information about this error, try `rustc --explain E0435`. diff --git a/src/test/ui/asm/x86_64/bad-clobber-abi.rs b/src/test/ui/asm/x86_64/bad-clobber-abi.rs new file mode 100644 index 0000000000000..f4ca033048d71 --- /dev/null +++ b/src/test/ui/asm/x86_64/bad-clobber-abi.rs @@ -0,0 +1,32 @@ +// needs-asm-support +// only-x86_64 + +// checks various modes of failure for the `clobber_abi` argument (after parsing) + +#![feature(asm)] + +fn main() { + unsafe { + asm!("", clobber_abi("C")); + asm!("", clobber_abi("foo")); + //~^ ERROR invalid ABI for `clobber_abi` + asm!("", clobber_abi("C", "foo")); + //~^ ERROR invalid ABI for `clobber_abi` + asm!("", clobber_abi("C", "C")); + //~^ ERROR `C` ABI specified multiple times + asm!("", clobber_abi("win64", "sysv64")); + asm!("", clobber_abi("win64", "efiapi")); + //~^ ERROR `win64` ABI specified multiple times + asm!("", clobber_abi("C", "foo", "C")); + //~^ ERROR invalid ABI for `clobber_abi` + //~| ERROR `C` ABI specified multiple times + asm!("", clobber_abi("win64", "foo", "efiapi")); + //~^ ERROR invalid ABI for `clobber_abi` + //~| ERROR `win64` ABI specified multiple times + asm!("", clobber_abi("C"), clobber_abi("C")); + //~^ ERROR `C` ABI specified multiple times + asm!("", clobber_abi("win64"), clobber_abi("sysv64")); + asm!("", clobber_abi("win64"), clobber_abi("efiapi")); + //~^ ERROR `win64` ABI specified multiple times + } +} diff --git a/src/test/ui/asm/x86_64/bad-clobber-abi.stderr b/src/test/ui/asm/x86_64/bad-clobber-abi.stderr new file mode 100644 index 0000000000000..46e91a3951fb5 --- /dev/null +++ b/src/test/ui/asm/x86_64/bad-clobber-abi.stderr @@ -0,0 +1,88 @@ +error: invalid ABI for `clobber_abi` + --> $DIR/bad-clobber-abi.rs:11:18 + | +LL | asm!("", clobber_abi("foo")); + | ^^^^^^^^^^^^^^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-clobber-abi.rs:13:35 + | +LL | asm!("", clobber_abi("C", "foo")); + | ^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: `C` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:15:35 + | +LL | asm!("", clobber_abi("C", "C")); + | --- ^^^ + | | + | previously specified here + +error: `win64` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:18:39 + | +LL | asm!("", clobber_abi("win64", "efiapi")); + | ------- ^^^^^^^^ + | | + | previously specified here + | + = note: these ABIs are equivalent on the current target + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-clobber-abi.rs:20:35 + | +LL | asm!("", clobber_abi("C", "foo", "C")); + | ^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: `C` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:20:42 + | +LL | asm!("", clobber_abi("C", "foo", "C")); + | --- ^^^ + | | + | previously specified here + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-clobber-abi.rs:23:39 + | +LL | asm!("", clobber_abi("win64", "foo", "efiapi")); + | ^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: `win64` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:23:46 + | +LL | asm!("", clobber_abi("win64", "foo", "efiapi")); + | ------- ^^^^^^^^ + | | + | previously specified here + | + = note: these ABIs are equivalent on the current target + +error: `C` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:26:36 + | +LL | asm!("", clobber_abi("C"), clobber_abi("C")); + | ---------------- ^^^^^^^^^^^^^^^^ + | | + | previously specified here + +error: `win64` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:29:40 + | +LL | asm!("", clobber_abi("win64"), clobber_abi("efiapi")); + | -------------------- ^^^^^^^^^^^^^^^^^^^^^ + | | + | previously specified here + | + = note: these ABIs are equivalent on the current target + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/asm/x86_64/bad-options.rs b/src/test/ui/asm/x86_64/bad-options.rs index dc61d1612e8d6..3facc87641569 100644 --- a/src/test/ui/asm/x86_64/bad-options.rs +++ b/src/test/ui/asm/x86_64/bad-options.rs @@ -21,6 +21,9 @@ fn main() { //~^ ERROR invalid ABI for `clobber_abi` asm!("{}", out(reg) foo, clobber_abi("C")); //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs + asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); + //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs + //~| ERROR `C` ABI specified multiple times asm!("", out("eax") foo, clobber_abi("C")); } } diff --git a/src/test/ui/asm/x86_64/bad-options.stderr b/src/test/ui/asm/x86_64/bad-options.stderr index 8cfd450ab02a5..e2351840eef21 100644 --- a/src/test/ui/asm/x86_64/bad-options.stderr +++ b/src/test/ui/asm/x86_64/bad-options.stderr @@ -36,38 +36,47 @@ LL | asm!("{}", out(reg) foo, clobber_abi("C")); | | | generic outputs +error: asm with `clobber_abi` must specify explicit registers for outputs + --> $DIR/bad-options.rs:24:20 + | +LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); + | ^^^^^^^^^^^^ ---------------- ---------------- clobber_abi + | | | + | | clobber_abi + | generic outputs + error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` - --> $DIR/bad-options.rs:28:25 + --> $DIR/bad-options.rs:31:25 | LL | global_asm!("", options(nomem)); | ^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `readonly` - --> $DIR/bad-options.rs:30:25 + --> $DIR/bad-options.rs:33:25 | LL | global_asm!("", options(readonly)); | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn` - --> $DIR/bad-options.rs:32:25 + --> $DIR/bad-options.rs:35:25 | LL | global_asm!("", options(noreturn)); | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `pure` - --> $DIR/bad-options.rs:34:25 + --> $DIR/bad-options.rs:37:25 | LL | global_asm!("", options(pure)); | ^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `nostack` - --> $DIR/bad-options.rs:36:25 + --> $DIR/bad-options.rs:39:25 | LL | global_asm!("", options(nostack)); | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags` - --> $DIR/bad-options.rs:38:25 + --> $DIR/bad-options.rs:41:25 | LL | global_asm!("", options(preserves_flags)); | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` @@ -80,5 +89,13 @@ LL | asm!("", clobber_abi("foo")); | = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` -error: aborting due to 13 previous errors +error: `C` ABI specified multiple times + --> $DIR/bad-options.rs:24:52 + | +LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); + | ---------------- ^^^^^^^^^^^^^^^^ + | | + | previously specified here + +error: aborting due to 15 previous errors diff --git a/src/test/ui/asm/x86_64/multiple-clobber-abi.rs b/src/test/ui/asm/x86_64/multiple-clobber-abi.rs new file mode 100644 index 0000000000000..10aa004d431bd --- /dev/null +++ b/src/test/ui/asm/x86_64/multiple-clobber-abi.rs @@ -0,0 +1,33 @@ +// run-pass +// needs-asm-support +// only-x86_64 + +// Checks that multiple clobber_abi options can be used + +#![feature(asm)] + +extern "sysv64" fn foo(x: i32) -> i32 { + x + 16 +} + +extern "win64" fn bar(x: i32) -> i32 { + x / 2 +} + +fn main() { + let x = 8; + let y: i32; + // call `foo` with `x` as the input, and then `bar` with the output of `foo` + // and output that to `y` + unsafe { + asm!( + "call {}; mov rcx, rax; call {}", + sym foo, + sym bar, + in("rdi") x, + out("rax") y, + clobber_abi("sysv64", "win64"), + ); + } + assert_eq!((x, y), (8, 12)); +} diff --git a/src/test/ui/asm/x86_64/parse-error.rs b/src/test/ui/asm/x86_64/parse-error.rs index e7f3804c5886c..1d6545f1b5c7a 100644 --- a/src/test/ui/asm/x86_64/parse-error.rs +++ b/src/test/ui/asm/x86_64/parse-error.rs @@ -37,12 +37,14 @@ fn main() { asm!("{}", options(), const foo); //~^ ERROR arguments are not allowed after options //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", clobber_abi()); + //~^ ERROR at least one abi must be provided asm!("", clobber_abi(foo)); //~^ ERROR expected string literal asm!("", clobber_abi("C" foo)); - //~^ ERROR expected `)`, found `foo` + //~^ ERROR expected one of `)` or `,`, found `foo` asm!("", clobber_abi("C", foo)); - //~^ ERROR expected `)`, found `,` + //~^ ERROR expected string literal asm!("{}", clobber_abi("C"), const foo); //~^ ERROR arguments are not allowed after clobber_abi //~^^ ERROR attempt to use a non-constant value in a constant @@ -50,8 +52,6 @@ fn main() { //~^ ERROR clobber_abi is not allowed after options asm!("{}", options(), clobber_abi("C"), const foo); //~^ ERROR clobber_abi is not allowed after options - asm!("", clobber_abi("C"), clobber_abi("C")); - //~^ ERROR clobber_abi specified multiple times asm!("{a}", a = const foo, a = const bar); //~^ ERROR duplicate argument named `a` //~^^ ERROR argument never used @@ -110,9 +110,9 @@ global_asm!("{}", options(), const FOO); global_asm!("", clobber_abi(FOO)); //~^ ERROR expected string literal global_asm!("", clobber_abi("C" FOO)); -//~^ ERROR expected `)`, found `FOO` +//~^ ERROR expected one of `)` or `,`, found `FOO` global_asm!("", clobber_abi("C", FOO)); -//~^ ERROR expected `)`, found `,` +//~^ ERROR expected string literal global_asm!("{}", clobber_abi("C"), const FOO); //~^ ERROR arguments are not allowed after clobber_abi //~^^ ERROR `clobber_abi` cannot be used with `global_asm!` @@ -121,7 +121,7 @@ global_asm!("", options(), clobber_abi("C")); global_asm!("{}", options(), clobber_abi("C"), const FOO); //~^ ERROR clobber_abi is not allowed after options global_asm!("", clobber_abi("C"), clobber_abi("C")); -//~^ ERROR clobber_abi specified multiple times +//~^ ERROR `clobber_abi` cannot be used with `global_asm!` global_asm!("{a}", a = const FOO, a = const BAR); //~^ ERROR duplicate argument named `a` //~^^ ERROR argument never used diff --git a/src/test/ui/asm/x86_64/parse-error.stderr b/src/test/ui/asm/x86_64/parse-error.stderr index 91a6baa4afb29..018df9826c6ee 100644 --- a/src/test/ui/asm/x86_64/parse-error.stderr +++ b/src/test/ui/asm/x86_64/parse-error.stderr @@ -90,26 +90,32 @@ LL | asm!("{}", options(), const foo); | | | previous options -error: expected string literal +error: at least one abi must be provided as an argument to `clobber_abi` --> $DIR/parse-error.rs:40:30 | +LL | asm!("", clobber_abi()); + | ^ + +error: expected string literal + --> $DIR/parse-error.rs:42:30 + | LL | asm!("", clobber_abi(foo)); | ^^^ not a string literal -error: expected `)`, found `foo` - --> $DIR/parse-error.rs:42:34 +error: expected one of `)` or `,`, found `foo` + --> $DIR/parse-error.rs:44:34 | LL | asm!("", clobber_abi("C" foo)); - | ^^^ expected `)` + | ^^^ expected one of `)` or `,` -error: expected `)`, found `,` - --> $DIR/parse-error.rs:44:33 +error: expected string literal + --> $DIR/parse-error.rs:46:35 | LL | asm!("", clobber_abi("C", foo)); - | ^ expected `)` + | ^^^ not a string literal error: arguments are not allowed after clobber_abi - --> $DIR/parse-error.rs:46:38 + --> $DIR/parse-error.rs:48:38 | LL | asm!("{}", clobber_abi("C"), const foo); | ---------------- ^^^^^^^^^ argument @@ -117,7 +123,7 @@ LL | asm!("{}", clobber_abi("C"), const foo); | clobber_abi error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:49:29 + --> $DIR/parse-error.rs:51:29 | LL | asm!("", options(), clobber_abi("C")); | --------- ^^^^^^^^^^^^^^^^ @@ -125,21 +131,13 @@ LL | asm!("", options(), clobber_abi("C")); | options error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:51:31 + --> $DIR/parse-error.rs:53:31 | LL | asm!("{}", options(), clobber_abi("C"), const foo); | --------- ^^^^^^^^^^^^^^^^ | | | options -error: clobber_abi specified multiple times - --> $DIR/parse-error.rs:53:36 - | -LL | asm!("", clobber_abi("C"), clobber_abi("C")); - | ---------------- ^^^^^^^^^^^^^^^^ - | | - | clobber_abi previously specified here - error: duplicate argument named `a` --> $DIR/parse-error.rs:55:36 | @@ -300,17 +298,17 @@ error: expected string literal LL | global_asm!("", clobber_abi(FOO)); | ^^^ not a string literal -error: expected `)`, found `FOO` +error: expected one of `)` or `,`, found `FOO` --> $DIR/parse-error.rs:112:33 | LL | global_asm!("", clobber_abi("C" FOO)); - | ^^^ expected `)` + | ^^^ expected one of `)` or `,` -error: expected `)`, found `,` - --> $DIR/parse-error.rs:114:32 +error: expected string literal + --> $DIR/parse-error.rs:114:34 | LL | global_asm!("", clobber_abi("C", FOO)); - | ^ expected `)` + | ^^^ not a string literal error: arguments are not allowed after clobber_abi --> $DIR/parse-error.rs:116:37 @@ -342,13 +340,11 @@ LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); | | | options -error: clobber_abi specified multiple times - --> $DIR/parse-error.rs:123:35 +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:123:17 | LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); - | ---------------- ^^^^^^^^^^^^^^^^ - | | - | clobber_abi previously specified here + | ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ error: duplicate argument named `a` --> $DIR/parse-error.rs:125:35 @@ -404,7 +400,7 @@ LL | asm!("{}", options(), const foo); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:46:44 + --> $DIR/parse-error.rs:48:44 | LL | let mut foo = 0; | ---------- help: consider using `const` instead of `let`: `const foo` diff --git a/src/tools/html-checker/main.rs b/src/tools/html-checker/main.rs index 7bdf527d8842b..f52fbdfe2d7dc 100644 --- a/src/tools/html-checker/main.rs +++ b/src/tools/html-checker/main.rs @@ -79,11 +79,34 @@ fn find_all_html_files(dir: &Path) -> (usize, usize) { (files_read, errors) } +/// Default `tidy` command for macOS is too old that it does not have `mute-id` and `mute` options. +/// `tidy` on macOS Monterey was released on 31 October 2006, and the same date can be seen seven +/// years ago at . Accordingly, +/// the macOS environment using pre-installed `tidy` should immediately suspend HTML checker process +/// and show a hint to install a newer one. +#[cfg(target_os = "macos")] +fn check_tidy_version() -> Result<(), String> { + let output = Command::new("tidy").arg("-v").output().expect("failed to run tidy command"); + let version = String::from_utf8(output.stdout).expect("failed to read version of tidy command"); + if version.contains("HTML Tidy for Mac OS X released on 31 October 2006") { + eprintln!("The pre-installed HTML Tidy for macOS is not supported."); + eprintln!("Consider installing a newer one and re-running."); + eprintln!("If you're using Homebrew, you can install it by the following command:"); + eprintln!(" brew install tidy-html5"); + eprintln!(); + Err("HTML check failed: 1 error".to_string()) + } else { + Ok(()) + } +} + fn main() -> Result<(), String> { let args = env::args().collect::>(); if args.len() != 2 { return Err(format!("Usage: {} ", args[0])); } + #[cfg(target_os = "macos")] + check_tidy_version()?; println!("Running HTML checker...");