From a18f43f25d414a9a3990bd2afe25e26b92f5fb22 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 1 Jan 2022 17:52:15 -0800 Subject: [PATCH 01/28] Fix unclosed boxes in pretty printing of TraitAlias --- compiler/rustc_ast_pretty/src/pprust/state.rs | 6 +++--- compiler/rustc_hir_pretty/src/lib.rs | 6 +++--- src/test/ui/macros/stringify.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index b87dd449a1e57..b5b87c0b48af1 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1354,9 +1354,7 @@ impl<'a> State<'a> { self.bclose(item.span, empty); } ast::ItemKind::TraitAlias(ref generics, ref bounds) => { - self.head(""); - self.print_visibility(&item.vis); - self.word_nbsp("trait"); + self.head(visibility_qualified(&item.vis, "trait")); self.print_ident(item.ident); self.print_generic_params(&generics.params); let mut real_bounds = Vec::with_capacity(bounds.len()); @@ -1374,6 +1372,8 @@ impl<'a> State<'a> { self.print_type_bounds("=", &real_bounds); self.print_where_clause(&generics.where_clause); self.word(";"); + self.end(); // end inner head-block + self.end(); // end outer head-block } ast::ItemKind::MacCall(ref mac) => { self.print_mac(mac); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index fb11aaf24c4b8..ad47c69652035 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -705,9 +705,7 @@ impl<'a> State<'a> { self.bclose(item.span); } hir::ItemKind::TraitAlias(ref generics, ref bounds) => { - self.head(""); - self.print_visibility(&item.vis); - self.word_nbsp("trait"); + self.head(visibility_qualified(&item.vis, "trait")); self.print_ident(item.ident); self.print_generic_params(&generics.params); let mut real_bounds = Vec::with_capacity(bounds.len()); @@ -725,6 +723,8 @@ impl<'a> State<'a> { self.print_bounds("=", real_bounds); self.print_where_clause(&generics.where_clause); self.word(";"); + self.end(); // end inner head-block + self.end(); // end outer head-block } } self.ann.post(self, AnnNode::Item(item)) diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs index 343a26c14a9b0..36e01a7508f34 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 = Sized where T: 'a; ), - "", // FIXME + "pub trait Trait = Sized where T: 'a;", ); // ItemKind::Impl From 8423ce9f9a86488d9e49fa448c8d6a13d10c878d Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Wed, 5 Jan 2022 11:40:30 +0100 Subject: [PATCH 02/28] Enable default libraries --- compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs index afe8bbb352886..3e3a6ac82a439 100644 --- a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs +++ b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs @@ -36,6 +36,7 @@ pub fn target() -> Target { features: "+vfp2".to_string(), pre_link_args, exe_suffix: ".elf".to_string(), + no_default_libraries: false, ..Default::default() }, } From 7ea03db04a38bd5bb8ad13ee805d94833aacf032 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 6 Jan 2022 14:50:46 +0000 Subject: [PATCH 03/28] Add diagnostic items for macros --- compiler/rustc_span/src/symbol.rs | 31 +++++++++++++++++++++++++++++++ library/alloc/src/macros.rs | 1 + library/core/src/macros/mod.rs | 24 ++++++++++++++++++++++++ library/std/src/macros.rs | 5 +++++ library/std/src/thread/local.rs | 1 + 5 files changed, 62 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 84cf8878af809..afad98b20c5d5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -334,8 +334,10 @@ symbols! { asm_sym, asm_unwind, assert, + assert_eq_macro, assert_inhabited, assert_macro, + assert_ne_macro, assert_receiver_is_total_eq, assert_uninit_valid, assert_zero_valid, @@ -405,6 +407,7 @@ symbols! { cfg_doctest, cfg_eval, cfg_hide, + cfg_macro, cfg_panic, cfg_sanitize, cfg_target_abi, @@ -432,15 +435,18 @@ symbols! { coerce_unsized, cold, column, + column_macro, compare_and_swap, compare_exchange, compare_exchange_weak, compile_error, + compile_error_macro, compiler_builtins, compiler_fence, concat, concat_bytes, concat_idents, + concat_macro, conservative_impl_trait, console, const_allocate, @@ -520,10 +526,13 @@ symbols! { custom_inner_attributes, custom_test_frameworks, d, + dbg_macro, dead_code, dealloc, debug, + debug_assert_eq_macro, debug_assert_macro, + debug_assert_ne_macro, debug_assertions, debug_struct, debug_trait_builder, @@ -593,6 +602,9 @@ symbols! { enclosing_scope, encode, env, + env_macro, + eprint_macro, + eprintln_macro, eq, ermsb_target_feature, exact_div, @@ -640,6 +652,7 @@ symbols! { field, field_init_shorthand, file, + file_macro, fill, finish, flags, @@ -662,6 +675,7 @@ symbols! { format, format_args, format_args_capture, + format_args_macro, format_args_nl, format_macro, freeze, @@ -728,7 +742,10 @@ symbols! { in_band_lifetimes, include, include_bytes, + include_bytes_macro, + include_macro, include_str, + include_str_macro, inclusive_range_syntax, index, index_mut, @@ -776,6 +793,7 @@ symbols! { lifetime, likely, line, + line_macro, link, link_args, link_cfg, @@ -819,6 +837,7 @@ symbols! { masked, match_beginning_vert, match_default_bindings, + matches_macro, maxnumf32, maxnumf64, may_dangle, @@ -855,6 +874,7 @@ symbols! { modifiers, module, module_path, + module_path_macro, more_qualified_paths, more_struct_aliases, movbe_target_feature, @@ -938,6 +958,7 @@ symbols! { optin_builtin_traits, option, option_env, + option_env_macro, options, or, or_patterns, @@ -1001,6 +1022,8 @@ symbols! { prelude_import, preserves_flags, primitive, + print_macro, + println_macro, proc_dash_macro: "proc-macro", proc_macro, proc_macro_attribute, @@ -1288,6 +1311,7 @@ symbols! { str, str_alloc, stringify, + stringify_macro, struct_field_attributes, struct_inherit, struct_variant, @@ -1331,6 +1355,8 @@ symbols! { then_with, thread, thread_local, + thread_local_macro, + todo_macro, tool_attributes, tool_lints, trace_macros, @@ -1381,6 +1407,7 @@ symbols! { underscore_imports, underscore_lifetimes, uniform_paths, + unimplemented_macro, unit, universal_impl_trait, unix, @@ -1389,6 +1416,7 @@ symbols! { unpin, unreachable, unreachable_code, + unreachable_macro, unrestricted_attribute_tokens, unsafe_block_in_unsafe_fn, unsafe_cell, @@ -1419,6 +1447,7 @@ symbols! { var, variant_count, vec, + vec_macro, version, vis, visible_private_types, @@ -1443,7 +1472,9 @@ symbols! { wrapping_sub, wreg, write_bytes, + write_macro, write_str, + writeln_macro, x87_reg, xer, xmm_reg, diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 189da9f06392a..d3e9e65c3fe57 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -37,6 +37,7 @@ #[cfg(not(test))] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "vec_macro"] #[allow_internal_unstable(box_syntax, liballoc_internals)] macro_rules! vec { () => ( diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index d8f6c85e428cd..d5cda360bba3a 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -31,6 +31,7 @@ macro_rules! panic { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "assert_eq_macro")] #[allow_internal_unstable(core_panic)] macro_rules! assert_eq { ($left:expr, $right:expr $(,)?) => ({ @@ -80,6 +81,7 @@ macro_rules! assert_eq { /// ``` #[macro_export] #[stable(feature = "assert_ne", since = "1.13.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "assert_ne_macro")] #[allow_internal_unstable(core_panic)] macro_rules! assert_ne { ($left:expr, $right:expr $(,)?) => ({ @@ -236,6 +238,7 @@ macro_rules! debug_assert { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "debug_assert_eq_macro")] macro_rules! debug_assert_eq { ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_eq!($($arg)*); }) } @@ -261,6 +264,7 @@ macro_rules! debug_assert_eq { /// ``` #[macro_export] #[stable(feature = "assert_ne", since = "1.13.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "debug_assert_ne_macro")] macro_rules! debug_assert_ne { ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); }) } @@ -320,6 +324,7 @@ pub macro debug_assert_matches($($arg:tt)*) { /// ``` #[macro_export] #[stable(feature = "matches_macro", since = "1.42.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "matches_macro")] macro_rules! matches { ($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { match $expression { @@ -475,6 +480,7 @@ macro_rules! r#try { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "write_macro")] macro_rules! write { ($dst:expr, $($arg:tt)*) => ($dst.write_fmt($crate::format_args!($($arg)*))) } @@ -525,6 +531,7 @@ macro_rules! write { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "writeln_macro")] #[allow_internal_unstable(format_args_nl)] macro_rules! writeln { ($dst:expr $(,)?) => ( @@ -589,6 +596,7 @@ macro_rules! writeln { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "unreachable_macro")] #[allow_internal_unstable(core_panic)] macro_rules! unreachable { () => ({ @@ -675,6 +683,7 @@ macro_rules! unreachable { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "unimplemented_macro")] #[allow_internal_unstable(core_panic)] macro_rules! unimplemented { () => ($crate::panicking::panic("not implemented")); @@ -737,6 +746,7 @@ macro_rules! unimplemented { /// ``` #[macro_export] #[stable(feature = "todo_macro", since = "1.40.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "todo_macro")] #[allow_internal_unstable(core_panic)] macro_rules! todo { () => ($crate::panicking::panic("not yet implemented")); @@ -786,6 +796,7 @@ pub(crate) mod builtin { #[stable(feature = "compile_error_macro", since = "1.20.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "compile_error_macro")] macro_rules! compile_error { ($msg:expr $(,)?) => {{ /* compiler built-in */ }}; } @@ -835,6 +846,7 @@ pub(crate) mod builtin { /// assert_eq!(s, format!("hello {}", "world")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "format_args_macro")] #[allow_internal_unsafe] #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] @@ -905,6 +917,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "env_macro")] macro_rules! env { ($name:expr $(,)?) => {{ /* compiler built-in */ }}; ($name:expr, $error_msg:expr $(,)?) => {{ /* compiler built-in */ }}; @@ -930,6 +943,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "option_env_macro")] macro_rules! option_env { ($name:expr $(,)?) => {{ /* compiler built-in */ }}; } @@ -1015,6 +1029,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "concat_macro")] macro_rules! concat { ($($e:expr),* $(,)?) => {{ /* compiler built-in */ }}; } @@ -1040,6 +1055,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "line_macro")] macro_rules! line { () => { /* compiler built-in */ @@ -1079,6 +1095,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "column_macro")] macro_rules! column { () => { /* compiler built-in */ @@ -1104,6 +1121,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "file_macro")] macro_rules! file { () => { /* compiler built-in */ @@ -1128,6 +1146,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "stringify_macro")] macro_rules! stringify { ($($t:tt)*) => { /* compiler built-in */ @@ -1169,6 +1188,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "include_str_macro")] macro_rules! include_str { ($file:expr $(,)?) => {{ /* compiler built-in */ }}; } @@ -1208,6 +1228,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "include_bytes_macro")] macro_rules! include_bytes { ($file:expr $(,)?) => {{ /* compiler built-in */ }}; } @@ -1232,6 +1253,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "module_path_macro")] macro_rules! module_path { () => { /* compiler built-in */ @@ -1265,6 +1287,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "cfg_macro")] macro_rules! cfg { ($($cfg:tt)*) => { /* compiler built-in */ @@ -1315,6 +1338,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(test), rustc_diagnostic_item = "include_macro")] macro_rules! include { ($file:expr $(,)?) => {{ /* compiler built-in */ }}; } diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 5dc75d32ec885..23cbfaeef485a 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -57,6 +57,7 @@ macro_rules! panic { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "print_macro")] #[allow_internal_unstable(print_internals)] macro_rules! print { ($($arg:tt)*) => ($crate::io::_print($crate::format_args!($($arg)*))); @@ -90,6 +91,7 @@ macro_rules! print { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "println_macro")] #[allow_internal_unstable(print_internals, format_args_nl)] macro_rules! println { () => ($crate::print!("\n")); @@ -121,6 +123,7 @@ macro_rules! println { /// ``` #[macro_export] #[stable(feature = "eprint", since = "1.19.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "eprint_macro")] #[allow_internal_unstable(print_internals)] macro_rules! eprint { ($($arg:tt)*) => ($crate::io::_eprint($crate::format_args!($($arg)*))); @@ -149,6 +152,7 @@ macro_rules! eprint { /// ``` #[macro_export] #[stable(feature = "eprint", since = "1.19.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "eprintln_macro")] #[allow_internal_unstable(print_internals, format_args_nl)] macro_rules! eprintln { () => ($crate::eprint!("\n")); @@ -282,6 +286,7 @@ macro_rules! eprintln { /// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html /// [`log`]: https://crates.io/crates/log #[macro_export] +#[cfg_attr(not(test), rustc_diagnostic_item = "dbg_macro")] #[stable(feature = "dbg_macro", since = "1.32.0")] macro_rules! dbg { // NOTE: We cannot use `concat!` to make a static string as a format argument diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 1d2f6e976800b..1be3ed757ba29 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -142,6 +142,7 @@ impl fmt::Debug for LocalKey { /// [`std::thread::LocalKey`]: crate::thread::LocalKey #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")] #[allow_internal_unstable(thread_local_internals)] macro_rules! thread_local { // empty (base case for the recursion) From 4c3e330a8c023af20beb23a3a46b5d6d77a62839 Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Fri, 7 Jan 2022 11:38:16 +0000 Subject: [PATCH 04/28] feat: pass_by_value lint attribute Useful for thin wrapper attributes that are best passed as value instead of reference. --- compiler/rustc_feature/src/builtin_attrs.rs | 5 + compiler/rustc_lint/src/internal.rs | 33 +----- compiler/rustc_lint/src/lib.rs | 6 +- compiler/rustc_lint/src/pass_by_value.rs | 103 ++++++++++++++++++ compiler/rustc_middle/src/ty/context.rs | 1 + compiler/rustc_middle/src/ty/mod.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 24 ++++ compiler/rustc_span/src/symbol.rs | 1 + ...ss_ty_by_ref.rs => rustc_pass_by_value.rs} | 2 +- ..._ref.stderr => rustc_pass_by_value.stderr} | 30 ++--- ...ef_self.rs => rustc_pass_by_value_self.rs} | 5 +- ...stderr => rustc_pass_by_value_self.stderr} | 10 +- 12 files changed, 165 insertions(+), 56 deletions(-) create mode 100644 compiler/rustc_lint/src/pass_by_value.rs rename src/test/ui-fulldeps/internal-lints/{pass_ty_by_ref.rs => rustc_pass_by_value.rs} (97%) rename src/test/ui-fulldeps/internal-lints/{pass_ty_by_ref.stderr => rustc_pass_by_value.stderr} (80%) rename src/test/ui-fulldeps/internal-lints/{pass_ty_by_ref_self.rs => rustc_pass_by_value_self.rs} (90%) rename src/test/ui-fulldeps/internal-lints/{pass_ty_by_ref_self.stderr => rustc_pass_by_value_self.stderr} (65%) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index f25b2d8f566c0..88bf81864b23f 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -623,6 +623,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, lang_items, "language items are subject to change", ), + rustc_attr!( + rustc_pass_by_value, Normal, + template!(Word, NameValueStr: "reason"), WarnFollowing, + "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." + ), BuiltinAttribute { name: sym::rustc_diagnostic_item, type_: Normal, diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index c64a67b6b9f1b..7353cd6b876b9 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -5,10 +5,7 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext} use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::{ - GenericArg, HirId, Item, ItemKind, MutTy, Mutability, Node, Path, PathSegment, QPath, Ty, - TyKind, -}; +use rustc_hir::{GenericArg, HirId, Item, ItemKind, Node, Path, PathSegment, QPath, Ty, TyKind}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; @@ -58,13 +55,6 @@ declare_tool_lint! { report_in_external_macro: true } -declare_tool_lint! { - pub rustc::TY_PASS_BY_REFERENCE, - Allow, - "passing `Ty` or `TyCtxt` by reference", - report_in_external_macro: true -} - declare_tool_lint! { pub rustc::USAGE_OF_QUALIFIED_TY, Allow, @@ -74,7 +64,6 @@ declare_tool_lint! { declare_lint_pass!(TyTyKind => [ USAGE_OF_TY_TYKIND, - TY_PASS_BY_REFERENCE, USAGE_OF_QUALIFIED_TY, ]); @@ -131,26 +120,6 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { } } } - TyKind::Rptr(_, MutTy { ty: inner_ty, mutbl: Mutability::Not }) => { - if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) { - if cx.tcx.impl_trait_ref(impl_did).is_some() { - return; - } - } - if let Some(t) = is_ty_or_ty_ctxt(cx, &inner_ty) { - cx.struct_span_lint(TY_PASS_BY_REFERENCE, ty.span, |lint| { - lint.build(&format!("passing `{}` by reference", t)) - .span_suggestion( - ty.span, - "try passing by value", - t, - // Changing type of function argument - Applicability::MaybeIncorrect, - ) - .emit(); - }) - } - } _ => {} } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c7823032b0c23..3b95a2487baed 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -56,6 +56,7 @@ mod non_ascii_idents; mod non_fmt_panic; mod nonstandard_style; mod noop_method_call; +mod pass_by_value; mod passes; mod redundant_semicolon; mod traits; @@ -85,6 +86,7 @@ use non_ascii_idents::*; use non_fmt_panic::NonPanicFmt; use nonstandard_style::*; use noop_method_call::*; +use pass_by_value::*; use redundant_semicolon::*; use traits::*; use types::*; @@ -489,6 +491,8 @@ fn register_internals(store: &mut LintStore) { store.register_late_pass(|| Box::new(ExistingDocKeyword)); store.register_lints(&TyTyKind::get_lints()); store.register_late_pass(|| Box::new(TyTyKind)); + store.register_lints(&PassByValue::get_lints()); + store.register_late_pass(|| Box::new(PassByValue)); store.register_group( false, "rustc::internal", @@ -496,8 +500,8 @@ fn register_internals(store: &mut LintStore) { vec![ LintId::of(DEFAULT_HASH_TYPES), LintId::of(USAGE_OF_TY_TYKIND), + LintId::of(PASS_BY_VALUE), LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), - LintId::of(TY_PASS_BY_REFERENCE), LintId::of(USAGE_OF_QUALIFIED_TY), LintId::of(EXISTING_DOC_KEYWORD), ], diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs new file mode 100644 index 0000000000000..0bfa2a673c2c4 --- /dev/null +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -0,0 +1,103 @@ +use crate::{LateContext, LateLintPass, LintContext}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::def_id::DefId; +use rustc_hir::{GenericArg, PathSegment, QPath, TyKind}; +use rustc_middle::ty; +use rustc_span::symbol::sym; + +declare_tool_lint! { + /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to always be passed by value. + /// This is usually used for types that are thin wrappers around references, so there is no benefit to an extra + /// layer of indirection. (Example: `Ty` which is a reference to a `TyS`) + pub rustc::PASS_BY_VALUE, + Warn, + "pass by reference of a type flagged as `#[rustc_pass_by_value]`", + report_in_external_macro: true +} + +declare_lint_pass!(PassByValue => [PASS_BY_VALUE]); + +impl<'tcx> LateLintPass<'tcx> for PassByValue { + fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) { + match &ty.kind { + TyKind::Rptr(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => { + if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) { + if cx.tcx.impl_trait_ref(impl_did).is_some() { + return; + } + } + if let Some(t) = path_for_pass_by_value(cx, &inner_ty) { + cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| { + lint.build(&format!("passing `{}` by reference", t)) + .span_suggestion( + ty.span, + "try passing by value", + t, + // Changing type of function argument + Applicability::MaybeIncorrect, + ) + .emit(); + }) + } + } + _ => {} + } + } +} + +fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option { + if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind { + match path.res { + Res::Def(_, def_id) if has_pass_by_value_attr(cx, def_id) => { + if let Some(name) = cx.tcx.get_diagnostic_name(def_id) { + return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap()))); + } + } + Res::SelfTy(None, Some((did, _))) => { + if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { + if has_pass_by_value_attr(cx, adt.did) { + if let Some(name) = cx.tcx.get_diagnostic_name(adt.did) { + return Some(format!("{}<{}>", name, substs[0])); + } + } + } + } + _ => (), + } + } + + None +} + +fn has_pass_by_value_attr(cx: &LateContext<'_>, def_id: DefId) -> bool { + for attr in cx.tcx.get_attrs(def_id).iter() { + if attr.has_name(sym::rustc_pass_by_value) { + return true; + } + } + false +} + +fn gen_args(segment: &PathSegment<'_>) -> String { + if let Some(args) = &segment.args { + let lifetimes = args + .args + .iter() + .filter_map(|arg| { + if let GenericArg::Lifetime(lt) = arg { + Some(lt.name.ident().to_string()) + } else { + None + } + }) + .collect::>(); + + if !lifetimes.is_empty() { + return format!("<{}>", lifetimes.join(", ")); + } + } + + String::new() +} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index dd571e29bf695..ab85f104ce398 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -961,6 +961,7 @@ pub struct FreeRegionInfo { /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/ty.html #[derive(Copy, Clone)] #[rustc_diagnostic_item = "TyCtxt"] +#[cfg_attr(not(bootstrap), rustc_pass_by_value)] pub struct TyCtxt<'tcx> { gcx: &'tcx GlobalCtxt<'tcx>, } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 78ccfbd5e8cdc..365d4c4aabaad 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -462,6 +462,7 @@ impl<'a, 'tcx> HashStable> for TyS<'tcx> { } #[rustc_diagnostic_item = "Ty"] +#[cfg_attr(not(bootstrap), rustc_pass_by_value)] pub type Ty<'tcx> = &'tcx TyS<'tcx>; impl ty::EarlyBoundRegion { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d7b00699491d4..2febb2e56ecf8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -114,6 +114,7 @@ impl CheckAttrVisitor<'_> { } sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target), sym::must_use => self.check_must_use(hir_id, &attr, span, target), + sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target), sym::rustc_const_unstable | sym::rustc_const_stable | sym::unstable @@ -1066,6 +1067,29 @@ impl CheckAttrVisitor<'_> { is_valid } + /// Warns against some misuses of `#[pass_by_value]` + fn check_pass_by_value(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Struct + | Target::Enum + | Target::Union + | Target::Trait + | Target::TraitAlias + | Target::TyAlias => true, + _ => { + self.tcx + .sess + .struct_span_err( + attr.span, + "`pass_by_value` attribute should be applied to a struct, enum, trait or type alias.", + ) + .span_label(*span, "is not a struct, enum, trait or type alias") + .emit(); + false + } + } + } + /// Warns against some misuses of `#[must_use]` fn check_must_use( &self, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 84cf8878af809..b1d868fbb88f6 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1143,6 +1143,7 @@ symbols! { rustc_paren_sugar, rustc_partition_codegened, rustc_partition_reused, + rustc_pass_by_value, rustc_peek, rustc_peek_definite_init, rustc_peek_liveness, 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 similarity index 97% rename from src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.rs rename to src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs index e0fdbaeac3069..783019d894513 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,7 @@ // compile-flags: -Z unstable-options #![feature(rustc_private)] -#![deny(rustc::ty_pass_by_reference)] +#![deny(rustc::pass_by_value)] #![allow(unused)] extern crate rustc_middle; diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr similarity index 80% rename from src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr rename to src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr index 2751a37f7419d..5fbde93878931 100644 --- a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr @@ -1,77 +1,77 @@ error: passing `Ty<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:13:13 + --> $DIR/rustc_pass_by_value.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 + --> $DIR/rustc_pass_by_value.rs:4:9 | -LL | #![deny(rustc::ty_pass_by_reference)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustc::pass_by_value)] + | ^^^^^^^^^^^^^^^^^^^^ error: passing `TyCtxt<'_>` by reference - --> $DIR/pass_ty_by_ref.rs:15:18 + --> $DIR/rustc_pass_by_value.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 + --> $DIR/rustc_pass_by_value.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 + --> $DIR/rustc_pass_by_value.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 + --> $DIR/rustc_pass_by_value.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 + --> $DIR/rustc_pass_by_value.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 + --> $DIR/rustc_pass_by_value.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 + --> $DIR/rustc_pass_by_value.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 + --> $DIR/rustc_pass_by_value.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 + --> $DIR/rustc_pass_by_value.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 + --> $DIR/rustc_pass_by_value.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 + --> $DIR/rustc_pass_by_value.rs:59:65 | LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` 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 similarity index 90% rename from src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs rename to src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs index 48b140d91744c..8877148bb56bd 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,11 @@ // 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 +19,12 @@ 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> { diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr similarity index 65% rename from src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr rename to src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr index 15a06e721ddcb..f86aea95aa7c6 100644 --- a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr @@ -1,17 +1,17 @@ error: passing `TyCtxt<'tcx>` by reference - --> $DIR/pass_ty_by_ref_self.rs:18:15 + --> $DIR/rustc_pass_by_value_self.rs:19: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 + --> $DIR/rustc_pass_by_value_self.rs:8:9 | -LL | #![deny(rustc::ty_pass_by_reference)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustc::pass_by_value)] + | ^^^^^^^^^^^^^^^^^^^^ error: passing `Ty<'tcx>` by reference - --> $DIR/pass_ty_by_ref_self.rs:31:21 + --> $DIR/rustc_pass_by_value_self.rs:32:21 | LL | fn by_ref(self: &Ty<'tcx>) {} | ^^^^^^^^^ help: try passing by value: `Ty<'tcx>` From 9057a6d66a9e3a1929a43460e7b0230dc6b6fbda Mon Sep 17 00:00:00 2001 From: Brennan Vincent Date: Sun, 9 Jan 2022 17:58:52 -0500 Subject: [PATCH 05/28] Clarify explicitly that BTree{Map,Set} are ordered. --- library/alloc/src/collections/btree/map.rs | 5 ++++- library/alloc/src/collections/btree/set.rs | 5 ++++- library/alloc/src/collections/mod.rs | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 199c05dc5df3e..9e4c22c3f4565 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -31,7 +31,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; // An empty map is represented either by the absence of a root node or by a // root node that is an empty leaf. -/// A map based on a [B-Tree]. +/// An ordered map based on a [B-Tree]. /// /// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing /// the amount of work performed in a search. In theory, a binary search tree (BST) is the optimal @@ -65,6 +65,9 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined /// behavior. /// +/// Entries in a `BTreeMap` are stored in ascending order according to the [`Ord`] implementation on the key. +/// Thus, iteration methods are guaranteed to produce iterators that yield items in that order. +/// /// [B-Tree]: https://en.wikipedia.org/wiki/B-tree /// [`Cell`]: core::cell::Cell /// [`RefCell`]: core::cell::RefCell diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 394c21bf51cd2..c2bf63b4a413f 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -15,7 +15,7 @@ use super::Recover; // FIXME(conventions): implement bounded iterators -/// A set based on a B-Tree. +/// An ordered set based on a B-Tree. /// /// See [`BTreeMap`]'s documentation for a detailed discussion of this collection's performance /// benefits and drawbacks. @@ -27,6 +27,9 @@ use super::Recover; /// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined /// behavior. /// +/// Entries in a `BTreeSet` are stored in ascending order according to the [`Ord`] implementation on the key. +/// Thus, iteration methods are guaranteed to produce iterators that yield items in that order. +/// /// [`Ord`]: core::cmp::Ord /// [`Cell`]: core::cell::Cell /// [`RefCell`]: core::cell::RefCell diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 1ea135a2aed82..628a5b155673c 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -14,7 +14,7 @@ pub mod vec_deque; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub mod btree_map { - //! A map based on a B-Tree. + //! An ordered map based on a B-Tree. #[stable(feature = "rust1", since = "1.0.0")] pub use super::btree::map::*; } @@ -22,7 +22,7 @@ pub mod btree_map { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub mod btree_set { - //! A set based on a B-Tree. + //! An ordered set based on a B-Tree. #[stable(feature = "rust1", since = "1.0.0")] pub use super::btree::set::*; } From ad57295fc9f5b0c747ae4f72d6208ccf03b94b0b Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 9 Jan 2022 23:53:57 -0500 Subject: [PATCH 06/28] Elaborate param_env predicates when checking if type outlives involving projection holds --- .../src/infer/outlives/obligations.rs | 4 ++- compiler/rustc_infer/src/traits/util.rs | 17 +++++++++--- .../src/traits/select/confirmation.rs | 4 ++- .../generic-associated-types/issue-92096.rs | 27 +++++++++++++++++++ .../issue-92096.stderr | 18 +++++++++++++ .../generic-associated-types/issue-92280.rs | 26 ++++++++++++++++++ 6 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/generic-associated-types/issue-92096.rs create mode 100644 src/test/ui/generic-associated-types/issue-92096.stderr create mode 100644 src/test/ui/generic-associated-types/issue-92280.rs diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 74eb263a63390..a5276afc5bfa7 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -164,7 +164,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { "cannot process registered region obligations in a snapshot" ); - debug!("process_registered_region_obligations()"); + debug!(?param_env, "process_registered_region_obligations()"); let my_region_obligations = self.take_registered_region_obligations(); @@ -356,6 +356,8 @@ where let trait_bounds: Vec<_> = self.verify_bound.projection_declared_bounds_from_trait(projection_ty).collect(); + debug!(?trait_bounds); + // Compute the bounds we can derive from the environment. This // is an "approximate" match -- in some cases, these bounds // may not apply. diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 8f5d6c85097cb..0833ebfd5f333 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -241,10 +241,19 @@ impl<'tcx> Elaborator<'tcx> { Component::UnresolvedInferenceVariable(_) => None, - Component::Projection(_) | Component::EscapingProjection(_) => { - // We can probably do more here. This - // corresponds to a case like `>::U: 'b`. + Component::Projection(projection) => { + // We might end up here if we have `Foo<::Assoc>: 'a`. + // With this, we can deduce that `::Assoc: 'a`. + let ty = + tcx.mk_projection(projection.item_def_id, projection.substs); + Some(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate( + ty, r_min, + ))) + } + + Component::EscapingProjection(_) => { + // We might be able to do more here, but we don't + // want to deal with escaping vars right now. None } }) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index b7fc578ea3bd3..d7b92c64fd7a1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -206,7 +206,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { })?); if let ty::Projection(..) = placeholder_self_ty.kind() { - for predicate in tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates { + let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates; + debug!(?predicates, "projection predicates"); + for predicate in predicates { let normalized = normalize_with_depth_to( self, obligation.param_env, 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 0000000000000..6c81babc0bccb --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-92096.rs @@ -0,0 +1,27 @@ +// edition:2018 +// check-fail +// FIXME(generic_associated_types): this should pass, but we end up +// essentially requiring that `for<'s> C: 's` + +#![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) -> impl '_ + Future + Send +//~^ ERROR the parameter +//~| 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-92096.stderr b/src/test/ui/generic-associated-types/issue-92096.stderr new file mode 100644 index 0000000000000..a897ba5b966ec --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-92096.stderr @@ -0,0 +1,18 @@ +error[E0311]: the parameter type `C` may not live long enough + --> $DIR/issue-92096.rs:18:33 + | +LL | fn call_connect(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:18:33 + | +LL | fn call_connect(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-92280.rs b/src/test/ui/generic-associated-types/issue-92280.rs new file mode 100644 index 0000000000000..db26493ecadfa --- /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 { + type Iter<'a> + where + Self: 'a; +} + +struct KeySegment_Broken { + key: T, +} +impl Iterate for KeySegment_Broken { + type Iter<'a> + where + Self: 'a, + = (); +} + +fn main() {} From 91ed6892f7ec60fb76eeaaa024919f293a58d733 Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Mon, 10 Jan 2022 08:54:42 +0000 Subject: [PATCH 07/28] rustc_pass_by_value lint: add test on custom types --- compiler/rustc_lint/src/pass_by_value.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 11 ++-- .../internal-lints/rustc_pass_by_value.rs | 40 ++++++++++++++ .../internal-lints/rustc_pass_by_value.stderr | 52 ++++++++++++++----- 4 files changed, 82 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 0bfa2a673c2c4..0847f600f9d14 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -11,6 +11,7 @@ declare_tool_lint! { /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to always be passed by value. /// This is usually used for types that are thin wrappers around references, so there is no benefit to an extra /// layer of indirection. (Example: `Ty` which is a reference to a `TyS`) + /// This lint relies on `#[rustc_diagnostic_item]` being available for the target. pub rustc::PASS_BY_VALUE, Warn, "pass by reference of a type flagged as `#[rustc_pass_by_value]`", diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2febb2e56ecf8..e700a61ce48ab 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1070,20 +1070,15 @@ impl CheckAttrVisitor<'_> { /// Warns against some misuses of `#[pass_by_value]` fn check_pass_by_value(&self, attr: &Attribute, span: &Span, target: Target) -> bool { match target { - Target::Struct - | Target::Enum - | Target::Union - | Target::Trait - | Target::TraitAlias - | Target::TyAlias => true, + Target::Struct | Target::Enum | Target::TyAlias => true, _ => { self.tcx .sess .struct_span_err( attr.span, - "`pass_by_value` attribute should be applied to a struct, enum, trait or type alias.", + "`pass_by_value` attribute should be applied to a struct, enum or type alias.", ) - .span_label(*span, "is not a struct, enum, trait or type alias") + .span_label(*span, "is not a struct, enum or type alias") .emit(); false } diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs index 783019d894513..bf2b1fbaf45fc 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs @@ -1,5 +1,6 @@ // compile-flags: -Z unstable-options +#![feature(rustc_attrs)] #![feature(rustc_private)] #![deny(rustc::pass_by_value)] #![allow(unused)] @@ -61,4 +62,43 @@ impl Foo { //~^^ ERROR passing `TyCtxt<'_>` by reference } +#[rustc_diagnostic_item = "CustomEnum"] +#[rustc_pass_by_value] +enum CustomEnum { + A, + B, +} + +impl CustomEnum { + fn test( + value: CustomEnum, + reference: &CustomEnum, //~ ERROR passing `CustomEnum` by reference + ) { + } +} + +#[rustc_diagnostic_item = "CustomStruct"] +#[rustc_pass_by_value] +struct CustomStruct { + s: u8, +} + +#[rustc_diagnostic_item = "CustomAlias"] +#[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 + ) { + } +} + 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 index 5fbde93878931..c59c1adf8997d 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr @@ -1,80 +1,104 @@ error: passing `Ty<'_>` by reference - --> $DIR/rustc_pass_by_value.rs:13:13 + --> $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:4:9 + --> $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:15:18 + --> $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:19:28 + --> $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:19:55 + --> $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:26:17 + --> $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:28:22 + --> $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:31:41 + --> $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:31:68 + --> $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:53:17 + --> $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:55:22 + --> $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:59:38 + --> $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:59:65 + --> $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: aborting due to 12 previous errors +error: passing `CustomEnum` by reference + --> $DIR/rustc_pass_by_value.rs:75:20 + | +LL | reference: &CustomEnum, + | ^^^^^^^^^^^ help: try passing by value: `CustomEnum` + +error: passing `CustomStruct` by reference + --> $DIR/rustc_pass_by_value.rs:88:24 + | +LL | type CustomAlias<'a> = &'a CustomStruct; + | ^^^^^^^^^^^^^^^^ help: try passing by value: `CustomStruct` + +error: passing `CustomStruct` by reference + --> $DIR/rustc_pass_by_value.rs:93:20 + | +LL | reference: &CustomStruct, + | ^^^^^^^^^^^^^ help: try passing by value: `CustomStruct` + +error: passing `CustomAlias<>` by reference + --> $DIR/rustc_pass_by_value.rs:99:20 + | +LL | reference: &CustomAlias, + | ^^^^^^^^^^^^ help: try passing by value: `CustomAlias<>` + +error: aborting due to 16 previous errors From 71e33146734362984258df415ac8308618968ed4 Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Mon, 10 Jan 2022 18:12:28 +0000 Subject: [PATCH 08/28] rustc_pass_by_value remove dependency on rustc_diagnostic_item --- compiler/rustc_lint/src/pass_by_value.rs | 11 ++++------- .../ui-fulldeps/internal-lints/rustc_pass_by_value.rs | 3 --- .../internal-lints/rustc_pass_by_value.stderr | 8 ++++---- .../internal-lints/rustc_pass_by_value_self.rs | 2 -- .../internal-lints/rustc_pass_by_value_self.stderr | 4 ++-- 5 files changed, 10 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 0847f600f9d14..c689f34d9e3b4 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -11,7 +11,6 @@ declare_tool_lint! { /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to always be passed by value. /// This is usually used for types that are thin wrappers around references, so there is no benefit to an extra /// layer of indirection. (Example: `Ty` which is a reference to a `TyS`) - /// This lint relies on `#[rustc_diagnostic_item]` being available for the target. pub rustc::PASS_BY_VALUE, Warn, "pass by reference of a type flagged as `#[rustc_pass_by_value]`", @@ -52,16 +51,14 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option { - if let Some(name) = cx.tcx.get_diagnostic_name(def_id) { - return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap()))); - } + let name = cx.tcx.item_name(def_id).to_ident_string(); + return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap()))); } Res::SelfTy(None, Some((did, _))) => { if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { if has_pass_by_value_attr(cx, adt.did) { - if let Some(name) = cx.tcx.get_diagnostic_name(adt.did) { - return Some(format!("{}<{}>", name, substs[0])); - } + let name = cx.tcx.item_name(adt.did).to_ident_string(); + return Some(format!("{}<{}>", name, substs[0])); } } } diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs index bf2b1fbaf45fc..293464c07ef78 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs @@ -62,7 +62,6 @@ impl Foo { //~^^ ERROR passing `TyCtxt<'_>` by reference } -#[rustc_diagnostic_item = "CustomEnum"] #[rustc_pass_by_value] enum CustomEnum { A, @@ -77,13 +76,11 @@ impl CustomEnum { } } -#[rustc_diagnostic_item = "CustomStruct"] #[rustc_pass_by_value] struct CustomStruct { s: u8, } -#[rustc_diagnostic_item = "CustomAlias"] #[rustc_pass_by_value] type CustomAlias<'a> = &'a CustomStruct; //~ ERROR passing `CustomStruct` by reference 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 index c59c1adf8997d..dbb9180ed7d2f 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr @@ -77,25 +77,25 @@ 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:75:20 + --> $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:88:24 + --> $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:93:20 + --> $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:99:20 + --> $DIR/rustc_pass_by_value.rs:96:20 | LL | reference: &CustomAlias, | ^^^^^^^^^^^^ help: try passing by value: `CustomAlias<>` diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs index 8877148bb56bd..a4529f9856368 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs @@ -8,7 +8,6 @@ #![deny(rustc::pass_by_value)] #![allow(unused)] -#[rustc_diagnostic_item = "TyCtxt"] #[rustc_pass_by_value] struct TyCtxt<'tcx> { inner: &'tcx (), @@ -23,7 +22,6 @@ struct TyS<'tcx> { inner: &'tcx (), } -#[rustc_diagnostic_item = "Ty"] #[rustc_pass_by_value] type Ty<'tcx> = &'tcx TyS<'tcx>; 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 index f86aea95aa7c6..ca47babd13d8a 100644 --- 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 @@ -1,5 +1,5 @@ error: passing `TyCtxt<'tcx>` by reference - --> $DIR/rustc_pass_by_value_self.rs:19:15 + --> $DIR/rustc_pass_by_value_self.rs:18:15 | LL | fn by_ref(&self) {} | ^^^^^ help: try passing by value: `TyCtxt<'tcx>` @@ -11,7 +11,7 @@ LL | #![deny(rustc::pass_by_value)] | ^^^^^^^^^^^^^^^^^^^^ error: passing `Ty<'tcx>` by reference - --> $DIR/rustc_pass_by_value_self.rs:32:21 + --> $DIR/rustc_pass_by_value_self.rs:30:21 | LL | fn by_ref(self: &Ty<'tcx>) {} | ^^^^^^^^^ help: try passing by value: `Ty<'tcx>` From 49553bbc98add28ed6f126225ffe6854a7ad7f29 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 6 Jan 2022 13:44:46 -0800 Subject: [PATCH 09/28] Remove hack that is no longer necessary This hack was added in 6ab1f05697c3f2df4e439a05ebcee479a9a16d80. I don't know what change allowed removing the hack, but that commit added a test (which I presume covered the hack's behavior), and all tests are passing with this change. So, I think it should be good. --- src/librustdoc/passes/collect_intra_doc_links.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 9d1a8b3f80fec..d02ef9dafe7ff 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -958,17 +958,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 From e18b23b7f494d57090be94351e92c1d69251f1a9 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 6 Jan 2022 13:59:01 -0800 Subject: [PATCH 10/28] Move two intra-doc-link tests into the `intra-doc` folder --- .../rustdoc/{intra-link-prim-self.rs => intra-doc/prim-self.rs} | 2 +- .../{intra-link-self-cache.rs => intra-doc/self-cache.rs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/test/rustdoc/{intra-link-prim-self.rs => intra-doc/prim-self.rs} (94%) rename src/test/rustdoc/{intra-link-self-cache.rs => intra-doc/self-cache.rs} (100%) diff --git a/src/test/rustdoc/intra-link-prim-self.rs b/src/test/rustdoc/intra-doc/prim-self.rs similarity index 94% rename from src/test/rustdoc/intra-link-prim-self.rs rename to src/test/rustdoc/intra-doc/prim-self.rs index 8a564acf2ca4b..dbd0a7cf0eb45 100644 --- a/src/test/rustdoc/intra-link-prim-self.rs +++ b/src/test/rustdoc/intra-doc/prim-self.rs @@ -7,7 +7,7 @@ #[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 { diff --git a/src/test/rustdoc/intra-link-self-cache.rs b/src/test/rustdoc/intra-doc/self-cache.rs similarity index 100% rename from src/test/rustdoc/intra-link-self-cache.rs rename to src/test/rustdoc/intra-doc/self-cache.rs From ca20d64fb77dc0aa5448e7bf9bcaa19164f1f521 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 6 Jan 2022 14:12:48 -0800 Subject: [PATCH 11/28] Enable ignored part of test Inherent associated types *are* supported, just unstable. --- src/test/rustdoc/intra-doc/prim-self.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/rustdoc/intra-doc/prim-self.rs b/src/test/rustdoc/intra-doc/prim-self.rs index dbd0a7cf0eb45..7a65723d77b21 100644 --- a/src/test/rustdoc/intra-doc/prim-self.rs +++ b/src/test/rustdoc/intra-doc/prim-self.rs @@ -1,7 +1,9 @@ #![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"] @@ -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")] From 977a7ca2e4b9c02d7f43a999bbeee651a31241d8 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 6 Jan 2022 14:49:28 -0800 Subject: [PATCH 12/28] Add test for disambiguator mismatch with crate This currently calls `std` a "crate" in one part of the message and a "module" in another part. The next commits fix this so it says "crate" in both places. --- .../rustdoc-ui/intra-doc/disambiguator-mismatch.rs | 5 +++++ .../intra-doc/disambiguator-mismatch.stderr | 13 ++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs index 142008cf76508..ae48db48c1833 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 module, 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 12122f5fa8674..1d48b5f7471b6 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 module, prefix with `mod@` + | +LL | /// Link to [mod@std] + | ~~~~ + +error: aborting due to 13 previous errors From 9acd8133806504f54e023151ec789c134656a1cc Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 6 Jan 2022 14:43:27 -0800 Subject: [PATCH 13/28] Use Res instead of Disambiguator for `resolved` in `report_mismatch` This allows simplifying a lot of code. It also fixes a subtle bug, exemplified by the test output changes. --- .../passes/collect_intra_doc_links.rs | 115 ++++++++---------- .../intra-doc/disambiguator-mismatch.rs | 2 +- .../intra-doc/disambiguator-mismatch.stderr | 2 +- 3 files changed, 52 insertions(+), 67 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index d02ef9dafe7ff..20e248a445cb7 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -109,6 +109,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 for Res { @@ -1267,7 +1306,7 @@ impl LinkCollector<'_, '_> { } } - let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { + let report_mismatch = |specified: Disambiguator, resolved: Res| { // 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| { @@ -1276,7 +1315,7 @@ impl LinkCollector<'_, '_> { resolved.article(), resolved.descr(), specified.article(), - specified.descr() + specified.descr(), ); if let Some(sp) = sp { diag.span_label(sp, ¬e); @@ -1311,7 +1350,7 @@ impl LinkCollector<'_, '_> { => {} (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { - report_mismatch(specified, Disambiguator::Kind(kind)); + report_mismatch(specified, Res::Def(kind, id)); return None; } } @@ -1362,7 +1401,7 @@ impl LinkCollector<'_, '_> { match disambiguator { Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {} Some(other) => { - report_mismatch(other, Disambiguator::Primitive); + report_mismatch(other, res); return None; } } @@ -1676,53 +1715,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, @@ -2070,15 +2062,9 @@ 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, - ) + // FIXME: does this need to be behind an `if`? + if matches!(res, Res::Def(..)) { + suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp); } format!( @@ -2214,8 +2200,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); } }); } @@ -2223,14 +2208,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, ) { - 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 ae48db48c1833..2d66566119bc3 100644 --- a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs +++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs @@ -77,5 +77,5 @@ trait T {} /// Link to [fn@std] //~^ ERROR unresolved link to `std` //~| NOTE this link resolves to the crate `std` -//~| HELP to link to the module, prefix with `mod@` +//~| 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 1d48b5f7471b6..ad9102c506f7f 100644 --- a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr +++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr @@ -144,7 +144,7 @@ error: unresolved link to `std` LL | /// Link to [fn@std] | ^^^^^^ this link resolves to the crate `std`, which is not in the value namespace | -help: to link to the module, prefix with `mod@` +help: to link to the crate, prefix with `mod@` | LL | /// Link to [mod@std] | ~~~~ From 591ec49df312ec4cbcdec0f082f123f473c182a9 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 6 Jan 2022 14:45:23 -0800 Subject: [PATCH 14/28] Remove unnecessary conditional for suggesting disambiguator Now that `res` is used directly, it seems the conditional is unnecessary. --- src/librustdoc/passes/collect_intra_doc_links.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 20e248a445cb7..dd2fa9d627360 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -2062,10 +2062,7 @@ fn resolution_failure( ResolutionFailure::NotResolved { .. } => unreachable!("handled above"), ResolutionFailure::Dummy => continue, ResolutionFailure::WrongNamespace { res, expected_ns } => { - // FIXME: does this need to be behind an `if`? - if matches!(res, Res::Def(..)) { - suggest_disambiguator(res, 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", From a5f09f74d6dc0f52fd2c73fca0a9e5bb99eb756c Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 6 Jan 2022 15:06:35 -0800 Subject: [PATCH 15/28] Update comment and make code clearer I'm still not sure why this hack works so seemingly well. --- src/librustdoc/passes/collect_intra_doc_links.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index dd2fa9d627360..13e1992a31caa 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; @@ -1736,9 +1735,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", } } From 895fa9cd5c79b5c30614852c4c74a963b3ec458a Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 6 Jan 2022 15:22:22 -0800 Subject: [PATCH 16/28] Extract functions for two closures These closures were quite complex and part of a quite complex function. The fact that they are closures makes mistakes likely when refactoring. For example, earlier, I meant to use `resolved`, an argument of the closure, but I instead typed `res`, which captured a local variable and caused a subtle bug that led to a confusing test failure. Extracting them as functions makes the code easier to understand and refactor. --- .../passes/collect_intra_doc_links.rs | 180 +++++++++++------- 1 file changed, 107 insertions(+), 73 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 13e1992a31caa..13b1d5b65a58a 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1305,79 +1305,9 @@ impl LinkCollector<'_, '_> { } } - let report_mismatch = |specified: Disambiguator, resolved: Res| { - // 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| { - 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, Res::Def(kind, id)); - 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, @@ -1386,7 +1316,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. @@ -1400,7 +1339,9 @@ impl LinkCollector<'_, '_> { match disambiguator { Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {} Some(other) => { - report_mismatch(other, res); + self.report_disambiguator_mismatch( + path_str, &ori_link, other, res, &diag_info, + ); return None; } } @@ -1414,13 +1355,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, + 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| { + 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) From 28d2353f3b1150313921916ae37a8525e9c2838d Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 6 Jan 2022 15:57:51 -0800 Subject: [PATCH 17/28] Update some comments post the side channel removal --- src/librustdoc/passes/collect_intra_doc_links.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 13b1d5b65a58a..adeafc0d7589c 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -705,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, @@ -1475,7 +1473,6 @@ impl LinkCollector<'_, '_> { diag: DiagnosticInfo<'_>, cache_resolution_failure: bool, ) -> Option<(Res, Option)> { - // 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) => { From a6762e962e50d5b6f864e33ebb27878e90651f22 Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Tue, 11 Jan 2022 09:28:13 +0000 Subject: [PATCH 18/28] rustc_pass_by_value: allow types with no parameters on self includes minor refactorings --- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_lint/src/pass_by_value.rs | 18 +++++------------- .../internal-lints/rustc_pass_by_value_self.rs | 7 +++++++ .../rustc_pass_by_value_self.stderr | 8 +++++++- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 88bf81864b23f..46817bc9c3f08 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -625,7 +625,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!( rustc_pass_by_value, Normal, - template!(Word, NameValueStr: "reason"), WarnFollowing, + template!(Word), WarnFollowing, "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." ), BuiltinAttribute { diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index c689f34d9e3b4..00b023c26f3f3 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -2,7 +2,6 @@ use crate::{LateContext, LateLintPass, LintContext}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::def_id::DefId; use rustc_hir::{GenericArg, PathSegment, QPath, TyKind}; use rustc_middle::ty; use rustc_span::symbol::sym; @@ -50,15 +49,17 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue { fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option { if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind { match path.res { - Res::Def(_, def_id) if has_pass_by_value_attr(cx, def_id) => { + Res::Def(_, def_id) if cx.tcx.has_attr(def_id, sym::rustc_pass_by_value) => { let name = cx.tcx.item_name(def_id).to_ident_string(); return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap()))); } Res::SelfTy(None, Some((did, _))) => { if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { - if has_pass_by_value_attr(cx, adt.did) { + if cx.tcx.has_attr(adt.did, sym::rustc_pass_by_value) { let name = cx.tcx.item_name(adt.did).to_ident_string(); - return Some(format!("{}<{}>", name, substs[0])); + let param = + substs.first().map(|s| format!("<{}>", s)).unwrap_or("".to_string()); + return Some(format!("{}{}", name, param)); } } } @@ -69,15 +70,6 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option, def_id: DefId) -> bool { - for attr in cx.tcx.get_attrs(def_id).iter() { - if attr.has_name(sym::rustc_pass_by_value) { - return true; - } - } - false -} - fn gen_args(segment: &PathSegment<'_>) -> String { if let Some(args) = &segment.args { let lifetimes = args diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs index a4529f9856368..1be01e21bd5f1 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs @@ -30,4 +30,11 @@ 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 +} + 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 index ca47babd13d8a..965e79d962cdf 100644 --- 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 @@ -16,5 +16,11 @@ error: passing `Ty<'tcx>` by reference LL | fn by_ref(self: &Ty<'tcx>) {} | ^^^^^^^^^ help: try passing by value: `Ty<'tcx>` -error: aborting due to 2 previous errors +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: aborting due to 3 previous errors From 65d47347ada25ddb45358ec7af07f378f60aa00d Mon Sep 17 00:00:00 2001 From: Brennan Vincent Date: Tue, 11 Jan 2022 12:08:46 -0700 Subject: [PATCH 19/28] Address review comments --- library/alloc/src/collections/btree/map.rs | 4 ++-- library/alloc/src/collections/btree/set.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 9e4c22c3f4565..b38c5848b4907 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -65,8 +65,8 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined /// behavior. /// -/// Entries in a `BTreeMap` are stored in ascending order according to the [`Ord`] implementation on the key. -/// Thus, iteration methods are guaranteed to produce iterators that yield items in that order. +/// Iterators yielded by functions such as [`BTreeMap::iter`], [`BTreeMap::values`], or [`BTreeMap::keys`] +/// yield their items in order by key, and take worst-case logarithmic and amortized constant time per item yielded. /// /// [B-Tree]: https://en.wikipedia.org/wiki/B-tree /// [`Cell`]: core::cell::Cell diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index c2bf63b4a413f..b32f539958861 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -27,8 +27,8 @@ use super::Recover; /// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined /// behavior. /// -/// Entries in a `BTreeSet` are stored in ascending order according to the [`Ord`] implementation on the key. -/// Thus, iteration methods are guaranteed to produce iterators that yield items in that order. +/// Iterators returned by [`BTreeSet::iter`] yield their items in order, +/// and take worst-case logarithmic and amortized constant time per item yielded. /// /// [`Ord`]: core::cmp::Ord /// [`Cell`]: core::cell::Cell From 959bf2bc2e79defd0fe7d3c9987a6023eb8503cd Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Tue, 11 Jan 2022 19:59:06 +0000 Subject: [PATCH 20/28] rustc_pass_by_value: handle generic and const type parameters --- compiler/rustc_lint/src/pass_by_value.rs | 33 +++++++++++-------- .../internal-lints/rustc_pass_by_value.rs | 15 +++++++++ .../internal-lints/rustc_pass_by_value.stderr | 14 +++++++- .../rustc_pass_by_value_self.rs | 14 ++++++++ .../rustc_pass_by_value_self.stderr | 14 +++++++- 5 files changed, 74 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 00b023c26f3f3..3435a5a6c82db 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -51,15 +51,13 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option { let name = cx.tcx.item_name(def_id).to_ident_string(); - return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap()))); + let path_segment = path.segments.last().unwrap(); + return Some(format!("{}{}", name, gen_args(cx, path_segment))); } Res::SelfTy(None, Some((did, _))) => { if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { if cx.tcx.has_attr(adt.did, sym::rustc_pass_by_value) { - let name = cx.tcx.item_name(adt.did).to_ident_string(); - let param = - substs.first().map(|s| format!("<{}>", s)).unwrap_or("".to_string()); - return Some(format!("{}{}", name, param)); + return Some(cx.tcx.def_path_str_with_substs(adt.did, substs)); } } } @@ -70,22 +68,29 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option) -> String { +fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String { if let Some(args) = &segment.args { - let lifetimes = args + let params = args .args .iter() - .filter_map(|arg| { - if let GenericArg::Lifetime(lt) = arg { - Some(lt.name.ident().to_string()) - } else { - None + .filter_map(|arg| match arg { + GenericArg::Lifetime(lt) => Some(lt.name.ident().to_string()), + GenericArg::Type(ty) => { + let snippet = + cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_default(); + Some(snippet) } + GenericArg::Const(c) => { + let snippet = + cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_default(); + Some(snippet) + } + _ => None, }) .collect::>(); - if !lifetimes.is_empty() { - return format!("<{}>", lifetimes.join(", ")); + if !params.is_empty() { + return format!("<{}>", params.join(", ")); } } diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs index 293464c07ef78..f8ab0f056d79f 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs @@ -98,4 +98,19 @@ impl CustomStruct { } } +#[rustc_pass_by_value] +struct WithParameters { + slice: [T; N], + m: M, +} + +impl WithParameters { + fn test( + value: WithParameters, + reference: &WithParameters, //~ ERROR passing `WithParameters` by reference + reference_with_m: &WithParameters, //~ ERROR passing `WithParameters` 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 index dbb9180ed7d2f..c5307f0f67d9b 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr @@ -100,5 +100,17 @@ error: passing `CustomAlias<>` by reference LL | reference: &CustomAlias, | ^^^^^^^^^^^^ help: try passing by value: `CustomAlias<>` -error: aborting due to 16 previous errors +error: passing `WithParameters` by reference + --> $DIR/rustc_pass_by_value.rs:110:20 + | +LL | reference: &WithParameters, + | ^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters` + +error: passing `WithParameters` by reference + --> $DIR/rustc_pass_by_value.rs:111:27 + | +LL | reference_with_m: &WithParameters, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters` + +error: aborting due to 18 previous errors diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs index 1be01e21bd5f1..2868517774d46 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs @@ -37,4 +37,18 @@ impl Foo { fn with_ref(&self) {} //~ ERROR passing `Foo` by reference } +#[rustc_pass_by_value] +struct WithParameters { + slice: [T; N], + m: M, +} + +impl WithParameters { + fn with_ref(&self) {} //~ ERROR passing `WithParameters` by reference +} + +impl WithParameters { + fn with_ref(&self) {} //~ ERROR passing `WithParameters` 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 index 965e79d962cdf..54a7cf7cab757 100644 --- 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 @@ -22,5 +22,17 @@ error: passing `Foo` by reference LL | fn with_ref(&self) {} | ^^^^^ help: try passing by value: `Foo` -error: aborting due to 3 previous errors +error: passing `WithParameters` by reference + --> $DIR/rustc_pass_by_value_self.rs:47:17 + | +LL | fn with_ref(&self) {} + | ^^^^^ help: try passing by value: `WithParameters` + +error: passing `WithParameters` by reference + --> $DIR/rustc_pass_by_value_self.rs:51:17 + | +LL | fn with_ref(&self) {} + | ^^^^^ help: try passing by value: `WithParameters` + +error: aborting due to 5 previous errors From 2728af7bc02ab48bf4dd861cb69b5b786ecb261d Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Tue, 11 Jan 2022 21:28:04 +0000 Subject: [PATCH 21/28] rustc_pass_by_value: handle inferred generic types (with _) --- compiler/rustc_lint/src/pass_by_value.rs | 14 +++++--------- .../internal-lints/rustc_pass_by_value.rs | 8 +++++--- .../internal-lints/rustc_pass_by_value.stderr | 18 +++++++++++++++--- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 3435a5a6c82db..26d0560bf89bb 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -73,19 +73,15 @@ fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String { let params = args .args .iter() - .filter_map(|arg| match arg { - GenericArg::Lifetime(lt) => Some(lt.name.ident().to_string()), + .map(|arg| match arg { + GenericArg::Lifetime(lt) => lt.name.ident().to_string(), GenericArg::Type(ty) => { - let snippet = - cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_default(); - Some(snippet) + cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_default() } GenericArg::Const(c) => { - let snippet = - cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_default(); - Some(snippet) + cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_default() } - _ => None, + GenericArg::Infer(_) => String::from("_"), }) .collect::>(); diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs index f8ab0f056d79f..402c41f376602 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs @@ -105,11 +105,13 @@ struct WithParameters { } impl WithParameters { - fn test( + fn test<'a>( value: WithParameters, - reference: &WithParameters, //~ ERROR passing `WithParameters` by reference + reference: &'a WithParameters, //~ ERROR passing `WithParameters` by reference reference_with_m: &WithParameters, //~ ERROR passing `WithParameters` by reference - ) { + ) -> &'a WithParameters { + //~^ ERROR passing `WithParameters` by reference + reference as &WithParameters<_, 1> //~ ERROR passing `WithParameters<_, 1>` by reference } } 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 index c5307f0f67d9b..7f6e57b38f38d 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr @@ -103,8 +103,8 @@ LL | reference: &CustomAlias, error: passing `WithParameters` by reference --> $DIR/rustc_pass_by_value.rs:110:20 | -LL | reference: &WithParameters, - | ^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters` +LL | reference: &'a WithParameters, + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters` error: passing `WithParameters` by reference --> $DIR/rustc_pass_by_value.rs:111:27 @@ -112,5 +112,17 @@ error: passing `WithParameters` by reference LL | reference_with_m: &WithParameters, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters` -error: aborting due to 18 previous errors +error: passing `WithParameters` by reference + --> $DIR/rustc_pass_by_value.rs:112:10 + | +LL | ) -> &'a WithParameters { + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters` + +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 From 962582981feca4a17dbe1fe560c924d9d4c664a0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 12 Jan 2022 16:09:01 +0100 Subject: [PATCH 22/28] remove unused FIXME --- compiler/rustc_index/src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 359b1859c6889..7919e40925392 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -9,7 +9,3 @@ pub mod bit_set; pub mod interval; pub mod vec; - -// FIXME(#56935): Work around ICEs during cross-compilation. -#[allow(unused)] -extern crate rustc_macros; From 9ff8ae097e88937a4aa6cf62d73471e479bac1df Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Tue, 11 Jan 2022 22:20:01 +0000 Subject: [PATCH 23/28] rustdoc: fix intra-link for generic trait impls --- .../passes/collect_intra_doc_links.rs | 13 ++++++++++++- .../rustdoc/intra-doc/generic-trait-impl.rs | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc/intra-doc/generic-trait-impl.rs diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 9d1a8b3f80fec..0bc10404dc0f0 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -903,7 +903,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 (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 } }) 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 0000000000000..c3d3f8b386607 --- /dev/null +++ b/src/test/rustdoc/intra-doc/generic-trait-impl.rs @@ -0,0 +1,19 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +// Test intra-doc links on trait implementations with generics + +use std::marker::PhantomData; + +pub trait Bar { + fn bar(&self); +} + +pub struct Foo(PhantomData); + +impl Bar for Foo { + 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() {} From ae20500d76e36b5e8692af499830c4707f713bc0 Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Thu, 13 Jan 2022 08:10:08 +0000 Subject: [PATCH 24/28] rustdoc: add intra-doc trait impl test for extern types --- src/test/rustdoc/intra-doc/extern-type.rs | 24 +++++++++++++++++-- .../rustdoc/intra-doc/generic-trait-impl.rs | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc/intra-doc/extern-type.rs b/src/test/rustdoc/intra-doc/extern-type.rs index f37ae62dde1aa..ab088ab789d43 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 { + fn g(&self, n: N) {} +} + impl ExternType { - pub fn f(&self) { + pub fn f(&self) {} +} - } +impl T for ExternType { + fn test(&self) {} +} + +impl G 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 index c3d3f8b386607..ba8595abfa959 100644 --- a/src/test/rustdoc/intra-doc/generic-trait-impl.rs +++ b/src/test/rustdoc/intra-doc/generic-trait-impl.rs @@ -1,6 +1,7 @@ #![deny(rustdoc::broken_intra_doc_links)] // Test intra-doc links on trait implementations with generics +// regression test for issue #92662 use std::marker::PhantomData; From cfc0bd12581651e5d0f51d0d4c2d8306cc13cb51 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 10 Jan 2022 22:02:19 +0000 Subject: [PATCH 25/28] Parse `Ty?` as `Option` and provide structured suggestion Swift has specific syntax that desugars to `Option` similar to our `?` operator, which means that people might try to use it in Rust. Parse it and gracefully recover. --- .../rustc_parse/src/parser/diagnostics.rs | 30 ++++++++++++++++++- compiler/rustc_parse/src/parser/expr.rs | 4 +-- compiler/rustc_parse/src/parser/ty.rs | 26 ++++++++++++++++ .../issues/issue-35813-postfix-after-cast.rs | 4 +-- .../issue-35813-postfix-after-cast.stderr | 4 +-- src/test/ui/parser/issues/issue-84148-1.rs | 5 ++-- .../ui/parser/issues/issue-84148-1.stderr | 18 +++++------ src/test/ui/parser/issues/issue-84148-2.rs | 3 +- .../ui/parser/issues/issue-84148-2.stderr | 24 +++++++-------- .../ui/parser/trailing-question-in-type.fixed | 10 +++++++ .../ui/parser/trailing-question-in-type.rs | 10 +++++++ .../parser/trailing-question-in-type.stderr | 24 +++++++++++++++ 12 files changed, 125 insertions(+), 37 deletions(-) create mode 100644 src/test/ui/parser/trailing-question-in-type.fixed create mode 100644 src/test/ui/parser/trailing-question-in-type.rs create mode 100644 src/test/ui/parser/trailing-question-in-type.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 9677e7642b88c..b844e96d39c54 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1,5 +1,5 @@ use super::pat::Expected; -use super::ty::AllowPlus; +use super::ty::{AllowPlus, IsAsCast}; use super::{ BlockMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, SemiColonMode, SeqSep, TokenExpectType, TokenType, @@ -1032,6 +1032,34 @@ impl<'a> Parser<'a> { } } + /// Swift lets users write `Ty?` to mean `Option`. Parse the construct and recover from it. + pub(super) fn maybe_recover_from_question_mark( + &mut self, + ty: P, + is_as_cast: IsAsCast, + ) -> P { + if let IsAsCast::Yes = is_as_cast { + return ty; + } + if self.token == token::Question { + self.bump(); + self.struct_span_err(self.prev_token.span, "invalid `?` in type") + .span_label(self.prev_token.span, "`?` is only allowed on expressions, not types") + .multipart_suggestion( + "if you meant to express that the type might not contain a value, use the `Option` wrapper type", + vec![ + (ty.span.shrink_to_lo(), "Option<".to_string()), + (self.prev_token.span, ">".to_string()), + ], + Applicability::MachineApplicable, + ) + .emit(); + self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err) + } else { + ty + } + } + pub(super) fn maybe_recover_from_bad_type_plus( &mut self, allow_plus: AllowPlus, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f706a98a4fcfa..cd3846d5a224e 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -682,7 +682,7 @@ impl<'a> Parser<'a> { // Save the state of the parser before parsing type normally, in case there is a // LessThan comparison after this cast. let parser_snapshot_before_type = self.clone(); - let cast_expr = match self.parse_ty_no_plus() { + let cast_expr = match self.parse_as_cast_ty() { Ok(rhs) => mk_expr(self, lhs, rhs), Err(mut type_err) => { // Rewind to before attempting to parse the type with generics, to recover @@ -808,7 +808,7 @@ impl<'a> Parser<'a> { "casts cannot be followed by {}", match with_postfix.kind { ExprKind::Index(_, _) => "indexing", - ExprKind::Try(_) => "?", + ExprKind::Try(_) => "`?`", ExprKind::Field(_, _) => "a field access", ExprKind::MethodCall(_, _, _) => "a method call", ExprKind::Call(_, _) => "a function call", diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 02a774ba1291c..566b77a5e9e55 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -44,6 +44,11 @@ pub(super) enum RecoverQPath { No, } +pub(super) enum IsAsCast { + Yes, + No, +} + /// Signals whether parsing a type should recover `->`. /// /// More specifically, when parsing a function like: @@ -100,6 +105,7 @@ impl<'a> Parser<'a> { RecoverQPath::Yes, RecoverReturnSign::Yes, None, + IsAsCast::No, ) } @@ -113,6 +119,7 @@ impl<'a> Parser<'a> { RecoverQPath::Yes, RecoverReturnSign::Yes, Some(ty_params), + IsAsCast::No, ) } @@ -126,6 +133,7 @@ impl<'a> Parser<'a> { RecoverQPath::Yes, RecoverReturnSign::Yes, None, + IsAsCast::No, ) } @@ -142,9 +150,22 @@ impl<'a> Parser<'a> { RecoverQPath::Yes, RecoverReturnSign::Yes, None, + IsAsCast::No, ) } + /// Parses a type following an `as` cast. Similar to `parse_ty_no_plus`, but signaling origin + /// for better diagnostics involving `?`. + pub(super) fn parse_as_cast_ty(&mut self) -> PResult<'a, P> { + self.parse_ty_common( + AllowPlus::No, + AllowCVariadic::No, + RecoverQPath::Yes, + RecoverReturnSign::Yes, + None, + IsAsCast::Yes, + ) + } /// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>` pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P> { self.parse_ty_common( @@ -153,6 +174,7 @@ impl<'a> Parser<'a> { RecoverQPath::Yes, RecoverReturnSign::OnlyFatArrow, None, + IsAsCast::No, ) } @@ -171,6 +193,7 @@ impl<'a> Parser<'a> { recover_qpath, recover_return_sign, None, + IsAsCast::No, )?; FnRetTy::Ty(ty) } else if recover_return_sign.can_recover(&self.token.kind) { @@ -191,6 +214,7 @@ impl<'a> Parser<'a> { recover_qpath, recover_return_sign, None, + IsAsCast::No, )?; FnRetTy::Ty(ty) } else { @@ -205,6 +229,7 @@ impl<'a> Parser<'a> { recover_qpath: RecoverQPath, recover_return_sign: RecoverReturnSign, ty_generics: Option<&Generics>, + is_as_cast: IsAsCast, ) -> PResult<'a, P> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); @@ -280,6 +305,7 @@ impl<'a> Parser<'a> { // Try to recover from use of `+` with incorrect priority. self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty); self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; + let ty = self.maybe_recover_from_question_mark(ty, is_as_cast); self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery) } 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 e725aa5d73d1f..23f245a51681b 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 { Err(0u64) as Result?; - //~^ ERROR: casts cannot be followed by ? + //~^ ERROR: casts cannot be followed by `?` Err(0u64): Result?; - //~^ 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 19b68556d79ad..e96b67da3364d 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?; @@ -276,7 +276,7 @@ help: try surrounding the expression in parentheses LL | (Err(0u64) as Result)?; | + + -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?; diff --git a/src/test/ui/parser/issues/issue-84148-1.rs b/src/test/ui/parser/issues/issue-84148-1.rs index 25f7ba4d1f88e..9fa8086c2c9bf 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 77f0896e9c155..9261067c22158 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:Optiont>) + | +++++++ ~ error: expected one of `->`, `where`, or `{`, found `` --> $DIR/issue-84148-1.rs:1:15 @@ -19,5 +15,5 @@ error: expected one of `->`, `where`, or `{`, found `` 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 257a3fd67207e..2f6a7facfb271 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 396208316df67..71d543f9b7344 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:Optiont> + | +++++++ ~ error: expected one of `->`, `where`, or `{`, found `` - --> $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 0000000000000..6ea24484e033e --- /dev/null +++ b/src/test/ui/parser/trailing-question-in-type.fixed @@ -0,0 +1,10 @@ +// run-rustfix + +fn foo() -> Option { //~ ERROR invalid `?` in type + let x: Option = Some(1); //~ ERROR invalid `?` in type + x +} + +fn main() { + let _: Option = 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 0000000000000..b1c508365cff5 --- /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 = 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 0000000000000..a3cd419c0c718 --- /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 { + | +++++++ ~ + +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 = Some(1); + | +++++++ ~ + +error: aborting due to 2 previous errors + From 554c7659e8106ee3390ba9bbcc8b44950bda309d Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 15 Jan 2022 10:18:24 -0800 Subject: [PATCH 26/28] Fix broken link --- src/librustdoc/passes/collect_intra_doc_links.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index adeafc0d7589c..8597940b34e86 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -384,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, From ad6408dd7a786db603c2ed323894feb7110e8dea Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 15 Jan 2022 19:28:19 -0800 Subject: [PATCH 27/28] Tweak btree iterator wording to not use 'yield' Yield means something else in the context of generators, which are sufficiently close to iterators that it's better to avoid the terminology collision here. --- library/alloc/src/collections/btree/map.rs | 5 +++-- library/alloc/src/collections/btree/set.rs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index b38c5848b4907..885632c69a8cc 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -65,8 +65,9 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined /// behavior. /// -/// Iterators yielded by functions such as [`BTreeMap::iter`], [`BTreeMap::values`], or [`BTreeMap::keys`] -/// yield their items in order by key, and take worst-case logarithmic and amortized constant time per item yielded. +/// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::values`], or +/// [`BTreeMap::keys`] produce their items in order by key, and take worst-case logarithmic and +/// amortized constant time per item returned. /// /// [B-Tree]: https://en.wikipedia.org/wiki/B-tree /// [`Cell`]: core::cell::Cell diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index b32f539958861..31df4e98ed746 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -27,8 +27,8 @@ use super::Recover; /// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined /// behavior. /// -/// Iterators returned by [`BTreeSet::iter`] yield their items in order, -/// and take worst-case logarithmic and amortized constant time per item yielded. +/// Iterators returned by [`BTreeSet::iter`] produce their items in order, and take worst-case +/// logarithmic and amortized constant time per item returned. /// /// [`Ord`]: core::cmp::Ord /// [`Cell`]: core::cell::Cell From ea562aeed553eaee9961a2adb259f48ffbe83666 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sat, 15 Jan 2022 23:17:32 -0500 Subject: [PATCH 28/28] Add nll revision for issue-92096 test that passes --- ...issue-92096.stderr => issue-92096.migrate.stderr} | 4 ++-- src/test/ui/generic-associated-types/issue-92096.rs | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) rename src/test/ui/generic-associated-types/{issue-92096.stderr => issue-92096.migrate.stderr} (92%) diff --git a/src/test/ui/generic-associated-types/issue-92096.stderr b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr similarity index 92% rename from src/test/ui/generic-associated-types/issue-92096.stderr rename to src/test/ui/generic-associated-types/issue-92096.migrate.stderr index a897ba5b966ec..72ade5774d749 100644 --- a/src/test/ui/generic-associated-types/issue-92096.stderr +++ b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr @@ -1,5 +1,5 @@ error[E0311]: the parameter type `C` may not live long enough - --> $DIR/issue-92096.rs:18:33 + --> $DIR/issue-92096.rs:20:33 | LL | fn call_connect(c: &'_ C) -> impl '_ + Future + Send | - ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds @@ -7,7 +7,7 @@ LL | fn call_connect(c: &'_ C) -> impl '_ + Future + Send | help: consider adding an explicit lifetime bound...: `C: 'a` error[E0311]: the parameter type `C` may not live long enough - --> $DIR/issue-92096.rs:18:33 + --> $DIR/issue-92096.rs:20:33 | LL | fn call_connect(c: &'_ C) -> impl '_ + Future + Send | - ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds diff --git a/src/test/ui/generic-associated-types/issue-92096.rs b/src/test/ui/generic-associated-types/issue-92096.rs index 6c81babc0bccb..066132a5d98bb 100644 --- a/src/test/ui/generic-associated-types/issue-92096.rs +++ b/src/test/ui/generic-associated-types/issue-92096.rs @@ -1,8 +1,10 @@ // edition:2018 -// check-fail -// FIXME(generic_associated_types): this should pass, but we end up -// essentially requiring that `for<'s> C: 's` +// [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; @@ -16,8 +18,8 @@ trait Client { } fn call_connect(c: &'_ C) -> impl '_ + Future + Send -//~^ ERROR the parameter -//~| ERROR the parameter +//[migrate]~^ ERROR the parameter +//[migrate]~| ERROR the parameter where C: Client + Send + Sync, {