Auto merge of #92970 - matthiaskrgr:rollup-tcx7cfb, r=matthiaskrgr

Rollup of 10 pull requests

Successful merges:

 - #92487 (Fix unclosed boxes in pretty printing of TraitAlias)
 - #92581 (ARMv6K Horizon - Enable default libraries)
 - #92619 (Add diagnostic items for macros)
 - #92635 (rustdoc: Yet more intra-doc links cleanup)
 - #92646 (feat: rustc_pass_by_value lint attribute)
 - #92706 (Clarify explicitly that BTree{Map,Set} are ordered.)
 - #92710 (Include Projections when elaborating TypeOutlives)
 - #92746 (Parse `Ty?` as `Option<Ty>` and provide structured suggestion)
 - #92792 (rustdoc: fix intra-link for generic trait impls)
 - #92814 (remove unused FIXME)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-01-16 17:22:57 +00:00
commit bd3cb52565
51 changed files with 907 additions and 363 deletions

View file

@ -1357,9 +1357,7 @@ fn print_associated_type(
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());
@ -1377,6 +1375,8 @@ fn print_associated_type(
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);

View file

@ -623,6 +623,11 @@ pub struct BuiltinAttribute {
lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, lang_items,
"language items are subject to change",
),
rustc_attr!(
rustc_pass_by_value, Normal,
template!(Word), 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,

View file

@ -705,9 +705,7 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
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 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
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))

View file

@ -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;

View file

@ -164,7 +164,7 @@ pub fn process_registered_region_obligations(
"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 @@ fn projection_must_outlive(
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.

View file

@ -241,10 +241,19 @@ fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
Component::UnresolvedInferenceVariable(_) => None,
Component::Projection(_) | Component::EscapingProjection(_) => {
// We can probably do more here. This
// corresponds to a case like `<T as
// Foo<'a>>::U: 'b`.
Component::Projection(projection) => {
// We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
// With this, we can deduce that `<Bar as Baz>::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
}
})

View file

@ -5,10 +5,7 @@
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 @@ fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
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 @@ fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
declare_lint_pass!(TyTyKind => [
USAGE_OF_TY_TYKIND,
TY_PASS_BY_REFERENCE,
USAGE_OF_QUALIFIED_TY,
]);
@ -131,26 +120,6 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
}
}
}
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();
})
}
}
_ => {}
}
}

View file

@ -56,6 +56,7 @@
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_fmt_panic::NonPanicFmt;
use nonstandard_style::*;
use noop_method_call::*;
use pass_by_value::*;
use redundant_semicolon::*;
use traits::*;
use types::*;
@ -490,6 +492,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",
@ -497,8 +501,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),
],

View file

@ -0,0 +1,94 @@
use crate::{LateContext, LateLintPass, LintContext};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::Res;
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<String> {
if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
match path.res {
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();
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) {
return Some(cx.tcx.def_path_str_with_substs(adt.did, substs));
}
}
}
_ => (),
}
}
None
}
fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String {
if let Some(args) = &segment.args {
let params = args
.args
.iter()
.map(|arg| match arg {
GenericArg::Lifetime(lt) => lt.name.ident().to_string(),
GenericArg::Type(ty) => {
cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_default()
}
GenericArg::Const(c) => {
cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_default()
}
GenericArg::Infer(_) => String::from("_"),
})
.collect::<Vec<_>>();
if !params.is_empty() {
return format!("<{}>", params.join(", "));
}
}
String::new()
}

View file

@ -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>,
}

View file

