From 69803f788819442900ba3ab5b937c928d50f81ce Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Sat, 15 Jan 2022 22:22:22 +0100 Subject: [PATCH 01/17] Make `span_extend_to_prev_str()` more robust --- compiler/rustc_resolve/src/diagnostics.rs | 38 ++++++++++----------- compiler/rustc_span/src/source_map.rs | 40 +++++++++++++++-------- src/test/ui/asm/x86_64/parse-error.stderr | 14 ++++---- src/test/ui/consts/issue-91560.fixed | 21 ++++++++++++ src/test/ui/consts/issue-91560.rs | 21 ++++++++++++ src/test/ui/consts/issue-91560.stderr | 21 ++++++++++++ 6 files changed, 116 insertions(+), 39 deletions(-) create mode 100644 src/test/ui/consts/issue-91560.fixed create mode 100644 src/test/ui/consts/issue-91560.rs create mode 100644 src/test/ui/consts/issue-91560.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c7edcb077b917..1f657218a64a9 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -453,28 +453,28 @@ impl<'a> Resolver<'a> { // edit: // only do this if the const and usage of the non-constant value are on the same line // the further the two are apart, the higher the chance of the suggestion being wrong - // also make sure that the pos for the suggestion is not 0 (ICE #90878) - let sp = - self.session.source_map().span_extend_to_prev_str(ident.span, current, true); - - let pos_for_suggestion = sp.lo().0.saturating_sub(current.len() as u32); + let sp = self + .session + .source_map() + .span_extend_to_prev_str(ident.span, current, true, false); - if sp.lo().0 == 0 - || pos_for_suggestion == 0 - || self.session.source_map().is_multiline(sp) - { - err.span_label(ident.span, &format!("this would need to be a `{}`", sugg)); - } else { - let sp = sp.with_lo(BytePos(pos_for_suggestion)); - err.span_suggestion( - sp, - &format!("consider using `{}` instead of `{}`", sugg, current), - format!("{} {}", sugg, ident), - Applicability::MaybeIncorrect, - ); - err.span_label(span, "non-constant value"); + match sp { + Some(sp) if !self.session.source_map().is_multiline(sp) => { + let sp = sp.with_lo(BytePos(sp.lo().0 - (current.len() as u32))); + err.span_suggestion( + sp, + &format!("consider using `{}` instead of `{}`", sugg, current), + format!("{} {}", sugg, ident), + Applicability::MaybeIncorrect, + ); + err.span_label(span, "non-constant value"); + } + _ => { + err.span_label(ident.span, &format!("this would need to be a `{}`", sugg)); + } } + err } ResolutionError::BindingShadowsSomethingUnacceptable { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 7414d201f511d..95177102dcf86 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -629,26 +629,41 @@ impl SourceMap { } /// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by - /// whitespace. Returns the same span if no character could be found or if an error occurred - /// while retrieving the code snippet. - pub fn span_extend_to_prev_str(&self, sp: Span, pat: &str, accept_newlines: bool) -> Span { + /// whitespace. Returns None if the pattern could not be found or if an error occurred while + /// retrieving the code snippet. + pub fn span_extend_to_prev_str( + &self, + sp: Span, + pat: &str, + accept_newlines: bool, + include_whitespace: bool, + ) -> Option { // assure that the pattern is delimited, to avoid the following // fn my_fn() // ^^^^ returned span without the check // ---------- correct span + let prev_source = self.span_to_prev_source(sp).ok()?; for ws in &[" ", "\t", "\n"] { let pat = pat.to_owned() + ws; - if let Ok(prev_source) = self.span_to_prev_source(sp) { - let prev_source = prev_source.rsplit(&pat).next().unwrap_or("").trim_start(); - if prev_source.is_empty() && sp.lo().0 != 0 { - return sp.with_lo(BytePos(sp.lo().0 - 1)); - } else if accept_newlines || !prev_source.contains('\n') { - return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32)); + if let Some(pat_pos) = prev_source.rfind(&pat) { + let just_after_pat_pos = pat_pos + pat.len() - 1; + let just_after_pat_plus_ws = if include_whitespace { + just_after_pat_pos + + prev_source[just_after_pat_pos..] + .find(|c: char| !c.is_whitespace()) + .unwrap_or(0) + } else { + just_after_pat_pos + }; + let len = prev_source.len() - just_after_pat_plus_ws; + let prev_source = &prev_source[just_after_pat_plus_ws..]; + if accept_newlines || !prev_source.trim_start().contains('\n') { + return Some(sp.with_lo(BytePos(sp.lo().0 - len as u32))); } } } - sp + None } /// Returns the source snippet as `String` after the given `Span`. @@ -927,7 +942,7 @@ impl SourceMap { } pub fn generate_fn_name_span(&self, span: Span) -> Option { - let prev_span = self.span_extend_to_prev_str(span, "fn", true); + let prev_span = self.span_extend_to_prev_str(span, "fn", true, true).unwrap_or(span); if let Ok(snippet) = self.span_to_snippet(prev_span) { debug!( "generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}", @@ -968,8 +983,7 @@ impl SourceMap { pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> { // Try to extend the span to the previous "fn" keyword to retrieve the function // signature. - let sugg_span = self.span_extend_to_prev_str(span, "fn", false); - if sugg_span != span { + if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) { if let Ok(snippet) = self.span_to_snippet(sugg_span) { // Consume the function name. let mut offset = snippet diff --git a/src/test/ui/asm/x86_64/parse-error.stderr b/src/test/ui/asm/x86_64/parse-error.stderr index 2d0a7a94d5676..194cd66a66e96 100644 --- a/src/test/ui/asm/x86_64/parse-error.stderr +++ b/src/test/ui/asm/x86_64/parse-error.stderr @@ -394,7 +394,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:39:37 | LL | let mut foo = 0; - | ---------- help: consider using `const` instead of `let`: `const foo` + | ----------- help: consider using `const` instead of `let`: `const foo` ... LL | asm!("{}", options(), const foo); | ^^^ non-constant value @@ -403,7 +403,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:50:44 | LL | let mut foo = 0; - | ---------- help: consider using `const` instead of `let`: `const foo` + | ----------- help: consider using `const` instead of `let`: `const foo` ... LL | asm!("{}", clobber_abi("C"), const foo); | ^^^ non-constant value @@ -412,7 +412,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:57:31 | LL | let mut foo = 0; - | ---------- help: consider using `const` instead of `let`: `const foo` + | ----------- help: consider using `const` instead of `let`: `const foo` ... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value @@ -421,7 +421,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:57:46 | LL | let mut bar = 0; - | ---------- help: consider using `const` instead of `let`: `const bar` + | ----------- help: consider using `const` instead of `let`: `const bar` ... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value @@ -430,7 +430,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:64:46 | LL | let mut bar = 0; - | ---------- help: consider using `const` instead of `let`: `const bar` + | ----------- help: consider using `const` instead of `let`: `const bar` ... LL | asm!("{a}", in("eax") foo, a = const bar); | ^^^ non-constant value @@ -439,7 +439,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:67:46 | LL | let mut bar = 0; - | ---------- help: consider using `const` instead of `let`: `const bar` + | ----------- help: consider using `const` instead of `let`: `const bar` ... LL | asm!("{a}", in("eax") foo, a = const bar); | ^^^ non-constant value @@ -448,7 +448,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:70:42 | LL | let mut bar = 0; - | ---------- help: consider using `const` instead of `let`: `const bar` + | ----------- help: consider using `const` instead of `let`: `const bar` ... LL | asm!("{1}", in("eax") foo, const bar); | ^^^ non-constant value diff --git a/src/test/ui/consts/issue-91560.fixed b/src/test/ui/consts/issue-91560.fixed new file mode 100644 index 0000000000000..41b9d95734a8d --- /dev/null +++ b/src/test/ui/consts/issue-91560.fixed @@ -0,0 +1,21 @@ +// Regression test for issue #91560. + +// run-rustfix + +#![allow(unused,non_upper_case_globals)] + +fn foo() { + const length: usize = 2; + //~^ HELP: consider using `const` + let arr = [0; length]; + //~^ ERROR: attempt to use a non-constant value in a constant [E0435] +} + +fn bar() { + const length: usize = 2; + //~^ HELP: consider using `const` + let arr = [0; length]; + //~^ ERROR: attempt to use a non-constant value in a constant [E0435] +} + +fn main() {} diff --git a/src/test/ui/consts/issue-91560.rs b/src/test/ui/consts/issue-91560.rs new file mode 100644 index 0000000000000..04592feb50541 --- /dev/null +++ b/src/test/ui/consts/issue-91560.rs @@ -0,0 +1,21 @@ +// Regression test for issue #91560. + +// run-rustfix + +#![allow(unused,non_upper_case_globals)] + +fn foo() { + let mut length: usize = 2; + //~^ HELP: consider using `const` + let arr = [0; length]; + //~^ ERROR: attempt to use a non-constant value in a constant [E0435] +} + +fn bar() { + let length: usize = 2; + //~^ HELP: consider using `const` + let arr = [0; length]; + //~^ ERROR: attempt to use a non-constant value in a constant [E0435] +} + +fn main() {} diff --git a/src/test/ui/consts/issue-91560.stderr b/src/test/ui/consts/issue-91560.stderr new file mode 100644 index 0000000000000..e1b5d4cacf8e3 --- /dev/null +++ b/src/test/ui/consts/issue-91560.stderr @@ -0,0 +1,21 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/issue-91560.rs:10:19 + | +LL | let mut length: usize = 2; + | -------------- help: consider using `const` instead of `let`: `const length` +LL | +LL | let arr = [0; length]; + | ^^^^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/issue-91560.rs:17:19 + | +LL | let length: usize = 2; + | ------------ help: consider using `const` instead of `let`: `const length` +LL | +LL | let arr = [0; length]; + | ^^^^^^ non-constant value + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0435`. From 71ff16bcef2b384ea52d07fa9493507b7248a9c4 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Mon, 31 Jan 2022 20:43:41 +0100 Subject: [PATCH 02/17] Update test output for `ui/asm/aarch64/parse-error.rs` --- src/test/ui/asm/aarch64/parse-error.stderr | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/ui/asm/aarch64/parse-error.stderr b/src/test/ui/asm/aarch64/parse-error.stderr index d80ab921fb83e..3f705ba5b64c2 100644 --- a/src/test/ui/asm/aarch64/parse-error.stderr +++ b/src/test/ui/asm/aarch64/parse-error.stderr @@ -382,7 +382,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:39:37 | LL | let mut foo = 0; - | ---------- help: consider using `const` instead of `let`: `const foo` + | ----------- help: consider using `const` instead of `let`: `const foo` ... LL | asm!("{}", options(), const foo); | ^^^ non-constant value @@ -391,7 +391,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:48:44 | LL | let mut foo = 0; - | ---------- help: consider using `const` instead of `let`: `const foo` + | ----------- help: consider using `const` instead of `let`: `const foo` ... LL | asm!("{}", clobber_abi("C"), const foo); | ^^^ non-constant value @@ -400,7 +400,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:55:31 | LL | let mut foo = 0; - | ---------- help: consider using `const` instead of `let`: `const foo` + | ----------- help: consider using `const` instead of `let`: `const foo` ... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value @@ -409,7 +409,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:55:46 | LL | let mut bar = 0; - | ---------- help: consider using `const` instead of `let`: `const bar` + | ----------- help: consider using `const` instead of `let`: `const bar` ... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value @@ -418,7 +418,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:62:45 | LL | let mut bar = 0; - | ---------- help: consider using `const` instead of `let`: `const bar` + | ----------- help: consider using `const` instead of `let`: `const bar` ... LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value @@ -427,7 +427,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:65:45 | LL | let mut bar = 0; - | ---------- help: consider using `const` instead of `let`: `const bar` + | ----------- help: consider using `const` instead of `let`: `const bar` ... LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value @@ -436,7 +436,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:68:41 | LL | let mut bar = 0; - | ---------- help: consider using `const` instead of `let`: `const bar` + | ----------- help: consider using `const` instead of `let`: `const bar` ... LL | asm!("{1}", in("x0") foo, const bar); | ^^^ non-constant value From 2d0bb0d4b9b072ebd2cb78c71f3ca3a706b5d12e Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Fri, 4 Feb 2022 19:47:34 +0000 Subject: [PATCH 03/17] jsondocck: Improved error messages for invalid json value and failed @count check --- src/tools/jsondocck/src/main.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index b8ea10f3d2277..d0f476955e1f7 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -231,7 +231,21 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let val = cache.get_value(&command.args[0])?; let results = select(&val, &command.args[1]).unwrap(); - results.len() == expected + let eq = results.len() == expected; + if !command.negated && !eq { + return Err(CkError::FailedCheck( + format!( + "`{}` matched to `{:?}` with length {}, but expected length {}", + &command.args[1], + results, + results.len(), + expected + ), + command, + )); + } else { + eq + } } CommandKind::Is => { // @has = check *exactly one* item matched by path, and it equals value @@ -317,6 +331,6 @@ fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> { panic!("No variable: `{}`. Current state: `{:?}`", &s[1..], cache.variables) })) } else { - Cow::Owned(serde_json::from_str(s).unwrap()) + Cow::Owned(serde_json::from_str(s).expect(&format!("Cannot convert `{}` to json", s))) } } From bf0e862903c4a799dd08dd00ffe68f9756fc6eb1 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Fri, 4 Feb 2022 19:49:18 +0000 Subject: [PATCH 04/17] rustdoc-json: Add some tests for `typealias` item --- src/test/rustdoc-json/type/dyn.rs | 21 ++++++++++++ src/test/rustdoc-json/type/fn_lifetime.rs | 28 ++++++++++++++++ src/test/rustdoc-json/type/generic_default.rs | 33 +++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 src/test/rustdoc-json/type/dyn.rs create mode 100644 src/test/rustdoc-json/type/fn_lifetime.rs create mode 100644 src/test/rustdoc-json/type/generic_default.rs diff --git a/src/test/rustdoc-json/type/dyn.rs b/src/test/rustdoc-json/type/dyn.rs new file mode 100644 index 0000000000000..f53dc03f4b47f --- /dev/null +++ b/src/test/rustdoc-json/type/dyn.rs @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items" 1 +// @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id" +// @is - "$.index[*][?(@.name=='dyn')].inner.items[0]" $sync_int_gen + +// @is - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}' +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.kind" \"resolved_path\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" [] +// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1 +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.name" \"Fn\" +// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[*]" 3 +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[0].trait_bound.trait.inner.name" \"Send\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[1].trait_bound.trait.inner.name" \"Sync\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}' +pub type SyncIntGen = Box i32 + Send + Sync + 'static>; diff --git a/src/test/rustdoc-json/type/fn_lifetime.rs b/src/test/rustdoc-json/type/fn_lifetime.rs new file mode 100644 index 0000000000000..e0d1e9649a0aa --- /dev/null +++ b/src/test/rustdoc-json/type/fn_lifetime.rs @@ -0,0 +1,28 @@ +// ignore-tidy-linelength + +// @is fn_lifetime.json "$.index[*][?(@.name=='GenericFn')].kind" \"typedef\" + +// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*]" 1 +// @is - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].name" \"\'a\" +// @has - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime" +// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime.outlives[*]" 0 +// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.where_predicates[*]" 0 +// @is - "$.index[*][?(@.name=='GenericFn')].inner.type.kind" \"function_pointer\" +// @count - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.generic_params[*]" 0 +// @count - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.inputs[*]" 1 +// @is - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.inputs[*][1].inner.lifetime" \"\'a\" +// @is - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.output.inner.lifetime" \"\'a\" + +pub type GenericFn<'a> = fn(&'a i32) -> &'a i32; + +// @is fn_lifetime.json "$.index[*][?(@.name=='ForAll')].kind" \"typedef\" +// @count - "$.index[*][?(@.name=='ForAll')].inner.generics.params[*]" 0 +// @count - "$.index[*][?(@.name=='ForAll')].inner.generics.where_predicates[*]" 0 +// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*]" 1 +// @is - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].name" \"\'a\" +// @has - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].kind.lifetime" +// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].kind.lifetime.outlives[*]" 0 +// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.inputs[*]" 1 +// @is - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.inputs[*][1].inner.lifetime" \"\'a\" +// @is - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.output.inner.lifetime" \"\'a\" +pub type ForAll = for<'a> fn(&'a i32) -> &'a i32; diff --git a/src/test/rustdoc-json/type/generic_default.rs b/src/test/rustdoc-json/type/generic_default.rs new file mode 100644 index 0000000000000..b6bb6dcc5fe2d --- /dev/null +++ b/src/test/rustdoc-json/type/generic_default.rs @@ -0,0 +1,33 @@ +// ignore-tidy-linelength + +// @set result = generic_default.json "$.index[*][?(@.name=='Result')].id" +pub enum Result { + Ok(T), + Err(E), +} + +// @set my_error = - "$.index[*][?(@.name=='MyError')].id" +pub struct MyError {} + +// @is - "$.index[*][?(@.name=='MyResult')].kind" \"typedef\" +// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.where_predicates[*]" 0 +// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[*]" 2 +// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].name" \"T\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].name" \"E\" +// @has - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type" +// @has - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type" +// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type.bounds[*]" 0 +// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.bounds[*]" 0 +// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type.default" null +// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.kind" \"resolved_path\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.inner.id" $my_error +// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.inner.name" \"MyError\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.kind" \"resolved_path\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.id" $result +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.name" \"Result\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.bindings" [] +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"generic\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[1].type.kind" \"generic\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[0].type.inner" \"T\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[1].type.inner" \"E\" +pub type MyResult = Result; From 1115f15e1cba09c60a9a1fe006941c562e91d348 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 17 Nov 2021 03:18:15 +0900 Subject: [PATCH 05/17] windows: Map `ERROR_INVALID_NAME` as `InvalidInput` --- library/std/src/sys/windows/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index c70f254cf39f8..4ec9437700e02 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -71,7 +71,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { c::ERROR_FILE_NOT_FOUND => return NotFound, c::ERROR_PATH_NOT_FOUND => return NotFound, c::ERROR_NO_DATA => return BrokenPipe, - c::ERROR_INVALID_PARAMETER => return InvalidInput, + c::ERROR_INVALID_PARAMETER | c::ERROR_INVALID_NAME => return InvalidInput, c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory, c::ERROR_SEM_TIMEOUT | c::WAIT_TIMEOUT From 755e475c8b518e4ad9ba79adead4ea8c8a268c22 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 31 Jan 2022 17:24:10 +0900 Subject: [PATCH 06/17] Rename `FilenameTooLong` to `FilenameInvalid` --- library/std/src/io/error.rs | 4 ++-- library/std/src/sys/unix/mod.rs | 2 +- library/std/src/sys/windows/mod.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 4b55324a2424c..c55f3c19ab60f 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -301,7 +301,7 @@ pub enum ErrorKind { /// The limit might be from the underlying filesystem or API, or an administratively imposed /// resource limit. #[unstable(feature = "io_error_more", issue = "86442")] - FilenameTooLong, + FilenameInvalid, /// Program argument list too long. /// /// When trying to run an external program, a system or process limit on the size of the @@ -382,7 +382,7 @@ impl ErrorKind { DirectoryNotEmpty => "directory not empty", ExecutableFileBusy => "executable file busy", FileTooLarge => "file too large", - FilenameTooLong => "filename too long", + FilenameInvalid => "filename too long", FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)", FilesystemQuotaExceeded => "filesystem quota exceeded", HostUnreachable => "host unreachable", diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 6382354eb6ebd..863b6c7c5a7ba 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -159,7 +159,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { libc::ENOSPC => StorageFull, libc::ENOSYS => Unsupported, libc::EMLINK => TooManyLinks, - libc::ENAMETOOLONG => FilenameTooLong, + libc::ENAMETOOLONG => FilenameInvalid, libc::ENETDOWN => NetworkDown, libc::ENETUNREACH => NetworkUnreachable, libc::ENOTCONN => NotConnected, diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 4ec9437700e02..57a25a0f30ab2 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -104,7 +104,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { c::ERROR_POSSIBLE_DEADLOCK => return Deadlock, c::ERROR_NOT_SAME_DEVICE => return CrossesDevices, c::ERROR_TOO_MANY_LINKS => return TooManyLinks, - c::ERROR_FILENAME_EXCED_RANGE => return FilenameTooLong, + c::ERROR_FILENAME_EXCED_RANGE => return FilenameInvalid, _ => {} } From cc9407924decf5212177769ff4740665047517d9 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 31 Jan 2022 17:28:05 +0900 Subject: [PATCH 07/17] Map `ERROR_INVALID_NAME` to `FilenameInvalid` --- library/std/src/sys/windows/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 57a25a0f30ab2..6d97bf42f6f56 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -71,7 +71,8 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { c::ERROR_FILE_NOT_FOUND => return NotFound, c::ERROR_PATH_NOT_FOUND => return NotFound, c::ERROR_NO_DATA => return BrokenPipe, - c::ERROR_INVALID_PARAMETER | c::ERROR_INVALID_NAME => return InvalidInput, + c::ERROR_INVALID_NAME => return FilenameInvalid, + c::ERROR_INVALID_PARAMETER => return InvalidInput, c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory, c::ERROR_SEM_TIMEOUT | c::WAIT_TIMEOUT From 861f3c70a27d007ed8113fe776aa393d8e25faa0 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 31 Jan 2022 09:17:34 -0800 Subject: [PATCH 08/17] Fix description of FilenameInvalid Co-authored-by: Mara Bos --- library/std/src/io/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index c55f3c19ab60f..90766d4acefdd 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -382,7 +382,7 @@ impl ErrorKind { DirectoryNotEmpty => "directory not empty", ExecutableFileBusy => "executable file busy", FileTooLarge => "file too large", - FilenameInvalid => "filename too long", + FilenameInvalid => "filename invalid", FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)", FilesystemQuotaExceeded => "filesystem quota exceeded", HostUnreachable => "host unreachable", From a898b31662aee14c9aaa46f39377724c7ae590b5 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 10 Feb 2022 23:49:27 +0900 Subject: [PATCH 09/17] Rename to `InvalidFilename` --- library/std/src/io/error.rs | 9 ++++----- library/std/src/io/error/repr_bitpacked.rs | 2 +- library/std/src/sys/unix/mod.rs | 2 +- library/std/src/sys/windows/mod.rs | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 90766d4acefdd..1aa6d65788912 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -296,12 +296,11 @@ pub enum ErrorKind { /// The filesystem does not support making so many hardlinks to the same file. #[unstable(feature = "io_error_more", issue = "86442")] TooManyLinks, - /// Filename too long. + /// A filename was invalid. /// - /// The limit might be from the underlying filesystem or API, or an administratively imposed - /// resource limit. + /// This error can also cause if it exceeded the filename length limit. #[unstable(feature = "io_error_more", issue = "86442")] - FilenameInvalid, + InvalidFilename, /// Program argument list too long. /// /// When trying to run an external program, a system or process limit on the size of the @@ -382,12 +381,12 @@ impl ErrorKind { DirectoryNotEmpty => "directory not empty", ExecutableFileBusy => "executable file busy", FileTooLarge => "file too large", - FilenameInvalid => "filename invalid", FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)", FilesystemQuotaExceeded => "filesystem quota exceeded", HostUnreachable => "host unreachable", Interrupted => "operation interrupted", InvalidData => "invalid data", + InvalidFilename => "invalid filename", InvalidInput => "invalid input parameter", IsADirectory => "is a directory", NetworkDown => "network down", diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index f317368e8e59d..4301e941b3dce 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -315,7 +315,7 @@ fn kind_from_prim(ek: u32) -> Option { Deadlock, CrossesDevices, TooManyLinks, - FilenameTooLong, + InvalidFilename, ArgumentListTooLong, Interrupted, Other, diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 863b6c7c5a7ba..605cc499b3c92 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -159,7 +159,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { libc::ENOSPC => StorageFull, libc::ENOSYS => Unsupported, libc::EMLINK => TooManyLinks, - libc::ENAMETOOLONG => FilenameInvalid, + libc::ENAMETOOLONG => InvalidFilename, libc::ENETDOWN => NetworkDown, libc::ENETUNREACH => NetworkUnreachable, libc::ENOTCONN => NotConnected, diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 6d97bf42f6f56..dc288176346bc 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -71,7 +71,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { c::ERROR_FILE_NOT_FOUND => return NotFound, c::ERROR_PATH_NOT_FOUND => return NotFound, c::ERROR_NO_DATA => return BrokenPipe, - c::ERROR_INVALID_NAME => return FilenameInvalid, + c::ERROR_INVALID_NAME => return InvalidFilename, c::ERROR_INVALID_PARAMETER => return InvalidInput, c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory, c::ERROR_SEM_TIMEOUT @@ -105,7 +105,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { c::ERROR_POSSIBLE_DEADLOCK => return Deadlock, c::ERROR_NOT_SAME_DEVICE => return CrossesDevices, c::ERROR_TOO_MANY_LINKS => return TooManyLinks, - c::ERROR_FILENAME_EXCED_RANGE => return FilenameInvalid, + c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename, _ => {} } From d39a6377e9cfa108eb181ea892366e6b01fd753f Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 31 Jan 2022 13:04:27 +0000 Subject: [PATCH 10/17] Split PAuth target feature --- compiler/rustc_codegen_llvm/src/attributes.rs | 31 ++++++++++-- compiler/rustc_codegen_llvm/src/llvm_util.rs | 49 ++++++++++++++++--- .../rustc_codegen_ssa/src/target_features.rs | 15 +++++- .../tied-features-cli.one.stderr | 4 ++ .../ui/target-feature/tied-features-cli.rs | 9 ++++ .../tied-features-cli.three.stderr | 4 ++ .../tied-features-cli.two.stderr | 4 ++ src/test/ui/target-feature/tied-features.rs | 29 +++++++++++ .../ui/target-feature/tied-features.stderr | 18 +++++++ 9 files changed, 148 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/target-feature/tied-features-cli.one.stderr create mode 100644 src/test/ui/target-feature/tied-features-cli.rs create mode 100644 src/test/ui/target-feature/tied-features-cli.three.stderr create mode 100644 src/test/ui/target-feature/tied-features-cli.two.stderr create mode 100644 src/test/ui/target-feature/tied-features.rs create mode 100644 src/test/ui/target-feature/tied-features.stderr diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 7f82ce307d526..2472789601e70 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -322,12 +322,33 @@ pub fn from_fn_attrs<'ll, 'tcx>( // The target doesn't care; the subtarget reads our attribute. apply_tune_cpu_attr(cx, llfn); - let mut function_features = codegen_fn_attrs - .target_features + let function_features = + codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::>(); + + if let Some(f) = llvm_util::check_tied_features( + cx.tcx.sess, + &function_features.iter().map(|f| (*f, true)).collect(), + ) { + let span = cx + .tcx + .get_attrs(instance.def_id()) + .iter() + .find(|a| a.has_name(rustc_span::sym::target_feature)) + .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); + let msg = format!( + "the target features {} must all be either enabled or disabled together", + f.join(", ") + ); + let mut err = cx.tcx.sess.struct_span_err(span, &msg); + err.help("add the missing features in a `target_feature` attribute"); + err.emit(); + return; + } + + let mut function_features = function_features .iter() - .flat_map(|f| { - let feature = f.as_str(); - llvm_util::to_llvm_feature(cx.tcx.sess, feature) + .flat_map(|feat| { + llvm_util::to_llvm_feature(cx.tcx.sess, feat) .into_iter() .map(|f| format!("+{}", f)) .collect::>() diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index f91fad2d9c963..727d079d83d93 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -2,8 +2,8 @@ use crate::back::write::create_informational_target_machine; use crate::{llvm, llvm_util}; use libc::c_int; use libloading::Library; -use rustc_codegen_ssa::target_features::supported_target_features; -use rustc_data_structures::fx::FxHashSet; +use rustc_codegen_ssa::target_features::{supported_target_features, tied_target_features}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_fs_util::path_to_c_string; use rustc_middle::bug; use rustc_session::config::PrintRequest; @@ -191,10 +191,30 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> Vec<&'a str> { ("aarch64", "frintts") => vec!["fptoint"], ("aarch64", "fcma") => vec!["complxnum"], ("aarch64", "pmuv3") => vec!["perfmon"], + ("aarch64", "paca") => vec!["pauth"], + ("aarch64", "pacg") => vec!["pauth"], (_, s) => vec![s], } } +// Given a map from target_features to whether they are enabled or disabled, +// ensure only valid combinations are allowed. +pub fn check_tied_features( + sess: &Session, + features: &FxHashMap<&str, bool>, +) -> Option<&'static [&'static str]> { + for tied in tied_target_features(sess) { + // Tied features must be set to the same value, or not set at all + let mut tied_iter = tied.iter(); + let enabled = features.get(tied_iter.next().unwrap()); + + if tied_iter.any(|f| enabled != features.get(f)) { + return Some(tied); + } + } + None +} + pub fn target_features(sess: &Session) -> Vec { let target_machine = create_informational_target_machine(sess); supported_target_features(sess) @@ -395,15 +415,19 @@ pub fn llvm_global_features(sess: &Session) -> Vec { Some(_) | None => {} }; + fn strip(s: &str) -> &str { + s.strip_prefix(&['+', '-']).unwrap_or(s) + } + let filter = |s: &str| { if s.is_empty() { return vec![]; } - let feature = if s.starts_with('+') || s.starts_with('-') { - &s[1..] - } else { + let feature = strip(s); + if feature == s { return vec![s.to_string()]; - }; + } + // Rustc-specific feature requests like `+crt-static` or `-crt-static` // are not passed down to LLVM. if RUSTC_SPECIFIC_FEATURES.contains(&feature) { @@ -420,8 +444,17 @@ pub fn llvm_global_features(sess: &Session) -> Vec { features.extend(sess.target.features.split(',').flat_map(&filter)); // -Ctarget-features - features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter)); - + let feats: Vec<&str> = sess.opts.cg.target_feature.split(',').collect(); + // LLVM enables based on the last occurence of a feature + if let Some(f) = + check_tied_features(sess, &feats.iter().map(|f| (strip(f), !f.starts_with("-"))).collect()) + { + sess.err(&format!( + "Target features {} must all be enabled or disabled together", + f.join(", ") + )); + } + features.extend(feats.iter().flat_map(|&f| filter(f))); features } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 63cc6faf9ec5e..f31b0ee592e9c 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -74,8 +74,10 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("ssbs", Some(sym::aarch64_target_feature)), // FEAT_SB ("sb", Some(sym::aarch64_target_feature)), - // FEAT_PAUTH - ("pauth", Some(sym::aarch64_target_feature)), + // FEAT_PAUTH (address authentication) + ("paca", Some(sym::aarch64_target_feature)), + // FEAT_PAUTH (generic authentication) + ("pacg", Some(sym::aarch64_target_feature)), // FEAT_DPB ("dpb", Some(sym::aarch64_target_feature)), // FEAT_DPB2 @@ -137,6 +139,8 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("v8.7a", Some(sym::aarch64_target_feature)), ]; +const AARCH64_TIED_FEATURES: &[&[&str]] = &[&["paca", "pacg"]]; + const X86_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("adx", Some(sym::adx_target_feature)), ("aes", None), @@ -256,6 +260,13 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt } } +pub fn tied_target_features(sess: &Session) -> &'static [&'static [&'static str]] { + match &*sess.target.arch { + "aarch64" => AARCH64_TIED_FEATURES, + _ => &[], + } +} + pub(crate) fn provide(providers: &mut Providers) { providers.supported_target_features = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); diff --git a/src/test/ui/target-feature/tied-features-cli.one.stderr b/src/test/ui/target-feature/tied-features-cli.one.stderr new file mode 100644 index 0000000000000..2bc64a76aae8d --- /dev/null +++ b/src/test/ui/target-feature/tied-features-cli.one.stderr @@ -0,0 +1,4 @@ +error: Target features paca, pacg must all be enabled or disabled together + +error: aborting due to previous error + diff --git a/src/test/ui/target-feature/tied-features-cli.rs b/src/test/ui/target-feature/tied-features-cli.rs new file mode 100644 index 0000000000000..ea09d4fc46093 --- /dev/null +++ b/src/test/ui/target-feature/tied-features-cli.rs @@ -0,0 +1,9 @@ +// only-aarch64 +// revisions: one two three four +//[one] compile-flags: -C target-feature=+paca +//[two] compile-flags: -C target-feature=-pacg,+pacg +//[three] compile-flags: -C target-feature=+paca,+pacg,-paca +//[four] check-pass +//[four] compile-flags: -C target-feature=-paca,+pacg -C target-feature=+paca + +fn main() {} diff --git a/src/test/ui/target-feature/tied-features-cli.three.stderr b/src/test/ui/target-feature/tied-features-cli.three.stderr new file mode 100644 index 0000000000000..2bc64a76aae8d --- /dev/null +++ b/src/test/ui/target-feature/tied-features-cli.three.stderr @@ -0,0 +1,4 @@ +error: Target features paca, pacg must all be enabled or disabled together + +error: aborting due to previous error + diff --git a/src/test/ui/target-feature/tied-features-cli.two.stderr b/src/test/ui/target-feature/tied-features-cli.two.stderr new file mode 100644 index 0000000000000..2bc64a76aae8d --- /dev/null +++ b/src/test/ui/target-feature/tied-features-cli.two.stderr @@ -0,0 +1,4 @@ +error: Target features paca, pacg must all be enabled or disabled together + +error: aborting due to previous error + diff --git a/src/test/ui/target-feature/tied-features.rs b/src/test/ui/target-feature/tied-features.rs new file mode 100644 index 0000000000000..86400361db314 --- /dev/null +++ b/src/test/ui/target-feature/tied-features.rs @@ -0,0 +1,29 @@ +// only-aarch64 +// build-fail + +#![feature(aarch64_target_feature, target_feature_11)] + +fn main() { + #[target_feature(enable = "pacg")] + //~^ ERROR must all be either enabled or disabled together + unsafe fn inner() {} + + unsafe { + foo(); + bar(); + baz(); + inner(); + } +} + +#[target_feature(enable = "paca")] +//~^ ERROR must all be either enabled or disabled together +unsafe fn foo() {} + + +#[target_feature(enable = "paca,pacg")] +unsafe fn bar() {} + +#[target_feature(enable = "paca")] +#[target_feature(enable = "pacg")] +unsafe fn baz() {} diff --git a/src/test/ui/target-feature/tied-features.stderr b/src/test/ui/target-feature/tied-features.stderr new file mode 100644 index 0000000000000..0b1460e0b753f --- /dev/null +++ b/src/test/ui/target-feature/tied-features.stderr @@ -0,0 +1,18 @@ +error: the target features paca, pacg must all be either enabled or disabled together + --> $DIR/tied-features.rs:7:5 + | +LL | #[target_feature(enable = "pacg")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add the missing features in a `target_feature` attribute + +error: the target features paca, pacg must all be either enabled or disabled together + --> $DIR/tied-features.rs:19:1 + | +LL | #[target_feature(enable = "paca")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add the missing features in a `target_feature` attribute + +error: aborting due to 2 previous errors + From 20e6c1d0139df1ec315bdbfa7c46dc98fafa84ab Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 10 Feb 2022 18:04:09 +0000 Subject: [PATCH 11/17] Fix incorrect register conflict detection in asm! This would previously incorrectly reject two subregisters that were distinct but part of the same larger register, for example `al` and `ah`. --- compiler/rustc_ast_lowering/src/asm.rs | 4 +++- src/test/ui/asm/reg-conflict.rs | 20 ++++++++++++++++++++ src/test/ui/asm/reg-conflict.stderr | 10 ++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/asm/reg-conflict.rs create mode 100644 src/test/ui/asm/reg-conflict.stderr diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 89d411d4b36fe..5a85356d96daa 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -373,7 +373,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { err.emit(); } Entry::Vacant(v) => { - v.insert(idx); + if r == reg { + v.insert(idx); + } } } }; diff --git a/src/test/ui/asm/reg-conflict.rs b/src/test/ui/asm/reg-conflict.rs new file mode 100644 index 0000000000000..983788a93ccd9 --- /dev/null +++ b/src/test/ui/asm/reg-conflict.rs @@ -0,0 +1,20 @@ +// compile-flags: --target armv7-unknown-linux-gnueabihf +// needs-llvm-components: arm + +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[lang = "sized"] +trait Sized {} + +fn main() { + unsafe { + asm!("", out("d0") _, out("d1") _); + asm!("", out("d0") _, out("s1") _); + //~^ ERROR register `s1` conflicts with register `d0` + } +} diff --git a/src/test/ui/asm/reg-conflict.stderr b/src/test/ui/asm/reg-conflict.stderr new file mode 100644 index 0000000000000..2395566de3945 --- /dev/null +++ b/src/test/ui/asm/reg-conflict.stderr @@ -0,0 +1,10 @@ +error: register `s1` conflicts with register `d0` + --> $DIR/reg-conflict.rs:17:31 + | +LL | asm!("", out("d0") _, out("s1") _); + | ----------- ^^^^^^^^^^^ register `s1` + | | + | register `d0` + +error: aborting due to previous error + From 1f98ef7793dde6c3a3c216d55ae5858da7e0c34e Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 10 Feb 2022 18:26:12 -0800 Subject: [PATCH 12/17] Implement `AsFd` for `&T` and `&mut T`. Add implementations of `AsFd` for `&T` and `&mut T`, so that users can write code like this: ```rust pub fn fchown(fd: F, uid: Option, gid: Option) -> io::Result<()> { ``` with `fd: F` rather than `fd: &F`. And similar for `AsHandle` and `AsSocket` on Windows. Also, adjust the `fchown` example to pass the file by reference. The code can work either way now, but passing by reference is more likely to be what users will want to do. This is an alternative to #93869, and is a simpler way to achieve the same goals: users don't need to pass borrowed-`BorrowedFd` arguments, and it prevents a pitfall in the case where users write `fd: F` instead of `fd: &F`. --- library/std/src/os/fd/owned.rs | 16 ++++++++++++++++ library/std/src/os/unix/fs.rs | 2 +- library/std/src/os/windows/io/handle.rs | 16 ++++++++++++++++ library/std/src/os/windows/io/socket.rs | 16 ++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index b53c3e79b0fe6..71c660e718675 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -200,6 +200,22 @@ pub trait AsFd { fn as_fd(&self) -> BorrowedFd<'_>; } +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for &T { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + T::as_fd(self) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for &mut T { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + T::as_fd(self) + } +} + #[unstable(feature = "io_safety", issue = "87074")] impl AsFd for BorrowedFd<'_> { #[inline] diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index db7edcd057432..75d65e6d5fc03 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -966,7 +966,7 @@ pub fn chown>(dir: P, uid: Option, gid: Option) -> io:: /// /// fn main() -> std::io::Result<()> { /// let f = std::fs::File::open("/file")?; -/// fs::fchown(f, Some(0), Some(0))?; +/// fs::fchown(&f, Some(0), Some(0))?; /// Ok(()) /// } /// ``` diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index e37ce633a129a..8df6c54a4144e 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -316,6 +316,22 @@ pub trait AsHandle { fn as_handle(&self) -> BorrowedHandle<'_>; } +#[unstable(feature = "io_safety", issue = "87074")] +impl AsHandle for &T { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + T::as_handle(self) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsHandle for &mut T { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + T::as_handle(self) + } +} + impl AsHandle for BorrowedHandle<'_> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index d3a5b6dcc76c6..2f13eb77a1b94 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -210,6 +210,22 @@ pub trait AsSocket { fn as_socket(&self) -> BorrowedSocket<'_>; } +#[unstable(feature = "io_safety", issue = "87074")] +impl AsSocket for &T { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + T::as_socket(self) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsSocket for &mut T { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + T::as_socket(self) + } +} + impl AsSocket for BorrowedSocket<'_> { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { From 22a24c98d3429f9e98e4ce5d096f58620d753458 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 3 Feb 2022 23:19:36 +0100 Subject: [PATCH 13/17] Add missing platform-specific information on current_dir and set_current_dir --- library/std/src/env.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index c06928647d389..5ed9fa9d6f0fd 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -23,6 +23,11 @@ use crate::sys::os as os_imp; /// Returns the current working directory as a [`PathBuf`]. /// +/// # Platform-specific behavior +/// +/// This function currently corresponds to the `getcwd` function on Unix +/// and the `GetCurrentDirectoryW` function on Windows. +/// /// # Errors /// /// Returns an [`Err`] if the current working directory value is invalid. @@ -49,6 +54,11 @@ pub fn current_dir() -> io::Result { /// Changes the current working directory to the specified path. /// +/// # Platform-specific behavior +/// +/// This function currently corresponds to the `chdir` function on Unix +/// and the `SetCurrentDirectoryW` function on Windows. +/// /// Returns an [`Err`] if the operation fails. /// /// # Examples From 45dc8ebb7c860939e045cfb758968c014fdeb96d Mon Sep 17 00:00:00 2001 From: Rose Hudson Date: Fri, 11 Feb 2022 15:34:33 +0000 Subject: [PATCH 14/17] fix mention of moved function in `rustc_hir` docs the function was moved from `Crate` to `Map` in db9fea508a6d but the docs weren't updated --- compiler/rustc_hir/src/itemlikevisit.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir/src/itemlikevisit.rs b/compiler/rustc_hir/src/itemlikevisit.rs index 0db562f91a6a5..db70002c2d66a 100644 --- a/compiler/rustc_hir/src/itemlikevisit.rs +++ b/compiler/rustc_hir/src/itemlikevisit.rs @@ -8,7 +8,7 @@ use super::{ForeignItem, ImplItem, Item, TraitItem}; /// /// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR. /// - Example: find all items with a `#[foo]` attribute on them. -/// - How: Implement `ItemLikeVisitor` and call `tcx.hir().krate().visit_all_item_likes()`. +/// - How: Implement `ItemLikeVisitor` and call `tcx.hir().visit_all_item_likes()`. /// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves. /// - Con: Don't get information about nesting /// - Con: Don't have methods for specific bits of HIR, like "on @@ -19,9 +19,9 @@ use super::{ForeignItem, ImplItem, Item, TraitItem}; /// - Example: Examine each expression to look for its type and do some check or other. /// - How: Implement `intravisit::Visitor` and override the `nested_visit_map()` method /// to return `NestedVisitorMap::OnlyBodies` and use -/// `tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within -/// your `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget -/// to invoke `intravisit::walk_expr()` to keep walking the subparts). +/// `tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within your +/// `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke +/// `intravisit::walk_expr()` to keep walking the subparts). /// - Pro: Visitor methods for any kind of HIR node, not just item-like things. /// - Pro: Integrates well into dependency tracking. /// - Con: Don't get information about nesting between items From f9cb01f8025d7feb10b35350b543ebbff580dd51 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 11 Feb 2022 16:23:39 +0100 Subject: [PATCH 15/17] Fix typo: explicitely->explicitly --- compiler/rustc_typeck/src/check/method/suggest.rs | 4 ++-- .../explicitly-unimplemented-error-message.rs | 8 ++++---- .../explicitly-unimplemented-error-message.stderr | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 58ea197d3e940..308f98f7aed8c 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1819,7 +1819,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { [] => {} [trait_info] => { let msg = format!( - "the trait `{}` defines an item `{}`, but is explicitely unimplemented", + "the trait `{}` defines an item `{}`, but is explicitly unimplemented", self.tcx.def_path_str(trait_info.def_id), item_name ); @@ -1827,7 +1827,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } trait_infos => { let mut msg = format!( - "the following traits define an item `{}`, but are explicitely unimplemented:", + "the following traits define an item `{}`, but are explicitly unimplemented:", item_name ); for trait_info in trait_infos { diff --git a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs index 3e336933937d0..1314f9cb0932d 100644 --- a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs +++ b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs @@ -34,20 +34,20 @@ fn main() { Qux.clone(); //~^ ERROR no method named `clone` found for struct `Qux` //~| NOTE method not found in `Qux` - //~| NOTE `Clone` defines an item `clone`, but is explicitely unimplemented + //~| NOTE `Clone` defines an item `clone`, but is explicitly unimplemented 0_u32.bar(); //~^ ERROR no method named `bar` found for type `u32` //~| NOTE method not found in `u32` - //~| NOTE `Bar` defines an item `bar`, but is explicitely unimplemented + //~| NOTE `Bar` defines an item `bar`, but is explicitly unimplemented Qux.foo(); //~^ ERROR no method named `foo` found for struct `Qux` //~| NOTE method not found in `Qux` - //~| NOTE the following traits define an item `foo`, but are explicitely unimplemented + //~| NOTE the following traits define an item `foo`, but are explicitly unimplemented 0_u32.foo(); //~^ ERROR no method named `foo` found for type `u32` //~| NOTE method not found in `u32` - //~| NOTE `FooBar` defines an item `foo`, but is explicitely unimplemented + //~| NOTE `FooBar` defines an item `foo`, but is explicitly unimplemented } diff --git a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr index 01e36a4a62a1b..c18abf95083da 100644 --- a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr +++ b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr @@ -8,7 +8,7 @@ LL | Qux.clone(); | ^^^^^ method not found in `Qux` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the trait `Clone` defines an item `clone`, but is explicitely unimplemented + = note: the trait `Clone` defines an item `clone`, but is explicitly unimplemented error[E0599]: no method named `bar` found for type `u32` in the current scope --> $DIR/explicitly-unimplemented-error-message.rs:39:11 @@ -17,7 +17,7 @@ LL | 0_u32.bar(); | ^^^ method not found in `u32` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the trait `Bar` defines an item `bar`, but is explicitely unimplemented + = note: the trait `Bar` defines an item `bar`, but is explicitly unimplemented error[E0599]: no method named `foo` found for struct `Qux` in the current scope --> $DIR/explicitly-unimplemented-error-message.rs:44:9 @@ -29,7 +29,7 @@ LL | Qux.foo(); | ^^^ method not found in `Qux` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following traits define an item `foo`, but are explicitely unimplemented: + = note: the following traits define an item `foo`, but are explicitly unimplemented: Foo FooBar @@ -45,7 +45,7 @@ note: `Foo` defines an item `foo`, perhaps you need to implement it | LL | trait Foo { | ^^^^^^^^^ - = note: the trait `FooBar` defines an item `foo`, but is explicitely unimplemented + = note: the trait `FooBar` defines an item `foo`, but is explicitly unimplemented error: aborting due to 4 previous errors From 55ceed81fe68bf09293176cd2c16fbb90aab0531 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 14 Jan 2022 14:25:52 +0100 Subject: [PATCH 16/17] Remove the alt_std_name option This option introduced in #15820 allows a custom crate to be imported in the place of std, but with the name std. I don't think there is any value to this. At most it is confusing users of a driver that uses this option. There are no users of this option on github. If anyone still needs it, they can emulate it injecting #![no_core] in addition to their own prelude. --- compiler/rustc_builtin_macros/src/standard_library_imports.rs | 3 +-- compiler/rustc_interface/src/passes.rs | 3 +-- compiler/rustc_session/src/config.rs | 2 -- compiler/rustc_session/src/options.rs | 4 ---- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index e106f6014a31d..3571517d2b258 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -11,7 +11,6 @@ pub fn inject( mut krate: ast::Crate, resolver: &mut dyn ResolverExpand, sess: &Session, - alt_std_name: Option, ) -> ast::Crate { let edition = sess.parse_sess.edition; @@ -53,7 +52,7 @@ pub fn inject( span, ident, vec![cx.attribute(cx.meta_word(span, sym::macro_use))], - ast::ItemKind::ExternCrate(alt_std_name), + ast::ItemKind::ExternCrate(None), ), ); } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index f5a4e11de16c0..66e1e78b2856c 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -286,8 +286,7 @@ pub fn configure_and_expand( rustc_builtin_macros::register_builtin_macros(resolver); krate = sess.time("crate_injection", || { - let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s)); - rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess, alt_std_name) + rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess) }); util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer()); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 8630ffec241f9..79962d5db8918 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -770,7 +770,6 @@ impl Default for Options { externs: Externs(BTreeMap::new()), extern_dep_specs: ExternDepSpecs(BTreeMap::new()), crate_name: None, - alt_std_name: None, libs: Vec::new(), unstable_features: UnstableFeatures::Disallow, debug_assertions: true, @@ -2382,7 +2381,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()), extern_dep_specs, crate_name, - alt_std_name: None, libs, debug_assertions, actually_rustdoc: false, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 550da9e05804f..ae1b638c34467 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -184,10 +184,6 @@ top_level_options!( externs: Externs [UNTRACKED], extern_dep_specs: ExternDepSpecs [UNTRACKED], crate_name: Option [TRACKED], - /// An optional name to use as the crate for std during std injection, - /// written `extern crate name as std`. Defaults to `std`. Used by - /// out-of-tree drivers. - alt_std_name: Option [TRACKED], /// Indicates how the compiler should treat unstable features. unstable_features: UnstableFeatures [TRACKED], From 7ba4110012730bffeb4eeb857a1f8ea408bdc9cc Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 25 Jun 2021 11:59:35 +0200 Subject: [PATCH 17/17] Make two functions private --- compiler/rustc_interface/src/util.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 6d9183eda9d32..f74cadfebacba 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -118,7 +118,7 @@ fn get_stack_size() -> Option { /// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need /// for `'static` bounds. #[cfg(not(parallel_compiler))] -pub fn scoped_thread R + Send, R: Send>(cfg: thread::Builder, f: F) -> R { +fn scoped_thread R + Send, R: Send>(cfg: thread::Builder, f: F) -> R { // SAFETY: join() is called immediately, so any closure captures are still // alive. match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() { @@ -379,7 +379,7 @@ fn sysroot_candidates() -> Vec { } } -pub fn get_codegen_sysroot(maybe_sysroot: &Option, backend_name: &str) -> MakeBackendFn { +fn get_codegen_sysroot(maybe_sysroot: &Option, backend_name: &str) -> MakeBackendFn { // For now we only allow this function to be called once as it'll dlopen a // few things, which seems to work best if we only do that once. In // general this assertion never trips due to the once guard in `get_codegen_backend`,