diff options
Diffstat (limited to 'src')
26 files changed, 623 insertions, 306 deletions
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index af62232e792..1544fae962c 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -6,13 +6,12 @@ use rustc_ast as ast; use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_expand::base::SyntaxExtensionKind; -use rustc_hir as hir; use rustc_hir::def::{ DefKind, Namespace::{self, *}, PerNS, }; -use rustc_hir::def_id::{CrateNum, DefId}; +use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_ID}; use rustc_middle::ty::{DefIdTree, Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; use rustc_resolve::ParentScope; @@ -109,6 +108,45 @@ impl Res { Res::Primitive(_) => None, } } + + /// Used for error reporting. + fn disambiguator_suggestion(self) -> Suggestion { + let kind = match self { + Res::Primitive(_) => return Suggestion::Prefix("prim"), + Res::Def(kind, _) => kind, + }; + if kind == DefKind::Macro(MacroKind::Bang) { + return Suggestion::Macro; + } else if kind == DefKind::Fn || kind == DefKind::AssocFn { + return Suggestion::Function; + } else if kind == DefKind::Field { + return Suggestion::RemoveDisambiguator; + } + + let prefix = match kind { + DefKind::Struct => "struct", + DefKind::Enum => "enum", + DefKind::Trait => "trait", + DefKind::Union => "union", + DefKind::Mod => "mod", + DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => { + "const" + } + DefKind::Static => "static", + DefKind::Macro(MacroKind::Derive) => "derive", + // Now handle things that don't have a specific disambiguator + _ => match kind + .ns() + .expect("tried to calculate a disambiguator for a def without a namespace?") + { + Namespace::TypeNS => "type", + Namespace::ValueNS => "value", + Namespace::MacroNS => "macro", + }, + }; + + Suggestion::Prefix(prefix) + } } impl TryFrom<ResolveRes> for Res { @@ -346,7 +384,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { /// In particular, this will return an error whenever there aren't three /// full path segments left in the link. /// - /// [enum struct variant]: hir::VariantData::Struct + /// [enum struct variant]: rustc_hir::VariantData::Struct fn variant_field<'path>( &self, path_str: &'path str, @@ -667,10 +705,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { })) } - /// Returns: - /// - None if no associated item was found - /// - Some((_, _, Some(_))) if an item was found and should go through a side channel - /// - Some((_, _, None)) otherwise + /// Resolve an associated item, returning its containing page's `Res` + /// and the fragment targeting the associated item on its page. fn resolve_associated_item( &mut self, root_res: Res, @@ -903,7 +939,18 @@ fn traits_implemented_by<'a>( ty ); // Fast path: if this is a primitive simple `==` will work - let saw_impl = impl_type == ty; + // NOTE: the `match` is necessary; see #92662. + // this allows us to ignore generics because the user input + // may not include the generic placeholders + // e.g. this allows us to match Foo (user comment) with Foo<T> (actual type) + let saw_impl = impl_type == ty + || match (impl_type.kind(), ty.kind()) { + (ty::Adt(impl_def, _), ty::Adt(ty_def, _)) => { + debug!("impl def_id: {:?}, ty def_id: {:?}", impl_def.did, ty_def.did); + impl_def.did == ty_def.did + } + _ => false, + }; if saw_impl { Some(trait_) } else { None } }) @@ -958,17 +1005,7 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { { self.cx.tcx.parent(did) } - Some(did) => match self.cx.tcx.parent(did) { - // HACK(jynelson): `clean` marks associated types as `TypedefItem`, not as `AssocTypeItem`. - // Fixing this breaks `fn render_deref_methods`. - // As a workaround, see if the parent of the item is an `impl`; if so this must be an associated item, - // regardless of what rustdoc wants to call it. - Some(parent) => { - let parent_kind = self.cx.tcx.def_kind(parent); - Some(if parent_kind == DefKind::Impl { parent } else { did }) - } - None => Some(did), - }, + Some(did) => Some(did), }; // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly @@ -1277,79 +1314,9 @@ impl LinkCollector<'_, '_> { } } - let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { - // The resolved item did not match the disambiguator; give a better error than 'not found' - let msg = format!("incompatible link kind for `{}`", path_str); - let callback = |diag: &mut DiagnosticBuilder<'_>, sp: Option<rustc_span::Span>| { - let note = format!( - "this link resolved to {} {}, which is not {} {}", - resolved.article(), - resolved.descr(), - specified.article(), - specified.descr() - ); - if let Some(sp) = sp { - diag.span_label(sp, ¬e); - } else { - diag.note(¬e); - } - suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp); - }; - report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, callback); - }; - - let verify = |kind: DefKind, id: DefId| { - let (kind, id) = if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment { - (self.cx.tcx.def_kind(id), id) - } else { - (kind, id) - }; - debug!("intra-doc link to {} resolved to {:?} (id: {:?})", path_str, res, id); - - // Disallow e.g. linking to enums with `struct@` - debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); - match (kind, disambiguator) { - | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) - // NOTE: this allows 'method' to mean both normal functions and associated functions - // This can't cause ambiguity because both are in the same namespace. - | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn))) - // These are namespaces; allow anything in the namespace to match - | (_, Some(Disambiguator::Namespace(_))) - // If no disambiguator given, allow anything - | (_, None) - // All of these are valid, so do nothing - => {} - (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} - (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { - report_mismatch(specified, Disambiguator::Kind(kind)); - return None; - } - } - - // item can be non-local e.g. when using #[doc(primitive = "pointer")] - if let Some((src_id, dst_id)) = id - .as_local() - // The `expect_def_id()` should be okay because `local_def_id_to_hir_id` - // would presumably panic if a fake `DefIndex` were passed. - .and_then(|dst_id| { - item.def_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id)) - }) - { - if self.cx.tcx.privacy_access_levels(()).is_exported(src_id) - && !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id) - { - privacy_error(self.cx, &diag_info, path_str); - } - } - - Some(()) - }; - match res { Res::Primitive(prim) => { if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment { - let kind = self.cx.tcx.def_kind(id); - // We're actually resolving an associated item of a primitive, so we need to // verify the disambiguator (if any) matches the type of the associated item. // This case should really follow the same flow as the `Res::Def` branch below, @@ -1358,7 +1325,16 @@ impl LinkCollector<'_, '_> { // doesn't allow statements like `use str::trim;`, making this a (hopefully) // valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677 // for discussion on the matter. - verify(kind, id)?; + let kind = self.cx.tcx.def_kind(id); + self.verify_disambiguator( + path_str, + &ori_link, + kind, + id, + disambiguator, + item, + &diag_info, + )?; // FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether. // However I'm not sure how to check that across crates. @@ -1372,7 +1348,9 @@ impl LinkCollector<'_, '_> { match disambiguator { Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {} Some(other) => { - report_mismatch(other, Disambiguator::Primitive); + self.report_disambiguator_mismatch( + path_str, &ori_link, other, res, &diag_info, + ); return None; } } @@ -1386,13 +1364,106 @@ impl LinkCollector<'_, '_> { }) } Res::Def(kind, id) => { - verify(kind, id)?; + let (kind_for_dis, id_for_dis) = + if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment { + (self.cx.tcx.def_kind(id), id) + } else { + (kind, id) + }; + self.verify_disambiguator( + path_str, + &ori_link, + kind_for_dis, + id_for_dis, + disambiguator, + item, + &diag_info, + )?; let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id)); Some(ItemLink { link: ori_link.link, link_text, did: id, fragment }) } } } + fn verify_disambiguator( + &self, + path_str: &str, + ori_link: &MarkdownLink, + kind: DefKind, + id: DefId, + disambiguator: Option<Disambiguator>, + item: &Item, + diag_info: &DiagnosticInfo<'_>, + ) -> Option<()> { + debug!("intra-doc link to {} resolved to {:?}", path_str, (kind, id)); + + // Disallow e.g. linking to enums with `struct@` + debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); + match (kind, disambiguator) { + | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) + // NOTE: this allows 'method' to mean both normal functions and associated functions + // This can't cause ambiguity because both are in the same namespace. + | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn))) + // These are namespaces; allow anything in the namespace to match + | (_, Some(Disambiguator::Namespace(_))) + // If no disambiguator given, allow anything + | (_, None) + // All of these are valid, so do nothing + => {} + (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} + (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { + self.report_disambiguator_mismatch(path_str,ori_link,specified, Res::Def(kind, id),diag_info); + return None; + } + } + + // item can be non-local e.g. when using #[doc(primitive = "pointer")] + if let Some((src_id, dst_id)) = id + .as_local() + // The `expect_def_id()` should be okay because `local_def_id_to_hir_id` + // would presumably panic if a fake `DefIndex` were passed. + .and_then(|dst_id| { + item.def_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id)) + }) + { + if self.cx.tcx.privacy_access_levels(()).is_exported(src_id) + && !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id) + { + privacy_error(self.cx, diag_info, path_str); + } + } + + Some(()) + } + + fn report_disambiguator_mismatch( + &self, + path_str: &str, + ori_link: &MarkdownLink, + specified: Disambiguator, + resolved: Res, + diag_info: &DiagnosticInfo<'_>, + ) { + // The resolved item did not match the disambiguator; give a better error than 'not found' + let msg = format!("incompatible link kind for `{}`", path_str); + let callback = |diag: &mut DiagnosticBuilder<'_>, sp: Option<rustc_span::Span>| { + let note = format!( + "this link resolved to {} {}, which is not {} {}", + resolved.article(), + resolved.descr(), + specified.article(), + specified.descr(), + ); + if let Some(sp) = sp { + diag.span_label(sp, ¬e); + } else { + diag.note(¬e); + } + suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp); + }; + report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, callback); + } + fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &MarkdownLink, item: &Item) { let span = super::source_span_for_markdown_range(self.cx.tcx, dox, &ori_link.range, &item.attrs) @@ -1413,7 +1484,6 @@ impl LinkCollector<'_, '_> { diag: DiagnosticInfo<'_>, cache_resolution_failure: bool, ) -> Option<(Res, Option<UrlFragment>)> { - // Try to look up both the result and the corresponding side channel value if let Some(ref cached) = self.visited_links.get(&key) { match cached { Some(cached) => { @@ -1686,53 +1756,6 @@ impl Disambiguator { } } - fn from_res(res: Res) -> Self { - match res { - Res::Def(kind, _) => Disambiguator::Kind(kind), - Res::Primitive(_) => Disambiguator::Primitive, - } - } - - /// Used for error reporting. - fn suggestion(self) -> Suggestion { - let kind = match self { - Disambiguator::Primitive => return Suggestion::Prefix("prim"), - Disambiguator::Kind(kind) => kind, - Disambiguator::Namespace(_) => panic!("display_for cannot be used on namespaces"), - }; - if kind == DefKind::Macro(MacroKind::Bang) { - return Suggestion::Macro; - } else if kind == DefKind::Fn || kind == DefKind::AssocFn { - return Suggestion::Function; - } else if kind == DefKind::Field { - return Suggestion::RemoveDisambiguator; - } - - let prefix = match kind { - DefKind::Struct => "struct", - DefKind::Enum => "enum", - DefKind::Trait => "trait", - DefKind::Union => "union", - DefKind::Mod => "mod", - DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => { - "const" - } - DefKind::Static => "static", - DefKind::Macro(MacroKind::Derive) => "derive", - // Now handle things that don't have a specific disambiguator - _ => match kind - .ns() - .expect("tried to calculate a disambiguator for a def without a namespace?") - { - Namespace::TypeNS => "type", - Namespace::ValueNS => "value", - Namespace::MacroNS => "macro", - }, - }; - - Suggestion::Prefix(prefix) - } - fn ns(self) -> Namespace { match self { Self::Namespace(n) => n, @@ -1754,9 +1777,9 @@ impl Disambiguator { fn descr(self) -> &'static str { match self { Self::Namespace(n) => n.descr(), - // HACK(jynelson): by looking at the source I saw the DefId we pass - // for `expected.descr()` doesn't matter, since it's not a crate - Self::Kind(k) => k.descr(DefId::local(hir::def_id::DefIndex::from_usize(0))), + // HACK(jynelson): the source of `DefKind::descr` only uses the DefId for + // printing "module" vs "crate" so using the wrong ID is not a huge problem + Self::Kind(k) => k.descr(CRATE_DEF_ID.to_def_id()), Self::Primitive => "builtin type", } } @@ -2080,16 +2103,7 @@ fn resolution_failure( ResolutionFailure::NotResolved { .. } => unreachable!("handled above"), ResolutionFailure::Dummy => continue, ResolutionFailure::WrongNamespace { res, expected_ns } => { - if let Res::Def(kind, _) = res { - let disambiguator = Disambiguator::Kind(kind); - suggest_disambiguator( - disambiguator, - diag, - path_str, - diag_info.ori_link, - sp, - ) - } + suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp); format!( "this link resolves to {}, which is not in the {} namespace", @@ -2224,8 +2238,7 @@ fn ambiguity_error( } for res in candidates { - let disambiguator = Disambiguator::from_res(res); - suggest_disambiguator(disambiguator, diag, path_str, diag_info.ori_link, sp); + suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp); } }); } @@ -2233,14 +2246,14 @@ fn ambiguity_error( /// In case of an ambiguity or mismatched disambiguator, suggest the correct /// disambiguator. fn suggest_disambiguator( - disambiguator: Disambiguator, + res: Res, diag: &mut DiagnosticBuilder<'_>, path_str: &str, ori_link: &str, sp: Option<rustc_span::Span>, ) { - let suggestion = disambiguator.suggestion(); - let help = format!("to link to the {}, {}", disambiguator.descr(), suggestion.descr()); + let suggestion = res.disambiguator_suggestion(); + let help = format!("to link to the {}, {}", res.descr(), suggestion.descr()); if let Some(sp) = sp { let mut spans = suggestion.as_help_span(path_str, ori_link, sp); diff --git a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs index 142008cf765..2d66566119b 100644 --- a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs +++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs @@ -73,4 +73,9 @@ trait T {} //~^ ERROR incompatible link kind for `f` //~| NOTE this link resolved //~| HELP add parentheses + +/// Link to [fn@std] +//~^ ERROR unresolved link to `std` +//~| NOTE this link resolves to the crate `std` +//~| HELP to link to the crate, prefix with `mod@` pub fn f() {} diff --git a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr index 12122f5fa86..ad9102c506f 100644 --- a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr +++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr @@ -138,5 +138,16 @@ LL - /// Link to [const@f] LL + /// Link to [f()] | -error: aborting due to 12 previous errors +error: unresolved link to `std` + --> $DIR/disambiguator-mismatch.rs:77:14 + | +LL | /// Link to [fn@std] + | ^^^^^^ this link resolves to the crate `std`, which is not in the value namespace + | +help: to link to the crate, prefix with `mod@` + | +LL | /// Link to [mod@std] + | ~~~~ + +error: aborting due to 13 previous errors diff --git a/src/test/rustdoc/intra-doc/extern-type.rs b/src/test/rustdoc/intra-doc/extern-type.rs index f37ae62dde1..ab088ab789d 100644 --- a/src/test/rustdoc/intra-doc/extern-type.rs +++ b/src/test/rustdoc/intra-doc/extern-type.rs @@ -4,14 +4,34 @@ extern { pub type ExternType; } +pub trait T { + fn test(&self) {} +} + +pub trait G<N> { + fn g(&self, n: N) {} +} + impl ExternType { - pub fn f(&self) { + pub fn f(&self) {} +} - } +impl T for ExternType { + fn test(&self) {} +} + +impl G<usize> for ExternType { + fn g(&self, n: usize) {} } // @has 'extern_type/foreigntype.ExternType.html' // @has 'extern_type/fn.links_to_extern_type.html' \ // 'href="foreigntype.ExternType.html#method.f"' +// @has 'extern_type/fn.links_to_extern_type.html' \ +// 'href="foreigntype.ExternType.html#method.test"' +// @has 'extern_type/fn.links_to_extern_type.html' \ +// 'href="foreigntype.ExternType.html#method.g"' /// See also [ExternType::f] +/// See also [ExternType::test] +/// See also [ExternType::g] pub fn links_to_extern_type() {} diff --git a/src/test/rustdoc/intra-doc/generic-trait-impl.rs b/src/test/rustdoc/intra-doc/generic-trait-impl.rs new file mode 100644 index 00000000000..ba8595abfa9 --- /dev/null +++ b/src/test/rustdoc/intra-doc/generic-trait-impl.rs @@ -0,0 +1,20 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +// Test intra-doc links on trait implementations with generics +// regression test for issue #92662 + +use std::marker::PhantomData; + +pub trait Bar<T> { + fn bar(&self); +} + +pub struct Foo<U>(PhantomData<U>); + +impl<T, U> Bar<T> for Foo<U> { + fn bar(&self) {} +} + +// @has generic_trait_impl/fn.main.html '//a[@href="struct.Foo.html#method.bar"]' 'Foo::bar' +/// link to [`Foo::bar`] +pub fn main() {} diff --git a/src/test/rustdoc/intra-link-prim-self.rs b/src/test/rustdoc/intra-doc/prim-self.rs index 8a564acf2ca..7a65723d77b 100644 --- a/src/test/rustdoc/intra-link-prim-self.rs +++ b/src/test/rustdoc/intra-doc/prim-self.rs @@ -1,13 +1,15 @@ #![deny(rustdoc::broken_intra_doc_links)] +#![allow(incomplete_features)] // inherent_associated_types #![feature(lang_items)] #![feature(no_core)] #![feature(rustdoc_internals)] +#![feature(inherent_associated_types)] #![no_core] #[lang = "usize"] /// [Self::f] /// [Self::MAX] -// @has intra_link_prim_self/primitive.usize.html +// @has prim_self/primitive.usize.html // @has - '//a[@href="primitive.usize.html#method.f"]' 'Self::f' // @has - '//a[@href="primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX' impl usize { @@ -17,10 +19,9 @@ impl usize { /// 10 and 2^32 are basically the same. pub const MAX: usize = 10; - // FIXME(#8995) uncomment this when associated types in inherent impls are supported - // @ has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedtype.ME"]' 'Self::ME' - // / [Self::ME] - //pub type ME = usize; + // @has - '//a[@href="primitive.usize.html#associatedtype.ME"]' 'Self::ME' + /// [Self::ME] + pub type ME = usize; } #[doc(primitive = "usize")] diff --git a/src/test/rustdoc/intra-link-self-cache.rs b/src/test/rustdoc/intra-doc/self-cache.rs index 63bf7fa5768..63bf7fa5768 100644 --- a/src/test/rustdoc/intra-link-self-cache.rs +++ b/src/test/rustdoc/intra-doc/self-cache.rs diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr deleted file mode 100644 index 2751a37f741..00000000000 --- a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr +++ /dev/null @@ -1,80 +0,0 @@ -error: passing `Ty<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:13:13 - | -LL | ty_ref: &Ty<'_>, - | ^^^^^^^ help: try passing by value: `Ty<'_>` - | -note: the lint level is defined here - --> $DIR/pass_ty_by_ref.rs:4:9 - | -LL | #![deny(rustc::ty_pass_by_reference)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: passing `TyCtxt<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:15:18 - | -LL | ty_ctxt_ref: &TyCtxt<'_>, - | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` - -error: passing `Ty<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:19:28 - | -LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} - | ^^^^^^^ help: try passing by value: `Ty<'_>` - -error: passing `TyCtxt<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:19:55 - | -LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} - | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` - -error: passing `Ty<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:26:17 - | -LL | ty_ref: &Ty<'_>, - | ^^^^^^^ help: try passing by value: `Ty<'_>` - -error: passing `TyCtxt<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:28:22 - | -LL | ty_ctxt_ref: &TyCtxt<'_>, - | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` - -error: passing `Ty<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:31:41 - | -LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>); - | ^^^^^^^ help: try passing by value: `Ty<'_>` - -error: passing `TyCtxt<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:31:68 - | -LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>); - | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` - -error: passing `Ty<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:53:17 - | -LL | ty_ref: &Ty<'_>, - | ^^^^^^^ help: try passing by value: `Ty<'_>` - -error: passing `TyCtxt<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:55:22 - | -LL | ty_ctxt_ref: &TyCtxt<'_>, - | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` - -error: passing `Ty<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:59:38 - | -LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} - | ^^^^^^^ help: try passing by value: `Ty<'_>` - -error: passing `TyCtxt<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:59:65 - | -LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} - | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` - -error: aborting due to 12 previous errors - diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr deleted file mode 100644 index 15a06e721dd..00000000000 --- a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: passing `TyCtxt<'tcx>` by reference - --> $DIR/pass_ty_by_ref_self.rs:18:15 - | -LL | fn by_ref(&self) {} - | ^^^^^ help: try passing by value: `TyCtxt<'tcx>` - | -note: the lint level is defined here - --> $DIR/pass_ty_by_ref_self.rs:8:9 - | -LL | #![deny(rustc::ty_pass_by_reference)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: passing `Ty<'tcx>` by reference - --> $DIR/pass_ty_by_ref_self.rs:31:21 - | -LL | fn by_ref(self: &Ty<'tcx>) {} - | ^^^^^^^^^ help: try passing by value: `Ty<'tcx>` - -error: aborting due to 2 previous errors - diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs index e0fdbaeac30..402c41f3766 100644 --- a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.rs +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs @@ -1,7 +1,8 @@ // compile-flags: -Z unstable-options +#![feature(rustc_attrs)] #![feature(rustc_private)] -#![deny(rustc::ty_pass_by_reference)] +#![deny(rustc::pass_by_value)] #![allow(unused)] extern crate rustc_middle; @@ -61,4 +62,57 @@ impl Foo { //~^^ ERROR passing `TyCtxt<'_>` by reference } +#[rustc_pass_by_value] +enum CustomEnum { + A, + B, +} + +impl CustomEnum { + fn test( + value: CustomEnum, + reference: &CustomEnum, //~ ERROR passing `CustomEnum` by reference + ) { + } +} + +#[rustc_pass_by_value] +struct CustomStruct { + s: u8, +} + +#[rustc_pass_by_value] +type CustomAlias<'a> = &'a CustomStruct; //~ ERROR passing `CustomStruct` by reference + +impl CustomStruct { + fn test( + value: CustomStruct, + reference: &CustomStruct, //~ ERROR passing `CustomStruct` by reference + ) { + } + + fn test_alias( + value: CustomAlias, + reference: &CustomAlias, //~ ERROR passing `CustomAlias<>` by reference + ) { + } +} + +#[rustc_pass_by_value] +struct WithParameters<T, const N: usize, M = u32> { + slice: [T; N], + m: M, +} + +impl<T> WithParameters<T, 1> { + fn test<'a>( + value: WithParameters<T, 1>, + reference: &'a WithParameters<T, 1>, //~ ERROR passing `WithParameters<T, 1>` by reference + reference_with_m: &WithParameters<T, 1, u32>, //~ ERROR passing `WithParameters<T, 1, u32>` by reference + ) -> &'a WithParameters<T, 1> { + //~^ ERROR passing `WithParameters<T, 1>` by reference + reference as &WithParameters<_, 1> //~ ERROR passing `WithParameters<_, 1>` by reference + } +} + fn main() {} diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr new file mode 100644 index 00000000000..7f6e57b38f3 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr @@ -0,0 +1,128 @@ +error: passing `Ty<'_>` by reference + --> $DIR/rustc_pass_by_value.rs:14:13 + | +LL | ty_ref: &Ty<'_>, + | ^^^^^^^ help: try passing by value: `Ty<'_>` + | +note: the lint level is defined here + --> $DIR/rustc_pass_by_value.rs:5:9 + | +LL | #![deny(rustc::pass_by_value)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: passing `TyCtxt<'_>` by reference + --> $DIR/rustc_pass_by_value.rs:16:18 + | +LL | ty_ctxt_ref: &TyCtxt<'_>, + | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` + +error: passing `Ty<'_>` by reference + --> $DIR/rustc_pass_by_value.rs:20:28 + | +LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} + | ^^^^^^^ help: try passing by value: `Ty<'_>` + +error: passing `TyCtxt<'_>` by reference + --> $DIR/rustc_pass_by_value.rs:20:55 + | +LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} + | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` + +error: passing `Ty<'_>` by reference + --> $DIR/rustc_pass_by_value.rs:27:17 + | +LL | ty_ref: &Ty<'_>, + | ^^^^^^^ help: try passing by value: `Ty<'_>` + +error: passing `TyCtxt<'_>` by reference + --> $DIR/rustc_pass_by_value.rs:29:22 + | +LL | ty_ctxt_ref: &TyCtxt<'_>, + | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` + +error: passing `Ty<'_>` by reference + --> $DIR/rustc_pass_by_value.rs:32:41 + | +LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>); + | ^^^^^^^ help: try passing by value: `Ty<'_>` + +error: passing `TyCtxt<'_>` by reference + --> $DIR/rustc_pass_by_value.rs:32:68 + | +LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>); + | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` + +error: passing `Ty<'_>` by reference + --> $DIR/rustc_pass_by_value.rs:54:17 + | +LL | ty_ref: &Ty<'_>, + | ^^^^^^^ help: try passing by value: `Ty<'_>` + +error: passing `TyCtxt<'_>` by reference + --> $DIR/rustc_pass_by_value.rs:56:22 + | +LL | ty_ctxt_ref: &TyCtxt<'_>, + | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` + +error: passing `Ty<'_>` by reference + --> $DIR/rustc_pass_by_value.rs:60:38 + | +LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} + | ^^^^^^^ help: try passing by value: `Ty<'_>` + +error: passing `TyCtxt<'_>` by reference + --> $DIR/rustc_pass_by_value.rs:60:65 + | +LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} + | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` + +error: passing `CustomEnum` by reference + --> $DIR/rustc_pass_by_value.rs:74:20 + | +LL | reference: &CustomEnum, + | ^^^^^^^^^^^ help: try passing by value: `CustomEnum` + +error: passing `CustomStruct` by reference + --> $DIR/rustc_pass_by_value.rs:85:24 + | +LL | type CustomAlias<'a> = &'a CustomStruct; + | ^^^^^^^^^^^^^^^^ help: try passing by value: `CustomStruct` + +error: passing `CustomStruct` by reference + --> $DIR/rustc_pass_by_value.rs:90:20 + | +LL | reference: &CustomStruct, + | ^^^^^^^^^^^^^ help: try passing by value: `CustomStruct` + +error: passing `CustomAlias<>` by reference + --> $DIR/rustc_pass_by_value.rs:96:20 + | +LL | reference: &CustomAlias, + | ^^^^^^^^^^^^ help: try passing by value: `CustomAlias<>` + +error: passing `WithParameters<T, 1>` by reference + --> $DIR/rustc_pass_by_value.rs:110:20 + | +LL | reference: &'a WithParameters<T, 1>, + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1>` + +error: passing `WithParameters<T, 1, u32>` by reference + --> $DIR/rustc_pass_by_value.rs:111:27 + | +LL | reference_with_m: &WithParameters<T, 1, u32>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1, u32>` + +error: passing `WithParameters<T, 1>` by reference + --> $DIR/rustc_pass_by_value.rs:112:10 + | +LL | ) -> &'a WithParameters<T, 1> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1>` + +error: passing `WithParameters<_, 1>` by reference + --> $DIR/rustc_pass_by_value.rs:114:22 + | +LL | reference as &WithParameters<_, 1> + | ^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<_, 1>` + +error: aborting due to 20 previous errors + diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs index 48b140d9174..2868517774d 100644 --- a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs @@ -5,10 +5,10 @@ // Considering that all other `internal-lints` are tested here // this seems like the cleaner solution though. #![feature(rustc_attrs)] -#![deny(rustc::ty_pass_by_reference)] +#![deny(rustc::pass_by_value)] #![allow(unused)] -#[rustc_diagnostic_item = "TyCtxt"] +#[rustc_pass_by_value] struct TyCtxt<'tcx> { inner: &'tcx (), } @@ -18,12 +18,11 @@ impl<'tcx> TyCtxt<'tcx> { fn by_ref(&self) {} //~ ERROR passing `TyCtxt<'tcx>` by reference } - struct TyS<'tcx> { inner: &'tcx (), } -#[rustc_diagnostic_item = "Ty"] +#[rustc_pass_by_value] type Ty<'tcx> = &'tcx TyS<'tcx>; impl<'tcx> TyS<'tcx> { @@ -31,4 +30,25 @@ impl<'tcx> TyS<'tcx> { fn by_ref(self: &Ty<'tcx>) {} //~ ERROR passing `Ty<'tcx>` by reference } +#[rustc_pass_by_value] +struct Foo; + +impl Foo { + fn with_ref(&self) {} //~ ERROR passing `Foo` by reference +} + +#[rustc_pass_by_value] +struct WithParameters<T, const N: usize, M = u32> { + slice: [T; N], + m: M, +} + +impl<T> WithParameters<T, 1> { + fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1_usize>` by reference +} + +impl<T> WithParameters<T, 1, u8> { + fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1_usize, u8>` by reference +} + fn main() {} diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr new file mode 100644 index 00000000000..54a7cf7cab7 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr @@ -0,0 +1,38 @@ +error: passing `TyCtxt<'tcx>` by reference + --> $DIR/rustc_pass_by_value_self.rs:18:15 + | +LL | fn by_ref(&self) {} + | ^^^^^ help: try passing by value: `TyCtxt<'tcx>` + | +note: the lint level is defined here + --> $DIR/rustc_pass_by_value_self.rs:8:9 + | +LL | #![deny(rustc::pass_by_value)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: passing `Ty<'tcx>` by reference + --> $DIR/rustc_pass_by_value_self.rs:30:21 + | +LL | fn by_ref(self: &Ty<'tcx>) {} + | ^^^^^^^^^ help: try passing by value: `Ty<'tcx>` + +error: passing `Foo` by reference + --> $DIR/rustc_pass_by_value_self.rs:37:17 + | +LL | fn with_ref(&self) {} + | ^^^^^ help: try passing by value: `Foo` + +error: passing `WithParameters<T, 1_usize>` by reference + --> $DIR/rustc_pass_by_value_self.rs:47:17 + | +LL | fn with_ref(&self) {} + | ^^^^^ help: try passing by value: `WithParameters<T, 1_usize>` + +error: passing `WithParameters<T, 1_usize, u8>` by reference + --> $DIR/rustc_pass_by_value_self.rs:51:17 + | +LL | fn with_ref(&self) {} + | ^^^^^ help: try passing by value: `WithParameters<T, 1_usize, u8>` + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/generic-associated-types/issue-92096.migrate.stderr b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr new file mode 100644 index 00000000000..72ade5774d7 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr @@ -0,0 +1,18 @@ +error[E0311]: the parameter type `C` may not live long enough + --> $DIR/issue-92096.rs:20:33 + | +LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send + | - ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds + | | + | help: consider adding an explicit lifetime bound...: `C: 'a` + +error[E0311]: the parameter type `C` may not live long enough + --> $DIR/issue-92096.rs:20:33 + | +LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send + | - ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds + | | + | help: consider adding an explicit lifetime bound...: `C: 'a` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/generic-associated-types/issue-92096.rs b/src/test/ui/generic-associated-types/issue-92096.rs new file mode 100644 index 00000000000..066132a5d98 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-92096.rs @@ -0,0 +1,29 @@ +// edition:2018 +// [nll] check-pass +// revisions: migrate nll +// Explicitly testing nll with revision, so ignore compare-mode=nll +// ignore-compare-mode-nll + +#![cfg_attr(nll, feature(nll))] +#![feature(generic_associated_types)] + +use std::future::Future; + +trait Client { + type Connecting<'a>: Future + Send + where + Self: 'a; + + fn connect(&'_ self) -> Self::Connecting<'_>; +} + +fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send +//[migrate]~^ ERROR the parameter +//[migrate]~| ERROR the parameter +where + C: Client + Send + Sync, +{ + async move { c.connect().await } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-92280.rs b/src/test/ui/generic-associated-types/issue-92280.rs new file mode 100644 index 00000000000..db26493ecad --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-92280.rs @@ -0,0 +1,26 @@ +// check-pass + +#![feature(generic_associated_types)] +#![allow(non_camel_case_types)] + +trait HasAssoc { + type Assoc; +} + +trait Iterate<S: HasAssoc> { + type Iter<'a> + where + Self: 'a; +} + +struct KeySegment_Broken<T> { + key: T, +} +impl<S: HasAssoc> Iterate<S> for KeySegment_Broken<S::Assoc> { + type Iter<'a> + where + Self: 'a, + = (); +} + +fn main() {} diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs index 820dcdb9394..004ab386b3f 100644 --- a/src/test/ui/macros/stringify.rs +++ b/src/test/ui/macros/stringify.rs @@ -589,7 +589,7 @@ fn test_item() { stringify_item!( pub trait Trait<T> = Sized where T: 'a; ), - "", // FIXME + "pub trait Trait<T> = Sized where T: 'a;", ); // ItemKind::Impl diff --git a/src/test/ui/parser/issues/issue-35813-postfix-after-cast.rs b/src/test/ui/parser/issues/issue-35813-postfix-after-cast.rs index e725aa5d73d..23f245a5168 100644 --- a/src/test/ui/parser/issues/issue-35813-postfix-after-cast.rs +++ b/src/test/ui/parser/issues/issue-35813-postfix-after-cast.rs @@ -117,9 +117,9 @@ static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); pub fn cast_then_try() -> Result<u64,u64> { Err(0u64) as Result<u64,u64>?; - //~^ ERROR: casts cannot be followed by ? + //~^ ERROR: casts cannot be followed by `?` Err(0u64): Result<u64,u64>?; - //~^ ERROR: casts cannot be followed by ? + //~^ ERROR: casts cannot be followed by `?` Ok(1) } diff --git a/src/test/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/src/test/ui/parser/issues/issue-35813-postfix-after-cast.stderr index 19b68556d79..e96b67da336 100644 --- a/src/test/ui/parser/issues/issue-35813-postfix-after-cast.stderr +++ b/src/test/ui/parser/issues/issue-35813-postfix-after-cast.stderr @@ -265,7 +265,7 @@ help: try surrounding the expression in parentheses LL | static bar2: &[i32] = &((&[1i32,2,3]: &[i32; 3])[0..1]); | + + -error: casts cannot be followed by ? +error: casts cannot be followed by `?` --> $DIR/issue-35813-postfix-after-cast.rs:119:5 | LL | Err(0u64) as Result<u64,u64>?; @@ -276,7 +276,7 @@ help: try surrounding the expression in parentheses LL | (Err(0u64) as Result<u64,u64>)?; | + + -error: casts cannot be followed by ? +error: casts cannot be followed by `?` --> $DIR/issue-35813-postfix-after-cast.rs:121:5 | LL | Err(0u64): Result<u64,u64>?; diff --git a/src/test/ui/parser/issues/issue-84148-1.rs b/src/test/ui/parser/issues/issue-84148-1.rs index 25f7ba4d1f8..9fa8086c2c9 100644 --- a/src/test/ui/parser/issues/issue-84148-1.rs +++ b/src/test/ui/parser/issues/issue-84148-1.rs @@ -1,4 +1,3 @@ fn f(t:for<>t?) -//~^ ERROR: expected parameter name -//~| ERROR: expected one of -//~| ERROR: expected one of +//~^ ERROR: expected one of +//~| ERROR: invalid `?` in type diff --git a/src/test/ui/parser/issues/issue-84148-1.stderr b/src/test/ui/parser/issues/issue-84148-1.stderr index 77f0896e9c1..9261067c221 100644 --- a/src/test/ui/parser/issues/issue-84148-1.stderr +++ b/src/test/ui/parser/issues/issue-84148-1.stderr @@ -1,17 +1,13 @@ -error: expected parameter name, found `?` +error: invalid `?` in type --> $DIR/issue-84148-1.rs:1:14 | LL | fn f(t:for<>t?) - | ^ expected parameter name - -error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?` - --> $DIR/issue-84148-1.rs:1:14 + | ^ `?` is only allowed on expressions, not types | -LL | fn f(t:for<>t?) - | ^ - | | - | expected one of `(`, `)`, `+`, `,`, `::`, or `<` - | help: missing `,` +help: if you meant to express that the type might not contain a value, use the `Option` wrapper type + | +LL | fn f(t:Option<for<>t>) + | +++++++ ~ error: expected one of `->`, `where`, or `{`, found `<eof>` --> $DIR/issue-84148-1.rs:1:15 @@ -19,5 +15,5 @@ error: expected one of `->`, `where`, or `{`, found `<eof>` LL | fn f(t:for<>t?) | ^ expected one of `->`, `where`, or `{` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/issues/issue-84148-2.rs b/src/test/ui/parser/issues/issue-84148-2.rs index 257a3fd6720..2f6a7facfb2 100644 --- a/src/test/ui/parser/issues/issue-84148-2.rs +++ b/src/test/ui/parser/issues/issue-84148-2.rs @@ -1,4 +1,3 @@ // error-pattern: this file contains an unclosed delimiter -// error-pattern: expected parameter name -// error-pattern: expected one of +// error-pattern: invalid `?` in type fn f(t:for<>t? diff --git a/src/test/ui/parser/issues/issue-84148-2.stderr b/src/test/ui/parser/issues/issue-84148-2.stderr index 396208316df..71d543f9b73 100644 --- a/src/test/ui/parser/issues/issue-84148-2.stderr +++ b/src/test/ui/parser/issues/issue-84148-2.stderr @@ -1,31 +1,27 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-84148-2.rs:4:16 + --> $DIR/issue-84148-2.rs:3:16 | LL | fn f(t:for<>t? | - ^ | | | unclosed delimiter -error: expected parameter name, found `?` - --> $DIR/issue-84148-2.rs:4:14 +error: invalid `?` in type + --> $DIR/issue-84148-2.rs:3:14 | LL | fn f(t:for<>t? - | ^ expected parameter name - -error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?` - --> $DIR/issue-84148-2.rs:4:14 + | ^ `?` is only allowed on expressions, not types | -LL | fn f(t:for<>t? - | ^ - | | - | expected one of `(`, `)`, `+`, `,`, `::`, or `<` - | help: missing `,` +help: if you meant to express that the type might not contain a value, use the `Option` wrapper type + | +LL | fn f(t:Option<for<>t> + | +++++++ ~ error: expected one of `->`, `where`, or `{`, found `<eof>` - --> $DIR/issue-84148-2.rs:4:16 + --> $DIR/issue-84148-2.rs:3:16 | LL | fn f(t:for<>t? | ^ expected one of `->`, `where`, or `{` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/trailing-question-in-type.fixed b/src/test/ui/parser/trailing-question-in-type.fixed new file mode 100644 index 00000000000..6ea24484e03 --- /dev/null +++ b/src/test/ui/parser/trailing-question-in-type.fixed @@ -0,0 +1,10 @@ +// run-rustfix + +fn foo() -> Option<i32> { //~ ERROR invalid `?` in type + let x: Option<i32> = Some(1); //~ ERROR invalid `?` in type + x +} + +fn main() { + let _: Option<i32> = foo(); +} diff --git a/src/test/ui/parser/trailing-question-in-type.rs b/src/test/ui/parser/trailing-question-in-type.rs new file mode 100644 index 00000000000..b1c508365cf --- /dev/null +++ b/src/test/ui/parser/trailing-question-in-type.rs @@ -0,0 +1,10 @@ +// run-rustfix + +fn foo() -> i32? { //~ ERROR invalid `?` in type + let x: i32? = Some(1); //~ ERROR invalid `?` in type + x +} + +fn main() { + let _: Option<i32> = foo(); +} diff --git a/src/test/ui/parser/trailing-question-in-type.stderr b/src/test/ui/parser/trailing-question-in-type.stderr new file mode 100644 index 00000000000..a3cd419c0c7 --- /dev/null +++ b/src/test/ui/parser/trailing-question-in-type.stderr @@ -0,0 +1,24 @@ +error: invalid `?` in type + --> $DIR/trailing-question-in-type.rs:3:16 + | +LL | fn foo() -> i32? { + | ^ `?` is only allowed on expressions, not types + | +help: if you meant to express that the type might not contain a value, use the `Option` wrapper type + | +LL | fn foo() -> Option<i32> { + | +++++++ ~ + +error: invalid `?` in type + --> $DIR/trailing-question-in-type.rs:4:15 + | +LL | let x: i32? = Some(1); + | ^ `?` is only allowed on expressions, not types + | +help: if you meant to express that the type might not contain a value, use the `Option` wrapper type + | +LL | let x: Option<i32> = Some(1); + | +++++++ ~ + +error: aborting due to 2 previous errors + |
