From 5b7ab8061a1e4ef87c4d4963818850a674453ba8 Mon Sep 17 00:00:00 2001 From: Andres Suarez Date: Tue, 20 Dec 2022 10:22:44 -0500 Subject: [PATCH 01/15] Stabilize path_as_mut_os_str Closes #105021 --- library/std/src/path.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 73b5056e93267..2cb7b3de16a8e 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1468,7 +1468,6 @@ impl PathBuf { /// # Examples /// /// ``` - /// #![feature(path_as_mut_os_str)] /// use std::path::{Path, PathBuf}; /// /// let mut path = PathBuf::from("/foo"); @@ -1480,7 +1479,7 @@ impl PathBuf { /// path.as_mut_os_string().push("baz"); /// assert_eq!(path, Path::new("/foo/barbaz")); /// ``` - #[unstable(feature = "path_as_mut_os_str", issue = "105021")] + #[stable(feature = "path_as_mut_os_str", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub fn as_mut_os_string(&mut self) -> &mut OsString { @@ -2036,7 +2035,6 @@ impl Path { /// # Examples /// /// ``` - /// #![feature(path_as_mut_os_str)] /// use std::path::{Path, PathBuf}; /// /// let mut path = PathBuf::from("Foo.TXT"); @@ -2046,7 +2044,7 @@ impl Path { /// path.as_mut_os_str().make_ascii_lowercase(); /// assert_eq!(path, Path::new("foo.txt")); /// ``` - #[unstable(feature = "path_as_mut_os_str", issue = "105021")] + #[stable(feature = "path_as_mut_os_str", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub fn as_mut_os_str(&mut self) -> &mut OsStr { From 52f7a218fb496aefb2364ccc508556c45df47e7f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 16 Dec 2022 04:20:34 +0000 Subject: [PATCH 02/15] Relax ordering rules for `asm!` operands The `asm!` and `global_asm!` macros require their operands to appear strictly in the following order: - Template strings - Positional operands - Named operands - Explicit register operands - `clobber_abi` - `options` This is overly strict and can be inconvienent when building complex `asm!` statements with macros. This PR relaxes the ordering requirements as follows: - Template strings must still come before all other operands. - Positional operands must still come before named and explicit register operands. - Named and explicit register operands can be freely mixed. - `options` and `clobber_abi` can appear in any position. --- compiler/rustc_builtin_macros/src/asm.rs | 35 +--- tests/ui/asm/aarch64/parse-error.rs | 23 +-- tests/ui/asm/aarch64/parse-error.stderr | 169 ++++++----------- .../bad-template.aarch64_mirunsafeck.stderr | 5 + .../bad-template.aarch64_thirunsafeck.stderr | 5 + .../bad-template.x86_64_mirunsafeck.stderr | 5 + .../bad-template.x86_64_thirunsafeck.stderr | 5 + tests/ui/asm/x86_64/parse-error.rs | 23 +-- tests/ui/asm/x86_64/parse-error.stderr | 173 ++++++------------ 9 files changed, 152 insertions(+), 291 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 925392b500ad2..7f7f27837ea14 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -203,17 +203,6 @@ pub fn parse_asm_args<'a>( // Validate the order of named, positional & explicit register operands and // clobber_abi/options. We do this at the end once we have the full span // of the argument available. - if !args.options_spans.is_empty() { - diag.struct_span_err(span, "arguments are not allowed after options") - .span_labels(args.options_spans.clone(), "previous options") - .span_label(span, "argument") - .emit(); - } else if let Some((_, abi_span)) = args.clobber_abis.last() { - diag.struct_span_err(span, "arguments are not allowed after clobber_abi") - .span_label(*abi_span, "clobber_abi") - .span_label(span, "argument") - .emit(); - } if explicit_reg { if name.is_some() { diag.struct_span_err(span, "explicit register arguments cannot have names").emit(); @@ -227,17 +216,6 @@ pub fn parse_asm_args<'a>( .emit(); continue; } - if !args.reg_args.is_empty() { - let mut err = diag.struct_span_err( - span, - "named arguments cannot follow explicit register arguments", - ); - err.span_label(span, "named argument"); - for pos in &args.reg_args { - err.span_label(args.operands[*pos].1, "explicit register argument"); - } - err.emit(); - } args.named_args.insert(name, slot); } else { if !args.named_args.is_empty() || !args.reg_args.is_empty() { @@ -478,15 +456,6 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, 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(full_span, "clobber_abi is not allowed after options"); - err.span_labels(args.options_spans.clone(), "options"); - return Err(err); - } - match &new_abis[..] { // should have errored above during parsing [] => unreachable!(), @@ -699,6 +668,10 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option $DIR/parse-error.rs:39:31 - | -LL | asm!("{}", options(), const foo); - | --------- ^^^^^^^^^ argument - | | - | previous options - error: expected string literal - --> $DIR/parse-error.rs:42:30 + --> $DIR/parse-error.rs:41:30 | LL | asm!("", clobber_abi(foo)); | ^^^ not a string literal error: expected one of `)` or `,`, found `foo` - --> $DIR/parse-error.rs:44:34 + --> $DIR/parse-error.rs:43:34 | LL | asm!("", clobber_abi("C" foo)); | ^^^ expected one of `)` or `,` error: expected string literal - --> $DIR/parse-error.rs:46:35 + --> $DIR/parse-error.rs:45:35 | LL | asm!("", clobber_abi("C", foo)); | ^^^ not a string literal -error: arguments are not allowed after clobber_abi - --> $DIR/parse-error.rs:48:38 - | -LL | asm!("{}", clobber_abi("C"), const foo); - | ---------------- ^^^^^^^^^ argument - | | - | clobber_abi - -error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:51:29 - | -LL | asm!("", options(), clobber_abi("C")); - | --------- ^^^^^^^^^^^^^^^^ - | | - | options - -error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:53:31 - | -LL | asm!("{}", options(), clobber_abi("C"), const foo); - | --------- ^^^^^^^^^^^^^^^^ - | | - | options - error: duplicate argument named `a` - --> $DIR/parse-error.rs:55:36 + --> $DIR/parse-error.rs:52:36 | LL | asm!("{a}", a = const foo, a = const bar); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -141,7 +109,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:52:36 | LL | asm!("{a}", a = const foo, a = const bar); | ^^^^^^^^^^^^^ argument never used @@ -149,29 +117,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:57:18 | LL | asm!("", a = in("x0") foo); | ^^^^^^^^^^^^^^^^ -error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:62:35 - | -LL | asm!("{a}", in("x0") foo, a = const bar); - | ------------ ^^^^^^^^^^^^^ named argument - | | - | explicit register argument - -error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:65:35 - | -LL | asm!("{a}", in("x0") foo, a = const bar); - | ------------ ^^^^^^^^^^^^^ named argument - | | - | explicit register argument - error: positional arguments cannot follow named arguments or explicit register arguments - --> $DIR/parse-error.rs:68:35 + --> $DIR/parse-error.rs:63:35 | LL | asm!("{1}", in("x0") foo, const bar); | ------------ ^^^^^^^^^ positional argument @@ -179,19 +131,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:66: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:68: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:70:14 | LL | asm!(format!("{{{}}}", 0), in(reg) foo); | ^^^^^^^^^^^^^^^^^^^^ @@ -199,7 +151,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:72:21 | LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); | ^^^^^^^^^^^^^^^^^^^^ @@ -207,135 +159,115 @@ 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:74:28 | LL | asm!("{}", in(reg) _); | ^ error: _ cannot be used for input operands - --> $DIR/parse-error.rs:81:31 + --> $DIR/parse-error.rs:76:31 | LL | asm!("{}", inout(reg) _); | ^ error: _ cannot be used for input operands - --> $DIR/parse-error.rs:83:35 + --> $DIR/parse-error.rs:78:35 | LL | asm!("{}", inlateout(reg) _); | ^ error: requires at least a template string argument - --> $DIR/parse-error.rs:90:1 + --> $DIR/parse-error.rs:85:1 | LL | global_asm!(); | ^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/parse-error.rs:92:13 + --> $DIR/parse-error.rs:87:13 | LL | global_asm!(FOO); | ^^^ error: expected token: `,` - --> $DIR/parse-error.rs:94:18 + --> $DIR/parse-error.rs:89:18 | LL | global_asm!("{}" FOO); | ^^^ expected `,` error: expected operand, options, or additional template string - --> $DIR/parse-error.rs:96:19 + --> $DIR/parse-error.rs:91: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:93: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:95: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:97: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:99: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:101: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 - | -LL | global_asm!("{}", options(), const FOO); - | --------- ^^^^^^^^^ argument - | | - | previous options - error: expected string literal - --> $DIR/parse-error.rs:110:29 + --> $DIR/parse-error.rs:104:29 | LL | global_asm!("", clobber_abi(FOO)); | ^^^ not a string literal error: expected one of `)` or `,`, found `FOO` - --> $DIR/parse-error.rs:112:33 + --> $DIR/parse-error.rs:106:33 | LL | global_asm!("", clobber_abi("C" FOO)); | ^^^ expected one of `)` or `,` error: expected string literal - --> $DIR/parse-error.rs:114:34 + --> $DIR/parse-error.rs:108:34 | LL | global_asm!("", clobber_abi("C", FOO)); | ^^^ not a string literal -error: arguments are not allowed after clobber_abi - --> $DIR/parse-error.rs:116:37 - | -LL | global_asm!("{}", clobber_abi("C"), const FOO); - | ---------------- ^^^^^^^^^ argument - | | - | clobber_abi - error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:116:19 + --> $DIR/parse-error.rs:110:19 | LL | global_asm!("{}", clobber_abi("C"), const FOO); | ^^^^^^^^^^^^^^^^ -error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:119:28 +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:112:28 | LL | global_asm!("", options(), clobber_abi("C")); - | --------- ^^^^^^^^^^^^^^^^ - | | - | options + | ^^^^^^^^^^^^^^^^ -error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:121:30 +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:114:30 | LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); - | --------- ^^^^^^^^^^^^^^^^ - | | - | options + | ^^^^^^^^^^^^^^^^ error: duplicate argument named `a` - --> $DIR/parse-error.rs:123:35 + --> $DIR/parse-error.rs:116:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -343,7 +275,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); | previously here error: argument never used - --> $DIR/parse-error.rs:123:35 + --> $DIR/parse-error.rs:116:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ^^^^^^^^^^^^^ argument never used @@ -351,19 +283,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`, `options`, or `sym`, found `""` - --> $DIR/parse-error.rs:126:28 + --> $DIR/parse-error.rs:119:28 | LL | global_asm!("", options(), ""); | ^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:128:30 + --> $DIR/parse-error.rs:121:30 | LL | global_asm!("{}", const FOO, "{}", const FOO); | ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: asm template must be a string literal - --> $DIR/parse-error.rs:130:13 + --> $DIR/parse-error.rs:123:13 | LL | global_asm!(format!("{{{}}}", 0), const FOO); | ^^^^^^^^^^^^^^^^^^^^ @@ -371,7 +303,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:132:20 + --> $DIR/parse-error.rs:125:20 | LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); | ^^^^^^^^^^^^^^^^^^^^ @@ -388,7 +320,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:48:44 + --> $DIR/parse-error.rs:47:44 | LL | let mut foo = 0; | ----------- help: consider using `const` instead of `let`: `const foo` @@ -397,7 +329,16 @@ 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:50:55 + | +LL | let mut foo = 0; + | ----------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{}", options(), clobber_abi("C"), const foo); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:52:31 | LL | let mut foo = 0; | ----------- help: consider using `const` instead of `let`: `const foo` @@ -406,7 +347,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:52:46 | LL | let mut bar = 0; | ----------- help: consider using `const` instead of `let`: `const bar` @@ -415,7 +356,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:59:45 | LL | let mut bar = 0; | ----------- help: consider using `const` instead of `let`: `const bar` @@ -424,7 +365,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:61:45 | LL | let mut bar = 0; | ----------- help: consider using `const` instead of `let`: `const bar` @@ -433,7 +374,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:63:41 | LL | let mut bar = 0; | ----------- help: consider using `const` instead of `let`: `const bar` @@ -441,6 +382,6 @@ LL | let mut bar = 0; LL | asm!("{1}", in("x0") foo, const bar); | ^^^ non-constant value -error: aborting due to 64 previous errors +error: aborting due to 57 previous errors For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/asm/bad-template.aarch64_mirunsafeck.stderr b/tests/ui/asm/bad-template.aarch64_mirunsafeck.stderr index bb6a222b22ee7..b16f9a06c2abe 100644 --- a/tests/ui/asm/bad-template.aarch64_mirunsafeck.stderr +++ b/tests/ui/asm/bad-template.aarch64_mirunsafeck.stderr @@ -81,6 +81,11 @@ note: explicit register arguments cannot be used in the asm template | LL | asm!("{}", in("x0") foo); | ^^^^^^^^^^^^ +help: use the register name directly in the assembly code + --> $DIR/bad-template.rs:48:20 + | +LL | asm!("{}", in("x0") foo); + | ^^^^^^^^^^^^ error: asm template modifier must be a single character --> $DIR/bad-template.rs:50:17 diff --git a/tests/ui/asm/bad-template.aarch64_thirunsafeck.stderr b/tests/ui/asm/bad-template.aarch64_thirunsafeck.stderr index bb6a222b22ee7..b16f9a06c2abe 100644 --- a/tests/ui/asm/bad-template.aarch64_thirunsafeck.stderr +++ b/tests/ui/asm/bad-template.aarch64_thirunsafeck.stderr @@ -81,6 +81,11 @@ note: explicit register arguments cannot be used in the asm template | LL | asm!("{}", in("x0") foo); | ^^^^^^^^^^^^ +help: use the register name directly in the assembly code + --> $DIR/bad-template.rs:48:20 + | +LL | asm!("{}", in("x0") foo); + | ^^^^^^^^^^^^ error: asm template modifier must be a single character --> $DIR/bad-template.rs:50:17 diff --git a/tests/ui/asm/bad-template.x86_64_mirunsafeck.stderr b/tests/ui/asm/bad-template.x86_64_mirunsafeck.stderr index 903b5e959f3ef..41ac37c33c2e0 100644 --- a/tests/ui/asm/bad-template.x86_64_mirunsafeck.stderr +++ b/tests/ui/asm/bad-template.x86_64_mirunsafeck.stderr @@ -81,6 +81,11 @@ note: explicit register arguments cannot be used in the asm template | LL | asm!("{}", in("eax") foo); | ^^^^^^^^^^^^^ +help: use the register name directly in the assembly code + --> $DIR/bad-template.rs:45:20 + | +LL | asm!("{}", in("eax") foo); + | ^^^^^^^^^^^^^ error: asm template modifier must be a single character --> $DIR/bad-template.rs:50:17 diff --git a/tests/ui/asm/bad-template.x86_64_thirunsafeck.stderr b/tests/ui/asm/bad-template.x86_64_thirunsafeck.stderr index 903b5e959f3ef..41ac37c33c2e0 100644 --- a/tests/ui/asm/bad-template.x86_64_thirunsafeck.stderr +++ b/tests/ui/asm/bad-template.x86_64_thirunsafeck.stderr @@ -81,6 +81,11 @@ note: explicit register arguments cannot be used in the asm template | LL | asm!("{}", in("eax") foo); | ^^^^^^^^^^^^^ +help: use the register name directly in the assembly code + --> $DIR/bad-template.rs:45:20 + | +LL | asm!("{}", in("eax") foo); + | ^^^^^^^^^^^^^ error: asm template modifier must be a single character --> $DIR/bad-template.rs:50:17 diff --git a/tests/ui/asm/x86_64/parse-error.rs b/tests/ui/asm/x86_64/parse-error.rs index 9aeb6b2853fba..2e714d464ae74 100644 --- a/tests/ui/asm/x86_64/parse-error.rs +++ b/tests/ui/asm/x86_64/parse-error.rs @@ -37,8 +37,7 @@ fn main() { asm!("", options(nomem, foo)); //~^ ERROR expected one of asm!("{}", options(), const foo); - //~^ ERROR arguments are not allowed after options - //~^^ ERROR attempt to use a non-constant value in a constant + //~^ 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)); @@ -48,12 +47,10 @@ fn main() { asm!("", clobber_abi("C", foo)); //~^ 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 + //~^ ERROR attempt to use a non-constant value in a constant asm!("", options(), clobber_abi("C")); - //~^ ERROR clobber_abi is not allowed after options asm!("{}", options(), clobber_abi("C"), const foo); - //~^ ERROR clobber_abi is not allowed after options + //~^ ERROR attempt to use a non-constant value in a constant asm!("{a}", a = const foo, a = const bar); //~^ ERROR duplicate argument named `a` //~^^ ERROR argument never used @@ -62,11 +59,9 @@ fn main() { asm!("", a = in("eax") foo); //~^ ERROR explicit register arguments cannot have names asm!("{a}", in("eax") foo, a = const bar); - //~^ ERROR named arguments cannot follow explicit register arguments - //~^^ ERROR attempt to use a non-constant value in a constant + //~^ ERROR attempt to use a non-constant value in a constant asm!("{a}", in("eax") foo, a = const bar); - //~^ ERROR named arguments cannot follow explicit register arguments - //~^^ ERROR attempt to use a non-constant value in a constant + //~^ ERROR attempt to use a non-constant value in a constant asm!("{1}", in("eax") foo, const bar); //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments //~^^ ERROR attempt to use a non-constant value in a constant @@ -108,7 +103,6 @@ global_asm!("", options(nomem FOO)); global_asm!("", options(nomem, FOO)); //~^ ERROR expected one of global_asm!("{}", options(), const FOO); -//~^ ERROR arguments are not allowed after options global_asm!("", clobber_abi(FOO)); //~^ ERROR expected string literal global_asm!("", clobber_abi("C" FOO)); @@ -116,12 +110,11 @@ global_asm!("", clobber_abi("C" FOO)); global_asm!("", clobber_abi("C", FOO)); //~^ 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!` +//~^ ERROR `clobber_abi` cannot be used with `global_asm!` global_asm!("", options(), clobber_abi("C")); -//~^ ERROR clobber_abi is not allowed after options +//~^ ERROR `clobber_abi` cannot be used with `global_asm!` global_asm!("{}", options(), clobber_abi("C"), const FOO); -//~^ ERROR clobber_abi is not allowed after options +//~^ ERROR `clobber_abi` cannot be used with `global_asm!` global_asm!("", clobber_abi("C"), clobber_abi("C")); //~^ ERROR `clobber_abi` cannot be used with `global_asm!` global_asm!("{a}", a = const FOO, a = const BAR); diff --git a/tests/ui/asm/x86_64/parse-error.stderr b/tests/ui/asm/x86_64/parse-error.stderr index 57702c37b7ce2..0c9d6f71529c1 100644 --- a/tests/ui/asm/x86_64/parse-error.stderr +++ b/tests/ui/asm/x86_64/parse-error.stderr @@ -82,64 +82,32 @@ error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `no LL | asm!("", options(nomem, foo)); | ^^^ expected one of 10 possible tokens -error: arguments are not allowed after options - --> $DIR/parse-error.rs:39:31 - | -LL | asm!("{}", options(), const foo); - | --------- ^^^^^^^^^ argument - | | - | previous options - error: at least one abi must be provided as an argument to `clobber_abi` - --> $DIR/parse-error.rs:42:30 + --> $DIR/parse-error.rs:41:30 | LL | asm!("", clobber_abi()); | ^ error: expected string literal - --> $DIR/parse-error.rs:44:30 + --> $DIR/parse-error.rs:43:30 | LL | asm!("", clobber_abi(foo)); | ^^^ not a string literal error: expected one of `)` or `,`, found `foo` - --> $DIR/parse-error.rs:46:34 + --> $DIR/parse-error.rs:45:34 | LL | asm!("", clobber_abi("C" foo)); | ^^^ expected one of `)` or `,` error: expected string literal - --> $DIR/parse-error.rs:48:35 + --> $DIR/parse-error.rs:47:35 | LL | asm!("", clobber_abi("C", foo)); | ^^^ not a string literal -error: arguments are not allowed after clobber_abi - --> $DIR/parse-error.rs:50:38 - | -LL | asm!("{}", clobber_abi("C"), const foo); - | ---------------- ^^^^^^^^^ argument - | | - | clobber_abi - -error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:53:29 - | -LL | asm!("", options(), clobber_abi("C")); - | --------- ^^^^^^^^^^^^^^^^ - | | - | options - -error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:55:31 - | -LL | asm!("{}", options(), clobber_abi("C"), const foo); - | --------- ^^^^^^^^^^^^^^^^ - | | - | options - error: duplicate argument named `a` - --> $DIR/parse-error.rs:57:36 + --> $DIR/parse-error.rs:54:36 | LL | asm!("{a}", a = const foo, a = const bar); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -147,7 +115,7 @@ LL | asm!("{a}", a = const foo, a = const bar); | previously here error: argument never used - --> $DIR/parse-error.rs:57:36 + --> $DIR/parse-error.rs:54:36 | LL | asm!("{a}", a = const foo, a = const bar); | ^^^^^^^^^^^^^ argument never used @@ -155,29 +123,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:62:18 + --> $DIR/parse-error.rs:59:18 | LL | asm!("", a = in("eax") foo); | ^^^^^^^^^^^^^^^^^ -error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:64:36 - | -LL | asm!("{a}", in("eax") foo, a = const bar); - | ------------- ^^^^^^^^^^^^^ named argument - | | - | explicit register argument - -error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:67:36 - | -LL | asm!("{a}", in("eax") foo, a = const bar); - | ------------- ^^^^^^^^^^^^^ named argument - | | - | explicit register argument - error: positional arguments cannot follow named arguments or explicit register arguments - --> $DIR/parse-error.rs:70:36 + --> $DIR/parse-error.rs:65:36 | LL | asm!("{1}", in("eax") foo, const bar); | ------------- ^^^^^^^^^ positional argument @@ -185,19 +137,19 @@ LL | asm!("{1}", in("eax") 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:73:29 + --> $DIR/parse-error.rs:68: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:75:33 + --> $DIR/parse-error.rs:70: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:77:14 + --> $DIR/parse-error.rs:72:14 | LL | asm!(format!("{{{}}}", 0), in(reg) foo); | ^^^^^^^^^^^^^^^^^^^^ @@ -205,7 +157,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:79:21 + --> $DIR/parse-error.rs:74:21 | LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); | ^^^^^^^^^^^^^^^^^^^^ @@ -213,141 +165,121 @@ 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:81:28 + --> $DIR/parse-error.rs:76:28 | LL | asm!("{}", in(reg) _); | ^ error: _ cannot be used for input operands - --> $DIR/parse-error.rs:83:31 + --> $DIR/parse-error.rs:78:31 | LL | asm!("{}", inout(reg) _); | ^ error: _ cannot be used for input operands - --> $DIR/parse-error.rs:85:35 + --> $DIR/parse-error.rs:80:35 | LL | asm!("{}", inlateout(reg) _); | ^ error: requires at least a template string argument - --> $DIR/parse-error.rs:92:1 + --> $DIR/parse-error.rs:87:1 | LL | global_asm!(); | ^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/parse-error.rs:94:13 + --> $DIR/parse-error.rs:89:13 | LL | global_asm!(FOO); | ^^^ error: expected token: `,` - --> $DIR/parse-error.rs:96:18 + --> $DIR/parse-error.rs:91:18 | LL | global_asm!("{}" FOO); | ^^^ expected `,` error: expected operand, options, or additional template string - --> $DIR/parse-error.rs:98:19 + --> $DIR/parse-error.rs:93:19 | LL | global_asm!("{}", FOO); | ^^^ expected operand, options, or additional template string error: expected expression, found end of macro arguments - --> $DIR/parse-error.rs:100:24 + --> $DIR/parse-error.rs:95:24 | LL | global_asm!("{}", const); | ^ expected expression error: expected one of `,`, `.`, `?`, or an operator, found `FOO` - --> $DIR/parse-error.rs:102:30 + --> $DIR/parse-error.rs:97: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:104:25 + --> $DIR/parse-error.rs:99: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:106:25 + --> $DIR/parse-error.rs:101: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:108:25 + --> $DIR/parse-error.rs:103: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:110:30 - | -LL | global_asm!("{}", options(), const FOO); - | --------- ^^^^^^^^^ argument - | | - | previous options - error: expected string literal - --> $DIR/parse-error.rs:112:29 + --> $DIR/parse-error.rs:106:29 | LL | global_asm!("", clobber_abi(FOO)); | ^^^ not a string literal error: expected one of `)` or `,`, found `FOO` - --> $DIR/parse-error.rs:114:33 + --> $DIR/parse-error.rs:108:33 | LL | global_asm!("", clobber_abi("C" FOO)); | ^^^ expected one of `)` or `,` error: expected string literal - --> $DIR/parse-error.rs:116:34 + --> $DIR/parse-error.rs:110:34 | LL | global_asm!("", clobber_abi("C", FOO)); | ^^^ not a string literal -error: arguments are not allowed after clobber_abi - --> $DIR/parse-error.rs:118:37 - | -LL | global_asm!("{}", clobber_abi("C"), const FOO); - | ---------------- ^^^^^^^^^ argument - | | - | clobber_abi - error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:118:19 + --> $DIR/parse-error.rs:112:19 | LL | global_asm!("{}", clobber_abi("C"), const FOO); | ^^^^^^^^^^^^^^^^ -error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:121:28 +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:114:28 | LL | global_asm!("", options(), clobber_abi("C")); - | --------- ^^^^^^^^^^^^^^^^ - | | - | options + | ^^^^^^^^^^^^^^^^ -error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:123:30 +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:116:30 | LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); - | --------- ^^^^^^^^^^^^^^^^ - | | - | options + | ^^^^^^^^^^^^^^^^ error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:125:17 + --> $DIR/parse-error.rs:118:17 | LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); | ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ error: duplicate argument named `a` - --> $DIR/parse-error.rs:127:35 + --> $DIR/parse-error.rs:120:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -355,7 +287,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); | previously here error: argument never used - --> $DIR/parse-error.rs:127:35 + --> $DIR/parse-error.rs:120:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ^^^^^^^^^^^^^ argument never used @@ -363,19 +295,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`, `options`, or `sym`, found `""` - --> $DIR/parse-error.rs:130:28 + --> $DIR/parse-error.rs:123:28 | LL | global_asm!("", options(), ""); | ^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:132:30 + --> $DIR/parse-error.rs:125:30 | LL | global_asm!("{}", const FOO, "{}", const FOO); | ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: asm template must be a string literal - --> $DIR/parse-error.rs:134:13 + --> $DIR/parse-error.rs:127:13 | LL | global_asm!(format!("{{{}}}", 0), const FOO); | ^^^^^^^^^^^^^^^^^^^^ @@ -383,7 +315,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:136:20 + --> $DIR/parse-error.rs:129:20 | LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); | ^^^^^^^^^^^^^^^^^^^^ @@ -400,7 +332,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:50:44 + --> $DIR/parse-error.rs:49:44 | LL | let mut foo = 0; | ----------- help: consider using `const` instead of `let`: `const foo` @@ -409,7 +341,16 @@ 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:57:31 + --> $DIR/parse-error.rs:52:55 + | +LL | let mut foo = 0; + | ----------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{}", options(), clobber_abi("C"), const foo); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:54:31 | LL | let mut foo = 0; | ----------- help: consider using `const` instead of `let`: `const foo` @@ -418,7 +359,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:57:46 + --> $DIR/parse-error.rs:54:46 | LL | let mut bar = 0; | ----------- help: consider using `const` instead of `let`: `const bar` @@ -427,7 +368,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:64:46 + --> $DIR/parse-error.rs:61:46 | LL | let mut bar = 0; | ----------- help: consider using `const` instead of `let`: `const bar` @@ -436,7 +377,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:67:46 + --> $DIR/parse-error.rs:63:46 | LL | let mut bar = 0; | ----------- help: consider using `const` instead of `let`: `const bar` @@ -445,7 +386,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:70:42 + --> $DIR/parse-error.rs:65:42 | LL | let mut bar = 0; | ----------- help: consider using `const` instead of `let`: `const bar` @@ -453,6 +394,6 @@ LL | let mut bar = 0; LL | asm!("{1}", in("eax") foo, const bar); | ^^^ non-constant value -error: aborting due to 66 previous errors +error: aborting due to 59 previous errors For more information about this error, try `rustc --explain E0435`. From 0f371caa860d90f67b9dc0518cd6c5a0f97827fa Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 28 Dec 2022 17:10:21 +0000 Subject: [PATCH 03/15] Support linking to rust dylibs from a staticlib --- .../rustc_metadata/src/dependency_format.rs | 23 +++++++--------- .../staticlib-dylib-linkage/Makefile | 27 +++++++++++++++++++ .../staticlib-dylib-linkage/bar.rs | 5 ++++ .../staticlib-dylib-linkage/foo.c | 10 +++++++ .../staticlib-dylib-linkage/foo.rs | 13 +++++++++ 5 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile create mode 100644 tests/run-make-fulldeps/staticlib-dylib-linkage/bar.rs create mode 100644 tests/run-make-fulldeps/staticlib-dylib-linkage/foo.c create mode 100644 tests/run-make-fulldeps/staticlib-dylib-linkage/foo.rs diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 39ef4276faf10..590a7374d116d 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -89,11 +89,12 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { // to try to eagerly statically link all dependencies. This is normally // done for end-product dylibs, not intermediate products. // - // Treat cdylibs similarly. If `-C prefer-dynamic` is set, the caller may - // be code-size conscious, but without it, it makes sense to statically - // link a cdylib. - CrateType::Dylib | CrateType::Cdylib if !sess.opts.cg.prefer_dynamic => Linkage::Static, - CrateType::Dylib | CrateType::Cdylib => Linkage::Dynamic, + // Treat cdylibs and staticlibs similarly. If `-C prefer-dynamic` is set, + // the caller may be code-size conscious, but without it, it makes sense + // to statically link a cdylib or staticlib. + CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib => { + if sess.opts.cg.prefer_dynamic { Linkage::Dynamic } else { Linkage::Static } + } // If the global prefer_dynamic switch is turned off, or the final // executable will be statically linked, prefer static crate linkage. @@ -108,9 +109,6 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { // No linkage happens with rlibs, we just needed the metadata (which we // got long ago), so don't bother with anything. CrateType::Rlib => Linkage::NotLinked, - - // staticlibs must have all static dependencies. - CrateType::Staticlib => Linkage::Static, }; match preferred_linkage { @@ -123,12 +121,11 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { return v; } - // Staticlibs and static executables must have all static dependencies. + // Static executables must have all static dependencies. // If any are not found, generate some nice pretty errors. - if ty == CrateType::Staticlib - || (ty == CrateType::Executable - && sess.crt_static(Some(ty)) - && !sess.target.crt_static_allows_dylibs) + if ty == CrateType::Executable + && sess.crt_static(Some(ty)) + && !sess.target.crt_static_allows_dylibs { for &cnum in tcx.crates(()).iter() { if tcx.dep_kind(cnum).macros_only() { diff --git a/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile b/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile new file mode 100644 index 0000000000000..bf811395981e5 --- /dev/null +++ b/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile @@ -0,0 +1,27 @@ +include ../tools.mk + +TARGET_SYSROOT := $(shell $(RUSTC) --print sysroot)/lib/rustlib/$(TARGET)/lib + +ifdef IS_MSVC +LIBSTD := $(wildcard $(TARGET_SYSROOT)/libstd-*.dll.lib) +else +LIBSTD := $(wildcard $(TARGET_SYSROOT)/$(call DYLIB_GLOB,std)) +STD := $(basename $(patsubst lib%,%, $(notdir $(LIBSTD)))) +endif + +all: $(call RUN_BINFILE,foo) + $(call RUN,foo) + +ifdef IS_MSVC +CLIBS := $(TMPDIR)/foo.lib $(TMPDIR)/bar.dll.lib $(LIBSTD) +$(call RUN_BINFILE,foo): $(call STATICLIB,foo) + $(CC) $(CFLAGS) foo.c $(CLIBS) $(call OUT_EXE,foo) +else +CLIBS := $(TMPDIR)/libfoo.a -lbar -l$(STD) -L $(TMPDIR) -L $(TARGET_SYSROOT) +$(call RUN_BINFILE,foo): $(call STATICLIB,foo) + $(CC) $(CFLAGS) foo.c $(CLIBS) -o $(call RUN_BINFILE,foo) +endif + +$(call STATICLIB,foo): + $(RUSTC) -C prefer-dynamic bar.rs + $(RUSTC) foo.rs diff --git a/tests/run-make-fulldeps/staticlib-dylib-linkage/bar.rs b/tests/run-make-fulldeps/staticlib-dylib-linkage/bar.rs new file mode 100644 index 0000000000000..b3a7539abaeff --- /dev/null +++ b/tests/run-make-fulldeps/staticlib-dylib-linkage/bar.rs @@ -0,0 +1,5 @@ +#![crate_type = "dylib"] + +pub fn bar() { + println!("hello!"); +} diff --git a/tests/run-make-fulldeps/staticlib-dylib-linkage/foo.c b/tests/run-make-fulldeps/staticlib-dylib-linkage/foo.c new file mode 100644 index 0000000000000..154f9682ef8f1 --- /dev/null +++ b/tests/run-make-fulldeps/staticlib-dylib-linkage/foo.c @@ -0,0 +1,10 @@ +#include + +extern void foo(); +extern unsigned bar(unsigned a, unsigned b); + +int main() { + foo(); + assert(bar(1, 2) == 3); + return 0; +} diff --git a/tests/run-make-fulldeps/staticlib-dylib-linkage/foo.rs b/tests/run-make-fulldeps/staticlib-dylib-linkage/foo.rs new file mode 100644 index 0000000000000..af439391c757e --- /dev/null +++ b/tests/run-make-fulldeps/staticlib-dylib-linkage/foo.rs @@ -0,0 +1,13 @@ +#![crate_type = "staticlib"] + +extern crate bar; + +#[no_mangle] +pub extern "C" fn foo() { + bar::bar(); +} + +#[no_mangle] +pub extern "C" fn bar(a: u32, b: u32) -> u32 { + a + b +} From 7e2f6c17a232cc3f5ce6e1bff15251b66d419e91 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 28 Dec 2022 18:13:19 +0000 Subject: [PATCH 04/15] Support `--print native-static-libs` with rust dylibs --- compiler/rustc_codegen_ssa/src/back/link.rs | 75 +++++++++++++++++-- .../staticlib-dylib-linkage/Makefile | 25 ++----- 2 files changed, 76 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8aa744ce93531..7b6d6018590e8 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -544,12 +544,38 @@ fn link_staticlib<'a>( ab.build(out_filename); - if !all_native_libs.is_empty() { - if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) { - print_native_static_libs(sess, &all_native_libs); + let crates = codegen_results.crate_info.used_crates.iter(); + + let fmts = codegen_results + .crate_info + .dependency_formats + .iter() + .find_map(|&(ty, ref list)| if ty == CrateType::Staticlib { Some(list) } else { None }) + .expect("no dependency formats for staticlib"); + + let mut all_rust_dylibs = vec![]; + for &cnum in crates { + match fmts.get(cnum.as_usize() - 1) { + Some(&Linkage::Dynamic) => {} + _ => continue, + } + let crate_name = codegen_results.crate_info.crate_name[&cnum]; + let used_crate_source = &codegen_results.crate_info.used_crate_source[&cnum]; + if let Some((path, _)) = &used_crate_source.dylib { + all_rust_dylibs.push(&**path); + } else { + if used_crate_source.rmeta.is_some() { + sess.emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name }); + } else { + sess.emit_fatal(errors::LinkRlibError::NotFound { crate_name }); + } } } + if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) { + print_native_static_libs(sess, &all_native_libs, &all_rust_dylibs); + } + Ok(()) } @@ -1289,8 +1315,12 @@ enum RlibFlavor { StaticlibBase, } -fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { - let lib_args: Vec<_> = all_native_libs +fn print_native_static_libs( + sess: &Session, + all_native_libs: &[NativeLib], + all_rust_dylibs: &[&Path], +) { + let mut lib_args: Vec<_> = all_native_libs .iter() .filter(|l| relevant_lib(sess, l)) .filter_map(|lib| { @@ -1319,6 +1349,41 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { } }) .collect(); + for path in all_rust_dylibs { + // FIXME deduplicate with add_dynamic_crate + + // Just need to tell the linker about where the library lives and + // what its name is + let parent = path.parent(); + if let Some(dir) = parent { + let dir = fix_windows_verbatim_for_gcc(dir); + if sess.target.is_like_msvc { + let mut arg = String::from("/LIBPATH:"); + arg.push_str(&dir.display().to_string()); + lib_args.push(arg); + } else { + lib_args.push("-L".to_owned()); + lib_args.push(dir.display().to_string()); + } + } + let stem = path.file_stem().unwrap().to_str().unwrap(); + // Convert library file-stem into a cc -l argument. + let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 }; + let lib = &stem[prefix..]; + let path = parent.unwrap_or_else(|| Path::new("")); + if sess.target.is_like_msvc { + // When producing a dll, the MSVC linker may not actually emit a + // `foo.lib` file if the dll doesn't actually export any symbols, so we + // check to see if the file is there and just omit linking to it if it's + // not present. + let name = format!("{}.dll.lib", lib); + if path.join(&name).exists() { + lib_args.push(name); + } + } else { + lib_args.push(format!("-l{}", lib)); + } + } if !lib_args.is_empty() { sess.emit_note(errors::StaticLibraryNativeArtifacts); // Prefix for greppability diff --git a/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile b/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile index bf811395981e5..faa4524310478 100644 --- a/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile +++ b/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile @@ -1,27 +1,14 @@ include ../tools.mk -TARGET_SYSROOT := $(shell $(RUSTC) --print sysroot)/lib/rustlib/$(TARGET)/lib +all: + $(RUSTC) -C prefer-dynamic bar.rs + $(RUSTC) foo.rs --crate-type staticlib --print native-static-libs 2>&1 | grep 'note: native-static-libs: ' | sed 's/note: native-static-libs: \(.*\)/\1/' > $(TMPDIR)/libs.txt + cat $(TMPDIR)/libs.txt ifdef IS_MSVC -LIBSTD := $(wildcard $(TARGET_SYSROOT)/libstd-*.dll.lib) + $(CC) $(CFLAGS) foo.c $(TMPDIR)/foo.lib $$(cat $(TMPDIR)/libs.txt) $(call OUT_EXE,foo) else -LIBSTD := $(wildcard $(TARGET_SYSROOT)/$(call DYLIB_GLOB,std)) -STD := $(basename $(patsubst lib%,%, $(notdir $(LIBSTD)))) + $(CC) $(CFLAGS) foo.c -L $(TMPDIR) -lfoo $$(cat $(TMPDIR)/libs.txt) -o $(call RUN_BINFILE,foo) endif -all: $(call RUN_BINFILE,foo) $(call RUN,foo) - -ifdef IS_MSVC -CLIBS := $(TMPDIR)/foo.lib $(TMPDIR)/bar.dll.lib $(LIBSTD) -$(call RUN_BINFILE,foo): $(call STATICLIB,foo) - $(CC) $(CFLAGS) foo.c $(CLIBS) $(call OUT_EXE,foo) -else -CLIBS := $(TMPDIR)/libfoo.a -lbar -l$(STD) -L $(TMPDIR) -L $(TARGET_SYSROOT) -$(call RUN_BINFILE,foo): $(call STATICLIB,foo) - $(CC) $(CFLAGS) foo.c $(CLIBS) -o $(call RUN_BINFILE,foo) -endif - -$(call STATICLIB,foo): - $(RUSTC) -C prefer-dynamic bar.rs - $(RUSTC) foo.rs From 832fedebdb14f009d04a39852762d6afdff9b3b5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 4 Jan 2023 20:24:03 +0000 Subject: [PATCH 05/15] Add unstable feature flags --- .../rustc_metadata/src/dependency_format.rs | 26 ++++++++++++++----- compiler/rustc_session/src/options.rs | 4 +++ .../staticlib-dylib-linkage/Makefile | 4 ++- tests/rustdoc-ui/z-help.stdout | 2 ++ 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 590a7374d116d..72b208a713276 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -91,9 +91,22 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { // // Treat cdylibs and staticlibs similarly. If `-C prefer-dynamic` is set, // the caller may be code-size conscious, but without it, it makes sense - // to statically link a cdylib or staticlib. - CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib => { - if sess.opts.cg.prefer_dynamic { Linkage::Dynamic } else { Linkage::Static } + // to statically link a cdylib or staticlib. For staticlibs we use + // `-Z staticlib-prefer-dynamic` for now. This may be merged into + // `-C prefer-dynamic` in the future. + CrateType::Dylib | CrateType::Cdylib => { + if sess.opts.cg.prefer_dynamic { + Linkage::Dynamic + } else { + Linkage::Static + } + } + CrateType::Staticlib => { + if sess.opts.unstable_opts.staticlib_prefer_dynamic { + Linkage::Dynamic + } else { + Linkage::Static + } } // If the global prefer_dynamic switch is turned off, or the final @@ -123,9 +136,10 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { // Static executables must have all static dependencies. // If any are not found, generate some nice pretty errors. - if ty == CrateType::Executable - && sess.crt_static(Some(ty)) - && !sess.target.crt_static_allows_dylibs + if (ty == CrateType::Staticlib && !sess.opts.unstable_opts.staticlib_allow_rdylib_deps) + || (ty == CrateType::Executable + && sess.crt_static(Some(ty)) + && !sess.target.crt_static_allows_dylibs) { for &cnum in tcx.crates(()).iter() { if tcx.dep_kind(cnum).macros_only() { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 4beac931632be..3dfc59123d490 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1673,6 +1673,10 @@ options! { #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")] stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED], "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), + staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED], + "allow staticlibs to have rust dylib dependencies"), + staticlib_prefer_dynamic: bool = (false, parse_bool, [TRACKED], + "prefer dynamic linking to static linking for staticlibs (default: no)"), strict_init_checks: bool = (false, parse_bool, [TRACKED], "control if mem::uninitialized and mem::zeroed panic on more UB"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], diff --git a/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile b/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile index faa4524310478..fd76f6c55784d 100644 --- a/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile +++ b/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile @@ -2,7 +2,9 @@ include ../tools.mk all: $(RUSTC) -C prefer-dynamic bar.rs - $(RUSTC) foo.rs --crate-type staticlib --print native-static-libs 2>&1 | grep 'note: native-static-libs: ' | sed 's/note: native-static-libs: \(.*\)/\1/' > $(TMPDIR)/libs.txt + $(RUSTC) foo.rs --crate-type staticlib --print native-static-libs \ + -Z staticlib-allow-rdylib-deps 2>&1 | grep 'note: native-static-libs: ' \ + | sed 's/note: native-static-libs: \(.*\)/\1/' > $(TMPDIR)/libs.txt cat $(TMPDIR)/libs.txt ifdef IS_MSVC diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout index 6aa9785f44e33..1584acbe3c7a3 100644 --- a/tests/rustdoc-ui/z-help.stdout +++ b/tests/rustdoc-ui/z-help.stdout @@ -170,6 +170,8 @@ by the linker -Z src-hash-algorithm=val -- hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`) -Z stack-protector=val -- control stack smash protection strategy (`rustc --print stack-protector-strategies` for details) + -Z staticlib-allow-rdylib-deps=val -- allow staticlibs to have rust dylib dependencies + -Z staticlib-prefer-dynamic=val -- prefer dynamic linking to static linking for staticlibs (default: no) -Z strict-init-checks=val -- control if mem::uninitialized and mem::zeroed panic on more UB -Z strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`) -Z symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0') From d3cbedd49eeb3d4495902ba7fc0f593460b18599 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sun, 5 Feb 2023 19:27:35 -0500 Subject: [PATCH 06/15] Stabilize movbe target feature --- compiler/rustc_codegen_ssa/src/target_features.rs | 3 +-- compiler/rustc_feature/src/accepted.rs | 4 +++- compiler/rustc_feature/src/active.rs | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index e59fad99ad798..d52e858833f40 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -192,7 +192,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("fxsr", None), ("gfni", Some(sym::avx512_target_feature)), ("lzcnt", None), - ("movbe", Some(sym::movbe_target_feature)), + ("movbe", None), ("pclmulqdq", None), ("popcnt", None), ("rdrand", None), @@ -394,7 +394,6 @@ pub fn from_target_feature( Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature, Some(sym::tbm_target_feature) => rust_features.tbm_target_feature, Some(sym::wasm_target_feature) => rust_features.wasm_target_feature, - Some(sym::movbe_target_feature) => rust_features.movbe_target_feature, Some(sym::rtm_target_feature) => rust_features.rtm_target_feature, Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature, Some(sym::bpf_target_feature) => rust_features.bpf_target_feature, diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index e7b2df34ccca2..ac93dd555b7a4 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -90,7 +90,7 @@ declare_features! ( (accepted, clone_closures, "1.26.0", Some(44490), None), /// Allows coercing non capturing closures to function pointers. (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), - /// Allows using `cmpxchg16b` from `core::arch::x86_64`. + /// Allows using the CMPXCHG16B target feature. (accepted, cmpxchg16b_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None), /// Allows usage of the `compile_error!` macro. (accepted, compile_error, "1.20.0", Some(40872), None), @@ -238,6 +238,8 @@ declare_features! ( (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), /// Allows using `Self` and associated types in struct expressions and patterns. (accepted, more_struct_aliases, "1.16.0", Some(37544), None), + /// Allows using the MOVBE target feature. + (accepted, movbe_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None), /// Allows patterns with concurrent by-move and by-ref bindings. /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. (accepted, move_ref_pattern, "1.49.0", Some(68354), None), diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index a01914f969eb7..2fa7bceb8bc0a 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -259,7 +259,6 @@ declare_features! ( (active, ermsb_target_feature, "1.49.0", Some(44839), None), (active, hexagon_target_feature, "1.27.0", Some(44839), None), (active, mips_target_feature, "1.27.0", Some(44839), None), - (active, movbe_target_feature, "1.34.0", Some(44839), None), (active, powerpc_target_feature, "1.27.0", Some(44839), None), (active, riscv_target_feature, "1.45.0", Some(44839), None), (active, rtm_target_feature, "1.35.0", Some(44839), None), From f1cf67b29ad0f7c322e1336370138f20e6b75423 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 4 Mar 2023 11:06:33 +0000 Subject: [PATCH 07/15] Fix test for MSVC --- tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile b/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile index fd76f6c55784d..89c0bcdc3b1d9 100644 --- a/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile +++ b/tests/run-make-fulldeps/staticlib-dylib-linkage/Makefile @@ -8,7 +8,7 @@ all: cat $(TMPDIR)/libs.txt ifdef IS_MSVC - $(CC) $(CFLAGS) foo.c $(TMPDIR)/foo.lib $$(cat $(TMPDIR)/libs.txt) $(call OUT_EXE,foo) + $(CC) $(CFLAGS) foo.c $(TMPDIR)/foo.lib $(call OUT_EXE,foo) /link $$(cat $(TMPDIR)/libs.txt) else $(CC) $(CFLAGS) foo.c -L $(TMPDIR) -lfoo $$(cat $(TMPDIR)/libs.txt) -o $(call RUN_BINFILE,foo) endif From ef807cb321604ae96ed0f78c78e3e9348d6d11ba Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 23 Dec 2022 14:59:42 +0000 Subject: [PATCH 08/15] use problem matchers for tidy CI --- src/ci/github-actions/problem_matchers.json | 15 +++++++++++++++ src/ci/scripts/run-build-from-ci.sh | 2 ++ 2 files changed, 17 insertions(+) create mode 100644 src/ci/github-actions/problem_matchers.json diff --git a/src/ci/github-actions/problem_matchers.json b/src/ci/github-actions/problem_matchers.json new file mode 100644 index 0000000000000..37561924b7d4f --- /dev/null +++ b/src/ci/github-actions/problem_matchers.json @@ -0,0 +1,15 @@ +{ + "problemMatcher": [ + { + "owner": "tidy-error-file-line", + "pattern": [ + { + "regexp": "^tidy error: /checkout/(.+):(\\d+): (.+)$", + "file": 1, + "line": 2, + "message": 3 + } + ] + } + ] +} diff --git a/src/ci/scripts/run-build-from-ci.sh b/src/ci/scripts/run-build-from-ci.sh index c02117f459de0..55e75800d91c4 100755 --- a/src/ci/scripts/run-build-from-ci.sh +++ b/src/ci/scripts/run-build-from-ci.sh @@ -10,6 +10,8 @@ source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" export CI="true" export SRC=. +echo "::add-matcher::src/ci/github-actions/problem_matchers.json" + # Remove any preexisting rustup installation since it can interfere # with the cargotest step and its auto-detection of things like Clippy in # the environment From a2040de541057a4d8d25c4d3f075f2e81276eef8 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 6 Jan 2023 10:50:09 +0000 Subject: [PATCH 09/15] do not run tidy on x86_64-gnu-llvm-13 --- src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile index db6032f875211..a007bf183ee11 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile @@ -62,6 +62,4 @@ ENV SCRIPT ../x.py --stage 2 test --exclude src/tools/tidy && \ # work. # ../x.ps1 --stage 2 test tests/ui --pass=check \ - --host='' --target=i686-unknown-linux-gnu && \ - # Run tidy at the very end, after all the other tests. - python2.7 ../x.py --stage 2 test src/tools/tidy + --host='' --target=i686-unknown-linux-gnu From 2c9b8c5a2e3dde0a606b60a7bd323f6d968d29c3 Mon Sep 17 00:00:00 2001 From: "Partha P. Das" Date: Tue, 7 Feb 2023 21:41:28 -0500 Subject: [PATCH 10/15] Implementing " --list --format json" #107307 #49359 --- .gitignore | 1 + compiler/rustc_builtin_macros/src/test.rs | 27 ++- compiler/rustc_span/src/source_map.rs | 31 ++- library/test/src/console.rs | 83 +++++--- library/test/src/formatters/json.rs | 52 ++++- library/test/src/formatters/junit.rs | 14 +- library/test/src/formatters/mod.rs | 6 +- library/test/src/formatters/pretty.rs | 29 ++- library/test/src/formatters/terse.rs | 14 +- library/test/src/tests.rs | 200 ++++++++++++++++++ library/test/src/types.rs | 10 + src/librustdoc/doctest.rs | 10 + src/tools/compiletest/src/header.rs | 10 + tests/pretty/tests-are-sorted.pp | 20 +- tests/pretty/tests-are-sorted.rs | 1 + .../tests-listing-format-default.rs | 18 ++ .../tests-listing-format-default.run.stdout | 5 + ...isting-format-json-without-unstableopts.rs | 18 ++ ...ormat-json-without-unstableopts.run.stderr | 1 + .../test-attrs/tests-listing-format-json.rs | 18 ++ .../tests-listing-format-json.run.stdout | 5 + .../test-attrs/tests-listing-format-terse.rs | 18 ++ .../tests-listing-format-terse.run.stdout | 3 + 23 files changed, 550 insertions(+), 44 deletions(-) create mode 100644 tests/ui/test-attrs/tests-listing-format-default.rs create mode 100644 tests/ui/test-attrs/tests-listing-format-default.run.stdout create mode 100644 tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs create mode 100644 tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr create mode 100644 tests/ui/test-attrs/tests-listing-format-json.rs create mode 100644 tests/ui/test-attrs/tests-listing-format-json.run.stdout create mode 100644 tests/ui/test-attrs/tests-listing-format-terse.rs create mode 100644 tests/ui/test-attrs/tests-listing-format-terse.run.stdout diff --git a/.gitignore b/.gitignore index ce797a7a8371d..089831b8013f7 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ Session.vim .project .favorites.json .settings/ +.vs/ ## Tool .valgrindrc diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index e02c7e6c01b7e..6eb01085ae73e 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_expand::base::*; use rustc_session::Session; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{FileNameDisplayPreference, Span}; use std::iter; use thin_vec::{thin_vec, ThinVec}; @@ -231,6 +231,8 @@ pub fn expand_test_or_bench( &item.ident, )); + let location_info = get_location_info(cx, &item); + let mut test_const = cx.item( sp, Ident::new(item.ident.name, sp), @@ -280,6 +282,16 @@ pub fn expand_test_or_bench( cx.expr_none(sp) }, ), + // source_file: + field("source_file", cx.expr_str(sp, location_info.0)), + // start_line: start line of the test fn identifier. + field("start_line", cx.expr_usize(sp, location_info.1)), + // start_col: start column of the test fn identifier. + field("start_col", cx.expr_usize(sp, location_info.2)), + // end_line: end line of the test fn identifier. + field("end_line", cx.expr_usize(sp, location_info.3)), + // end_col: end column of the test fn identifier. + field("end_col", cx.expr_usize(sp, location_info.4)), // compile_fail: true | false field("compile_fail", cx.expr_bool(sp, false)), // no_run: true | false @@ -364,6 +376,19 @@ pub fn expand_test_or_bench( } } +fn get_location_info(cx: &ExtCtxt<'_>, item: &ast::Item) -> (Symbol, usize, usize, usize, usize) { + let span = item.ident.span; + let (source_file, lo_line, lo_col, hi_line, hi_col) = + cx.sess.source_map().span_to_location_info(span); + + let file_name = match source_file { + Some(sf) => sf.name.display(FileNameDisplayPreference::Local).to_string(), + None => "no-location".to_string(), + }; + + (Symbol::intern(&file_name), lo_line, lo_col, hi_line, hi_col) +} + fn item_path(mod_path: &[Ident], item_ident: &Ident) -> String { mod_path .iter() diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 2e339a9d2d2b0..cca9359141c68 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -443,25 +443,36 @@ impl SourceMap { sp: Span, filename_display_pref: FileNameDisplayPreference, ) -> String { - if self.files.borrow().source_files.is_empty() || sp.is_dummy() { - return "no-location".to_string(); - } + let (source_file, lo_line, lo_col, hi_line, hi_col) = self.span_to_location_info(sp); + + let file_name = match source_file { + Some(sf) => sf.name.display(filename_display_pref).to_string(), + None => return "no-location".to_string(), + }; - let lo = self.lookup_char_pos(sp.lo()); - let hi = self.lookup_char_pos(sp.hi()); format!( - "{}:{}:{}{}", - lo.file.name.display(filename_display_pref), - lo.line, - lo.col.to_usize() + 1, + "{file_name}:{lo_line}:{lo_col}{}", if let FileNameDisplayPreference::Short = filename_display_pref { String::new() } else { - format!(": {}:{}", hi.line, hi.col.to_usize() + 1) + format!(": {hi_line}:{hi_col}") } ) } + pub fn span_to_location_info( + &self, + sp: Span, + ) -> (Option>, usize, usize, usize, usize) { + if self.files.borrow().source_files.is_empty() || sp.is_dummy() { + return (None, 0, 0, 0, 0); + } + + let lo = self.lookup_char_pos(sp.lo()); + let hi = self.lookup_char_pos(sp.hi()); + (Some(lo.file), lo.line, lo.col.to_usize() + 1, hi.line, hi.col.to_usize() + 1) + } + /// Format the span location suitable for embedding in build artifacts pub fn span_to_embeddable_string(&self, sp: Span) -> String { self.span_to_string(sp, FileNameDisplayPreference::Remapped) diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 1ee68c8540bcc..7eee4ca236190 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -41,6 +41,46 @@ impl Write for OutputLocation { } } +pub struct ConsoleTestDiscoveryState { + pub log_out: Option, + pub tests: usize, + pub benchmarks: usize, + pub ignored: usize, + pub options: Options, +} + +impl ConsoleTestDiscoveryState { + pub fn new(opts: &TestOpts) -> io::Result { + let log_out = match opts.logfile { + Some(ref path) => Some(File::create(path)?), + None => None, + }; + + Ok(ConsoleTestDiscoveryState { + log_out, + tests: 0, + benchmarks: 0, + ignored: 0, + options: opts.options, + }) + } + + pub fn write_log(&mut self, msg: F) -> io::Result<()> + where + S: AsRef, + F: FnOnce() -> S, + { + match self.log_out { + None => Ok(()), + Some(ref mut o) => { + let msg = msg(); + let msg = msg.as_ref(); + o.write_all(msg.as_bytes()) + } + } + } +} + pub struct ConsoleTestState { pub log_out: Option, pub total: usize, @@ -138,53 +178,44 @@ impl ConsoleTestState { // List the tests to console, and optionally to logfile. Filters are honored. pub fn list_tests_console(opts: &TestOpts, tests: Vec) -> io::Result<()> { - let mut output = match term::stdout() { + let output = match term::stdout() { None => OutputLocation::Raw(io::stdout().lock()), Some(t) => OutputLocation::Pretty(t), }; - let quiet = opts.format == OutputFormat::Terse; - let mut st = ConsoleTestState::new(opts)?; - - let mut ntest = 0; - let mut nbench = 0; + let mut out: Box = match opts.format { + OutputFormat::Pretty | OutputFormat::Junit => { + Box::new(PrettyFormatter::new(output, false, 0, false, None)) + } + OutputFormat::Terse => Box::new(TerseFormatter::new(output, false, 0, false)), + OutputFormat::Json => Box::new(JsonFormatter::new(output)), + }; + let mut st = ConsoleTestDiscoveryState::new(opts)?; + out.write_discovery_start()?; for test in filter_tests(opts, tests).into_iter() { use crate::TestFn::*; - let TestDescAndFn { desc: TestDesc { name, .. }, testfn } = test; + let TestDescAndFn { desc, testfn } = test; let fntype = match testfn { StaticTestFn(..) | DynTestFn(..) => { - ntest += 1; + st.tests += 1; "test" } StaticBenchFn(..) | DynBenchFn(..) => { - nbench += 1; + st.benchmarks += 1; "benchmark" } }; - writeln!(output, "{name}: {fntype}")?; - st.write_log(|| format!("{fntype} {name}\n"))?; - } + st.ignored += if desc.ignore { 1 } else { 0 }; - fn plural(count: u32, s: &str) -> String { - match count { - 1 => format!("1 {s}"), - n => format!("{n} {s}s"), - } + out.write_test_discovered(&desc, fntype)?; + st.write_log(|| format!("{fntype} {}\n", desc.name))?; } - if !quiet { - if ntest != 0 || nbench != 0 { - writeln!(output)?; - } - - writeln!(output, "{}, {}", plural(ntest, "test"), plural(nbench, "benchmark"))?; - } - - Ok(()) + out.write_discovery_finish(&st) } // Updates `ConsoleTestState` depending on result of the test execution. diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs index 95d2faf25060f..40976ec5e1c8b 100644 --- a/library/test/src/formatters/json.rs +++ b/library/test/src/formatters/json.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, io, io::prelude::Write}; use super::OutputFormatter; use crate::{ - console::{ConsoleTestState, OutputLocation}, + console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation}, test_result::TestResult, time, types::TestDesc, @@ -60,6 +60,56 @@ impl JsonFormatter { } impl OutputFormatter for JsonFormatter { + fn write_discovery_start(&mut self) -> io::Result<()> { + self.writeln_message(&format!(r#"{{ "type": "suite", "event": "discovery" }}"#)) + } + + fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> { + let TestDesc { + name, + ignore, + ignore_message, + #[cfg(not(bootstrap))] + source_file, + #[cfg(not(bootstrap))] + start_line, + #[cfg(not(bootstrap))] + start_col, + #[cfg(not(bootstrap))] + end_line, + #[cfg(not(bootstrap))] + end_col, + .. + } = desc; + + #[cfg(bootstrap)] + let source_file = ""; + #[cfg(bootstrap)] + let start_line = 0; + #[cfg(bootstrap)] + let start_col = 0; + #[cfg(bootstrap)] + let end_line = 0; + #[cfg(bootstrap)] + let end_col = 0; + + self.writeln_message(&format!( + r#"{{ "type": "{test_type}", "event": "discovered", "name": "{}", "ignore": {ignore}, "ignore_message": "{}", "source_path": "{}", "start_line": {start_line}, "start_col": {start_col}, "end_line": {end_line}, "end_col": {end_col} }}"#, + EscapedString(name.as_slice()), + ignore_message.unwrap_or(""), + EscapedString(source_file), + )) + } + + fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()> { + let ConsoleTestDiscoveryState { tests, benchmarks, ignored, .. } = state; + + let total = tests + benchmarks; + self.writeln_message(&format!( + r#"{{ "type": "suite", "event": "completed", "tests": {tests}, "benchmarks": {benchmarks}, "total": {total}, "ignored": {ignored} }}"# + )) + } + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option) -> io::Result<()> { let shuffle_seed_json = if let Some(shuffle_seed) = shuffle_seed { format!(r#", "shuffle_seed": {shuffle_seed}"#) diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs index 7a40ce33cb741..2e07ce3c09923 100644 --- a/library/test/src/formatters/junit.rs +++ b/library/test/src/formatters/junit.rs @@ -3,7 +3,7 @@ use std::time::Duration; use super::OutputFormatter; use crate::{ - console::{ConsoleTestState, OutputLocation}, + console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation}, test_result::TestResult, time, types::{TestDesc, TestType}, @@ -27,6 +27,18 @@ impl JunitFormatter { } impl OutputFormatter for JunitFormatter { + fn write_discovery_start(&mut self) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!")) + } + + fn write_test_discovered(&mut self, _desc: &TestDesc, _test_type: &str) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!")) + } + + fn write_discovery_finish(&mut self, _state: &ConsoleTestDiscoveryState) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!")) + } + fn write_run_start( &mut self, _test_count: usize, diff --git a/library/test/src/formatters/mod.rs b/library/test/src/formatters/mod.rs index cb67b6491a392..bc6ffebc1d3b2 100644 --- a/library/test/src/formatters/mod.rs +++ b/library/test/src/formatters/mod.rs @@ -1,7 +1,7 @@ use std::{io, io::prelude::Write}; use crate::{ - console::ConsoleTestState, + console::{ConsoleTestDiscoveryState, ConsoleTestState}, test_result::TestResult, time, types::{TestDesc, TestName}, @@ -18,6 +18,10 @@ pub(crate) use self::pretty::PrettyFormatter; pub(crate) use self::terse::TerseFormatter; pub(crate) trait OutputFormatter { + fn write_discovery_start(&mut self) -> io::Result<()>; + fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()>; + fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()>; + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option) -> io::Result<()>; fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()>; fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>; diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs index 247778e515f0d..22654a3400b44 100644 --- a/library/test/src/formatters/pretty.rs +++ b/library/test/src/formatters/pretty.rs @@ -3,7 +3,7 @@ use std::{io, io::prelude::Write}; use super::OutputFormatter; use crate::{ bench::fmt_bench_samples, - console::{ConsoleTestState, OutputLocation}, + console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation}, term, test_result::TestResult, time, @@ -181,6 +181,33 @@ impl PrettyFormatter { } impl OutputFormatter for PrettyFormatter { + fn write_discovery_start(&mut self) -> io::Result<()> { + Ok(()) + } + + fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> { + self.write_plain(format!("{}: {test_type}\n", desc.name)) + } + + fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()> { + fn plural(count: usize, s: &str) -> String { + match count { + 1 => format!("1 {s}"), + n => format!("{n} {s}s"), + } + } + + if state.tests != 0 || state.benchmarks != 0 { + self.write_plain("\n")?; + } + + self.write_plain(format!( + "{}, {}\n", + plural(state.tests, "test"), + plural(state.benchmarks, "benchmark") + )) + } + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option) -> io::Result<()> { let noun = if test_count != 1 { "tests" } else { "test" }; let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed { diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs index a431acfbc2753..2931ca6ead0ac 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -3,7 +3,7 @@ use std::{io, io::prelude::Write}; use super::OutputFormatter; use crate::{ bench::fmt_bench_samples, - console::{ConsoleTestState, OutputLocation}, + console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation}, term, test_result::TestResult, time, @@ -167,6 +167,18 @@ impl TerseFormatter { } impl OutputFormatter for TerseFormatter { + fn write_discovery_start(&mut self) -> io::Result<()> { + Ok(()) + } + + fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> { + self.write_plain(format!("{}: {test_type}\n", desc.name)) + } + + fn write_discovery_finish(&mut self, _state: &ConsoleTestDiscoveryState) -> io::Result<()> { + Ok(()) + } + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option) -> io::Result<()> { self.total_test_count = test_count; let noun = if test_count != 1 { "tests" } else { "test" }; diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 44776fb0a316d..5ffdbf73fbf93 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -63,6 +63,16 @@ fn one_ignored_one_unignored_test() -> Vec { name: StaticTestName("1"), ignore: true, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -75,6 +85,16 @@ fn one_ignored_one_unignored_test() -> Vec { name: StaticTestName("2"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -95,6 +115,16 @@ pub fn do_not_run_ignored_tests() { name: StaticTestName("whatever"), ignore: true, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -118,6 +148,16 @@ pub fn ignored_tests_result_in_ignored() { name: StaticTestName("whatever"), ignore: true, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -143,6 +183,16 @@ fn test_should_panic() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::Yes, compile_fail: false, no_run: false, @@ -168,6 +218,16 @@ fn test_should_panic_good_message() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::YesWithMessage("error message"), compile_fail: false, no_run: false, @@ -198,6 +258,16 @@ fn test_should_panic_bad_message() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::YesWithMessage(expected), compile_fail: false, no_run: false, @@ -232,6 +302,16 @@ fn test_should_panic_non_string_message_type() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::YesWithMessage(expected), compile_fail: false, no_run: false, @@ -260,6 +340,16 @@ fn test_should_panic_but_succeeds() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic, compile_fail: false, no_run: false, @@ -288,6 +378,16 @@ fn report_time_test_template(report_time: bool) -> Option { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -325,6 +425,16 @@ fn time_test_failure_template(test_type: TestType) -> TestResult { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -364,6 +474,16 @@ fn typed_test_desc(test_type: TestType) -> TestDesc { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -476,6 +596,16 @@ pub fn exclude_should_panic_option() { name: StaticTestName("3"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::Yes, compile_fail: false, no_run: false, @@ -500,6 +630,16 @@ pub fn exact_filter_match() { name: StaticTestName(name), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -591,6 +731,16 @@ fn sample_tests() -> Vec { name: DynTestName((*name).clone()), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -720,6 +870,16 @@ pub fn test_bench_no_iter() { name: StaticTestName("f"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -743,6 +903,16 @@ pub fn test_bench_iter() { name: StaticTestName("f"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -759,6 +929,16 @@ fn should_sort_failures_before_printing_them() { name: StaticTestName("a"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -769,6 +949,16 @@ fn should_sort_failures_before_printing_them() { name: StaticTestName("b"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -816,6 +1006,16 @@ fn test_dyn_bench_returning_err_fails_when_run_as_test() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, diff --git a/library/test/src/types.rs b/library/test/src/types.rs index 6f2e033095a37..8d4e204c8ac12 100644 --- a/library/test/src/types.rs +++ b/library/test/src/types.rs @@ -119,6 +119,16 @@ pub struct TestDesc { pub name: TestName, pub ignore: bool, pub ignore_message: Option<&'static str>, + #[cfg(not(bootstrap))] + pub source_file: &'static str, + #[cfg(not(bootstrap))] + pub start_line: usize, + #[cfg(not(bootstrap))] + pub start_col: usize, + #[cfg(not(bootstrap))] + pub end_line: usize, + #[cfg(not(bootstrap))] + pub end_col: usize, pub should_panic: options::ShouldPanic, pub compile_fail: bool, pub no_run: bool, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 9cf84acc79f8d..aaa83ecce4817 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1057,6 +1057,16 @@ impl Tester for Collector { Ignore::Some(ref ignores) => ignores.iter().any(|s| target_str.contains(s)), }, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, // compiler failures are test failures should_panic: test::ShouldPanic::No, compile_fail: config.compile_fail, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index d9b39927ca4bc..22a0b1d13be16 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -1047,6 +1047,16 @@ pub fn make_test_description( name, ignore, ignore_message, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic, compile_fail: false, no_run: false, diff --git a/tests/pretty/tests-are-sorted.pp b/tests/pretty/tests-are-sorted.pp index 15dcd4ed97df4..b58bad35104ec 100644 --- a/tests/pretty/tests-are-sorted.pp +++ b/tests/pretty/tests-are-sorted.pp @@ -18,6 +18,11 @@ name: test::StaticTestName("m_test"), ignore: false, ignore_message: ::core::option::Option::None, + source_file: "/checkout/tests/pretty/tests-are-sorted.rs", + start_line: 7usize, + start_col: 4usize, + end_line: 7usize, + end_col: 10usize, compile_fail: false, no_run: false, should_panic: test::ShouldPanic::No, @@ -34,8 +39,13 @@ test::TestDescAndFn { desc: test::TestDesc { name: test::StaticTestName("z_test"), - ignore: false, - ignore_message: ::core::option::Option::None, + ignore: true, + ignore_message: ::core::option::Option::Some("not yet implemented"), + source_file: "/checkout/tests/pretty/tests-are-sorted.rs", + start_line: 11usize, + start_col: 4usize, + end_line: 11usize, + end_col: 10usize, compile_fail: false, no_run: false, should_panic: test::ShouldPanic::No, @@ -43,6 +53,7 @@ }, testfn: test::StaticTestFn(|| test::assert_test_result(z_test())), }; +#[ignore = "not yet implemented"] fn z_test() {} extern crate test; @@ -54,6 +65,11 @@ name: test::StaticTestName("a_test"), ignore: false, ignore_message: ::core::option::Option::None, + source_file: "/checkout/tests/pretty/tests-are-sorted.rs", + start_line: 14usize, + start_col: 4usize, + end_line: 14usize, + end_col: 10usize, compile_fail: false, no_run: false, should_panic: test::ShouldPanic::No, diff --git a/tests/pretty/tests-are-sorted.rs b/tests/pretty/tests-are-sorted.rs index 1f737d5471930..0899b820f269f 100644 --- a/tests/pretty/tests-are-sorted.rs +++ b/tests/pretty/tests-are-sorted.rs @@ -7,6 +7,7 @@ fn m_test() {} #[test] +#[ignore = "not yet implemented"] fn z_test() {} #[test] diff --git a/tests/ui/test-attrs/tests-listing-format-default.rs b/tests/ui/test-attrs/tests-listing-format-default.rs new file mode 100644 index 0000000000000..d5df4b57b0591 --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-default.rs @@ -0,0 +1,18 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --list +// run-pass +// check-run-results + +// Checks the listing of tests with no --format arguments. + +#![cfg(test)] +#[test] +fn m_test() {} + +#[test] +#[ignore = "not yet implemented"] +fn z_test() {} + +#[test] +fn a_test() {} diff --git a/tests/ui/test-attrs/tests-listing-format-default.run.stdout b/tests/ui/test-attrs/tests-listing-format-default.run.stdout new file mode 100644 index 0000000000000..72337daf02cdf --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-default.run.stdout @@ -0,0 +1,5 @@ +a_test: test +m_test: test +z_test: test + +3 tests, 0 benchmarks diff --git a/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs new file mode 100644 index 0000000000000..5247f1f8f1746 --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs @@ -0,0 +1,18 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --list --format json +// run-fail +// check-run-results + +// Checks that --format json does not work without -Zunstable-options. + +#![cfg(test)] +#[test] +fn m_test() {} + +#[test] +#[ignore = "not yet implemented"] +fn z_test() {} + +#[test] +fn a_test() {} diff --git a/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr new file mode 100644 index 0000000000000..9f6276300a0bd --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr @@ -0,0 +1 @@ +error: The "json" format is only accepted on the nightly compiler diff --git a/tests/ui/test-attrs/tests-listing-format-json.rs b/tests/ui/test-attrs/tests-listing-format-json.rs new file mode 100644 index 0000000000000..24c87d551584f --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-json.rs @@ -0,0 +1,18 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --list --format json -Zunstable-options +// run-pass +// check-run-results + +// Checks the listing of tests with --format json. + +#![cfg(test)] +#[test] +fn m_test() {} + +#[test] +#[ignore = "not yet implemented"] +fn z_test() {} + +#[test] +fn a_test() {} diff --git a/tests/ui/test-attrs/tests-listing-format-json.run.stdout b/tests/ui/test-attrs/tests-listing-format-json.run.stdout new file mode 100644 index 0000000000000..b97a031bae4bd --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-json.run.stdout @@ -0,0 +1,5 @@ +{ "type": "suite", "event": "discovery" } +{ "type": "test", "event": "discovered", "name": "a_test", "ignore": false, "ignore_message": "", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 18, "start_col": 4, "end_line": 18, "end_col": 10 } +{ "type": "test", "event": "discovered", "name": "m_test", "ignore": false, "ignore_message": "", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 11, "start_col": 4, "end_line": 11, "end_col": 10 } +{ "type": "test", "event": "discovered", "name": "z_test", "ignore": true, "ignore_message": "not yet implemented", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 15, "start_col": 4, "end_line": 15, "end_col": 10 } +{ "type": "suite", "event": "completed", "tests": 3, "benchmarks": 0, "total": 3, "ignored": 1 } diff --git a/tests/ui/test-attrs/tests-listing-format-terse.rs b/tests/ui/test-attrs/tests-listing-format-terse.rs new file mode 100644 index 0000000000000..7835f71759cb4 --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-terse.rs @@ -0,0 +1,18 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --list --format terse +// run-pass +// check-run-results + +// Checks the listing of tests with --format terse. + +#![cfg(test)] +#[test] +fn m_test() {} + +#[test] +#[ignore = "not yet implemented"] +fn z_test() {} + +#[test] +fn a_test() {} diff --git a/tests/ui/test-attrs/tests-listing-format-terse.run.stdout b/tests/ui/test-attrs/tests-listing-format-terse.run.stdout new file mode 100644 index 0000000000000..22afe104bfb1d --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-terse.run.stdout @@ -0,0 +1,3 @@ +a_test: test +m_test: test +z_test: test From 057d6ed1470730554d4380cde316a987ade97022 Mon Sep 17 00:00:00 2001 From: Kazu Hirata Date: Tue, 7 Mar 2023 22:40:14 -0800 Subject: [PATCH 11/15] Remove an extraneous include SymbolWrapper.cpp doesn't use std::optional or llvm::Optional, so this patch removes the extraneous include. Note that llvm/ADT/Optional.h has been deprecated upstream. This patch ensures that SymbolWrapper.cpp continues to compile even after the upcoming removal of Optional.h. --- compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp index 974207e918cd6..0493d6b05d030 100644 --- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp @@ -9,7 +9,6 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/ADT/Optional.h" using namespace llvm; using namespace llvm::sys; From a5258d17216d122bfc27f4aad316689f8d29a62a Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 9 Mar 2023 12:53:03 +0100 Subject: [PATCH 12/15] no more do while --- .../rustc_mir_build/src/build/matches/mod.rs | 8 ++-- .../rustc_mir_transform/src/coverage/graph.rs | 40 +++++++++---------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index de2851a1af9fd..2984dfa735e0a 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -581,8 +581,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // let PATTERN = ... might not even exist until we do the assignment. // so we set it here instead. if set_match_place { - let mut candidate_ref = &candidate; - while let Some(next) = { + let mut next = Some(&candidate); + while let Some(candidate_ref) = next.take() { for binding in &candidate_ref.bindings { let local = self.var_local_id(binding.var_id, OutsideGuard); // `try_to_place` may fail if it is unable to resolve the given @@ -610,9 +610,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } // All of the subcandidates should bind the same locals, so we // only visit the first one. - candidate_ref.subcandidates.get(0) - } { - candidate_ref = next; + next = candidate_ref.subcandidates.get(0) } } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index a2671eef2e940..87cac7702dc50 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -538,29 +538,29 @@ impl TraverseCoverageGraphWithLoops { "TraverseCoverageGraphWithLoops::next - context_stack: {:?}", self.context_stack.iter().rev().collect::>() ); - while let Some(next_bcb) = { - // Strip contexts with empty worklists from the top of the stack - while self.context_stack.last().map_or(false, |context| context.worklist.is_empty()) { + + while let Some(context) = self.context_stack.last_mut() { + if let Some(next_bcb) = context.worklist.pop() { + if !self.visited.insert(next_bcb) { + debug!("Already visited: {:?}", next_bcb); + continue; + } + debug!("Visiting {:?}", next_bcb); + if self.backedges[next_bcb].len() > 0 { + debug!("{:?} is a loop header! Start a new TraversalContext...", next_bcb); + self.context_stack.push(TraversalContext { + loop_backedges: Some((self.backedges[next_bcb].clone(), next_bcb)), + worklist: Vec::new(), + }); + } + self.extend_worklist(basic_coverage_blocks, next_bcb); + return Some(next_bcb); + } else { + // Strip contexts with empty worklists from the top of the stack self.context_stack.pop(); } - // Pop the next bcb off of the current context_stack. If none, all BCBs were visited. - self.context_stack.last_mut().map_or(None, |context| context.worklist.pop()) - } { - if !self.visited.insert(next_bcb) { - debug!("Already visited: {:?}", next_bcb); - continue; - } - debug!("Visiting {:?}", next_bcb); - if self.backedges[next_bcb].len() > 0 { - debug!("{:?} is a loop header! Start a new TraversalContext...", next_bcb); - self.context_stack.push(TraversalContext { - loop_backedges: Some((self.backedges[next_bcb].clone(), next_bcb)), - worklist: Vec::new(), - }); - } - self.extend_worklist(basic_coverage_blocks, next_bcb); - return Some(next_bcb); } + None } From 3abcae2beb1bc8d2ef1d92fd74fdd6ca4aeb1173 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Wed, 8 Mar 2023 16:55:28 +0000 Subject: [PATCH 13/15] Document tool lints --- compiler/rustc_lint/src/internal.rs | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 2fd0ef3cda8b7..a14dc20fca369 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -17,6 +17,11 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; declare_tool_lint! { + /// The `default_hash_type` lint detects use of [`std::collections::HashMap`]/[`std::collections::HashSet`], + /// suggesting the use of `FxHashMap`/`FxHashSet`. + /// + /// This can help as `FxHasher` can perform better than the default hasher. DOS protection is not + /// required as input is assumed to be trusted. pub rustc::DEFAULT_HASH_TYPES, Allow, "forbid HashMap and HashSet and suggest the FxHash* variants", @@ -67,6 +72,12 @@ fn typeck_results_of_method_fn<'tcx>( } declare_tool_lint! { + /// The `potential_query_instability` lint detects use of methods which can lead to + /// potential query instability, such as iterating over a `HashMap`. + /// + /// Due to the [incremental compilation](https://rustc-dev-guide.rust-lang.org/queries/incremental-compilation.html) model, + /// queries must return deterministic, stable results. `HashMap` iteration order can change between compilations, + /// and will introduce instability if query results expose the order. pub rustc::POTENTIAL_QUERY_INSTABILITY, Allow, "require explicit opt-in when using potentially unstable methods or functions", @@ -92,6 +103,8 @@ impl LateLintPass<'_> for QueryStability { } declare_tool_lint! { + /// The `usage_of_ty_tykind` lint detects usages of `ty::TyKind::`, + /// where `ty::` would suffice. pub rustc::USAGE_OF_TY_TYKIND, Allow, "usage of `ty::TyKind` outside of the `ty::sty` module", @@ -99,6 +112,8 @@ declare_tool_lint! { } declare_tool_lint! { + /// The `usage_of_qualified_ty` lint detects usages of `ty::TyKind`, + /// where `Ty` should be used instead. pub rustc::USAGE_OF_QUALIFIED_TY, Allow, "using `ty::{Ty,TyCtxt}` instead of importing it", @@ -254,6 +269,8 @@ fn gen_args(segment: &PathSegment<'_>) -> String { } declare_tool_lint! { + /// The `lint_pass_impl_without_macro` detects manual implementations of a lint + /// pass, without using [`declare_lint_pass`] or [`impl_lint_pass`]. pub rustc::LINT_PASS_IMPL_WITHOUT_MACRO, Allow, "`impl LintPass` without the `declare_lint_pass!` or `impl_lint_pass!` macros" @@ -285,6 +302,8 @@ impl EarlyLintPass for LintPassImpl { } declare_tool_lint! { + /// The `existing_doc_keyword` lint detects use `#[doc()]` keywords + /// that don't exist, e.g. `#[doc(keyword = "..")]`. pub rustc::EXISTING_DOC_KEYWORD, Allow, "Check that documented keywords in std and core actually exist", @@ -325,6 +344,10 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { } declare_tool_lint! { + /// The `untranslatable_diagnostic` lint detects diagnostics created + /// without using translatable Fluent strings. + /// + /// More details on translatable diagnostics can be found [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html). pub rustc::UNTRANSLATABLE_DIAGNOSTIC, Allow, "prevent creation of diagnostics which cannot be translated", @@ -332,6 +355,11 @@ declare_tool_lint! { } declare_tool_lint! { + /// The `diagnostic_outside_of_impl` lint detects diagnostics created manually, + /// and inside an `IntoDiagnostic`/`AddToDiagnostic` implementation, + /// or a `#[derive(Diagnostic)]`/`#[derive(Subdiagnostic)]` expansion. + /// + /// More details on diagnostics implementations can be found [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html). pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL, Allow, "prevent creation of diagnostics outside of `IntoDiagnostic`/`AddToDiagnostic` impls", @@ -396,6 +424,8 @@ impl LateLintPass<'_> for Diagnostics { } declare_tool_lint! { + /// The `bad_opt_access` lint detects accessing options by field instad of + /// the wrapper function. pub rustc::BAD_OPT_ACCESS, Deny, "prevent using options by field access when there is a wrapper function", From 9bb87eb68187b3b3bbd4ed327706ba31a772a4f2 Mon Sep 17 00:00:00 2001 From: Collin Baker Date: Mon, 13 Feb 2023 18:36:38 -0500 Subject: [PATCH 14/15] Add soon-to-be-default --no-undefined-version flag --- compiler/rustc_codegen_ssa/src/back/linker.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 52c01b423a7d5..23e2b272410e6 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -720,6 +720,7 @@ impl<'a> Linker for GccLinker<'a> { let mut arg = OsString::from("--version-script="); arg.push(path); self.linker_arg(arg); + self.linker_arg("--no-undefined-version"); } } } From cb41803899ae6531ea2e8fd236f67663e7815ae3 Mon Sep 17 00:00:00 2001 From: Collin Baker Date: Mon, 13 Feb 2023 18:48:06 -0500 Subject: [PATCH 15/15] Don't export of __rust_* alloc symbols if not codegened --- .../rustc_codegen_cranelift/src/allocator.rs | 28 +++++------- .../src/back/symbol_export.rs | 5 ++- compiler/rustc_codegen_ssa/src/base.rs | 44 ++++++++++--------- 3 files changed, 37 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index 1c73957ca571c..2c246ceb37d54 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -4,6 +4,7 @@ use crate::prelude::*; use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; +use rustc_codegen_ssa::base::allocator_kind_for_codegen; use rustc_session::config::OomStrategy; use rustc_span::symbol::sym; @@ -13,24 +14,15 @@ pub(crate) fn codegen( module: &mut impl Module, unwind_context: &mut UnwindContext, ) -> bool { - let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| { - use rustc_middle::middle::dependency_format::Linkage; - list.iter().any(|&linkage| linkage == Linkage::Dynamic) - }); - if any_dynamic_crate { - false - } else if let Some(kind) = tcx.allocator_kind(()) { - codegen_inner( - module, - unwind_context, - kind, - tcx.alloc_error_handler_kind(()).unwrap(), - tcx.sess.opts.unstable_opts.oom, - ); - true - } else { - false - } + let Some(kind) = allocator_kind_for_codegen(tcx) else { return false }; + codegen_inner( + module, + unwind_context, + kind, + tcx.alloc_error_handler_kind(()).unwrap(), + tcx.sess.opts.unstable_opts.oom, + ); + true } fn codegen_inner( diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 1a94d4ab8b1d8..7b58e55dbe84a 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -1,3 +1,5 @@ +use crate::base::allocator_kind_for_codegen; + use std::collections::hash_map::Entry::*; use rustc_ast::expand::allocator::ALLOCATOR_METHODS; @@ -200,7 +202,8 @@ fn exported_symbols_provider_local( )); } - if tcx.allocator_kind(()).is_some() { + // Mark allocator shim symbols as exported only if they were generated. + if allocator_kind_for_codegen(tcx).is_some() { for symbol_name in ALLOCATOR_METHODS .iter() .map(|method| format!("__rust_{}", method.name)) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 73179249bc4d8..abc510e360d56 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -13,6 +13,7 @@ use crate::mir::place::PlaceRef; use crate::traits::*; use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind}; +use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; @@ -545,6 +546,23 @@ pub fn collect_debugger_visualizers_transitive( .collect::>() } +/// Decide allocator kind to codegen. If `Some(_)` this will be the same as +/// `tcx.allocator_kind`, but it may be `None` in more cases (e.g. if using +/// allocator definitions from a dylib dependency). +pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option { + // If the crate doesn't have an `allocator_kind` set then there's definitely + // no shim to generate. Otherwise we also check our dependency graph for all + // our output crate types. If anything there looks like its a `Dynamic` + // linkage, then it's already got an allocator shim and we'll be using that + // one instead. If nothing exists then it's our job to generate the + // allocator! + let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| { + use rustc_middle::middle::dependency_format::Linkage; + list.iter().any(|&linkage| linkage == Linkage::Dynamic) + }); + if any_dynamic_crate { None } else { tcx.allocator_kind(()) } +} + pub fn codegen_crate( backend: B, tcx: TyCtxt<'_>, @@ -615,20 +633,7 @@ pub fn codegen_crate( ); // Codegen an allocator shim, if necessary. - // - // If the crate doesn't have an `allocator_kind` set then there's definitely - // no shim to generate. Otherwise we also check our dependency graph for all - // our output crate types. If anything there looks like its a `Dynamic` - // linkage, then it's already got an allocator shim and we'll be using that - // one instead. If nothing exists then it's our job to generate the - // allocator! - let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| { - use rustc_middle::middle::dependency_format::Linkage; - list.iter().any(|&linkage| linkage == Linkage::Dynamic) - }); - let allocator_module = if any_dynamic_crate { - None - } else if let Some(kind) = tcx.allocator_kind(()) { + if let Some(kind) = allocator_kind_for_codegen(tcx) { let llmod_id = cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string(); let module_llvm = tcx.sess.time("write_allocator_module", || { @@ -642,13 +647,10 @@ pub fn codegen_crate( ) }); - Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator }) - } else { - None - }; - - if let Some(allocator_module) = allocator_module { - ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module); + ongoing_codegen.submit_pre_codegened_module_to_llvm( + tcx, + ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator }, + ); } // For better throughput during parallel processing by LLVM, we used to sort