@ -464,6 +464,7 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
}
#[rustc_diagnostic_item = "Ty"]
#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
pub type Ty<'tcx> = &'tcx TyS<'tcx>;
impl ty::EarlyBoundRegion {

View file

@ -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 @@ pub(super) fn maybe_report_ambiguous_plus(
}
}
/// Swift lets users write `Ty?` to mean `Option<Ty>`. Parse the construct and recover from it.
pub(super) fn maybe_recover_from_question_mark(
&mut self,
ty: P<Ty>,
is_as_cast: IsAsCast,
) -> P<Ty> {
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,

View file

@ -682,7 +682,7 @@ fn parse_assoc_op_cast(
// 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 @@ fn parse_and_disallow_postfix_after_cast(
"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",

View file

@ -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 @@ pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
RecoverQPath::Yes,
RecoverReturnSign::Yes,
None,
IsAsCast::No,
)
}
@ -113,6 +119,7 @@ pub(super) fn parse_ty_with_generics_recovery(
RecoverQPath::Yes,
RecoverReturnSign::Yes,
Some(ty_params),
IsAsCast::No,
)
}
@ -126,6 +133,7 @@ pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> {
RecoverQPath::Yes,
RecoverReturnSign::Yes,
None,
IsAsCast::No,
)
}
@ -142,9 +150,22 @@ pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
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<Ty>> {
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<Ty>> {
self.parse_ty_common(
@ -153,6 +174,7 @@ pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
RecoverQPath::Yes,
RecoverReturnSign::OnlyFatArrow,
None,
IsAsCast::No,
)
}
@ -171,6 +193,7 @@ pub(super) fn parse_ret_ty(
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 @@ pub(super) fn parse_ret_ty(
recover_qpath,
recover_return_sign,
None,
IsAsCast::No,
)?;
FnRetTy::Ty(ty)
} else {
@ -205,6 +229,7 @@ fn parse_ty_common(
recover_qpath: RecoverQPath,
recover_return_sign: RecoverReturnSign,
ty_generics: Option<&Generics>,
is_as_cast: IsAsCast,
) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
@ -280,6 +305,7 @@ fn parse_ty_common(
// 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)
}

View file

@ -114,6 +114,7 @@ fn check_attributes(
}
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,24 @@ fn check_doc_attrs(
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::TyAlias => true,
_ => {
self.tcx
.sess
.struct_span_err(
attr.span,
"`pass_by_value` attribute should be applied to a struct, enum or type alias.",
)
.span_label(*span, "is not a struct, enum or type alias")
.emit();
false
}
}
}
/// Warns against some misuses of `#[must_use]`
fn check_must_use(
&self,

View file

@ -336,8 +336,10 @@
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,
@ -407,6 +409,7 @@
cfg_doctest,
cfg_eval,
cfg_hide,
cfg_macro,
cfg_panic,
cfg_sanitize,
cfg_target_abi,
@ -434,15 +437,18 @@
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,
@ -522,10 +528,13 @@
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,
@ -597,6 +606,9 @@
encode,
end,
env,
env_macro,
eprint_macro,
eprintln_macro,
eq,
ermsb_target_feature,
exact_div,
@ -644,6 +656,7 @@
field,
field_init_shorthand,
file,
file_macro,
fill,
finish,
flags,
@ -666,6 +679,7 @@
format,
format_args,
format_args_capture,
format_args_macro,
format_args_nl,
format_macro,
freeze,
@ -732,7 +746,10 @@
in_band_lifetimes,
include,
include_bytes,
include_bytes_macro,
include_macro,
include_str,
include_str_macro,
inclusive_range_syntax,
index,
index_mut,
@ -780,6 +797,7 @@
lifetime,
likely,
line,
line_macro,
link,
link_args,
link_cfg,
@ -823,6 +841,7 @@
masked,
match_beginning_vert,
match_default_bindings,
matches_macro,
maxnumf32,
maxnumf64,
may_dangle,
@ -859,6 +878,7 @@
modifiers,
module,
module_path,
module_path_macro,
more_qualified_paths,
more_struct_aliases,
movbe_target_feature,
@ -942,6 +962,7 @@
optin_builtin_traits,
option,
option_env,
option_env_macro,
options,
or,
or_patterns,
@ -1005,6 +1026,8 @@
prelude_import,
preserves_flags,
primitive,
print_macro,
println_macro,
proc_dash_macro: "proc-macro",
proc_macro,
proc_macro_attribute,
@ -1147,6 +1170,7 @@
rustc_paren_sugar,
rustc_partition_codegened,
rustc_partition_reused,
rustc_pass_by_value,
rustc_peek,
rustc_peek_definite_init,
rustc_peek_liveness,
@ -1292,6 +1316,7 @@
str,
str_alloc,
stringify,
stringify_macro,
struct_field_attributes,
struct_inherit,
struct_variant,
@ -1335,6 +1360,8 @@
then_with,
thread,
thread_local,
thread_local_macro,
todo_macro,
tool_attributes,
tool_lints,
trace_macros,
@ -1385,6 +1412,7 @@
underscore_imports,
underscore_lifetimes,
uniform_paths,
unimplemented_macro,
unit,
universal_impl_trait,
unix,
@ -1393,6 +1421,7 @@
unpin,
unreachable,
unreachable_code,
unreachable_macro,
unrestricted_attribute_tokens,
unsafe_block_in_unsafe_fn,
unsafe_cell,
@ -1423,6 +1452,7 @@
var,
variant_count,
vec,
vec_macro,
version,
vis,
visible_private_types,
@ -1447,7 +1477,9 @@
wrapping_sub,
wreg,
write_bytes,
write_macro,
write_str,
writeln_macro,
x87_reg,
xer,
xmm_reg,

View file

@ -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()
},
}

View file

@ -206,7 +206,9 @@ fn confirm_projection_candidate(
})?);
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,

View file

@ -34,7 +34,7 @@
// 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
@ -68,6 +68,10 @@
/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
/// behavior.
///
/// 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
/// [`RefCell`]: core::cell::RefCell

View file

@ -15,7 +15,7 @@
// 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 @@
/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
/// behavior.
///
/// 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
/// [`RefCell`]: core::cell::RefCell

View file

@ -14,7 +14,7 @@
#[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::*;
}

View file

