From c6015851f7e54d1e1e267afb315a2b4b23096d0d Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 9 Mar 2023 13:18:07 -0700 Subject: [PATCH 01/19] rustdoc: move notable trait tests into their own directory --- .../doc-notable_trait-mut_t_is_not_an_iterator.rs | 0 .../{ => notable-trait}/doc-notable_trait-mut_t_is_not_ref_t.rs | 0 .../doc-notable_trait-slice.bare_fn_matches.html | 0 tests/rustdoc/{ => notable-trait}/doc-notable_trait-slice.rs | 0 tests/rustdoc/{ => notable-trait}/doc-notable_trait.bare-fn.html | 0 tests/rustdoc/{ => notable-trait}/doc-notable_trait.rs | 0 .../{ => notable-trait}/doc-notable_trait.some-struct-new.html | 0 tests/rustdoc/{ => notable-trait}/doc-notable_trait.wrap-me.html | 0 .../doc-notable_trait_box_is_not_an_iterator.rs | 0 .../{ => notable-trait}/spotlight-from-dependency.odd.html | 0 tests/rustdoc/{ => notable-trait}/spotlight-from-dependency.rs | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => notable-trait}/doc-notable_trait-mut_t_is_not_an_iterator.rs (100%) rename tests/rustdoc/{ => notable-trait}/doc-notable_trait-mut_t_is_not_ref_t.rs (100%) rename tests/rustdoc/{ => notable-trait}/doc-notable_trait-slice.bare_fn_matches.html (100%) rename tests/rustdoc/{ => notable-trait}/doc-notable_trait-slice.rs (100%) rename tests/rustdoc/{ => notable-trait}/doc-notable_trait.bare-fn.html (100%) rename tests/rustdoc/{ => notable-trait}/doc-notable_trait.rs (100%) rename tests/rustdoc/{ => notable-trait}/doc-notable_trait.some-struct-new.html (100%) rename tests/rustdoc/{ => notable-trait}/doc-notable_trait.wrap-me.html (100%) rename tests/rustdoc/{ => notable-trait}/doc-notable_trait_box_is_not_an_iterator.rs (100%) rename tests/rustdoc/{ => notable-trait}/spotlight-from-dependency.odd.html (100%) rename tests/rustdoc/{ => notable-trait}/spotlight-from-dependency.rs (100%) diff --git a/tests/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs similarity index 100% rename from tests/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs rename to tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs diff --git a/tests/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs similarity index 100% rename from tests/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs rename to tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs diff --git a/tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html b/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html similarity index 100% rename from tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html rename to tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html diff --git a/tests/rustdoc/doc-notable_trait-slice.rs b/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs similarity index 100% rename from tests/rustdoc/doc-notable_trait-slice.rs rename to tests/rustdoc/notable-trait/doc-notable_trait-slice.rs diff --git a/tests/rustdoc/doc-notable_trait.bare-fn.html b/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html similarity index 100% rename from tests/rustdoc/doc-notable_trait.bare-fn.html rename to tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html diff --git a/tests/rustdoc/doc-notable_trait.rs b/tests/rustdoc/notable-trait/doc-notable_trait.rs similarity index 100% rename from tests/rustdoc/doc-notable_trait.rs rename to tests/rustdoc/notable-trait/doc-notable_trait.rs diff --git a/tests/rustdoc/doc-notable_trait.some-struct-new.html b/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html similarity index 100% rename from tests/rustdoc/doc-notable_trait.some-struct-new.html rename to tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html diff --git a/tests/rustdoc/doc-notable_trait.wrap-me.html b/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html similarity index 100% rename from tests/rustdoc/doc-notable_trait.wrap-me.html rename to tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html diff --git a/tests/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs b/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs similarity index 100% rename from tests/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs rename to tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs diff --git a/tests/rustdoc/spotlight-from-dependency.odd.html b/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html similarity index 100% rename from tests/rustdoc/spotlight-from-dependency.odd.html rename to tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html diff --git a/tests/rustdoc/spotlight-from-dependency.rs b/tests/rustdoc/notable-trait/spotlight-from-dependency.rs similarity index 100% rename from tests/rustdoc/spotlight-from-dependency.rs rename to tests/rustdoc/notable-trait/spotlight-from-dependency.rs From ee6b228b6a8b874ca8b6e88cd58d4618cf20fb20 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 9 Mar 2023 13:41:13 -0700 Subject: [PATCH 02/19] rustdoc: handle generics better when matching notable traits This commit makes the `clean::Type::is_same` non-commutative, so that a generic `impl` matches a concrete return, but a generic return does not match a concrete `impl`. It makes slice and vector Write for `u8` not match on every generic return value. --- src/librustdoc/clean/types.rs | 46 +++++++++++++++++-- src/librustdoc/clean/types/tests.rs | 11 +++++ src/librustdoc/html/render/mod.rs | 4 +- .../notable-trait/doc-notable_trait-slice.rs | 6 +++ .../notable-trait/notable-trait-generics.rs | 35 ++++++++++++++ 5 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 tests/rustdoc/notable-trait/notable-trait-generics.rs diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6d8380c5fcc18..5217de7aa8a4f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1471,11 +1471,37 @@ impl Type { result } - /// Check if two types are "potentially the same". + pub(crate) fn is_borrowed_ref(&self) -> bool { + matches!(self, Type::BorrowedRef { .. }) + } + + /// Check if two types are "the same" for documentation purposes. + /// /// This is different from `Eq`, because it knows that things like /// `Placeholder` are possible matches for everything. + /// + /// This relation is not commutative when generics are involved: + /// + /// ```ignore(private) + /// # // see types/tests.rs:is_same_generic for the real test + /// use rustdoc::format::cache::Cache; + /// use rustdoc::clean::types::{Type, PrimitiveType}; + /// let cache = Cache::new(false); + /// let generic = Type::Generic(rustc_span::symbol::sym::Any); + /// let unit = Type::Primitive(PrimitiveType::Unit); + /// assert!(!generic.is_same(&unit, &cache)); + /// assert!(unit.is_same(&generic, &cache)); + /// ``` + /// + /// An owned type is also the same as its borrowed variants (this is commutative), + /// but `&T` is not the same as `&mut T`. pub(crate) fn is_same(&self, other: &Self, cache: &Cache) -> bool { - match (self, other) { + let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() { + (self.without_borrowed_ref(), other.without_borrowed_ref()) + } else { + (self, other) + }; + match (self_cleared, other_cleared) { // Recursive cases. (Type::Tuple(a), Type::Tuple(b)) => { a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(b, cache)) @@ -1489,9 +1515,21 @@ impl Type { Type::BorrowedRef { mutability, type_, .. }, Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. }, ) => mutability == b_mutability && type_.is_same(b_type_, cache), - // Placeholders and generics are equal to all other types. + // Placeholders are equal to all other types. (Type::Infer, _) | (_, Type::Infer) => true, - (Type::Generic(_), _) | (_, Type::Generic(_)) => true, + // Generics match everything on the right, but not on the left. + (_, Type::Generic(_)) => true, + (Type::Generic(_), _) => false, + // Paths account for both the path itself and its generics. + (Type::Path { path: a }, Type::Path { path: b }) => { + a.def_id() == b.def_id() + && a.generics() + .zip(b.generics()) + .map(|(ag, bg)| { + ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_same(bt, cache)) + }) + .unwrap_or(true) + } // Other cases, such as primitives, just use recursion. (a, b) => a .def_id(cache) diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs index 20627c2cfc164..7df87a9804aa2 100644 --- a/src/librustdoc/clean/types/tests.rs +++ b/src/librustdoc/clean/types/tests.rs @@ -69,3 +69,14 @@ fn should_not_trim() { run_test("\t line1 \n\t line2", "line1 \nline2"); run_test(" \tline1 \n \tline2", "line1 \nline2"); } + +#[test] +fn is_same_generic() { + use crate::clean::types::{PrimitiveType, Type}; + use crate::formats::cache::Cache; + let cache = Cache::new(false); + let generic = Type::Generic(rustc_span::symbol::sym::Any); + let unit = Type::Primitive(PrimitiveType::Unit); + assert!(!generic.is_same(&unit, &cache)); + assert!(unit.is_same(&generic, &cache)); +} diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index e6a040d02e565..f8c26dc4706b1 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1291,7 +1291,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O if let Some(impls) = cx.cache().impls.get(&did) { for i in impls { let impl_ = i.inner_impl(); - if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) { + if !ty.is_same(&impl_.for_, cx.cache()) { // Two different types might have the same did, // without actually being the same. continue; @@ -1327,7 +1327,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { for i in impls { let impl_ = i.inner_impl(); - if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) { + if !ty.is_same(&impl_.for_, cx.cache()) { // Two different types might have the same did, // without actually being the same. continue; diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs b/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs index 2411da8cd4549..ef206710b4b08 100644 --- a/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs @@ -18,3 +18,9 @@ pub fn bare_fn_matches() -> &'static [SomeStruct] { pub fn bare_fn_no_matches() -> &'static [OtherStruct] { &[] } + +// @has doc_notable_trait_slice/fn.bare_fn_mut_no_matches.html +// @count - '//script[@id="notable-traits-data"]' 0 +pub fn bare_fn_mut_no_matches() -> &'static mut [SomeStruct] { + &mut [] +} diff --git a/tests/rustdoc/notable-trait/notable-trait-generics.rs b/tests/rustdoc/notable-trait/notable-trait-generics.rs new file mode 100644 index 0000000000000..7bfe9d43ea986 --- /dev/null +++ b/tests/rustdoc/notable-trait/notable-trait-generics.rs @@ -0,0 +1,35 @@ +#![feature(doc_notable_trait)] + +// Notable traits SHOULD be shown when the `impl` has a generic type and the +// return type has a concrete type. +pub mod generic_return { + pub struct Wrapper(T); + + #[doc(notable_trait)] + pub trait NotableTrait {} + + impl NotableTrait for Wrapper {} + + // @has notable_trait_generics/generic_return/fn.returning.html + // @!has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper' + pub fn returning() -> Wrapper { + loop {} + } +} + +// Notable traits SHOULD NOT be shown when the `impl` has a concrete type and +// the return type has a generic type. +pub mod generic_impl { + pub struct Wrapper(T); + + #[doc(notable_trait)] + pub trait NotableTrait {} + + impl NotableTrait for Wrapper {} + + // @has notable_trait_generics/generic_impl/fn.returning.html + // @has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper' + pub fn returning() -> Wrapper { + loop {} + } +} From 86179c4549e74acf22fc4da02b64f0bb2ce1f4aa Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 12 Mar 2023 17:45:15 -0700 Subject: [PATCH 03/19] rustdoc: rename `Type::is_same` to `is_doc_subtype_of` --- src/librustdoc/clean/types.rs | 14 +++++++------- src/librustdoc/clean/types/tests.rs | 4 ++-- src/librustdoc/html/render/mod.rs | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5217de7aa8a4f..1b8478ee21c68 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1495,7 +1495,7 @@ impl Type { /// /// An owned type is also the same as its borrowed variants (this is commutative), /// but `&T` is not the same as `&mut T`. - pub(crate) fn is_same(&self, other: &Self, cache: &Cache) -> bool { + pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool { let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() { (self.without_borrowed_ref(), other.without_borrowed_ref()) } else { @@ -1504,17 +1504,17 @@ impl Type { match (self_cleared, other_cleared) { // Recursive cases. (Type::Tuple(a), Type::Tuple(b)) => { - a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(b, cache)) + a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache)) } - (Type::Slice(a), Type::Slice(b)) => a.is_same(b, cache), - (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(b, cache), + (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache), + (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache), (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => { - mutability == b_mutability && type_.is_same(b_type_, cache) + mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache) } ( Type::BorrowedRef { mutability, type_, .. }, Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. }, - ) => mutability == b_mutability && type_.is_same(b_type_, cache), + ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache), // Placeholders are equal to all other types. (Type::Infer, _) | (_, Type::Infer) => true, // Generics match everything on the right, but not on the left. @@ -1526,7 +1526,7 @@ impl Type { && a.generics() .zip(b.generics()) .map(|(ag, bg)| { - ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_same(bt, cache)) + ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)) }) .unwrap_or(true) } diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs index 7df87a9804aa2..afbee3e5f78ca 100644 --- a/src/librustdoc/clean/types/tests.rs +++ b/src/librustdoc/clean/types/tests.rs @@ -77,6 +77,6 @@ fn is_same_generic() { let cache = Cache::new(false); let generic = Type::Generic(rustc_span::symbol::sym::Any); let unit = Type::Primitive(PrimitiveType::Unit); - assert!(!generic.is_same(&unit, &cache)); - assert!(unit.is_same(&generic, &cache)); + assert!(!generic.is_doc_subtype_of(&unit, &cache)); + assert!(unit.is_doc_subtype_of(&generic, &cache)); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index f8c26dc4706b1..832c4e7cfe77b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1291,7 +1291,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O if let Some(impls) = cx.cache().impls.get(&did) { for i in impls { let impl_ = i.inner_impl(); - if !ty.is_same(&impl_.for_, cx.cache()) { + if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { // Two different types might have the same did, // without actually being the same. continue; @@ -1327,7 +1327,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { for i in impls { let impl_ = i.inner_impl(); - if !ty.is_same(&impl_.for_, cx.cache()) { + if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { // Two different types might have the same did, // without actually being the same. continue; From bfb66eb4bb4ada8a0b4d48d73a93e8f5df0e54be Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 13 Mar 2023 23:03:53 -0700 Subject: [PATCH 04/19] rustdoc: fix comments in test --- tests/rustdoc/notable-trait/notable-trait-generics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/rustdoc/notable-trait/notable-trait-generics.rs b/tests/rustdoc/notable-trait/notable-trait-generics.rs index 7bfe9d43ea986..611902abad65b 100644 --- a/tests/rustdoc/notable-trait/notable-trait-generics.rs +++ b/tests/rustdoc/notable-trait/notable-trait-generics.rs @@ -1,7 +1,7 @@ #![feature(doc_notable_trait)] -// Notable traits SHOULD be shown when the `impl` has a generic type and the -// return type has a concrete type. +// Notable traits SHOULD NOT be shown when the `impl` has a concrete type and +// the return type has a generic type. pub mod generic_return { pub struct Wrapper(T); @@ -17,8 +17,8 @@ pub mod generic_return { } } -// Notable traits SHOULD NOT be shown when the `impl` has a concrete type and -// the return type has a generic type. +// Notable traits SHOULD be shown when the `impl` has a generic type and the +// return type has a concrete type. pub mod generic_impl { pub struct Wrapper(T); From 7f76084933b69ae856bc872c3eecdc2378a21f4b Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 17 Mar 2023 10:46:38 -0700 Subject: [PATCH 05/19] Add clarifying comments --- src/librustdoc/clean/types.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 1b8478ee21c68..7dbb3f76a0a83 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1496,6 +1496,8 @@ impl Type { /// An owned type is also the same as its borrowed variants (this is commutative), /// but `&T` is not the same as `&mut T`. pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool { + // Strip the references so that it can compare the actual types, unless both are references. + // If both are references, leave them alone and compare the mutabilities later. let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() { (self.without_borrowed_ref(), other.without_borrowed_ref()) } else { @@ -1518,6 +1520,7 @@ impl Type { // Placeholders are equal to all other types. (Type::Infer, _) | (_, Type::Infer) => true, // Generics match everything on the right, but not on the left. + // If both sides are generic, this returns true. (_, Type::Generic(_)) => true, (Type::Generic(_), _) => false, // Paths account for both the path itself and its generics. From c9ddb73184290e0698060a80b0b5727d6ee11098 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Fri, 17 Mar 2023 21:35:43 +1300 Subject: [PATCH 06/19] refactor: refactor identifier parsing somewhat --- compiler/rustc_parse/messages.ftl | 2 +- compiler/rustc_parse/src/errors.rs | 6 ++--- .../rustc_parse/src/parser/diagnostics.rs | 17 +++++++++--- compiler/rustc_parse/src/parser/item.rs | 2 +- compiler/rustc_parse/src/parser/mod.rs | 27 +++++++++---------- 5 files changed, 31 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index c39ada95a4ec4..96765c296e79b 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -336,7 +336,7 @@ parse_expected_identifier_found_reserved_keyword = expected identifier, found re parse_expected_identifier_found_doc_comment = expected identifier, found doc comment parse_expected_identifier = expected identifier -parse_sugg_escape_to_use_as_identifier = escape `{$ident_name}` to use it as an identifier +parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier parse_sugg_remove_comma = remove this comma diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index af0c3026c6605..2def5c5b32f17 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -888,12 +888,12 @@ pub(crate) struct InvalidMetaItem { #[derive(Subdiagnostic)] #[suggestion( - parse_sugg_escape_to_use_as_identifier, + parse_sugg_escape_identifier, style = "verbose", applicability = "maybe-incorrect", code = "r#" )] -pub(crate) struct SuggEscapeToUseAsIdentifier { +pub(crate) struct SuggEscapeIdentifier { #[primary_span] pub span: Span, pub ident_name: String, @@ -937,7 +937,7 @@ impl ExpectedIdentifierFound { pub(crate) struct ExpectedIdentifier { pub span: Span, pub token: Token, - pub suggest_raw: Option, + pub suggest_raw: Option, pub suggest_remove_comma: Option, pub help_cannot_start_number: Option, } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 5b12bcc182222..a9f24ab44ea84 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -6,14 +6,14 @@ use super::{ use crate::errors::{ AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub, ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, - ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType, - DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, + ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, + DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, - StructLiteralNeedingParensSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma, + StructLiteralNeedingParensSugg, SuggEscapeIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, }; @@ -268,7 +268,16 @@ impl<'a> Parser<'a> { self.sess.source_map().span_to_snippet(span) } + /// Emits an error with suggestions if an identifier was expected but not found. pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + if let TokenKind::DocComment(..) = self.prev_token.kind { + return DocCommentDoesNotDocumentAnything { + span: self.prev_token.span, + missing_comma: None, + } + .into_diagnostic(&self.sess.span_diagnostic); + } + let valid_follow = &[ TokenKind::Eq, TokenKind::Colon, @@ -286,7 +295,7 @@ impl<'a> Parser<'a> { if ident.is_raw_guess() && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) => { - Some(SuggEscapeToUseAsIdentifier { + Some(SuggEscapeIdentifier { span: ident.span.shrink_to_lo(), // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`, // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 85cc8ca02a977..b7415dc8fb84c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1744,7 +1744,7 @@ impl<'a> Parser<'a> { /// Parses a field identifier. Specialized version of `parse_ident_common` /// for better diagnostics and suggestions. fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> { - let (ident, is_raw) = self.ident_or_err()?; + let (ident, is_raw) = self.ident_or_err(true)?; if !is_raw && ident.is_reserved() { let snapshot = self.create_snapshot_for_diagnostic(); let err = if self.check_fn_front_matter(false, Case::Sensitive) { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3251dd6d0c6fb..6991520895ddd 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -42,8 +42,7 @@ use thin_vec::ThinVec; use tracing::debug; use crate::errors::{ - DocCommentDoesNotDocumentAnything, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, - NonStringAbiLiteral, + IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral, }; bitflags::bitflags! { @@ -552,19 +551,8 @@ impl<'a> Parser<'a> { self.parse_ident_common(true) } - fn ident_or_err(&mut self) -> PResult<'a, (Ident, /* is_raw */ bool)> { - self.token.ident().ok_or_else(|| match self.prev_token.kind { - TokenKind::DocComment(..) => DocCommentDoesNotDocumentAnything { - span: self.prev_token.span, - missing_comma: None, - } - .into_diagnostic(&self.sess.span_diagnostic), - _ => self.expected_ident_found(), - }) - } - fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> { - let (ident, is_raw) = self.ident_or_err()?; + let (ident, is_raw) = self.ident_or_err(recover)?; if !is_raw && ident.is_reserved() { let mut err = self.expected_ident_found(); if recover { @@ -577,6 +565,17 @@ impl<'a> Parser<'a> { Ok(ident) } + fn ident_or_err(&mut self, _recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> { + let result = self.token.ident().ok_or_else(|| self.expected_ident_found()); + + let (ident, is_raw) = match result { + Ok(ident) => ident, + Err(err) => return Err(err), + }; + + Ok((ident, is_raw)) + } + /// Checks if the next token is `tok`, and returns `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not From b4e17a5098f0413b01c90c8505e0f01e8bea50de Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Fri, 17 Mar 2023 21:41:26 +1300 Subject: [PATCH 07/19] refactor: improve "ident starts with number" error --- compiler/rustc_parse/src/errors.rs | 5 ++- .../rustc_parse/src/parser/diagnostics.rs | 34 +++++++++++++------ compiler/rustc_parse/src/parser/pat.rs | 6 +--- compiler/rustc_span/src/lib.rs | 12 +++++++ .../parser/integer-literal-start-ident.stderr | 6 +++- tests/ui/parser/issues/issue-104088.stderr | 18 ++++++++-- 6 files changed, 61 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 2def5c5b32f17..a9d116012ae5b 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -986,7 +986,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { #[derive(Subdiagnostic)] #[help(parse_invalid_identifier_with_leading_number)] -pub(crate) struct HelpIdentifierStartsWithNumber; +pub(crate) struct HelpIdentifierStartsWithNumber { + #[primary_span] + pub num_span: Span, +} pub(crate) struct ExpectedSemi { pub span: Span, diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a9f24ab44ea84..47d1108491530 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -38,7 +38,7 @@ use rustc_errors::{ use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{Span, SpanSnippetError, DUMMY_SP}; +use rustc_span::{Span, SpanSnippetError, Symbol, DUMMY_SP}; use std::mem::take; use std::ops::{Deref, DerefMut}; use thin_vec::{thin_vec, ThinVec}; @@ -309,8 +309,11 @@ impl<'a> Parser<'a> { && self.look_ahead(1, |t| t.is_ident())) .then_some(SuggRemoveComma { span: self.token.span }); - let help_cannot_start_number = - self.is_lit_bad_ident().then_some(HelpIdentifierStartsWithNumber); + let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, _valid_portion)| { + let (invalid, _valid) = self.token.span.split_at(len as u32); + + HelpIdentifierStartsWithNumber { num_span: invalid } + }); let err = ExpectedIdentifier { span: self.token.span, @@ -378,13 +381,24 @@ impl<'a> Parser<'a> { /// Checks if the current token is a integer or float literal and looks like /// it could be a invalid identifier with digits at the start. - pub(super) fn is_lit_bad_ident(&mut self) -> bool { - matches!(self.token.uninterpolate().kind, token::Literal(Lit { kind: token::LitKind::Integer | token::LitKind::Float, .. }) - // ensure that the integer literal is followed by a *invalid* - // suffix: this is how we know that it is a identifier with an - // invalid beginning. - if rustc_ast::MetaItemLit::from_token(&self.token).is_none() - ) + /// + /// Returns the number of characters (bytes) composing the invalid portion + /// of the identifier and the valid portion of the identifier. + pub(super) fn is_lit_bad_ident(&mut self) -> Option<(usize, Symbol)> { + // ensure that the integer literal is followed by a *invalid* + // suffix: this is how we know that it is a identifier with an + // invalid beginning. + if let token::Literal(Lit { + kind: token::LitKind::Integer | token::LitKind::Float, + symbol, + suffix, + }) = self.token.uninterpolate().kind + && rustc_ast::MetaItemLit::from_token(&self.token).is_none() + { + Some((symbol.as_str().len(), suffix.unwrap())) + } else { + None + } } pub(super) fn expected_one_of_not_found( diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index fc9f1d1330a72..d9af241584868 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -348,10 +348,6 @@ impl<'a> Parser<'a> { lo = self.token.span; } - if self.is_lit_bad_ident() { - return Err(self.expected_ident_found()); - } - let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd { self.parse_pat_deref(expected)? } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { @@ -395,7 +391,7 @@ impl<'a> Parser<'a> { } else { PatKind::Lit(const_expr) } - } else if self.can_be_ident_pat() { + } else if self.can_be_ident_pat() || self.is_lit_bad_ident().is_some() { // Parse `ident @ pat` // This can give false positives and parse nullary enums, // they are dealt with later in resolve. diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 873cd33f6a4f2..02cffc762bed3 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -795,6 +795,18 @@ impl Span { }) } + /// Splits a span into two composite spans around a certain position. + pub fn split_at(self, pos: u32) -> (Span, Span) { + let len = self.hi().0 - self.lo().0; + debug_assert!(pos <= len); + + let split_pos = BytePos(self.lo().0 + pos); + ( + Span::new(self.lo(), split_pos, self.ctxt(), self.parent()), + Span::new(split_pos, self.hi(), self.ctxt(), self.parent()), + ) + } + /// Returns a `Span` that would enclose both `self` and `end`. /// /// Note that this can also be used to extend the span "backwards": diff --git a/tests/ui/parser/integer-literal-start-ident.stderr b/tests/ui/parser/integer-literal-start-ident.stderr index 51c37a0d24c3c..b2c6612965608 100644 --- a/tests/ui/parser/integer-literal-start-ident.stderr +++ b/tests/ui/parser/integer-literal-start-ident.stderr @@ -4,7 +4,11 @@ error: expected identifier, found `1main` LL | fn 1main() {} | ^^^^^ expected identifier | - = help: identifiers cannot start with a number +help: identifiers cannot start with a number + --> $DIR/integer-literal-start-ident.rs:1:4 + | +LL | fn 1main() {} + | ^ error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-104088.stderr b/tests/ui/parser/issues/issue-104088.stderr index 6511a313149f4..08ea1c891c172 100644 --- a/tests/ui/parser/issues/issue-104088.stderr +++ b/tests/ui/parser/issues/issue-104088.stderr @@ -4,7 +4,11 @@ error: expected identifier, found `1x` LL | let 1x = 123; | ^^ expected identifier | - = help: identifiers cannot start with a number +help: identifiers cannot start with a number + --> $DIR/issue-104088.rs:6:9 + | +LL | let 1x = 123; + | ^ error: expected identifier, found `2x` --> $DIR/issue-104088.rs:11:9 @@ -12,7 +16,11 @@ error: expected identifier, found `2x` LL | let 2x: i32 = 123; | ^^ expected identifier | - = help: identifiers cannot start with a number +help: identifiers cannot start with a number + --> $DIR/issue-104088.rs:11:9 + | +LL | let 2x: i32 = 123; + | ^ error: expected identifier, found `23name` --> $DIR/issue-104088.rs:22:9 @@ -20,7 +28,11 @@ error: expected identifier, found `23name` LL | let 23name = 123; | ^^^^^^ expected identifier | - = help: identifiers cannot start with a number +help: identifiers cannot start with a number + --> $DIR/issue-104088.rs:22:9 + | +LL | let 23name = 123; + | ^^ error[E0308]: mismatched types --> $DIR/issue-104088.rs:16:12 From 4da79703b6f2f96e473bdd0317743c433792a29e Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 19 Mar 2023 20:41:22 +0000 Subject: [PATCH 08/19] Update stdarch Bring the the `#![allow(internal_features)]` --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index a0c30f3e3c75a..b655243782c18 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit a0c30f3e3c75adcd6ee7efc94014ebcead61c507 +Subproject commit b655243782c18d3419439daa523782e0818ecf26 From 43008cedafe730c71c071dd9278855e72021ea50 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 19 Mar 2023 21:08:56 +0000 Subject: [PATCH 09/19] Add `#![feature(generic_arg_infer)]` to core for stdarch --- library/core/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 1076d357070ef..a6b9acb576eb4 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -209,6 +209,7 @@ #![feature(derive_const)] #![feature(doc_cfg)] #![feature(doc_notable_trait)] +#![feature(generic_arg_infer)] #![feature(rustdoc_internals)] #![feature(exhaustive_patterns)] #![feature(doc_cfg_hide)] From 20dc53208557db5672a1bcf97b3e582a95913f2c Mon Sep 17 00:00:00 2001 From: Mu42 Date: Mon, 20 Mar 2023 15:32:21 +0800 Subject: [PATCH 10/19] Remove Ty::is_region_ptr --- .../src/diagnostics/mutability_errors.rs | 13 ++++--------- compiler/rustc_codegen_cranelift/src/vtable.rs | 4 +--- compiler/rustc_codegen_ssa/src/mir/block.rs | 4 ++-- compiler/rustc_hir_typeck/src/demand.rs | 2 +- compiler/rustc_hir_typeck/src/method/suggest.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 7 +------ compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- compiler/rustc_ty_utils/src/abi.rs | 2 +- 8 files changed, 12 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index bad08451adf08..a8c216407f931 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -120,9 +120,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { && !self.upvars.is_empty() { item_msg = access_place_desc; - debug_assert!( - self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr() - ); + debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref()); debug_assert!(is_closure_or_generator( Place::ty_from( the_place_err.local, @@ -470,11 +468,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { let local_decl = &self.body.local_decls[local]; - let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() { - ("&", "reference") - } else { - ("*const", "pointer") - }; + let (pointer_sigil, pointer_desc) = + if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") }; match self.local_names[local] { Some(name) if !local_decl.from_compiler_desugaring() => { @@ -1258,7 +1253,7 @@ fn suggest_ampmut<'tcx>( ( suggestability, highlight_span, - if local_decl.ty.is_region_ptr() { + if local_decl.ty.is_ref() { format!("&mut {}", ty_mut.ty) } else { format!("*mut {}", ty_mut.ty) diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index b7bfd8fd39526..94806e0d798ed 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -48,9 +48,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( ) -> (Pointer, Value) { let (ptr, vtable) = 'block: { if let Abi::Scalar(_) = arg.layout().abi { - 'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() - && !arg.layout().ty.is_region_ptr() - { + 'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() { for i in 0..arg.layout().fields.count() { let field = arg.value_field(fx, mir::Field::new(i)); if !field.layout().is_zst() { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index f9aa2aecf65bc..6bad5c3eb2822 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -917,7 +917,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // // This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`. 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr() - && !op.layout.ty.is_region_ptr() + && !op.layout.ty.is_ref() { for i in 0..op.layout.fields.count() { let field = op.extract_field(bx, i); @@ -959,7 +959,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Immediate(_) => { // See comment above explaining why we peel these newtypes 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr() - && !op.layout.ty.is_region_ptr() + && !op.layout.ty.is_ref() { for i in 0..op.layout.fields.count() { let field = op.extract_field(bx, i); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index f65f16e317d49..23845d39a981f 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1487,7 +1487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let deref_kind = if checked_ty.is_box() { "unboxing the value" - } else if checked_ty.is_region_ptr() { + } else if checked_ty.is_ref() { "dereferencing the borrow" } else { "dereferencing the type" diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 50f2b71250c01..b219be4ae1992 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1182,7 +1182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .inputs() .skip_binder() .get(0) - .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr()) + .filter(|ty| ty.is_ref() && !rcvr_ty.is_ref()) .copied() .unwrap_or(rcvr_ty), }; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 4c606b939b25e..2e691ab250d83 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1913,11 +1913,6 @@ impl<'tcx> Ty<'tcx> { } } - #[inline] - pub fn is_region_ptr(self) -> bool { - matches!(self.kind(), Ref(..)) - } - #[inline] pub fn is_mutable_ptr(self) -> bool { matches!( @@ -1944,7 +1939,7 @@ impl<'tcx> Ty<'tcx> { /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer). #[inline] pub fn is_any_ptr(self) -> bool { - self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr() + self.is_ref() || self.is_unsafe_ptr() || self.is_fn_ptr() } #[inline] diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index cecb8a61aa2f4..6fd9b9dbb5755 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -185,7 +185,7 @@ impl<'tcx> Cx<'tcx> { if self.typeck_results().is_coercion_cast(source.hir_id) { // Convert the lexpr to a vexpr. ExprKind::Use { source: self.mirror_expr(source) } - } else if self.typeck_results().expr_ty(source).is_region_ptr() { + } else if self.typeck_results().expr_ty(source).is_ref() { // Special cased so that we can type check that the element // type of the source matches the pointed to type of the // destination. diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 35c9f95eb03b1..ee5a7909ba3dc 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -539,7 +539,7 @@ fn make_thin_self_ptr<'tcx>( // get a built-in pointer type let mut fat_pointer_layout = layout; 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() - && !fat_pointer_layout.ty.is_region_ptr() + && !fat_pointer_layout.ty.is_ref() { for i in 0..fat_pointer_layout.fields.count() { let field_layout = fat_pointer_layout.field(cx, i); From 05b5046633e9f594f955e0365a1219d1a96a5b54 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Fri, 17 Mar 2023 22:27:17 +1300 Subject: [PATCH 11/19] feat: implement error recovery in `expected_ident_found` --- .../rustc_parse/src/parser/diagnostics.rs | 84 +++++++++++++------ compiler/rustc_parse/src/parser/item.rs | 8 +- compiler/rustc_parse/src/parser/mod.rs | 13 ++- compiler/rustc_parse/src/parser/pat.rs | 10 ++- tests/ui/parser/ident-recovery.rs | 16 ++++ tests/ui/parser/ident-recovery.stderr | 42 ++++++++++ tests/ui/parser/issues/issue-104088.rs | 23 ++--- tests/ui/parser/issues/issue-104088.stderr | 48 +++++++---- 8 files changed, 175 insertions(+), 69 deletions(-) create mode 100644 tests/ui/parser/ident-recovery.rs create mode 100644 tests/ui/parser/ident-recovery.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 47d1108491530..9544afd3d6df9 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -269,13 +269,18 @@ impl<'a> Parser<'a> { } /// Emits an error with suggestions if an identifier was expected but not found. - pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + /// + /// Returns a possibly recovered identifier. + pub(super) fn expected_ident_found( + &mut self, + recover: bool, + ) -> PResult<'a, (Ident, /* is_raw */ bool)> { if let TokenKind::DocComment(..) = self.prev_token.kind { - return DocCommentDoesNotDocumentAnything { + return Err(DocCommentDoesNotDocumentAnything { span: self.prev_token.span, missing_comma: None, } - .into_diagnostic(&self.sess.span_diagnostic); + .into_diagnostic(&self.sess.span_diagnostic)); } let valid_follow = &[ @@ -290,34 +295,51 @@ impl<'a> Parser<'a> { TokenKind::CloseDelim(Delimiter::Parenthesis), ]; - let suggest_raw = match self.token.ident() { - Some((ident, false)) - if ident.is_raw_guess() - && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) => - { - Some(SuggEscapeIdentifier { - span: ident.span.shrink_to_lo(), - // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`, - // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` - ident_name: ident.name.to_string(), - }) - } - _ => None, - }; + let mut recovered_ident = None; + // we take this here so that the correct original token is retained in + // the diagnostic, regardless of eager recovery. + let bad_token = self.token.clone(); + + // suggest prepending a keyword in identifier position with `r#` + let suggest_raw = if let Some((ident, false)) = self.token.ident() + && ident.is_raw_guess() + && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) + { + recovered_ident = Some((ident, true)); + + // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`, + // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` + let ident_name = ident.name.to_string(); + + Some(SuggEscapeIdentifier { + span: ident.span.shrink_to_lo(), + ident_name + }) + } else { None }; + + let suggest_remove_comma = + if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { + if recover { + self.bump(); + recovered_ident = self.ident_or_err(false).ok(); + }; + + Some(SuggRemoveComma { span: bad_token.span }) + } else { + None + }; - let suggest_remove_comma = (self.token == token::Comma - && self.look_ahead(1, |t| t.is_ident())) - .then_some(SuggRemoveComma { span: self.token.span }); + let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, valid_portion)| { + let (invalid, valid) = self.token.span.split_at(len as u32); - let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, _valid_portion)| { - let (invalid, _valid) = self.token.span.split_at(len as u32); + recovered_ident = Some((Ident::new(valid_portion, valid), false)); HelpIdentifierStartsWithNumber { num_span: invalid } }); let err = ExpectedIdentifier { - span: self.token.span, - token: self.token.clone(), + span: bad_token.span, + token: bad_token, suggest_raw, suggest_remove_comma, help_cannot_start_number, @@ -326,6 +348,7 @@ impl<'a> Parser<'a> { // if the token we have is a `<` // it *might* be a misplaced generic + // FIXME: could we recover with this? if self.token == token::Lt { // all keywords that could have generic applied let valid_prev_keywords = @@ -376,7 +399,16 @@ impl<'a> Parser<'a> { } } - err + if let Some(recovered_ident) = recovered_ident && recover { + err.emit(); + Ok(recovered_ident) + } else { + Err(err) + } + } + + pub(super) fn expected_ident_found_err(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + self.expected_ident_found(false).unwrap_err() } /// Checks if the current token is a integer or float literal and looks like @@ -392,7 +424,7 @@ impl<'a> Parser<'a> { kind: token::LitKind::Integer | token::LitKind::Float, symbol, suffix, - }) = self.token.uninterpolate().kind + }) = self.token.kind && rustc_ast::MetaItemLit::from_token(&self.token).is_none() { Some((symbol.as_str().len(), suffix.unwrap())) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index b7415dc8fb84c..ae8fe90e9d611 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1181,7 +1181,7 @@ impl<'a> Parser<'a> { defaultness: Defaultness, ) -> PResult<'a, ItemInfo> { let impl_span = self.token.span; - let mut err = self.expected_ident_found(); + let mut err = self.expected_ident_found_err(); // Only try to recover if this is implementing a trait for a type let mut impl_info = match self.parse_item_impl(attrs, defaultness) { @@ -1776,7 +1776,7 @@ impl<'a> Parser<'a> { Err(err) => { err.cancel(); self.restore_snapshot(snapshot); - self.expected_ident_found() + self.expected_ident_found_err() } } } else if self.eat_keyword(kw::Struct) { @@ -1792,11 +1792,11 @@ impl<'a> Parser<'a> { Err(err) => { err.cancel(); self.restore_snapshot(snapshot); - self.expected_ident_found() + self.expected_ident_found_err() } } } else { - let mut err = self.expected_ident_found(); + let mut err = self.expected_ident_found_err(); if self.eat_keyword_noexpect(kw::Let) && let removal_span = self.prev_token.span.until(self.token.span) && let Ok(ident) = self.parse_ident_common(false) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 6991520895ddd..53c25a80c4bf3 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -553,8 +553,9 @@ impl<'a> Parser<'a> { fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> { let (ident, is_raw) = self.ident_or_err(recover)?; + if !is_raw && ident.is_reserved() { - let mut err = self.expected_ident_found(); + let mut err = self.expected_ident_found_err(); if recover { err.emit(); } else { @@ -565,12 +566,16 @@ impl<'a> Parser<'a> { Ok(ident) } - fn ident_or_err(&mut self, _recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> { - let result = self.token.ident().ok_or_else(|| self.expected_ident_found()); + fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> { + let result = self.token.ident().ok_or_else(|| self.expected_ident_found(recover)); let (ident, is_raw) = match result { Ok(ident) => ident, - Err(err) => return Err(err), + Err(err) => match err { + // we recovered! + Ok(ident) => ident, + Err(err) => return Err(err), + }, }; Ok((ident, is_raw)) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index d9af241584868..2246002f5d32a 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -391,7 +391,13 @@ impl<'a> Parser<'a> { } else { PatKind::Lit(const_expr) } - } else if self.can_be_ident_pat() || self.is_lit_bad_ident().is_some() { + // Don't eagerly error on semantically invalid tokens when matching + // declarative macros, as the input to those doesn't have to be + // semantically valid. For attribute/derive proc macros this is not the + // case, so doing the recovery for them is fine. + } else if self.can_be_ident_pat() + || (self.is_lit_bad_ident().is_some() && self.may_recover()) + { // Parse `ident @ pat` // This can give false positives and parse nullary enums, // they are dealt with later in resolve. @@ -590,7 +596,7 @@ impl<'a> Parser<'a> { // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`. if let token::Interpolated(nt) = &self.token.kind { if let token::NtPat(_) = **nt { - self.expected_ident_found().emit(); + self.expected_ident_found_err().emit(); } } diff --git a/tests/ui/parser/ident-recovery.rs b/tests/ui/parser/ident-recovery.rs new file mode 100644 index 0000000000000..7575372b940fd --- /dev/null +++ b/tests/ui/parser/ident-recovery.rs @@ -0,0 +1,16 @@ +fn ,comma() { + //~^ ERROR expected identifier, found `,` + struct Foo { + x: i32,, + //~^ ERROR expected identifier, found `,` + y: u32, + } +} + +fn break() { +//~^ ERROR expected identifier, found keyword `break` + let continue = 5; + //~^ ERROR expected identifier, found keyword `continue` +} + +fn main() {} diff --git a/tests/ui/parser/ident-recovery.stderr b/tests/ui/parser/ident-recovery.stderr new file mode 100644 index 0000000000000..e9a55026d1245 --- /dev/null +++ b/tests/ui/parser/ident-recovery.stderr @@ -0,0 +1,42 @@ +error: expected identifier, found `,` + --> $DIR/ident-recovery.rs:1:4 + | +LL | fn ,comma() { + | ^ + | | + | expected identifier + | help: remove this comma + +error: expected identifier, found `,` + --> $DIR/ident-recovery.rs:4:16 + | +LL | x: i32,, + | ^ + | | + | expected identifier + | help: remove this comma + +error: expected identifier, found keyword `break` + --> $DIR/ident-recovery.rs:10:4 + | +LL | fn break() { + | ^^^^^ expected identifier, found keyword + | +help: escape `break` to use it as an identifier + | +LL | fn r#break() { + | ++ + +error: expected identifier, found keyword `continue` + --> $DIR/ident-recovery.rs:12:9 + | +LL | let continue = 5; + | ^^^^^^^^ expected identifier, found keyword + | +help: escape `continue` to use it as an identifier + | +LL | let r#continue = 5; + | ++ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/parser/issues/issue-104088.rs b/tests/ui/parser/issues/issue-104088.rs index 86988c8cd21da..3dc636b6a33bd 100644 --- a/tests/ui/parser/issues/issue-104088.rs +++ b/tests/ui/parser/issues/issue-104088.rs @@ -1,26 +1,19 @@ -fn test() { +fn 1234test() { +//~^ ERROR expected identifier, found `1234test` if let 123 = 123 { println!("yes"); } -} - -fn test_2() { - let 1x = 123; - //~^ ERROR expected identifier, found `1x` -} - -fn test_3() { - let 2x: i32 = 123; - //~^ ERROR expected identifier, found `2x` -} -fn test_4() { if let 2e1 = 123 { //~^ ERROR mismatched types } -} -fn test_5() { let 23name = 123; //~^ ERROR expected identifier, found `23name` + + let 2x: i32 = 123; + //~^ ERROR expected identifier, found `2x` + + let 1x = 123; + //~^ ERROR expected identifier, found `1x` } fn main() {} diff --git a/tests/ui/parser/issues/issue-104088.stderr b/tests/ui/parser/issues/issue-104088.stderr index 08ea1c891c172..8b751759d69a6 100644 --- a/tests/ui/parser/issues/issue-104088.stderr +++ b/tests/ui/parser/issues/issue-104088.stderr @@ -1,47 +1,59 @@ -error: expected identifier, found `1x` - --> $DIR/issue-104088.rs:6:9 +error: expected identifier, found `1234test` + --> $DIR/issue-104088.rs:1:4 | -LL | let 1x = 123; - | ^^ expected identifier +LL | fn 1234test() { + | ^^^^^^^^ expected identifier | help: identifiers cannot start with a number - --> $DIR/issue-104088.rs:6:9 + --> $DIR/issue-104088.rs:1:4 | -LL | let 1x = 123; - | ^ +LL | fn 1234test() { + | ^^^^ + +error: expected identifier, found `23name` + --> $DIR/issue-104088.rs:9:9 + | +LL | let 23name = 123; + | ^^^^^^ expected identifier + | +help: identifiers cannot start with a number + --> $DIR/issue-104088.rs:9:9 + | +LL | let 23name = 123; + | ^^ error: expected identifier, found `2x` - --> $DIR/issue-104088.rs:11:9 + --> $DIR/issue-104088.rs:12:9 | LL | let 2x: i32 = 123; | ^^ expected identifier | help: identifiers cannot start with a number - --> $DIR/issue-104088.rs:11:9 + --> $DIR/issue-104088.rs:12:9 | LL | let 2x: i32 = 123; | ^ -error: expected identifier, found `23name` - --> $DIR/issue-104088.rs:22:9 +error: expected identifier, found `1x` + --> $DIR/issue-104088.rs:15:9 | -LL | let 23name = 123; - | ^^^^^^ expected identifier +LL | let 1x = 123; + | ^^ expected identifier | help: identifiers cannot start with a number - --> $DIR/issue-104088.rs:22:9 + --> $DIR/issue-104088.rs:15:9 | -LL | let 23name = 123; - | ^^ +LL | let 1x = 123; + | ^ error[E0308]: mismatched types - --> $DIR/issue-104088.rs:16:12 + --> $DIR/issue-104088.rs:5:12 | LL | if let 2e1 = 123 { | ^^^ --- this expression has type `{integer}` | | | expected integer, found floating-point number -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0308`. From 460ecd288a34f73f9178acc723a459cbfe77607a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 16 Mar 2023 10:05:09 +0000 Subject: [PATCH 12/19] Eagerly intern and check CrateNum/StableCrateId collisions --- Cargo.lock | 1 + compiler/rustc_metadata/src/creader.rs | 75 ++++++------------- compiler/rustc_metadata/src/rmeta/decoder.rs | 4 - .../src/rmeta/decoder/cstore_impl.rs | 5 +- compiler/rustc_span/Cargo.toml | 1 + compiler/rustc_span/src/def_id.rs | 6 +- tests/run-make-fulldeps/issue-83045/Makefile | 2 +- 7 files changed, 33 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c0b5d6ab3b57..aa4d79ed26117 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5294,6 +5294,7 @@ name = "rustc_span" version = "0.0.0" dependencies = [ "cfg-if", + "indexmap", "md-5", "rustc_arena", "rustc_data_structures", diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index f870a1db82d9c..538e61c985104 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -6,11 +6,11 @@ use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::{self as ast, *}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard}; use rustc_expand::base::SyntaxExtension; -use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_index::vec::IndexVec; use rustc_middle::ty::TyCtxt; @@ -46,9 +46,8 @@ pub struct CStore { /// This crate has a `#[alloc_error_handler]` item. has_alloc_error_handler: bool, - /// This map is used to verify we get no hash conflicts between - /// `StableCrateId` values. - pub(crate) stable_crate_ids: FxHashMap, + /// The interned [StableCrateId]s. + pub(crate) stable_crate_ids: StableCrateIdMap, /// Unused externs of the crate unused_externs: Vec, @@ -144,9 +143,21 @@ impl CStore { }) } - fn alloc_new_crate_num(&mut self) -> CrateNum { - self.metas.push(None); - CrateNum::new(self.metas.len() - 1) + fn intern_stable_crate_id(&mut self, root: &CrateRoot) -> Result { + assert_eq!(self.metas.len(), self.stable_crate_ids.len()); + let num = CrateNum::new(self.stable_crate_ids.len()); + if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) { + let crate_name0 = root.name(); + if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) { + Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1)) + } else { + Err(CrateError::SymbolConflictsCurrent(crate_name0)) + } + } else { + self.metas.push(None); + self.stable_crate_ids.insert(root.stable_crate_id(), num); + Ok(num) + } } pub fn has_crate_data(&self, cnum: CrateNum) -> bool { @@ -247,7 +258,7 @@ impl CStore { } pub fn new(sess: &Session) -> CStore { - let mut stable_crate_ids = FxHashMap::default(); + let mut stable_crate_ids = StableCrateIdMap::default(); stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE); CStore { // We add an empty entry for LOCAL_CRATE (which maps to zero) in @@ -342,42 +353,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { None } - fn verify_no_symbol_conflicts(&self, root: &CrateRoot) -> Result<(), CrateError> { - // Check for (potential) conflicts with the local crate - if self.sess.local_stable_crate_id() == root.stable_crate_id() { - return Err(CrateError::SymbolConflictsCurrent(root.name())); - } - - // Check for conflicts with any crate loaded so far - for (_, other) in self.cstore.iter_crate_data() { - // Same stable crate id but different SVH - if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() { - bug!( - "Previously returned E0523 here. \ - See https://github.com/rust-lang/rust/pull/100599 for additional discussion.\ - root.name() = {}.", - root.name() - ); - } - } - - Ok(()) - } - - fn verify_no_stable_crate_id_hash_conflicts( - &mut self, - root: &CrateRoot, - cnum: CrateNum, - ) -> Result<(), CrateError> { - if let Some(existing) = self.cstore.stable_crate_ids.insert(root.stable_crate_id(), cnum) { - let crate_name0 = root.name(); - let crate_name1 = self.cstore.get_crate_data(existing).name(); - return Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1)); - } - - Ok(()) - } - fn register_crate( &mut self, host_lib: Option, @@ -396,7 +371,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { self.sess.opts.externs.get(name.as_str()).map_or(false, |e| e.is_private_dep); // Claim this crate number and cache it - let cnum = self.cstore.alloc_new_crate_num(); + let cnum = self.cstore.intern_stable_crate_id(&crate_root)?; info!( "register crate `{}` (cnum = {}. private_dep = {})", @@ -432,14 +407,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { None }; - // Perform some verification *after* resolve_crate_deps() above is - // known to have been successful. It seems that - in error cases - the - // cstore can be in a temporarily invalid state between cnum allocation - // and dependency resolution and the verification code would produce - // ICEs in that case (see #83045). - self.verify_no_symbol_conflicts(&crate_root)?; - self.verify_no_stable_crate_id_hash_conflicts(&crate_root, cnum)?; - let crate_metadata = CrateMetadata::new( self.sess, &self.cstore, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 0070e46ffdf02..cabc144077fd5 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1709,10 +1709,6 @@ impl CrateMetadata { self.root.name } - pub(crate) fn stable_crate_id(&self) -> StableCrateId { - self.root.stable_crate_id - } - pub(crate) fn hash(&self) -> Svh { self.root.hash } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index a98433953367b..e0f1435ccb3ae 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -615,7 +615,10 @@ impl CrateStore for CStore { } fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum { - self.stable_crate_ids[&stable_crate_id] + *self + .stable_crate_ids + .get(&stable_crate_id) + .unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}")) } /// Returns the `DefKey` for a given `DefId`. This indicates the diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index ae81d95e27967..98d6e0ab117a3 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -18,3 +18,4 @@ tracing = "0.1" sha1 = "0.10.0" sha2 = "0.10.1" md5 = { package = "md-5", version = "0.10.0" } +indexmap = { version = "1.9.1" } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 162c15574b56c..b2c58caff2ec4 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -1,13 +1,17 @@ use crate::{HashStableContext, Symbol}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::unhash::Unhasher; use rustc_data_structures::AtomicRef; use rustc_index::vec::Idx; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::borrow::Borrow; use std::fmt; -use std::hash::{Hash, Hasher}; +use std::hash::{BuildHasherDefault, Hash, Hasher}; + +pub type StableCrateIdMap = + indexmap::IndexMap>; rustc_index::newtype_index! { #[custom_encodable] diff --git a/tests/run-make-fulldeps/issue-83045/Makefile b/tests/run-make-fulldeps/issue-83045/Makefile index 34853cb1d31e5..fc180ccfe28e2 100644 --- a/tests/run-make-fulldeps/issue-83045/Makefile +++ b/tests/run-make-fulldeps/issue-83045/Makefile @@ -29,5 +29,5 @@ all: --crate-type=rlib \ --edition=2018 \ c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0 - $(CGREP) E0463 < $(TMPDIR)/output.txt + $(CGREP) E0519 < $(TMPDIR)/output.txt $(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt From 47f24a881bb05293c4d922218d9dfed7e29511cd Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 21 Mar 2023 16:26:23 +0100 Subject: [PATCH 13/19] new solver cleanup + coherence --- compiler/rustc_middle/src/traits/solve.rs | 11 ++- .../src/solve/assembly.rs | 69 +++++++++++-------- .../src/solve/eval_ctxt.rs | 9 ++- .../rustc_trait_selection/src/solve/mod.rs | 19 +++-- .../src/solve/project_goals.rs | 6 +- .../src/solve/search_graph/mod.rs | 13 +++- .../src/solve/trait_goals.rs | 27 +++++++- .../rustc_trait_selection/src/traits/mod.rs | 2 +- .../new-solver/coherence/issue-102048.rs | 44 ++++++++++++ .../new-solver/coherence/issue-102048.stderr | 12 ++++ .../coherence-conflict.next.stderr | 11 +++ ...t.stderr => coherence-conflict.old.stderr} | 2 +- .../reservation-impl/coherence-conflict.rs | 3 +- .../{no-use.stderr => no-use.next.stderr} | 2 +- .../traits/reservation-impl/no-use.old.stderr | 13 ++++ tests/ui/traits/reservation-impl/no-use.rs | 3 +- .../traits/reservation-impl/non-lattice-ok.rs | 6 ++ tests/ui/traits/reservation-impl/ok.rs | 3 + 18 files changed, 203 insertions(+), 52 deletions(-) create mode 100644 tests/ui/traits/new-solver/coherence/issue-102048.rs create mode 100644 tests/ui/traits/new-solver/coherence/issue-102048.stderr create mode 100644 tests/ui/traits/reservation-impl/coherence-conflict.next.stderr rename tests/ui/traits/reservation-impl/{coherence-conflict.stderr => coherence-conflict.old.stderr} (91%) rename tests/ui/traits/reservation-impl/{no-use.stderr => no-use.next.stderr} (93%) create mode 100644 tests/ui/traits/reservation-impl/no-use.old.stderr diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 92d3e73e683cd..f47f4cbdb4db7 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -63,14 +63,13 @@ impl Certainty { (Certainty::Yes, Certainty::Yes) => Certainty::Yes, (Certainty::Yes, Certainty::Maybe(_)) => other, (Certainty::Maybe(_), Certainty::Yes) => self, - (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => { + (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => { Certainty::Maybe(MaybeCause::Overflow) } - // If at least one of the goals is ambiguous, hide the overflow as the ambiguous goal - // may still result in failure. - (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(_)) - | (Certainty::Maybe(_), Certainty::Maybe(MaybeCause::Ambiguity)) => { - Certainty::Maybe(MaybeCause::Ambiguity) + (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Overflow)) + | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity)) + | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => { + Certainty::Maybe(MaybeCause::Overflow) } } } diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 76cde1a669225..8cb09108e83ca 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -2,7 +2,8 @@ #[cfg(doc)] use super::trait_goals::structural_traits::*; -use super::EvalCtxt; +use super::{EvalCtxt, SolverMode}; +use crate::traits::coherence; use itertools::Itertools; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; @@ -87,6 +88,8 @@ pub(super) enum CandidateSource { pub(super) trait GoalKind<'tcx>: TypeFoldable> + Copy + Eq { fn self_ty(self) -> Ty<'tcx>; + fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>; + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self; fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId; @@ -244,15 +247,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.assemble_object_bound_candidates(goal, &mut candidates); + self.assemble_coherence_unknowable_candidates(goal, &mut candidates); + candidates } /// If the self type of a goal is a projection, computing the relevant candidates is difficult. /// /// To deal with this, we first try to normalize the self type and add the candidates for the normalized - /// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in - /// this case as projections as self types add - // FIXME complete the unfinished sentence above + /// self type to the list of candidates in case that succeeds. We also have to consider candidates with the + /// projection as a self type as well fn assemble_candidates_after_normalizing_self_ty>( &mut self, goal: Goal<'tcx, G>, @@ -468,14 +472,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + fn assemble_coherence_unknowable_candidates>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + match self.solver_mode() { + SolverMode::Normal => return, + SolverMode::Coherence => { + let trait_ref = goal.predicate.trait_ref(self.tcx()); + match coherence::trait_ref_is_knowable(self.tcx(), trait_ref) { + Ok(()) => {} + Err(_) => match self + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + { + Ok(result) => candidates + .push(Candidate { source: CandidateSource::BuiltinImpl, result }), + // FIXME: This will be reachable at some point if we're in + // `assemble_candidates_after_normalizing_self_ty` and we get a + // universe error. We'll deal with it at this point. + Err(NoSolution) => bug!("coherence candidate resulted in NoSolution"), + }, + } + } + } + } + #[instrument(level = "debug", skip(self), ret)] - pub(super) fn merge_candidates_and_discard_reservation_impls( + pub(super) fn merge_candidates( &mut self, mut candidates: Vec>, ) -> QueryResult<'tcx> { match candidates.len() { 0 => return Err(NoSolution), - 1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result), + 1 => return Ok(candidates.pop().unwrap().result), _ => {} } @@ -483,10 +513,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let mut i = 0; 'outer: while i < candidates.len() { for j in (0..candidates.len()).filter(|&j| i != j) { - if self.trait_candidate_should_be_dropped_in_favor_of( - &candidates[i], - &candidates[j], - ) { + if self.candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j]) + { debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len()); candidates.swap_remove(i); continue 'outer; @@ -511,11 +539,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - // FIXME: What if there are >1 candidates left with the same response, and one is a reservation impl? - Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result) + Ok(candidates.pop().unwrap().result) } - fn trait_candidate_should_be_dropped_in_favor_of( + fn candidate_should_be_dropped_in_favor_of( &self, candidate: &Candidate<'tcx>, other: &Candidate<'tcx>, @@ -528,20 +555,4 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | (CandidateSource::BuiltinImpl, _) => false, } } - - fn discard_reservation_impl(&mut self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> { - if let CandidateSource::Impl(def_id) = candidate.source { - if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) { - debug!("Selected reservation impl"); - // We assemble all candidates inside of a probe so by - // making a new canonical response here our result will - // have no constraints. - candidate.result = self - .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - .unwrap(); - } - } - - candidate - } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 9541292235795..4b85be69e61bd 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -17,6 +17,7 @@ use rustc_span::DUMMY_SP; use std::ops::ControlFlow; use super::search_graph::{self, OverflowHandler}; +use super::SolverMode; use super::{search_graph::SearchGraph, Goal}; pub struct EvalCtxt<'a, 'tcx> { @@ -78,7 +79,9 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, ) -> Result<(bool, Certainty), NoSolution> { - let mut search_graph = search_graph::SearchGraph::new(self.tcx); + let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; + + let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode); let mut ecx = EvalCtxt { search_graph: &mut search_graph, @@ -101,6 +104,10 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { } impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { + pub(super) fn solver_mode(&self) -> SolverMode { + self.search_graph.solver_mode() + } + /// The entry point of the solver. /// /// This function deals with (coinductive) cycles, overflow, and caching diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 606c2eaa51051..89f4056a58db4 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -9,10 +9,6 @@ //! FIXME(@lcnr): Write that section. If you read this before then ask me //! about it on zulip. -// FIXME: Instead of using `infcx.canonicalize_query` we have to add a new routine which -// preserves universes and creates a unique var (in the highest universe) for each -// appearance of a region. - // FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented. use rustc_hir::def_id::DefId; @@ -41,6 +37,19 @@ mod trait_goals; pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt}; pub use fulfill::FulfillmentCtxt; +#[derive(Debug, Clone, Copy)] +enum SolverMode { + /// Ordinary trait solving, using everywhere except for coherence. + Normal, + /// Trait solving during coherence. There are a few notable differences + /// between coherence and ordinary trait solving. + /// + /// Most importantly, trait solving during coherence must not be incomplete, + /// i.e. return `Err(NoSolution)` for goals for which a solution exists. + /// This means that we must not make any guesses or arbitrary choices. + Coherence, +} + trait CanonicalResponseExt { fn has_no_inference_or_external_constraints(&self) -> bool; } @@ -255,7 +264,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return Err(NoSolution); } - // FIXME(-Ztreat-solver=next): We should instead try to find a `Certainty::Yes` response with + // FIXME(-Ztrait-solver=next): We should instead try to find a `Certainty::Yes` response with // a subset of the constraints that all the other responses have. let one = candidates[0]; if candidates[1..].iter().all(|resp| resp == &one) { diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 93d77c39f9580..998859966528b 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -34,7 +34,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // projection cache in the solver. if self.term_is_fully_unconstrained(goal) { let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates_and_discard_reservation_impls(candidates) + self.merge_candidates(candidates) } else { let predicate = goal.predicate; let unconstrained_rhs = self.next_term_infer_of_kind(predicate.term); @@ -56,6 +56,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { self.self_ty() } + fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { + self.projection_ty.trait_ref(tcx) + } + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { self.with_self_ty(tcx, self_ty) } diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 83d77a69c0020..b94c44cbdd038 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -1,8 +1,9 @@ mod cache; mod overflow; +pub(super) use overflow::OverflowHandler; + use self::cache::ProvisionalEntry; -pub(super) use crate::solve::search_graph::overflow::OverflowHandler; use cache::ProvisionalCache; use overflow::OverflowData; use rustc_index::vec::IndexVec; @@ -11,6 +12,8 @@ use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryRes use rustc_middle::ty::TyCtxt; use std::{collections::hash_map::Entry, mem}; +use super::SolverMode; + rustc_index::newtype_index! { pub struct StackDepth {} } @@ -21,6 +24,7 @@ struct StackElem<'tcx> { } pub(super) struct SearchGraph<'tcx> { + mode: SolverMode, /// The stack of goals currently being computed. /// /// An element is *deeper* in the stack if its index is *lower*. @@ -30,14 +34,19 @@ pub(super) struct SearchGraph<'tcx> { } impl<'tcx> SearchGraph<'tcx> { - pub(super) fn new(tcx: TyCtxt<'tcx>) -> SearchGraph<'tcx> { + pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> { Self { + mode, stack: Default::default(), overflow_data: OverflowData::new(tcx), provisional_cache: ProvisionalCache::empty(), } } + pub(super) fn solver_mode(&self) -> SolverMode { + self.mode + } + pub(super) fn is_empty(&self) -> bool { self.stack.is_empty() && self.provisional_cache.is_empty() } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 8ab55c79fc450..2ebdfc8fe72a1 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -2,7 +2,7 @@ use std::iter; -use super::{assembly, EvalCtxt}; +use super::{assembly, EvalCtxt, SolverMode}; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; use rustc_infer::traits::query::NoSolution; @@ -20,6 +20,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { self.self_ty() } + fn trait_ref(self, _: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { + self.trait_ref + } + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { self.with_self_ty(tcx, self_ty) } @@ -43,6 +47,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } + let impl_polarity = tcx.impl_polarity(impl_def_id); + // An upper bound of the certainty of this goal, used to lower the certainty + // of reservation impl to ambiguous during coherence. + let maximal_certainty = match impl_polarity { + ty::ImplPolarity::Positive | ty::ImplPolarity::Negative => { + match impl_polarity == goal.predicate.polarity { + true => Certainty::Yes, + false => return Err(NoSolution), + } + } + ty::ImplPolarity::Reservation => match ecx.solver_mode() { + SolverMode::Normal => return Err(NoSolution), + SolverMode::Coherence => Certainty::AMBIGUOUS, + }, + }; + ecx.probe(|ecx| { let impl_substs = ecx.fresh_substs_for_item(impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); @@ -55,7 +75,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { .into_iter() .map(|pred| goal.with(tcx, pred)); ecx.add_goals(where_clause_bounds); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + + ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty) }) } @@ -547,6 +568,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, TraitPredicate<'tcx>>, ) -> QueryResult<'tcx> { let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates_and_discard_reservation_impls(candidates) + self.merge_candidates(candidates) } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index bfeda88a6d40c..2de420b52940a 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -4,7 +4,7 @@ pub mod auto_trait; mod chalk_fulfill; -mod coherence; +pub(crate) mod coherence; pub mod const_evaluatable; mod engine; pub mod error_reporting; diff --git a/tests/ui/traits/new-solver/coherence/issue-102048.rs b/tests/ui/traits/new-solver/coherence/issue-102048.rs new file mode 100644 index 0000000000000..11636bfeb5509 --- /dev/null +++ b/tests/ui/traits/new-solver/coherence/issue-102048.rs @@ -0,0 +1,44 @@ +// This must fail coherence. +// +// Getting this to pass was fairly difficult, so here's an explanation +// of what's happening: +// +// Normalizing projections currently tries to replace them with inference variables +// while emitting a nested `Projection` obligation. This cannot be done if the projection +// has bound variables which is the case here. +// +// So the projections stay until after normalization. When unifying two projections we +// currently treat them as if they are injective, so we **incorrectly** unify their +// substs. This means that coherence for the two impls ends up unifying `?T` and `?U` +// as it tries to unify `>::Assoc` with `>::Assoc`. +// +// `impl1` therefore has the projection `>::Assoc` and we have the +// assumption `?T: for<'a> WithAssoc2<'a, Assoc = i32>` in the `param_env`, so we normalize +// that to `i32`. We then try to unify `i32` from `impl1` with `u32` from `impl2` which fails, +// causing coherence to consider these two impls distinct. + +// compile-flags: -Ztrait-solver=next +pub trait Trait {} + +pub trait WithAssoc1<'a> { + type Assoc; +} +pub trait WithAssoc2<'a> { + type Assoc; +} + +// impl 1 +impl Trait fn(>::Assoc, >::Assoc)> for (T, U) +where + T: for<'a> WithAssoc1<'a> + for<'a> WithAssoc2<'a, Assoc = i32>, + U: for<'a> WithAssoc2<'a>, +{ +} + +// impl 2 +impl Trait fn(>::Assoc, u32)> for (T, U) where + U: for<'a> WithAssoc1<'a> //~^ ERROR conflicting implementations of trait +{ +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/coherence/issue-102048.stderr b/tests/ui/traits/new-solver/coherence/issue-102048.stderr new file mode 100644 index 0000000000000..17a43838fe275 --- /dev/null +++ b/tests/ui/traits/new-solver/coherence/issue-102048.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait fn(<_ as WithAssoc1<'a>>::Assoc, <_ as WithAssoc2<'a>>::Assoc)>` for type `(_, _)` + --> $DIR/issue-102048.rs:39:1 + | +LL | impl Trait fn(>::Assoc, >::Assoc)> for (T, U) + | --------------------------------------------------------------------------------------------------- first implementation here +... +LL | impl Trait fn(>::Assoc, u32)> for (T, U) where + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_, _)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr b/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr new file mode 100644 index 0000000000000..e5a3c3f5cc4b7 --- /dev/null +++ b/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `OtherTrait` for type `()` + --> $DIR/coherence-conflict.rs:12:1 + | +LL | impl OtherTrait for () {} + | ---------------------- first implementation here +LL | impl OtherTrait for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.stderr b/tests/ui/traits/reservation-impl/coherence-conflict.old.stderr similarity index 91% rename from tests/ui/traits/reservation-impl/coherence-conflict.stderr rename to tests/ui/traits/reservation-impl/coherence-conflict.old.stderr index a811d7e32016b..393350ea3f12a 100644 --- a/tests/ui/traits/reservation-impl/coherence-conflict.stderr +++ b/tests/ui/traits/reservation-impl/coherence-conflict.old.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `OtherTrait` for type `()` - --> $DIR/coherence-conflict.rs:11:1 + --> $DIR/coherence-conflict.rs:12:1 | LL | impl OtherTrait for () {} | ---------------------- first implementation here diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.rs b/tests/ui/traits/reservation-impl/coherence-conflict.rs index fa4a309315b47..6bbd90f94dc39 100644 --- a/tests/ui/traits/reservation-impl/coherence-conflict.rs +++ b/tests/ui/traits/reservation-impl/coherence-conflict.rs @@ -1,5 +1,6 @@ // check that reservation impls are accounted for in negative reasoning. - +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next #![feature(rustc_attrs)] trait MyTrait {} diff --git a/tests/ui/traits/reservation-impl/no-use.stderr b/tests/ui/traits/reservation-impl/no-use.next.stderr similarity index 93% rename from tests/ui/traits/reservation-impl/no-use.stderr rename to tests/ui/traits/reservation-impl/no-use.next.stderr index cefb2a8792f17..542e3a28adf28 100644 --- a/tests/ui/traits/reservation-impl/no-use.stderr +++ b/tests/ui/traits/reservation-impl/no-use.next.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `(): MyTrait` is not satisfied - --> $DIR/no-use.rs:10:26 + --> $DIR/no-use.rs:11:26 | LL | <() as MyTrait>::foo(&()); | -------------------- ^^^ the trait `MyTrait` is not implemented for `()` diff --git a/tests/ui/traits/reservation-impl/no-use.old.stderr b/tests/ui/traits/reservation-impl/no-use.old.stderr new file mode 100644 index 0000000000000..542e3a28adf28 --- /dev/null +++ b/tests/ui/traits/reservation-impl/no-use.old.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `(): MyTrait` is not satisfied + --> $DIR/no-use.rs:11:26 + | +LL | <() as MyTrait>::foo(&()); + | -------------------- ^^^ the trait `MyTrait` is not implemented for `()` + | | + | required by a bound introduced by this call + | + = help: the trait `MyTrait` is implemented for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/reservation-impl/no-use.rs b/tests/ui/traits/reservation-impl/no-use.rs index 65a55d9e20936..864f1791fd0a7 100644 --- a/tests/ui/traits/reservation-impl/no-use.rs +++ b/tests/ui/traits/reservation-impl/no-use.rs @@ -1,5 +1,6 @@ // check that reservation impls can't be used as normal impls in positive reasoning. - +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next #![feature(rustc_attrs)] trait MyTrait { fn foo(&self); } diff --git a/tests/ui/traits/reservation-impl/non-lattice-ok.rs b/tests/ui/traits/reservation-impl/non-lattice-ok.rs index a71051243c893..7787904d9b22d 100644 --- a/tests/ui/traits/reservation-impl/non-lattice-ok.rs +++ b/tests/ui/traits/reservation-impl/non-lattice-ok.rs @@ -30,6 +30,12 @@ // // [ii]: https://smallcultfollowing.com/babysteps/blog/2016/09/24/intersection-impls/ + +// check that reservation impls can't be used as normal impls in positive reasoning. + +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next + #![feature(rustc_attrs, never_type)] trait MyTrait {} diff --git a/tests/ui/traits/reservation-impl/ok.rs b/tests/ui/traits/reservation-impl/ok.rs index 611c8d8841323..8ff6645a2b3d3 100644 --- a/tests/ui/traits/reservation-impl/ok.rs +++ b/tests/ui/traits/reservation-impl/ok.rs @@ -3,6 +3,9 @@ // rpass test for reservation impls. Not 100% required because `From` uses them, // but still. +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next + #![feature(rustc_attrs)] use std::mem; From 938434ab82609c8de83028fa80bde4d6d28c282a Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 21 Mar 2023 16:34:04 +0100 Subject: [PATCH 14/19] enable `intercrate` in the solver `InferCtxt` --- compiler/rustc_infer/src/infer/mod.rs | 4 ++-- .../rustc_trait_selection/src/solve/eval_ctxt.rs | 10 ++++++++-- .../rustc_trait_selection/src/traits/coherence.rs | 14 ++++++++++---- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index aeb4ddb421259..ed5fd590934f3 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -585,8 +585,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } - pub fn intercrate(mut self) -> Self { - self.intercrate = true; + pub fn intercrate(mut self, intercrate: bool) -> Self { + self.intercrate = intercrate; self } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 4b85be69e61bd..c492c8c0aea05 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -127,8 +127,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // // The actual solver logic happens in `ecx.compute_goal`. search_graph.with_new_goal(tcx, canonical_goal, |search_graph| { - let (ref infcx, goal, var_values) = - tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); + let intercrate = match search_graph.solver_mode() { + SolverMode::Normal => false, + SolverMode::Coherence => true, + }; + let (ref infcx, goal, var_values) = tcx + .infer_ctxt() + .intercrate(intercrate) + .build_with_canonical(DUMMY_SP, &canonical_goal); let mut ecx = EvalCtxt { infcx, var_values, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index f4cfe4ec0b0ce..5bb0cdda1af0f 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -95,8 +95,11 @@ pub fn overlapping_impls( return None; } - let infcx = - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build(); + let infcx = tcx + .infer_ctxt() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .intercrate(true) + .build(); let selcx = &mut SelectionContext::new(&infcx); let overlaps = overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some(); @@ -107,8 +110,11 @@ pub fn overlapping_impls( // In the case where we detect an error, run the check again, but // this time tracking intercrate ambiguity causes for better // diagnostics. (These take time and can lead to false errors.) - let infcx = - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build(); + let infcx = tcx + .infer_ctxt() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .intercrate(true) + .build(); let selcx = &mut SelectionContext::new(&infcx); selcx.enable_tracking_intercrate_ambiguity_causes(); Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap()) From a7ec045be8133fe679c34a7eaba989ca6975d53e Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 21 Mar 2023 16:38:40 +0100 Subject: [PATCH 15/19] disable global caching during coherence --- compiler/rustc_trait_selection/src/solve/search_graph/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index b94c44cbdd038..219890b9dc42c 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -254,7 +254,8 @@ impl<'tcx> SearchGraph<'tcx> { // dependencies, our non-root goal may no longer appear as child of the root goal. // // See https://github.com/rust-lang/rust/pull/108071 for some additional context. - let should_cache_globally = !self.overflow_data.did_overflow() || self.stack.is_empty(); + let should_cache_globally = matches!(self.solver_mode(), SolverMode::Normal) + && (!self.overflow_data.did_overflow() || self.stack.is_empty()); if should_cache_globally { tcx.new_solver_evaluation_cache.insert( current_goal.goal, From f86b0358f81aa67ff5ca8abf90935226fcab4f40 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 21 Mar 2023 16:39:24 +0100 Subject: [PATCH 16/19] woops --- compiler/rustc_middle/src/traits/solve.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index f47f4cbdb4db7..512d67f34b97d 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -64,7 +64,7 @@ impl Certainty { (Certainty::Yes, Certainty::Maybe(_)) => other, (Certainty::Maybe(_), Certainty::Yes) => self, (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => { - Certainty::Maybe(MaybeCause::Overflow) + Certainty::Maybe(MaybeCause::Ambiguity) } (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Overflow)) | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity)) From 293f21c876278df7943eea889dacd977155a2f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 21 Mar 2023 01:09:00 +0100 Subject: [PATCH 17/19] iat selection: erase regions in self type --- .../rustc_hir_analysis/src/astconv/mod.rs | 82 ++++++++++++------- .../issue-109299-1.rs | 12 +++ .../issue-109299-1.stderr | 15 ++++ .../associated-inherent-types/issue-109299.rs | 12 +++ .../issue-109299.stderr | 11 +++ 5 files changed, 101 insertions(+), 31 deletions(-) create mode 100644 tests/ui/associated-inherent-types/issue-109299-1.rs create mode 100644 tests/ui/associated-inherent-types/issue-109299-1.stderr create mode 100644 tests/ui/associated-inherent-types/issue-109299.rs create mode 100644 tests/ui/associated-inherent-types/issue-109299.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 6a27383121d2d..9d3f8c2b3e74f 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -31,6 +31,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::middle::stability::AllowUnstable; +use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::DynKind; use rustc_middle::ty::GenericParamDefKind; @@ -2226,47 +2227,66 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let param_env = tcx.param_env(block.owner.to_def_id()); let cause = ObligationCause::misc(span, block.owner.def_id); + let mut fulfillment_errors = Vec::new(); - let mut applicable_candidates: Vec<_> = candidates - .iter() - .filter_map(|&(impl_, (assoc_item, def_scope))| { - infcx.probe(|_| { - let ocx = ObligationCtxt::new_in_snapshot(&infcx); + let mut applicable_candidates: Vec<_> = infcx.probe(|_| { + let universe = infcx.create_next_universe(); + + // Regions are not considered during selection. + let self_ty = tcx.replace_escaping_bound_vars_uncached( + self_ty, + FnMutDelegate { + regions: &mut |_| tcx.lifetimes.re_erased, + types: &mut |bv| { + tcx.mk_placeholder(ty::PlaceholderType { universe, name: bv.kind }) + }, + consts: &mut |bv, ty| { + tcx.mk_const(ty::PlaceholderConst { universe, name: bv }, ty) + }, + }, + ); - let impl_ty = tcx.type_of(impl_); - let impl_substs = infcx.fresh_item_substs(impl_); - let impl_ty = impl_ty.subst(tcx, impl_substs); - let impl_ty = ocx.normalize(&cause, param_env, impl_ty); + candidates + .iter() + .filter_map(|&(impl_, (assoc_item, def_scope))| { + infcx.probe(|_| { + let ocx = ObligationCtxt::new_in_snapshot(&infcx); - // Check that the Self-types can be related. - // FIXME(fmease): Should we use `eq` here? - ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?; + let impl_ty = tcx.type_of(impl_); + let impl_substs = infcx.fresh_item_substs(impl_); + let impl_ty = impl_ty.subst(tcx, impl_substs); + let impl_ty = ocx.normalize(&cause, param_env, impl_ty); - // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = tcx.predicates_of(impl_); - let impl_bounds = impl_bounds.instantiate(tcx, impl_substs); + // Check that the Self-types can be related. + // FIXME(fmease): Should we use `eq` here? + ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?; - let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds); + // Check whether the impl imposes obligations we have to worry about. + let impl_bounds = tcx.predicates_of(impl_); + let impl_bounds = impl_bounds.instantiate(tcx, impl_substs); - let impl_obligations = traits::predicates_for_generics( - |_, _| cause.clone(), - param_env, - impl_bounds, - ); + let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds); - ocx.register_obligations(impl_obligations); + let impl_obligations = traits::predicates_for_generics( + |_, _| cause.clone(), + param_env, + impl_bounds, + ); - let mut errors = ocx.select_where_possible(); - if !errors.is_empty() { - fulfillment_errors.append(&mut errors); - return None; - } + ocx.register_obligations(impl_obligations); + + let mut errors = ocx.select_where_possible(); + if !errors.is_empty() { + fulfillment_errors.append(&mut errors); + return None; + } - // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot. - Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs))) + // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot. + Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs))) + }) }) - }) - .collect(); + .collect() + }); if applicable_candidates.len() > 1 { return Err(self.complain_about_ambiguous_inherent_assoc_type( diff --git a/tests/ui/associated-inherent-types/issue-109299-1.rs b/tests/ui/associated-inherent-types/issue-109299-1.rs new file mode 100644 index 0000000000000..6f95273116b78 --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-109299-1.rs @@ -0,0 +1,12 @@ +#![feature(inherent_associated_types, non_lifetime_binders, type_alias_impl_trait)] +#![allow(incomplete_features)] + +struct Lexer(T); + +impl Lexer { + type Cursor = (); +} + +type X = impl for Fn() -> Lexer::Cursor; //~ ERROR associated type `Cursor` not found for `Lexer` in the current scope + +fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109299-1.stderr b/tests/ui/associated-inherent-types/issue-109299-1.stderr new file mode 100644 index 0000000000000..dc59b56ee207d --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-109299-1.stderr @@ -0,0 +1,15 @@ +error[E0220]: associated type `Cursor` not found for `Lexer` in the current scope + --> $DIR/issue-109299-1.rs:10:40 + | +LL | struct Lexer(T); + | --------------- associated item `Cursor` not found for this struct +... +LL | type X = impl for Fn() -> Lexer::Cursor; + | ^^^^^^ associated item not found in `Lexer` + | + = note: the associated type was found for + - `Lexer` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-inherent-types/issue-109299.rs b/tests/ui/associated-inherent-types/issue-109299.rs new file mode 100644 index 0000000000000..84e4f9e72527a --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-109299.rs @@ -0,0 +1,12 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +struct Lexer<'d>(&'d ()); + +impl Lexer<'d> { //~ ERROR use of undeclared lifetime name `'d` + type Cursor = (); +} + +fn test(_: Lexer::Cursor) {} + +fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109299.stderr b/tests/ui/associated-inherent-types/issue-109299.stderr new file mode 100644 index 0000000000000..63f50732d3c50 --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-109299.stderr @@ -0,0 +1,11 @@ +error[E0261]: use of undeclared lifetime name `'d` + --> $DIR/issue-109299.rs:6:12 + | +LL | impl Lexer<'d> { + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'d` here: `<'d>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0261`. From 67a2c5bec838884a0a45d0bd14b7778af731a97b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 19 Mar 2023 21:32:34 +0400 Subject: [PATCH 18/19] rustc: Remove unused `Session` argument from some attribute functions --- compiler/rustc_ast/src/attr/mod.rs | 22 +++++ compiler/rustc_ast_lowering/src/lib.rs | 2 +- .../rustc_ast_passes/src/ast_validation.rs | 8 +- compiler/rustc_ast_passes/src/feature_gate.rs | 8 +- compiler/rustc_attr/src/builtin.rs | 8 +- .../src/deriving/default.rs | 12 +-- .../src/proc_macro_harness.rs | 8 +- .../src/standard_library_imports.rs | 8 +- compiler/rustc_builtin_macros/src/test.rs | 22 +++-- .../rustc_builtin_macros/src/test_harness.rs | 26 +++--- compiler/rustc_builtin_macros/src/util.rs | 4 +- .../rustc_codegen_llvm/src/debuginfo/gdb.rs | 4 +- compiler/rustc_codegen_ssa/src/back/write.rs | 5 +- compiler/rustc_codegen_ssa/src/base.rs | 2 +- compiler/rustc_expand/src/base.rs | 10 +-- .../rustc_interface/src/proc_macro_decls.rs | 3 +- compiler/rustc_interface/src/util.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 27 +++---- compiler/rustc_lint/src/nonstandard_style.rs | 5 +- compiler/rustc_metadata/src/creader.rs | 37 ++++----- compiler/rustc_metadata/src/rmeta/encoder.rs | 22 +++-- compiler/rustc_middle/src/ty/context.rs | 6 +- compiler/rustc_mir_build/src/build/mod.rs | 3 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_passes/src/entry.rs | 9 ++- .../rustc_resolve/src/build_reduced_graph.rs | 28 +++---- compiler/rustc_resolve/src/lib.rs | 8 +- compiler/rustc_resolve/src/macros.rs | 4 +- compiler/rustc_session/src/output.rs | 4 +- compiler/rustc_session/src/session.rs | 36 +-------- .../clippy_lints/src/functions/must_use.rs | 6 +- src/tools/clippy/clippy_utils/src/attrs.rs | 4 +- src/tools/rustfmt/src/attr.rs | 16 +--- src/tools/rustfmt/src/parse/parser.rs | 5 +- src/tools/rustfmt/src/reorder.rs | 4 +- .../auxiliary/lint-for-crate-rpass.rs | 80 ------------------- tests/ui-fulldeps/auxiliary/lint-for-crate.rs | 12 ++- 37 files changed, 173 insertions(+), 299 deletions(-) delete mode 100644 tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 2e83b3e623f07..c4771115cacf2 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -180,6 +180,12 @@ impl Attribute { self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str())) } + pub fn is_proc_macro_attr(&self) -> bool { + [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] + .iter() + .any(|kind| self.has_name(*kind)) + } + /// Extracts the MetaItem from inside this Attribute. pub fn meta(&self) -> Option { match &self.kind { @@ -627,6 +633,22 @@ pub fn mk_attr_name_value_str( mk_attr(g, style, path, args, span) } +pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator { + attrs.iter().filter(move |attr| attr.has_name(name)) +} + +pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> { + filter_by_name(attrs, name).next() +} + +pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option { + find_by_name(attrs, name).and_then(|attr| attr.value_str()) +} + +pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool { + find_by_name(attrs, name).is_some() +} + pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { items.iter().any(|item| item.has_name(name)) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ea7fa02521e44..0b6b02ba00fb5 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2185,7 +2185,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { def_id: self.local_def_id(param.id), name, span: self.lower_span(param.span()), - pure_wrt_drop: self.tcx.sess.contains_name(¶m.attrs, sym::may_dangle), + pure_wrt_drop: attr::contains_name(¶m.attrs, sym::may_dangle), kind, colon_span: param.colon_span.map(|s| self.lower_span(s)), source, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 539c822ea0977..93c854cc80942 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -799,11 +799,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_item(&mut self, item: &'a Item) { - if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) { + if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) { self.has_proc_macro_decls = true; } - if self.session.contains_name(&item.attrs, sym::no_mangle) { + if attr::contains_name(&item.attrs, sym::no_mangle) { self.check_nomangle_item_asciionly(item.ident, item.span); } @@ -973,7 +973,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) - && !self.session.contains_name(&item.attrs, sym::path) + && !attr::contains_name(&item.attrs, sym::path) { self.check_mod_file_item_asciionly(item.ident); } @@ -1248,7 +1248,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { - if self.session.contains_name(&item.attrs, sym::no_mangle) { + if attr::contains_name(&item.attrs, sym::no_mangle) { self.check_nomangle_item_asciionly(item.ident, item.span); } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 6a5d5614b1cb9..344a1e7f5e795 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; -use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId}; +use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId}; use rustc_ast::{PatKind, RangeEnd}; use rustc_errors::{Applicability, StashKey}; use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP}; @@ -232,7 +232,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } ast::ItemKind::Fn(..) => { - if self.sess.contains_name(&i.attrs, sym::start) { + if attr::contains_name(&i.attrs, sym::start) { gate_feature_post!( &self, start, @@ -245,7 +245,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } ast::ItemKind::Struct(..) => { - for attr in self.sess.filter_by_name(&i.attrs, sym::repr) { + for attr in attr::filter_by_name(&i.attrs, sym::repr) { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { if item.has_name(sym::simd) { gate_feature_post!( @@ -306,7 +306,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { match i.kind { ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => { - let link_name = self.sess.first_attr_value_str_by_name(&i.attrs, sym::link_name); + let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); let links_to_llvm = link_name.map_or(false, |val| val.as_str().starts_with("llvm.")); if links_to_llvm { diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 3d240108b4ab1..d6dbdd3975e93 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1,6 +1,6 @@ //! Parsing and validation of builtin attributes -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId}; use rustc_ast_pretty::pprust; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; @@ -556,8 +556,8 @@ where (stab, const_stab, body_stab) } -pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option { - sess.first_attr_value_str_by_name(attrs, sym::crate_name) +pub fn find_crate_name(attrs: &[Attribute]) -> Option { + attr::first_attr_value_str_by_name(attrs, sym::crate_name) } #[derive(Clone, Debug)] @@ -1177,7 +1177,7 @@ fn allow_unstable<'a>( attrs: &'a [Attribute], symbol: Symbol, ) -> impl Iterator + 'a { - let attrs = sess.filter_by_name(attrs, symbol); + let attrs = attr::filter_by_name(attrs, symbol); let list = attrs .filter_map(move |attr| { attr.meta_item_list().or_else(|| { diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 4d753a2ed805c..cc32739d083c7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,7 +1,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use rustc_ast as ast; -use rustc_ast::{walk_list, EnumDef, VariantData}; +use rustc_ast::{attr, walk_list, EnumDef, VariantData}; use rustc_errors::Applicability; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::symbol::Ident; @@ -106,7 +106,7 @@ fn extract_default_variant<'a>( let default_variants: SmallVec<[_; 1]> = enum_def .variants .iter() - .filter(|variant| cx.sess.contains_name(&variant.attrs, kw::Default)) + .filter(|variant| attr::contains_name(&variant.attrs, kw::Default)) .collect(); let variant = match default_variants.as_slice() { @@ -116,7 +116,7 @@ fn extract_default_variant<'a>( .variants .iter() .filter(|variant| matches!(variant.data, VariantData::Unit(..))) - .filter(|variant| !cx.sess.contains_name(&variant.attrs, sym::non_exhaustive)); + .filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive)); let mut diag = cx.struct_span_err(trait_span, "no default declared"); diag.help("make a unit variant default by placing `#[default]` above it"); @@ -146,7 +146,7 @@ fn extract_default_variant<'a>( if v.span == variant.span { None } else { - Some((cx.sess.find_by_name(&v.attrs, kw::Default)?.span, String::new())) + Some((attr::find_by_name(&v.attrs, kw::Default)?.span, String::new())) } }) .collect(); @@ -174,7 +174,7 @@ fn extract_default_variant<'a>( return Err(()); } - if let Some(non_exhaustive_attr) = cx.sess.find_by_name(&variant.attrs, sym::non_exhaustive) { + if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) { cx.struct_span_err(variant.ident.span, "default variant must be exhaustive") .span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here") .help("consider a manual implementation of `Default`") @@ -191,7 +191,7 @@ fn validate_default_attribute( default_variant: &rustc_ast::Variant, ) -> Result<(), ()> { let attrs: SmallVec<[_; 1]> = - cx.sess.filter_by_name(&default_variant.attrs, kw::Default).collect(); + attr::filter_by_name(&default_variant.attrs, kw::Default).collect(); let attr = match attrs.as_slice() { [attr] => attr, diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index bc513607ddd1d..a73fed6ccb222 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -1,6 +1,6 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{self as ast, NodeId}; +use rustc_ast::{self as ast, attr, NodeId}; use rustc_ast_pretty::pprust; use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; @@ -34,7 +34,6 @@ enum ProcMacro { } struct CollectProcMacros<'a> { - sess: &'a Session, macros: Vec, in_root: bool, handler: &'a rustc_errors::Handler, @@ -56,7 +55,6 @@ pub fn inject( let mut cx = ExtCtxt::new(sess, ecfg, resolver, None); let mut collect = CollectProcMacros { - sess, macros: Vec::new(), in_root: true, handler, @@ -160,7 +158,7 @@ impl<'a> CollectProcMacros<'a> { impl<'a> Visitor<'a> for CollectProcMacros<'a> { fn visit_item(&mut self, item: &'a ast::Item) { if let ast::ItemKind::MacroDef(..) = item.kind { - if self.is_proc_macro_crate && self.sess.contains_name(&item.attrs, sym::macro_export) { + if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) { let msg = "cannot export macro_rules! macros from a `proc-macro` crate type currently"; self.handler.span_err(self.source_map.guess_head_span(item.span), msg); @@ -176,7 +174,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { let mut found_attr: Option<&'a ast::Attribute> = None; for attr in &item.attrs { - if self.sess.is_proc_macro_attr(&attr) { + if attr.is_proc_macro_attr() { if let Some(prev_attr) = found_attr { let prev_item = prev_attr.get_normal_item(); let item = attr.get_normal_item(); diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index e67c0dba68597..caed40d9fa81b 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -1,4 +1,4 @@ -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::ExpansionConfig; use rustc_session::Session; @@ -16,10 +16,10 @@ pub fn inject( let edition = sess.parse_sess.edition; // the first name in this list is the crate name of the crate with the prelude - let names: &[Symbol] = if sess.contains_name(&krate.attrs, sym::no_core) { + let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) { return krate; - } else if sess.contains_name(&krate.attrs, sym::no_std) { - if sess.contains_name(&krate.attrs, sym::compiler_builtins) { + } else if attr::contains_name(&krate.attrs, sym::no_std) { + if attr::contains_name(&krate.attrs, sym::compiler_builtins) { &[sym::core] } else { &[sym::core, sym::compiler_builtins] diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 151afd2d458b0..44b9c4718a75f 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -1,12 +1,11 @@ /// The expansion from a test function to the appropriate test struct for libtest /// Ideally, this code would be in libtest but for efficiency and error messages it lives here. use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; -use rustc_ast as ast; use rustc_ast::ptr::P; +use rustc_ast::{self as ast, attr}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_expand::base::*; -use rustc_session::Session; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{FileNameDisplayPreference, Span}; use std::iter; @@ -291,14 +290,11 @@ pub fn expand_test_or_bench( ), ), // ignore: true | false - field( - "ignore", - cx.expr_bool(sp, should_ignore(&cx.sess, &item)), - ), + field("ignore", cx.expr_bool(sp, should_ignore(&item)),), // ignore_message: Some("...") | None field( "ignore_message", - if let Some(msg) = should_ignore_message(cx, &item) { + if let Some(msg) = should_ignore_message(&item) { cx.expr_some(sp, cx.expr_str(sp, msg)) } else { cx.expr_none(sp) @@ -425,12 +421,12 @@ enum ShouldPanic { Yes(Option), } -fn should_ignore(sess: &Session, i: &ast::Item) -> bool { - sess.contains_name(&i.attrs, sym::ignore) +fn should_ignore(i: &ast::Item) -> bool { + attr::contains_name(&i.attrs, sym::ignore) } -fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option { - match cx.sess.find_by_name(&i.attrs, sym::ignore) { +fn should_ignore_message(i: &ast::Item) -> Option { + match attr::find_by_name(&i.attrs, sym::ignore) { Some(attr) => { match attr.meta_item_list() { // Handle #[ignore(bar = "foo")] @@ -444,7 +440,7 @@ fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option { } fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { - match cx.sess.find_by_name(&i.attrs, sym::should_panic) { + match attr::find_by_name(&i.attrs, sym::should_panic) { Some(attr) => { let sd = &cx.sess.parse_sess.span_diagnostic; @@ -510,7 +506,7 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType { } fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { - let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic); + let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic); let sd = &cx.sess.parse_sess.span_diagnostic; match &i.kind { ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => { diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index d8e3db9e8ee09..2d491b2dac8b2 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -47,11 +47,11 @@ pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast // unconditional, so that the attribute is still marked as used in // non-test builds. let reexport_test_harness_main = - sess.first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main); + attr::first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main); // Do this here so that the test_runner crate attribute gets marked as used // even in non-test builds - let test_runner = get_test_runner(sess, span_diagnostic, &krate); + let test_runner = get_test_runner(span_diagnostic, &krate); if sess.opts.test { let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) { @@ -123,7 +123,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { let mut item = i.into_inner(); - if let Some(name) = get_test_name(&self.cx.ext_cx.sess, &item) { + if let Some(name) = get_test_name(&item) { debug!("this is a test item"); let test = Test { span: item.span, ident: item.ident, name }; @@ -145,12 +145,12 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { // Beware, this is duplicated in librustc_passes/entry.rs (with // `rustc_hir::Item`), so make sure to keep them in sync. -fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPointType { +fn entry_point_type(item: &ast::Item, depth: usize) -> EntryPointType { match item.kind { ast::ItemKind::Fn(..) => { - if sess.contains_name(&item.attrs, sym::start) { + if attr::contains_name(&item.attrs, sym::start) { EntryPointType::Start - } else if sess.contains_name(&item.attrs, sym::rustc_main) { + } else if attr::contains_name(&item.attrs, sym::rustc_main) { EntryPointType::RustcMainAttr } else if item.ident.name == sym::main { if depth == 0 { @@ -184,7 +184,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { // Remove any #[rustc_main] or #[start] from the AST so it doesn't // clash with the one we're going to add, but mark it as // #[allow(dead_code)] to avoid printing warnings. - let item = match entry_point_type(self.sess, &item, self.depth) { + let item = match entry_point_type(&item, self.depth) { EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => { item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| { let allow_dead_code = attr::mk_attr_nested_word( @@ -373,16 +373,12 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P { ) } -fn get_test_name(sess: &Session, i: &ast::Item) -> Option { - sess.first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker) +fn get_test_name(i: &ast::Item) -> Option { + attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker) } -fn get_test_runner( - sess: &Session, - sd: &rustc_errors::Handler, - krate: &ast::Crate, -) -> Option { - let test_attr = sess.find_by_name(&krate.attrs, sym::test_runner)?; +fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option { + let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?; let meta_list = test_attr.meta_item_list()?; let span = test_attr.span; match &*meta_list { diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index 83812631c2ff7..9463a1418ce31 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -1,4 +1,4 @@ -use rustc_ast::{AttrStyle, Attribute, MetaItem}; +use rustc_ast::{attr, AttrStyle, Attribute, MetaItem}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_feature::AttributeTemplate; use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; @@ -36,7 +36,7 @@ pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: _ => None, }; if let Some(attrs) = attrs { - if let Some(attr) = ecx.sess.find_by_name(attrs, name) { + if let Some(attr) = attr::find_by_name(attrs, name) { ecx.parse_sess().buffer_lint( DUPLICATE_MACRO_ATTRIBUTES, attr.span, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 80fd9726fc780..ff2b005d75767 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -5,12 +5,12 @@ use crate::llvm; use crate::builder::Builder; use crate::common::CodegenCx; use crate::value::Value; +use rustc_ast::attr; use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive; use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_session::config::{CrateType, DebugInfo}; - use rustc_span::symbol::sym; use rustc_span::DebuggerVisualizerType; @@ -87,7 +87,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, ' pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { let omit_gdb_pretty_printer_section = - cx.tcx.sess.contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); + attr::contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); // To ensure the section `__rustc_debug_gdb_scripts_section__` will not create // ODR violations at link time, this section will not be emitted for rlibs since diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 8508ab87532c2..7ce72d2172799 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -8,6 +8,7 @@ use crate::{ CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, }; use jobserver::{Acquired, Client}; +use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; @@ -447,8 +448,8 @@ pub fn start_async_codegen( let sess = tcx.sess; let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let no_builtins = tcx.sess.contains_name(crate_attrs, sym::no_builtins); - let is_compiler_builtins = tcx.sess.contains_name(crate_attrs, sym::compiler_builtins); + let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); + let is_compiler_builtins = attr::contains_name(crate_attrs, sym::compiler_builtins); let crate_info = CrateInfo::new(tcx, target_cpu); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index abc510e360d56..4d34b3da5f501 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -809,7 +809,7 @@ impl CrateInfo { .collect(); let local_crate_name = tcx.crate_name(LOCAL_CRATE); let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); + let subsystem = attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); let windows_subsystem = subsystem.map(|subsystem| { if subsystem != sym::windows && subsystem != sym::console { tcx.sess.emit_fatal(errors::InvalidWindowsSubsystem { subsystem }); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 713e4fbbdce23..6eb0d24eb976e 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -776,16 +776,14 @@ impl SyntaxExtension { let allow_internal_unstable = attr::allow_internal_unstable(sess, &attrs).collect::>(); - let allow_internal_unsafe = sess.contains_name(attrs, sym::allow_internal_unsafe); - let local_inner_macros = sess - .find_by_name(attrs, sym::macro_export) + let allow_internal_unsafe = attr::contains_name(attrs, sym::allow_internal_unsafe); + let local_inner_macros = attr::find_by_name(attrs, sym::macro_export) .and_then(|macro_export| macro_export.meta_item_list()) .map_or(false, |l| attr::list_contains_name(&l, sym::local_inner_macros)); - let collapse_debuginfo = sess.contains_name(attrs, sym::collapse_debuginfo); + let collapse_debuginfo = attr::contains_name(attrs, sym::collapse_debuginfo); tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe); - let (builtin_name, helper_attrs) = sess - .find_by_name(attrs, sym::rustc_builtin_macro) + let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro) .map(|attr| { // Override `helper_attrs` passed above if it's a built-in macro, // marking `proc_macro_derive` macros as built-in is not a realistic use case. diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index 9bf7778bfb29c..1c58caa03532e 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -1,3 +1,4 @@ +use rustc_ast::attr; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; @@ -8,7 +9,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option { for id in tcx.hir().items() { let attrs = tcx.hir().attrs(id.hir_id()); - if tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) { + if attr::contains_name(attrs, sym::rustc_proc_macro_decls) { decls = Some(id.owner_id.def_id); } } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 043892410ceaa..8abdcebb7516d 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -505,7 +505,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu .opts .crate_name .clone() - .or_else(|| rustc_attr::find_crate_name(sess, attrs).map(|n| n.to_string())) + .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string())) .unwrap_or_else(|| sess.io.input.filestem().to_owned()); OutputFilenames::new( diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8af1a663ef5e3..29ba480cdd20e 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -358,29 +358,29 @@ impl EarlyLintPass for UnsafeCode { } ast::ItemKind::Fn(..) => { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn); } } ast::ItemKind::Static(..) => { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic); } } @@ -391,10 +391,10 @@ impl EarlyLintPass for UnsafeCode { fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { if let ast::AssocItemKind::Fn(..) = it.kind { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod); } } @@ -1123,12 +1123,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { }; match it.kind { hir::ItemKind::Fn(.., ref generics, _) => { - if let Some(no_mangle_attr) = cx.sess().find_by_name(attrs, sym::no_mangle) { + if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) { check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span); } } hir::ItemKind::Const(..) => { - if cx.sess().contains_name(attrs, sym::no_mangle) { + if attr::contains_name(attrs, sym::no_mangle) { // account for "pub const" (#45562) let start = cx .tcx @@ -1152,9 +1152,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => { for it in *items { if let hir::AssocItemKind::Fn { .. } = it.kind { - if let Some(no_mangle_attr) = cx - .sess() - .find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle) + if let Some(no_mangle_attr) = + attr::find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle) { check_no_mangle_on_generic_fn( no_mangle_attr, @@ -1836,7 +1835,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { } let attrs = cx.tcx.hir().attrs(it.hir_id()); - if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) { + if let Some(attr) = attr::find_by_name(attrs, sym::rustc_test_marker) { cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems); } } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 0f44dde59485a..9efc14849c76f 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -328,8 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { Some(Ident::from_str(name)) } else { - cx.sess() - .find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name) + attr::find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name) .and_then(|attr| attr.meta()) .and_then(|meta| { meta.name_value_literal().and_then(|lit| { @@ -489,7 +488,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(it.hir_id()); match it.kind { - hir::ItemKind::Static(..) if !cx.sess().contains_name(attrs, sym::no_mangle) => { + hir::ItemKind::Static(..) if !attr::contains_name(attrs, sym::no_mangle) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident); } hir::ItemKind::Const(..) => { diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index f870a1db82d9c..0dea1c52d1f2f 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -720,8 +720,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // compilation mode also comes into play. let desired_strategy = self.sess.panic_strategy(); let mut runtime_found = false; - let mut needs_panic_runtime = - self.sess.contains_name(&krate.attrs, sym::needs_panic_runtime); + let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime); for (cnum, data) in self.cstore.iter_crate_data() { needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime(); @@ -789,7 +788,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { info!("loading profiler"); let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime); - if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) { + if name == sym::profiler_builtins && attr::contains_name(&krate.attrs, sym::no_core) { self.sess.emit_err(errors::ProfilerBuiltinsNeedsCore); } @@ -803,14 +802,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } fn inject_allocator_crate(&mut self, krate: &ast::Crate) { - self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) { + self.cstore.has_global_allocator = match &*global_allocator_spans(krate) { [span1, span2, ..] => { self.sess.emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 }); true } spans => !spans.is_empty(), }; - self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(&self.sess, krate) { + self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(krate) { [span1, span2, ..] => { self.sess .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 }); @@ -822,7 +821,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // Check to see if we actually need an allocator. This desire comes // about through the `#![needs_allocator]` attribute and is typically // written down in liballoc. - if !self.sess.contains_name(&krate.attrs, sym::needs_allocator) + if !attr::contains_name(&krate.attrs, sym::needs_allocator) && !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator()) { return; @@ -881,7 +880,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // allocator. At this point our allocator request is typically fulfilled // by the standard library, denoted by the `#![default_lib_allocator]` // attribute. - if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator) + if !attr::contains_name(&krate.attrs, sym::default_lib_allocator) && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator()) { self.sess.emit_err(errors::GlobalAllocRequired); @@ -1003,7 +1002,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } None => item.ident.name, }; - let dep_kind = if self.sess.contains_name(&item.attrs, sym::no_link) { + let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) { CrateDepKind::MacrosOnly } else { CrateDepKind::Explicit @@ -1049,16 +1048,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } -fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec { - struct Finder<'a> { - sess: &'a Session, +fn global_allocator_spans(krate: &ast::Crate) -> Vec { + struct Finder { name: Symbol, spans: Vec, } - impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> { + impl<'ast> visit::Visitor<'ast> for Finder { fn visit_item(&mut self, item: &'ast ast::Item) { if item.ident.name == self.name - && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol) + && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol) { self.spans.push(item.span); } @@ -1067,21 +1065,20 @@ fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec { } let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc)); - let mut f = Finder { sess, name, spans: Vec::new() }; + let mut f = Finder { name, spans: Vec::new() }; visit::walk_crate(&mut f, krate); f.spans } -fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec { - struct Finder<'a> { - sess: &'a Session, +fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec { + struct Finder { name: Symbol, spans: Vec, } - impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> { + impl<'ast> visit::Visitor<'ast> for Finder { fn visit_item(&mut self, item: &'ast ast::Item) { if item.ident.name == self.name - && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol) + && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol) { self.spans.push(item.span); } @@ -1090,7 +1087,7 @@ fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec { } let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom)); - let mut f = Finder { sess, name, spans: Vec::new() }; + let mut f = Finder { name, spans: Vec::new() }; visit::walk_crate(&mut f, krate); f.spans } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index ef3eda584e1b8..eb4d9343f1dfb 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -681,17 +681,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE), has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), - has_default_lib_allocator: tcx - .sess - .contains_name(&attrs, sym::default_lib_allocator), + has_default_lib_allocator: attr::contains_name(&attrs, sym::default_lib_allocator), proc_macro_data, debugger_visualizers, - compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins), - needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator), - needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime), - no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins), - panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime), - profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime), + compiler_builtins: attr::contains_name(&attrs, sym::compiler_builtins), + needs_allocator: attr::contains_name(&attrs, sym::needs_allocator), + needs_panic_runtime: attr::contains_name(&attrs, sym::needs_panic_runtime), + no_builtins: attr::contains_name(&attrs, sym::no_builtins), + panic_runtime: attr::contains_name(&attrs, sym::panic_runtime), + profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime), symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(), crate_deps, @@ -1730,11 +1728,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Proc-macros may have attributes like `#[allow_internal_unstable]`, // so downstream crates need access to them. let attrs = hir.attrs(proc_macro); - let macro_kind = if tcx.sess.contains_name(attrs, sym::proc_macro) { + let macro_kind = if attr::contains_name(attrs, sym::proc_macro) { MacroKind::Bang - } else if tcx.sess.contains_name(attrs, sym::proc_macro_attribute) { + } else if attr::contains_name(attrs, sym::proc_macro_attribute) { MacroKind::Attr - } else if let Some(attr) = tcx.sess.find_by_name(attrs, sym::proc_macro_derive) { + } else if let Some(attr) = attr::find_by_name(attrs, sym::proc_macro_derive) { // This unwrap chain should have been checked by the proc-macro harness. name = attr.meta_item_list().unwrap()[0] .meta_item() diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 653763353987c..a1c1acc4a2541 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -28,7 +28,7 @@ use crate::ty::{ TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, Visibility, }; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::intern::Interned; @@ -2520,9 +2520,9 @@ pub fn provide(providers: &mut ty::query::Providers) { providers.extern_mod_stmt_cnum = |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned(); providers.is_panic_runtime = - |tcx, LocalCrate| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime); + |tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::panic_runtime); providers.is_compiler_builtins = - |tcx, LocalCrate| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins); + |tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins); providers.has_panic_handler = |tcx, LocalCrate| { // We want to check if the panic handler was defined in this crate tcx.lang_items().panic_impl().map_or(false, |did| did.is_local()) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 80d8b27336c54..1923e10ddb586 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -3,6 +3,7 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::scope::DropKind; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; +use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_errors::ErrorGuaranteed; @@ -680,7 +681,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Some functions always have overflow checks enabled, // however, they may not get codegen'd, depending on // the settings for the crate they are codegened in. - let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks); + let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks); // Respect -C overflow-checks. check_overflow |= tcx.sess.overflow_checks(); // Constants always need overflow checks. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8bed788814209..1c459edabb89e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1907,7 +1907,7 @@ impl CheckAttrVisitor<'_> { match target { Target::Fn => { for attr in attrs { - if self.tcx.sess.is_proc_macro_attr(attr) { + if attr.is_proc_macro_attr() { debug!("Is proc macro attr"); return true; } diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index b7e6a11998b1c..f3e683f4b3a0a 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,3 +1,4 @@ +use rustc_ast::attr; use rustc_ast::entry::EntryPointType; use rustc_errors::error_code; use rustc_hir::def::DefKind; @@ -37,7 +38,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { } // If the user wants no main function at all, then stop here. - if tcx.sess.contains_name(&tcx.hir().attrs(CRATE_HIR_ID), sym::no_main) { + if attr::contains_name(&tcx.hir().attrs(CRATE_HIR_ID), sym::no_main) { return None; } @@ -57,9 +58,9 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { // An equivalent optimization was not applied to the duplicated code in test_harness.rs. fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType { let attrs = ctxt.tcx.hir().attrs(id.hir_id()); - if ctxt.tcx.sess.contains_name(attrs, sym::start) { + if attr::contains_name(attrs, sym::start) { EntryPointType::Start - } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) { + } else if attr::contains_name(attrs, sym::rustc_main) { EntryPointType::RustcMainAttr } else { if let Some(name) = ctxt.tcx.opt_item_name(id.owner_id.to_def_id()) @@ -78,7 +79,7 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option { let attrs = ctxt.tcx.hir().attrs(id.hir_id()); - ctxt.tcx.sess.find_by_name(attrs, sym).map(|attr| attr.span) + attr::find_by_name(attrs, sym).map(|attr| attr.span) } fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 362ef693c48d5..f79807fee3957 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -570,7 +570,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } ast::UseTreeKind::Glob => { let kind = ImportKind::Glob { - is_prelude: self.r.tcx.sess.contains_name(&item.attrs, sym::prelude_import), + is_prelude: attr::contains_name(&item.attrs, sym::prelude_import), max_vis: Cell::new(None), id, }; @@ -685,7 +685,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { expansion.to_expn_id(), item.span, parent.no_implicit_prelude - || self.r.tcx.sess.contains_name(&item.attrs, sym::no_implicit_prelude), + || attr::contains_name(&item.attrs, sym::no_implicit_prelude), ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); @@ -750,7 +750,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { // If the structure is marked as non_exhaustive then lower the visibility // to within the crate. let mut ctor_vis = if vis.is_public() - && self.r.tcx.sess.contains_name(&item.attrs, sym::non_exhaustive) + && attr::contains_name(&item.attrs, sym::non_exhaustive) { ty::Visibility::Restricted(CRATE_DEF_ID) } else { @@ -1168,12 +1168,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { - if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro) { + if attr::contains_name(&item.attrs, sym::proc_macro) { return Some((MacroKind::Bang, item.ident, item.span)); - } else if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro_attribute) { + } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) { return Some((MacroKind::Attr, item.ident, item.span)); - } else if let Some(attr) = self.r.tcx.sess.find_by_name(&item.attrs, sym::proc_macro_derive) - { + } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { if let Some(ident) = nested_meta.ident() { return Some((MacroKind::Derive, ident, ident.span)); @@ -1228,7 +1227,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { if macro_rules { let ident = ident.normalize_to_macros_2_0(); self.r.macro_names.insert(ident); - let is_macro_export = self.r.tcx.sess.contains_name(&item.attrs, sym::macro_export); + let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { ty::Visibility::Public } else { @@ -1488,13 +1487,12 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.visibilities.insert(def_id, vis); // If the variant is marked as non_exhaustive then lower the visibility to within the crate. - let ctor_vis = if vis.is_public() - && self.r.tcx.sess.contains_name(&variant.attrs, sym::non_exhaustive) - { - ty::Visibility::Restricted(CRATE_DEF_ID) - } else { - vis - }; + let ctor_vis = + if vis.is_public() && attr::contains_name(&variant.attrs, sym::non_exhaustive) { + ty::Visibility::Restricted(CRATE_DEF_ID) + } else { + vis + }; // Define a constructor name in the value namespace. if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&variant.data) { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cd90fd3ef84d8..a0b9188c3159e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -23,7 +23,7 @@ extern crate tracing; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; -use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID}; +use rustc_ast::{self as ast, attr, NodeId, CRATE_NODE_ID}; use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; @@ -1190,7 +1190,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), ExpnId::root(), krate.spans.inner_span, - tcx.sess.contains_name(&krate.attrs, sym::no_implicit_prelude), + attr::contains_name(&krate.attrs, sym::no_implicit_prelude), &mut module_map, ); let empty_module = arenas.new_module( @@ -1222,9 +1222,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .map(|(name, _)| (Ident::from_str(name), Default::default())) .collect(); - if !tcx.sess.contains_name(&krate.attrs, sym::no_core) { + if !attr::contains_name(&krate.attrs, sym::no_core) { extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default()); - if !tcx.sess.contains_name(&krate.attrs, sym::no_std) { + if !attr::contains_name(&krate.attrs, sym::no_std) { extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default()); } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 37153854f7e7f..9c22ed7a2d7c1 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -5,7 +5,7 @@ use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment}; -use rustc_ast::{self as ast, Inline, ItemKind, ModKind, NodeId}; +use rustc_ast::{self as ast, attr, Inline, ItemKind, ModKind, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::intern::Interned; @@ -113,7 +113,7 @@ fn fast_print_path(path: &ast::Path) -> Symbol { pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { let mut registered_tools = RegisteredTools::default(); let krate = tcx.crate_for_resolver(()).borrow(); - for attr in tcx.sess.filter_by_name(&krate.attrs, sym::register_tool) { + for attr in attr::filter_by_name(&krate.attrs, sym::register_tool) { for nested_meta in attr.meta_item_list().unwrap_or_default() { match nested_meta.ident() { Some(ident) => { diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index c3f0c4b58f57a..fdb9fae44e153 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -5,7 +5,7 @@ use crate::errors::{ InvalidCharacterInCrateName, }; use crate::Session; -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use std::path::{Path, PathBuf}; @@ -56,7 +56,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute]) -> Symbol { // the command line over one found in the #[crate_name] attribute. If we // find both we ensure that they're the same later on as well. let attr_crate_name = - sess.find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s))); + attr::find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s))); if let Some(ref s) = sess.opts.crate_name { let s = Symbol::intern(s); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index fdacf814dd672..700a059c368ba 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -30,7 +30,7 @@ use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; use rustc_span::edition::Edition; use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap, Span}; -use rustc_span::{sym, SourceFileHashAlgorithm, Symbol}; +use rustc_span::{SourceFileHashAlgorithm, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel}; use rustc_target::spec::{ @@ -1003,40 +1003,6 @@ impl Session { || self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS) } - pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool { - [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] - .iter() - .any(|kind| attr.has_name(*kind)) - } - - pub fn contains_name(&self, attrs: &[Attribute], name: Symbol) -> bool { - attrs.iter().any(|item| item.has_name(name)) - } - - pub fn find_by_name<'a>( - &'a self, - attrs: &'a [Attribute], - name: Symbol, - ) -> Option<&'a Attribute> { - attrs.iter().find(|attr| attr.has_name(name)) - } - - pub fn filter_by_name<'a>( - &'a self, - attrs: &'a [Attribute], - name: Symbol, - ) -> impl Iterator { - attrs.iter().filter(move |attr| attr.has_name(name)) - } - - pub fn first_attr_value_str_by_name( - &self, - attrs: &[Attribute], - name: Symbol, - ) -> Option { - attrs.iter().find(|at| at.has_name(name)).and_then(|at| at.value_str()) - } - pub fn diagnostic_width(&self) -> usize { let default_column_width = 140; if let Some(width) = self.opts.diagnostic_width { diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index eacbf6c6ec9b6..67877780c0e90 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -28,7 +28,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); - } else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { + } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { check_must_use_candidate( cx, sig.decl, @@ -51,7 +51,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); } else if is_public - && !is_proc_macro(cx.sess(), attrs) + && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() { check_must_use_candidate( @@ -78,7 +78,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); } else if let hir::TraitFn::Provided(eid) = *eid { let body = cx.tcx.hir().body(eid); - if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) { + if attr.is_none() && is_public && !is_proc_macro(attrs) { check_must_use_candidate( cx, sig.decl, diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index 7987a233bdc18..bc3d774540a51 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -145,8 +145,8 @@ pub fn get_unique_attr<'a>( /// Return true if the attributes contain any of `proc_macro`, /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise -pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool { - attrs.iter().any(|attr| sess.is_proc_macro_attr(attr)) +pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool { + attrs.iter().any(|attr| attr.is_proc_macro_attr()) } /// Return true if the attributes contain `#[doc(hidden)]` diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 5648e1254ed7c..22e45082a9f71 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -2,7 +2,7 @@ use rustc_ast::ast; use rustc_ast::HasAttrs; -use rustc_span::{symbol::sym, Span, Symbol}; +use rustc_span::{symbol::sym, Span}; use self::doc_comment::DocCommentFormatter; use crate::comment::{contains_comment, rewrite_doc_comment, CommentStyle}; @@ -19,20 +19,6 @@ use crate::utils::{count_newlines, mk_sp}; mod doc_comment; -pub(crate) fn contains_name(attrs: &[ast::Attribute], name: Symbol) -> bool { - attrs.iter().any(|attr| attr.has_name(name)) -} - -pub(crate) fn first_attr_value_str_by_name( - attrs: &[ast::Attribute], - name: Symbol, -) -> Option { - attrs - .iter() - .find(|attr| attr.has_name(name)) - .and_then(|attr| attr.value_str()) -} - /// Returns attributes on the given statement. pub(crate) fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] { stmt.attrs() diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs index 7ab042506bd29..6bc53159b38ba 100644 --- a/src/tools/rustfmt/src/parse/parser.rs +++ b/src/tools/rustfmt/src/parse/parser.rs @@ -2,13 +2,12 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; use std::path::{Path, PathBuf}; use rustc_ast::token::TokenKind; -use rustc_ast::{ast, ptr}; +use rustc_ast::{ast, attr, ptr}; use rustc_errors::Diagnostic; use rustc_parse::{new_parser_from_file, parser::Parser as RawParser}; use rustc_span::{sym, Span}; use thin_vec::ThinVec; -use crate::attr::first_attr_value_str_by_name; use crate::parse::session::ParseSess; use crate::Input; @@ -93,7 +92,7 @@ pub(crate) enum ParserError { impl<'a> Parser<'a> { pub(crate) fn submod_path_from_attr(attrs: &[ast::Attribute], path: &Path) -> Option { - let path_sym = first_attr_value_str_by_name(attrs, sym::path)?; + let path_sym = attr::first_attr_value_str_by_name(attrs, sym::path)?; let path_str = path_sym.as_str(); // On windows, the base path might have the form diff --git a/src/tools/rustfmt/src/reorder.rs b/src/tools/rustfmt/src/reorder.rs index 9e4a668aa4930..3bddf4c1b6a41 100644 --- a/src/tools/rustfmt/src/reorder.rs +++ b/src/tools/rustfmt/src/reorder.rs @@ -8,7 +8,7 @@ use std::cmp::{Ord, Ordering}; -use rustc_ast::ast; +use rustc_ast::{ast, attr}; use rustc_span::{symbol::sym, Span}; use crate::config::{Config, GroupImportsTactic}; @@ -167,7 +167,7 @@ fn rewrite_reorderable_or_regroupable_items( } fn contains_macro_use_attr(item: &ast::Item) -> bool { - crate::attr::contains_name(&item.attrs, sym::macro_use) + attr::contains_name(&item.attrs, sym::macro_use) } /// Divides imports into three groups, corresponding to standard, external diff --git a/tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs deleted file mode 100644 index a3b570ad8c40c..0000000000000 --- a/tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs +++ /dev/null @@ -1,80 +0,0 @@ -// force-host - -#![feature(rustc_private)] - -extern crate rustc_driver; -extern crate rustc_hir; -extern crate rustc_lint; -extern crate rustc_span; -#[macro_use] -extern crate rustc_session; -extern crate rustc_ast; - -use rustc_ast::attr; -use rustc_driver::plugin::Registry; -use rustc_lint::{LateContext, LateLintPass, LintContext, LintPass}; -use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::symbol::Symbol; - -macro_rules! fake_lint_pass { - ($struct:ident, $($attr:expr),*) => { - struct $struct; - - impl LintPass for $struct { - fn name(&self) -> &'static str { - stringify!($struct) - } - } - - impl LateLintPass<'_> for $struct { - fn check_crate(&mut self, cx: &LateContext) { - let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let span = cx.tcx.def_span(CRATE_DEF_ID); - $( - if !cx.sess().contains_name(attrs, $attr) { - cx.lint(CRATE_NOT_OKAY, |lint| { - let msg = format!("crate is not marked with #![{}]", $attr); - lint.build(&msg).set_span(span).emit(); - }); - } - )* - } - } - - } -} - -declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]"); -declare_lint!(CRATE_NOT_RED, Warn, "crate not marked with #![crate_red]"); -declare_lint!(CRATE_NOT_BLUE, Warn, "crate not marked with #![crate_blue]"); -declare_lint!(CRATE_NOT_GREY, Warn, "crate not marked with #![crate_grey]"); -declare_lint!(CRATE_NOT_GREEN, Warn, "crate not marked with #![crate_green]"); - -fake_lint_pass! { - PassOkay, - Symbol::intern("crate_okay") -} - -fake_lint_pass! { - PassRedBlue, - Symbol::intern("crate_red"), Symbol::intern("crate_blue") -} - -fake_lint_pass! { - PassGreyGreen, - Symbol::intern("crate_grey"), Symbol::intern("crate_green") -} - -#[no_mangle] -fn __rustc_plugin_registrar(reg: &mut Registry) { - reg.lint_store.register_lints(&[ - &CRATE_NOT_OKAY, - &CRATE_NOT_RED, - &CRATE_NOT_BLUE, - &CRATE_NOT_GREY, - &CRATE_NOT_GREEN, - ]); - reg.lint_store.register_late_pass(|_| Box::new(PassOkay)); - reg.lint_store.register_late_pass(|_| Box::new(PassRedBlue)); - reg.lint_store.register_late_pass(|_| Box::new(PassGreyGreen)); -} diff --git a/tests/ui-fulldeps/auxiliary/lint-for-crate.rs b/tests/ui-fulldeps/auxiliary/lint-for-crate.rs index 073da688c7cd9..6304c07d2c7ce 100644 --- a/tests/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/tests/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -4,13 +4,13 @@ extern crate rustc_driver; extern crate rustc_hir; -#[macro_use] extern crate rustc_lint; #[macro_use] extern crate rustc_session; extern crate rustc_ast; extern crate rustc_span; +use rustc_ast::attr; use rustc_driver::plugin::Registry; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_span::def_id::CRATE_DEF_ID; @@ -28,12 +28,10 @@ impl<'tcx> LateLintPass<'tcx> for Pass { fn check_crate(&mut self, cx: &LateContext) { let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); let span = cx.tcx.def_span(CRATE_DEF_ID); - if !cx.sess().contains_name(attrs, Symbol::intern("crate_okay")) { - cx.lint( - CRATE_NOT_OKAY, - "crate is not marked with #![crate_okay]", - |lint| lint.set_span(span) - ); + if !attr::contains_name(attrs, Symbol::intern("crate_okay")) { + cx.lint(CRATE_NOT_OKAY, "crate is not marked with #![crate_okay]", |lint| { + lint.set_span(span) + }); } } } From 1581b97acb53217ed604dd873911870f38adbfbb Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Wed, 22 Mar 2023 22:01:19 +0100 Subject: [PATCH 19/19] make link clickable --- compiler/rustc_error_codes/src/error_codes/E0794.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0794.md b/compiler/rustc_error_codes/src/error_codes/E0794.md index a33802885c006..4377a29247331 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0794.md +++ b/compiler/rustc_error_codes/src/error_codes/E0794.md @@ -59,6 +59,6 @@ In the definition of `bar`, the lifetime parameter `'a` is late-bound, while where `'a` is universally quantified and `'b` is substituted by a specific lifetime. It is not allowed to explicitly specify early-bound lifetime arguments when late-bound lifetime parameters are present (as for `bar_fn2`, -see issue #42868: https://github.com/rust-lang/rust/issues/42868), although the +see [issue #42868](https://github.com/rust-lang/rust/issues/42868)), although the types that are constrained by early-bound parameters can be specified (as for `bar_fn3`).