From 52f7a218fb496aefb2364ccc508556c45df47e7f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 16 Dec 2022 04:20:34 +0000 Subject: [PATCH 01/26] 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 be3452a02f7006f50acca2b89e04a9bb710ad652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 3 Feb 2023 08:05:59 +0100 Subject: [PATCH 02/26] Test that TLS access works outside of the dylib it's defined in --- tests/ui/auxiliary/tls-export.rs | 13 +++++++++++++ tests/ui/tls-dylib-access.rs | 13 +++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/ui/auxiliary/tls-export.rs create mode 100644 tests/ui/tls-dylib-access.rs diff --git a/tests/ui/auxiliary/tls-export.rs b/tests/ui/auxiliary/tls-export.rs new file mode 100644 index 0000000000000..f02faaa4c26d7 --- /dev/null +++ b/tests/ui/auxiliary/tls-export.rs @@ -0,0 +1,13 @@ +#![crate_type = "dylib"] +#![feature(thread_local)] +#![feature(cfg_target_thread_local)] + +#[cfg(target_thread_local)] +#[thread_local] +pub static FOO: bool = true; + +#[cfg(target_thread_local)] +#[inline(never)] +pub fn foo_addr() -> usize { + &FOO as *const bool as usize +} diff --git a/tests/ui/tls-dylib-access.rs b/tests/ui/tls-dylib-access.rs new file mode 100644 index 0000000000000..1ee8cf2f7247d --- /dev/null +++ b/tests/ui/tls-dylib-access.rs @@ -0,0 +1,13 @@ +// aux-build: tls-export.rs +// run-pass + +#![feature(cfg_target_thread_local)] + +#[cfg(target_thread_local)] +extern crate tls_export; + +fn main() { + // Check that we get the real address of the TLS in the dylib + #[cfg(target_thread_local)] + assert_eq!(&tls_export::FOO as *const bool as usize, tls_export::foo_addr()); +} From 34c87080edee005f80775d895b629082b5c187cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 3 Feb 2023 09:04:12 +0100 Subject: [PATCH 03/26] Support TLS access into dylibs on Windows --- .../src/back/symbol_export.rs | 40 +++++- compiler/rustc_codegen_ssa/src/mir/block.rs | 71 ++++++++--- compiler/rustc_codegen_ssa/src/mir/mod.rs | 120 +++++++++++++++++- .../src/interpret/terminator.rs | 1 + .../src/rmeta/decoder/cstore_impl.rs | 12 ++ .../src/middle/exported_symbols.rs | 5 + compiler/rustc_middle/src/mir/mono.rs | 1 + compiler/rustc_middle/src/mir/visit.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 4 + compiler/rustc_middle/src/ty/instance.rs | 16 ++- compiler/rustc_middle/src/ty/mod.rs | 1 + compiler/rustc_mir_transform/src/inline.rs | 1 + .../rustc_mir_transform/src/inline/cycle.rs | 1 + compiler/rustc_mir_transform/src/shim.rs | 31 +++++ compiler/rustc_monomorphize/src/collector.rs | 24 +++- .../src/partitioning/default.rs | 10 ++ compiler/rustc_symbol_mangling/src/legacy.rs | 4 + compiler/rustc_symbol_mangling/src/v0.rs | 1 + compiler/rustc_target/src/spec/mod.rs | 5 + compiler/rustc_target/src/spec/msvc_base.rs | 1 + .../rustc_target/src/spec/windows_gnu_base.rs | 1 + .../src/spec/windows_gnullvm_base.rs | 1 + compiler/rustc_ty_utils/src/abi.rs | 16 ++- 23 files changed, 333 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 11bd47a8f0c79..c465fd43f2962 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -178,14 +178,29 @@ fn exported_symbols_provider_local( // FIXME: Sorting this is unnecessary since we are sorting later anyway. // Can we skip the later sorting? - let mut symbols: Vec<_> = tcx.with_stable_hashing_context(|hcx| { - tcx.reachable_non_generics(LOCAL_CRATE) - .to_sorted(&hcx, true) - .into_iter() - .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)) - .collect() + let sorted = tcx.with_stable_hashing_context(|hcx| { + tcx.reachable_non_generics(LOCAL_CRATE).to_sorted(&hcx, true) }); + let mut symbols: Vec<_> = + sorted.iter().map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)).collect(); + + // Export TLS shims + if !tcx.sess.target.dll_tls_export { + symbols.extend(sorted.iter().filter_map(|(&def_id, &info)| { + tcx.is_thread_local_static(def_id).then(|| { + ( + ExportedSymbol::ThreadLocalShim(def_id), + SymbolExportInfo { + level: info.level, + kind: SymbolExportKind::Text, + used: info.used, + }, + ) + }) + })) + } + if tcx.entry_fn(()).is_some() { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref())); @@ -380,7 +395,9 @@ fn upstream_monomorphizations_provider( continue; } } - ExportedSymbol::NonGeneric(..) | ExportedSymbol::NoDefId(..) => { + ExportedSymbol::NonGeneric(..) + | ExportedSymbol::ThreadLocalShim(..) + | ExportedSymbol::NoDefId(..) => { // These are no monomorphizations continue; } @@ -500,6 +517,13 @@ pub fn symbol_name_for_instance_in_crate<'tcx>( instantiating_crate, ) } + ExportedSymbol::ThreadLocalShim(def_id) => { + rustc_symbol_mangling::symbol_name_for_instance_in_crate( + tcx, + Instance::new(def_id, ty::InternalSubsts::empty()), + instantiating_crate, + ) + } ExportedSymbol::DropGlue(ty) => rustc_symbol_mangling::symbol_name_for_instance_in_crate( tcx, Instance::resolve_drop_in_place(tcx, ty), @@ -548,6 +572,8 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>( ExportedSymbol::DropGlue(..) => None, // NoDefId always follow the target's default symbol decoration scheme. ExportedSymbol::NoDefId(..) => None, + // ThreadLocalShim always follow the target's default symbol decoration scheme. + ExportedSymbol::ThreadLocalShim(..) => None, }; let (conv, args) = instance diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index cdc3e1dc237b2..e301acee3bbd3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -12,7 +12,8 @@ use crate::MemFlags; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::lang_items::LangItem; -use rustc_index::vec::Idx; +use rustc_hir::Unsafety; +use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::{self, AssertKind, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; @@ -743,25 +744,58 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let source_info = terminator.source_info; let span = source_info.span; - // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. - let callee = self.codegen_operand(bx, func); + let thread_local_shim_call = if !self.call_thread_local_shims.is_empty() { + self.call_thread_local_shims.iter().find(|e| &e.0 == func).map(|e| e.1) + } else { + None + }; - let (instance, mut llfn) = match *callee.layout.ty.kind() { - ty::FnDef(def_id, substs) => ( - Some( - ty::Instance::expect_resolve( - bx.tcx(), - ty::ParamEnv::reveal_all(), - def_id, - substs, - ) - .polymorphize(bx.tcx()), - ), - None, - ), - ty::FnPtr(_) => (None, Some(callee.immediate())), - _ => bug!("{} is not callable", callee.layout.ty), + let (sig, instance, mut llfn) = match thread_local_shim_call { + Some(thread_local) => { + // Replace thread local dummy calls with calls to the real shim + let instance = ty::Instance { + def: ty::InstanceDef::ThreadLocalShim(thread_local), + substs: ty::InternalSubsts::empty(), + }; + let ty = mir::Rvalue::ThreadLocalRef(thread_local).ty(&IndexVec::new(), bx.tcx()); + ( + ty::Binder::dummy(bx.tcx().mk_fn_sig( + [].iter(), + &ty, + false, + Unsafety::Normal, + Abi::Unadjusted, + )), + Some(instance), + None, + ) + } + None => { + // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. + let callee = self.codegen_operand(bx, func); + + let sig = callee.layout.ty.fn_sig(bx.tcx()); + + match *callee.layout.ty.kind() { + ty::FnDef(def_id, substs) => ( + sig, + Some( + ty::Instance::expect_resolve( + bx.tcx(), + ty::ParamEnv::reveal_all(), + def_id, + substs, + ) + .polymorphize(bx.tcx()), + ), + None, + ), + ty::FnPtr(_) => (sig, None, Some(callee.immediate())), + _ => bug!("{} is not callable", callee.layout.ty), + } + } }; + let def = instance.map(|i| i.def); if let Some(ty::InstanceDef::DropGlue(_, None)) = def { @@ -773,7 +807,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // FIXME(eddyb) avoid computing this if possible, when `instance` is // available - right now `sig` is only needed for getting the `abi` // and figuring out how many extra args were passed to a C-variadic `fn`. - let sig = callee.layout.ty.fn_sig(bx.tcx()); let abi = sig.abi(); // Handle intrinsics old codegen wants Expr's for, ourselves. diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 2ec9fdbf44f11..78bf37ecff7c0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -1,9 +1,15 @@ use crate::base; use crate::traits::*; +use rustc_hir::def_id::DefId; +use rustc_index::vec::Idx; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::mir::visit::Visitor; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout}; +use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_span::DUMMY_SP; use rustc_target::abi::call::{FnAbi, PassMode}; use std::iter; @@ -43,6 +49,9 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, + // Used to replace call terminators with a call to a thread local shim. + call_thread_local_shims: Vec<(mir::Operand<'tcx>, DefId)>, + /// When unwinding is initiated, we have to store this personality /// value somewhere so that we can load it and re-use it in the /// resume instruction. The personality is (afaik) some kind of @@ -142,6 +151,112 @@ impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> { } } +struct FindThreadLocal(bool); + +impl<'tcx> Visitor<'tcx> for FindThreadLocal { + fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) { + if let mir::Rvalue::ThreadLocalRef(..) = rvalue { + self.0 = true; + } + self.super_rvalue(rvalue, location); + } +} + +struct ReplaceThreadLocal<'tcx> { + tcx: TyCtxt<'tcx>, + local_start: usize, + list: Vec, +} + +impl<'tcx> MutVisitor<'tcx> for ReplaceThreadLocal<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_rvalue(&mut self, rvalue: &mut mir::Rvalue<'tcx>, location: mir::Location) { + if let mir::Rvalue::ThreadLocalRef(def_id) = *rvalue { + if self.tcx.is_in_upstream_dylib(def_id.krate) { + *rvalue = mir::Rvalue::Use(mir::Operand::Copy(mir::Place { + local: mir::Local::new(self.local_start + self.list.len()), + projection: self.tcx.intern_place_elems(&[]), + })); + self.list.push(def_id); + } + } + self.super_rvalue(rvalue, location); + } +} + +// Convert thread local references to thread local function shims if necessary +fn convert_tls_rvalues<'tcx>( + tcx: TyCtxt<'tcx>, + mir: &mut &'tcx mir::Body<'tcx>, +) -> Vec<(mir::Operand<'tcx>, DefId)> { + if tcx.sess.target.dll_tls_export { + // The target supports DLL TLS exports. We don't need to do anything + return Vec::new(); + } + + // Fast path to look for any thread locals + let mut visitor = FindThreadLocal(false); + visitor.visit_body(&mir); + if !visitor.0 { + return Vec::new(); + } + + // Don't modify shims + if let ty::InstanceDef::ThreadLocalShim(..) = mir.source.instance { + return Vec::new(); + } + + let mut result = Vec::new(); + let mut body = mir.clone(); + + let mut visitor = + ReplaceThreadLocal { tcx, local_start: mir.local_decls.len(), list: Vec::new() }; + visitor.visit_body(&mut body); + + for (i, &def_id) in visitor.list.iter().enumerate() { + let ty = mir::Rvalue::ThreadLocalRef(def_id).ty(&IndexVec::new(), tcx); + body.local_decls.push(mir::LocalDecl::new(ty, DUMMY_SP)); + let local = mir::Local::new(visitor.local_start + i); + let place = mir::Place { local, projection: tcx.intern_place_elems(&[]) }; + let func = mir::Operand::Copy(place); + + result.push((func.clone(), def_id)); + + let blocks = body.basic_blocks.as_mut(); + + let new_entry = mir::BasicBlock::new(blocks.len()); + + let entry = std::mem::replace( + &mut blocks[mir::BasicBlock::new(0)], + mir::BasicBlockData { + statements: Vec::new(), + terminator: Some(mir::Terminator { + source_info: mir::SourceInfo::outermost(DUMMY_SP), + kind: mir::TerminatorKind::Call { + func, + args: Vec::new(), + destination: place, + target: Some(new_entry), + cleanup: None, + from_hir_call: false, + fn_span: DUMMY_SP, + }, + }), + is_cleanup: false, + }, + ); + + blocks.push(entry); + } + + *mir = tcx.arena.alloc(body); + + result +} + /////////////////////////////////////////////////////////////////////////// #[instrument(level = "debug", skip(cx))] @@ -153,7 +268,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let llfn = cx.get_fn(instance); - let mir = cx.tcx().instance_mir(instance.def); + let mut mir = cx.tcx().instance_mir(instance.def); + + let call_thread_local_shims = convert_tls_rvalues(cx.tcx(), &mut mir); let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); debug!("fn_abi: {:?}", fn_abi); @@ -183,6 +300,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( llfn, fn_abi, cx, + call_thread_local_shims, personality_slot: None, cached_llbbs, unreachable_block: None, diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index d934cfbbb84ea..6a53775ab8e10 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -389,6 +389,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) + | ty::InstanceDef::ThreadLocalShim(..) | ty::InstanceDef::Item(_) => { // We need MIR for this fn let Some((body, instance)) = diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 83a0e833edc1d..15de38cc14f28 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -11,6 +11,7 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::metadata::ModChild; +use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::ty::fast_reject::SimplifiedType; @@ -501,6 +502,17 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { tcx.arena .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE)) }, + is_in_upstream_dylib: |tcx, cnum| { + if cnum == LOCAL_CRATE { + return false; + } + tcx.dependency_formats(()).iter().any(|(_, linkage)| { + match linkage[cnum.as_usize() - 1] { + Linkage::NotLinked | Linkage::Static => false, + Linkage::IncludedFromDylib | Linkage::Dynamic => true, + } + }) + }, crates: |tcx, ()| tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).crates_untracked()), ..*providers }; diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 631fd09ec4cf6..c0c0fd07b6e06 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -43,6 +43,7 @@ pub enum ExportedSymbol<'tcx> { NonGeneric(DefId), Generic(DefId, SubstsRef<'tcx>), DropGlue(Ty<'tcx>), + ThreadLocalShim(DefId), NoDefId(ty::SymbolName<'tcx>), } @@ -58,6 +59,10 @@ impl<'tcx> ExportedSymbol<'tcx> { ExportedSymbol::DropGlue(ty) => { tcx.symbol_name(ty::Instance::resolve_drop_in_place(tcx, ty)) } + ExportedSymbol::ThreadLocalShim(def_id) => tcx.symbol_name(ty::Instance { + def: ty::InstanceDef::ThreadLocalShim(def_id), + substs: ty::InternalSubsts::empty(), + }), ExportedSymbol::NoDefId(symbol_name) => symbol_name, } } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 7a05ee2ff37fd..c66d9fb51b917 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -381,6 +381,7 @@ impl<'tcx> CodegenUnit<'tcx> { | InstanceDef::Virtual(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::DropGlue(..) + | InstanceDef::ThreadLocalShim(..) | InstanceDef::CloneShim(..) => None, } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 7f0935fb149fa..ef9b6911318de 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -335,6 +335,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::VTableShim(_def_id) | ty::InstanceDef::ReifyShim(_def_id) | ty::InstanceDef::Virtual(_def_id, _) | + ty::InstanceDef::ThreadLocalShim(_def_id) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | ty::InstanceDef::DropGlue(_def_id, None) => {} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6a34e5ede1938..558496a8da537 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1808,6 +1808,10 @@ rustc_queries! { eval_always desc { "generating a postorder list of CrateNums" } } + query is_in_upstream_dylib(_: CrateNum) -> bool { + eval_always + desc { "checking if a crate is placed in an upstream dylib" } + } /// Returns whether or not the crate with CrateNum 'cnum' /// is marked as a private dependency query is_private_dep(c: CrateNum) -> bool { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index d07fa0e546f34..d356cbfb29641 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -82,6 +82,10 @@ pub enum InstanceDef<'tcx> { /// The `DefId` is the ID of the `call_once` method in `FnOnce`. ClosureOnceShim { call_once: DefId, track_caller: bool }, + /// Compiler-generated accessor for thread locals. This is used to export thread locals + /// from dylibs on platforms lacking native support. + ThreadLocalShim(DefId), + /// `core::ptr::drop_in_place::`. /// /// The `DefId` is for `core::ptr::drop_in_place`. @@ -149,6 +153,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id) + | InstanceDef::ThreadLocalShim(def_id) | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) => def_id, @@ -159,7 +164,9 @@ impl<'tcx> InstanceDef<'tcx> { pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option { match self { ty::InstanceDef::Item(def) => Some(def.did), - ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id), + ty::InstanceDef::DropGlue(def_id, Some(_)) | InstanceDef::ThreadLocalShim(def_id) => { + Some(def_id) + } InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) @@ -182,6 +189,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Intrinsic(def_id) | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | InstanceDef::DropGlue(def_id, _) + | InstanceDef::ThreadLocalShim(def_id) | InstanceDef::CloneShim(def_id, _) => ty::WithOptConstParam::unknown(def_id), } } @@ -201,6 +209,7 @@ impl<'tcx> InstanceDef<'tcx> { let def_id = match *self { ty::InstanceDef::Item(def) => def.did, ty::InstanceDef::DropGlue(_, Some(_)) => return false, + ty::InstanceDef::ThreadLocalShim(_) => return false, _ => return true, }; matches!( @@ -241,6 +250,9 @@ impl<'tcx> InstanceDef<'tcx> { ) }); } + if let ty::InstanceDef::ThreadLocalShim(..) = *self { + return false; + } tcx.codegen_fn_attrs(self.def_id()).requests_inline() } @@ -264,6 +276,7 @@ impl<'tcx> InstanceDef<'tcx> { pub fn has_polymorphic_mir_body(&self) -> bool { match *self { InstanceDef::CloneShim(..) + | InstanceDef::ThreadLocalShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::DropGlue(_, Some(_)) => false, InstanceDef::ClosureOnceShim { .. } @@ -295,6 +308,7 @@ fn fmt_instance( InstanceDef::Item(_) => Ok(()), InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"), InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"), + InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"), InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num), InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({})", ty), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 7dcc3ff4e7b33..46ca1778e8a0a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2346,6 +2346,7 @@ impl<'tcx> TyCtxt<'tcx> { | ty::InstanceDef::Virtual(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::DropGlue(..) + | ty::InstanceDef::ThreadLocalShim(..) | ty::InstanceDef::CloneShim(..) => self.mir_shims(instance), } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 8c6b0463a739a..66c72f00b6a14 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -270,6 +270,7 @@ impl<'tcx> Inliner<'tcx> { | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::DropGlue(..) + | InstanceDef::ThreadLocalShim(..) | InstanceDef::CloneShim(..) => return Ok(()), } diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 792457c80b0b7..0a3b498edf30a 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -83,6 +83,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ThreadLocalShim { .. } | InstanceDef::CloneShim(..) => {} InstanceDef::DropGlue(..) => { // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 682ad081f5cf3..c312b8512caf8 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -76,6 +76,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' build_drop_shim(tcx, def_id, ty) } + ty::InstanceDef::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance), ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), ty::InstanceDef::Virtual(..) => { bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance) @@ -321,6 +322,36 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { } } +fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'tcx> { + let def_id = instance.def_id(); + + let span = tcx.def_span(def_id); + let source_info = SourceInfo::outermost(span); + + let mut blocks = IndexVec::with_capacity(1); + blocks.push(BasicBlockData { + statements: vec![Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + Place::return_place(), + Rvalue::ThreadLocalRef(def_id), + ))), + }], + terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), + is_cleanup: false, + }); + + let ret_ty = Rvalue::ThreadLocalRef(def_id).ty(&IndexVec::new(), tcx); + + new_body( + MirSource::from_instance(instance), + blocks, + iter::once(LocalDecl::new(ret_ty, span)).collect(), + 0, + span, + ) +} + /// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`. fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> { debug!("build_clone_shim(def_id={:?})", def_id); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index ff409a8071611..be9e06420fe7d 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -190,7 +190,8 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::query::TyCtxtAt; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{ - self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, VtblEntry, + self, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, + VtblEntry, }; use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext}; use rustc_session::config::EntryFnType; @@ -462,6 +463,16 @@ fn collect_items_rec<'tcx>( collect_miri(tcx, id, &mut neighbors); } } + + if !tcx.sess.target.dll_tls_export && tcx.is_thread_local_static(def_id) { + neighbors.push(respan( + starting_point.span, + MonoItem::Fn(Instance { + def: InstanceDef::ThreadLocalShim(def_id), + substs: InternalSubsts::empty(), + }), + )); + } } MonoItem::Fn(instance) => { // Sanity check whether this ended up being collected accidentally @@ -963,6 +974,9 @@ fn visit_instance_use<'tcx>( bug!("{:?} being reified", instance); } } + ty::InstanceDef::ThreadLocalShim(..) => { + bug!("{:?} being reified", instance); + } ty::InstanceDef::DropGlue(_, None) => { // Don't need to emit noop drop glue if we are calling directly. if !is_direct_call { @@ -1210,11 +1224,9 @@ impl<'v> RootCollector<'_, 'v> { self.output.push(dummy_spanned(MonoItem::GlobalAsm(id))); } DefKind::Static(..) => { - debug!( - "RootCollector: ItemKind::Static({})", - self.tcx.def_path_str(id.owner_id.to_def_id()) - ); - self.output.push(dummy_spanned(MonoItem::Static(id.owner_id.to_def_id()))); + let def_id = id.owner_id.to_def_id(); + debug!("RootCollector: ItemKind::Static({})", self.tcx.def_path_str(def_id)); + self.output.push(dummy_spanned(MonoItem::Static(def_id))); } DefKind::Const => { // const items only generate mono items if they are diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index 2c56edd89bc31..d51b8a7552b82 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -278,6 +278,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( | ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::Virtual(..) + | ty::InstanceDef::ThreadLocalShim(..) | ty::InstanceDef::CloneShim(..) => return None, }; @@ -424,6 +425,15 @@ fn mono_item_visibility<'tcx>( InstanceDef::Item(def) => def.did, InstanceDef::DropGlue(def_id, Some(_)) => def_id, + InstanceDef::ThreadLocalShim(def_id) => { + return if tcx.is_reachable_non_generic(def_id) { + *can_be_internalized = false; + default_visibility(tcx, def_id, false) + } else { + Visibility::Hidden + }; + } + // These are all compiler glue and such, never exported, always hidden. InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 2368468c89123..5cbca81926b9a 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -65,6 +65,10 @@ pub(super) fn mangle<'tcx>( ) .unwrap(); + if let ty::InstanceDef::ThreadLocalShim(..) = instance.def { + let _ = printer.write_str("{{tls-shim}}"); + } + if let ty::InstanceDef::VTableShim(..) = instance.def { let _ = printer.write_str("{{vtable-shim}}"); } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 2f20d42139c8d..cac7ff72267db 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -42,6 +42,7 @@ pub(super) fn mangle<'tcx>( // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance. let shim_kind = match instance.def { + ty::InstanceDef::ThreadLocalShim(_) => Some("tls"), ty::InstanceDef::VTableShim(_) => Some("vtable"), ty::InstanceDef::ReifyShim(_) => Some("reify"), diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 0d86a3032a659..4538f03da3ebf 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1466,6 +1466,8 @@ pub struct TargetOptions { pub features: StaticCow, /// Whether dynamic linking is available on this target. Defaults to false. pub dynamic_linking: bool, + /// Whether dynamic linking can export TLS globals. Defaults to true. + pub dll_tls_export: bool, /// If dynamic linking is available, whether only cdylibs are supported. pub only_cdylib: bool, /// Whether executables are available on this target. Defaults to true. @@ -1857,6 +1859,7 @@ impl Default for TargetOptions { cpu: "generic".into(), features: "".into(), dynamic_linking: false, + dll_tls_export: true, only_cdylib: false, executables: true, relocation_model: RelocModel::Pic, @@ -2528,6 +2531,7 @@ impl Target { key!(cpu); key!(features); key!(dynamic_linking, bool); + key!(dll_tls_export, bool); key!(only_cdylib, bool); key!(executables, bool); key!(relocation_model, RelocModel)?; @@ -2781,6 +2785,7 @@ impl ToJson for Target { target_option_val!(cpu); target_option_val!(features); target_option_val!(dynamic_linking); + target_option_val!(dll_tls_export); target_option_val!(only_cdylib); target_option_val!(executables); target_option_val!(relocation_model); diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs index 1dad9133ea3d2..efe949a4e9074 100644 --- a/compiler/rustc_target/src/spec/msvc_base.rs +++ b/compiler/rustc_target/src/spec/msvc_base.rs @@ -8,6 +8,7 @@ pub fn opts() -> TargetOptions { TargetOptions { linker_flavor: LinkerFlavor::Msvc(Lld::No), + dll_tls_export: false, is_like_windows: true, is_like_msvc: true, pre_link_args, diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index a32ca469b2f58..2231983f07126 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -78,6 +78,7 @@ pub fn opts() -> TargetOptions { function_sections: false, linker: Some("gcc".into()), dynamic_linking: true, + dll_tls_export: false, dll_prefix: "".into(), dll_suffix: ".dll".into(), exe_suffix: ".exe".into(), diff --git a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs index cada28652f98a..b1d8e2be5a61f 100644 --- a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs @@ -23,6 +23,7 @@ pub fn opts() -> TargetOptions { abi: "llvm".into(), linker: Some("clang".into()), dynamic_linking: true, + dll_tls_export: false, dll_prefix: "".into(), dll_suffix: ".dll".into(), exe_suffix: ".exe".into(), diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 41924dc2a6d93..62bd36a09609c 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,9 +1,11 @@ use rustc_hir as hir; use rustc_hir::lang_items::LangItem; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::Rvalue; use rustc_middle::ty::layout::{ fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout, }; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt}; use rustc_session::config::OptLevel; use rustc_span::def_id::DefId; use rustc_target::abi::call::{ @@ -29,6 +31,18 @@ fn fn_sig_for_fn_abi<'tcx>( instance: ty::Instance<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> ty::PolyFnSig<'tcx> { + if let InstanceDef::ThreadLocalShim(..) = instance.def { + let ret_ty = Rvalue::ThreadLocalRef(instance.def_id()).ty(&IndexVec::new(), tcx); + + return ty::Binder::dummy(tcx.mk_fn_sig( + [].iter(), + &ret_ty, + false, + hir::Unsafety::Normal, + rustc_target::spec::abi::Abi::Unadjusted, + )); + } + let ty = instance.ty(tcx, param_env); match *ty.kind() { ty::FnDef(..) => { From 98d2669d0def4d49f7f4b7f5b2ace9265952900f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 15 Feb 2023 16:50:28 +0100 Subject: [PATCH 04/26] Use #[inline] on Windows for thread local access --- library/std/src/thread/local.rs | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index cf7c2e05a2e9d..8f573b5ce5db9 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -181,7 +181,7 @@ macro_rules! thread_local { macro_rules! __thread_local_inner { // used to generate the `LocalKey` value for const-initialized thread locals (@key $t:ty, const $init:expr) => {{ - #[cfg_attr(not(windows), inline)] // see comments below + #[cfg_attr(not(bootstrap), inline)] #[deny(unsafe_op_in_unsafe_fn)] unsafe fn __getit( _init: $crate::option::Option<&mut $crate::option::Option<$t>>, @@ -293,29 +293,7 @@ macro_rules! __thread_local_inner { #[inline] fn __init() -> $t { $init } - // When reading this function you might ask "why is this inlined - // everywhere other than Windows?", and that's a very reasonable - // question to ask. The short story is that it segfaults rustc if - // this function is inlined. The longer story is that Windows looks - // to not support `extern` references to thread locals across DLL - // boundaries. This appears to at least not be supported in the ABI - // that LLVM implements. - // - // Because of this we never inline on Windows, but we do inline on - // other platforms (where external references to thread locals - // across DLLs are supported). A better fix for this would be to - // inline this function on Windows, but only for "statically linked" - // components. For example if two separately compiled rlibs end up - // getting linked into a DLL then it's fine to inline this function - // across that boundary. It's only not fine to inline this function - // across a DLL boundary. Unfortunately rustc doesn't currently - // have this sort of logic available in an attribute, and it's not - // clear that rustc is even equipped to answer this (it's more of a - // Cargo question kinda). This means that, unfortunately, Windows - // gets the pessimistic path for now where it's never inlined. - // - // The issue of "should enable on Windows sometimes" is #84933 - #[cfg_attr(not(windows), inline)] + #[cfg_attr(not(bootstrap), inline)] unsafe fn __getit( init: $crate::option::Option<&mut $crate::option::Option<$t>>, ) -> $crate::option::Option<&'static $t> { From c044df2d5fd19ef0b74e34de16c1a3afe9efdcdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 16 Feb 2023 20:35:55 +0100 Subject: [PATCH 05/26] Only avoid shims for the local crate --- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- .../rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 12 ------------ compiler/rustc_middle/src/query/mod.rs | 4 ---- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 78bf37ecff7c0..c84181ff32a27 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -175,7 +175,7 @@ impl<'tcx> MutVisitor<'tcx> for ReplaceThreadLocal<'tcx> { fn visit_rvalue(&mut self, rvalue: &mut mir::Rvalue<'tcx>, location: mir::Location) { if let mir::Rvalue::ThreadLocalRef(def_id) = *rvalue { - if self.tcx.is_in_upstream_dylib(def_id.krate) { + if !def_id.is_local() { *rvalue = mir::Rvalue::Use(mir::Operand::Copy(mir::Place { local: mir::Local::new(self.local_start + self.list.len()), projection: self.tcx.intern_place_elems(&[]), diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 15de38cc14f28..83a0e833edc1d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -11,7 +11,6 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::metadata::ModChild; -use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::ty::fast_reject::SimplifiedType; @@ -502,17 +501,6 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { tcx.arena .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE)) }, - is_in_upstream_dylib: |tcx, cnum| { - if cnum == LOCAL_CRATE { - return false; - } - tcx.dependency_formats(()).iter().any(|(_, linkage)| { - match linkage[cnum.as_usize() - 1] { - Linkage::NotLinked | Linkage::Static => false, - Linkage::IncludedFromDylib | Linkage::Dynamic => true, - } - }) - }, crates: |tcx, ()| tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).crates_untracked()), ..*providers }; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 558496a8da537..6a34e5ede1938 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1808,10 +1808,6 @@ rustc_queries! { eval_always desc { "generating a postorder list of CrateNums" } } - query is_in_upstream_dylib(_: CrateNum) -> bool { - eval_always - desc { "checking if a crate is placed in an upstream dylib" } - } /// Returns whether or not the crate with CrateNum 'cnum' /// is marked as a private dependency query is_private_dep(c: CrateNum) -> bool { From 524d14042b5dfbe8fa24a4c1fd9704959969c0c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 16 Feb 2023 20:59:41 +0100 Subject: [PATCH 06/26] Lower TLS to calls for rvalues directly --- compiler/rustc_codegen_ssa/src/mir/block.rs | 71 +++-------- compiler/rustc_codegen_ssa/src/mir/mod.rs | 120 +------------------ compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 13 +- 3 files changed, 32 insertions(+), 172 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e301acee3bbd3..cdc3e1dc237b2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -12,8 +12,7 @@ use crate::MemFlags; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::lang_items::LangItem; -use rustc_hir::Unsafety; -use rustc_index::vec::{Idx, IndexVec}; +use rustc_index::vec::Idx; use rustc_middle::mir::{self, AssertKind, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; @@ -744,58 +743,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let source_info = terminator.source_info; let span = source_info.span; - let thread_local_shim_call = if !self.call_thread_local_shims.is_empty() { - self.call_thread_local_shims.iter().find(|e| &e.0 == func).map(|e| e.1) - } else { - None - }; + // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. + let callee = self.codegen_operand(bx, func); - let (sig, instance, mut llfn) = match thread_local_shim_call { - Some(thread_local) => { - // Replace thread local dummy calls with calls to the real shim - let instance = ty::Instance { - def: ty::InstanceDef::ThreadLocalShim(thread_local), - substs: ty::InternalSubsts::empty(), - }; - let ty = mir::Rvalue::ThreadLocalRef(thread_local).ty(&IndexVec::new(), bx.tcx()); - ( - ty::Binder::dummy(bx.tcx().mk_fn_sig( - [].iter(), - &ty, - false, - Unsafety::Normal, - Abi::Unadjusted, - )), - Some(instance), - None, - ) - } - None => { - // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. - let callee = self.codegen_operand(bx, func); - - let sig = callee.layout.ty.fn_sig(bx.tcx()); - - match *callee.layout.ty.kind() { - ty::FnDef(def_id, substs) => ( - sig, - Some( - ty::Instance::expect_resolve( - bx.tcx(), - ty::ParamEnv::reveal_all(), - def_id, - substs, - ) - .polymorphize(bx.tcx()), - ), - None, - ), - ty::FnPtr(_) => (sig, None, Some(callee.immediate())), - _ => bug!("{} is not callable", callee.layout.ty), - } - } + let (instance, mut llfn) = match *callee.layout.ty.kind() { + ty::FnDef(def_id, substs) => ( + Some( + ty::Instance::expect_resolve( + bx.tcx(), + ty::ParamEnv::reveal_all(), + def_id, + substs, + ) + .polymorphize(bx.tcx()), + ), + None, + ), + ty::FnPtr(_) => (None, Some(callee.immediate())), + _ => bug!("{} is not callable", callee.layout.ty), }; - let def = instance.map(|i| i.def); if let Some(ty::InstanceDef::DropGlue(_, None)) = def { @@ -807,6 +773,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // FIXME(eddyb) avoid computing this if possible, when `instance` is // available - right now `sig` is only needed for getting the `abi` // and figuring out how many extra args were passed to a C-variadic `fn`. + let sig = callee.layout.ty.fn_sig(bx.tcx()); let abi = sig.abi(); // Handle intrinsics old codegen wants Expr's for, ourselves. diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index c84181ff32a27..2ec9fdbf44f11 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -1,15 +1,9 @@ use crate::base; use crate::traits::*; -use rustc_hir::def_id::DefId; -use rustc_index::vec::Idx; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::mir::visit::MutVisitor; -use rustc_middle::mir::visit::Visitor; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout}; -use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; -use rustc_span::DUMMY_SP; use rustc_target::abi::call::{FnAbi, PassMode}; use std::iter; @@ -49,9 +43,6 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, - // Used to replace call terminators with a call to a thread local shim. - call_thread_local_shims: Vec<(mir::Operand<'tcx>, DefId)>, - /// When unwinding is initiated, we have to store this personality /// value somewhere so that we can load it and re-use it in the /// resume instruction. The personality is (afaik) some kind of @@ -151,112 +142,6 @@ impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> { } } -struct FindThreadLocal(bool); - -impl<'tcx> Visitor<'tcx> for FindThreadLocal { - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) { - if let mir::Rvalue::ThreadLocalRef(..) = rvalue { - self.0 = true; - } - self.super_rvalue(rvalue, location); - } -} - -struct ReplaceThreadLocal<'tcx> { - tcx: TyCtxt<'tcx>, - local_start: usize, - list: Vec, -} - -impl<'tcx> MutVisitor<'tcx> for ReplaceThreadLocal<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_rvalue(&mut self, rvalue: &mut mir::Rvalue<'tcx>, location: mir::Location) { - if let mir::Rvalue::ThreadLocalRef(def_id) = *rvalue { - if !def_id.is_local() { - *rvalue = mir::Rvalue::Use(mir::Operand::Copy(mir::Place { - local: mir::Local::new(self.local_start + self.list.len()), - projection: self.tcx.intern_place_elems(&[]), - })); - self.list.push(def_id); - } - } - self.super_rvalue(rvalue, location); - } -} - -// Convert thread local references to thread local function shims if necessary -fn convert_tls_rvalues<'tcx>( - tcx: TyCtxt<'tcx>, - mir: &mut &'tcx mir::Body<'tcx>, -) -> Vec<(mir::Operand<'tcx>, DefId)> { - if tcx.sess.target.dll_tls_export { - // The target supports DLL TLS exports. We don't need to do anything - return Vec::new(); - } - - // Fast path to look for any thread locals - let mut visitor = FindThreadLocal(false); - visitor.visit_body(&mir); - if !visitor.0 { - return Vec::new(); - } - - // Don't modify shims - if let ty::InstanceDef::ThreadLocalShim(..) = mir.source.instance { - return Vec::new(); - } - - let mut result = Vec::new(); - let mut body = mir.clone(); - - let mut visitor = - ReplaceThreadLocal { tcx, local_start: mir.local_decls.len(), list: Vec::new() }; - visitor.visit_body(&mut body); - - for (i, &def_id) in visitor.list.iter().enumerate() { - let ty = mir::Rvalue::ThreadLocalRef(def_id).ty(&IndexVec::new(), tcx); - body.local_decls.push(mir::LocalDecl::new(ty, DUMMY_SP)); - let local = mir::Local::new(visitor.local_start + i); - let place = mir::Place { local, projection: tcx.intern_place_elems(&[]) }; - let func = mir::Operand::Copy(place); - - result.push((func.clone(), def_id)); - - let blocks = body.basic_blocks.as_mut(); - - let new_entry = mir::BasicBlock::new(blocks.len()); - - let entry = std::mem::replace( - &mut blocks[mir::BasicBlock::new(0)], - mir::BasicBlockData { - statements: Vec::new(), - terminator: Some(mir::Terminator { - source_info: mir::SourceInfo::outermost(DUMMY_SP), - kind: mir::TerminatorKind::Call { - func, - args: Vec::new(), - destination: place, - target: Some(new_entry), - cleanup: None, - from_hir_call: false, - fn_span: DUMMY_SP, - }, - }), - is_cleanup: false, - }, - ); - - blocks.push(entry); - } - - *mir = tcx.arena.alloc(body); - - result -} - /////////////////////////////////////////////////////////////////////////// #[instrument(level = "debug", skip(cx))] @@ -268,9 +153,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let llfn = cx.get_fn(instance); - let mut mir = cx.tcx().instance_mir(instance.def); - - let call_thread_local_shims = convert_tls_rvalues(cx.tcx(), &mut mir); + let mir = cx.tcx().instance_mir(instance.def); let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); debug!("fn_abi: {:?}", fn_abi); @@ -300,7 +183,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( llfn, fn_abi, cx, - call_thread_local_shims, personality_slot: None, cached_llbbs, unreachable_block: None, diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 41cd1c09a4e70..2bb94001d1f66 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -462,8 +462,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::ThreadLocalRef(def_id) => { assert!(bx.cx().tcx().is_static(def_id)); - let static_ = bx.get_static(def_id); let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id)); + let static_ = if !def_id.is_local() && !bx.cx().tcx().sess.target.dll_tls_export { + let instance = ty::Instance { + def: ty::InstanceDef::ThreadLocalShim(def_id), + substs: ty::InternalSubsts::empty(), + }; + let fn_ptr = bx.get_fn_addr(instance); + let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty()); + let fn_ty = bx.fn_decl_backend_type(&fn_abi); + bx.call(fn_ty, Some(fn_abi), fn_ptr, &[], None) + } else { + bx.get_static(def_id) + }; OperandRef { val: OperandValue::Immediate(static_), layout } } mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand), From cf3683f0629fd78ea3c732362e17404399e18c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 19 Feb 2023 01:04:54 +0100 Subject: [PATCH 07/26] Address comments --- compiler/rustc_middle/src/mir/tcx.rs | 12 +----- compiler/rustc_middle/src/ty/instance.rs | 5 ++- compiler/rustc_middle/src/ty/util.rs | 13 +++++++ compiler/rustc_mir_transform/src/shim.rs | 4 +- .../src/partitioning/default.rs | 37 +++++++++---------- compiler/rustc_ty_utils/src/abi.rs | 8 +--- 6 files changed, 37 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index aa9f170477bcb..e1ef6aebb8a3a 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -164,17 +164,7 @@ impl<'tcx> Rvalue<'tcx> { Rvalue::Repeat(ref operand, count) => { tcx.mk_array_with_const_len(operand.ty(local_decls, tcx), count) } - Rvalue::ThreadLocalRef(did) => { - let static_ty = tcx.type_of(did).subst_identity(); - if tcx.is_mutable_static(did) { - tcx.mk_mut_ptr(static_ty) - } else if tcx.is_foreign_item(did) { - tcx.mk_imm_ptr(static_ty) - } else { - // FIXME: These things don't *really* have 'static lifetime. - tcx.mk_imm_ref(tcx.lifetimes.re_static, static_ty) - } - } + Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did), Rvalue::Ref(reg, bk, ref place) => { let place_ty = place.ty(local_decls, tcx).ty; tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() }) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index d356cbfb29641..4e304c35324b3 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -82,8 +82,9 @@ pub enum InstanceDef<'tcx> { /// The `DefId` is the ID of the `call_once` method in `FnOnce`. ClosureOnceShim { call_once: DefId, track_caller: bool }, - /// Compiler-generated accessor for thread locals. This is used to export thread locals - /// from dylibs on platforms lacking native support. + /// Compiler-generated accessor for thread locals which returns a reference to the thread local + /// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking + /// native support. ThreadLocalShim(DefId), /// `core::ptr::drop_in_place::`. diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 2ac3adda80b94..5718ec5bca1b2 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -599,6 +599,19 @@ impl<'tcx> TyCtxt<'tcx> { self.static_mutability(def_id) == Some(hir::Mutability::Mut) } + /// Returns the type a reference to the thread local takes in MIR. + pub fn thread_local_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { + let static_ty = self.type_of(def_id).subst_identity(); + if self.is_mutable_static(def_id) { + self.mk_mut_ptr(static_ty) + } else if self.is_foreign_item(def_id) { + self.mk_imm_ptr(static_ty) + } else { + // FIXME: These things don't *really* have 'static lifetime. + self.mk_imm_ref(self.lifetimes.re_static, static_ty) + } + } + /// Get the type of the pointer to the static that we use in MIR. pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { // Make sure that any constants in the static's type are evaluated. diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index c312b8512caf8..b976278b4750b 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -341,12 +341,10 @@ fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'t is_cleanup: false, }); - let ret_ty = Rvalue::ThreadLocalRef(def_id).ty(&IndexVec::new(), tcx); - new_body( MirSource::from_instance(instance), blocks, - iter::once(LocalDecl::new(ret_ty, span)).collect(), + IndexVec::from_raw(vec![LocalDecl::new(tcx.thread_local_ptr_ty(def_id), span)]), 0, span, ) diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index d51b8a7552b82..b8d47f527afa9 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -392,6 +392,19 @@ fn mono_item_linkage_and_visibility<'tcx>( type CguNameCache = FxHashMap<(DefId, bool), Symbol>; +fn static_visibility<'tcx>( + tcx: TyCtxt<'tcx>, + can_be_internalized: &mut bool, + def_id: DefId, +) -> Visibility { + if tcx.is_reachable_non_generic(def_id) { + *can_be_internalized = false; + default_visibility(tcx, def_id, false) + } else { + Visibility::Hidden + } +} + fn mono_item_visibility<'tcx>( tcx: TyCtxt<'tcx>, mono_item: &MonoItem<'tcx>, @@ -403,21 +416,9 @@ fn mono_item_visibility<'tcx>( MonoItem::Fn(instance) => instance, // Misc handling for generics and such, but otherwise: - MonoItem::Static(def_id) => { - return if tcx.is_reachable_non_generic(*def_id) { - *can_be_internalized = false; - default_visibility(tcx, *def_id, false) - } else { - Visibility::Hidden - }; - } + MonoItem::Static(def_id) => return static_visibility(tcx, can_be_internalized, *def_id), MonoItem::GlobalAsm(item_id) => { - return if tcx.is_reachable_non_generic(item_id.owner_id) { - *can_be_internalized = false; - default_visibility(tcx, item_id.owner_id.to_def_id(), false) - } else { - Visibility::Hidden - }; + return static_visibility(tcx, can_be_internalized, item_id.owner_id.to_def_id()); } }; @@ -425,13 +426,9 @@ fn mono_item_visibility<'tcx>( InstanceDef::Item(def) => def.did, InstanceDef::DropGlue(def_id, Some(_)) => def_id, + // We match the visiblity of statics here InstanceDef::ThreadLocalShim(def_id) => { - return if tcx.is_reachable_non_generic(def_id) { - *can_be_internalized = false; - default_visibility(tcx, def_id, false) - } else { - Visibility::Hidden - }; + return static_visibility(tcx, can_be_internalized, def_id); } // These are all compiler glue and such, never exported, always hidden. diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 62bd36a09609c..9166f426d8518 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,7 +1,5 @@ use rustc_hir as hir; use rustc_hir::lang_items::LangItem; -use rustc_index::vec::IndexVec; -use rustc_middle::mir::Rvalue; use rustc_middle::ty::layout::{ fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout, }; @@ -32,11 +30,9 @@ fn fn_sig_for_fn_abi<'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> ty::PolyFnSig<'tcx> { if let InstanceDef::ThreadLocalShim(..) = instance.def { - let ret_ty = Rvalue::ThreadLocalRef(instance.def_id()).ty(&IndexVec::new(), tcx); - return ty::Binder::dummy(tcx.mk_fn_sig( - [].iter(), - &ret_ty, + [], + tcx.thread_local_ptr_ty(instance.def_id()), false, hir::Unsafety::Normal, rustc_target::spec::abi::Abi::Unadjusted, From e61ac42702b19e025a889454fe6c280696abcbdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 19 Feb 2023 01:18:19 +0100 Subject: [PATCH 08/26] Don't use thread local shims for foreign thread locals --- compiler/rustc_codegen_ssa/src/back/symbol_export.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 3 ++- compiler/rustc_middle/src/ty/util.rs | 9 +++++++++ compiler/rustc_monomorphize/src/collector.rs | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index c465fd43f2962..96c5af8d14020 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -188,7 +188,7 @@ fn exported_symbols_provider_local( // Export TLS shims if !tcx.sess.target.dll_tls_export { symbols.extend(sorted.iter().filter_map(|(&def_id, &info)| { - tcx.is_thread_local_static(def_id).then(|| { + tcx.needs_thread_local_shim(def_id).then(|| { ( ExportedSymbol::ThreadLocalShim(def_id), SymbolExportInfo { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 2bb94001d1f66..ee57a5a66d0d0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -463,7 +463,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::ThreadLocalRef(def_id) => { assert!(bx.cx().tcx().is_static(def_id)); let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id)); - let static_ = if !def_id.is_local() && !bx.cx().tcx().sess.target.dll_tls_export { + let static_ = if !def_id.is_local() && bx.cx().tcx().needs_thread_local_shim(def_id) + { let instance = ty::Instance { def: ty::InstanceDef::ThreadLocalShim(def_id), substs: ty::InternalSubsts::empty(), diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 5718ec5bca1b2..6f61101c1bd09 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -599,6 +599,15 @@ impl<'tcx> TyCtxt<'tcx> { self.static_mutability(def_id) == Some(hir::Mutability::Mut) } + /// Returns `true` if the item pointed to by `def_id` is a thread local which needs a + /// thread local shim generated. + #[inline] + pub fn needs_thread_local_shim(self, def_id: DefId) -> bool { + !self.sess.target.dll_tls_export + && self.is_thread_local_static(def_id) + && !self.is_foreign_item(def_id) + } + /// Returns the type a reference to the thread local takes in MIR. pub fn thread_local_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { let static_ty = self.type_of(def_id).subst_identity(); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index be9e06420fe7d..2e31be4828920 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -464,7 +464,7 @@ fn collect_items_rec<'tcx>( } } - if !tcx.sess.target.dll_tls_export && tcx.is_thread_local_static(def_id) { + if tcx.needs_thread_local_shim(def_id) { neighbors.push(respan( starting_point.span, MonoItem::Fn(Instance { From 6c9d7505e6413bbcbf696396f72506b060f62f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 19 Feb 2023 15:57:04 +0100 Subject: [PATCH 09/26] Add cranelift support --- .../rustc_codegen_cranelift/src/constant.rs | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 49c4f1aaaefc6..67ff008ff504c 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -54,12 +54,22 @@ pub(crate) fn codegen_tls_ref<'tcx>( def_id: DefId, layout: TyAndLayout<'tcx>, ) -> CValue<'tcx> { - let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); - let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); - if fx.clif_comments.enabled() { - fx.add_comment(local_data_id, format!("tls {:?}", def_id)); - } - let tls_ptr = fx.bcx.ins().tls_value(fx.pointer_type, local_data_id); + let tls_ptr = if !def_id.is_local() && fx.tcx.needs_thread_local_shim(def_id) { + let instance = ty::Instance { + def: ty::InstanceDef::ThreadLocalShim(def_id), + substs: ty::InternalSubsts::empty(), + }; + let func_ref = fx.get_function_ref(instance); + let call = fx.bcx.ins().call(func_ref, &[]); + fx.bcx.func.dfg.first_result(call) + } else { + let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); + let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + if fx.clif_comments.enabled() { + fx.add_comment(local_data_id, format!("tls {:?}", def_id)); + } + fx.bcx.ins().tls_value(fx.pointer_type, local_data_id) + }; CValue::by_val(tls_ptr, layout) } From 530913543d4aae12f91c693fe0871d08515425b8 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Sun, 26 Feb 2023 01:37:26 -0800 Subject: [PATCH 10/26] move pal cfgs in f32 and f64 to sys --- library/std/src/f32.rs | 5 +---- library/std/src/f64.rs | 11 +++-------- library/std/src/sys/mod.rs | 29 +++++++++++++++++++++++++++++ src/tools/tidy/src/pal.rs | 2 -- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 6b1f0cba82dfc..bb78fc5c2bfd2 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -470,10 +470,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f32 { - #[cfg(target_os = "android")] - return crate::sys::android::log2f32(self); - #[cfg(not(target_os = "android"))] - return unsafe { intrinsics::log2f32(self) }; + return crate::sys::log2f32(self); } /// Returns the base 10 logarithm of the number. diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 16359766b510d..0735bab9efa2b 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -470,12 +470,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f64 { - self.log_wrapper(|n| { - #[cfg(target_os = "android")] - return crate::sys::android::log2f64(n); - #[cfg(not(target_os = "android"))] - return unsafe { intrinsics::log2f64(n) }; - }) + self.log_wrapper(crate::sys::log2f64) } /// Returns the base 10 logarithm of the number. @@ -936,8 +931,8 @@ impl f64 { // of expected NaN). #[rustc_allow_incoherent_impl] fn log_wrapper f64>(self, log_fn: F) -> f64 { - if !cfg!(any(target_os = "solaris", target_os = "illumos")) { - log_fn(self) + if let Some(result) = crate::sys::log_wrapper(self) { + log_fn(result) } else if self.is_finite() { if self > 0.0 { log_fn(self) diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index c080c176a2ace..c95b1a2fa28da 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -76,3 +76,32 @@ cfg_if::cfg_if! { pub mod c; } } + +#[cfg(not(test))] +cfg_if::cfg_if! { + if #[cfg(target_os = "android")] { + pub use crate::android::log2f32; + pub use crate::android::log2f64; + } else { + pub fn log2f32(n: f32) -> f32 { + unsafe { crate::intrinsics::log2f32(n) } + } + + pub fn log2f64(n: f64) -> f64 { + unsafe { crate::intrinsics::log2f64(n) } + } + } +} + +#[cfg(not(test))] +cfg_if::cfg_if! { + if #[cfg(any(target_os = "solaris", target_os = "illumos"))] { + pub fn log_wrapper(n: f64) -> Option { + Some(n) + } + } else { + pub fn log_wrapper(_n: f64) -> Option { + None + } + } +} diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index f4592fdcff9dc..5699cd253d285 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -54,8 +54,6 @@ const EXCEPTION_PATHS: &[&str] = &[ // FIXME: platform-specific code should be moved to `sys` "library/std/src/io/copy.rs", "library/std/src/io/stdio.rs", - "library/std/src/f32.rs", - "library/std/src/f64.rs", "library/std/src/path.rs", "library/std/src/sys_common", // Should only contain abstractions over platforms "library/std/src/net/test.rs", // Utility helpers for tests From 0e825653f1f78bb735e6606b05c39e1e54a8dc0c Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Sun, 26 Feb 2023 13:24:11 -0800 Subject: [PATCH 11/26] fix weird log --- library/std/src/f64.rs | 30 +++--------------------------- library/std/src/sys/mod.rs | 25 +++++++++++++++++++++---- 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 0735bab9efa2b..84938d7949584 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -426,7 +426,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln(self) -> f64 { - self.log_wrapper(|n| unsafe { intrinsics::logf64(n) }) + crate::sys::log_wrapper(self, |n| unsafe { intrinsics::logf64(n) }) } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -470,7 +470,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f64 { - self.log_wrapper(crate::sys::log2f64) + crate::sys::log_wrapper(self, crate::sys::log2f64) } /// Returns the base 10 logarithm of the number. @@ -490,7 +490,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log10(self) -> f64 { - self.log_wrapper(|n| unsafe { intrinsics::log10f64(n) }) + crate::sys::log_wrapper(self, |n| unsafe { intrinsics::log10f64(n) }) } /// The positive difference of two numbers. @@ -925,28 +925,4 @@ impl f64 { pub fn atanh(self) -> f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } - - // Solaris/Illumos requires a wrapper around log, log2, and log10 functions - // because of their non-standard behavior (e.g., log(-n) returns -Inf instead - // of expected NaN). - #[rustc_allow_incoherent_impl] - fn log_wrapper f64>(self, log_fn: F) -> f64 { - if let Some(result) = crate::sys::log_wrapper(self) { - log_fn(result) - } else if self.is_finite() { - if self > 0.0 { - log_fn(self) - } else if self == 0.0 { - Self::NEG_INFINITY // log(0) = -Inf - } else { - Self::NAN // log(-n) = NaN - } - } else if self.is_nan() { - self // log(NaN) = NaN - } else if self > 0.0 { - self // log(Inf) = Inf - } else { - Self::NAN // log(-Inf) = NaN - } - } } diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index c95b1a2fa28da..4be4e873ffcee 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -93,15 +93,32 @@ cfg_if::cfg_if! { } } +// Solaris/Illumos requires a wrapper around log, log2, and log10 functions +// because of their non-standard behavior (e.g., log(-n) returns -Inf instead +// of expected NaN). #[cfg(not(test))] cfg_if::cfg_if! { if #[cfg(any(target_os = "solaris", target_os = "illumos"))] { - pub fn log_wrapper(n: f64) -> Option { - Some(n) + pub fn log_wrapper f64>(n: f64, log_fn: F) -> f64 { + if n.is_finite() { + if n > 0.0 { + log_fn(n) + } else if n == 0.0 { + f64::NEG_INFINITY // log(0) = -Inf + } else { + f64::NAN // log(-n) = NaN + } + } else if n.is_nan() { + n // log(NaN) = NaN + } else if n > 0.0 { + n // log(Inf) = Inf + } else { + f64::NAN // log(-Inf) = NaN + } } } else { - pub fn log_wrapper(_n: f64) -> Option { - None + pub fn log_wrapper f64>(n: f64, log_fn: F) -> f64 { + log_fn(n) } } } From deaa64342599db1166c51311302f2e5450f7c654 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Sun, 26 Feb 2023 16:12:33 -0800 Subject: [PATCH 12/26] return --- library/std/src/f32.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index bb78fc5c2bfd2..e06b14fdcca92 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -470,7 +470,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f32 { - return crate::sys::log2f32(self); + crate::sys::log2f32(self) } /// Returns the base 10 logarithm of the number. 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 13/26] 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 14/26] 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 15/26] 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 832b33e6b1e0359130b67f0c83f2def0420a6832 Mon Sep 17 00:00:00 2001 From: bwmf2 Date: Sun, 26 Feb 2023 23:22:50 +0100 Subject: [PATCH 16/26] Force parentheses around `match` expression in binary expression --- compiler/rustc_ast_pretty/src/pprust/state/expr.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index cacfe9eb2f107..a4d91a9566273 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -244,6 +244,10 @@ impl<'a> State<'a> { (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => { parser::PREC_FORCE_PAREN } + // For a binary expression like `(match () { _ => a }) OP b`, the parens are required + // otherwise the parser would interpret `match () { _ => a }` as a statement, + // with the remaining `OP b` not making sense. So we force parens. + (&ast::ExprKind::Match(..), _) => parser::PREC_FORCE_PAREN, _ => left_prec, }; From cdeb0e3e02cc70ca4efb41fa67b55b5722a81121 Mon Sep 17 00:00:00 2001 From: bwmf2 Date: Tue, 28 Feb 2023 06:04:56 +0100 Subject: [PATCH 17/26] Fix UI test --- .../ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs index b8b6f0846bb44..39ba1714cc70b 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs @@ -164,7 +164,7 @@ fn main() { // mac call // match - [ match elem { _ => elem } == 3 ] => "Assertion failed: match elem { _ => elem, } == 3" + [ match elem { _ => elem } == 3 ] => "Assertion failed: (match elem { _ => elem, }) == 3" // ret [ (|| { return elem; })() == 3 ] => "Assertion failed: (|| { return elem; })() == 3" From 219195fc4c98649785154e2c66075be716bc0c01 Mon Sep 17 00:00:00 2001 From: bwmf2 Date: Tue, 28 Feb 2023 06:05:45 +0100 Subject: [PATCH 18/26] Add UI test --- tests/ui/macros/issue-98790.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/ui/macros/issue-98790.rs diff --git a/tests/ui/macros/issue-98790.rs b/tests/ui/macros/issue-98790.rs new file mode 100644 index 0000000000000..8fe6fc41d10b7 --- /dev/null +++ b/tests/ui/macros/issue-98790.rs @@ -0,0 +1,24 @@ +// run-pass + +macro_rules! stringify_item { + ($item:item) => { + stringify!($item) + }; +} + +macro_rules! repro { + ($expr:expr) => { + stringify_item! { + pub fn repro() -> bool { + $expr + } + } + }; +} + +fn main() { + assert_eq!( + repro!(match () { () => true } | true), + "pub fn repro() -> bool { (match () { () => true, }) | true }" + ); +} From 1ccb1de5992dce38f7b8a941ee390a4f9aee1159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 3 Mar 2023 04:54:42 +0100 Subject: [PATCH 19/26] Place size limits on query keys and values --- compiler/rustc_middle/src/ty/query.rs | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 2bc51baf87905..9d41e4af959c7 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -250,6 +250,36 @@ macro_rules! define_callbacks { )* } + $( + // Ensure that keys grow no larger than 64 bytes + #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] + const _: () = { + if mem::size_of::>() > 64 { + panic!("{}", concat!( + "the query `", + stringify!($name), + "` has a key type `", + stringify!($($K)*), + "` that is too large" + )); + } + }; + + // Ensure that values grow no larger than 64 bytes + #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] + const _: () = { + if mem::size_of::>() > 64 { + panic!("{}", concat!( + "the query `", + stringify!($name), + "` has a value type `", + stringify!($V), + "` that is too large" + )); + } + }; + )* + pub struct QueryArenas<'tcx> { $($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*] (WorkerLocal::Target>>) From 27ee6703e97520cf8366437a1d54d044fe306319 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Fri, 3 Mar 2023 23:55:50 -0800 Subject: [PATCH 20/26] review --- library/std/src/sys/mod.rs | 45 ++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 4be4e873ffcee..bd3329e99a6fd 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -83,10 +83,12 @@ cfg_if::cfg_if! { pub use crate::android::log2f32; pub use crate::android::log2f64; } else { + #[inline] pub fn log2f32(n: f32) -> f32 { unsafe { crate::intrinsics::log2f32(n) } } + #[inline] pub fn log2f64(n: f64) -> f64 { unsafe { crate::intrinsics::log2f64(n) } } @@ -97,28 +99,29 @@ cfg_if::cfg_if! { // because of their non-standard behavior (e.g., log(-n) returns -Inf instead // of expected NaN). #[cfg(not(test))] -cfg_if::cfg_if! { - if #[cfg(any(target_os = "solaris", target_os = "illumos"))] { - pub fn log_wrapper f64>(n: f64, log_fn: F) -> f64 { - if n.is_finite() { - if n > 0.0 { - log_fn(n) - } else if n == 0.0 { - f64::NEG_INFINITY // log(0) = -Inf - } else { - f64::NAN // log(-n) = NaN - } - } else if n.is_nan() { - n // log(NaN) = NaN - } else if n > 0.0 { - n // log(Inf) = Inf - } else { - f64::NAN // log(-Inf) = NaN - } - } - } else { - pub fn log_wrapper f64>(n: f64, log_fn: F) -> f64 { +#[cfg(any(target_os = "solaris", target_os = "illumos"))] +#[inline] +pub fn log_wrapper f64>(n: f64, log_fn: F) -> f64 { + if n.is_finite() { + if n > 0.0 { log_fn(n) + } else if n == 0.0 { + f64::NEG_INFINITY // log(0) = -Inf + } else { + f64::NAN // log(-n) = NaN } + } else if n.is_nan() { + n // log(NaN) = NaN + } else if n > 0.0 { + n // log(Inf) = Inf + } else { + f64::NAN // log(-Inf) = NaN } } + +#[cfg(not(test))] +#[cfg(not(any(target_os = "solaris", target_os = "illumos")))] +#[inline] +pub fn log_wrapper f64>(n: f64, log_fn: F) -> f64 { + log_fn(n) +} 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 21/26] 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 de2e16cf715572b19b0c980af2f834c1e9e0e958 Mon Sep 17 00:00:00 2001 From: 823984418 <823984418@qq.com> Date: Sat, 4 Mar 2023 22:51:23 +0800 Subject: [PATCH 22/26] Prevent the `start_bx` basic block in codegen from having two `Builder`s at the same time --- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 2ec9fdbf44f11..8db81b793eab6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -258,6 +258,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Apply debuginfo to the newly allocated locals. fx.debug_introduce_locals(&mut start_bx); + drop(start_bx); + // Codegen the body of each block using reverse postorder for (bb, _) in traversal::reverse_postorder(&mir) { fx.codegen_block(bb); From ef807cb321604ae96ed0f78c78e3e9348d6d11ba Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 23 Dec 2022 14:59:42 +0000 Subject: [PATCH 23/26] 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 24/26] 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 871b4feba648981f7451d2c65c60771a2af19618 Mon Sep 17 00:00:00 2001 From: 823984418 <823984418@qq.com> Date: Wed, 8 Mar 2023 11:19:12 +0800 Subject: [PATCH 25/26] Add a comment about drop(start_bx) --- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 8db81b793eab6..5cffca5230a8f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -258,6 +258,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Apply debuginfo to the newly allocated locals. fx.debug_introduce_locals(&mut start_bx); + // The builders will be created separately for each basic block at `codegen_block`. + // So drop the builder of `start_llbb` to avoid having two at the same time. drop(start_bx); // Codegen the body of each block using reverse postorder From 7d402681dd8f7c46bc00c60237c13a19d374e8b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 8 Mar 2023 22:14:06 +0100 Subject: [PATCH 26/26] tidy: bump ROOT_ENTRY_LIMIT by ten --- src/tools/tidy/src/ui_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 15c36923e885f..6900727558a28 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -9,7 +9,7 @@ use std::path::Path; const ENTRY_LIMIT: usize = 1000; // FIXME: The following limits should be reduced eventually. -const ROOT_ENTRY_LIMIT: usize = 940; +const ROOT_ENTRY_LIMIT: usize = 950; const ISSUES_ENTRY_LIMIT: usize = 1978; fn check_entries(path: &Path, bad: &mut bool) {