@ -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 {
() => (

View file

@ -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 @@ macro_rules! debug_assert_ne {
/// ```
#[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 @@ macro_rules! compile_error {
/// 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 @@ macro_rules! format_args_nl {
#[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 @@ macro_rules! env {
#[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 @@ macro_rules! concat_bytes {
#[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 @@ macro_rules! concat {
#[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 @@ macro_rules! line {
#[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 @@ macro_rules! column {
#[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 @@ macro_rules! file {
#[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 @@ macro_rules! stringify {
#[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 @@ macro_rules! include_str {
#[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 @@ macro_rules! include_bytes {
#[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 @@ macro_rules! module_path {
#[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 @@ macro_rules! cfg {
#[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 */ }};
}

View file

@ -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

View file

@ -142,6 +142,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// [`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)

View file

@ -6,13 +6,12 @@
use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_expand::base::SyntaxExtensionKind;
use rustc_hir as hir;
use rustc_hir::def::{
DefKind,
Namespace::{self, *},
PerNS,
};
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_ID};
use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
use rustc_middle::{bug, span_bug, ty};
use rustc_resolve::ParentScope;
@ -109,6 +108,45 @@ fn as_hir_res(self) -> Option<rustc_hir::def::Res> {
Res::Primitive(_) => None,
}
}
/// Used for error reporting.
fn disambiguator_suggestion(self) -> Suggestion {
let kind = match self {
Res::Primitive(_) => return Suggestion::Prefix("prim"),
Res::Def(kind, _) => kind,
};
if kind == DefKind::Macro(MacroKind::Bang) {
return Suggestion::Macro;
} else if kind == DefKind::Fn || kind == DefKind::AssocFn {
return Suggestion::Function;
} else if kind == DefKind::Field {
return Suggestion::RemoveDisambiguator;
}
let prefix = match kind {
DefKind::Struct => "struct",
DefKind::Enum => "enum",
DefKind::Trait => "trait",
DefKind::Union => "union",
DefKind::Mod => "mod",
DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => {
"const"
}
DefKind::Static => "static",
DefKind::Macro(MacroKind::Derive) => "derive",
// Now handle things that don't have a specific disambiguator
_ => match kind
.ns()
.expect("tried to calculate a disambiguator for a def without a namespace?")
{
Namespace::TypeNS => "type",
Namespace::ValueNS => "value",
Namespace::MacroNS => "macro",
},
};
Suggestion::Prefix(prefix)
}
}
impl TryFrom<ResolveRes> for Res {
@ -346,7 +384,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
/// In particular, this will return an error whenever there aren't three
/// full path segments left in the link.
///
/// [enum struct variant]: hir::VariantData::Struct
/// [enum struct variant]: rustc_hir::VariantData::Struct
fn variant_field<'path>(
&self,
path_str: &'path str,
@ -667,10 +705,8 @@ fn primitive_type_to_ty(&mut self, prim: PrimitiveType) -> Option<Ty<'tcx>> {
}))
}
/// Returns:
/// - None if no associated item was found
/// - Some((_, _, Some(_))) if an item was found and should go through a side channel
/// - Some((_, _, None)) otherwise
/// Resolve an associated item, returning its containing page's `Res`
/// and the fragment targeting the associated item on its page.
fn resolve_associated_item(
&mut self,
root_res: Res,
@ -903,7 +939,18 @@ fn traits_implemented_by<'a>(
ty
);
// Fast path: if this is a primitive simple `==` will work
let saw_impl = impl_type == ty;
// NOTE: the `match` is necessary; see #92662.
// this allows us to ignore generics because the user input
// may not include the generic placeholders
// e.g. this allows us to match Foo (user comment) with Foo<T> (actual type)
let saw_impl = impl_type == ty
|| match (impl_type.kind(), ty.kind()) {
(ty::Adt(impl_def, _), ty::Adt(ty_def, _)) => {
debug!("impl def_id: {:?}, ty def_id: {:?}", impl_def.did, ty_def.did);
impl_def.did == ty_def.did
}
_ => false,
};
if saw_impl { Some(trait_) } else { None }
})
@ -958,17 +1005,7 @@ fn visit_item(&mut self, item: &Item) {
{
self.cx.tcx.parent(did)
}
Some(did) => match self.cx.tcx.parent(did) {
// HACK(jynelson): `clean` marks associated types as `TypedefItem`, not as `AssocTypeItem`.
// Fixing this breaks `fn render_deref_methods`.
// As a workaround, see if the parent of the item is an `impl`; if so this must be an associated item,
// regardless of what rustdoc wants to call it.
Some(parent) => {
let parent_kind = self.cx.tcx.def_kind(parent);
Some(if parent_kind == DefKind::Impl { parent } else { did })
}
None => Some(did),
},
Some(did) => Some(did),
};
// FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly
@ -1277,79 +1314,9 @@ fn resolve_link(
}
}
let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| {
// The resolved item did not match the disambiguator; give a better error than 'not found'
let msg = format!("incompatible link kind for `{}`", path_str);
let callback = |diag: &mut DiagnosticBuilder<'_>, sp: Option<rustc_span::Span>| {
let note = format!(
"this link resolved to {} {}, which is not {} {}",
resolved.article(),
resolved.descr(),
specified.article(),
specified.descr()
);
if let Some(sp) = sp {
diag.span_label(sp, &note);
} else {
diag.note(&note);
}
suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp);
};
report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, callback);
};
let verify = |kind: DefKind, id: DefId| {
let (kind, id) = if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
(self.cx.tcx.def_kind(id), id)
} else {
(kind, id)
};
debug!("intra-doc link to {} resolved to {:?} (id: {:?})", path_str, res, id);
// Disallow e.g. linking to enums with `struct@`
debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
match (kind, disambiguator) {
| (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
// NOTE: this allows 'method' to mean both normal functions and associated functions
// This can't cause ambiguity because both are in the same namespace.
| (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
// These are namespaces; allow anything in the namespace to match
| (_, Some(Disambiguator::Namespace(_)))
// If no disambiguator given, allow anything
| (_, None)
// All of these are valid, so do nothing
=> {}
(actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
(_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
report_mismatch(specified, Disambiguator::Kind(kind));
return None;
}
}
// item can be non-local e.g. when using #[doc(primitive = "pointer")]
if let Some((src_id, dst_id)) = id
.as_local()
// The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
// would presumably panic if a fake `DefIndex` were passed.
.and_then(|dst_id| {
item.def_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
})
{
if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
&& !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id)
{
privacy_error(self.cx, &diag_info, path_str);
}
}
Some(())
};
match res {
Res::Primitive(prim) => {
if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
let kind = self.cx.tcx.def_kind(id);
// We're actually resolving an associated item of a primitive, so we need to
// verify the disambiguator (if any) matches the type of the associated item.
// This case should really follow the same flow as the `Res::Def` branch below,
@ -1358,7 +1325,16 @@ fn resolve_link(
// doesn't allow statements like `use str::trim;`, making this a (hopefully)
// valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677
// for discussion on the matter.
verify(kind, id)?;
let kind = self.cx.tcx.def_kind(id);
self.verify_disambiguator(
path_str,
&ori_link,
kind,
id,
disambiguator,
item,
&diag_info,
)?;
// FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether.
// However I'm not sure how to check that across crates.
@ -1372,7 +1348,9 @@ fn resolve_link(
match disambiguator {
Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {}
Some(other) => {
report_mismatch(other, Disambiguator::Primitive);
self.report_disambiguator_mismatch(
path_str, &ori_link, other, res, &diag_info,
);
return None;
}
}
@ -1386,13 +1364,106 @@ fn resolve_link(
})
}
Res::Def(kind, id) => {
verify(kind, id)?;
let (kind_for_dis, id_for_dis) =
if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
(self.cx.tcx.def_kind(id), id)
} else {
(kind, id)
};
self.verify_disambiguator(
path_str,
&ori_link,
kind_for_dis,
id_for_dis,
disambiguator,
item,
&diag_info,
)?;
let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
Some(ItemLink { link: ori_link.link, link_text, did: id, fragment })
}
}
}
fn verify_disambiguator(
&self,
path_str: &str,
ori_link: &MarkdownLink,
kind: DefKind,
id: DefId,
disambiguator: Option<Disambiguator>,
item: &Item,
diag_info: &DiagnosticInfo<'_>,
) -> Option<()> {
debug!("intra-doc link to {} resolved to {:?}", path_str, (kind, id));
// Disallow e.g. linking to enums with `struct@`
debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
match (kind, disambiguator) {
| (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
// NOTE: this allows 'method' to mean both normal functions and associated functions
// This can't cause ambiguity because both are in the same namespace.
| (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
// These are namespaces; allow anything in the namespace to match
| (_, Some(Disambiguator::Namespace(_)))
// If no disambiguator given, allow anything
| (_, None)
// All of these are valid, so do nothing
=> {}
(actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
(_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
self.report_disambiguator_mismatch(path_str,ori_link,specified, Res::Def(kind, id),diag_info);
return None;
}
}
// item can be non-local e.g. when using #[doc(primitive = "pointer")]
if let Some((src_id, dst_id)) = id
.as_local()
// The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
// would presumably panic if a fake `DefIndex` were passed.
.and_then(|dst_id| {
item.def_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
})
{
if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
&& !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id)
{
privacy_error(self.cx, diag_info, path_str);
}
}
Some(())
}
fn report_disambiguator_mismatch(
&self,
path_str: &str,
ori_link: &MarkdownLink,
specified: Disambiguator,
resolved: Res,
diag_info: &DiagnosticInfo<'_>,
) {
// The resolved item did not match the disambiguator; give a better error than 'not found'
let msg = format!("incompatible link kind for `{}`", path_str);
let callback = |diag: &mut DiagnosticBuilder<'_>, sp: Option<rustc_span::Span>| {
let note = format!(
"this link resolved to {} {}, which is not {} {}",
resolved.article(),
resolved.descr(),
specified.article(),
specified.descr(),
);
if let Some(sp) = sp {
diag.span_label(sp, &note);
} else {
diag.note(&note);
}
suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp);
};
report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, callback);
}
fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &MarkdownLink, item: &Item) {
let span =
super::source_span_for_markdown_range(self.cx.tcx, dox, &ori_link.range, &item.attrs)
@ -1413,7 +1484,6 @@ fn resolve_with_disambiguator_cached(
diag: DiagnosticInfo<'_>,
cache_resolution_failure: bool,
) -> Option<(Res, Option<UrlFragment>)> {
// Try to look up both the result and the corresponding side channel value
if let Some(ref cached) = self.visited_links.get(&key) {
match cached {
Some(cached) => {
@ -1686,53 +1756,6 @@ fn from_str(link: &str) -> Result<Option<(Self, &str, &str)>, (String, Range<usi
}
}
fn from_res(res: Res) -> Self {
match res {
Res::Def(kind, _) => Disambiguator::Kind(kind),
Res::Primitive(_) => Disambiguator::Primitive,
}
}
/// Used for error reporting.
fn suggestion(self) -> Suggestion {
let kind = match self {
Disambiguator::Primitive => return Suggestion::Prefix("prim"),
Disambiguator::Kind(kind) => kind,
Disambiguator::Namespace(_) => panic!("display_for cannot be used on namespaces"),
};
if kind == DefKind::Macro(MacroKind::Bang) {
return Suggestion::Macro;
} else if kind == DefKind::Fn || kind == DefKind::AssocFn {
return Suggestion::Function;
} else if kind == DefKind::Field {
return Suggestion::RemoveDisambiguator;
}
let prefix = match kind {
DefKind::Struct => "struct",
DefKind::Enum => "enum",
DefKind::Trait => "trait",
DefKind::Union => "union",
DefKind::Mod => "mod",
DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => {
"const"
}
DefKind::Static => "static",
DefKind::Macro(MacroKind::Derive) => "derive",
// Now handle things that don't have a specific disambiguator
_ => match kind
.ns()
.expect("tried to calculate a disambiguator for a def without a namespace?")
{
Namespace::TypeNS => "type",
Namespace::ValueNS => "value",
Namespace::MacroNS => "macro",
},
};
Suggestion::Prefix(prefix)
}
fn ns(self) -> Namespace {
match self {
Self::Namespace(n) => n,
@ -1754,9 +1777,9 @@ fn article(self) -> &'static str {
fn descr(self) -> &'static str {
match self {
Self::Namespace(n) => n.descr(),
// HACK(jynelson): by looking at the source I saw the DefId we pass
// for `expected.descr()` doesn't matter, since it's not a crate
Self::Kind(k) => k.descr(DefId::local(hir::def_id::DefIndex::from_usize(0))),
// HACK(jynelson): the source of `DefKind::descr` only uses the DefId for
// printing "module" vs "crate" so using the wrong ID is not a huge problem
Self::Kind(k) => k.descr(CRATE_DEF_ID.to_def_id()),
Self::Primitive => "builtin type",
}
}
@ -2080,16 +2103,7 @@ fn split(path: &str) -> Option<(&str, &str)> {
ResolutionFailure::NotResolved { .. } => unreachable!("handled above"),
ResolutionFailure::Dummy => continue,
ResolutionFailure::WrongNamespace { res, expected_ns } => {
if let Res::Def(kind, _) = res {
let disambiguator = Disambiguator::Kind(kind);
suggest_disambiguator(
disambiguator,
diag,
path_str,
diag_info.ori_link,
sp,
)
}
suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
format!(
"this link resolves to {}, which is not in the {} namespace",
@ -2224,8 +2238,7 @@ fn ambiguity_error(
}
for res in candidates {
let disambiguator = Disambiguator::from_res(res);
suggest_disambiguator(disambiguator, diag, path_str, diag_info.ori_link, sp);
suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
}
});
}
@ -2233,14 +2246,14 @@ fn ambiguity_error(
/// In case of an ambiguity or mismatched disambiguator, suggest the correct
/// disambiguator.
fn suggest_disambiguator(
disambiguator: Disambiguator,
res: Res,
diag: &mut DiagnosticBuilder<'_>,
path_str: &str,
ori_link: &str,
sp: Option<rustc_span::Span>,
) {
let suggestion = disambiguator.suggestion();
let help = format!("to link to the {}, {}", disambiguator.descr(), suggestion.descr());
let suggestion = res.disambiguator_suggestion();
let help = format!("to link to the {}, {}", res.descr(), suggestion.descr());
if let Some(sp) = sp {
let mut spans = suggestion.as_help_span(path_str, ori_link, sp);

View file

@ -73,4 +73,9 @@ trait T {}
//~^ ERROR incompatible link kind for `f`
//~| NOTE this link resolved
//~| HELP add parentheses
/// Link to [fn@std]
//~^ ERROR unresolved link to `std`
//~| NOTE this link resolves to the crate `std`
//~| HELP to link to the crate, prefix with `mod@`
pub fn f() {}

View file

@ -138,5 +138,16 @@ LL - /// Link to [const@f]
LL + /// Link to [f()]
|
error: aborting due to 12 previous errors
error: unresolved link to `std`
--> $DIR/disambiguator-mismatch.rs:77:14
|
LL | /// Link to [fn@std]
| ^^^^^^ this link resolves to the crate `std`, which is not in the value namespace
|
help: to link to the crate, prefix with `mod@`
|
LL | /// Link to [mod@std]
| ~~~~
error: aborting due to 13 previous errors

View file

@ -4,14 +4,34 @@
pub type ExternType;
}
impl ExternType {
pub fn f(&self) {
pub trait T {
fn test(&self) {}
}
}
pub trait G<N> {
fn g(&self, n: N) {}
}
impl ExternType {
pub fn f(&self) {}
}
impl T for ExternType {
fn test(&self) {}
}
impl G<usize> for ExternType {
fn g(&self, n: usize) {}
}
// @has 'extern_type/foreigntype.ExternType.html'
// @has 'extern_type/fn.links_to_extern_type.html' \
// 'href="foreigntype.ExternType.html#method.f"'
// @has 'extern_type/fn.links_to_extern_type.html' \
// 'href="foreigntype.ExternType.html#method.test"'
// @has 'extern_type/fn.links_to_extern_type.html' \
// 'href="foreigntype.ExternType.html#method.g"'
/// See also [ExternType::f]
/// See also [ExternType::test]
/// See also [ExternType::g]
pub fn links_to_extern_type() {}

View file

@ -0,0 +1,20 @@
#![deny(rustdoc::broken_intra_doc_links)]
// Test intra-doc links on trait implementations with generics
// regression test for issue #92662
use std::marker::PhantomData;
pub trait Bar<T> {
fn bar(&self);
}
pub struct Foo<U>(PhantomData<U>);
impl<T, U> Bar<T> for Foo<U> {
fn bar(&self) {}
}
// @has generic_trait_impl/fn.main.html '//a[@href="struct.Foo.html#method.bar"]' 'Foo::bar'
/// link to [`Foo::bar`]
pub fn main() {}

View file

@ -1,13 +1,15 @@
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(incomplete_features)] // inherent_associated_types
#![feature(lang_items)]
#![feature(no_core)]
#![feature(rustdoc_internals)]
#![feature(inherent_associated_types)]
#![no_core]
#[lang = "usize"]
/// [Self::f]
/// [Self::MAX]
// @has intra_link_prim_self/primitive.usize.html
// @has prim_self/primitive.usize.html
// @has - '//a[@href="primitive.usize.html#method.f"]' 'Self::f'
// @has - '//a[@href="primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
impl usize {
@ -17,10 +19,9 @@ pub fn f() {}
/// 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")]

View file

@ -1,80 +0,0 @@
error: passing `Ty<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:13:13
|
LL | ty_ref: &Ty<'_>,
| ^^^^^^^ help: try passing by value: `Ty<'_>`
|
note: the lint level is defined here
--> $DIR/pass_ty_by_ref.rs:4:9
|
LL | #![deny(rustc::ty_pass_by_reference)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: passing `TyCtxt<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:15:18
|
LL | ty_ctxt_ref: &TyCtxt<'_>,
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:19:28
|
LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:19:55
|
LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:26:17
|
LL | ty_ref: &Ty<'_>,
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:28:22
|
LL | ty_ctxt_ref: &TyCtxt<'_>,
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:31:41
|
LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:31:68
|
LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:53:17
|
LL | ty_ref: &Ty<'_>,
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:55:22
|
LL | ty_ctxt_ref: &TyCtxt<'_>,
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:59:38
|
LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:59:65
|
LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: aborting due to 12 previous errors

View file

@ -1,20 +0,0 @@
error: passing `TyCtxt<'tcx>` by reference
--> $DIR/pass_ty_by_ref_self.rs:18:15
|
LL | fn by_ref(&self) {}
| ^^^^^ help: try passing by value: `TyCtxt<'tcx>`
|
note: the lint level is defined here
--> $DIR/pass_ty_by_ref_self.rs:8:9
|
LL | #![deny(rustc::ty_pass_by_reference)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: passing `Ty<'tcx>` by reference
--> $DIR/pass_ty_by_ref_self.rs:31:21
|
LL | fn by_ref(self: &Ty<'tcx>) {}
| ^^^^^^^^^ help: try passing by value: `Ty<'tcx>`
error: aborting due to 2 previous errors

View file

@ -1,7 +1,8 @@
// compile-flags: -Z unstable-options
#![feature(rustc_attrs)]
#![feature(rustc_private)]
#![deny(rustc::ty_pass_by_reference)]
#![deny(rustc::pass_by_value)]
#![allow(unused)]
extern crate rustc_middle;
@ -61,4 +62,57 @@ fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
//~^^ ERROR passing `TyCtxt<'_>` by reference
}
#[rustc_pass_by_value]
enum CustomEnum {
A,
B,
}
impl CustomEnum {
fn test(
value: CustomEnum,
reference: &CustomEnum, //~ ERROR passing `CustomEnum` by reference
) {
}
}
#[rustc_pass_by_value]
struct CustomStruct {
s: u8,
}
#[rustc_pass_by_value]
type CustomAlias<'a> = &'a CustomStruct; //~ ERROR passing `CustomStruct` by reference
impl CustomStruct {
fn test(
value: CustomStruct,
reference: &CustomStruct, //~ ERROR passing `CustomStruct` by reference
) {
}
fn test_alias(
value: CustomAlias,
reference: &CustomAlias, //~ ERROR passing `CustomAlias<>` by reference
) {
}
}
#[rustc_pass_by_value]
struct WithParameters<T, const N: usize, M = u32> {
slice: [T; N],
m: M,
}
impl<T> WithParameters<T, 1> {
fn test<'a>(
value: WithParameters<T, 1>,
reference: &'a WithParameters<T, 1>, //~ ERROR passing `WithParameters<T, 1>` by reference
reference_with_m: &WithParameters<T, 1, u32>, //~ ERROR passing `WithParameters<T, 1, u32>` by reference
) -> &'a WithParameters<T, 1> {
//~^ ERROR passing `WithParameters<T, 1>` by reference
reference as &WithParameters<_, 1> //~ ERROR passing `WithParameters<_, 1>` by reference
}
}
fn main() {}

View file

@ -0,0 +1,128 @@
error: passing `Ty<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:14:13
|
LL | ty_ref: &Ty<'_>,
| ^^^^^^^ help: try passing by value: `Ty<'_>`
|
note: the lint level is defined here
--> $DIR/rustc_pass_by_value.rs:5:9
|
LL | #![deny(rustc::pass_by_value)]
| ^^^^^^^^^^^^^^^^^^^^
error: passing `TyCtxt<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:16:18
|
LL | ty_ctxt_ref: &TyCtxt<'_>,
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:20:28
|
LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:20:55
|
LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:27:17
|
LL | ty_ref: &Ty<'_>,
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:29:22
|
LL | ty_ctxt_ref: &TyCtxt<'_>,
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:32:41
|
LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:32:68
|
LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:54:17
|
LL | ty_ref: &Ty<'_>,
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:56:22
|
LL | ty_ctxt_ref: &TyCtxt<'_>,
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:60:38
|
LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:60:65
|
LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `CustomEnum` by reference
--> $DIR/rustc_pass_by_value.rs:74:20
|
LL | reference: &CustomEnum,
| ^^^^^^^^^^^ help: try passing by value: `CustomEnum`
error: passing `CustomStruct` by reference
--> $DIR/rustc_pass_by_value.rs:85:24
|
LL | type CustomAlias<'a> = &'a CustomStruct;
| ^^^^^^^^^^^^^^^^ help: try passing by value: `CustomStruct`
error: passing `CustomStruct` by reference
--> $DIR/rustc_pass_by_value.rs:90:20
|
LL | reference: &CustomStruct,
| ^^^^^^^^^^^^^ help: try passing by value: `CustomStruct`
error: passing `CustomAlias<>` by reference
--> $DIR/rustc_pass_by_value.rs:96:20
|
LL | reference: &CustomAlias,
| ^^^^^^^^^^^^ help: try passing by value: `CustomAlias<>`
error: passing `WithParameters<T, 1>` by reference
--> $DIR/rustc_pass_by_value.rs:110:20
|
LL | reference: &'a WithParameters<T, 1>,
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1>`
error: passing `WithParameters<T, 1, u32>` by reference
--> $DIR/rustc_pass_by_value.rs:111:27
|
LL | reference_with_m: &WithParameters<T, 1, u32>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1, u32>`
error: passing `WithParameters<T, 1>` by reference
--> $DIR/rustc_pass_by_value.rs:112:10
|
LL | ) -> &'a WithParameters<T, 1> {
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1>`
error: passing `WithParameters<_, 1>` by reference
--> $DIR/rustc_pass_by_value.rs:114:22
|
LL | reference as &WithParameters<_, 1>
| ^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<_, 1>`
error: aborting due to 20 previous errors

View file

@ -5,10 +5,10 @@
// Considering that all other `internal-lints` are tested here
// this seems like the cleaner solution though.
#![feature(rustc_attrs)]
#![deny(rustc::ty_pass_by_reference)]
#![deny(rustc::pass_by_value)]
#![allow(unused)]
#[rustc_diagnostic_item = "TyCtxt"]
#[rustc_pass_by_value]
struct TyCtxt<'tcx> {
inner: &'tcx (),
}
@ -18,12 +18,11 @@ fn by_value(self) {} // OK
fn by_ref(&self) {} //~ ERROR passing `TyCtxt<'tcx>` by reference
}
struct TyS<'tcx> {
inner: &'tcx (),
}
#[rustc_diagnostic_item = "Ty"]
#[rustc_pass_by_value]
type Ty<'tcx> = &'tcx TyS<'tcx>;
impl<'tcx> TyS<'tcx> {
@ -31,4 +30,25 @@ fn by_value(self: Ty<'tcx>) {}
fn by_ref(self: &Ty<'tcx>) {} //~ ERROR passing `Ty<'tcx>` by reference
}
#[rustc_pass_by_value]
struct Foo;
impl Foo {
fn with_ref(&self) {} //~ ERROR passing `Foo` by reference
}
#[rustc_pass_by_value]
struct WithParameters<T, const N: usize, M = u32> {
slice: [T; N],
m: M,
}
impl<T> WithParameters<T, 1> {
fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1_usize>` by reference
}
impl<T> WithParameters<T, 1, u8> {
fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1_usize, u8>` by reference
}
fn main() {}

View file

@ -0,0 +1,38 @@
error: passing `TyCtxt<'tcx>` by reference
--> $DIR/rustc_pass_by_value_self.rs:18:15
|
LL | fn by_ref(&self) {}
| ^^^^^ help: try passing by value: `TyCtxt<'tcx>`
|
note: the lint level is defined here
--> $DIR/rustc_pass_by_value_self.rs:8:9
|
LL | #![deny(rustc::pass_by_value)]
| ^^^^^^^^^^^^^^^^^^^^
error: passing `Ty<'tcx>` by reference
--> $DIR/rustc_pass_by_value_self.rs:30:21
|
LL | fn by_ref(self: &Ty<'tcx>) {}
| ^^^^^^^^^ help: try passing by value: `Ty<'tcx>`
error: passing `Foo` by reference
--> $DIR/rustc_pass_by_value_self.rs:37:17
|
LL | fn with_ref(&self) {}
| ^^^^^ help: try passing by value: `Foo`
error: passing `WithParameters<T, 1_usize>` by reference
--> $DIR/rustc_pass_by_value_self.rs:47:17
|
LL | fn with_ref(&self) {}
| ^^^^^ help: try passing by value: `WithParameters<T, 1_usize>`
error: passing `WithParameters<T, 1_usize, u8>` by reference
--> $DIR/rustc_pass_by_value_self.rs:51:17
|
LL | fn with_ref(&self) {}
| ^^^^^ help: try passing by value: `WithParameters<T, 1_usize, u8>`
error: aborting due to 5 previous errors

View file

@ -0,0 +1,18 @@
error[E0311]: the parameter type `C` may not live long enough
--> $DIR/issue-92096.rs:20:33
|
LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
| - ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
| |
| help: consider adding an explicit lifetime bound...: `C: 'a`
error[E0311]: the parameter type `C` may not live long enough
--> $DIR/issue-92096.rs:20:33
|
LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
| - ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
| |
| help: consider adding an explicit lifetime bound...: `C: 'a`
error: aborting due to 2 previous errors

View file

@ -0,0 +1,29 @@
// edition:2018
// [nll] check-pass
// revisions: migrate nll
// Explicitly testing nll with revision, so ignore compare-mode=nll
// ignore-compare-mode-nll
#![cfg_attr(nll, feature(nll))]
#![feature(generic_associated_types)]
use std::future::Future;
trait Client {
type Connecting<'a>: Future + Send
where
Self: 'a;
fn connect(&'_ self) -> Self::Connecting<'_>;
}
fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
//[migrate]~^ ERROR the parameter
//[migrate]~| ERROR the parameter
where
C: Client + Send + Sync,
{
async move { c.connect().await }
}
fn main() {}

View file

@ -0,0 +1,26 @@
// check-pass
#![feature(generic_associated_types)]
#![allow(non_camel_case_types)]
trait HasAssoc {
type Assoc;
}
trait Iterate<S: HasAssoc> {
type Iter<'a>
where
Self: 'a;
}
struct KeySegment_Broken<T> {
key: T,
}
impl<S: HasAssoc> Iterate<S> for KeySegment_Broken<S::Assoc> {
type Iter<'a>
where
Self: 'a,
= ();
}
fn main() {}

View file

@ -589,7 +589,7 @@ trait Trait<'a>: Sized
stringify_item!(
pub trait Trait<T> = Sized where T: 'a;
),
"", // FIXME
"pub trait Trait<T> = Sized where T: 'a;",
);
// ItemKind::Impl

View file

@ -117,9 +117,9 @@ pub fn inside_block() {
pub fn cast_then_try() -> Result<u64,u64> {
Err(0u64) as Result<u64,u64>?;
//~^ ERROR: casts cannot be followed by ?
//~^ ERROR: casts cannot be followed by `?`
Err(0u64): Result<u64,u64>?;
//~^ ERROR: casts cannot be followed by ?
//~^ ERROR: casts cannot be followed by `?`
Ok(1)
}

View file

@ -265,7 +265,7 @@ help: try surrounding the expression in parentheses
LL | static bar2: &[i32] = &((&[1i32,2,3]: &[i32; 3])[0..1]);
| + +
error: casts cannot be followed by ?
error: casts cannot be followed by `?`
--> $DIR/issue-35813-postfix-after-cast.rs:119:5
|
LL | Err(0u64) as Result<u64,u64>?;
@ -276,7 +276,7 @@ help: try surrounding the expression in parentheses
LL | (Err(0u64) as Result<u64,u64>)?;
| + +
error: casts cannot be followed by ?
error: casts cannot be followed by `?`
--> $DIR/issue-35813-postfix-after-cast.rs:121:5
|
LL | Err(0u64): Result<u64,u64>?;

View file

@ -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

View file

@ -1,17 +1,13 @@
error: expected parameter name, found `?`
error: invalid `?` in type
--> $DIR/issue-84148-1.rs:1:14
|
LL | fn f(t:for<>t?)
| ^ expected parameter name
error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
--> $DIR/issue-84148-1.rs:1:14
| ^ `?` is only allowed on expressions, not types
|
LL | fn f(t:for<>t?)
| ^
| |
| expected one of `(`, `)`, `+`, `,`, `::`, or `<`
| help: missing `,`
help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
|
LL | fn f(t:Option<for<>t>)
| +++++++ ~
error: expected one of `->`, `where`, or `{`, found `<eof>`
--> $DIR/issue-84148-1.rs:1:15
@ -19,5 +15,5 @@ error: expected one of `->`, `where`, or `{`, found `<eof>`
LL | fn f(t:for<>t?)
| ^ expected one of `->`, `where`, or `{`
error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

View file

@ -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?

View file

@ -1,31 +1,27 @@
error: this file contains an unclosed delimiter
--> $DIR/issue-84148-2.rs:4:16
--> $DIR/issue-84148-2.rs:3:16
|
LL | fn f(t:for<>t?
| - ^
| |
| unclosed delimiter
error: expected parameter name, found `?`
--> $DIR/issue-84148-2.rs:4:14
error: invalid `?` in type
--> $DIR/issue-84148-2.rs:3:14
|
LL | fn f(t:for<>t?
| ^ expected parameter name
error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
--> $DIR/issue-84148-2.rs:4:14
| ^ `?` is only allowed on expressions, not types
|
LL | fn f(t:for<>t?
| ^
| |
| expected one of `(`, `)`, `+`, `,`, `::`, or `<`
| help: missing `,`
help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
|
LL | fn f(t:Option<for<>t>
| +++++++ ~
error: expected one of `->`, `where`, or `{`, found `<eof>`
--> $DIR/issue-84148-2.rs:4:16
--> $DIR/issue-84148-2.rs:3:16
|
LL | fn f(t:for<>t?
| ^ expected one of `->`, `where`, or `{`
error: aborting due to 4 previous errors
error: aborting due to 3 previous errors

View file

@ -0,0 +1,10 @@
// run-rustfix
fn foo() -> Option<i32> { //~ ERROR invalid `?` in type
let x: Option<i32> = Some(1); //~ ERROR invalid `?` in type
x
}
fn main() {
let _: Option<i32> = foo();
}

View file

@ -0,0 +1,10 @@
// run-rustfix
fn foo() -> i32? { //~ ERROR invalid `?` in type
let x: i32? = Some(1); //~ ERROR invalid `?` in type
x
}
fn main() {
let _: Option<i32> = foo();
}

View file

@ -0,0 +1,24 @@
error: invalid `?` in type
--> $DIR/trailing-question-in-type.rs:3:16
|
LL | fn foo() -> i32? {
| ^ `?` is only allowed on expressions, not types
|
help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
|
LL | fn foo() -> Option<i32> {
| +++++++ ~
error: invalid `?` in type
--> $DIR/trailing-question-in-type.rs:4:15
|
LL | let x: i32? = Some(1);
| ^ `?` is only allowed on expressions, not types
|
help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
|
LL | let x: Option<i32> = Some(1);
| +++++++ ~
error: aborting due to 2 previous errors