"humantime 2.0.1",
"ignore",
"im-rc",
+ "indexmap",
"itertools",
"jobserver",
"lazy_static",
"serde_ignored",
"serde_json",
"shell-escape",
+ "snapbox",
"strip-ansi-escapes",
"tar",
"tempfile",
"winapi",
]
+[[package]]
+name = "concolor"
+version = "0.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "015267563b1df20adccdd00cb05257b1dfbea70a04928e9cf88ffb850c1a40af"
+dependencies = [
+ "atty",
+ "bitflags",
+ "concolor-query",
+]
+
+[[package]]
+name = "concolor-query"
+version = "0.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6417fe6fc03a8b533fd2177742eeb39a90c7233eedec7bac96d4d6b69a09449"
+
+[[package]]
+name = "content_inspector"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "core"
version = "0.0.0"
"rustc-std-workspace-core",
]
+[[package]]
+name = "dunce"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
+
[[package]]
name = "either"
version = "1.6.0"
"version_check",
]
+[[package]]
+name = "normalize-line-endings"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
+
[[package]]
name = "ntapi"
version = "0.3.6"
[[package]]
name = "once_cell"
-version = "1.7.2"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
+checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "opaque-debug"
[[package]]
name = "openssl"
-version = "0.10.35"
+version = "0.10.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "549430950c79ae24e6d02e0b7404534ecf311d94cc9f861e9e4020187d13d885"
+checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
[[package]]
name = "openssl-sys"
-version = "0.9.65"
+version = "0.9.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a7907e3bfa08bb85105209cdfcb6c63d109f8f6c1ed6ca318fff5c1853fbc1d"
+checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
dependencies = [
"autocfg",
"cc",
name = "proc_macro"
version = "0.0.0"
dependencies = [
+ "core",
"std",
]
"rustc_infer",
"rustc_middle",
"rustc_parse_format",
- "rustc_serialize",
"rustc_session",
"rustc_span",
"rustc_target",
"expect-test",
"itertools",
"minifier",
+ "once_cell",
"pulldown-cmark",
"rayon",
"regex",
"libc",
]
+[[package]]
+name = "similar"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3"
+
[[package]]
name = "siphasher"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e"
+[[package]]
+name = "snapbox"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1f212b806d6f56d19838e36a0aaa7e79a0bc9ca177e873fb87651ad92f983e2"
+dependencies = [
+ "concolor",
+ "content_inspector",
+ "dunce",
+ "filetime",
+ "normalize-line-endings",
+ "similar",
+ "snapbox-macros",
+ "tempfile",
+ "walkdir",
+ "yansi",
+]
+
+[[package]]
+name = "snapbox-macros"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c01dea7e04cbb27ef4c86e9922184608185f7cd95c1763bc30d727cda4a5e930"
+
[[package]]
name = "socket2"
version = "0.4.1"
[[package]]
name = "walkdir"
-version = "2.3.1"
+version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"linked-hash-map",
]
+[[package]]
+name = "yansi"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
+
[[package]]
name = "yansi-term"
version = "0.1.2"
}
}
-impl<CTX> HashStable<CTX> for Path {
+impl<CTX: rustc_span::HashStableContext> HashStable<CTX> for Path {
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
self.segments.len().hash_stable(hcx, hasher);
for segment in &self.segments {
- segment.ident.name.hash_stable(hcx, hasher);
+ segment.ident.hash_stable(hcx, hasher);
}
}
}
use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
use crate::tokenstream::{DelimSpan, Spacing, TokenTree, TreeAndSpacing};
use crate::tokenstream::{LazyTokenStream, TokenStream};
+use crate::util::comments;
use rustc_index::bit_set::GrowableBitSet;
use rustc_span::source_map::BytePos;
}
}
+ pub fn may_have_doc_links(&self) -> bool {
+ self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
+ }
+
pub fn get_normal_item(&self) -> &AttrItem {
match self.kind {
AttrKind::Normal(ref item, _) => item,
TokenTree::Token(Token::new(kind, span))
}
- /// Returns the opening delimiter as a token tree.
- pub fn open_tt(span: DelimSpan, delim: DelimToken) -> TokenTree {
- TokenTree::token(token::OpenDelim(delim), span.open)
- }
-
- /// Returns the closing delimiter as a token tree.
- pub fn close_tt(span: DelimSpan, delim: DelimToken) -> TokenTree {
- TokenTree::token(token::CloseDelim(delim), span.close)
- }
-
pub fn uninterpolate(self) -> TokenTree {
match self {
TokenTree::Token(token) => TokenTree::Token(token.uninterpolate().into_owned()),
Cursor { stream, index: 0 }
}
+ #[inline]
pub fn next_with_spacing(&mut self) -> Option<TreeAndSpacing> {
- if self.index < self.stream.len() {
+ self.stream.0.get(self.index).map(|tree| {
self.index += 1;
- Some(self.stream.0[self.index - 1].clone())
- } else {
- None
- }
+ tree.clone()
+ })
+ }
+
+ #[inline]
+ pub fn next_with_spacing_ref(&mut self) -> Option<&TreeAndSpacing> {
+ self.stream.0.get(self.index).map(|tree| {
+ self.index += 1;
+ tree
+ })
}
pub fn index(&self) -> usize {
pub pos: BytePos,
}
+/// A fast conservative estimate on whether the string can contain documentation links.
+/// A pair of square brackets `[]` must exist in the string, but we only search for the
+/// opening bracket because brackets always go in pairs in practice.
+#[inline]
+pub fn may_have_doc_links(s: &str) -> bool {
+ s.contains('[')
+}
+
/// Makes a doc string more presentable to users.
/// Used by rustdoc and perhaps other tools, but not by rustc.
pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
#[derive(Copy, Clone, Debug)]
pub enum FnKind<'a> {
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
- Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>),
+ Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
/// E.g., `|x, y| body`.
Closure(&'a FnDecl, &'a Expr),
impl<'a> FnKind<'a> {
pub fn header(&self) -> Option<&'a FnHeader> {
match *self {
- FnKind::Fn(_, _, sig, _, _) => Some(&sig.header),
+ FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
FnKind::Closure(_, _) => None,
}
}
pub fn decl(&self) -> &'a FnDecl {
match self {
- FnKind::Fn(_, _, sig, _, _) => &sig.decl,
+ FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
FnKind::Closure(decl, _) => decl,
}
}
walk_list!(visitor, visit_expr, expr);
}
ItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
- visitor.visit_generics(generics);
- let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
+ let kind =
+ FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
visitor.visit_fn(kind, item.span, item.id)
}
ItemKind::Mod(_unsafety, ref mod_kind) => match mod_kind {
walk_list!(visitor, visit_expr, expr);
}
ForeignItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
- visitor.visit_generics(generics);
- let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
+ let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref());
visitor.visit_fn(kind, span, id);
}
ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) {
match kind {
- FnKind::Fn(_, _, sig, _, body) => {
+ FnKind::Fn(_, _, sig, _, generics, body) => {
+ visitor.visit_generics(generics);
visitor.visit_fn_header(&sig.header);
walk_fn_decl(visitor, &sig.decl);
walk_list!(visitor, visit_block, body);
walk_list!(visitor, visit_expr, expr);
}
AssocItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
- visitor.visit_generics(generics);
- let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
+ let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
visitor.visit_fn(kind, span, id);
}
AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
/// an "elided" or "underscore" lifetime name. In the future, we probably want to move
/// everything into HIR lowering.
#[derive(Copy, Clone, Debug)]
-enum AnonymousLifetimeMode {
+pub enum AnonymousLifetimeMode {
/// For **Modern** cases, create a new anonymous region parameter
/// and reference that.
///
// Output lifetime like `'_`:
for (span, node_id) in lifetimes_to_define {
let param = this.fresh_lifetime_to_generic_param(span, node_id);
- lifetime_params.push((span, hir::LifetimeName::Implicit(false)));
+ lifetime_params.push((span, hir::LifetimeName::Implicit));
generic_params.push(param);
}
let generic_params = this.arena.alloc_from_iter(generic_params);
});
let param_name = match lt.name {
hir::LifetimeName::Param(param_name) => param_name,
- hir::LifetimeName::Implicit(_)
- | hir::LifetimeName::Underscore
- | hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
+ hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
+ hir::ParamName::Plain(lt.name.ident())
+ }
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
self.sess.diagnostic().span_bug(
param.ident.span,
"object-lifetime-default should not occur here",
);
}
- hir::LifetimeName::Error => ParamName::Error,
+ hir::LifetimeName::Static | hir::LifetimeName::Error => ParamName::Error,
};
let kind =
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
- AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span, false),
+ AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
}
}
/// Report an error on illegal use of `'_` or a `&T` with no explicit lifetime;
/// return an "error lifetime".
fn new_error_lifetime(&mut self, id: Option<NodeId>, span: Span) -> hir::Lifetime {
- let (id, msg, label) = match id {
- Some(id) => (id, "`'_` cannot be used here", "`'_` is a reserved lifetime name"),
-
- None => (
- self.resolver.next_node_id(),
- "`&` without an explicit lifetime name cannot be used here",
- "explicit lifetime name needed here",
- ),
- };
-
- let mut err = struct_span_err!(self.sess, span, E0637, "{}", msg,);
- err.span_label(span, label);
- err.emit();
-
+ let id = id.unwrap_or_else(|| self.resolver.next_node_id());
self.new_named_lifetime(id, span, hir::LifetimeName::Error)
}
&'s mut self,
span: Span,
count: usize,
- param_mode: ParamMode,
) -> impl Iterator<Item = hir::Lifetime> + Captures<'a> + Captures<'s> + Captures<'hir> {
- (0..count).map(move |_| self.elided_path_lifetime(span, param_mode))
+ (0..count).map(move |_| self.elided_path_lifetime(span))
}
- fn elided_path_lifetime(&mut self, span: Span, param_mode: ParamMode) -> hir::Lifetime {
+ fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
match self.anonymous_lifetime_mode {
AnonymousLifetimeMode::CreateParameter => {
// We should have emitted E0726 when processing this path above
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
// later, at which point a suitable error will be emitted.
AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
- self.new_implicit_lifetime(span, param_mode == ParamMode::Explicit)
+ self.new_implicit_lifetime(span)
}
}
}
r
}
- fn new_implicit_lifetime(&mut self, span: Span, missing: bool) -> hir::Lifetime {
+ fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
hir::Lifetime {
hir_id: self.next_id(),
span: self.lower_span(span),
- name: hir::LifetimeName::Implicit(missing),
+ name: hir::LifetimeName::Implicit,
}
}
}
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
let name = match lifetime.name {
- hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => {
+ hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
if self.collect_elided_lifetimes {
// Use `'_` for both implicit and underscore lifetimes in
// `type Foo<'_> = impl SomeTrait<'_>;`.
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
};
generic_args.args = self
- .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes, param_mode)
+ .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes)
.map(GenericArg::Lifetime)
.chain(generic_args.args.into_iter())
.collect();
- // In create-parameter mode we error here because we don't want to support
- // deprecated impl elision in new features like impl elision and `async fn`,
- // both of which work using the `CreateParameter` mode:
- //
- // impl Foo for std::cell::Ref<u32> // note lack of '_
- // async fn foo(_: std::cell::Ref<u32>) { ... }
if let (ParamMode::Explicit, AnonymousLifetimeMode::CreateParameter) =
(param_mode, self.anonymous_lifetime_mode)
{
- let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
- let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
- let no_bindings = generic_args.bindings.is_empty();
- let (incl_angl_brckt, suggestion) = if no_non_lt_args && no_bindings {
- // If there are no generic args, our suggestion can include the angle brackets.
- (true, format!("<{}>", anon_lt_suggestion))
- } else {
- // Otherwise we'll insert a `'_, ` right after the opening bracket.
- (false, format!("{}, ", anon_lt_suggestion))
- };
- let insertion_sp = elided_lifetime_span.shrink_to_hi();
- let mut err = struct_span_err!(
- self.sess,
- path_span,
- E0726,
- "implicit elided lifetime not allowed here"
- );
- rustc_errors::add_elided_lifetime_in_path_suggestion(
- &self.sess.source_map(),
- &mut err,
- expected_lifetimes,
- path_span,
- incl_angl_brckt,
- insertion_sp,
- suggestion,
- );
- err.note("assuming a `'static` lifetime...");
- err.emit();
+ // Late resolver should have issued the error.
+ self.sess
+ .delay_span_bug(elided_lifetime_span, "implicit lifetime not allowed here");
}
}
self.is_impl_trait_banned = old;
}
- fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
- let old = mem::replace(&mut self.is_tilde_const_allowed, true);
+ fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) {
+ let old = mem::replace(&mut self.is_tilde_const_allowed, allowed);
f(self);
self.is_tilde_const_allowed = old;
}
+ fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
+ self.with_tilde_const(true, f)
+ }
+
fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
- let old = mem::replace(&mut self.is_tilde_const_allowed, false);
- f(self);
- self.is_tilde_const_allowed = old;
+ self.with_tilde_const(false, f)
}
fn with_let_management(
}
self.visit_vis(&item.vis);
self.visit_ident(item.ident);
- if let Const::Yes(_) = sig.header.constness {
- self.with_tilde_const_allowed(|this| this.visit_generics(generics));
- } else {
- self.visit_generics(generics);
- }
- let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
+ let kind =
+ FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
self.visit_fn(kind, item.span, item.id);
walk_list!(self, visit_attribute, &item.attrs);
return; // Avoid visiting again.
FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. },
_,
_,
+ _,
) = fk
{
self.maybe_lint_missing_abi(*sig_span, id);
}
// Functions without bodies cannot have patterns.
- if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
+ if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
let (code, msg, label) = match ctxt {
FnCtxt::Foreign => (
});
}
- visit::walk_fn(self, fk, span);
+ let tilde_const_allowed =
+ matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
+ || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
+
+ self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span));
}
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
{
self.visit_vis(&item.vis);
self.visit_ident(item.ident);
- self.with_tilde_const_allowed(|this| this.visit_generics(generics));
- let kind =
- FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
+ let kind = FnKind::Fn(
+ FnCtxt::Assoc(ctxt),
+ item.ident,
+ sig,
+ &item.vis,
+ generics,
+ body.as_deref(),
+ );
self.visit_fn(kind, item.span, item.id);
}
_ => self
sup: self.static_region,
sub: next_static_idx.into(),
locations: Locations::All(DUMMY_SP),
+ span: DUMMY_SP,
category: ConstraintCategory::Internal,
variance_info: VarianceDiagInfo::default(),
})
use rustc_index::vec::IndexVec;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
+use rustc_span::Span;
use std::fmt;
use std::ops::Index;
/// Where did this constraint arise?
pub locations: Locations,
+ /// The `Span` associated with the creation of this constraint.
+ /// This should be used in preference to obtaining the span from
+ /// `locations`, since the `locations` may give a poor span
+ /// in some cases (e.g. converting a constraint from a promoted).
+ pub span: Span,
+
/// What caused this constraint?
pub category: ConstraintCategory,
err.span_suggestion_hidden(
return_span,
"use `.collect()` to allocate the iterator",
- format!("{}{}", snippet, ".collect::<Vec<_>>()"),
+ format!("{snippet}.collect::<Vec<_>>()"),
Applicability::MaybeIncorrect,
);
}
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
}
- hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit(_) => {
+ hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
// In this case, the user left off the lifetime; so
// they wrote something like:
//
let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
constraints.sort_by_key(|c| (c.sup, c.sub));
for constraint in &constraints {
- let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
+ let OutlivesConstraint { sup, sub, locations, category, span, variance_info: _ } =
+ constraint;
let (name, arg) = match locations {
Locations::All(span) => {
("All", tcx.sess.source_map().span_to_embeddable_string(*span))
}
Locations::Single(loc) => ("Single", format!("{:?}", loc)),
};
- with_msg(&format!("{:?}: {:?} due to {:?} at {}({})", sup, sub, category, name, arg))?;
+ with_msg(&format!(
+ "{:?}: {:?} due to {:?} at {}({}) ({:?}",
+ sup, sub, category, name, arg, span
+ ))?;
}
Ok(())
crate fn retrieve_closure_constraint_info(
&self,
- body: &Body<'tcx>,
+ _body: &Body<'tcx>,
constraint: &OutlivesConstraint<'tcx>,
) -> BlameConstraint<'tcx> {
let loc = match constraint.locations {
.unwrap_or(BlameConstraint {
category: constraint.category,
from_closure: false,
- cause: ObligationCause::dummy_with_span(body.source_info(loc).span),
+ cause: ObligationCause::dummy_with_span(constraint.span),
variance_info: constraint.variance_info,
})
}
sup: r,
sub: constraint.min_choice,
locations: Locations::All(p_c.definition_span),
+ span: p_c.definition_span,
category: ConstraintCategory::OpaqueType,
variance_info: ty::VarianceDiagInfo::default(),
};
category: constraint.category,
from_closure: false,
cause: ObligationCause::new(
- constraint.locations.span(body),
+ constraint.span,
CRATE_HIR_ID,
cause_code.clone(),
),
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::DUMMY_SP;
+use rustc_span::{Span, DUMMY_SP};
use crate::{
constraints::OutlivesConstraint,
implicit_region_bound: Option<ty::Region<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
locations: Locations,
+ span: Span,
category: ConstraintCategory,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
}
implicit_region_bound: Option<ty::Region<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
locations: Locations,
+ span: Span,
category: ConstraintCategory,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
) -> Self {
implicit_region_bound,
param_env,
locations,
+ span,
category,
constraints,
}
self.constraints.outlives_constraints.push(OutlivesConstraint {
locations: self.locations,
category: self.category,
+ span: self.span,
sub,
sup,
variance_info: ty::VarianceDiagInfo::default(),
self.implicit_region_bound,
self.param_env,
Locations::All(DUMMY_SP),
+ DUMMY_SP,
ConstraintCategory::Internal,
&mut self.constraints,
)
Some(self.implicit_region_bound),
self.param_env,
Locations::All(DUMMY_SP),
+ DUMMY_SP,
ConstraintCategory::Internal,
&mut self.borrowck_context.constraints,
)
Some(self.implicit_region_bound),
self.param_env,
locations,
+ locations.span(self.body),
category,
&mut self.borrowck_context.constraints,
)
sup: ref_region.to_region_vid(),
sub: borrow_region.to_region_vid(),
locations: location.to_locations(),
+ span: location.to_locations().span(body),
category,
variance_info: ty::VarianceDiagInfo::default(),
});
sup,
sub,
locations: self.locations,
+ span: self.locations.span(self.type_checker.body),
category: self.category,
variance_info: info,
},
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => unimplemented!(),
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => unimplemented!(),
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
InlineAsmRegClass::X86(
X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
| InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg) => unimplemented!(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => cx.type_i16(),
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
_ => unreachable!(),
},
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => None,
InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
InlineAsmRegClass::X86(
- X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
+ X86InlineAsmRegClass::x87_reg
+ | X86InlineAsmRegClass::mmx_reg
+ | X86InlineAsmRegClass::kreg0,
) => unreachable!("clobber-only"),
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
_ => unreachable!(),
},
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
- InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+ InlineAsmRegClass::X86(
+ X86InlineAsmRegClass::x87_reg
+ | X86InlineAsmRegClass::mmx_reg
+ | X86InlineAsmRegClass::kreg0,
+ ) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
| InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
- InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+ InlineAsmRegClass::X86(
+ X86InlineAsmRegClass::x87_reg
+ | X86InlineAsmRegClass::mmx_reg
+ | X86InlineAsmRegClass::kreg0,
+ ) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
// On MSVC packed debug information is produced by the linker itself so
// there's no need to do anything else here.
- SplitDebuginfo::Packed if sess.target.is_like_msvc => {}
+ SplitDebuginfo::Packed if sess.target.is_like_windows => {}
// ... and otherwise we're processing a `*.dwp` packed dwarf file.
//
use std::collections::hash_map::Entry::*;
use rustc_ast::expand::allocator::ALLOCATOR_METHODS;
-use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::Node;
-use rustc_index::vec::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::exported_symbols::{
metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
let mut instances: DefIdMap<FxHashMap<_, _>> = Default::default();
- let cnum_stable_ids: IndexVec<CrateNum, Fingerprint> = {
- let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO, cnums.len() + 1);
-
- for &cnum in cnums.iter() {
- cnum_stable_ids[cnum] =
- tcx.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX }).0;
- }
-
- cnum_stable_ids
- };
-
let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn();
for &cnum in cnums.iter() {
// If there are multiple monomorphizations available,
// we select one deterministically.
let other_cnum = *e.get();
- if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] {
+ if tcx.stable_crate_id(other_cnum) > tcx.stable_crate_id(cnum) {
e.insert(cnum);
}
}
if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
bug!("intern_const_alloc_recursive should not error in this case")
}
- ConstValue::Scalar(Scalar::from_pointer(loc_place.ptr.into_pointer_or_addr().unwrap(), &tcx))
+ ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx))
}
/// Convert an evaluated constant to a type level constant
return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
return_to_block: StackPopCleanup,
) -> InterpResult<'tcx> {
- debug!("body: {:#?}", body);
+ trace!("body: {:#?}", body);
// first push a stack frame so we have access to the local substs
let pre_frame = Frame {
body,
return Ok(());
}
- debug!("locals: {:#?}", frame.locals);
+ trace!("locals: {:#?}", frame.locals);
// Cleanup: deallocate all locals that are backed by an allocation.
for local in &frame.locals {
/// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to.
type PointerTag: Provenance + Eq + Hash + 'static;
+ /// When getting the AllocId of a pointer, some extra data is also obtained from the tag
+ /// that is passed to memory access hooks so they can do things with it.
+ type TagExtra: Copy + 'static;
+
/// Machines can define extra (non-instance) things that represent values of function pointers.
/// For example, Miri uses this to return a function pointer from `dlsym`
/// that can later be called to execute the right thing.
/// Whether, when checking alignment, we should `force_int` and thus support
/// custom alignment logic based on whatever the integer address happens to be.
+ ///
+ /// Requires PointerTag::OFFSET_IS_ADDR to be true.
fn force_int_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
/// Whether to enforce the validity invariant
addr: u64,
) -> Pointer<Option<Self::PointerTag>>;
- /// Convert a pointer with provenance into an allocation-offset pair.
+ /// Convert a pointer with provenance into an allocation-offset pair
+ /// and extra provenance info.
+ ///
+ /// The returned `AllocId` must be the same as `ptr.provenance.get_alloc_id()`.
fn ptr_get_alloc(
ecx: &InterpCx<'mir, 'tcx, Self>,
ptr: Pointer<Self::PointerTag>,
- ) -> (AllocId, Size);
+ ) -> (AllocId, Size, Self::TagExtra);
/// Called to initialize the "extra" state of an allocation and make the pointers
/// it contains (in relocations) tagged. The way we construct allocations is
_tcx: TyCtxt<'tcx>,
_machine: &Self,
_alloc_extra: &Self::AllocExtra,
- _tag: Self::PointerTag,
+ _tag: (AllocId, Self::TagExtra),
_range: AllocRange,
) -> InterpResult<'tcx> {
Ok(())
_tcx: TyCtxt<'tcx>,
_machine: &mut Self,
_alloc_extra: &mut Self::AllocExtra,
- _tag: Self::PointerTag,
+ _tag: (AllocId, Self::TagExtra),
_range: AllocRange,
) -> InterpResult<'tcx> {
Ok(())
_tcx: TyCtxt<'tcx>,
_machine: &mut Self,
_alloc_extra: &mut Self::AllocExtra,
- _tag: Self::PointerTag,
+ _tag: (AllocId, Self::TagExtra),
_range: AllocRange,
) -> InterpResult<'tcx> {
Ok(())
// (CTFE and ConstProp) use the same instance. Here, we share that code.
pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
type PointerTag = AllocId;
+ type TagExtra = ();
+
type ExtraFnVal = !;
type MemoryMap =
}
#[inline(always)]
- fn ptr_get_alloc(_ecx: &InterpCx<$mir, $tcx, Self>, ptr: Pointer<AllocId>) -> (AllocId, Size) {
+ fn ptr_get_alloc(
+ _ecx: &InterpCx<$mir, $tcx, Self>,
+ ptr: Pointer<AllocId>,
+ ) -> (AllocId, Size, Self::TagExtra) {
// We know `offset` is relative to the allocation, so we can use `into_parts`.
let (alloc_id, offset) = ptr.into_parts();
- (alloc_id, offset)
+ (alloc_id, offset, ())
}
}
&self,
ptr: Pointer<AllocId>,
) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
- // We know `offset` is relative to the allocation, so we can use `into_parts`.
- let (alloc_id, offset) = ptr.into_parts();
+ let alloc_id = ptr.provenance;
// We need to handle `extern static`.
match self.tcx.get_global_alloc(alloc_id) {
Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => {
_ => {}
}
// And we need to get the tag.
- Ok(M::tag_alloc_base_pointer(self, Pointer::new(alloc_id, offset)))
+ Ok(M::tag_alloc_base_pointer(self, ptr))
}
pub fn create_fn_alloc_ptr(
new_align: Align,
kind: MemoryKind<M::MemoryKind>,
) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
- let (alloc_id, offset, ptr) = self.ptr_get_alloc_id(ptr)?;
+ let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
if offset.bytes() != 0 {
throw_ub_format!(
"reallocating {:?} which does not point to the beginning of an object",
};
// This will also call the access hooks.
self.mem_copy(
- ptr.into(),
+ ptr,
Align::ONE,
new_ptr.into(),
Align::ONE,
old_size.min(new_size),
/*nonoverlapping*/ true,
)?;
- self.deallocate_ptr(ptr.into(), old_size_and_align, kind)?;
+ self.deallocate_ptr(ptr, old_size_and_align, kind)?;
Ok(new_ptr)
}
old_size_and_align: Option<(Size, Align)>,
kind: MemoryKind<M::MemoryKind>,
) -> InterpResult<'tcx> {
- let (alloc_id, offset, ptr) = self.ptr_get_alloc_id(ptr)?;
+ let (alloc_id, offset, tag) = self.ptr_get_alloc_id(ptr)?;
trace!("deallocating: {}", alloc_id);
if offset.bytes() != 0 {
*self.tcx,
&mut self.machine,
&mut alloc.extra,
- ptr.provenance,
+ (alloc_id, tag),
alloc_range(Size::ZERO, size),
)?;
ptr: Pointer<Option<M::PointerTag>>,
size: Size,
align: Align,
- ) -> InterpResult<'tcx, Option<(AllocId, Size, Pointer<M::PointerTag>)>> {
+ ) -> InterpResult<'tcx, Option<(AllocId, Size, M::TagExtra)>> {
let align = M::enforce_alignment(&self).then_some(align);
self.check_and_deref_ptr(
ptr,
size,
align,
CheckInAllocMsg::MemoryAccessTest,
- |alloc_id, offset, ptr| {
+ |alloc_id, offset, tag| {
let (size, align) =
self.get_alloc_size_and_align(alloc_id, AllocCheck::Dereferenceable)?;
- Ok((size, align, (alloc_id, offset, ptr)))
+ Ok((size, align, (alloc_id, offset, tag)))
},
)
}
size: Size,
align: Option<Align>,
msg: CheckInAllocMsg,
- alloc_size: impl FnOnce(
- AllocId,
- Size,
- Pointer<M::PointerTag>,
- ) -> InterpResult<'tcx, (Size, Align, T)>,
+ alloc_size: impl FnOnce(AllocId, Size, M::TagExtra) -> InterpResult<'tcx, (Size, Align, T)>,
) -> InterpResult<'tcx, Option<T>> {
fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
if offset % align.bytes() == 0 {
}
None
}
- Ok((alloc_id, offset, ptr)) => {
- let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, ptr)?;
+ Ok((alloc_id, offset, tag)) => {
+ let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, tag)?;
// Test bounds. This also ensures non-null.
// It is sufficient to check this for the end pointer. Also check for overflow!
if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) {
// we want the error to be about the bounds.
if let Some(align) = align {
if M::force_int_for_alignment_check(self) {
- let addr = Scalar::from_pointer(ptr, &self.tcx)
- .to_machine_usize(&self.tcx)
- .expect("ptr-to-int cast for align check should never fail");
- check_offset_align(addr, align)?;
+ // `force_int_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
+ check_offset_align(ptr.addr().bytes(), align)?;
} else {
// Check allocation alignment and offset alignment.
if alloc_align.bytes() < align.bytes() {
size,
align,
CheckInAllocMsg::MemoryAccessTest,
- |alloc_id, offset, ptr| {
+ |alloc_id, offset, tag| {
let alloc = self.get_alloc_raw(alloc_id)?;
- Ok((alloc.size(), alloc.align, (alloc_id, offset, ptr, alloc)))
+ Ok((alloc.size(), alloc.align, (alloc_id, offset, tag, alloc)))
},
)?;
- if let Some((alloc_id, offset, ptr, alloc)) = ptr_and_alloc {
+ if let Some((alloc_id, offset, tag, alloc)) = ptr_and_alloc {
let range = alloc_range(offset, size);
- M::memory_read(*self.tcx, &self.machine, &alloc.extra, ptr.provenance, range)?;
+ M::memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, tag), range)?;
Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id }))
} else {
// Even in this branch we have to be sure that we actually access the allocation, in
align: Align,
) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::PointerTag, M::AllocExtra>>> {
let parts = self.get_ptr_access(ptr, size, align)?;
- if let Some((alloc_id, offset, ptr)) = parts {
+ if let Some((alloc_id, offset, tag)) = parts {
let tcx = *self.tcx;
// FIXME: can we somehow avoid looking up the allocation twice here?
// We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?;
let range = alloc_range(offset, size);
- M::memory_written(tcx, machine, &mut alloc.extra, ptr.provenance, range)?;
+ M::memory_written(tcx, machine, &mut alloc.extra, (alloc_id, tag), range)?;
Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id }))
} else {
Ok(None)
ptr: Pointer<Option<M::PointerTag>>,
) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
trace!("get_fn({:?})", ptr);
- let (alloc_id, offset, _ptr) = self.ptr_get_alloc_id(ptr)?;
+ let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
if offset.bytes() != 0 {
throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))
}
range: AllocRange,
val: ScalarMaybeUninit<Tag>,
) -> InterpResult<'tcx> {
+ let range = self.range.subrange(range);
+ debug!(
+ "write_scalar in {} at {:#x}, size {}: {:?}",
+ self.alloc_id,
+ range.start.bytes(),
+ range.size.bytes(),
+ val
+ );
Ok(self
.alloc
- .write_scalar(&self.tcx, self.range.subrange(range), val)
+ .write_scalar(&self.tcx, range, val)
.map_err(|e| e.to_interp_error(self.alloc_id))?)
}
}
/// Mark the entire referenced range as uninitalized
- pub fn write_uninit(&mut self) {
- self.alloc.mark_init(self.range, false);
+ pub fn write_uninit(&mut self) -> InterpResult<'tcx> {
+ Ok(self
+ .alloc
+ .write_uninit(&self.tcx, self.range)
+ .map_err(|e| e.to_interp_error(self.alloc_id))?)
}
}
impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
- Ok(self
+ let range = self.range.subrange(range);
+ let res = self
.alloc
- .read_scalar(&self.tcx, self.range.subrange(range))
- .map_err(|e| e.to_interp_error(self.alloc_id))?)
+ .read_scalar(&self.tcx, range)
+ .map_err(|e| e.to_interp_error(self.alloc_id))?;
+ debug!(
+ "read_scalar in {} at {:#x}, size {}: {:?}",
+ self.alloc_id,
+ range.start.bytes(),
+ range.size.bytes(),
+ res
+ );
+ Ok(res)
}
pub fn read_ptr_sized(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
// and once below to get the underlying `&[mut] Allocation`.
// Source alloc preparations and access hooks.
- let Some((src_alloc_id, src_offset, src)) = src_parts else {
+ let Some((src_alloc_id, src_offset, src_tag)) = src_parts else {
// Zero-sized *source*, that means dst is also zero-sized and we have nothing to do.
return Ok(());
};
let src_alloc = self.get_alloc_raw(src_alloc_id)?;
let src_range = alloc_range(src_offset, size);
- M::memory_read(*tcx, &self.machine, &src_alloc.extra, src.provenance, src_range)?;
+ M::memory_read(*tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_tag), src_range)?;
// We need the `dest` ptr for the next operation, so we get it now.
// We already did the source checks and called the hooks so we are good to return early.
- let Some((dest_alloc_id, dest_offset, dest)) = dest_parts else {
+ let Some((dest_alloc_id, dest_offset, dest_tag)) = dest_parts else {
// Zero-sized *destination*.
return Ok(());
};
// Destination alloc preparations and access hooks.
let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?;
let dest_range = alloc_range(dest_offset, size * num_copies);
- M::memory_written(*tcx, extra, &mut dest_alloc.extra, dest.provenance, dest_range)?;
+ M::memory_written(
+ *tcx,
+ extra,
+ &mut dest_alloc.extra,
+ (dest_alloc_id, dest_tag),
+ dest_range,
+ )?;
let dest_bytes = dest_alloc
.get_bytes_mut_ptr(&tcx, dest_range)
.map_err(|e| e.to_interp_error(dest_alloc_id))?
// This also avoids writing to the target bytes so that the backing allocation is never
// touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary
// operating system this can avoid physically allocating the page.
- dest_alloc.mark_init(dest_range, false); // `Size` multiplication
- dest_alloc.mark_relocation_range(relocations);
+ dest_alloc
+ .write_uninit(&tcx, dest_range)
+ .map_err(|e| e.to_interp_error(dest_alloc_id))?;
+ // We can forget about the relocations, this is all not initialized anyway.
return Ok(());
}
pub fn ptr_try_get_alloc_id(
&self,
ptr: Pointer<Option<M::PointerTag>>,
- ) -> Result<(AllocId, Size, Pointer<M::PointerTag>), u64> {
+ ) -> Result<(AllocId, Size, M::TagExtra), u64> {
match ptr.into_pointer_or_addr() {
Ok(ptr) => {
- let (alloc_id, offset) = M::ptr_get_alloc(self, ptr);
- Ok((alloc_id, offset, ptr))
+ let (alloc_id, offset, extra) = M::ptr_get_alloc(self, ptr);
+ Ok((alloc_id, offset, extra))
}
Err(addr) => Err(addr.bytes()),
}
pub fn ptr_get_alloc_id(
&self,
ptr: Pointer<Option<M::PointerTag>>,
- ) -> InterpResult<'tcx, (AllocId, Size, Pointer<M::PointerTag>)> {
+ ) -> InterpResult<'tcx, (AllocId, Size, M::TagExtra)> {
self.ptr_try_get_alloc_id(ptr).map_err(|offset| {
err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into()
})
// Zero-sized access
return Ok(());
};
- alloc.write_uninit();
+ alloc.write_uninit()?;
Ok(())
}
if let Some(ref mut ref_tracking) = self.ref_tracking {
// Proceed recursively even for ZST, no reason to skip them!
// `!` is a ZST and we want to validate it.
- if let Ok((alloc_id, _offset, _ptr)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
+ if let Ok((alloc_id, _offset, _tag)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
// Special handling for pointers to statics (irrespective of their type).
let alloc_kind = self.ecx.tcx.get_global_alloc(alloc_id);
if let Some(GlobalAlloc::Static(did)) = alloc_kind {
fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType;
}
-// Implement HashStable by just calling `Hash::hash()`. This works fine for
-// self-contained values that don't depend on the hashing context `CTX`.
-#[macro_export]
+/// Implement HashStable by just calling `Hash::hash()`.
+///
+/// **WARNING** This is only valid for types that *really* don't need any context for fingerprinting.
+/// But it is easy to misuse this macro (see [#96013](https://github.com/rust-lang/rust/issues/96013)
+/// for examples). Therefore this macro is not exported and should only be used in the limited cases
+/// here in this module.
+///
+/// Use `#[derive(HashStable_Generic)]` instead.
macro_rules! impl_stable_hash_via_hash {
($t:ty) => {
impl<CTX> $crate::stable_hasher::HashStable<CTX> for $t {
}
impl<CTX> HashStable<CTX> for ::std::num::NonZeroU32 {
+ #[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
self.get().hash_stable(ctx, hasher)
}
}
impl<CTX> HashStable<CTX> for ::std::num::NonZeroUsize {
+ #[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
self.get().hash_stable(ctx, hasher)
}
}
impl<CTX> HashStable<CTX> for ::std::cmp::Ordering {
+ #[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
(*self as i8).hash_stable(ctx, hasher);
}
}
impl<T1: HashStable<CTX>, CTX> HashStable<CTX> for (T1,) {
+ #[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
let (ref _0,) = *self;
_0.hash_stable(ctx, hasher);
/// Returns `true` if any of the primary spans are displayable.
pub fn has_primary_spans(&self) -> bool {
- self.primary_spans.iter().any(|sp| !sp.is_dummy())
+ !self.is_dummy()
}
/// Returns `true` if this contains only a dummy primary span with any hygienic context.
pub fn is_dummy(&self) -> bool {
- let mut is_dummy = true;
- for span in &self.primary_spans {
- if !span.is_dummy() {
- is_dummy = false;
- }
- }
- is_dummy
+ self.primary_spans.iter().all(|sp| sp.is_dummy())
}
/// Replaces all occurrences of one Span with another. Used to move `Span`s in areas that don't
use crate::snippet::Style;
use crate::{
CodeSuggestion, DiagnosticMessage, Level, MultiSpan, Substitution, SubstitutionPart,
- SuggestionStyle, ToolMetadata,
+ SuggestionStyle,
};
use rustc_data_structures::stable_map::FxHashMap;
use rustc_error_messages::FluentValue;
use rustc_lint_defs::{Applicability, LintExpectationId};
-use rustc_serialize::json::Json;
use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
msg: msg.into(),
style,
applicability,
- tool_metadata: Default::default(),
});
self
}
msg: msg.into(),
style: SuggestionStyle::CompletelyHidden,
applicability,
- tool_metadata: Default::default(),
});
self
}
msg: msg.into(),
style,
applicability,
- tool_metadata: Default::default(),
});
self
}
msg: msg.into(),
style: SuggestionStyle::ShowCode,
applicability,
- tool_metadata: Default::default(),
});
self
}
msg: msg.into(),
style: SuggestionStyle::ShowCode,
applicability,
- tool_metadata: Default::default(),
});
self
}
self
}
- /// Adds a suggestion intended only for a tool. The intent is that the metadata encodes
- /// the suggestion in a tool-specific way, as it may not even directly involve Rust code.
- pub fn tool_only_suggestion_with_metadata(
- &mut self,
- msg: impl Into<DiagnosticMessage>,
- applicability: Applicability,
- tool_metadata: Json,
- ) {
- self.push_suggestion(CodeSuggestion {
- substitutions: vec![],
- msg: msg.into(),
- style: SuggestionStyle::CompletelyHidden,
- applicability,
- tool_metadata: ToolMetadata::new(tool_metadata),
- })
- }
-
pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
self.span = sp.into();
if let Some(span) = self.span.primary_span() {
use crate::emitter::{Emitter, HumanReadableErrorType};
use crate::registry::Registry;
use crate::DiagnosticId;
-use crate::ToolMetadata;
use crate::{
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
};
use std::vec;
use rustc_serialize::json::{as_json, as_pretty_json};
-use rustc_serialize::{Encodable, Encoder};
#[cfg(test)]
mod tests;
// The following data types are provided just for serialisation.
-// NOTE: this has a manual implementation of Encodable which needs to be updated in
-// parallel.
+#[derive(Encodable)]
struct Diagnostic {
/// The primary error message.
message: String,
children: Vec<Diagnostic>,
/// The message as rustc would render it.
rendered: Option<String>,
- /// Extra tool metadata
- tool_metadata: ToolMetadata,
-}
-
-macro_rules! encode_fields {
- (
- $enc:expr, // encoder
- $idx:expr, // starting field index
- $struct:expr, // struct we're serializing
- $struct_name:ident, // struct name
- [ $($name:ident),+$(,)? ], // fields to encode
- [ $($ignore:ident),+$(,)? ] // fields we're skipping
- ) => {
- {
- // Pattern match to make sure all fields are accounted for
- let $struct_name { $($name,)+ $($ignore: _,)+ } = $struct;
- let mut idx = $idx;
- $(
- $enc.emit_struct_field(
- stringify!($name),
- idx == 0,
- |enc| $name.encode(enc),
- )?;
- idx += 1;
- )+
- idx
- }
- };
-}
-
-// Special-case encoder to skip tool_metadata if not set
-impl<E: Encoder> Encodable<E> for Diagnostic {
- fn encode(&self, s: &mut E) -> Result<(), E::Error> {
- s.emit_struct(false, |s| {
- let mut idx = 0;
-
- idx = encode_fields!(
- s,
- idx,
- self,
- Self,
- [message, code, level, spans, children, rendered],
- [tool_metadata]
- );
- if self.tool_metadata.is_set() {
- idx = encode_fields!(
- s,
- idx,
- self,
- Self,
- [tool_metadata],
- [message, code, level, spans, children, rendered]
- );
- }
-
- let _ = idx;
- Ok(())
- })
- }
}
#[derive(Encodable)]
spans: DiagnosticSpan::from_suggestion(sugg, &args, je),
children: vec![],
rendered: None,
- tool_metadata: sugg.tool_metadata.clone(),
}
});
.chain(sugg)
.collect(),
rendered: Some(output),
- tool_metadata: ToolMetadata::default(),
}
}
.unwrap_or_else(|| DiagnosticSpan::from_multispan(&diag.span, args, je)),
children: vec![],
rendered: None,
- tool_metadata: ToolMetadata::default(),
}
}
}
LazyFallbackBundle, MultiSpan, SpanLabel, DEFAULT_LOCALE_RESOURCES,
};
pub use rustc_lint_defs::{pluralize, Applicability};
-use rustc_serialize::json::Json;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_span::source_map::SourceMap;
+use rustc_span::HashStableContext;
use rustc_span::{Loc, Span};
use std::borrow::Cow;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
use std::num::NonZeroUsize;
use std::panic;
use std::path::Path;
}
}
-#[derive(Clone, Debug, PartialEq, Default)]
-pub struct ToolMetadata(pub Option<Json>);
-
-impl ToolMetadata {
- fn new(json: Json) -> Self {
- ToolMetadata(Some(json))
- }
-
- fn is_set(&self) -> bool {
- self.0.is_some()
- }
-}
-
-impl Hash for ToolMetadata {
- fn hash<H: Hasher>(&self, _state: &mut H) {}
-}
-
-// Doesn't really need to round-trip
-impl<D: Decoder> Decodable<D> for ToolMetadata {
- fn decode(_d: &mut D) -> Self {
- ToolMetadata(None)
- }
-}
-
-impl<S: Encoder> Encodable<S> for ToolMetadata {
- fn encode(&self, e: &mut S) -> Result<(), S::Error> {
- match &self.0 {
- None => e.emit_unit(),
- Some(json) => json.encode(e),
- }
- }
-}
-
#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
pub struct CodeSuggestion {
/// Each substitute can have multiple variants due to multiple
/// which are useful for users but not useful for
/// tools like rustfix
pub applicability: Applicability,
- /// Tool-specific metadata
- pub tool_metadata: ToolMetadata,
}
#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
path_span: Span,
incl_angl_brckt: bool,
insertion_span: Span,
- anon_lts: String,
) {
- let (replace_span, suggestion) = if incl_angl_brckt {
- (insertion_span, anon_lts)
- } else {
- // When possible, prefer a suggestion that replaces the whole
- // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
- // at a point (which makes for an ugly/confusing label)
- if let Ok(snippet) = source_map.span_to_snippet(path_span) {
- // But our spans can get out of whack due to macros; if the place we think
- // we want to insert `'_` isn't even within the path expression's span, we
- // should bail out of making any suggestion rather than panicking on a
- // subtract-with-overflow or string-slice-out-out-bounds (!)
- // FIXME: can we do better?
- if insertion_span.lo().0 < path_span.lo().0 {
- return;
- }
- let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
- if insertion_index > snippet.len() {
- return;
- }
- let (before, after) = snippet.split_at(insertion_index);
- (path_span, format!("{}{}{}", before, anon_lts, after))
- } else {
- (insertion_span, anon_lts)
- }
- };
- diag.span_suggestion(
- replace_span,
+ diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n)));
+ if source_map.span_to_snippet(insertion_span).is_err() {
+ // Do not try to suggest anything if generated by a proc-macro.
+ return;
+ }
+ let anon_lts = vec!["'_"; n].join(", ");
+ let suggestion =
+ if incl_angl_brckt { format!("<{}>", anon_lts) } else { format!("{}, ", anon_lts) };
+ diag.span_suggestion_verbose(
+ insertion_span.shrink_to_hi(),
&format!("indicate the anonymous lifetime{}", pluralize!(n)),
suggestion,
Applicability::MachineApplicable,
/// Useful type to use with `Result<>` indicate that an error has already
/// been reported to the user, so no need to continue checking.
#[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(HashStable_Generic)]
pub struct ErrorGuaranteed(());
impl ErrorGuaranteed {
ErrorGuaranteed(())
}
}
-
-rustc_data_structures::impl_stable_hash_via_hash!(ErrorGuaranteed);
-use crate::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use crate::def_id::DefId;
use crate::hir;
use rustc_ast as ast;
pub fn descr(self, def_id: DefId) -> &'static str {
match self {
DefKind::Fn => "function",
- DefKind::Mod if def_id.index == CRATE_DEF_INDEX && def_id.krate != LOCAL_CRATE => {
- "crate"
- }
+ DefKind::Mod if def_id.is_crate_root() && !def_id.is_local() => "crate",
DefKind::Mod => "module",
DefKind::Static(..) => "static",
DefKind::Enum => "enum",
}
}
- /// Retrieves the root definition.
- pub fn get_root_def(&self) -> LocalDefId {
- LocalDefId { local_def_index: CRATE_DEF_INDEX }
- }
-
/// Adds a definition with a parent definition.
pub fn create_def(
&mut self,
/// User wrote nothing (e.g., the lifetime in `&u32`).
///
/// The bool indicates whether the user should have written something.
- Implicit(bool),
+ Implicit,
/// Implicit lifetime in a context like `dyn Foo`. This is
/// distinguished from implicit lifetimes elsewhere because the
pub fn ident(&self) -> Ident {
match *self {
LifetimeName::ImplicitObjectLifetimeDefault
- | LifetimeName::Implicit(_)
+ | LifetimeName::Implicit
| LifetimeName::Error => Ident::empty(),
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
pub fn is_elided(&self) -> bool {
match self {
LifetimeName::ImplicitObjectLifetimeDefault
- | LifetimeName::Implicit(_)
+ | LifetimeName::Implicit
| LifetimeName::Underscore => true,
// It might seem surprising that `Fresh(_)` counts as
-use crate::def_id::{LocalDefId, CRATE_DEF_INDEX};
+use crate::def_id::{LocalDefId, CRATE_DEF_ID};
use std::fmt;
/// Uniquely identifies a node in the HIR of the current crate. It is
/// integers starting at zero, so a mapping that maps all or most nodes within
/// an "item-like" to something else can be implemented by a `Vec` instead of a
/// tree or hash map.
+ #[derive(HashStable_Generic)]
pub struct ItemLocalId { .. }
}
-rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId);
+
impl ItemLocalId {
/// Signal local id which should never be used.
pub const INVALID: ItemLocalId = ItemLocalId::MAX;
}
-/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`.
-pub const CRATE_HIR_ID: HirId = HirId {
- owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
- local_id: ItemLocalId::from_u32(0),
-};
+/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
+pub const CRATE_HIR_ID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::from_u32(0) };
| LifetimeName::Param(ParamName::Error)
| LifetimeName::Static
| LifetimeName::Error
- | LifetimeName::Implicit(_)
+ | LifetimeName::Implicit
| LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Underscore => {}
}
let targets = node_set(&query, &edge_filter.target);
filter_nodes(&query, &sources, &targets)
}
- Err(_) => query.nodes().into_iter().collect(),
+ Err(_) => query.nodes().into_iter().map(|n| n.kind).collect(),
};
let edges = filter_edges(&query, &nodes);
}
#[allow(missing_docs)]
-pub struct GraphvizDepGraph<'q>(FxHashSet<&'q DepNode>, Vec<(&'q DepNode, &'q DepNode)>);
+pub struct GraphvizDepGraph(FxHashSet<DepKind>, Vec<(DepKind, DepKind)>);
-impl<'a, 'q> dot::GraphWalk<'a> for GraphvizDepGraph<'q> {
- type Node = &'q DepNode;
- type Edge = (&'q DepNode, &'q DepNode);
- fn nodes(&self) -> dot::Nodes<'_, &'q DepNode> {
+impl<'a> dot::GraphWalk<'a> for GraphvizDepGraph {
+ type Node = DepKind;
+ type Edge = (DepKind, DepKind);
+ fn nodes(&self) -> dot::Nodes<'_, DepKind> {
let nodes: Vec<_> = self.0.iter().cloned().collect();
nodes.into()
}
- fn edges(&self) -> dot::Edges<'_, (&'q DepNode, &'q DepNode)> {
+ fn edges(&self) -> dot::Edges<'_, (DepKind, DepKind)> {
self.1[..].into()
}
- fn source(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode {
+ fn source(&self, edge: &(DepKind, DepKind)) -> DepKind {
edge.0
}
- fn target(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode {
+ fn target(&self, edge: &(DepKind, DepKind)) -> DepKind {
edge.1
}
}
-impl<'a, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> {
- type Node = &'q DepNode;
- type Edge = (&'q DepNode, &'q DepNode);
+impl<'a> dot::Labeller<'a> for GraphvizDepGraph {
+ type Node = DepKind;
+ type Edge = (DepKind, DepKind);
fn graph_id(&self) -> dot::Id<'_> {
dot::Id::new("DependencyGraph").unwrap()
}
- fn node_id(&self, n: &&'q DepNode) -> dot::Id<'_> {
+ fn node_id(&self, n: &DepKind) -> dot::Id<'_> {
let s: String = format!("{:?}", n)
.chars()
.map(|c| if c == '_' || c.is_alphanumeric() { c } else { '_' })
debug!("n={:?} s={:?}", n, s);
dot::Id::new(s).unwrap()
}
- fn node_label(&self, n: &&'q DepNode) -> dot::LabelText<'_> {
+ fn node_label(&self, n: &DepKind) -> dot::LabelText<'_> {
dot::LabelText::label(format!("{:?}", n))
}
}
query: &'q DepGraphQuery,
sources: &Option<FxHashSet<&'q DepNode>>,
targets: &Option<FxHashSet<&'q DepNode>>,
-) -> FxHashSet<&'q DepNode> {
+) -> FxHashSet<DepKind> {
if let Some(sources) = sources {
if let Some(targets) = targets {
walk_between(query, sources, targets)
} else if let Some(targets) = targets {
walk_nodes(query, targets, INCOMING)
} else {
- query.nodes().into_iter().collect()
+ query.nodes().into_iter().map(|n| n.kind).collect()
}
}
query: &'q DepGraphQuery,
starts: &FxHashSet<&'q DepNode>,
direction: Direction,
-) -> FxHashSet<&'q DepNode> {
+) -> FxHashSet<DepKind> {
let mut set = FxHashSet::default();
for &start in starts {
debug!("walk_nodes: start={:?} outgoing?={:?}", start, direction == OUTGOING);
- if set.insert(start) {
+ if set.insert(start.kind) {
let mut stack = vec![query.indices[start]];
while let Some(index) = stack.pop() {
for (_, edge) in query.graph.adjacent_edges(index, direction) {
let neighbor_index = edge.source_or_target(direction);
let neighbor = query.graph.node_data(neighbor_index);
- if set.insert(neighbor) {
+ if set.insert(neighbor.kind) {
stack.push(neighbor_index);
}
}
query: &'q DepGraphQuery,
sources: &FxHashSet<&'q DepNode>,
targets: &FxHashSet<&'q DepNode>,
-) -> FxHashSet<&'q DepNode> {
+) -> FxHashSet<DepKind> {
// This is a bit tricky. We want to include a node only if it is:
// (a) reachable from a source and (b) will reach a target. And we
// have to be careful about cycles etc. Luckily efficiency is not
let index = query.indices[n];
node_states[index.0] == State::Included
})
+ .map(|n| n.kind)
.collect();
fn recurse(query: &DepGraphQuery, node_states: &mut [State], node: NodeIndex) -> bool {
fn filter_edges<'q>(
query: &'q DepGraphQuery,
- nodes: &FxHashSet<&'q DepNode>,
-) -> Vec<(&'q DepNode, &'q DepNode)> {
- query
+ nodes: &FxHashSet<DepKind>,
+) -> Vec<(DepKind, DepKind)> {
+ let uniq: FxHashSet<_> = query
.edges()
.into_iter()
- .filter(|&(source, target)| nodes.contains(source) && nodes.contains(target))
- .collect()
+ .map(|(s, t)| (s.kind, t.kind))
+ .filter(|(source, target)| nodes.contains(source) && nodes.contains(target))
+ .collect();
+ uniq.into_iter().collect()
}
// Avoid fetching the variance if we are in an invariant
// context; no need, and it can induce dependency cycles
// (e.g., #41849).
- relate::relate_substs(self, None, a_subst, b_subst)
+ relate::relate_substs(self, a_subst, b_subst)
} else {
let tcx = self.tcx();
let opt_variances = tcx.variances_of(item_def_id);
- relate::relate_substs(self, Some((item_def_id, &opt_variances)), a_subst, b_subst)
+ relate::relate_substs_with_variances(
+ self,
+ item_def_id,
+ &opt_variances,
+ a_subst,
+ b_subst,
+ )
}
}
// performing trait matching (which then performs equality
// unification).
- relate::relate_substs(self, None, a_subst, b_subst)
+ relate::relate_substs(self, a_subst, b_subst)
}
fn relate_with_variance<T: Relate<'tcx>>(
rustc_feature = { path = "../rustc_feature" }
rustc_index = { path = "../rustc_index" }
rustc_session = { path = "../rustc_session" }
-rustc_serialize = { path = "../rustc_serialize" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_parse_format = { path = "../rustc_parse_format" }
rustc_infer = { path = "../rustc_infer" }
_,
ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. },
_,
+ _,
body,
) = fk
{
use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync;
-use rustc_errors::{struct_span_err, Applicability, MultiSpan, SuggestionStyle};
+use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err};
+use rustc_errors::{Applicability, MultiSpan, SuggestionStyle};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
-use rustc_serialize::json::Json;
-use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec};
+use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
use rustc_session::Session;
use rustc_span::lev_distance::find_best_match_for_name;
) => {
db.span_note(span_def, "the macro is defined here");
}
+ BuiltinLintDiagnostics::ElidedLifetimesInPaths(
+ n,
+ path_span,
+ incl_angl_brckt,
+ insertion_span,
+ ) => {
+ add_elided_lifetime_in_path_suggestion(
+ sess.source_map(),
+ &mut db,
+ n,
+ path_span,
+ incl_angl_brckt,
+ insertion_span,
+ );
+ }
BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => {
db.span_suggestion(span, ¬e, sugg, Applicability::MaybeIncorrect);
}
BuiltinLintDiagnostics::LegacyDeriveHelpers(span) => {
db.span_label(span, "the attribute is introduced here");
}
- BuiltinLintDiagnostics::ExternDepSpec(krate, loc) => {
- let json = match loc {
- ExternDepSpec::Json(json) => {
- db.help(&format!("remove unnecessary dependency `{}`", krate));
- json
- }
- ExternDepSpec::Raw(raw) => {
- db.help(&format!("remove unnecessary dependency `{}` at `{}`", krate, raw));
- db.span_suggestion_with_style(
- DUMMY_SP,
- "raw extern location",
- raw.clone(),
- Applicability::Unspecified,
- SuggestionStyle::CompletelyHidden,
- );
- Json::String(raw)
- }
- };
- db.tool_only_suggestion_with_metadata(
- "json extern location",
- Applicability::Unspecified,
- json
- );
- }
BuiltinLintDiagnostics::ProcMacroBackCompat(note) => {
db.note(¬e);
}
// Explicitly check for lints associated with 'closure_id', since
// it does not have a corresponding AST node
- if let ast_visit::FnKind::Fn(_, _, sig, _, _) = fk {
+ if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk {
if let ast::Async::Yes { closure_id, .. } = sig.header.asyncness {
self.check_id(closure_id);
}
ast_visit::walk_path(self, p);
}
+ fn visit_path_segment(&mut self, path_span: Span, s: &'a ast::PathSegment) {
+ self.check_id(s.id);
+ ast_visit::walk_path_segment(self, path_span, s);
+ }
+
fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
run_early_pass!(self, check_attribute, attr);
}
use rustc_ast::{AttrId, Attribute};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_error_messages::MultiSpan;
+use rustc_hir::HashStableContext;
use rustc_hir::HirId;
-use rustc_serialize::json::Json;
use rustc_span::edition::Edition;
use rustc_span::{sym, symbol::Ident, Span, Symbol};
use rustc_target::spec::abi::Abi;
/// Setting for how to handle a lint.
///
/// See: <https://doc.rust-lang.org/rustc/lints/levels.html>
-#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, HashStable_Generic)]
pub enum Level {
/// The `allow` level will not issue any message.
Allow,
Forbid,
}
-rustc_data_structures::impl_stable_hash_via_hash!(Level);
-
impl Level {
/// Converts a level to a lower-case string.
pub fn as_str(self) -> &'static str {
}
}
-// Duplicated from rustc_session::config::ExternDepSpec to avoid cyclic dependency
-#[derive(PartialEq, Debug)]
-pub enum ExternDepSpec {
- Json(Json),
- Raw(String),
-}
-
// This could be a closure, but then implementing derive trait
// becomes hacky (and it gets allocated).
#[derive(Debug)]
AbsPathWithModule(Span),
ProcMacroDeriveResolutionFallback(Span),
MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
+ ElidedLifetimesInPaths(usize, Span, bool, Span),
UnknownCrateTypes(Span, String, String),
UnusedImports(String, Vec<(Span, String)>, Option<Span>),
RedundantImport(Vec<(Span, bool)>, Ident),
UnusedBuiltinAttribute { attr_name: Symbol, macro_name: String, invoc_span: Span },
PatternsInFnsWithoutBody(Span, Ident),
LegacyDeriveHelpers(Span),
- ExternDepSpec(String, ExternDepSpec),
ProcMacroBackCompat(String),
OrPatternsBackCompat(Span, String),
ReservedPrefix(Span),
/// # extern crate rust_middle;
/// # use rustc_middle::ty::Ty;
/// #[derive(SessionDiagnostic)]
-/// #[error(code = "E0505", slug = "move-out-of-borrow-error")]
+/// #[error(code = "E0505", slug = "borrowck-move-out-of-borrow")]
/// pub struct MoveOutOfBorrowError<'tcx> {
/// pub name: Ident,
/// pub ty: Ty<'tcx>,
/// #[primary_span]
-/// #[label = "cannot move out of borrow"]
+/// #[label]
/// pub span: Span,
-/// #[label = "`{ty}` first borrowed here"]
-/// pub other_span: Span,
-/// #[suggestion(message = "consider cloning here", code = "{name}.clone()")]
-/// pub opt_sugg: Option<(Span, Applicability)>
+/// #[label = "first-borrow-label"]
+/// pub first_borrow_span: Span,
+/// #[suggestion(code = "{name}.clone()")]
+/// pub clone_sugg: Option<(Span, Applicability)>
/// }
/// ```
///
+/// ```fluent
+/// move-out-of-borrow = cannot move out of {$name} because it is borrowed
+/// .label = cannot move out of borrow
+/// .first-borrow-label = `{$ty}` first borrowed here
+/// .suggestion = consider cloning here
+/// ```
+///
/// Then, later, to emit the error:
///
/// ```ignore (pseudo-rust)
/// expected,
/// actual,
/// span,
-/// other_span,
-/// opt_sugg: Some(suggestion, Applicability::MachineApplicable),
+/// first_borrow_span,
+/// clone_sugg: Some(suggestion, Applicability::MachineApplicable),
/// });
/// ```
+///
+/// See rustc dev guide for more examples on using the `#[derive(SessionDiagnostic)]`:
+/// <https://rustc-dev-guide.rust-lang.org/diagnostics/sessiondiagnostic.html>
pub fn session_diagnostic_derive(s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
// Names for the diagnostic we build and the session we build it from.
let diag = format_ident!("diag");
use rustc_hir::definitions::Definitions;
use rustc_index::vec::IndexVec;
use rustc_middle::ty::TyCtxt;
-use rustc_serialize::json::ToJson;
use rustc_session::config::{self, CrateType, ExternLocation};
use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate};
use rustc_session::cstore::{ExternCrateSource, MetadataLoaderDyn};
-use rustc_session::lint::{self, BuiltinLintDiagnostics, ExternDepSpec};
+use rustc_session::lint;
use rustc_session::output::validate_crate_name;
use rustc_session::search_paths::PathKind;
use rustc_session::Session;
use rustc_target::spec::{PanicStrategy, TargetTriple};
use proc_macro::bridge::client::ProcMacro;
-use std::collections::BTreeMap;
use std::ops::Fn;
use std::path::Path;
use std::{cmp, env};
continue;
}
- let diag = match self.sess.opts.extern_dep_specs.get(name) {
- Some(loc) => BuiltinLintDiagnostics::ExternDepSpec(name.clone(), loc.into()),
- None => {
- // If we don't have a specific location, provide a json encoding of the `--extern`
- // option.
- let meta: BTreeMap<String, String> =
- std::iter::once(("name".to_string(), name.to_string())).collect();
- BuiltinLintDiagnostics::ExternDepSpec(
- name.clone(),
- ExternDepSpec::Json(meta.to_json()),
- )
- }
- };
- self.sess.parse_sess.buffer_lint_with_diagnostic(
+ self.sess.parse_sess.buffer_lint(
lint::builtin::UNUSED_CRATE_DEPENDENCIES,
span,
ast::CRATE_NODE_ID,
name,
self.local_crate_name,
name),
- diag,
);
}
}
use rustc_middle::thir;
use rustc_middle::ty::codec::TyDecoder;
use rustc_middle::ty::fast_reject::SimplifiedType;
+use rustc_middle::ty::GeneratorDiagnosticData;
use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
use rustc_serialize::{opaque, Decodable, Decoder};
use rustc_session::cstore::{
.collect()
})
}
+
+ fn get_generator_diagnostic_data(
+ self,
+ tcx: TyCtxt<'tcx>,
+ id: DefIndex,
+ ) -> Option<GeneratorDiagnosticData<'tcx>> {
+ self.root
+ .tables
+ .generator_diagnostic_data
+ .get(self, id)
+ .map(|param| param.decode((self, tcx)))
+ .map(|generator_data| GeneratorDiagnosticData {
+ generator_interior_types: generator_data.generator_interior_types,
+ hir_owner: generator_data.hir_owner,
+ nodes_types: generator_data.nodes_types,
+ adjustments: generator_data.adjustments,
+ })
+ }
+
+ fn get_may_have_doc_links(self, index: DefIndex) -> bool {
+ self.root.tables.may_have_doc_links.get(self, index).is_some()
+ }
}
impl CrateMetadata {
use rustc_ast as ast;
use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
use rustc_middle::metadata::ModChild;
use rustc_middle::middle::exported_symbols::ExportedSymbol;
crate_extern_paths => { cdata.source().paths().cloned().collect() }
expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
+ generator_diagnostic_data => { cdata.get_generator_diagnostic_data(tcx, def_id.index) }
}
pub(in crate::rmeta) fn provide(providers: &mut Providers) {
continue;
}
- bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX });
+ bfs_queue.push_back(cnum.as_def_id());
}
let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &ModChild, parent: DefId| {
) -> impl Iterator<Item = DefId> + '_ {
self.get_crate_data(cnum).get_all_incoherent_impls()
}
+
+ pub fn associated_item_def_ids_untracked<'a>(
+ &'a self,
+ def_id: DefId,
+ sess: &'a Session,
+ ) -> impl Iterator<Item = DefId> + 'a {
+ self.get_crate_data(def_id.krate).get_associated_item_def_ids(def_id.index, sess)
+ }
+
+ pub fn may_have_doc_links_untracked(&self, def_id: DefId) -> bool {
+ self.get_crate_data(def_id.krate).get_may_have_doc_links(def_id.index)
+ }
}
impl CrateStore for CStore {
}
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+ fn encode_attrs(&mut self, def_id: DefId) {
+ let attrs = self.tcx.get_attrs(def_id);
+ record!(self.tables.attributes[def_id] <- attrs);
+ if attrs.iter().any(|attr| attr.may_have_doc_links()) {
+ self.tables.may_have_doc_links.set(def_id.index, ());
+ }
+ }
+
fn encode_def_ids(&mut self) {
if self.is_proc_macro {
return;
let Some(def_kind) = def_kind else { continue };
self.tables.opt_def_kind.set(def_id.index, def_kind);
record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
- record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
+ self.encode_attrs(def_id);
record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
if should_encode_visibility(def_kind) {
record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
fn encode_info_for_closure(&mut self, hir_id: hir::HirId) {
let def_id = self.tcx.hir().local_def_id(hir_id);
debug!("EncodeContext::encode_info_for_closure({:?})", def_id);
-
// NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic,
// including on the signature, which is inferred in `typeck.
- let ty = self.tcx.typeck(def_id).node_type(hir_id);
-
+ let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id);
+ let ty = typeck_result.node_type(hir_id);
match ty.kind() {
ty::Generator(..) => {
let data = self.tcx.generator_kind(def_id).unwrap();
+ let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data();
record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Generator);
record!(self.tables.generator_kind[def_id.to_def_id()] <- data);
+ record!(self.tables.generator_diagnostic_data[def_id.to_def_id()] <- generator_diagnostic_data);
}
ty::Closure(..) => {
let hir = tcx.hir();
let proc_macro_decls_static = tcx.proc_macro_decls_static(()).unwrap().local_def_index;
- let stability = tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX));
+ let stability = tcx.lookup_stability(CRATE_DEF_ID);
let macros =
self.lazy(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index));
let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans();
self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
- record!(self.tables.attributes[LOCAL_CRATE.as_def_id()] <- tcx.get_attrs(LOCAL_CRATE.as_def_id()));
+ self.encode_attrs(LOCAL_CRATE.as_def_id());
record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
if let Some(stability) = stability {
record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability);
let def_id = id.to_def_id();
self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind));
record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
- record!(self.tables.attributes[def_id] <- attrs);
+ self.encode_attrs(def_id);
record!(self.tables.def_keys[def_id] <- def_key);
record!(self.tables.def_ident_span[def_id] <- span);
record!(self.tables.def_span[def_id] <- span);
use rustc_middle::thir;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::GeneratorDiagnosticData;
use rustc_middle::ty::{self, ReprOptions, Ty};
use rustc_serialize::opaque::Encoder;
use rustc_session::config::SymbolManglingVersion;
def_keys: Table<DefIndex, Lazy<DefKey>>,
def_path_hashes: Table<DefIndex, DefPathHash>,
proc_macro_quoted_spans: Table<usize, Lazy<Span>>,
+ generator_diagnostic_data: Table<DefIndex, Lazy<GeneratorDiagnosticData<'tcx>>>,
+ may_have_doc_links: Table<DefIndex, ()>,
}
#[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)]
}
}
+impl FixedSizeEncoding for Option<()> {
+ type ByteArray = [u8; 1];
+
+ #[inline]
+ fn from_bytes(b: &[u8; 1]) -> Self {
+ (b[0] != 0).then(|| ())
+ }
+
+ #[inline]
+ fn write_to_bytes(self, b: &mut [u8; 1]) {
+ b[0] = self.is_some() as u8
+ }
+}
+
// NOTE(eddyb) there could be an impl for `usize`, which would enable a more
// generic `Lazy<T>` impl, but in the general case we might not need / want to
// fit every `usize` in `u32`.
use crate::ty::TyCtxt;
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
use rustc_hir::definitions::DefPathHash;
use rustc_hir::HirId;
use rustc_query_system::dep_graph::FingerprintStyle;
#[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
- let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
+ let def_id = self.as_def_id();
def_id.to_fingerprint(tcx)
}
use rustc_feature::GateIssue;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self, HirId};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
};
}
- let is_staged_api =
- self.lookup_stability(DefId { index: CRATE_DEF_INDEX, ..def_id }).is_some();
+ let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
if !is_staged_api {
return EvalResult::Allow;
}
/// `get_bytes_with_uninit_and_ptr` instead,
///
/// This function also guarantees that the resulting pointer will remain stable
- /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
+ /// even when new allocations are pushed to the `HashMap`. `mem_copy_repeatedly` relies
/// on that.
///
/// It is the caller's responsibility to check bounds and alignment beforehand.
let val = match val {
ScalarMaybeUninit::Scalar(scalar) => scalar,
ScalarMaybeUninit::Uninit => {
- self.mark_init(range, false);
- return Ok(());
+ return self.write_uninit(cx, range);
}
};
Ok(())
}
+
+ /// Write "uninit" to the given memory range.
+ pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
+ self.mark_init(range, false);
+ self.clear_relocations(cx, range)?;
+ return Ok(());
+ }
}
/// Relocations.
if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE {
return Err(AllocError::PartialPointerOverwrite(first));
}
+ warn!(
+ "Partial pointer overwrite! De-initializing memory at offsets {first:?}..{start:?}."
+ );
self.init_mask.set_range(first, start, false);
}
if last > end {
last - cx.data_layout().pointer_size,
));
}
+ warn!(
+ "Partial pointer overwrite! De-initializing memory at offsets {end:?}..{last:?}."
+ );
self.init_mask.set_range(end, last, false);
}
// Forget all the relocations.
+ // Since relocations do not overlap, we know that removing until `last` (exclusive) is fine,
+ // i.e., this will not remove any other relocations just after the ones we care about.
self.relocations.0.remove_range(first..last);
Ok(())
}
/// A partial, owned list of relocations to transfer into another allocation.
+///
+/// Offsets are already adjusted to the destination allocation.
pub struct AllocationRelocations<Tag> {
- relative_relocations: Vec<(Size, Tag)>,
+ dest_relocations: Vec<(Size, Tag)>,
}
impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
) -> AllocationRelocations<Tag> {
let relocations = self.get_relocations(cx, src);
if relocations.is_empty() {
- return AllocationRelocations { relative_relocations: Vec::new() };
+ return AllocationRelocations { dest_relocations: Vec::new() };
}
let size = src.size;
let mut new_relocations = Vec::with_capacity(relocations.len() * (count as usize));
+ // If `count` is large, this is rather wasteful -- we are allocating a big array here, which
+ // is mostly filled with redundant information since it's just N copies of the same `Tag`s
+ // at slightly adjusted offsets. The reason we do this is so that in `mark_relocation_range`
+ // we can use `insert_presorted`. That wouldn't work with an `Iterator` that just produces
+ // the right sequence of relocations for all N copies.
for i in 0..count {
new_relocations.extend(relocations.iter().map(|&(offset, reloc)| {
// compute offset for current repetition
}));
}
- AllocationRelocations { relative_relocations: new_relocations }
+ AllocationRelocations { dest_relocations: new_relocations }
}
/// Applies a relocation copy.
/// The affected range, as defined in the parameters to `prepare_relocation_copy` is expected
/// to be clear of relocations.
+ ///
+ /// This is dangerous to use as it can violate internal `Allocation` invariants!
+ /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations<Tag>) {
- self.relocations.0.insert_presorted(relocations.relative_relocations);
+ self.relocations.0.insert_presorted(relocations.dest_relocations);
}
}
})
}
- pub fn mark_init(&mut self, range: AllocRange, is_init: bool) {
+ fn mark_init(&mut self, range: AllocRange, is_init: bool) {
if range.size.bytes() == 0 {
return;
}
}
/// Applies multiple instances of the run-length encoding to the initialization mask.
+ ///
+ /// This is dangerous to use as it can violate internal `Allocation` invariants!
+ /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
pub fn mark_compressed_init_range(
&mut self,
defined: &InitMaskCompressed,
}
static_assert_size!(Pointer, 16);
+// `Option<Tag>` pointers are also passed around quite a bit
+// (but not stored in permanent machine state).
+static_assert_size!(Pointer<Option<AllocId>>, 16);
// We want the `Debug` output to be readable as it is used by `derive(Debug)` for
// all the Miri types.
}
impl<Tag> Pointer<Option<Tag>> {
+ /// Convert this pointer that *might* have a tag into a pointer that *definitely* has a tag, or
+ /// an absolute address.
+ ///
+ /// This is rarely what you want; call `ptr_try_get_alloc_id` instead.
pub fn into_pointer_or_addr(self) -> Result<Pointer<Tag>, Size> {
match self.provenance {
Some(tag) => Ok(Pointer::new(tag, self.offset)),
None => Err(self.offset),
}
}
+
+ /// Returns the absolute address the pointer points to.
+ /// Only works if Tag::OFFSET_IS_ADDR is true!
+ pub fn addr(self) -> Size
+ where
+ Tag: Provenance,
+ {
+ assert!(Tag::OFFSET_IS_ADDR);
+ self.offset
+ }
}
impl<Tag> Pointer<Option<Tag>> {
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::{CtorKind, Namespace};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
use rustc_hir::{self, GeneratorKind};
use rustc_hir::{self as hir, HirId};
use rustc_session::Session;
pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
let mut body = Body {
phase: MirPhase::Built,
- source: MirSource::item(DefId::local(CRATE_DEF_INDEX)),
+ source: MirSource::item(CRATE_DEF_ID.to_def_id()),
basic_blocks,
source_scopes: IndexVec::new(),
generator: None,
}
if let Some(&tag) = alloc.relocations().get(&i) {
// Memory with a relocation must be defined
+ assert!(alloc.init_mask().is_range_initialized(i, i + ptr_size).is_ok());
let j = i.bytes_usize();
let offset = alloc
.inspect_with_uninit_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize());
eval_always
desc { "computing the backend features for CLI flags" }
}
+
+ query generator_diagnostic_data(key: DefId) -> Option<GeneratorDiagnosticData<'tcx>> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
+ }
}
static_assert_size!(ConstS<'_>, 48);
impl<'tcx> Const<'tcx> {
+ #[inline]
pub fn ty(self) -> Ty<'tcx> {
self.0.ty
}
+ #[inline]
pub fn val(self) -> ConstKind<'tcx> {
self.0.val
}
pub expr: Option<hir::HirId>,
}
+// This type holds diagnostic information on generators and async functions across crate boundaries
+// and is used to provide better error messages
+#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
+pub struct GeneratorDiagnosticData<'tcx> {
+ pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
+ pub hir_owner: DefId,
+ pub nodes_types: ItemLocalMap<Ty<'tcx>>,
+ pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
+}
+
#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
pub struct TypeckResults<'tcx> {
/// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
}
+ pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
+ let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
+ vec.iter()
+ .map(|item| {
+ GeneratorInteriorTypeCause {
+ ty: item.ty,
+ span: item.span,
+ scope_span: item.scope_span,
+ yield_span: item.yield_span,
+ expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
+ }
+ })
+ .collect::<Vec<_>>()
+ });
+ GeneratorDiagnosticData {
+ generator_interior_types: generator_interior_type,
+ hir_owner: self.hir_owner.to_def_id(),
+ nodes_types: self.node_types.clone(),
+ adjustments: self.adjustments.clone(),
+ }
+ }
+
pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
self.node_type_opt(id).unwrap_or_else(|| {
bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id)))
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_ID};
use rustc_hir::Node;
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
};
pub use self::context::{
tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
- CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt,
- Lift, OnDiskCache, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex,
+ CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData,
+ GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
+ UserTypeAnnotationIndex,
};
pub use self::instance::{Instance, InstanceDef};
pub use self::list::List;
pub fn from_hir(visibility: &hir::Visibility<'_>, id: hir::HirId, tcx: TyCtxt<'_>) -> Self {
match visibility.node {
hir::VisibilityKind::Public => Visibility::Public,
- hir::VisibilityKind::Crate(_) => Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)),
+ hir::VisibilityKind::Crate(_) => Visibility::Restricted(CRATE_DEF_ID.to_def_id()),
hir::VisibilityKind::Restricted { ref path, .. } => match path.res {
// If there is no resolution, `resolve` will have already reported an error, so
// assume that the visibility is public to avoid reporting more privacy errors.
}
fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
- if def_id.index == CRATE_DEF_INDEX {
- Some(self.crate_name(def_id.krate))
+ if let Some(cnum) = def_id.as_crate_root() {
+ Some(self.crate_name(cnum))
} else {
let def_key = self.def_key(def_id);
match def_key.disambiguated_data.data {
use rustc_data_structures::sso::SsoHashSet;
use rustc_hir as hir;
use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
-use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
use rustc_session::config::TrimmedDefPaths;
use rustc_session::cstore::{ExternCrate, ExternCrateSource};
// If `def_id` is a direct or injected extern crate, return the
// path to the crate followed by the path to the item within the crate.
- if def_id.index == CRATE_DEF_INDEX {
- let cnum = def_id.krate;
-
+ if let Some(cnum) = def_id.as_crate_root() {
if cnum == LOCAL_CRATE {
return Ok((self.path_crate(cnum)?, true));
}
ty::BrNamed(_, _) => br.kind,
ty::BrAnon(i) => {
let name = region_map[&(i + 1)];
- ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+ ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
}
ty::BrEnv => {
let name = region_map[&0];
- ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+ ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
}
};
self.tcx.mk_region(ty::ReLateBound(
}
};
do_continue(&mut self, name);
- ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+ ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
}
};
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
let mut seen_defs: DefIdSet = Default::default();
for &cnum in tcx.crates(()).iter() {
- let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+ let def_id = cnum.as_def_id();
// Ignore crates that are not direct dependencies.
match tcx.extern_crate(def_id) {
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::util::AlwaysRequiresDrop;
+use crate::ty::GeneratorDiagnosticData;
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
+use rustc_ast as ast;
use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_attr as attr;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
use rustc_session::utils::NativeLibKind;
use rustc_session::Limits;
-use rustc_target::abi;
-use rustc_target::spec::PanicStrategy;
-
-use rustc_ast as ast;
-use rustc_attr as attr;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi;
+use rustc_target::spec::PanicStrategy;
use std::ops::Deref;
use std::path::PathBuf;
use std::sync::Arc;
let tcx = self.tcx();
let opt_variances = tcx.variances_of(item_def_id);
- relate_substs(self, Some((item_def_id, opt_variances)), a_subst, b_subst)
+ relate_substs_with_variances(self, item_def_id, opt_variances, a_subst, b_subst)
}
/// Switch variance for the purpose of relating `a` and `b`.
}
}
+#[inline]
pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>(
relation: &mut R,
- variances: Option<(DefId, &[ty::Variance])>,
+ a_subst: SubstsRef<'tcx>,
+ b_subst: SubstsRef<'tcx>,
+) -> RelateResult<'tcx, SubstsRef<'tcx>> {
+ relation.tcx().mk_substs(iter::zip(a_subst, b_subst).map(|(a, b)| {
+ relation.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)
+ }))
+}
+
+pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ ty_def_id: DefId,
+ variances: &[ty::Variance],
a_subst: SubstsRef<'tcx>,
b_subst: SubstsRef<'tcx>,
) -> RelateResult<'tcx, SubstsRef<'tcx>> {
let tcx = relation.tcx();
- let mut cached_ty = None;
+ let mut cached_ty = None;
let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
- let (variance, variance_info) = match variances {
- Some((ty_def_id, variances)) => {
- let variance = variances[i];
- let variance_info = if variance == ty::Invariant {
- let ty = *cached_ty
- .get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
- ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
- } else {
- ty::VarianceDiagInfo::default()
- };
- (variance, variance_info)
- }
- None => (ty::Invariant, ty::VarianceDiagInfo::default()),
+ let variance = variances[i];
+ let variance_info = if variance == ty::Invariant {
+ let ty = *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
+ ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
+ } else {
+ ty::VarianceDiagInfo::default()
};
relation.relate_with_variance(variance, variance_info, a, b)
});
if a.def_id != b.def_id {
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
} else {
- let substs = relate_substs(relation, None, a.substs, b.substs)?;
+ let substs = relate_substs(relation, a.substs, b.substs)?;
Ok(ty::TraitRef { def_id: a.def_id, substs })
}
}
if a.def_id != b.def_id {
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
} else {
- let substs = relate_substs(relation, None, a.substs, b.substs)?;
+ let substs = relate_substs(relation, a.substs, b.substs)?;
Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs })
}
}
(&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
if a_def_id == b_def_id =>
{
- let substs = relate_substs(relation, None, a_substs, b_substs)?;
+ let substs = relate_substs(relation, a_substs, b_substs)?;
Ok(tcx.mk_opaque(a_def_id, substs))
}
a: ty::ClosureSubsts<'tcx>,
b: ty::ClosureSubsts<'tcx>,
) -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> {
- let substs = relate_substs(relation, None, a.substs, b.substs)?;
+ let substs = relate_substs(relation, a.substs, b.substs)?;
Ok(ty::ClosureSubsts { substs })
}
}
a: ty::GeneratorSubsts<'tcx>,
b: ty::GeneratorSubsts<'tcx>,
) -> RelateResult<'tcx, ty::GeneratorSubsts<'tcx>> {
- let substs = relate_substs(relation, None, a.substs, b.substs)?;
+ let substs = relate_substs(relation, a.substs, b.substs)?;
Ok(ty::GeneratorSubsts { substs })
}
}
a: SubstsRef<'tcx>,
b: SubstsRef<'tcx>,
) -> RelateResult<'tcx, SubstsRef<'tcx>> {
- relate_substs(relation, None, a, b)
+ relate_substs(relation, a, b)
}
}
use rustc_data_structures::functor::IdFunctor;
use rustc_hir as hir;
use rustc_hir::def::Namespace;
-use rustc_hir::def_id::CRATE_DEF_INDEX;
use rustc_index::vec::{Idx, IndexVec};
use std::fmt;
match *self {
ty::BrAnon(n) => write!(f, "BrAnon({:?})", n),
ty::BrNamed(did, name) => {
- if did.index == CRATE_DEF_INDEX {
+ if did.is_crate_root() {
write!(f, "BrNamed({})", name)
} else {
write!(f, "BrNamed({:?}, {})", did, name)
func: fun,
args,
cleanup: None,
- // FIXME(varkor): replace this with an uninhabitedness-based check.
- // This requires getting access to the current module to call
- // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
- destination: if expr.ty.is_never() {
+ // The presence or absence of a return edge affects control-flow sensitive
+ // MIR checks and ultimately whether code is accepted or not. We can only
+ // omit the return edge if a return type is visibly uninhabited to a module
+ // that makes the call.
+ destination: if this.tcx.is_ty_uninhabited_from(
+ this.parent_module,
+ expr.ty,
+ this.param_env,
+ ) {
None
} else {
Some((destination, success))
def_id: DefId,
hir_id: hir::HirId,
+ parent_module: DefId,
check_overflow: bool,
fn_span: Span,
arg_count: usize,
);
let lint_level = LintLevel::Explicit(hir_id);
+ let param_env = tcx.param_env(def.did);
let mut builder = Builder {
thir,
tcx,
infcx,
typeck_results: tcx.typeck_opt_const_arg(def),
region_scope_tree: tcx.region_scope_tree(def.did),
- param_env: tcx.param_env(def.did),
+ param_env,
def_id: def.did.to_def_id(),
hir_id,
+ parent_module: tcx.parent_module(hir_id).to_def_id(),
check_overflow,
cfg: CFG { basic_blocks: IndexVec::new() },
fn_span: span,
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::definitions::DefPathDataName;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::exported_symbols::SymbolExportLevel;
let mut cgu_def_id = None;
// Walk backwards from the item we want to find the module for.
loop {
- if current_def_id.index == CRATE_DEF_INDEX {
+ if current_def_id.is_crate_root() {
if cgu_def_id.is_none() {
// If we have not found a module yet, take the crate root.
- cgu_def_id = Some(DefId { krate: def_id.krate, index: CRATE_DEF_INDEX });
+ cgu_def_id = Some(def_id.krate.as_def_id());
}
break;
} else if tcx.def_kind(current_def_id) == DefKind::Mod {
impl CreateTokenStream for LazyTokenStreamImpl {
fn create_token_stream(&self) -> AttrAnnotatedTokenStream {
- // The token produced by the final call to `{,inlined_}next` or
- // `{,inlined_}next_desugared` was not actually consumed by the
- // callback. The combination of chaining the initial token and using
- // `take` produces the desired result - we produce an empty
- // `TokenStream` if no calls were made, and omit the final token
- // otherwise.
+ // The token produced by the final call to `{,inlined_}next` was not
+ // actually consumed by the callback. The combination of chaining the
+ // initial token and using `take` produces the desired result - we
+ // produce an empty `TokenStream` if no calls were made, and omit the
+ // final token otherwise.
let mut cursor_snapshot = self.cursor_snapshot.clone();
let tokens =
std::iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1))
.chain((0..self.num_calls).map(|_| {
- let token = if cursor_snapshot.desugar_doc_comments {
- cursor_snapshot.next_desugared()
- } else {
- cursor_snapshot.next()
- };
+ let token = cursor_snapshot.next(cursor_snapshot.desugar_doc_comments);
(FlatToken::Token(token.0), token.1)
}))
.take(self.num_calls);
pub capture_cfg: bool,
restrictions: Restrictions,
expected_tokens: Vec<TokenType>,
- // Important: This must only be advanced from `next_tok`
- // to ensure that `token_cursor.num_next_calls` is updated properly
+ // Important: This must only be advanced from `bump` to ensure that
+ // `token_cursor.num_next_calls` is updated properly.
token_cursor: TokenCursor,
desugar_doc_comments: bool,
/// This field is used to keep track of how many left angle brackets we have seen. This is
pub current_closure: Option<ClosureSpans>,
}
+// This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure
+// it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Parser<'_>, 328);
+
/// Stores span information about a closure.
#[derive(Clone)]
pub struct ClosureSpans {
#[derive(Clone)]
struct TokenCursor {
+ // The current (innermost) frame. `frame` and `stack` could be combined,
+ // but it's faster to have them separately to access `frame` directly
+ // rather than via something like `stack.last().unwrap()` or
+ // `stack[stack.len() - 1]`.
frame: TokenCursorFrame,
+ // Additional frames that enclose `frame`.
stack: Vec<TokenCursorFrame>,
desugar_doc_comments: bool,
- // Counts the number of calls to `{,inlined_}next` or
- // `{,inlined_}next_desugared`, depending on whether
- // `desugar_doc_comments` is set.
+ // Counts the number of calls to `{,inlined_}next`.
num_next_calls: usize,
// During parsing, we may sometimes need to 'unglue' a
// glued token into two component tokens
struct TokenCursorFrame {
delim: token::DelimToken,
span: DelimSpan,
- open_delim: bool,
tree_cursor: tokenstream::Cursor,
- close_delim: bool,
}
impl TokenCursorFrame {
fn new(span: DelimSpan, delim: DelimToken, tts: TokenStream) -> Self {
- TokenCursorFrame {
- delim,
- span,
- open_delim: false,
- tree_cursor: tts.into_trees(),
- close_delim: false,
- }
+ TokenCursorFrame { delim, span, tree_cursor: tts.into_trees() }
}
}
impl TokenCursor {
- fn next(&mut self) -> (Token, Spacing) {
- self.inlined_next()
+ fn next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) {
+ self.inlined_next(desugar_doc_comments)
}
/// This always-inlined version should only be used on hot code paths.
#[inline(always)]
- fn inlined_next(&mut self) -> (Token, Spacing) {
+ fn inlined_next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) {
loop {
- let (tree, spacing) = if !self.frame.open_delim {
- self.frame.open_delim = true;
- TokenTree::open_tt(self.frame.span, self.frame.delim).into()
- } else if let Some(tree) = self.frame.tree_cursor.next_with_spacing() {
- tree
- } else if !self.frame.close_delim {
- self.frame.close_delim = true;
- TokenTree::close_tt(self.frame.span, self.frame.delim).into()
+ // FIXME: we currently don't return `NoDelim` open/close delims. To fix #67062 we will
+ // need to, whereupon the `delim != DelimToken::NoDelim` conditions below can be
+ // removed, as well as the loop.
+ if let Some((tree, spacing)) = self.frame.tree_cursor.next_with_spacing_ref() {
+ match tree {
+ &TokenTree::Token(ref token) => match (desugar_doc_comments, token) {
+ (true, &Token { kind: token::DocComment(_, attr_style, data), span }) => {
+ return self.desugar(attr_style, data, span);
+ }
+ _ => return (token.clone(), *spacing),
+ },
+ &TokenTree::Delimited(sp, delim, ref tts) => {
+ // Set `open_delim` to true here because we deal with it immediately.
+ let frame = TokenCursorFrame::new(sp, delim, tts.clone());
+ self.stack.push(mem::replace(&mut self.frame, frame));
+ if delim != DelimToken::NoDelim {
+ return (Token::new(token::OpenDelim(delim), sp.open), Spacing::Alone);
+ }
+ // No open delimeter to return; continue on to the next iteration.
+ }
+ };
} else if let Some(frame) = self.stack.pop() {
+ let delim = self.frame.delim;
+ let span = self.frame.span;
self.frame = frame;
- continue;
- } else {
- (TokenTree::Token(Token::new(token::Eof, DUMMY_SP)), Spacing::Alone)
- };
-
- match tree {
- TokenTree::Token(token) => {
- return (token, spacing);
- }
- TokenTree::Delimited(sp, delim, tts) => {
- let frame = TokenCursorFrame::new(sp, delim, tts);
- self.stack.push(mem::replace(&mut self.frame, frame));
+ if delim != DelimToken::NoDelim {
+ return (Token::new(token::CloseDelim(delim), span.close), Spacing::Alone);
}
+ // No close delimiter to return; continue on to the next iteration.
+ } else {
+ return (Token::new(token::Eof, DUMMY_SP), Spacing::Alone);
}
}
}
- fn next_desugared(&mut self) -> (Token, Spacing) {
- self.inlined_next_desugared()
- }
-
- /// This always-inlined version should only be used on hot code paths.
- #[inline(always)]
- fn inlined_next_desugared(&mut self) -> (Token, Spacing) {
- let (data, attr_style, sp) = match self.inlined_next() {
- (Token { kind: token::DocComment(_, attr_style, data), span }, _) => {
- (data, attr_style, span)
- }
- tok => return tok,
- };
-
+ fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> (Token, Spacing) {
// Searches for the occurrences of `"#*` and returns the minimum number of `#`s
// required to wrap the text.
let mut num_of_hashes = 0;
num_of_hashes = cmp::max(num_of_hashes, count);
}
- let delim_span = DelimSpan::from_single(sp);
+ let delim_span = DelimSpan::from_single(span);
let body = TokenTree::Delimited(
delim_span,
token::Bracket,
[
- TokenTree::token(token::Ident(sym::doc, false), sp),
- TokenTree::token(token::Eq, sp),
- TokenTree::token(TokenKind::lit(token::StrRaw(num_of_hashes), data, None), sp),
+ TokenTree::token(token::Ident(sym::doc, false), span),
+ TokenTree::token(token::Eq, span),
+ TokenTree::token(TokenKind::lit(token::StrRaw(num_of_hashes), data, None), span),
]
.iter()
.cloned()
delim_span,
token::NoDelim,
if attr_style == AttrStyle::Inner {
- [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body]
+ [TokenTree::token(token::Pound, span), TokenTree::token(token::Not, span), body]
.iter()
.cloned()
.collect::<TokenStream>()
} else {
- [TokenTree::token(token::Pound, sp), body]
+ [TokenTree::token(token::Pound, span), body]
.iter()
.cloned()
.collect::<TokenStream>()
),
));
- self.next()
+ self.next(/* desugar_doc_comments */ false)
}
}
desugar_doc_comments: bool,
subparser_name: Option<&'static str>,
) -> Self {
- let mut start_frame = TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, tokens);
- start_frame.open_delim = true;
- start_frame.close_delim = true;
+ // Note: because of the way `TokenCursor::inlined_next` is structured, the `span` and
+ // `delim` arguments here are never used.
+ let start_frame = TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, tokens);
let mut parser = Parser {
sess,
parser
}
- #[inline]
- fn next_tok(&mut self, fallback_span: Span) -> (Token, Spacing) {
- loop {
- let (mut next, spacing) = if self.desugar_doc_comments {
- self.token_cursor.inlined_next_desugared()
- } else {
- self.token_cursor.inlined_next()
- };
- self.token_cursor.num_next_calls += 1;
- // We've retrieved an token from the underlying
- // cursor, so we no longer need to worry about
- // an unglued token. See `break_and_eat` for more details
- self.token_cursor.break_last_token = false;
- if next.span.is_dummy() {
- // Tweak the location for better diagnostics, but keep syntactic context intact.
- next.span = fallback_span.with_ctxt(next.span.ctxt());
- }
- if matches!(
- next.kind,
- token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim)
- ) {
- continue;
- }
- return (next, spacing);
- }
- }
-
pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
match self.expect_one_of(&[], &[]) {
Err(e) => Err(e),
//
// If we consume any additional tokens, then this token
// is not needed (we'll capture the entire 'glued' token),
- // and `next_tok` will set this field to `None`
+ // and `bump` will set this field to `None`
self.token_cursor.break_last_token = true;
// Use the spacing of the glued token as the spacing
// of the unglued second token.
/// This always-inlined version should only be used on hot code paths.
#[inline(always)]
fn inlined_bump_with(&mut self, (next_token, next_spacing): (Token, Spacing)) {
- // Bumping after EOF is a bad sign, usually an infinite loop.
- if self.prev_token.kind == TokenKind::Eof {
- let msg = "attempted to bump the parser past EOF (may be stuck in a loop)";
- self.span_bug(self.token.span, msg);
- }
-
// Update the current and previous tokens.
self.prev_token = mem::replace(&mut self.token, next_token);
self.token_spacing = next_spacing;
/// Advance the parser by one token.
pub fn bump(&mut self) {
- let next_token = self.next_tok(self.token.span);
- self.inlined_bump_with(next_token);
+ // Note: destructuring here would give nicer code, but it was found in #96210 to be slower
+ // than `.0`/`.1` access.
+ let mut next = self.token_cursor.inlined_next(self.desugar_doc_comments);
+ self.token_cursor.num_next_calls += 1;
+ // We've retrieved an token from the underlying
+ // cursor, so we no longer need to worry about
+ // an unglued token. See `break_and_eat` for more details
+ self.token_cursor.break_last_token = false;
+ if next.0.span.is_dummy() {
+ // Tweak the location for better diagnostics, but keep syntactic context intact.
+ let fallback_span = self.token.span;
+ next.0.span = fallback_span.with_ctxt(next.0.span.ctxt());
+ }
+ debug_assert!(!matches!(
+ next.0.kind,
+ token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim)
+ ));
+ self.inlined_bump_with(next)
}
/// Look-ahead `dist` tokens of `self.token` and get access to that token there.
let mut i = 0;
let mut token = Token::dummy();
while i < dist {
- token = cursor.next().0;
+ token = cursor.next(/* desugar_doc_comments */ false).0;
if matches!(
token.kind,
token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim)
pub(crate) fn parse_token_tree(&mut self) -> TokenTree {
match self.token.kind {
token::OpenDelim(..) => {
- let depth = self.token_cursor.stack.len();
+ // Grab the tokens from this frame.
+ let frame = &self.token_cursor.frame;
+ let stream = frame.tree_cursor.stream.clone();
+ let span = frame.span;
+ let delim = frame.delim;
- // We keep advancing the token cursor until we hit
- // the matching `CloseDelim` token.
- while !(depth == self.token_cursor.stack.len()
- && matches!(self.token.kind, token::CloseDelim(_)))
- {
+ // Advance the token cursor through the entire delimited
+ // sequence. After getting the `OpenDelim` we are *within* the
+ // delimited sequence, i.e. at depth `d`. After getting the
+ // matching `CloseDelim` we are *after* the delimited sequence,
+ // i.e. at depth `d - 1`.
+ let target_depth = self.token_cursor.stack.len() - 1;
+ loop {
// Advance one token at a time, so `TokenCursor::next()`
// can capture these tokens if necessary.
self.bump();
+ if self.token_cursor.stack.len() == target_depth {
+ debug_assert!(matches!(self.token.kind, token::CloseDelim(_)));
+ break;
+ }
}
- // We are still inside the frame corresponding
- // to the delimited stream we captured, so grab
- // the tokens from this frame.
- let frame = &self.token_cursor.frame;
- let stream = frame.tree_cursor.stream.clone();
- let span = frame.span;
- let delim = frame.delim;
+
// Consume close delimiter
self.bump();
TokenTree::Delimited(span, delim, stream)
impl<'a> Parser<'a> {
/// Checks whether a non-terminal may begin with a particular token.
///
- /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that
- /// token. Be conservative (return true) if not sure.
+ /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with
+ /// that token. Be conservative (return true) if not sure. Inlined because it has a single call
+ /// site.
+ #[inline]
pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool {
/// Checks whether the non-terminal may contain a single (non-keyword) identifier.
fn may_be_ident(nt: &token::Nonterminal) -> bool {
}
}
- /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`).
+ /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call
+ /// site.
+ #[inline]
pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, NtOrTt> {
// Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`)
// needs to have them force-captured here.
use rustc_ast::entry::EntryPointType;
use rustc_errors::struct_span_err;
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
-use rustc_middle::hir::map::Map;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{DefIdTree, TyCtxt};
use rustc_session::config::{CrateType, EntryFnType};
use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::{Span, DUMMY_SP};
-struct EntryContext<'a, 'tcx> {
- session: &'a Session,
-
- map: Map<'tcx>,
+struct EntryContext<'tcx> {
+ tcx: TyCtxt<'tcx>,
/// The function that has attribute named `main`.
attr_main_fn: Option<(LocalDefId, Span)>,
non_main_fns: Vec<Span>,
}
-impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
+impl<'tcx> ItemLikeVisitor<'tcx> for EntryContext<'tcx> {
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
- let def_key = self.map.def_key(item.def_id);
- let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
+ let at_root = self.tcx.local_parent(item.def_id) == Some(CRATE_DEF_ID);
find_item(item, self, at_root);
}
return None;
}
- let mut ctxt = EntryContext {
- session: tcx.sess,
- map: tcx.hir(),
- attr_main_fn: None,
- start_fn: None,
- non_main_fns: Vec::new(),
- };
+ let mut ctxt =
+ EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() };
tcx.hir().visit_all_item_likes(&mut ctxt);
// Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
// (with `ast::Item`), so make sure to keep them in sync.
-fn entry_point_type(ctxt: &EntryContext<'_, '_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
- let attrs = ctxt.map.attrs(item.hir_id());
- if ctxt.session.contains_name(attrs, sym::start) {
+fn entry_point_type(ctxt: &EntryContext<'_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
+ let attrs = ctxt.tcx.hir().attrs(item.hir_id());
+ if ctxt.tcx.sess.contains_name(attrs, sym::start) {
EntryPointType::Start
- } else if ctxt.session.contains_name(attrs, sym::rustc_main) {
+ } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
EntryPointType::MainAttr
} else if item.ident.name == sym::main {
if at_root {
.emit();
}
-fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
+fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) {
match entry_point_type(ctxt, item, at_root) {
EntryPointType::None => (),
_ if !matches!(item.kind, ItemKind::Fn(..)) => {
- let attrs = ctxt.map.attrs(item.hir_id());
- if let Some(attr) = ctxt.session.find_by_name(attrs, sym::start) {
- throw_attr_err(&ctxt.session, attr.span, "start");
+ let attrs = ctxt.tcx.hir().attrs(item.hir_id());
+ if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) {
+ throw_attr_err(&ctxt.tcx.sess, attr.span, "start");
}
- if let Some(attr) = ctxt.session.find_by_name(attrs, sym::rustc_main) {
- throw_attr_err(&ctxt.session, attr.span, "rustc_main");
+ if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::rustc_main) {
+ throw_attr_err(&ctxt.tcx.sess, attr.span, "rustc_main");
}
}
EntryPointType::MainNamed => (),
ctxt.attr_main_fn = Some((item.def_id, item.span));
} else {
struct_span_err!(
- ctxt.session,
+ ctxt.tcx.sess,
item.span,
E0137,
"multiple functions with a `#[main]` attribute"
if ctxt.start_fn.is_none() {
ctxt.start_fn = Some((item.def_id, item.span));
} else {
- struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions")
+ struct_span_err!(ctxt.tcx.sess, item.span, E0138, "multiple `start` functions")
.span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
.span_label(item.span, "multiple `start` functions")
.emit();
}
}
-fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> {
+fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
if let Some((def_id, _)) = visitor.start_fn {
Some((def_id.to_def_id(), EntryFnType::Start))
} else if let Some((def_id, _)) = visitor.attr_main_fn {
}
}
-fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
+fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
let sp = tcx.def_span(CRATE_DEF_ID);
if *tcx.sess.parse_sess.reached_eof.borrow() {
// There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lock;
use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::intravisit;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::{HirId, ItemLocalId};
self.owner = Some(owner);
walk(self);
- if owner.local_def_index == CRATE_DEF_INDEX {
+ if owner == CRATE_DEF_ID {
return;
}
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.def_id) else {
return;
};
- let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+ let def_id = cnum.as_def_id();
self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None);
}
use measureme::{StringComponent, StringId};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::profiling::SelfProfiler;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::DefPathData;
use rustc_middle::ty::{TyCtxt, WithOptConstParam};
use rustc_query_system::query::QueryCache;
&self,
builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
) -> StringId {
- builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX })
+ builder.def_id_to_string_id(self.as_def_id())
}
}
use rustc_expand::base::SyntaxExtension;
use rustc_expand::expand::AstFragment;
use rustc_hir::def::{self, *};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
use rustc_metadata::creader::LoadedMacro;
use rustc_middle::bug;
use rustc_middle::metadata::ModChild;
let parent = def_key.parent.map(|index| {
self.get_nearest_non_block_module(DefId { index, krate: def_id.krate })
});
- let name = if def_id.index == CRATE_DEF_INDEX {
- self.cstore().crate_name(def_id.krate)
+ let name = if let Some(cnum) = def_id.as_crate_root() {
+ self.cstore().crate_name(cnum)
} else {
def_key.disambiguated_data.data.get_opt_name().expect("module without name")
};
match vis.kind {
ast::VisibilityKind::Public => Ok(ty::Visibility::Public),
ast::VisibilityKind::Crate(..) => {
- Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)))
+ Ok(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()))
}
ast::VisibilityKind::Inherited => {
Ok(match self.parent_scope.module.kind {
// while the current crate doesn't have a valid `crate_name`.
if crate_name != kw::Empty {
// `crate_name` should not be interpreted as relative.
- module_path.push(Segment {
- ident: Ident { name: kw::PathRoot, span: source.ident.span },
- id: Some(self.r.next_node_id()),
- has_generic_args: false,
- });
+ module_path.push(Segment::from_ident_and_id(
+ Ident { name: kw::PathRoot, span: source.ident.span },
+ self.r.next_node_id(),
+ ));
source.ident.name = crate_name;
}
if rename.is_none() {
let mut ctor_vis = if vis == ty::Visibility::Public
&& self.r.session.contains_name(&item.attrs, sym::non_exhaustive)
{
- ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+ ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
} else {
vis
};
root_span: span,
span,
module_path: Vec::new(),
- vis: Cell::new(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))),
+ vis: Cell::new(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())),
used: Cell::new(false),
})
};
let vis = if is_macro_export {
ty::Visibility::Public
} else {
- ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+ ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
};
let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
self.r.set_binding_parent_module(binding, parent_scope.module);
let ctor_vis = if vis == ty::Visibility::Public
&& self.r.session.contains_name(&variant.attrs, sym::non_exhaustive)
{
- ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+ ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
} else {
vis
};
}
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
- if let FnKind::Fn(_, _, sig, _, body) = fn_kind {
+ if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind {
if let Async::Yes { closure_id, return_impl_trait_id, .. } = sig.header.asyncness {
+ self.visit_generics(generics);
+
let return_impl_trait_id =
self.create_def(return_impl_trait_id, DefPathData::ImplTrait, span);
use rustc_feature::BUILTIN_ATTRIBUTES;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::PrimTy;
use rustc_middle::bug;
use rustc_middle::ty::DefIdTree;
}
ResolutionError::InvalidAsmSym => {
let mut err = self.session.struct_span_err(span, "invalid `sym` operand");
- err.span_label(span, &format!("is a local variable"));
+ err.span_label(span, "is a local variable");
err.help("`sym` operands must refer to either a function or a static");
err
}
}
Scope::ExternPrelude => {
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
- let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
+ let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
filter_fn(res).then_some(TypoSuggestion::typo_from_res(ident.name, res))
}));
}
let mut allow_super = true;
let mut second_binding = None;
- for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
+ for (i, &Segment { ident, id, .. }) in path.iter().enumerate() {
debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
let record_segment_res = |this: &mut Self, res| {
if finalize.is_some() {
use rustc_errors::DiagnosticId;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
use rustc_hir::{PrimTy, TraitCandidate};
+use rustc_middle::ty::DefIdTree;
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{BytePos, Span};
use smallvec::{smallvec, SmallVec};
use rustc_span::source_map::{respan, Spanned};
}
}
+#[derive(Copy, Clone, Debug)]
+enum LifetimeRibKind {
+ /// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
+ Item,
+
+ /// This rib declares generic parameters.
+ Generics { span: Span, kind: LifetimeBinderKind },
+
+ /// For **Modern** cases, create a new anonymous region parameter
+ /// and reference that.
+ ///
+ /// For **Dyn Bound** cases, pass responsibility to
+ /// `resolve_lifetime` code.
+ ///
+ /// For **Deprecated** cases, report an error.
+ AnonymousCreateParameter,
+
+ /// Give a hard error when either `&` or `'_` is written. Used to
+ /// rule out things like `where T: Foo<'_>`. Does not imply an
+ /// error on default object bounds (e.g., `Box<dyn Foo>`).
+ AnonymousReportError,
+
+ /// Pass responsibility to `resolve_lifetime` code for all cases.
+ AnonymousPassThrough,
+}
+
+#[derive(Copy, Clone, Debug)]
+enum LifetimeBinderKind {
+ BareFnType,
+ PolyTrait,
+ WhereBound,
+ Item,
+ Function,
+ ImplBlock,
+}
+
+impl LifetimeBinderKind {
+ fn descr(self) -> &'static str {
+ use LifetimeBinderKind::*;
+ match self {
+ BareFnType => "type",
+ PolyTrait => "bound",
+ WhereBound => "bound",
+ Item => "item",
+ ImplBlock => "impl block",
+ Function => "function",
+ }
+ }
+}
+
+#[derive(Debug)]
+struct LifetimeRib {
+ kind: LifetimeRibKind,
+ bindings: IdentMap<()>,
+}
+
+impl LifetimeRib {
+ fn new(kind: LifetimeRibKind) -> LifetimeRib {
+ LifetimeRib { bindings: Default::default(), kind }
+ }
+}
+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
crate enum AliasPossibility {
No,
/// The current set of local scopes, for labels.
label_ribs: Vec<Rib<'a, NodeId>>,
+ /// The current set of local scopes for lifetimes.
+ lifetime_ribs: Vec<LifetimeRib>,
+
/// The trait that the current context can refer to.
current_trait_ref: Option<(Module<'a>, TraitRef)>,
let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
// Always report errors in items we just entered.
let old_ignore = replace(&mut self.in_func_body, false);
- self.resolve_item(item);
+ self.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item));
self.in_func_body = old_ignore;
self.diagnostic_metadata.current_item = prev;
}
let prev = self.diagnostic_metadata.current_trait_object;
let prev_ty = self.diagnostic_metadata.current_type_path;
match ty.kind {
+ TyKind::Rptr(None, _) => {
+ // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
+ // NodeId `ty.id`.
+ let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo());
+ self.resolve_elided_lifetime(ty.id, span);
+ }
TyKind::Path(ref qself, ref path) => {
self.diagnostic_metadata.current_type_path = Some(ty);
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
TyKind::TraitObject(ref bounds, ..) => {
self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
}
+ TyKind::BareFn(ref bare_fn) => {
+ let span = if bare_fn.generic_params.is_empty() {
+ ty.span.shrink_to_lo()
+ } else {
+ ty.span
+ };
+ self.with_generic_param_rib(
+ &bare_fn.generic_params,
+ NormalRibKind,
+ LifetimeRibKind::Generics { kind: LifetimeBinderKind::BareFnType, span },
+ |this| {
+ this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+ this.visit_generic_param_vec(&bare_fn.generic_params, false);
+ visit::walk_fn_decl(this, &bare_fn.decl);
+ });
+ },
+ );
+ self.diagnostic_metadata.current_trait_object = prev;
+ return;
+ }
_ => (),
}
visit::walk_ty(self, ty);
self.diagnostic_metadata.current_trait_object = prev;
self.diagnostic_metadata.current_type_path = prev_ty;
}
- fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
- self.smart_resolve_path(
- tref.trait_ref.ref_id,
- None,
- &tref.trait_ref.path,
- PathSource::Trait(AliasPossibility::Maybe),
+ fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBoundModifier) {
+ let span =
+ if tref.bound_generic_params.is_empty() { tref.span.shrink_to_lo() } else { tref.span };
+ self.with_generic_param_rib(
+ &tref.bound_generic_params,
+ NormalRibKind,
+ LifetimeRibKind::Generics { kind: LifetimeBinderKind::PolyTrait, span },
+ |this| {
+ this.visit_generic_param_vec(&tref.bound_generic_params, false);
+ this.smart_resolve_path(
+ tref.trait_ref.ref_id,
+ None,
+ &tref.trait_ref.path,
+ PathSource::Trait(AliasPossibility::Maybe),
+ );
+ this.visit_trait_ref(&tref.trait_ref);
+ },
);
- visit::walk_poly_trait_ref(self, tref, m);
}
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
match foreign_item.kind {
- ForeignItemKind::Fn(box Fn { ref generics, .. })
- | ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
- self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
- visit::walk_foreign_item(this, foreign_item);
+ ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
+ self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
+ this.with_generic_param_rib(
+ &generics.params,
+ ItemRibKind(HasGenericParams::Yes),
+ LifetimeRibKind::Generics {
+ kind: LifetimeBinderKind::Item,
+ span: generics.span,
+ },
+ |this| visit::walk_foreign_item(this, foreign_item),
+ )
+ });
+ }
+ ForeignItemKind::Fn(box Fn { ref generics, .. }) => {
+ self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
+ this.with_generic_param_rib(
+ &generics.params,
+ ItemRibKind(HasGenericParams::Yes),
+ LifetimeRibKind::Generics {
+ kind: LifetimeBinderKind::Function,
+ span: generics.span,
+ },
+ |this| visit::walk_foreign_item(this, foreign_item),
+ )
});
}
ForeignItemKind::Static(..) => {
- self.with_item_rib(HasGenericParams::No, |this| {
+ self.with_item_rib(|this| {
visit::walk_foreign_item(this, foreign_item);
});
}
ForeignItemKind::MacCall(..) => {
- visit::walk_foreign_item(self, foreign_item);
+ panic!("unexpanded macro in resolve!")
}
}
}
let rib_kind = match fn_kind {
// Bail if the function is foreign, and thus cannot validly have
// a body, or if there's no body for some other reason.
- FnKind::Fn(FnCtxt::Foreign, _, sig, ..) | FnKind::Fn(_, _, sig, .., None) => {
- // We don't need to deal with patterns in parameters, because
- // they are not possible for foreign or bodiless functions.
- self.visit_fn_header(&sig.header);
- visit::walk_fn_decl(self, &sig.decl);
+ FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
+ | FnKind::Fn(_, _, sig, _, generics, None) => {
+ self.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+ // We don't need to deal with patterns in parameters, because
+ // they are not possible for foreign or bodiless functions.
+ this.visit_fn_header(&sig.header);
+ this.visit_generics(generics);
+ visit::walk_fn_decl(this, &sig.decl);
+ });
return;
}
FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
self.with_rib(ValueNS, rib_kind, |this| {
// Create a label rib for the function.
this.with_label_rib(rib_kind, |this| {
- // Add each argument to the rib.
- this.resolve_params(&declaration.inputs);
+ let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id());
- visit::walk_fn_ret_ty(this, &declaration.output);
+ if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
+ this.visit_generics(generics);
+ }
+
+ if async_node_id.is_some() {
+ // In `async fn`, argument-position elided lifetimes
+ // must be transformed into fresh generic parameters so that
+ // they can be applied to the opaque `impl Trait` return type.
+ this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| {
+ // Add each argument to the rib.
+ this.resolve_params(&declaration.inputs)
+ });
+
+ this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+ visit::walk_fn_ret_ty(this, &declaration.output)
+ });
+ } else {
+ this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+ // Add each argument to the rib.
+ this.resolve_params(&declaration.inputs);
+
+ visit::walk_fn_ret_ty(this, &declaration.output);
+ });
+ };
// Ignore errors in function bodies if this is rustdoc
// Be sure not to set this until the function signature has been resolved.
let previous_state = replace(&mut this.in_func_body, true);
// Resolve the function body, potentially inside the body of an async closure
- match fn_kind {
- FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
- FnKind::Closure(_, body) => this.visit_expr(body),
- };
+ this.with_lifetime_rib(
+ LifetimeRibKind::AnonymousPassThrough,
+ |this| match fn_kind {
+ FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
+ FnKind::Closure(_, body) => this.visit_expr(body),
+ },
+ );
debug!("(resolving function) leaving function");
this.in_func_body = previous_state;
});
self.diagnostic_metadata.current_function = previous_value;
}
+ fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
+ self.resolve_lifetime(lifetime)
+ }
fn visit_generics(&mut self, generics: &'ast Generics) {
- // For type parameter defaults, we have to ban access
- // to following type parameters, as the InternalSubsts can only
- // provide previous type parameters as they're built. We
- // put all the parameters on the ban list and then remove
- // them one by one as they are processed and become available.
- let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
- let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
- for param in generics.params.iter() {
- match param.kind {
- GenericParamKind::Type { .. } => {
- forward_ty_ban_rib
- .bindings
- .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
- }
- GenericParamKind::Const { .. } => {
- forward_const_ban_rib
- .bindings
- .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
- }
- GenericParamKind::Lifetime => {}
- }
- }
-
- // rust-lang/rust#61631: The type `Self` is essentially
- // another type parameter. For ADTs, we consider it
- // well-defined only after all of the ADT type parameters have
- // been provided. Therefore, we do not allow use of `Self`
- // anywhere in ADT type parameter defaults.
- //
- // (We however cannot ban `Self` for defaults on *all* generic
- // lists; e.g. trait generics can usefully refer to `Self`,
- // such as in the case of `trait Add<Rhs = Self>`.)
- if self.diagnostic_metadata.current_self_item.is_some() {
- // (`Some` if + only if we are in ADT's generics.)
- forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
- }
-
- for param in &generics.params {
- match param.kind {
- GenericParamKind::Lifetime => self.visit_generic_param(param),
- GenericParamKind::Type { ref default } => {
- for bound in ¶m.bounds {
- self.visit_param_bound(bound);
- }
-
- if let Some(ref ty) = default {
- self.ribs[TypeNS].push(forward_ty_ban_rib);
- self.ribs[ValueNS].push(forward_const_ban_rib);
- self.visit_ty(ty);
- forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
- forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
- }
-
- // Allow all following defaults to refer to this type parameter.
- forward_ty_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
- }
- GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
- // Const parameters can't have param bounds.
- assert!(param.bounds.is_empty());
-
- self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
- self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
- self.visit_ty(ty);
- self.ribs[TypeNS].pop().unwrap();
- self.ribs[ValueNS].pop().unwrap();
-
- if let Some(ref expr) = default {
- self.ribs[TypeNS].push(forward_ty_ban_rib);
- self.ribs[ValueNS].push(forward_const_ban_rib);
- self.visit_anon_const(expr);
- forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
- forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
- }
-
- // Allow all following defaults to refer to this const parameter.
- forward_const_ban_rib
- .bindings
- .remove(&Ident::with_dummy_span(param.ident.name));
- }
- }
- }
+ self.visit_generic_param_vec(
+ &generics.params,
+ self.diagnostic_metadata.current_self_item.is_some(),
+ );
for p in &generics.where_clause.predicates {
self.visit_where_predicate(p);
}
self.diagnostic_metadata.currently_processing_generics = prev;
}
+ fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
+ if let Some(ref args) = path_segment.args {
+ match &**args {
+ GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args),
+ GenericArgs::Parenthesized(..) => self
+ .with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+ visit::walk_generic_args(this, path_span, args)
+ }),
+ }
+ }
+ }
+
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
debug!("visit_where_predicate {:?}", p);
let previous_value =
replace(&mut self.diagnostic_metadata.current_where_predicate, Some(p));
- visit::walk_where_predicate(self, p);
+ self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+ if let WherePredicate::BoundPredicate(WhereBoundPredicate {
+ ref bounded_ty,
+ ref bounds,
+ ref bound_generic_params,
+ span: predicate_span,
+ ..
+ }) = p
+ {
+ let span = if bound_generic_params.is_empty() {
+ predicate_span.shrink_to_lo()
+ } else {
+ *predicate_span
+ };
+ this.with_generic_param_rib(
+ &bound_generic_params,
+ NormalRibKind,
+ LifetimeRibKind::Generics { kind: LifetimeBinderKind::WhereBound, span },
+ |this| {
+ this.visit_generic_param_vec(&bound_generic_params, false);
+ this.visit_ty(bounded_ty);
+ for bound in bounds {
+ this.visit_param_bound(bound)
+ }
+ },
+ );
+ } else {
+ visit::walk_where_predicate(this, p);
+ }
+ });
self.diagnostic_metadata.current_where_predicate = previous_value;
}
macro_ns: vec![Rib::new(start_rib_kind)],
},
label_ribs: Vec::new(),
+ lifetime_ribs: Vec::new(),
current_trait_ref: None,
diagnostic_metadata: DiagnosticMetadata::default(),
// errors at module scope should always be reported
}
}
+ fn visit_generic_param_vec(&mut self, params: &'ast Vec<GenericParam>, add_self_upper: bool) {
+ // For type parameter defaults, we have to ban access
+ // to following type parameters, as the InternalSubsts can only
+ // provide previous type parameters as they're built. We
+ // put all the parameters on the ban list and then remove
+ // them one by one as they are processed and become available.
+ let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
+ let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
+ for param in params.iter() {
+ match param.kind {
+ GenericParamKind::Type { .. } => {
+ forward_ty_ban_rib
+ .bindings
+ .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
+ }
+ GenericParamKind::Const { .. } => {
+ forward_const_ban_rib
+ .bindings
+ .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
+ }
+ GenericParamKind::Lifetime => {}
+ }
+ }
+
+ // rust-lang/rust#61631: The type `Self` is essentially
+ // another type parameter. For ADTs, we consider it
+ // well-defined only after all of the ADT type parameters have
+ // been provided. Therefore, we do not allow use of `Self`
+ // anywhere in ADT type parameter defaults.
+ //
+ // (We however cannot ban `Self` for defaults on *all* generic
+ // lists; e.g. trait generics can usefully refer to `Self`,
+ // such as in the case of `trait Add<Rhs = Self>`.)
+ if add_self_upper {
+ // (`Some` if + only if we are in ADT's generics.)
+ forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
+ }
+
+ self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+ for param in params {
+ match param.kind {
+ GenericParamKind::Lifetime => {
+ for bound in ¶m.bounds {
+ this.visit_param_bound(bound);
+ }
+ }
+ GenericParamKind::Type { ref default } => {
+ for bound in ¶m.bounds {
+ this.visit_param_bound(bound);
+ }
+
+ if let Some(ref ty) = default {
+ this.ribs[TypeNS].push(forward_ty_ban_rib);
+ this.ribs[ValueNS].push(forward_const_ban_rib);
+ this.visit_ty(ty);
+ forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
+ forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap();
+ }
+
+ // Allow all following defaults to refer to this type parameter.
+ forward_ty_ban_rib
+ .bindings
+ .remove(&Ident::with_dummy_span(param.ident.name));
+ }
+ GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
+ // Const parameters can't have param bounds.
+ assert!(param.bounds.is_empty());
+
+ this.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
+ this.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
+ this.visit_ty(ty);
+ this.ribs[TypeNS].pop().unwrap();
+ this.ribs[ValueNS].pop().unwrap();
+
+ if let Some(ref expr) = default {
+ this.ribs[TypeNS].push(forward_ty_ban_rib);
+ this.ribs[ValueNS].push(forward_const_ban_rib);
+ this.visit_anon_const(expr);
+ forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
+ forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap();
+ }
+
+ // Allow all following defaults to refer to this const parameter.
+ forward_const_ban_rib
+ .bindings
+ .remove(&Ident::with_dummy_span(param.ident.name));
+ }
+ }
+ }
+ })
+ }
+
+ #[tracing::instrument(level = "debug", skip(self, work))]
+ fn with_lifetime_rib<T>(
+ &mut self,
+ kind: LifetimeRibKind,
+ work: impl FnOnce(&mut Self) -> T,
+ ) -> T {
+ self.lifetime_ribs.push(LifetimeRib::new(kind));
+ let ret = work(self);
+ self.lifetime_ribs.pop();
+ ret
+ }
+
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime) {
+ let ident = lifetime.ident;
+
+ if ident.name == kw::StaticLifetime {
+ return;
+ }
+
+ if ident.name == kw::UnderscoreLifetime {
+ return self.resolve_anonymous_lifetime(lifetime, false);
+ }
+
+ let mut indices = (0..self.lifetime_ribs.len()).rev();
+ for i in &mut indices {
+ let rib = &self.lifetime_ribs[i];
+ let normalized_ident = ident.normalize_to_macros_2_0();
+ if let Some(_) = rib.bindings.get_key_value(&normalized_ident) {
+ return;
+ }
+
+ if let LifetimeRibKind::Item = rib.kind {
+ break;
+ }
+ }
+
+ let mut outer_res = None;
+ for i in indices {
+ let rib = &self.lifetime_ribs[i];
+ let normalized_ident = ident.normalize_to_macros_2_0();
+ if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) {
+ outer_res = Some(outer);
+ break;
+ }
+ }
+
+ self.emit_undeclared_lifetime_error(lifetime, outer_res);
+ }
+
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
+ debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
+
+ for i in (0..self.lifetime_ribs.len()).rev() {
+ let rib = &mut self.lifetime_ribs[i];
+ match rib.kind {
+ LifetimeRibKind::AnonymousReportError => {
+ let (msg, note) = if elided {
+ (
+ "`&` without an explicit lifetime name cannot be used here",
+ "explicit lifetime name needed here",
+ )
+ } else {
+ ("`'_` cannot be used here", "`'_` is a reserved lifetime name")
+ };
+ rustc_errors::struct_span_err!(
+ self.r.session,
+ lifetime.ident.span,
+ E0637,
+ "{}",
+ msg,
+ )
+ .span_label(lifetime.ident.span, note)
+ .emit();
+
+ return;
+ }
+ LifetimeRibKind::AnonymousCreateParameter
+ | LifetimeRibKind::AnonymousPassThrough
+ | LifetimeRibKind::Item => return,
+ _ => {}
+ }
+ }
+ }
+
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) {
+ let id = self.r.next_node_id();
+ let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) };
+ self.resolve_anonymous_lifetime(<, true);
+ }
+
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn resolve_elided_lifetimes_in_path(
+ &mut self,
+ path_id: NodeId,
+ partial_res: PartialRes,
+ path: &[Segment],
+ source: PathSource<'_>,
+ finalize: Finalize,
+ ) {
+ let Some(path_span) = finalize.path_span() else {
+ return;
+ };
+ let proj_start = path.len() - partial_res.unresolved_segments();
+ for (i, segment) in path.iter().enumerate() {
+ if segment.has_lifetime_args {
+ continue;
+ }
+ let Some(segment_id) = segment.id else {
+ continue;
+ };
+
+ // Figure out if this is a type/trait segment,
+ // which may need lifetime elision performed.
+ let type_def_id = match partial_res.base_res() {
+ Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
+ self.r.parent(def_id).unwrap()
+ }
+ Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
+ self.r.parent(def_id).unwrap()
+ }
+ Res::Def(DefKind::Struct, def_id)
+ | Res::Def(DefKind::Union, def_id)
+ | Res::Def(DefKind::Enum, def_id)
+ | Res::Def(DefKind::TyAlias, def_id)
+ | Res::Def(DefKind::Trait, def_id)
+ if i + 1 == proj_start =>
+ {
+ def_id
+ }
+ _ => continue,
+ };
+
+ let expected_lifetimes = self.r.item_generics_num_lifetimes(type_def_id);
+ if expected_lifetimes == 0 {
+ continue;
+ }
+
+ let missing = match source {
+ PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true,
+ PathSource::Expr(..)
+ | PathSource::Pat
+ | PathSource::Struct
+ | PathSource::TupleStruct(..) => false,
+ };
+ let mut error = false;
+ for rib in self.lifetime_ribs.iter().rev() {
+ match rib.kind {
+ // In create-parameter mode we error here because we don't want to support
+ // deprecated impl elision in new features like impl elision and `async fn`,
+ // both of which work using the `CreateParameter` mode:
+ //
+ // impl Foo for std::cell::Ref<u32> // note lack of '_
+ // async fn foo(_: std::cell::Ref<u32>) { ... }
+ LifetimeRibKind::AnonymousCreateParameter => {
+ error = true;
+ break;
+ }
+ // `PassThrough` is the normal case.
+ // `new_error_lifetime`, which would usually be used in the case of `ReportError`,
+ // is unsuitable here, as these can occur from missing lifetime parameters in a
+ // `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
+ // lifetime. Instead, we simply create an implicit lifetime, which will be checked
+ // later, at which point a suitable error will be emitted.
+ LifetimeRibKind::AnonymousPassThrough
+ | LifetimeRibKind::AnonymousReportError
+ | LifetimeRibKind::Item => break,
+ _ => {}
+ }
+ }
+
+ if !missing {
+ continue;
+ }
+
+ let elided_lifetime_span = if segment.has_generic_args {
+ // If there are brackets, but not generic arguments, then use the opening bracket
+ segment.args_span.with_hi(segment.args_span.lo() + BytePos(1))
+ } else {
+ // If there are no brackets, use the identifier span.
+ // HACK: we use find_ancestor_inside to properly suggest elided spans in paths
+ // originating from macros, since the segment's span might be from a macro arg.
+ segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
+ };
+ if error {
+ let sess = self.r.session;
+ let mut err = rustc_errors::struct_span_err!(
+ sess,
+ path_span,
+ E0726,
+ "implicit elided lifetime not allowed here"
+ );
+ rustc_errors::add_elided_lifetime_in_path_suggestion(
+ sess.source_map(),
+ &mut err,
+ expected_lifetimes,
+ path_span,
+ !segment.has_generic_args,
+ elided_lifetime_span,
+ );
+ err.note("assuming a `'static` lifetime...");
+ err.emit();
+ } else {
+ self.r.lint_buffer.buffer_lint_with_diagnostic(
+ lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
+ segment_id,
+ elided_lifetime_span,
+ "hidden lifetime parameters in types are deprecated",
+ lint::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
+ expected_lifetimes,
+ path_span,
+ !segment.has_generic_args,
+ elided_lifetime_span,
+ ),
+ );
+ }
+ }
+ }
+
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
/// label and reports an error if the label is not found or is unreachable.
fn resolve_label(&self, mut label: Ident) -> Option<NodeId> {
fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
debug!("resolve_adt");
self.with_current_self_item(item, |this| {
- this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
- let item_def_id = this.r.local_def_id(item.id).to_def_id();
- this.with_self_rib(
- Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) },
- |this| {
- visit::walk_item(this, item);
- },
- );
- });
+ this.with_generic_param_rib(
+ &generics.params,
+ ItemRibKind(HasGenericParams::Yes),
+ LifetimeRibKind::Generics { kind: LifetimeBinderKind::Item, span: generics.span },
+ |this| {
+ let item_def_id = this.r.local_def_id(item.id).to_def_id();
+ this.with_self_rib(
+ Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) },
+ |this| {
+ visit::walk_item(this, item);
+ },
+ );
+ },
+ );
});
}
debug!("(resolving item) resolving {} ({:?})", name, item.kind);
match item.kind {
- ItemKind::TyAlias(box TyAlias { ref generics, .. })
- | ItemKind::Fn(box Fn { ref generics, .. }) => {
- self.compute_num_lifetime_params(item.id, generics);
- self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
- visit::walk_item(this, item)
- });
+ ItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
+ self.with_generic_param_rib(
+ &generics.params,
+ ItemRibKind(HasGenericParams::Yes),
+ LifetimeRibKind::Generics {
+ kind: LifetimeBinderKind::Item,
+ span: generics.span,
+ },
+ |this| visit::walk_item(this, item),
+ );
+ }
+
+ ItemKind::Fn(box Fn { ref generics, .. }) => {
+ self.with_generic_param_rib(
+ &generics.params,
+ ItemRibKind(HasGenericParams::Yes),
+ LifetimeRibKind::Generics {
+ kind: LifetimeBinderKind::Function,
+ span: generics.span,
+ },
+ |this| visit::walk_item(this, item),
+ );
}
ItemKind::Enum(_, ref generics)
| ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics) => {
- self.compute_num_lifetime_params(item.id, generics);
self.resolve_adt(item, generics);
}
items: ref impl_items,
..
}) => {
- self.compute_num_lifetime_params(item.id, generics);
self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items);
}
ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => {
- self.compute_num_lifetime_params(item.id, generics);
// Create a new rib for the trait-wide type parameters.
- self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
- let def = this.r.local_def_id(item.id).to_def_id();
- this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
- this.visit_generics(generics);
- walk_list!(this, visit_param_bound, bounds);
-
- let walk_assoc_item = |this: &mut Self, generics, item| {
- this.with_generic_param_rib(generics, AssocItemRibKind, |this| {
- visit::walk_assoc_item(this, item, AssocCtxt::Trait)
- });
- };
-
- this.with_trait_items(items, |this| {
- for item in items {
- match &item.kind {
- AssocItemKind::Const(_, ty, default) => {
- this.visit_ty(ty);
- // Only impose the restrictions of `ConstRibKind` for an
- // actual constant expression in a provided default.
- if let Some(expr) = default {
- // We allow arbitrary const expressions inside of associated consts,
- // even if they are potentially not const evaluatable.
- //
- // Type parameters can already be used and as associated consts are
- // not used as part of the type system, this is far less surprising.
- this.with_constant_rib(
- IsRepeatExpr::No,
- true,
- None,
- |this| this.visit_expr(expr),
- );
- }
- }
- AssocItemKind::Fn(box Fn { generics, .. }) => {
- walk_assoc_item(this, generics, item);
- }
- AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
- walk_assoc_item(this, generics, item);
- }
- AssocItemKind::MacCall(_) => {
- panic!("unexpanded macro in resolve!")
+ self.with_generic_param_rib(
+ &generics.params,
+ ItemRibKind(HasGenericParams::Yes),
+ LifetimeRibKind::Generics {
+ kind: LifetimeBinderKind::Item,
+ span: generics.span,
+ },
+ |this| {
+ let local_def_id = this.r.local_def_id(item.id).to_def_id();
+ this.with_self_rib(
+ Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
+ |this| {
+ this.visit_generics(generics);
+ walk_list!(this, visit_param_bound, bounds);
+
+ let walk_assoc_item =
+ |this: &mut Self,
+ generics: &Generics,
+ kind,
+ item: &'ast AssocItem| {
+ this.with_generic_param_rib(
+ &generics.params,
+ AssocItemRibKind,
+ LifetimeRibKind::Generics { span: generics.span, kind },
+ |this| {
+ visit::walk_assoc_item(this, item, AssocCtxt::Trait)
+ },
+ );
+ };
+
+ this.with_trait_items(items, |this| {
+ for item in items {
+ match &item.kind {
+ AssocItemKind::Const(_, ty, default) => {
+ this.visit_ty(ty);
+ // Only impose the restrictions of `ConstRibKind` for an
+ // actual constant expression in a provided default.
+ if let Some(expr) = default {
+ // We allow arbitrary const expressions inside of associated consts,
+ // even if they are potentially not const evaluatable.
+ //
+ // Type parameters can already be used and as associated consts are
+ // not used as part of the type system, this is far less surprising.
+ this.with_constant_rib(
+ IsRepeatExpr::No,
+ true,
+ None,
+ |this| this.visit_expr(expr),
+ );
+ }
+ }
+ AssocItemKind::Fn(box Fn { generics, .. }) => {
+ walk_assoc_item(
+ this,
+ generics,
+ LifetimeBinderKind::Function,
+ item,
+ );
+ }
+ AssocItemKind::TyAlias(box TyAlias {
+ generics,
+ ..
+ }) => {
+ walk_assoc_item(
+ this,
+ generics,
+ LifetimeBinderKind::Item,
+ item,
+ );
+ }
+ AssocItemKind::MacCall(_) => {
+ panic!("unexpanded macro in resolve!")
+ }
+ };
}
- };
- }
- });
- });
- });
+ });
+ },
+ );
+ },
+ );
}
ItemKind::TraitAlias(ref generics, ref bounds) => {
- self.compute_num_lifetime_params(item.id, generics);
// Create a new rib for the trait-wide type parameters.
- self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
- let def = this.r.local_def_id(item.id).to_def_id();
- this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
- this.visit_generics(generics);
- walk_list!(this, visit_param_bound, bounds);
- });
- });
+ self.with_generic_param_rib(
+ &generics.params,
+ ItemRibKind(HasGenericParams::Yes),
+ LifetimeRibKind::Generics {
+ kind: LifetimeBinderKind::Item,
+ span: generics.span,
+ },
+ |this| {
+ let local_def_id = this.r.local_def_id(item.id).to_def_id();
+ this.with_self_rib(
+ Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
+ |this| {
+ this.visit_generics(generics);
+ walk_list!(this, visit_param_bound, bounds);
+ },
+ );
+ },
+ );
}
ItemKind::Mod(..) | ItemKind::ForeignMod(_) => {
}
ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
- self.with_item_rib(HasGenericParams::No, |this| {
+ self.with_item_rib(|this| {
this.visit_ty(ty);
if let Some(expr) = expr {
let constant_item_kind = match item.kind {
}
}
- fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: RibKind<'a>, f: F)
- where
+ fn with_generic_param_rib<'c, F>(
+ &'c mut self,
+ params: &'c Vec<GenericParam>,
+ kind: RibKind<'a>,
+ lifetime_kind: LifetimeRibKind,
+ f: F,
+ ) where
F: FnOnce(&mut Self),
{
debug!("with_generic_param_rib");
let mut function_type_rib = Rib::new(kind);
let mut function_value_rib = Rib::new(kind);
+ let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
let mut seen_bindings = FxHashMap::default();
// We also can't shadow bindings from the parent item
add_bindings_for_ns(TypeNS);
}
- for param in &generics.params {
- if let GenericParamKind::Lifetime = param.kind {
- continue;
- }
-
+ for param in params {
let ident = param.ident.normalize_to_macros_2_0();
debug!("with_generic_param_rib: {}", param.id);
Entry::Occupied(entry) => {
let span = *entry.get();
let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
- self.report_error(param.ident.span, err);
+ if !matches!(param.kind, GenericParamKind::Lifetime) {
+ self.report_error(param.ident.span, err);
+ }
}
Entry::Vacant(entry) => {
entry.insert(param.ident.span);
}
}
+ if param.ident.name == kw::UnderscoreLifetime {
+ rustc_errors::struct_span_err!(
+ self.r.session,
+ param.ident.span,
+ E0637,
+ "`'_` cannot be used here"
+ )
+ .span_label(param.ident.span, "`'_` is a reserved lifetime name")
+ .emit();
+ continue;
+ }
+
+ if param.ident.name == kw::StaticLifetime {
+ rustc_errors::struct_span_err!(
+ self.r.session,
+ param.ident.span,
+ E0262,
+ "invalid lifetime parameter name: `{}`",
+ param.ident,
+ )
+ .span_label(param.ident.span, "'static is a reserved lifetime name")
+ .emit();
+ continue;
+ }
+
+ let def_id = self.r.local_def_id(param.id);
+
// Plain insert (no renaming).
let (rib, def_kind) = match param.kind {
GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
- _ => unreachable!(),
+ GenericParamKind::Lifetime => {
+ function_lifetime_rib.bindings.insert(ident, ());
+ continue;
+ }
};
- let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id());
+ let res = Res::Def(def_kind, def_id.to_def_id());
self.r.record_partial_res(param.id, PartialRes::new(res));
rib.bindings.insert(ident, res);
}
+ self.lifetime_ribs.push(function_lifetime_rib);
self.ribs[ValueNS].push(function_value_rib);
self.ribs[TypeNS].push(function_type_rib);
self.ribs[TypeNS].pop();
self.ribs[ValueNS].pop();
+ self.lifetime_ribs.pop();
}
fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) {
self.label_ribs.pop();
}
- fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce(&mut Self)) {
- let kind = ItemRibKind(has_generic_params);
- self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
+ fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) {
+ let kind = ItemRibKind(HasGenericParams::No);
+ self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
+ this.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
+ })
}
// HACK(min_const_generics,const_evaluatable_unchecked): We
) {
debug!("resolve_implementation");
// If applicable, create a rib for the type parameters.
- self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
+ self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::ImplBlock }, |this| {
// Dummy self type for better errors if `Self` is used in the trait path.
this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
- // Resolve the trait reference, if necessary.
- this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
- let item_def_id = this.r.local_def_id(item_id);
-
- // Register the trait definitions from here.
- if let Some(trait_id) = trait_id {
- this.r.trait_impls.entry(trait_id).or_default().push(item_def_id);
- }
-
- let item_def_id = item_def_id.to_def_id();
- let res =
- Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) };
- this.with_self_rib(res, |this| {
- if let Some(trait_ref) = opt_trait_reference.as_ref() {
- // Resolve type arguments in the trait path.
- visit::walk_trait_ref(this, trait_ref);
+ this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| {
+ // Resolve the trait reference, if necessary.
+ this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
+ let item_def_id = this.r.local_def_id(item_id);
+
+ // Register the trait definitions from here.
+ if let Some(trait_id) = trait_id {
+ this.r.trait_impls.entry(trait_id).or_default().push(item_def_id);
}
- // Resolve the self type.
- this.visit_ty(self_type);
- // Resolve the generic parameters.
- this.visit_generics(generics);
- // Resolve the items within the impl.
- this.with_current_self_type(self_type, |this| {
- this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
- debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
- for item in impl_items {
- use crate::ResolutionError::*;
- match &item.kind {
- AssocItemKind::Const(_default, _ty, _expr) => {
- debug!("resolve_implementation AssocItemKind::Const");
- // If this is a trait impl, ensure the const
- // exists in trait
- this.check_trait_item(
- item.id,
- item.ident,
- &item.kind,
- ValueNS,
- item.span,
- |i, s, c| ConstNotMemberOfTrait(i, s, c),
- );
-
- // We allow arbitrary const expressions inside of associated consts,
- // even if they are potentially not const evaluatable.
- //
- // Type parameters can already be used and as associated consts are
- // not used as part of the type system, this is far less surprising.
- this.with_constant_rib(
- IsRepeatExpr::No,
- true,
- None,
- |this| {
- visit::walk_assoc_item(
- this,
- item,
- AssocCtxt::Impl,
- )
- },
- );
- }
- AssocItemKind::Fn(box Fn { generics, .. }) => {
- debug!("resolve_implementation AssocItemKind::Fn");
- // We also need a new scope for the impl item type parameters.
- this.with_generic_param_rib(
- generics,
- AssocItemRibKind,
- |this| {
- // If this is a trait impl, ensure the method
- // exists in trait
- this.check_trait_item(
- item.id,
- item.ident,
- &item.kind,
- ValueNS,
- item.span,
- |i, s, c| MethodNotMemberOfTrait(i, s, c),
- );
-
- visit::walk_assoc_item(
- this,
- item,
- AssocCtxt::Impl,
- )
- },
- );
- }
- AssocItemKind::TyAlias(box TyAlias {
- generics, ..
- }) => {
- debug!("resolve_implementation AssocItemKind::TyAlias");
- // We also need a new scope for the impl item type parameters.
- this.with_generic_param_rib(
- generics,
- AssocItemRibKind,
- |this| {
- // If this is a trait impl, ensure the type
- // exists in trait
- this.check_trait_item(
- item.id,
- item.ident,
- &item.kind,
- TypeNS,
- item.span,
- |i, s, c| TypeNotMemberOfTrait(i, s, c),
- );
- visit::walk_assoc_item(
- this,
- item,
- AssocCtxt::Impl,
- )
- },
- );
- }
- AssocItemKind::MacCall(_) => {
- panic!("unexpanded macro in resolve!")
- }
- }
- }
- });
+ let item_def_id = item_def_id.to_def_id();
+ let res =
+ Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) };
+ this.with_self_rib(res, |this| {
+ if let Some(trait_ref) = opt_trait_reference.as_ref() {
+ // Resolve type arguments in the trait path.
+ visit::walk_trait_ref(this, trait_ref);
+ }
+ // Resolve the self type.
+ this.visit_ty(self_type);
+ // Resolve the generic parameters.
+ this.visit_generics(generics);
+
+ // Resolve the items within the impl.
+ this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough,
+ |this| {
+ this.with_current_self_type(self_type, |this| {
+ this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
+ debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
+ for item in impl_items {
+ use crate::ResolutionError::*;
+ match &item.kind {
+ AssocItemKind::Const(_default, _ty, _expr) => {
+ debug!("resolve_implementation AssocItemKind::Const");
+ // If this is a trait impl, ensure the const
+ // exists in trait
+ this.check_trait_item(
+ item.id,
+ item.ident,
+ &item.kind,
+ ValueNS,
+ item.span,
+ |i, s, c| ConstNotMemberOfTrait(i, s, c),
+ );
+
+ // We allow arbitrary const expressions inside of associated consts,
+ // even if they are potentially not const evaluatable.
+ //
+ // Type parameters can already be used and as associated consts are
+ // not used as part of the type system, this is far less surprising.
+ this.with_constant_rib(
+ IsRepeatExpr::No,
+ true,
+ None,
+ |this| {
+ visit::walk_assoc_item(
+ this,
+ item,
+ AssocCtxt::Impl,
+ )
+ },
+ );
+ }
+ AssocItemKind::Fn(box Fn { generics, .. }) => {
+ debug!("resolve_implementation AssocItemKind::Fn");
+ // We also need a new scope for the impl item type parameters.
+ this.with_generic_param_rib(
+ &generics.params,
+ AssocItemRibKind,
+ LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Function },
+ |this| {
+ // If this is a trait impl, ensure the method
+ // exists in trait
+ this.check_trait_item(
+ item.id,
+ item.ident,
+ &item.kind,
+ ValueNS,
+ item.span,
+ |i, s, c| MethodNotMemberOfTrait(i, s, c),
+ );
+
+ visit::walk_assoc_item(
+ this,
+ item,
+ AssocCtxt::Impl,
+ )
+ },
+ );
+ }
+ AssocItemKind::TyAlias(box TyAlias {
+ generics, ..
+ }) => {
+ debug!("resolve_implementation AssocItemKind::TyAlias");
+ // We also need a new scope for the impl item type parameters.
+ this.with_generic_param_rib(
+ &generics.params,
+ AssocItemRibKind,
+ LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Item },
+ |this| {
+ // If this is a trait impl, ensure the type
+ // exists in trait
+ this.check_trait_item(
+ item.id,
+ item.ident,
+ &item.kind,
+ TypeNS,
+ item.span,
+ |i, s, c| TypeNotMemberOfTrait(i, s, c),
+ );
+
+ visit::walk_assoc_item(
+ this,
+ item,
+ AssocCtxt::Impl,
+ )
+ },
+ );
+ }
+ AssocItemKind::MacCall(_) => {
+ panic!("unexpanded macro in resolve!")
+ }
+ }
+ }
+ });
+ });
+ },
+ );
});
});
});
self.r.record_partial_res(id, partial_res);
}
+ self.resolve_elided_lifetimes_in_path(id, partial_res, path, source, finalize);
partial_res
}
// trait to resolve. In that case, we leave the `B`
// segment to be resolved by type-check.
return Ok(Some(PartialRes::with_unresolved_segments(
- Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)),
+ Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()),
path.len(),
)));
}
Some((ident.name, ns)),
)
}
+}
+
+struct LifetimeCountVisitor<'a, 'b> {
+ r: &'b mut Resolver<'a>,
+}
- fn compute_num_lifetime_params(&mut self, id: NodeId, generics: &Generics) {
- let def_id = self.r.local_def_id(id);
- let count = generics
- .params
- .iter()
- .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime { .. }))
- .count();
- self.r.item_generics_num_lifetimes.insert(def_id, count);
+/// Walks the whole crate in DFS order, visiting each item, counting the declared number of
+/// lifetime generic parameters.
+impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_> {
+ fn visit_item(&mut self, item: &'ast Item) {
+ match &item.kind {
+ ItemKind::TyAlias(box TyAlias { ref generics, .. })
+ | ItemKind::Fn(box Fn { ref generics, .. })
+ | ItemKind::Enum(_, ref generics)
+ | ItemKind::Struct(_, ref generics)
+ | ItemKind::Union(_, ref generics)
+ | ItemKind::Impl(box Impl { ref generics, .. })
+ | ItemKind::Trait(box Trait { ref generics, .. })
+ | ItemKind::TraitAlias(ref generics, _) => {
+ let def_id = self.r.local_def_id(item.id);
+ let count = generics
+ .params
+ .iter()
+ .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime { .. }))
+ .count();
+ self.r.item_generics_num_lifetimes.insert(def_id, count);
+ }
+
+ ItemKind::Mod(..)
+ | ItemKind::ForeignMod(..)
+ | ItemKind::Static(..)
+ | ItemKind::Const(..)
+ | ItemKind::Use(..)
+ | ItemKind::ExternCrate(..)
+ | ItemKind::MacroDef(..)
+ | ItemKind::GlobalAsm(..)
+ | ItemKind::MacCall(..) => {}
+ }
+ visit::walk_item(self, item)
}
}
impl<'a> Resolver<'a> {
pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) {
+ visit::walk_crate(&mut LifetimeCountVisitor { r: self }, krate);
let mut late_resolution_visitor = LateResolutionVisitor::new(self);
visit::walk_crate(&mut late_resolution_visitor, krate);
for (id, span) in late_resolution_visitor.diagnostic_metadata.unused_labels.iter() {
use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
+use crate::late::{LifetimeBinderKind, LifetimeRibKind};
use crate::path_names_to_string;
use crate::{Finalize, Module, ModuleKind, ModuleOrUniformRoot};
use crate::{PathResult, PathSource, Segment};
use rustc_hir as hir;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::PrimTy;
use rustc_session::parse::feature_err;
use rustc_span::edition::Edition;
}
})
.collect::<Vec<_>>();
- let crate_def_id = DefId::local(CRATE_DEF_INDEX);
+ let crate_def_id = CRATE_DEF_ID.to_def_id();
if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
let mut enum_candidates: Vec<_> = self
.r
names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
self.r.crate_loader.maybe_process_path_extern(ident.name).and_then(
|crate_id| {
- let crate_mod = Res::Def(
- DefKind::Mod,
- DefId { krate: crate_id, index: CRATE_DEF_INDEX },
- );
+ let crate_mod =
+ Res::Def(DefKind::Mod, crate_id.as_def_id());
if filter_fn(crate_mod) {
Some(TypoSuggestion::typo_from_res(
(*ident, within_scope)
})
}
-}
-impl<'tcx> LifetimeContext<'_, 'tcx> {
- crate fn report_missing_lifetime_specifiers(
+ crate fn emit_undeclared_lifetime_error(
&self,
- spans: Vec<Span>,
- count: usize,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- struct_span_err!(
- self.tcx.sess,
- spans,
- E0106,
- "missing lifetime specifier{}",
- pluralize!(count)
- )
- }
+ lifetime_ref: &ast::Lifetime,
+ outer_lifetime_ref: Option<Ident>,
+ ) {
+ debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime);
+ let mut err = if let Some(outer) = outer_lifetime_ref {
+ let mut err = struct_span_err!(
+ self.r.session,
+ lifetime_ref.ident.span,
+ E0401,
+ "can't use generic parameters from outer item",
+ );
+ err.span_label(lifetime_ref.ident.span, "use of generic parameter from outer item");
+ err.span_label(outer.span, "lifetime parameter from outer item");
+ err
+ } else {
+ let mut err = struct_span_err!(
+ self.r.session,
+ lifetime_ref.ident.span,
+ E0261,
+ "use of undeclared lifetime name `{}`",
+ lifetime_ref.ident
+ );
+ err.span_label(lifetime_ref.ident.span, "undeclared lifetime");
+ err
+ };
+ let mut suggest_note = true;
- crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) {
- let mut err = struct_span_err!(
- self.tcx.sess,
- lifetime_ref.span,
- E0261,
- "use of undeclared lifetime name `{}`",
- lifetime_ref
- );
- err.span_label(lifetime_ref.span, "undeclared lifetime");
- let mut suggested_spans = vec![];
- for missing in &self.missing_named_lifetime_spots {
- match missing {
- MissingLifetimeSpot::Generics(generics) => {
- let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| {
- !matches!(
- p.kind,
- hir::GenericParamKind::Type { synthetic: true, .. }
- | hir::GenericParamKind::Lifetime {
- kind: hir::LifetimeParamKind::Elided,
- }
- )
- }) {
- (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
- } else {
- (generics.span, format!("<{}>", lifetime_ref))
- };
- if suggested_spans.contains(&span) {
+ for rib in self.lifetime_ribs.iter().rev() {
+ match rib.kind {
+ LifetimeRibKind::Generics { span, kind } => {
+ if !span.can_be_used_for_suggestions() && suggest_note {
+ suggest_note = false; // Avoid displaying the same help multiple times.
+ err.span_label(
+ span,
+ &format!(
+ "lifetime `{}` is missing in item created through this procedural macro",
+ lifetime_ref.ident,
+ ),
+ );
continue;
}
- suggested_spans.push(span);
- if span.can_be_used_for_suggestions() {
+
+ let higher_ranked = matches!(
+ kind,
+ LifetimeBinderKind::BareFnType
+ | LifetimeBinderKind::PolyTrait
+ | LifetimeBinderKind::WhereBound
+ );
+ let (span, sugg) = if span.is_empty() {
+ let sugg = format!(
+ "{}<{}>{}",
+ if higher_ranked { "for" } else { "" },
+ lifetime_ref.ident,
+ if higher_ranked { " " } else { "" },
+ );
+ (span, sugg)
+ } else {
+ let span =
+ self.r.session.source_map().span_through_char(span, '<').shrink_to_hi();
+ let sugg = format!("{}, ", lifetime_ref.ident);
+ (span, sugg)
+ };
+ if higher_ranked {
+ err.span_suggestion(
+ span,
+ &format!(
+ "consider making the {} lifetime-generic with a new `{}` lifetime",
+ kind.descr(),
+ lifetime_ref
+ ),
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ err.note_once(
+ "for more information on higher-ranked polymorphism, visit \
+ https://doc.rust-lang.org/nomicon/hrtb.html",
+ );
+ } else {
err.span_suggestion(
span,
- &format!("consider introducing lifetime `{}` here", lifetime_ref),
+ &format!("consider introducing lifetime `{}` here", lifetime_ref.ident),
sugg,
Applicability::MaybeIncorrect,
);
}
}
- MissingLifetimeSpot::HigherRanked { span, span_type } => {
- err.span_suggestion(
- *span,
- &format!(
- "consider making the {} lifetime-generic with a new `{}` lifetime",
- span_type.descr(),
- lifetime_ref
- ),
- span_type.suggestion(&lifetime_ref.to_string()),
- Applicability::MaybeIncorrect,
- );
- err.note(
- "for more information on higher-ranked polymorphism, visit \
- https://doc.rust-lang.org/nomicon/hrtb.html",
- );
- }
+ LifetimeRibKind::Item => break,
_ => {}
}
}
+
err.emit();
}
+}
+
+impl<'tcx> LifetimeContext<'_, 'tcx> {
+ crate fn report_missing_lifetime_specifiers(
+ &self,
+ spans: Vec<Span>,
+ count: usize,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ struct_span_err!(
+ self.tcx.sess,
+ spans,
+ E0106,
+ "missing lifetime specifier{}",
+ pluralize!(count)
+ )
+ }
/// Returns whether to add `'static` lifetime to the suggested lifetime list.
crate fn report_elision_failure(
}
}
- crate fn report_elided_lifetime_in_ty(&self, lifetime_refs: &[&hir::Lifetime]) {
- let Some(missing_lifetime) = lifetime_refs.iter().find(|lt| {
- lt.name == hir::LifetimeName::Implicit(true)
- }) else { return };
-
- let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
- spans.sort();
- let mut spans_dedup = spans.clone();
- spans_dedup.dedup();
- let spans_with_counts: Vec<_> = spans_dedup
- .into_iter()
- .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count()))
- .collect();
-
- self.tcx.struct_span_lint_hir(
- rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
- missing_lifetime.hir_id,
- spans,
- |lint| {
- let mut db = lint.build("hidden lifetime parameters in types are deprecated");
- self.add_missing_lifetime_specifiers_label(
- &mut db,
- spans_with_counts,
- &FxHashSet::from_iter([kw::UnderscoreLifetime]),
- Vec::new(),
- &[],
- );
- db.emit();
- },
- );
- }
-
// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
// generics. We are disallowing this until we can decide on how we want to handle non-'static
// lifetimes in const generics. See issue #74052 for discussion.
);
let is_allowed_lifetime = matches!(
lifetime_ref.name,
- hir::LifetimeName::Implicit(_)
- | hir::LifetimeName::Static
- | hir::LifetimeName::Underscore
+ hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
);
if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
map: &'a mut NamedRegionMap,
scope: ScopeRef<'a>,
- /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
- is_in_fn_syntax: bool,
-
is_in_const_generic: bool,
/// Indicates that we only care about the definition of a trait. This should
tcx,
map: &mut named_region_map,
scope: ROOT_SCOPE,
- is_in_fn_syntax: false,
is_in_const_generic: false,
trait_definition_only,
labels_in_fn: vec![],
match ty.kind {
hir::TyKind::BareFn(ref c) => {
let next_early_index = self.next_early_index();
- let was_in_fn_syntax = self.is_in_fn_syntax;
- self.is_in_fn_syntax = true;
let lifetime_span: Option<Span> =
c.generic_params.iter().rev().find_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(param.span),
intravisit::walk_ty(this, ty);
});
self.missing_named_lifetime_spots.pop();
- self.is_in_fn_syntax = was_in_fn_syntax;
}
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
debug!(?bounds, ?lifetime, "TraitObject");
}
});
match lifetime.name {
- LifetimeName::Implicit(_) => {
+ LifetimeName::Implicit => {
// For types like `dyn Foo`, we should
// generate a special form of elided.
span_bug!(ty.span, "object-lifetime-default expected, not implicit",);
tcx: *tcx,
map,
scope: &wrap_scope,
- is_in_fn_syntax: self.is_in_fn_syntax,
is_in_const_generic: self.is_in_const_generic,
trait_definition_only: self.trait_definition_only,
labels_in_fn,
self.insert_lifetime(lifetime_ref, def);
} else {
- self.emit_undeclared_lifetime_error(lifetime_ref);
+ self.tcx.sess.delay_span_bug(
+ lifetime_ref.span,
+ &format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
+ );
}
}
);
if generic_args.parenthesized {
- let was_in_fn_syntax = self.is_in_fn_syntax;
- self.is_in_fn_syntax = true;
self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty()));
- self.is_in_fn_syntax = was_in_fn_syntax;
return;
}
let error = loop {
match *scope {
// Do not assign any resolution, it will be inferred.
- Scope::Body { .. } => break Ok(()),
+ Scope::Body { .. } => return,
- Scope::Root => break Err(None),
+ Scope::Root => break None,
Scope::Binder { s, ref lifetimes, scope_type, .. } => {
// collect named lifetimes for suggestions
self.insert_lifetime(lifetime_ref, lifetime);
}
- break Ok(());
+ return;
}
Scope::Elision { elide: Elide::Exact(l), .. } => {
for lifetime_ref in lifetime_refs {
self.insert_lifetime(lifetime_ref, lifetime);
}
- break Ok(());
+ return;
}
Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => {
_ => break,
}
}
- break Err(Some(&e[..]));
+ break Some(&e[..]);
}
- Scope::Elision { elide: Elide::Forbid, .. } => break Err(None),
+ Scope::Elision { elide: Elide::Forbid, .. } => break None,
Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
}
};
- let error = match error {
- Ok(()) => {
- self.report_elided_lifetime_in_ty(lifetime_refs);
- return;
- }
- Err(error) => error,
- };
-
// If we specifically need the `scope_for_path` map, then we're in the
// diagnostic pass and we don't want to emit more errors.
if self.map.scope_for_path.is_some() {
if let hir::ParamName::Plain(_) = lifetime_i_name {
let name = lifetime_i_name.ident().name;
if name == kw::UnderscoreLifetime || name == kw::StaticLifetime {
- let mut err = struct_span_err!(
- self.tcx.sess,
- lifetime_i.span,
- E0262,
- "invalid lifetime parameter name: `{}`",
- lifetime_i.name.ident(),
- );
- err.span_label(
+ self.tcx.sess.delay_span_bug(
lifetime_i.span,
- format!("{} is a reserved lifetime name", name),
+ &format!("invalid lifetime parameter name: `{}`", lifetime_i.name.ident()),
);
- err.emit();
}
}
))
.emit();
}
- hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit(_) => {
+ hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
self.resolve_lifetime_ref(lt);
}
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
#![feature(drain_filter)]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
+#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(let_else)]
#![feature(never_type)]
use rustc_arena::{DroplessArena, TypedArena};
use rustc_ast::node_id::NodeMap;
use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID};
-use rustc_ast::{Crate, Expr, ExprKind, LitKind, Path};
+use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::intern::Interned;
use rustc_hir::def::Namespace::*;
use rustc_hir::def::{self, CtorOf, DefKind, PartialRes};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId};
-use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
use rustc_hir::TraitCandidate;
use rustc_index::vec::IndexVec;
/// Signals whether this `PathSegment` has generic arguments. Used to avoid providing
/// nonsensical suggestions.
has_generic_args: bool,
+ /// Signals whether this `PathSegment` has lifetime arguments.
+ has_lifetime_args: bool,
+ args_span: Span,
}
impl Segment {
}
fn from_ident(ident: Ident) -> Segment {
- Segment { ident, id: None, has_generic_args: false }
+ Segment {
+ ident,
+ id: None,
+ has_generic_args: false,
+ has_lifetime_args: false,
+ args_span: DUMMY_SP,
+ }
+ }
+
+ fn from_ident_and_id(ident: Ident, id: NodeId) -> Segment {
+ Segment {
+ ident,
+ id: Some(id),
+ has_generic_args: false,
+ has_lifetime_args: false,
+ args_span: DUMMY_SP,
+ }
}
fn names_to_string(segments: &[Segment]) -> String {
impl<'a> From<&'a ast::PathSegment> for Segment {
fn from(seg: &'a ast::PathSegment) -> Segment {
- Segment { ident: seg.ident, id: Some(seg.id), has_generic_args: seg.args.is_some() }
+ let has_generic_args = seg.args.is_some();
+ let (args_span, has_lifetime_args) = if let Some(args) = seg.args.as_deref() {
+ match args {
+ GenericArgs::AngleBracketed(args) => {
+ let found_lifetimes = args
+ .args
+ .iter()
+ .any(|arg| matches!(arg, AngleBracketedArg::Arg(GenericArg::Lifetime(_))));
+ (args.span, found_lifetimes)
+ }
+ GenericArgs::Parenthesized(args) => (args.span, true),
+ }
+ } else {
+ (DUMMY_SP, false)
+ };
+ Segment {
+ ident: seg.ident,
+ id: Some(seg.id),
+ has_generic_args,
+ has_lifetime_args,
+ args_span,
+ }
}
}
NameBindingKind::Module(&ModuleData {
kind: ModuleKind::Def(DefKind::Mod, def_id, _),
..
- }) => def_id.index == CRATE_DEF_INDEX,
+ }) => def_id.is_crate_root(),
_ => false,
}
}
);
let definitions = Definitions::new(session.local_stable_crate_id(), krate.spans.inner_span);
- let root = definitions.get_root_def();
let mut visibilities = FxHashMap::default();
visibilities.insert(CRATE_DEF_ID, ty::Visibility::Public);
let mut def_id_to_node_id = IndexVec::default();
- assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), root);
+ assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), CRATE_DEF_ID);
let mut node_id_to_def_id = FxHashMap::default();
- node_id_to_def_id.insert(CRATE_NODE_ID, root);
+ node_id_to_def_id.insert(CRATE_NODE_ID, CRATE_DEF_ID);
let mut invocation_parents = FxHashMap::default();
- invocation_parents.insert(LocalExpnId::ROOT, (root, ImplTraitContext::Existential));
+ invocation_parents.insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential));
let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = session
.opts
}
pub fn next_node_id(&mut self) -> NodeId {
- let next =
- self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
- mem::replace(&mut self.next_node_id, ast::NodeId::from_u32(next))
+ let start = self.next_node_id;
+ let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
+ self.next_node_id = ast::NodeId::from_u32(next);
+ start
+ }
+
+ pub fn next_node_ids(&mut self, count: usize) -> std::ops::Range<NodeId> {
+ let start = self.next_node_id;
+ let end = start.as_usize().checked_add(count).expect("input too large; ran out of NodeIds");
+ self.next_node_id = ast::NodeId::from_usize(end);
+ start..self.next_node_id
}
pub fn lint_buffer(&mut self) -> &mut LintBuffer {
pub use crate::options::*;
-use crate::lint;
use crate::search_paths::SearchPath;
use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
use crate::{early_error, early_warn, Session};
+use crate::{lint, HashStableContext};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::impl_stable_hash_via_hash;
+use rustc_data_structures::stable_hasher::ToStableHashKey;
use rustc_target::abi::{Align, TargetDataLayout};
use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS};
-use rustc_serialize::json;
-
use crate::parse::{CrateCheckConfig, CrateConfig};
use rustc_feature::UnstableFeatures;
use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
Full,
}
-#[derive(Clone, Copy, Debug, PartialEq, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
pub enum OptLevel {
No, // -O0
Less, // -O1
SizeMin, // -Oz
}
-impl_stable_hash_via_hash!(OptLevel);
-
/// This is what the `LtoCli` values get mapped to after resolving defaults and
/// and taking other command line options into account.
///
}
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
#[derive(Encodable, Decodable)]
pub enum SymbolManglingVersion {
Legacy,
V0,
}
-impl_stable_hash_via_hash!(SymbolManglingVersion);
-
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum DebugInfo {
None,
}
}
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
#[derive(Encodable, Decodable)]
pub enum OutputType {
Bitcode,
DepInfo,
}
-impl_stable_hash_via_hash!(OutputType);
+impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
+ type KeyType = Self;
+
+ fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
+ *self
+ }
+}
impl OutputType {
fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
/// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
/// dependency tracking for command-line arguments. Also only hash keys, since tracking
/// should only depend on the output types, not the paths they're written to.
-#[derive(Clone, Debug, Hash)]
+#[derive(Clone, Debug, Hash, HashStable_Generic)]
pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
impl OutputTypes {
#[derive(Clone)]
pub struct Externs(BTreeMap<String, ExternEntry>);
-#[derive(Clone)]
-pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
-
#[derive(Clone, Debug)]
pub struct ExternEntry {
pub location: ExternLocation,
ExactPaths(BTreeSet<CanonicalizedPath>),
}
-/// Supplied source location of a dependency - for example in a build specification
-/// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
-/// a file and line, then the build system can specify that. On the other hand, it may
-/// make more sense to have an arbitrary raw string.
-#[derive(Clone, PartialEq)]
-pub enum ExternDepSpec {
- /// Raw string
- Raw(String),
- /// Raw data in json format
- Json(json::Json),
-}
-
-impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
- fn from(from: &'a ExternDepSpec) -> Self {
- match from {
- ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
- ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
- }
- }
-}
-
impl Externs {
/// Used for testing.
pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
}
}
-impl ExternDepSpecs {
- pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
- ExternDepSpecs(data)
- }
-
- pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
- self.0.get(key)
- }
-}
-
-impl fmt::Display for ExternDepSpec {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- ExternDepSpec::Raw(raw) => fmt.write_str(raw),
- ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
- }
- }
-}
-
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum PrintRequest {
FileNames,
}
}
-#[derive(Clone, Hash, Debug)]
+#[derive(Clone, Hash, Debug, HashStable_Generic)]
pub struct OutputFilenames {
pub out_directory: PathBuf,
filestem: String,
pub outputs: OutputTypes,
}
-impl_stable_hash_via_hash!(OutputFilenames);
-
pub const RLINK_EXT: &str = "rlink";
pub const RUST_CGU_EXT: &str = "rcgu";
pub const DWARF_OBJECT_EXT: &str = "dwo";
cg: Default::default(),
error_format: ErrorOutputType::default(),
externs: Externs(BTreeMap::new()),
- extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
crate_name: None,
libs: Vec::new(),
unstable_features: UnstableFeatures::Disallow,
}
// The type of entry function, so users can have their own entry functions
-#[derive(Copy, Clone, PartialEq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
pub enum EntryFnType {
Main,
Start,
}
-impl_stable_hash_via_hash!(EntryFnType);
-
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
pub enum CrateType {
Executable,
Dylib,
ProcMacro,
}
-impl_stable_hash_via_hash!(CrateType);
-
impl CrateType {
/// When generated, is this crate type an archive?
pub fn is_archive(&self) -> bool {
"Specify where an external rust library is located",
"NAME[=PATH]",
),
- opt::multi_s(
- "",
- "extern-location",
- "Location where an external crate dependency is specified",
- "NAME=LOCATION",
- ),
opt::opt_s("", "sysroot", "Override the system root", "PATH"),
opt::multi("Z", "", "Set internal debugging options", "FLAG"),
opt::opt_s(
Externs(externs)
}
-fn parse_extern_dep_specs(
- matches: &getopts::Matches,
- debugging_opts: &DebuggingOptions,
- error_format: ErrorOutputType,
-) -> ExternDepSpecs {
- let is_unstable_enabled = debugging_opts.unstable_options;
- let mut map = BTreeMap::new();
-
- for arg in matches.opt_strs("extern-location") {
- if !is_unstable_enabled {
- early_error(
- error_format,
- "`--extern-location` option is unstable: set `-Z unstable-options`",
- );
- }
-
- let mut parts = arg.splitn(2, '=');
- let name = parts.next().unwrap_or_else(|| {
- early_error(error_format, "`--extern-location` value must not be empty")
- });
- let loc = parts.next().unwrap_or_else(|| {
- early_error(
- error_format,
- &format!("`--extern-location`: specify location for extern crate `{name}`"),
- )
- });
-
- let locparts: Vec<_> = loc.split(':').collect();
- let spec = match &locparts[..] {
- ["raw", ..] => {
- // Don't want `:` split string
- let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
- early_error(error_format, "`--extern-location`: missing `raw` location")
- });
- ExternDepSpec::Raw(raw.to_string())
- }
- ["json", ..] => {
- // Don't want `:` split string
- let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
- early_error(error_format, "`--extern-location`: missing `json` location")
- });
- let json = json::from_str(raw).unwrap_or_else(|_| {
- early_error(
- error_format,
- &format!("`--extern-location`: malformed json location `{raw}`"),
- )
- });
- ExternDepSpec::Json(json)
- }
- [bad, ..] => early_error(
- error_format,
- &format!("unknown location type `{bad}`: use `raw` or `json`"),
- ),
- [] => early_error(error_format, "missing location specification"),
- };
-
- map.insert(name.to_string(), spec);
- }
-
- ExternDepSpecs::new(map)
-}
-
fn parse_remap_path_prefix(
matches: &getopts::Matches,
debugging_opts: &DebuggingOptions,
}
let externs = parse_externs(matches, &debugging_opts, error_format);
- let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
let crate_name = matches.opt_str("crate-name");
error_format,
externs,
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
- extern_dep_specs,
crate_name,
libs,
debug_assertions,
borrowck_mode: BorrowckMode [UNTRACKED],
cg: CodegenOptions [SUBSTRUCT],
externs: Externs [UNTRACKED],
- extern_dep_specs: ExternDepSpecs [UNTRACKED],
crate_name: Option<String> [TRACKED],
/// Indicates how the compiler should treat unstable features.
unstable_features: UnstableFeatures [TRACKED],
pub file_name_str: String,
}
-#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable)]
+#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable, HashStable_Generic)]
pub enum PathKind {
Native,
Crate,
All,
}
-rustc_data_structures::impl_stable_hash_via_hash!(PathKind);
-
impl PathKind {
pub fn matches(&self, kind: PathKind) -> bool {
match (self, kind) {
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
pub enum NativeLibKind {
/// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC)
Static {
}
}
-rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind);
-
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
pub struct NativeLib {
pub name: String,
pub new_name: Option<String>,
}
}
-rustc_data_structures::impl_stable_hash_via_hash!(NativeLib);
-
/// A path that has been canonicalized along with its original, non-canonicalized form
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CanonicalizedPath {
self.as_local().unwrap_or_else(|| panic!("DefId::expect_local: `{:?}` isn't local", self))
}
+ #[inline]
+ pub fn is_crate_root(self) -> bool {
+ self.index == CRATE_DEF_INDEX
+ }
+
+ #[inline]
+ pub fn as_crate_root(self) -> Option<CrateNum> {
+ if self.is_crate_root() { Some(self.krate) } else { None }
+ }
+
+ #[inline]
pub fn is_top_level_module(self) -> bool {
- self.is_local() && self.index == CRATE_DEF_INDEX
+ self.is_local() && self.is_crate_root()
}
}
#[inline]
pub fn is_top_level_module(self) -> bool {
- self.local_def_index == CRATE_DEF_INDEX
+ self == CRATE_DEF_ID
}
}
/// of `HashingControls` settings.
fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str) {
match ctx.hashing_controls() {
- // Ideally, we would also check that `node_id_hashing_mode` was always
- // `NodeIdHashingMode::HashDefPath`. However, we currently end up hashing
- // `Span`s in this mode, and there's not an easy way to change that.
- // All of the span-related data that we hash is pretty self-contained
- // (in particular, we don't hash any `HirId`s), so this shouldn't result
- // in any caching problems.
- // FIXME: Enforce that we don't end up transitively hashing any `HirId`s,
- // or ensure that this method is always invoked with the same
- // `NodeIdHashingMode`
- //
// Note that we require that `hash_spans` be set according to the global
// `-Z incremental-ignore-spans` option. Normally, this option is disabled,
// which will cause us to require that this method always be called with `Span` hashing
pub struct OffsetOverflowError;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
pub enum SourceFileHashAlgorithm {
Md5,
Sha1,
}
}
-rustc_data_structures::impl_stable_hash_via_hash!(SourceFileHashAlgorithm);
-
/// The hash of the on-disk source file used for debug info.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[derive(HashStable_Generic, Encodable, Decodable)]
keyword,
kind,
kreg,
+ kreg0,
label,
label_break_value,
lang,
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
- k1, k2, k3, k4, k5, k6, k7,
+ k0, k1, k2, k3, k4, k5, k6, k7,
mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
st0, st1, st2, st3, st4, st5, st6, st7,
zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
- k1, k2, k3, k4, k5, k6, k7,
+ k0, k1, k2, k3, k4, k5, k6, k7,
mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
st0, st1, st2, st3, st4, st5, st6, st7,
zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
- k1, k2, k3, k4, k5, k6, k7,
+ k0, k1, k2, k3, k4, k5, k6, k7,
mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
st0, st1, st2, st3, st4, st5, st6, st7,
ymm_reg,
zmm_reg,
kreg,
+ kreg0,
mmx_reg,
x87_reg,
}
}
Self::reg_byte => &[],
Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'],
- Self::kreg => &[],
+ Self::kreg | Self::kreg0 => &[],
Self::mmx_reg | Self::x87_reg => &[],
}
}
256 => Some(('y', "ymm0")),
_ => Some(('x', "xmm0")),
},
- Self::kreg => None,
+ Self::kreg | Self::kreg0 => None,
Self::mmx_reg | Self::x87_reg => None,
}
}
Self::xmm_reg => Some(('x', "xmm0")),
Self::ymm_reg => Some(('y', "ymm0")),
Self::zmm_reg => Some(('z', "zmm0")),
- Self::kreg => None,
+ Self::kreg | Self::kreg0 => None,
Self::mmx_reg | Self::x87_reg => None,
}
}
avx512f: I8, I16;
avx512bw: I32, I64;
},
+ Self::kreg0 => &[],
Self::mmx_reg | Self::x87_reg => &[],
}
}
zmm29: zmm_reg = ["zmm29", "xmm29", "ymm29"] % x86_64_only,
zmm30: zmm_reg = ["zmm30", "xmm30", "ymm30"] % x86_64_only,
zmm31: zmm_reg = ["zmm31", "xmm31", "ymm31"] % x86_64_only,
+ k0: kreg0 = ["k0"],
k1: kreg = ["k1"],
k2: kreg = ["k2"],
k3: kreg = ["k3"],
"the stack pointer cannot be used as an operand for inline asm",
#error = ["ip", "eip", "rip"] =>
"the instruction pointer cannot be used as an operand for inline asm",
- #error = ["k0"] =>
- "the k0 AVX mask register cannot be used as an operand for inline asm",
}
}
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
+use rustc_middle::hir::map;
use rustc_middle::ty::{
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
- Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable,
+ GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, ToPredicate, Ty, TyCtxt,
+ TypeFoldable,
};
use rustc_middle::ty::{TypeAndMut, TypeckResults};
use rustc_session::Limit;
Upvar(Span),
}
+// This type provides a uniform interface to retrieve data on generators, whether it originated from
+// the local crate being compiled or from a foreign crate.
+#[derive(Debug)]
+pub enum GeneratorData<'tcx, 'a> {
+ Local(&'a TypeckResults<'tcx>),
+ Foreign(&'tcx GeneratorDiagnosticData<'tcx>),
+}
+
+impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
+ // Try to get information about variables captured by the generator that matches a type we are
+ // looking for with `ty_matches` function. We uses it to find upvar which causes a failure to
+ // meet an obligation
+ fn try_get_upvar_span<F>(
+ &self,
+ infer_context: &InferCtxt<'a, 'tcx>,
+ generator_did: DefId,
+ ty_matches: F,
+ ) -> Option<GeneratorInteriorOrUpvar>
+ where
+ F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
+ {
+ match self {
+ GeneratorData::Local(typeck_results) => {
+ infer_context.tcx.upvars_mentioned(generator_did).and_then(|upvars| {
+ upvars.iter().find_map(|(upvar_id, upvar)| {
+ let upvar_ty = typeck_results.node_type(*upvar_id);
+ let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty);
+ if ty_matches(ty::Binder::dummy(upvar_ty)) {
+ Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
+ } else {
+ None
+ }
+ })
+ })
+ }
+ GeneratorData::Foreign(_) => None,
+ }
+ }
+
+ // Try to get the span of a type being awaited on that matches the type we are looking with the
+ // `ty_matches` function. We uses it to find awaited type which causes a failure to meet an
+ // obligation
+ fn get_from_await_ty<F>(
+ &self,
+ visitor: AwaitsVisitor,
+ hir: map::Map<'tcx>,
+ ty_matches: F,
+ ) -> Option<Span>
+ where
+ F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
+ {
+ match self {
+ GeneratorData::Local(typeck_results) => visitor
+ .awaits
+ .into_iter()
+ .map(|id| hir.expect_expr(id))
+ .find(|await_expr| {
+ ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
+ })
+ .map(|expr| expr.span),
+ GeneratorData::Foreign(generator_diagnostic_data) => visitor
+ .awaits
+ .into_iter()
+ .map(|id| hir.expect_expr(id))
+ .find(|await_expr| {
+ ty_matches(ty::Binder::dummy(
+ generator_diagnostic_data
+ .adjustments
+ .get(&await_expr.hir_id.local_id)
+ .map_or::<&[ty::adjustment::Adjustment<'tcx>], _>(&[], |a| &a[..])
+ .last()
+ .map_or_else::<Ty<'tcx>, _, _>(
+ || {
+ generator_diagnostic_data
+ .nodes_types
+ .get(&await_expr.hir_id.local_id)
+ .cloned()
+ .unwrap_or_else(|| {
+ bug!(
+ "node_type: no type for node `{}`",
+ ty::tls::with(|tcx| tcx
+ .hir()
+ .node_to_string(await_expr.hir_id))
+ )
+ })
+ },
+ |adj| adj.target,
+ ),
+ ))
+ })
+ .map(|expr| expr.span),
+ }
+ }
+
+ /// Get the type, expression, span and optional scope span of all types
+ /// that are live across the yield of this generator
+ fn get_generator_interior_types(
+ &self,
+ ) -> ty::Binder<'tcx, &Vec<GeneratorInteriorTypeCause<'tcx>>> {
+ match self {
+ GeneratorData::Local(typeck_result) => typeck_result.generator_interior_types.as_ref(),
+ GeneratorData::Foreign(generator_diagnostic_data) => {
+ generator_diagnostic_data.generator_interior_types.as_ref()
+ }
+ }
+ }
+
+ // Used to get the source of the data, note we don't have as much information for generators
+ // originated from foreign crates
+ fn is_foreign(&self) -> bool {
+ match self {
+ GeneratorData::Local(_) => false,
+ GeneratorData::Foreign(_) => true,
+ }
+ }
+}
+
// This trait is public to expose the diagnostics methods to clippy.
pub trait InferCtxtExt<'tcx> {
fn suggest_restricting_param_bound(
err: &mut Diagnostic,
interior_or_upvar_span: GeneratorInteriorOrUpvar,
interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
- inner_generator_body: Option<&hir::Body<'tcx>>,
+ is_async: bool,
outer_generator: Option<DefId>,
trait_pred: ty::TraitPredicate<'tcx>,
target_ty: Ty<'tcx>,
.map(|def_id| hir.local_def_id_to_hir_id(def_id))
.and_then(|hir_id| hir.maybe_body_owned_by(hir_id))
.map(|body_id| hir.body(body_id));
+ let is_async = match generator_did.as_local() {
+ Some(_) => generator_body
+ .and_then(|body| body.generator_kind())
+ .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
+ .unwrap_or(false),
+ None => self
+ .tcx
+ .generator_kind(generator_did)
+ .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
+ .unwrap_or(false),
+ };
let mut visitor = AwaitsVisitor::default();
if let Some(body) = generator_body {
visitor.visit_body(body);
// type-checking; otherwise, get them by performing a query. This is needed to avoid
// cycles. If we can't use resolved types because the generator comes from another crate,
// we still provide a targeted error but without all the relevant spans.
- let query_typeck_results;
- let typeck_results: Option<&TypeckResults<'tcx>> = match &in_progress_typeck_results {
- Some(t) if t.hir_owner.to_def_id() == generator_did_root => Some(&t),
+ let generator_data: Option<GeneratorData<'tcx, '_>> = match &in_progress_typeck_results {
+ Some(t) if t.hir_owner.to_def_id() == generator_did_root => {
+ Some(GeneratorData::Local(&t))
+ }
_ if generator_did.is_local() => {
- query_typeck_results = self.tcx.typeck(generator_did.expect_local());
- Some(&query_typeck_results)
+ Some(GeneratorData::Local(self.tcx.typeck(generator_did.expect_local())))
}
- _ => None, // Do not ICE on closure typeck (#66868).
+ _ => self
+ .tcx
+ .generator_diagnostic_data(generator_did)
+ .as_ref()
+ .map(|generator_diag_data| GeneratorData::Foreign(generator_diag_data)),
};
- if let Some(typeck_results) = typeck_results {
- if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
- interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
- let upvar_ty = typeck_results.node_type(*upvar_id);
- let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
- if ty_matches(ty::Binder::dummy(upvar_ty)) {
- Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
- } else {
- None
- }
- });
- };
+
+ if let Some(generator_data) = generator_data.as_ref() {
+ interior_or_upvar_span =
+ generator_data.try_get_upvar_span(&self, generator_did, ty_matches);
// The generator interior types share the same binders
if let Some(cause) =
- typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
+ generator_data.get_generator_interior_types().skip_binder().iter().find(
|ty::GeneratorInteriorTypeCause { ty, .. }| {
- ty_matches(typeck_results.generator_interior_types.rebind(*ty))
+ ty_matches(generator_data.get_generator_interior_types().rebind(*ty))
},
)
{
- // Check to see if any awaited expressions have the target type.
- let from_awaited_ty = visitor
- .awaits
- .into_iter()
- .map(|id| hir.expect_expr(id))
- .find(|await_expr| {
- ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
- })
- .map(|expr| expr.span);
+ let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches);
let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
cause;
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
- };
- } else {
- interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+ }
+
+ if interior_or_upvar_span.is_none() && generator_data.is_foreign() {
+ interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+ }
}
if let Some(interior_or_upvar_span) = interior_or_upvar_span {
+ let typeck_results = generator_data.and_then(|generator_data| match generator_data {
+ GeneratorData::Local(typeck_results) => Some(typeck_results),
+ GeneratorData::Foreign(_) => None,
+ });
self.note_obligation_cause_for_async_await(
err,
interior_or_upvar_span,
interior_extra_info,
- generator_body,
+ is_async,
outer_generator,
trait_ref,
target_ty,
err: &mut Diagnostic,
interior_or_upvar_span: GeneratorInteriorOrUpvar,
interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
- inner_generator_body: Option<&hir::Body<'tcx>>,
+ is_async: bool,
outer_generator: Option<DefId>,
trait_pred: ty::TraitPredicate<'tcx>,
target_ty: Ty<'tcx>,
) {
let source_map = self.tcx.sess.source_map();
- let is_async = inner_generator_body
- .and_then(|body| body.generator_kind())
- .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
- .unwrap_or(false);
let (await_or_yield, an_await_or_yield) =
if is_async { ("await", "an await") } else { ("yield", "a yield") };
let future_or_generator = if is_async { "future" } else { "generator" };
use rustc_span::{Span, DUMMY_SP};
use std::collections::BTreeSet;
-use std::iter;
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
let mut suggestions = vec![];
let mut types_count = 0;
let mut where_constraints = vec![];
+ let mut already_has_generics_args_suggestion = false;
for (span, assoc_items) in &associated_types {
let mut names: FxHashMap<_, usize> = FxHashMap::default();
for item in assoc_items {
}
}
if potential_assoc_types.len() == assoc_items.len() {
- // Only suggest when the amount of missing associated types equals the number of
- // extra type arguments present, as that gives us a relatively high confidence
- // that the user forgot to give the associated type's name. The canonical
- // example would be trying to use `Iterator<isize>` instead of
- // `Iterator<Item = isize>`.
- for (potential, item) in iter::zip(&potential_assoc_types, assoc_items) {
- if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) {
- suggestions.push((*potential, format!("{} = {}", item.name, snippet)));
- }
- }
+ // When the amount of missing associated types equals the number of
+ // extra type arguments present. A suggesting to replace the generic args with
+ // associated types is already emitted.
+ already_has_generics_args_suggestion = true;
} else if let (Ok(snippet), false) =
(tcx.sess.source_map().span_to_snippet(*span), dupes)
{
// the same associated type name.
err.help(where_msg);
}
- if suggestions.len() != 1 {
+ if suggestions.len() != 1 || already_has_generics_args_suggestion {
// We don't need this label if there's an inline suggestion, show otherwise.
for (span, assoc_items) in &associated_types {
let mut names: FxHashMap<_, usize> = FxHashMap::default();
SuggestionText::Remove(plural) => {
Some(format!("remove the extra argument{}", if plural { "s" } else { "" }))
}
- SuggestionText::Swap => Some(format!("swap these arguments")),
- SuggestionText::Reorder => Some(format!("reorder these arguments")),
- SuggestionText::DidYouMean => Some(format!("did you mean")),
+ SuggestionText::Swap => Some("swap these arguments".to_string()),
+ SuggestionText::Reorder => Some("reorder these arguments".to_string()),
+ SuggestionText::DidYouMean => Some("did you mean".to_string()),
};
if let Some(suggestion_text) = suggestion_text {
let source_map = self.sess().source_map();
self.tcx.sess,
span,
E0529,
- "expected an array or slice, found `{}`",
- expected_ty
+ "expected an array or slice, found `{expected_ty}`"
);
- if let ty::Ref(_, ty, _) = expected_ty.kind() {
- if let ty::Array(..) | ty::Slice(..) = ty.kind() {
- err.help("the semantics of slice patterns changed recently; see issue #62254");
- }
+ if let ty::Ref(_, ty, _) = expected_ty.kind()
+ && let ty::Array(..) | ty::Slice(..) = ty.kind()
+ {
+ err.help("the semantics of slice patterns changed recently; see issue #62254");
} else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span)
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
+ && let (Some(span), true) = (ti.span, ti.origin_expr)
+ && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
{
- if let (Some(span), true) = (ti.span, ti.origin_expr) {
- if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
- let applicability = Autoderef::new(
- &self.infcx,
- self.param_env,
- self.body_id,
- span,
- self.resolve_vars_if_possible(ti.expected),
+ let ty = self.resolve_vars_if_possible(ti.expected);
+ let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(&mut err, snippet.clone(), ty);
+ match is_slice_or_array_or_vector.1.kind() {
+ ty::Adt(adt_def, _)
+ if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
+ || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
+ {
+ // Slicing won't work here, but `.as_deref()` might (issue #91328).
+ err.span_suggestion(
span,
- )
- .find_map(|(ty, _)| {
- match ty.kind() {
- ty::Adt(adt_def, _)
- if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
- || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
- {
- // Slicing won't work here, but `.as_deref()` might (issue #91328).
- err.span_suggestion(
- span,
- "consider using `as_deref` here",
- format!("{}.as_deref()", snippet),
- Applicability::MaybeIncorrect,
- );
- Some(None)
- }
-
- ty::Slice(..) | ty::Array(..) => {
- Some(Some(Applicability::MachineApplicable))
- }
-
- _ => None,
- }
- })
- .unwrap_or(Some(Applicability::MaybeIncorrect));
-
- if let Some(applicability) = applicability {
- err.span_suggestion(
- span,
- "consider slicing here",
- format!("{}[..]", snippet),
- applicability,
- );
- }
+ "consider using `as_deref` here",
+ format!("{snippet}.as_deref()"),
+ Applicability::MaybeIncorrect,
+ );
}
+ _ => ()
+ }
+ if is_slice_or_array_or_vector.0 {
+ err.span_suggestion(
+ span,
+ "consider slicing here",
+ format!("{snippet}[..]"),
+ Applicability::MachineApplicable,
+ );
}
}
- err.span_label(span, format!("pattern cannot match with input type `{}`", expected_ty));
+ err.span_label(span, format!("pattern cannot match with input type `{expected_ty}`"));
err.emit();
}
+
+ fn is_slice_or_array_or_vector(
+ &self,
+ err: &mut Diagnostic,
+ snippet: String,
+ ty: Ty<'tcx>,
+ ) -> (bool, Ty<'tcx>) {
+ match ty.kind() {
+ ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
+ (true, ty)
+ }
+ ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(err, snippet, *ty),
+ ty::Slice(..) | ty::Array(..) => (true, ty),
+ _ => (false, ty),
+ }
+ }
}
#[primary_span]
#[label]
pub span: Span,
- #[suggestion_verbose(message = "suggestion", code = "{ty}")]
+ #[suggestion_verbose(code = "{ty}")]
pub opt_sugg: Option<(Span, Applicability)>,
}
use rustc_hir as hir;
use rustc_middle::hir::map::fn_sig;
use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath;
-use rustc_middle::ty::{self as ty, TyCtxt};
+use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
use rustc_session::Session;
use rustc_span::def_id::DefId;
+use std::iter;
use GenericArgsInfo::*;
.join(", ")
}
+ fn get_unbound_associated_types(&self) -> Vec<String> {
+ if self.tcx.is_trait(self.def_id) {
+ let items: &AssocItems<'_> = self.tcx.associated_items(self.def_id);
+ items
+ .in_definition_order()
+ .filter(|item| item.kind == AssocKind::Type)
+ .filter(|item| {
+ !self.gen_args.bindings.iter().any(|binding| binding.ident.name == item.name)
+ })
+ .map(|item| item.name.to_ident_string())
+ .collect()
+ } else {
+ Vec::default()
+ }
+ }
+
fn create_error_message(&self) -> String {
let def_path = self.tcx.def_path_str(self.def_id);
let def_kind = self.tcx.def_kind(self.def_id).descr(self.def_id);
fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) {
let num_provided_lt_args = self.num_provided_lifetime_args();
let num_provided_type_const_args = self.num_provided_type_or_const_args();
+ let unbound_types = self.get_unbound_associated_types();
let num_provided_args = num_provided_lt_args + num_provided_type_const_args;
assert!(num_provided_args > 0);
let redundant_type_or_const_args = num_redundant_type_or_const_args > 0;
let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
+ let provided_args_matches_unbound_traits =
+ unbound_types.len() == num_redundant_type_or_const_args;
let remove_lifetime_args = |err: &mut Diagnostic| {
let mut lt_arg_spans = Vec::new();
);
};
- if remove_entire_generics {
+ // If there is a single unbound associated type and a single excess generic param
+ // suggest replacing the generic param with the associated type bound
+ if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
+ let mut suggestions = vec![];
+ let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
+ for (potential, name) in iter::zip(unused_generics, &unbound_types) {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(potential.span()) {
+ suggestions.push((potential.span(), format!("{} = {}", name, snippet)));
+ }
+ }
+
+ if !suggestions.is_empty() {
+ err.multipart_suggestion(
+ &format!(
+ "replace the generic bound{s} with the associated type{s}",
+ s = pluralize!(unbound_types.len())
+ ),
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ } else if remove_entire_generics {
let span = self
.path_segment
.args
# FIXME(#61117): Some tests fail when this option is enabled.
#debuginfo-level-tests = 0
-# Whether to run `dsymutil` on Apple platforms to gather debug info into .dSYM
-# bundles. `dsymutil` adds time to builds for no clear benefit, and also makes
-# it more difficult for debuggers to find debug info. The compiler currently
-# defaults to running `dsymutil` to preserve its historical default, but when
-# compiling the compiler itself, we skip it by default since we know it's safe
-# to do so in that case.
-#run-dsymutil = false
+# Should rustc be build with split debuginfo? Default is platform dependent.
+# Valid values are the same as those accepted by `-C split-debuginfo`
+# (`off`/`unpacked`/`packed`).
+#
+# On Linux, split debuginfo is disabled by default.
+#
+# On Apple platforms, unpacked split debuginfo is used by default. Unpacked
+# debuginfo does not run `dsymutil`, which packages debuginfo from disparate
+# object files into a single `.dSYM` file. `dsymutil` adds time to builds for
+# no clear benefit, and also makes it more difficult for debuggers to find
+# debug info. The compiler currently defaults to running `dsymutil` to preserve
+# its historical default, but when compiling the compiler itself, we skip it by
+# default since we know it's safe to do so in that case.
+#
+# On Windows platforms, packed debuginfo is the only supported option,
+# producing a `.pdb` file.
+#split-debuginfo = if linux { off } else if windows { packed } else if apple { unpacked }
# Whether or not `panic!`s generate backtraces (RUST_BACKTRACE)
#backtrace = true
/// be mindful of side effects.
///
/// [`Vec`]: crate::vec::Vec
-#[cfg(not(test))]
+#[cfg(all(not(no_global_oom_handling), not(test)))]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "vec_macro"]
// required for this macro definition, is not available. Instead use the
// `slice::into_vec` function which is only available with cfg(test)
// NB see the slice::hack module in slice.rs for more information
-#[cfg(test)]
+#[cfg(all(not(no_global_oom_handling), test))]
macro_rules! vec {
() => (
$crate::vec::Vec::new()
//! Compiler intrinsics.
//!
-//! The corresponding definitions are in `compiler/rustc_codegen_llvm/src/intrinsic.rs`.
-//! The corresponding const implementations are in `compiler/rustc_mir/src/interpret/intrinsics.rs`
+//! The corresponding definitions are in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_llvm/src/intrinsic.rs>.
+//! The corresponding const implementations are in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs>.
//!
//! # Const intrinsics
//!
//!
//! In order to make an intrinsic usable at compile-time, one needs to copy the implementation
//! from <https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs> to
-//! `compiler/rustc_mir/src/interpret/intrinsics.rs` and add a
-//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic.
+//! <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs> and add a
+//! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration.
//!
//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get accessed (read or written) through any other pointer.
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get accessed (read or written) through any other pointer.
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get accessed (read or written) through any other pointer.
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get accessed (read or written) through any other pointer.
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get accessed (read or written) through any other pointer.
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get accessed (read or written) through any other pointer.
///
/// This applies even if the result of this method is unused!
pub(super) fn new(slice: &'a [T], pred: P) -> Self {
Self { v: slice, pred, finished: false }
}
+ /// Returns a slice which contains items not yet handled by split.
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(split_as_slice)]
+ /// let slice = [1,2,3,4,5];
+ /// let mut split = slice.split(|v| v % 2 == 0);
+ /// assert!(split.next().is_some());
+ /// assert_eq!(split.as_slice(), &[3,4,5]);
+ /// ```
+ #[unstable(feature = "split_as_slice", issue = "96137")]
+ pub fn as_slice(&self) -> &'a [T] {
+ if self.finished { &[] } else { &self.v }
+ }
}
#[stable(feature = "core_impl_debug", since = "1.9.0")]
}
}
-macro_rules! u8to64_le {
- ($buf:expr, $i:expr) => {
- $buf[0 + $i] as u64
- | ($buf[1 + $i] as u64) << 8
- | ($buf[2 + $i] as u64) << 16
- | ($buf[3 + $i] as u64) << 24
- | ($buf[4 + $i] as u64) << 32
- | ($buf[5 + $i] as u64) << 40
- | ($buf[6 + $i] as u64) << 48
- | ($buf[7 + $i] as u64) << 56
- };
- ($buf:expr, $i:expr, $len:expr) => {{
- let mut t = 0;
- let mut out = 0;
- while t < $len {
- out |= ($buf[t + $i] as u64) << t * 8;
- t += 1;
- }
- out
- }};
-}
-
fn hash_with<H: Hasher, T: Hash>(mut st: H, x: &T) -> u64 {
x.hash(&mut st);
st.finish()
let mut state_inc = SipHasher13::new_with_keys(k0, k1);
while t < 64 {
- let vec = u8to64_le!(vecs[t], 0);
+ let vec = u64::from_le_bytes(vecs[t]);
let out = hash_with(SipHasher13::new_with_keys(k0, k1), &Bytes(&buf));
assert_eq!(vec, out);
let mut state_inc = SipHasher::new_with_keys(k0, k1);
while t < 64 {
- let vec = u8to64_le!(vecs[t], 0);
+ let vec = u64::from_le_bytes(vecs[t]);
let out = hash_with(SipHasher::new_with_keys(k0, k1), &Bytes(&buf));
assert_eq!(vec, out);
#![feature(sort_internals)]
#![feature(slice_take)]
#![feature(slice_from_ptr_range)]
+#![feature(split_as_slice)]
#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_array_assume_init)]
#![feature(maybe_uninit_write_slice)]
}
}
+#[test]
+fn split_as_slice() {
+ let arr = [1, 2, 3, 4, 5, 6];
+ let mut split = arr.split(|v| v % 2 == 0);
+ assert_eq!(split.as_slice(), &[1, 2, 3, 4, 5, 6]);
+ assert!(split.next().is_some());
+ assert_eq!(split.as_slice(), &[3, 4, 5, 6]);
+ assert!(split.next().is_some());
+ assert!(split.next().is_some());
+ assert_eq!(split.as_slice(), &[]);
+}
+
#[should_panic]
#[test]
fn slice_split_array_ref_out_of_bounds() {
[dependencies]
std = { path = "../std" }
+# Workaround: when documenting this crate rustdoc will try to load crate named
+# `core` when resolving doc links. Without this line a different `core` will be
+# loaded from sysroot causing duplicate lang items and other similar errors.
+core = { path = "../core" }
/// Run a parser, but fail if the entire input wasn't consumed.
/// Doesn't run atomically.
- fn parse_with<T, F>(&mut self, inner: F) -> Result<T, AddrParseError>
+ fn parse_with<T, F>(&mut self, inner: F, kind: AddrKind) -> Result<T, AddrParseError>
where
F: FnOnce(&mut Parser<'_>) -> Option<T>,
{
let result = inner(self);
- if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(()))
+ if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(kind))
}
/// Peek the next character from the input
impl FromStr for IpAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
- Parser::new(s).parse_with(|p| p.read_ip_addr())
+ Parser::new(s).parse_with(|p| p.read_ip_addr(), AddrKind::Ip)
}
}
fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
// don't try to parse if too long
if s.len() > 15 {
- Err(AddrParseError(()))
+ Err(AddrParseError(AddrKind::Ipv4))
} else {
- Parser::new(s).parse_with(|p| p.read_ipv4_addr())
+ Parser::new(s).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
}
}
}
impl FromStr for Ipv6Addr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
- Parser::new(s).parse_with(|p| p.read_ipv6_addr())
+ Parser::new(s).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
}
}
impl FromStr for SocketAddrV4 {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
- Parser::new(s).parse_with(|p| p.read_socket_addr_v4())
+ Parser::new(s).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4)
}
}
impl FromStr for SocketAddrV6 {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
- Parser::new(s).parse_with(|p| p.read_socket_addr_v6())
+ Parser::new(s).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6)
}
}
impl FromStr for SocketAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
- Parser::new(s).parse_with(|p| p.read_socket_addr())
+ Parser::new(s).parse_with(|p| p.read_socket_addr(), AddrKind::Socket)
}
}
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum AddrKind {
+ Ip,
+ Ipv4,
+ Ipv6,
+ Socket,
+ SocketV4,
+ SocketV6,
+}
+
/// An error which can be returned when parsing an IP address or a socket address.
///
/// This error is used as the error type for the [`FromStr`] implementation for
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct AddrParseError(());
+pub struct AddrParseError(AddrKind);
#[stable(feature = "addr_parse_error_error", since = "1.4.0")]
impl fmt::Display for AddrParseError {
impl Error for AddrParseError {
#[allow(deprecated)]
fn description(&self) -> &str {
- "invalid IP address syntax"
+ match self.0 {
+ AddrKind::Ip => "invalid IP address syntax",
+ AddrKind::Ipv4 => "invalid IPv4 address syntax",
+ AddrKind::Ipv6 => "invalid IPv6 address syntax",
+ AddrKind::Socket => "invalid socket address syntax",
+ AddrKind::SocketV4 => "invalid IPv4 socket address syntax",
+ AddrKind::SocketV6 => "invalid IPv6 socket address syntax",
+ }
}
}
use crate::cell::UnsafeCell;
use crate::collections::VecDeque;
-use crate::ffi::c_void;
use crate::hint;
use crate::ops::{Deref, DerefMut, Drop};
use crate::ptr;
#[inline]
pub unsafe fn destroy(&self) {}
}
-
-pub struct ReentrantMutex {
- inner: *const c_void,
-}
-
-impl ReentrantMutex {
- pub const unsafe fn uninitialized() -> ReentrantMutex {
- ReentrantMutex { inner: ptr::null() }
- }
-
- #[inline]
- pub unsafe fn init(&self) {
- let _ = abi::recmutex_init(&self.inner as *const *const c_void as *mut _);
- }
-
- #[inline]
- pub unsafe fn lock(&self) {
- let _ = abi::recmutex_lock(self.inner);
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- true
- }
-
- #[inline]
- pub unsafe fn unlock(&self) {
- let _ = abi::recmutex_unlock(self.inner);
- }
-
- #[inline]
- pub unsafe fn destroy(&self) {
- let _ = abi::recmutex_destroy(self.inner);
- }
-}
error::{expect_success, expect_success_aborting, fail, ItronError},
spin::SpinIdOnceCell,
};
-use crate::cell::UnsafeCell;
pub struct Mutex {
/// The ID of the underlying mutex object
unsafe { self.0.unlock() };
}
}
-
-// All empty stubs because this platform does not yet support threads, so lock
-// acquisition always succeeds.
-pub struct ReentrantMutex {
- /// The ID of the underlying mutex object
- mtx: abi::ID,
- /// The lock count.
- count: UnsafeCell<usize>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
- pub const unsafe fn uninitialized() -> ReentrantMutex {
- ReentrantMutex { mtx: 0, count: UnsafeCell::new(0) }
- }
-
- pub unsafe fn init(&mut self) {
- self.mtx = expect_success(
- unsafe {
- abi::acre_mtx(&abi::T_CMTX {
- // Priority inheritance mutex
- mtxatr: abi::TA_INHERIT,
- // Unused
- ceilpri: 0,
- })
- },
- &"acre_mtx",
- );
- }
-
- pub unsafe fn lock(&self) {
- match unsafe { abi::loc_mtx(self.mtx) } {
- abi::E_OBJ => {
- // Recursive lock
- unsafe {
- let count = &mut *self.count.get();
- if let Some(new_count) = count.checked_add(1) {
- *count = new_count;
- } else {
- // counter overflow
- rtabort!("lock count overflow");
- }
- }
- }
- er => {
- expect_success(er, &"loc_mtx");
- }
- }
- }
-
- pub unsafe fn unlock(&self) {
- unsafe {
- let count = &mut *self.count.get();
- if *count > 0 {
- *count -= 1;
- return;
- }
- }
-
- expect_success_aborting(unsafe { abi::unl_mtx(self.mtx) }, &"unl_mtx");
- }
-
- pub unsafe fn try_lock(&self) -> bool {
- let er = unsafe { abi::ploc_mtx(self.mtx) };
- if er == abi::E_OBJ {
- // Recursive lock
- unsafe {
- let count = &mut *self.count.get();
- if let Some(new_count) = count.checked_add(1) {
- *count = new_count;
- } else {
- // counter overflow
- rtabort!("lock count overflow");
- }
- }
- true
- } else if er == abi::E_TMOUT {
- // Locked by another thread
- false
- } else {
- expect_success(er, &"ploc_mtx");
- // Top-level lock by the current thread
- true
- }
- }
-
- pub unsafe fn destroy(&self) {
- expect_success_aborting(unsafe { abi::del_mtx(self.mtx) }, &"del_mtx");
- }
-}
-use fortanix_sgx_abi::Tcs;
-
-use super::abi::thread;
-
-use super::waitqueue::{try_lock_or_false, NotifiedTcs, SpinMutex, WaitQueue, WaitVariable};
+use super::waitqueue::{try_lock_or_false, SpinMutex, WaitQueue, WaitVariable};
pub struct Mutex {
inner: SpinMutex<WaitVariable<bool>>,
#[inline]
pub unsafe fn destroy(&self) {}
}
-
-struct ReentrantLock {
- owner: Option<Tcs>,
- count: usize,
-}
-
-pub struct ReentrantMutex {
- inner: SpinMutex<WaitVariable<ReentrantLock>>,
-}
-
-impl ReentrantMutex {
- pub const fn uninitialized() -> ReentrantMutex {
- ReentrantMutex {
- inner: SpinMutex::new(WaitVariable::new(ReentrantLock { owner: None, count: 0 })),
- }
- }
-
- #[inline]
- pub unsafe fn init(&self) {}
-
- #[inline]
- pub unsafe fn lock(&self) {
- let mut guard = self.inner.lock();
- match guard.lock_var().owner {
- Some(tcs) if tcs != thread::current() => {
- // Another thread has the lock, wait
- WaitQueue::wait(guard, || {});
- // Another thread has passed the lock to us
- }
- _ => {
- // We are just now obtaining the lock
- guard.lock_var_mut().owner = Some(thread::current());
- guard.lock_var_mut().count += 1;
- }
- }
- }
-
- #[inline]
- pub unsafe fn unlock(&self) {
- let mut guard = self.inner.lock();
- if guard.lock_var().count > 1 {
- guard.lock_var_mut().count -= 1;
- } else {
- match WaitQueue::notify_one(guard) {
- Err(mut guard) => {
- // No other waiters, unlock
- guard.lock_var_mut().count = 0;
- guard.lock_var_mut().owner = None;
- }
- Ok(mut guard) => {
- // There was a thread waiting, just pass the lock
- if let NotifiedTcs::Single(tcs) = guard.notified_tcs() {
- guard.lock_var_mut().owner = Some(tcs)
- } else {
- unreachable!() // called notify_one
- }
- }
- }
- }
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- let mut guard = try_lock_or_false!(self.inner);
- match guard.lock_var().owner {
- Some(tcs) if tcs != thread::current() => {
- // Another thread has the lock
- false
- }
- _ => {
- // We are just now obtaining the lock
- guard.lock_var_mut().owner = Some(thread::current());
- guard.lock_var_mut().count += 1;
- true
- }
- }
- }
-
- #[inline]
- pub unsafe fn destroy(&self) {}
-}
fn remove_dir_all_recursive(parent_fd: Option<RawFd>, path: &CStr) -> io::Result<()> {
// try opening as directory
let fd = match openat_nofollow_dironly(parent_fd, &path) {
- Err(err) if err.raw_os_error() == Some(libc::ENOTDIR) => {
+ Err(err) if matches!(err.raw_os_error(), Some(libc::ENOTDIR | libc::ELOOP)) => {
// not a directory - don't traverse further
+ // (for symlinks, older Linux kernels may return ELOOP instead of ENOTDIR)
return match parent_fd {
// unlink...
Some(parent_fd) => {
}
}
-#[cfg(target_os = "emscripten")]
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) {
- extern "C" {
- fn emscripten_futex_wait(
- addr: *const AtomicU32,
- val: libc::c_uint,
- max_wait_ms: libc::c_double,
- ) -> libc::c_int;
- }
-
- unsafe {
- emscripten_futex_wait(
- futex,
- expected,
- timeout.map_or(crate::f64::INFINITY, |d| d.as_secs_f64() * 1000.0),
- );
- }
-}
-
/// Wake up one thread that's blocked on futex_wait on this futex.
///
/// Returns true if this actually woke up such a thread,
}
#[cfg(target_os = "emscripten")]
-pub fn futex_wake(futex: &AtomicU32) -> bool {
- extern "C" {
- fn emscripten_futex_wake(addr: *const AtomicU32, count: libc::c_int) -> libc::c_int;
+extern "C" {
+ fn emscripten_futex_wake(addr: *const AtomicU32, count: libc::c_int) -> libc::c_int;
+ fn emscripten_futex_wait(
+ addr: *const AtomicU32,
+ val: libc::c_uint,
+ max_wait_ms: libc::c_double,
+ ) -> libc::c_int;
+}
+
+#[cfg(target_os = "emscripten")]
+pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+ unsafe {
+ emscripten_futex_wait(
+ futex,
+ expected,
+ timeout.map_or(f64::INFINITY, |d| d.as_secs_f64() * 1000.0),
+ ) != -libc::ETIMEDOUT
}
+}
+#[cfg(target_os = "emscripten")]
+pub fn futex_wake(futex: &AtomicU32) -> bool {
unsafe { emscripten_futex_wake(futex, 1) > 0 }
}
+
+#[cfg(target_os = "emscripten")]
+pub fn futex_wake_all(futex: &AtomicU32) {
+ unsafe { emscripten_futex_wake(futex, i32::MAX) };
+}
-use crate::cell::UnsafeCell;
use crate::sync::atomic::{
- AtomicU32, AtomicUsize,
+ AtomicU32,
Ordering::{Acquire, Relaxed, Release},
};
use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all};
r
}
}
-
-/// A reentrant mutex. Used by stdout().lock() and friends.
-///
-/// The 'owner' field tracks which thread has locked the mutex.
-///
-/// We use current_thread_unique_ptr() as the thread identifier,
-/// which is just the address of a thread local variable.
-///
-/// If `owner` is set to the identifier of the current thread,
-/// we assume the mutex is already locked and instead of locking it again,
-/// we increment `lock_count`.
-///
-/// When unlocking, we decrement `lock_count`, and only unlock the mutex when
-/// it reaches zero.
-///
-/// `lock_count` is protected by the mutex and only accessed by the thread that has
-/// locked the mutex, so needs no synchronization.
-///
-/// `owner` can be checked by other threads that want to see if they already
-/// hold the lock, so needs to be atomic. If it compares equal, we're on the
-/// same thread that holds the mutex and memory access can use relaxed ordering
-/// since we're not dealing with multiple threads. If it compares unequal,
-/// synchronization is left to the mutex, making relaxed memory ordering for
-/// the `owner` field fine in all cases.
-pub struct ReentrantMutex {
- mutex: Mutex,
- owner: AtomicUsize,
- lock_count: UnsafeCell<u32>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
- #[inline]
- pub const unsafe fn uninitialized() -> Self {
- Self { mutex: Mutex::new(), owner: AtomicUsize::new(0), lock_count: UnsafeCell::new(0) }
- }
-
- #[inline]
- pub unsafe fn init(&self) {}
-
- #[inline]
- pub unsafe fn destroy(&self) {}
-
- pub unsafe fn try_lock(&self) -> bool {
- let this_thread = current_thread_unique_ptr();
- if self.owner.load(Relaxed) == this_thread {
- self.increment_lock_count();
- true
- } else if self.mutex.try_lock() {
- self.owner.store(this_thread, Relaxed);
- debug_assert_eq!(*self.lock_count.get(), 0);
- *self.lock_count.get() = 1;
- true
- } else {
- false
- }
- }
-
- pub unsafe fn lock(&self) {
- let this_thread = current_thread_unique_ptr();
- if self.owner.load(Relaxed) == this_thread {
- self.increment_lock_count();
- } else {
- self.mutex.lock();
- self.owner.store(this_thread, Relaxed);
- debug_assert_eq!(*self.lock_count.get(), 0);
- *self.lock_count.get() = 1;
- }
- }
-
- unsafe fn increment_lock_count(&self) {
- *self.lock_count.get() = (*self.lock_count.get())
- .checked_add(1)
- .expect("lock count overflow in reentrant mutex");
- }
-
- pub unsafe fn unlock(&self) {
- *self.lock_count.get() -= 1;
- if *self.lock_count.get() == 0 {
- self.owner.store(0, Relaxed);
- self.mutex.unlock();
- }
- }
-}
-
-/// Get an address that is unique per running thread.
-///
-/// This can be used as a non-null usize-sized ID.
-pub fn current_thread_unique_ptr() -> usize {
- // Use a non-drop type to make sure it's still available during thread destruction.
- thread_local! { static X: u8 = const { 0 } }
- X.with(|x| <*const _>::addr(x))
-}
if #[cfg(any(
target_os = "linux",
target_os = "android",
+ all(target_os = "emscripten", target_feature = "atomics"),
))] {
mod futex;
mod futex_rwlock;
- pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar, ReentrantMutex};
+ pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
pub use futex_rwlock::{RwLock, MovableRwLock};
} else {
mod pthread_mutex;
- mod pthread_remutex;
mod pthread_rwlock;
mod pthread_condvar;
pub use pthread_mutex::{Mutex, MovableMutex};
- pub use pthread_remutex::ReentrantMutex;
pub use pthread_rwlock::{RwLock, MovableRwLock};
pub use pthread_condvar::{Condvar, MovableCondvar};
}
+++ /dev/null
-use super::pthread_mutex::PthreadMutexAttr;
-use crate::cell::UnsafeCell;
-use crate::mem::MaybeUninit;
-use crate::sys::cvt_nz;
-
-pub struct ReentrantMutex {
- inner: UnsafeCell<libc::pthread_mutex_t>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
- pub const unsafe fn uninitialized() -> ReentrantMutex {
- ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
- }
-
- pub unsafe fn init(&self) {
- let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
- cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap();
- let attr = PthreadMutexAttr(&mut attr);
- cvt_nz(libc::pthread_mutexattr_settype(attr.0.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE))
- .unwrap();
- cvt_nz(libc::pthread_mutex_init(self.inner.get(), attr.0.as_ptr())).unwrap();
- }
-
- pub unsafe fn lock(&self) {
- let result = libc::pthread_mutex_lock(self.inner.get());
- debug_assert_eq!(result, 0);
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- libc::pthread_mutex_trylock(self.inner.get()) == 0
- }
-
- pub unsafe fn unlock(&self) {
- let result = libc::pthread_mutex_unlock(self.inner.get());
- debug_assert_eq!(result, 0);
- }
-
- pub unsafe fn destroy(&self) {
- let result = libc::pthread_mutex_destroy(self.inner.get());
- debug_assert_eq!(result, 0);
- }
-}
crate::fs::read_to_string("sys:exe").map(PathBuf::from)
}
-#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
+#[cfg(target_os = "l4re")]
pub fn current_exe() -> io::Result<PathBuf> {
use crate::io::ErrorKind;
Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!"))
super::unsupported::unsupported()
}
+#[cfg(target_os = "fuchsia")]
+pub fn current_exe() -> io::Result<PathBuf> {
+ use crate::io::ErrorKind;
+
+ #[cfg(test)]
+ use realstd::env;
+
+ #[cfg(not(test))]
+ use crate::env;
+
+ let exe_path = env::args().next().ok_or(io::const_io_error!(
+ ErrorKind::Uncategorized,
+ "an executable path was not found because no arguments were provided through argv"
+ ))?;
+ let path = PathBuf::from(exe_path);
+
+ // Prepend the current working directory to the path if it's not absolute.
+ if !path.is_absolute() { getcwd().map(|cwd| cwd.join(path)) } else { Ok(path) }
+}
+
pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
}
use crate::ffi::OsStr;
use crate::mem;
use crate::ptr;
-use crate::sys::cvt;
+use crate::sys::{cvt, cvt_nz};
macro_rules! t {
($e:expr) => {
let mut old_set = mem::MaybeUninit::<libc::sigset_t>::uninit();
t!(cvt(sigemptyset(set.as_mut_ptr())));
t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT)));
- t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr())));
+ t!(cvt_nz(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr())));
cmd.stdin(Stdio::MakePipe);
cmd.stdout(Stdio::MakePipe);
let stdin_write = pipes.stdin.take().unwrap();
let stdout_read = pipes.stdout.take().unwrap();
- t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut())));
+ t!(cvt_nz(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut())));
t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
// We need to wait until SIGINT is definitely delivered. The
#[cfg(not(target_os = "emscripten"))]
{
use crate::mem::MaybeUninit;
+ use crate::sys::cvt_nz;
// Reset signal handling so the child process starts in a
// standardized state. libstd ignores SIGPIPE, and signal-handling
// libraries often set a mask. Child processes inherit ignored
// we're about to run.
let mut set = MaybeUninit::<libc::sigset_t>::uninit();
cvt(sigemptyset(set.as_mut_ptr()))?;
- cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), ptr::null_mut()))?;
+ cvt_nz(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), ptr::null_mut()))?;
#[cfg(target_os = "android")] // see issue #88585
{
use crate::ffi::CStr;
use crate::marker::PhantomData;
use crate::mem;
-use crate::sync::atomic::{self, AtomicUsize, Ordering};
+use crate::ptr;
+use crate::sync::atomic::{self, AtomicPtr, Ordering};
// We can use true weak linkage on ELF targets.
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
}
pub(crate) struct DlsymWeak<F> {
name: &'static str,
- addr: AtomicUsize,
+ func: AtomicPtr<libc::c_void>,
_marker: PhantomData<F>,
}
impl<F> DlsymWeak<F> {
pub(crate) const fn new(name: &'static str) -> Self {
- DlsymWeak { name, addr: AtomicUsize::new(1), _marker: PhantomData }
+ DlsymWeak { name, func: AtomicPtr::new(ptr::invalid_mut(1)), _marker: PhantomData }
}
#[inline]
unsafe {
// Relaxed is fine here because we fence before reading through the
// pointer (see the comment below).
- match self.addr.load(Ordering::Relaxed) {
- 1 => self.initialize(),
- 0 => None,
- addr => {
- let func = mem::transmute_copy::<usize, F>(&addr);
+ match self.func.load(Ordering::Relaxed) {
+ func if func.addr() == 1 => self.initialize(),
+ func if func.is_null() => None,
+ func => {
+ let func = mem::transmute_copy::<*mut libc::c_void, F>(&func);
// The caller is presumably going to read through this value
// (by calling the function we've dlsymed). This means we'd
// need to have loaded it with at least C11's consume
// Cold because it should only happen during first-time initialization.
#[cold]
unsafe fn initialize(&self) -> Option<F> {
- assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+ assert_eq!(mem::size_of::<F>(), mem::size_of::<*mut libc::c_void>());
let val = fetch(self.name);
// This synchronizes with the acquire fence in `get`.
- self.addr.store(val, Ordering::Release);
+ self.func.store(val, Ordering::Release);
- match val {
- 0 => None,
- addr => Some(mem::transmute_copy::<usize, F>(&addr)),
- }
+ if val.is_null() { None } else { Some(mem::transmute_copy::<*mut libc::c_void, F>(&val)) }
}
}
-unsafe fn fetch(name: &str) -> usize {
+unsafe fn fetch(name: &str) -> *mut libc::c_void {
let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
Ok(cstr) => cstr,
- Err(..) => return 0,
+ Err(..) => return ptr::null_mut(),
};
- libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
+ libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr())
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
mod mutex;
mod rwlock;
pub use condvar::{Condvar, MovableCondvar};
-pub use mutex::{MovableMutex, Mutex, ReentrantMutex};
+pub use mutex::{MovableMutex, Mutex};
pub use rwlock::{MovableRwLock, RwLock};
#[inline]
pub unsafe fn destroy(&self) {}
}
-
-// All empty stubs because this platform does not yet support threads, so lock
-// acquisition always succeeds.
-pub struct ReentrantMutex {}
-
-impl ReentrantMutex {
- pub const unsafe fn uninitialized() -> ReentrantMutex {
- ReentrantMutex {}
- }
-
- pub unsafe fn init(&self) {}
-
- pub unsafe fn lock(&self) {}
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- true
- }
-
- pub unsafe fn unlock(&self) {}
-
- pub unsafe fn destroy(&self) {}
-}
+++ /dev/null
-use crate::arch::wasm32;
-use crate::cmp;
-use crate::mem;
-use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-use crate::sys::locks::Mutex;
-use crate::time::Duration;
-
-pub struct Condvar {
- cnt: AtomicUsize,
-}
-
-pub type MovableCondvar = Condvar;
-
-// Condition variables are implemented with a simple counter internally that is
-// likely to cause spurious wakeups. Blocking on a condition variable will first
-// read the value of the internal counter, unlock the given mutex, and then
-// block if and only if the counter's value is still the same. Notifying a
-// condition variable will modify the counter (add one for now) and then wake up
-// a thread waiting on the address of the counter.
-//
-// A thread waiting on the condition variable will as a result avoid going to
-// sleep if it's notified after the lock is unlocked but before it fully goes to
-// sleep. A sleeping thread is guaranteed to be woken up at some point as it can
-// only be woken up with a call to `wake`.
-//
-// Note that it's possible for 2 or more threads to be woken up by a call to
-// `notify_one` with this implementation. That can happen where the modification
-// of `cnt` causes any threads in the middle of `wait` to avoid going to sleep,
-// and the subsequent `wake` may wake up a thread that's actually blocking. We
-// consider this a spurious wakeup, though, which all users of condition
-// variables must already be prepared to handle. As a result, this source of
-// spurious wakeups is currently though to be ok, although it may be problematic
-// later on if it causes too many spurious wakeups.
-
-impl Condvar {
- pub const fn new() -> Condvar {
- Condvar { cnt: AtomicUsize::new(0) }
- }
-
- #[inline]
- pub unsafe fn init(&mut self) {
- // nothing to do
- }
-
- pub unsafe fn notify_one(&self) {
- self.cnt.fetch_add(1, SeqCst);
- // SAFETY: ptr() is always valid
- unsafe {
- wasm32::memory_atomic_notify(self.ptr(), 1);
- }
- }
-
- #[inline]
- pub unsafe fn notify_all(&self) {
- self.cnt.fetch_add(1, SeqCst);
- // SAFETY: ptr() is always valid
- unsafe {
- wasm32::memory_atomic_notify(self.ptr(), u32::MAX); // -1 == "wake everyone"
- }
- }
-
- pub unsafe fn wait(&self, mutex: &Mutex) {
- // "atomically block and unlock" implemented by loading our current
- // counter's value, unlocking the mutex, and blocking if the counter
- // still has the same value.
- //
- // Notifications happen by incrementing the counter and then waking a
- // thread. Incrementing the counter after we unlock the mutex will
- // prevent us from sleeping and otherwise the call to `wake` will
- // wake us up once we're asleep.
- let ticket = self.cnt.load(SeqCst) as i32;
- mutex.unlock();
- let val = wasm32::memory_atomic_wait32(self.ptr(), ticket, -1);
- // 0 == woken, 1 == not equal to `ticket`, 2 == timeout (shouldn't happen)
- debug_assert!(val == 0 || val == 1);
- mutex.lock();
- }
-
- pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
- let ticket = self.cnt.load(SeqCst) as i32;
- mutex.unlock();
- let nanos = dur.as_nanos();
- let nanos = cmp::min(i64::MAX as u128, nanos);
-
- // If the return value is 2 then a timeout happened, so we return
- // `false` as we weren't actually notified.
- let ret = wasm32::memory_atomic_wait32(self.ptr(), ticket, nanos as i64) != 2;
- mutex.lock();
- return ret;
- }
-
- #[inline]
- pub unsafe fn destroy(&self) {
- // nothing to do
- }
-
- #[inline]
- fn ptr(&self) -> *mut i32 {
- assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
- self.cnt.as_mut_ptr() as *mut i32
- }
-}
use crate::sync::atomic::AtomicU32;
use crate::time::Duration;
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) {
+/// Wait for a futex_wake operation to wake us.
+///
+/// Returns directly if the futex doesn't hold the expected value.
+///
+/// Returns false on timeout, and true in all other cases.
+pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1);
unsafe {
wasm32::memory_atomic_wait32(
futex as *const AtomicU32 as *mut i32,
expected as i32,
timeout,
- );
+ ) < 2
}
}
-pub fn futex_wake(futex: &AtomicU32) {
+/// Wake up one thread that's blocked on futex_wait on this futex.
+///
+/// Returns true if this actually woke up such a thread,
+/// or false if no thread was waiting on this futex.
+pub fn futex_wake(futex: &AtomicU32) -> bool {
+ unsafe { wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1) > 0 }
+}
+
+/// Wake up all threads that are waiting on futex_wait on this futex.
+pub fn futex_wake_all(futex: &AtomicU32) {
unsafe {
- wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1);
+ wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, i32::MAX as u32);
}
}
+++ /dev/null
-use crate::arch::wasm32;
-use crate::cell::UnsafeCell;
-use crate::mem;
-use crate::sync::atomic::{AtomicU32, AtomicUsize, Ordering::SeqCst};
-use crate::sys::thread;
-
-pub struct Mutex {
- locked: AtomicUsize,
-}
-
-pub type MovableMutex = Mutex;
-
-// Mutexes have a pretty simple implementation where they contain an `i32`
-// internally that is 0 when unlocked and 1 when the mutex is locked.
-// Acquisition has a fast path where it attempts to cmpxchg the 0 to a 1, and
-// if it fails it then waits for a notification. Releasing a lock is then done
-// by swapping in 0 and then notifying any waiters, if present.
-
-impl Mutex {
- pub const fn new() -> Mutex {
- Mutex { locked: AtomicUsize::new(0) }
- }
-
- #[inline]
- pub unsafe fn init(&mut self) {
- // nothing to do
- }
-
- pub unsafe fn lock(&self) {
- while !self.try_lock() {
- // SAFETY: the caller must uphold the safety contract for `memory_atomic_wait32`.
- let val = unsafe {
- wasm32::memory_atomic_wait32(
- self.ptr(),
- 1, // we expect our mutex is locked
- -1, // wait infinitely
- )
- };
- // we should have either woke up (0) or got a not-equal due to a
- // race (1). We should never time out (2)
- debug_assert!(val == 0 || val == 1);
- }
- }
-
- pub unsafe fn unlock(&self) {
- let prev = self.locked.swap(0, SeqCst);
- debug_assert_eq!(prev, 1);
- wasm32::memory_atomic_notify(self.ptr(), 1); // wake up one waiter, if any
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
- }
-
- #[inline]
- pub unsafe fn destroy(&self) {
- // nothing to do
- }
-
- #[inline]
- fn ptr(&self) -> *mut i32 {
- assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
- self.locked.as_mut_ptr() as *mut i32
- }
-}
-
-pub struct ReentrantMutex {
- owner: AtomicU32,
- recursions: UnsafeCell<u32>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-// Reentrant mutexes are similarly implemented to mutexes above except that
-// instead of "1" meaning unlocked we use the id of a thread to represent
-// whether it has locked a mutex. That way we have an atomic counter which
-// always holds the id of the thread that currently holds the lock (or 0 if the
-// lock is unlocked).
-//
-// Once a thread acquires a lock recursively, which it detects by looking at
-// the value that's already there, it will update a local `recursions` counter
-// in a nonatomic fashion (as we hold the lock). The lock is then fully
-// released when this recursion counter reaches 0.
-
-impl ReentrantMutex {
- pub const unsafe fn uninitialized() -> ReentrantMutex {
- ReentrantMutex { owner: AtomicU32::new(0), recursions: UnsafeCell::new(0) }
- }
-
- pub unsafe fn init(&self) {
- // nothing to do...
- }
-
- pub unsafe fn lock(&self) {
- let me = thread::my_id();
- while let Err(owner) = self._try_lock(me) {
- // SAFETY: the caller must guarantee that `self.ptr()` and `owner` are valid i32.
- let val = unsafe { wasm32::memory_atomic_wait32(self.ptr(), owner as i32, -1) };
- debug_assert!(val == 0 || val == 1);
- }
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- unsafe { self._try_lock(thread::my_id()).is_ok() }
- }
-
- #[inline]
- unsafe fn _try_lock(&self, id: u32) -> Result<(), u32> {
- let id = id.checked_add(1).unwrap();
- match self.owner.compare_exchange(0, id, SeqCst, SeqCst) {
- // we transitioned from unlocked to locked
- Ok(_) => {
- debug_assert_eq!(*self.recursions.get(), 0);
- Ok(())
- }
-
- // we currently own this lock, so let's update our count and return
- // true.
- Err(n) if n == id => {
- *self.recursions.get() += 1;
- Ok(())
- }
-
- // Someone else owns the lock, let our caller take care of it
- Err(other) => Err(other),
- }
- }
-
- pub unsafe fn unlock(&self) {
- // If we didn't ever recursively lock the lock then we fully unlock the
- // mutex and wake up a waiter, if any. Otherwise we decrement our
- // recursive counter and let some one else take care of the zero.
- match *self.recursions.get() {
- 0 => {
- self.owner.swap(0, SeqCst);
- // SAFETY: the caller must guarantee that `self.ptr()` is valid i32.
- unsafe {
- wasm32::memory_atomic_notify(self.ptr() as *mut i32, 1);
- } // wake up one waiter, if any
- }
- ref mut n => *n -= 1,
- }
- }
-
- pub unsafe fn destroy(&self) {
- // nothing to do...
- }
-
- #[inline]
- fn ptr(&self) -> *mut i32 {
- self.owner.as_mut_ptr() as *mut i32
- }
-}
+++ /dev/null
-use crate::cell::UnsafeCell;
-use crate::sys::locks::{Condvar, Mutex};
-
-pub struct RwLock {
- lock: Mutex,
- cond: Condvar,
- state: UnsafeCell<State>,
-}
-
-pub type MovableRwLock = RwLock;
-
-enum State {
- Unlocked,
- Reading(usize),
- Writing,
-}
-
-unsafe impl Send for RwLock {}
-unsafe impl Sync for RwLock {}
-
-// This rwlock implementation is a relatively simple implementation which has a
-// condition variable for readers/writers as well as a mutex protecting the
-// internal state of the lock. A current downside of the implementation is that
-// unlocking the lock will notify *all* waiters rather than just readers or just
-// writers. This can cause lots of "thundering stampede" problems. While
-// hopefully correct this implementation is very likely to want to be changed in
-// the future.
-
-impl RwLock {
- pub const fn new() -> RwLock {
- RwLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) }
- }
-
- #[inline]
- pub unsafe fn read(&self) {
- self.lock.lock();
- while !(*self.state.get()).inc_readers() {
- self.cond.wait(&self.lock);
- }
- self.lock.unlock();
- }
-
- #[inline]
- pub unsafe fn try_read(&self) -> bool {
- self.lock.lock();
- let ok = (*self.state.get()).inc_readers();
- self.lock.unlock();
- return ok;
- }
-
- #[inline]
- pub unsafe fn write(&self) {
- self.lock.lock();
- while !(*self.state.get()).inc_writers() {
- self.cond.wait(&self.lock);
- }
- self.lock.unlock();
- }
-
- #[inline]
- pub unsafe fn try_write(&self) -> bool {
- self.lock.lock();
- let ok = (*self.state.get()).inc_writers();
- self.lock.unlock();
- return ok;
- }
-
- #[inline]
- pub unsafe fn read_unlock(&self) {
- self.lock.lock();
- let notify = (*self.state.get()).dec_readers();
- self.lock.unlock();
- if notify {
- // FIXME: should only wake up one of these some of the time
- self.cond.notify_all();
- }
- }
-
- #[inline]
- pub unsafe fn write_unlock(&self) {
- self.lock.lock();
- (*self.state.get()).dec_writers();
- self.lock.unlock();
- // FIXME: should only wake up one of these some of the time
- self.cond.notify_all();
- }
-
- #[inline]
- pub unsafe fn destroy(&self) {
- self.lock.destroy();
- self.cond.destroy();
- }
-}
-
-impl State {
- fn inc_readers(&mut self) -> bool {
- match *self {
- State::Unlocked => {
- *self = State::Reading(1);
- true
- }
- State::Reading(ref mut cnt) => {
- *cnt += 1;
- true
- }
- State::Writing => false,
- }
- }
-
- fn inc_writers(&mut self) -> bool {
- match *self {
- State::Unlocked => {
- *self = State::Writing;
- true
- }
- State::Reading(_) | State::Writing => false,
- }
- }
-
- fn dec_readers(&mut self) -> bool {
- let zero = match *self {
- State::Reading(ref mut cnt) => {
- *cnt -= 1;
- *cnt == 0
- }
- State::Unlocked | State::Writing => invalid(),
- };
- if zero {
- *self = State::Unlocked;
- }
- zero
- }
-
- fn dec_writers(&mut self) {
- match *self {
- State::Writing => {}
- State::Unlocked | State::Reading(_) => invalid(),
- }
- *self = State::Unlocked;
- }
-}
-
-fn invalid() -> ! {
- panic!("inconsistent rwlock");
-}
None
}
}
-
-// We currently just use our own thread-local to store our
-// current thread's ID, and then we lazily initialize it to something allocated
-// from a global counter.
-pub fn my_id() -> u32 {
- use crate::sync::atomic::{AtomicU32, Ordering::SeqCst};
-
- static NEXT_ID: AtomicU32 = AtomicU32::new(0);
-
- #[thread_local]
- static mut MY_ID: u32 = 0;
-
- unsafe {
- // If our thread ID isn't set yet then we need to allocate one. Do so
- // with with a simple "atomically add to a global counter" strategy.
- // This strategy doesn't handled what happens when the counter
- // overflows, however, so just abort everything once the counter
- // overflows and eventually we could have some sort of recycling scheme
- // (or maybe this is all totally irrelevant by that point!). In any case
- // though we're using a CAS loop instead of a `fetch_add` to ensure that
- // the global counter never overflows.
- if MY_ID == 0 {
- let mut cur = NEXT_ID.load(SeqCst);
- MY_ID = loop {
- let next = cur.checked_add(1).unwrap_or_else(|| crate::process::abort());
- match NEXT_ID.compare_exchange(cur, next, SeqCst, SeqCst) {
- Ok(_) => break next,
- Err(i) => cur = i,
- }
- };
- }
- MY_ID
- }
-}
cfg_if::cfg_if! {
if #[cfg(target_feature = "atomics")] {
- #[path = "atomics/condvar.rs"]
- mod condvar;
- #[path = "atomics/mutex.rs"]
- mod mutex;
- #[path = "atomics/rwlock.rs"]
- mod rwlock;
+ #[path = "../unix/locks"]
pub mod locks {
- pub use super::condvar::*;
- pub use super::mutex::*;
- pub use super::rwlock::*;
+ #![allow(unsafe_op_in_unsafe_fn)]
+ mod futex;
+ mod futex_rwlock;
+ pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
+ pub use futex_rwlock::{RwLock, MovableRwLock};
}
#[path = "atomics/futex.rs"]
pub mod futex;
pub struct SRWLOCK {
pub ptr: LPVOID,
}
-#[repr(C)]
-pub struct CRITICAL_SECTION {
- CriticalSectionDebug: LPVOID,
- LockCount: LONG,
- RecursionCount: LONG,
- OwningThread: HANDLE,
- LockSemaphore: HANDLE,
- SpinCount: ULONG_PTR,
-}
#[repr(C)]
pub struct REPARSE_MOUNTPOINT_DATA_BUFFER {
#[link(name = "kernel32")]
extern "system" {
pub fn GetCurrentProcessId() -> DWORD;
- pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
- pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
- pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL;
- pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
- pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
pub fn GetSystemDirectoryW(lpBuffer: LPWSTR, uSize: UINT) -> UINT;
pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
mod mutex;
mod rwlock;
pub use condvar::{Condvar, MovableCondvar};
-pub use mutex::{MovableMutex, Mutex, ReentrantMutex};
+pub use mutex::{MovableMutex, Mutex};
pub use rwlock::{MovableRwLock, RwLock};
//! is that there are no guarantees of fairness.
use crate::cell::UnsafeCell;
-use crate::mem::MaybeUninit;
use crate::sys::c;
pub struct Mutex {
// SRWLock does not need to be destroyed.
}
}
-
-pub struct ReentrantMutex {
- inner: MaybeUninit<UnsafeCell<c::CRITICAL_SECTION>>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
- pub const fn uninitialized() -> ReentrantMutex {
- ReentrantMutex { inner: MaybeUninit::uninit() }
- }
-
- pub unsafe fn init(&self) {
- c::InitializeCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
- }
-
- pub unsafe fn lock(&self) {
- c::EnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- c::TryEnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())) != 0
- }
-
- pub unsafe fn unlock(&self) {
- c::LeaveCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
- }
-
- pub unsafe fn destroy(&self) {
- c::DeleteCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
- }
-}
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
+use crate::cell::UnsafeCell;
use crate::marker::PhantomPinned;
use crate::ops::Deref;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::pin::Pin;
+use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
use crate::sys::locks as sys;
/// A re-entrant mutual exclusion
/// This mutex will block *other* threads waiting for the lock to become
/// available. The thread which has already locked the mutex can lock it
/// multiple times without blocking, preventing a common source of deadlocks.
+///
+/// This is used by stdout().lock() and friends.
+///
+/// ## Implementation details
+///
+/// The 'owner' field tracks which thread has locked the mutex.
+///
+/// We use current_thread_unique_ptr() as the thread identifier,
+/// which is just the address of a thread local variable.
+///
+/// If `owner` is set to the identifier of the current thread,
+/// we assume the mutex is already locked and instead of locking it again,
+/// we increment `lock_count`.
+///
+/// When unlocking, we decrement `lock_count`, and only unlock the mutex when
+/// it reaches zero.
+///
+/// `lock_count` is protected by the mutex and only accessed by the thread that has
+/// locked the mutex, so needs no synchronization.
+///
+/// `owner` can be checked by other threads that want to see if they already
+/// hold the lock, so needs to be atomic. If it compares equal, we're on the
+/// same thread that holds the mutex and memory access can use relaxed ordering
+/// since we're not dealing with multiple threads. If it compares unequal,
+/// synchronization is left to the mutex, making relaxed memory ordering for
+/// the `owner` field fine in all cases.
pub struct ReentrantMutex<T> {
- inner: sys::ReentrantMutex,
+ mutex: sys::Mutex,
+ owner: AtomicUsize,
+ lock_count: UnsafeCell<u32>,
data: T,
_pinned: PhantomPinned,
}
/// lock/unlock methods safe.
pub const unsafe fn new(t: T) -> ReentrantMutex<T> {
ReentrantMutex {
- inner: sys::ReentrantMutex::uninitialized(),
+ mutex: sys::Mutex::new(),
+ owner: AtomicUsize::new(0),
+ lock_count: UnsafeCell::new(0),
data: t,
_pinned: PhantomPinned,
}
/// Unsafe to call more than once, and must be called after this will no
/// longer move in memory.
pub unsafe fn init(self: Pin<&mut Self>) {
- self.get_unchecked_mut().inner.init()
+ self.get_unchecked_mut().mutex.init()
}
/// Acquires a mutex, blocking the current thread until it is able to do so.
/// this call will return failure if the mutex would otherwise be
/// acquired.
pub fn lock(self: Pin<&Self>) -> ReentrantMutexGuard<'_, T> {
- unsafe { self.inner.lock() }
+ let this_thread = current_thread_unique_ptr();
+ // Safety: We only touch lock_count when we own the lock,
+ // and since self is pinned we can safely call the lock() on the mutex.
+ unsafe {
+ if self.owner.load(Relaxed) == this_thread {
+ self.increment_lock_count();
+ } else {
+ self.mutex.lock();
+ self.owner.store(this_thread, Relaxed);
+ debug_assert_eq!(*self.lock_count.get(), 0);
+ *self.lock_count.get() = 1;
+ }
+ }
ReentrantMutexGuard { lock: self }
}
/// this call will return failure if the mutex would otherwise be
/// acquired.
pub fn try_lock(self: Pin<&Self>) -> Option<ReentrantMutexGuard<'_, T>> {
- if unsafe { self.inner.try_lock() } {
- Some(ReentrantMutexGuard { lock: self })
- } else {
- None
+ let this_thread = current_thread_unique_ptr();
+ // Safety: We only touch lock_count when we own the lock,
+ // and since self is pinned we can safely call the try_lock on the mutex.
+ unsafe {
+ if self.owner.load(Relaxed) == this_thread {
+ self.increment_lock_count();
+ Some(ReentrantMutexGuard { lock: self })
+ } else if self.mutex.try_lock() {
+ self.owner.store(this_thread, Relaxed);
+ debug_assert_eq!(*self.lock_count.get(), 0);
+ *self.lock_count.get() = 1;
+ Some(ReentrantMutexGuard { lock: self })
+ } else {
+ None
+ }
}
}
+
+ unsafe fn increment_lock_count(&self) {
+ *self.lock_count.get() = (*self.lock_count.get())
+ .checked_add(1)
+ .expect("lock count overflow in reentrant mutex");
+ }
}
impl<T> Drop for ReentrantMutex<T> {
fn drop(&mut self) {
- // This is actually safe b/c we know that there is no further usage of
- // this mutex (it's up to the user to arrange for a mutex to get
- // dropped, that's not our job)
- unsafe { self.inner.destroy() }
+ // Safety: We're the unique owner of this mutex and not going to use it afterwards.
+ unsafe { self.mutex.destroy() }
}
}
impl<T> Drop for ReentrantMutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
+ // Safety: We own the lock, and the lock is pinned.
unsafe {
- self.lock.inner.unlock();
+ *self.lock.lock_count.get() -= 1;
+ if *self.lock.lock_count.get() == 0 {
+ self.lock.owner.store(0, Relaxed);
+ self.lock.mutex.unlock();
+ }
}
}
}
+
+/// Get an address that is unique per running thread.
+///
+/// This can be used as a non-null usize-sized ID.
+pub fn current_thread_unique_ptr() -> usize {
+ // Use a non-drop type to make sure it's still available during thread destruction.
+ thread_local! { static X: u8 = const { 0 } }
+ X.with(|x| <*const _>::addr(x))
+}
macro_rules! __thread_local_inner {
// used to generate the `LocalKey` value for const-initialized thread locals
(@key $t:ty, const $init:expr) => {{
- #[cfg_attr(not(windows), inline(always))] // see comments below
+ #[cfg_attr(not(windows), inline)] // see comments below
#[deny(unsafe_op_in_unsafe_fn)]
unsafe fn __getit(
_init: $crate::option::Option<&mut $crate::option::Option<$t>>,
// gets the pessimistic path for now where it's never inlined.
//
// The issue of "should enable on Windows sometimes" is #84933
- #[cfg_attr(not(windows), inline(always))]
+ #[cfg_attr(not(windows), inline)]
unsafe fn __getit(
init: $crate::option::Option<&mut $crate::option::Option<$t>>,
) -> $crate::option::Option<&'static $t> {
return os.path.join(self.bin_root(True), '.rustfmt-stamp')
def llvm_stamp(self):
- """Return the path for .rustfmt-stamp
+ """Return the path for .llvm-stamp
>>> rb = RustBuild()
>>> rb.build_dir = "build"
use std::collections::BTreeSet;
use std::env;
use std::ffi::OsStr;
-use std::fmt::Debug;
+use std::fmt::{Debug, Write};
use std::fs;
use std::hash::Hash;
use std::ops::Deref;
use crate::cache::{Cache, Interned, INTERNER};
use crate::check;
use crate::compile;
-use crate::config::TargetSelection;
+use crate::config::{SplitDebuginfo, TargetSelection};
use crate::dist;
use crate::doc;
use crate::flags::{Color, Subcommand};
if found_kind.is_empty() {
panic!("empty kind in task path {}", path.display());
}
- kind = Some(Kind::parse(found_kind));
+ kind = Kind::parse(found_kind);
+ assert!(kind.is_some());
path = Path::new(found_prefix).join(components.as_path());
}
}
self
}
+ // single alias, which does not correspond to any on-disk path
+ pub fn alias(mut self, alias: &str) -> Self {
+ assert!(
+ !self.builder.src.join(alias).exists(),
+ "use `builder.path()` for real paths: {}",
+ alias
+ );
+ self.paths.insert(PathSet::Set(
+ std::iter::once(TaskPath { path: alias.into(), kind: Some(self.kind) }).collect(),
+ ));
+ self
+ }
+
// single, non-aliased path
pub fn path(self, path: &str) -> Self {
self.paths(&[path])
// multiple aliases for the same job
pub fn paths(mut self, paths: &[&str]) -> Self {
self.paths.insert(PathSet::Set(
- paths.iter().map(|p| TaskPath { path: p.into(), kind: Some(self.kind) }).collect(),
+ paths
+ .iter()
+ .map(|p| {
+ // FIXME(#96188): make sure this is actually a path.
+ // This currently breaks for paths within submodules.
+ //assert!(
+ // self.builder.src.join(p).exists(),
+ // "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}",
+ // p
+ //);
+ TaskPath { path: p.into(), kind: Some(self.kind) }
+ })
+ .collect(),
));
self
}
Check,
Clippy,
Fix,
+ Format,
Test,
Bench,
- Dist,
Doc,
+ Clean,
+ Dist,
Install,
Run,
+ Setup,
}
impl Kind {
- fn parse(string: &str) -> Kind {
- match string {
- "build" => Kind::Build,
- "check" => Kind::Check,
+ pub fn parse(string: &str) -> Option<Kind> {
+ // these strings, including the one-letter aliases, must match the x.py help text
+ Some(match string {
+ "build" | "b" => Kind::Build,
+ "check" | "c" => Kind::Check,
"clippy" => Kind::Clippy,
"fix" => Kind::Fix,
- "test" => Kind::Test,
+ "fmt" => Kind::Format,
+ "test" | "t" => Kind::Test,
"bench" => Kind::Bench,
+ "doc" | "d" => Kind::Doc,
+ "clean" => Kind::Clean,
"dist" => Kind::Dist,
- "doc" => Kind::Doc,
"install" => Kind::Install,
- "run" => Kind::Run,
- other => panic!("unknown kind: {}", other),
- }
+ "run" | "r" => Kind::Run,
+ "setup" => Kind::Setup,
+ _ => return None,
+ })
}
- fn as_str(&self) -> &'static str {
+ pub fn as_str(&self) -> &'static str {
match self {
Kind::Build => "build",
Kind::Check => "check",
Kind::Clippy => "clippy",
Kind::Fix => "fix",
+ Kind::Format => "fmt",
Kind::Test => "test",
Kind::Bench => "bench",
- Kind::Dist => "dist",
Kind::Doc => "doc",
+ Kind::Clean => "clean",
+ Kind::Dist => "dist",
Kind::Install => "install",
Kind::Run => "run",
+ Kind::Setup => "setup",
}
}
}
native::Lld,
native::CrtBeginEnd
),
- Kind::Check | Kind::Clippy { .. } | Kind::Fix => describe!(
+ Kind::Check => describe!(
check::Std,
check::Rustc,
check::Rustdoc,
install::Rustc
),
Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest, run::BumpStage0),
+ // These commands either don't use paths, or they're special-cased in Build::build()
+ Kind::Clean | Kind::Clippy | Kind::Fix | Kind::Format | Kind::Setup => vec![],
}
}
- pub fn get_help(build: &Build, subcommand: &str) -> Option<String> {
- let kind = match subcommand {
- "build" | "b" => Kind::Build,
- "doc" | "d" => Kind::Doc,
- "test" | "t" => Kind::Test,
- "bench" => Kind::Bench,
- "dist" => Kind::Dist,
- "install" => Kind::Install,
- _ => return None,
- };
+ pub fn get_help(build: &Build, kind: Kind) -> Option<String> {
+ let step_descriptions = Builder::get_step_descriptions(kind);
+ if step_descriptions.is_empty() {
+ return None;
+ }
let builder = Self::new_internal(build, kind, vec![]);
let builder = &builder;
// The "build" kind here is just a placeholder, it will be replaced with something else in
// the following statement.
let mut should_run = ShouldRun::new(builder, Kind::Build);
- for desc in Builder::get_step_descriptions(builder.kind) {
+ for desc in step_descriptions {
should_run.kind = desc.kind;
should_run = (desc.should_run)(should_run);
}
let mut help = String::from("Available paths:\n");
let mut add_path = |path: &Path| {
- help.push_str(&format!(" ./x.py {} {}\n", subcommand, path.display()));
+ t!(write!(help, " ./x.py {} {}\n", kind.as_str(), path.display()));
};
for pathset in should_run.paths {
match pathset {
},
);
- // `dsymutil` adds time to builds on Apple platforms for no clear benefit, and also makes
- // it more difficult for debuggers to find debug info. The compiler currently defaults to
- // running `dsymutil` to preserve its historical default, but when compiling the compiler
- // itself, we skip it by default since we know it's safe to do so in that case.
- // See https://github.com/rust-lang/rust/issues/79361 for more info on this flag.
- if target.contains("apple") {
- if self.config.rust_run_dsymutil {
- rustflags.arg("-Csplit-debuginfo=packed");
- } else {
- rustflags.arg("-Csplit-debuginfo=unpacked");
+ // FIXME(davidtwco): #[cfg(not(bootstrap))] - #95612 needs to be in the bootstrap compiler
+ // for this conditional to be removed.
+ if !target.contains("windows") || compiler.stage >= 1 {
+ if target.contains("linux") || target.contains("windows") {
+ rustflags.arg("-Zunstable-options");
}
+ match self.config.rust_split_debuginfo {
+ SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"),
+ SplitDebuginfo::Unpacked => rustflags.arg("-Csplit-debuginfo=unpacked"),
+ SplitDebuginfo::Off => rustflags.arg("-Csplit-debuginfo=off"),
+ };
}
if self.config.cmd.bless() {
build.verbose(&format!("AR_{} = {:?}", &target.triple, ar));
build.ar.insert(target, ar);
}
+
+ if let Some(ranlib) = config.and_then(|c| c.ranlib.clone()) {
+ build.ranlib.insert(target, ranlib);
+ }
}
}
pub rust_debuginfo_level_std: u32,
pub rust_debuginfo_level_tools: u32,
pub rust_debuginfo_level_tests: u32,
- pub rust_run_dsymutil: bool,
+ pub rust_split_debuginfo: SplitDebuginfo,
pub rust_rpath: bool,
pub rustc_parallel: bool,
pub rustc_default_linker: Option<String>,
}
}
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum SplitDebuginfo {
+ Packed,
+ Unpacked,
+ Off,
+}
+
+impl Default for SplitDebuginfo {
+ fn default() -> Self {
+ SplitDebuginfo::Off
+ }
+}
+
+impl std::str::FromStr for SplitDebuginfo {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "packed" => Ok(SplitDebuginfo::Packed),
+ "unpacked" => Ok(SplitDebuginfo::Unpacked),
+ "off" => Ok(SplitDebuginfo::Off),
+ _ => Err(()),
+ }
+ }
+}
+
+impl SplitDebuginfo {
+ /// Returns the default `-Csplit-debuginfo` value for the current target. See the comment for
+ /// `rust.split-debuginfo` in `config.toml.example`.
+ fn default_for_platform(target: &str) -> Self {
+ if target.contains("apple") {
+ SplitDebuginfo::Unpacked
+ } else if target.contains("windows") {
+ SplitDebuginfo::Packed
+ } else {
+ SplitDebuginfo::Off
+ }
+ }
+}
+
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TargetSelection {
pub triple: Interned<String>,
debuginfo_level_std: Option<u32> = "debuginfo-level-std",
debuginfo_level_tools: Option<u32> = "debuginfo-level-tools",
debuginfo_level_tests: Option<u32> = "debuginfo-level-tests",
+ split_debuginfo: Option<String> = "split-debuginfo",
run_dsymutil: Option<bool> = "run-dsymutil",
backtrace: Option<bool> = "backtrace",
incremental: Option<bool> = "incremental",
debuginfo_level_std = rust.debuginfo_level_std;
debuginfo_level_tools = rust.debuginfo_level_tools;
debuginfo_level_tests = rust.debuginfo_level_tests;
- config.rust_run_dsymutil = rust.run_dsymutil.unwrap_or(false);
+ config.rust_split_debuginfo = rust
+ .split_debuginfo
+ .as_deref()
+ .map(SplitDebuginfo::from_str)
+ .map(|v| v.expect("invalid value for rust.split_debuginfo"))
+ .unwrap_or(SplitDebuginfo::default_for_platform(&config.build.triple));
optimize = rust.optimize;
ignore_git = rust.ignore_git;
config.rust_new_symbol_mangling = rust.new_symbol_mangling;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = run.builder.config.docs;
- run.path("rust-docs").default_condition(default)
+ run.alias("rust-docs").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
- run.path("rustc-docs").default_condition(builder.config.compiler_docs)
+ run.alias("rustc-docs").default_condition(builder.config.compiler_docs)
}
fn make_run(run: RunConfig<'_>) {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("rust-mingw")
+ run.alias("rust-mingw")
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("rustc")
+ run.alias("rustc")
}
fn make_run(run: RunConfig<'_>) {
type Output = ();
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/lldb_batchmode.py")
+ run.path("src/etc/lldb_batchmode.py")
}
fn make_run(run: RunConfig<'_>) {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("rust-std")
+ run.alias("rust-std")
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("rustc-dev")
+ run.alias("rustc-dev")
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "analysis");
- run.path("rust-analysis").default_condition(default)
+ run.alias("rust-analysis").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("rust-src")
+ run.alias("rust-src")
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
- run.path("rustc-src").default_condition(builder.config.rust_dist_src)
+ run.alias("rustc-src").default_condition(builder.config.rust_dist_src)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "cargo");
- run.path("cargo").default_condition(default)
+ run.alias("cargo").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "rls");
- run.path("rls").default_condition(default)
+ run.alias("rls").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "rust-analyzer");
- run.path("rust-analyzer").default_condition(default)
+ run.alias("rust-analyzer").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "clippy");
- run.path("clippy").default_condition(default)
+ run.alias("clippy").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "miri");
- run.path("miri").default_condition(default)
+ run.alias("miri").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "rustfmt");
- run.path("rustfmt").default_condition(default)
+ run.alias("rustfmt").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
// we run the step by default when only `extended = true`, and decide whether to actually
// run it or not later.
let default = run.builder.config.extended;
- run.path("rust-demangler").default_condition(default)
+ run.alias("rust-demangler").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
- run.path("extended").default_condition(builder.config.extended)
+ run.alias("extended").default_condition(builder.config.extended)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "llvm-tools");
- run.path("llvm-tools").default_condition(default)
+ // FIXME: allow using the names of the tools themselves?
+ run.alias("llvm-tools").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("rust-dev")
+ run.alias("rust-dev")
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("build-manifest")
+ run.alias("build-manifest")
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("reproducible-artifacts")
+ run.alias("reproducible-artifacts")
}
fn make_run(run: RunConfig<'_>) {
use getopts::Options;
-use crate::builder::Builder;
+use crate::builder::{Builder, Kind};
use crate::config::{Config, TargetSelection};
use crate::setup::Profile;
use crate::util::t;
// the subcommand. Therefore we must manually identify the subcommand first, so that we can
// complete the definition of the options. Then we can use the getopt::Matches object from
// there on out.
- let subcommand = args.iter().find(|&s| {
- (s == "build")
- || (s == "b")
- || (s == "check")
- || (s == "c")
- || (s == "clippy")
- || (s == "fix")
- || (s == "fmt")
- || (s == "test")
- || (s == "t")
- || (s == "bench")
- || (s == "doc")
- || (s == "d")
- || (s == "clean")
- || (s == "dist")
- || (s == "install")
- || (s == "run")
- || (s == "r")
- || (s == "setup")
- });
- let subcommand = match subcommand {
+ let subcommand = match args.iter().find_map(|s| Kind::parse(&s)) {
Some(s) => s,
None => {
// No or an invalid subcommand -- show the general usage and subcommand help
};
// Some subcommands get extra options
- match subcommand.as_str() {
- "test" | "t" => {
+ match subcommand {
+ Kind::Test => {
opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
opts.optmulti(
"",
`/<build_base>/rustfix_missing_coverage.txt`",
);
}
- "check" | "c" => {
+ Kind::Check => {
opts.optflag("", "all-targets", "Check all targets");
}
- "bench" => {
+ Kind::Bench => {
opts.optmulti("", "test-args", "extra arguments", "ARGS");
}
- "clippy" => {
+ Kind::Clippy => {
opts.optflag("", "fix", "automatically apply lint suggestions");
}
- "doc" | "d" => {
+ Kind::Doc => {
opts.optflag("", "open", "open the docs in a browser");
}
- "clean" => {
+ Kind::Clean => {
opts.optflag("", "all", "clean all build artifacts");
}
- "fmt" => {
+ Kind::Format => {
opts.optflag("", "check", "check formatting instead of applying.");
}
_ => {}
// fn usage()
let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! {
- let mut extra_help = String::new();
-
- // All subcommands except `clean` can have an optional "Available paths" section
- if verbose {
- let config = Config::parse(&["build".to_string()]);
- let build = Build::new(config);
-
- let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
- extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
- } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") {
- extra_help.push_str(
- format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand)
- .as_str(),
- );
- }
+ let config = Config::parse(&["build".to_string()]);
+ let build = Build::new(config);
+ let paths = Builder::get_help(&build, subcommand);
println!("{}", opts.usage(subcommand_help));
- if !extra_help.is_empty() {
- println!("{}", extra_help);
+ if let Some(s) = paths {
+ if verbose {
+ println!("{}", s);
+ } else {
+ println!(
+ "Run `./x.py {} -h -v` to see a list of available paths.",
+ subcommand.as_str()
+ );
+ }
+ } else if verbose {
+ panic!("No paths available for subcommand `{}`", subcommand.as_str());
}
process::exit(exit_code);
};
// ^-- option ^ ^- actual subcommand
// \_ arg to option could be mistaken as subcommand
let mut pass_sanity_check = true;
- match matches.free.get(0) {
+ match matches.free.get(0).and_then(|s| Kind::parse(&s)) {
Some(check_subcommand) => {
if check_subcommand != subcommand {
pass_sanity_check = false;
process::exit(1);
}
// Extra help text for some commands
- match subcommand.as_str() {
- "build" | "b" => {
+ match subcommand {
+ Kind::Build => {
subcommand_help.push_str(
"\n
Arguments:
./x.py build ",
);
}
- "check" | "c" => {
+ Kind::Check => {
subcommand_help.push_str(
"\n
Arguments:
If no arguments are passed then many artifacts are checked.",
);
}
- "clippy" => {
+ Kind::Clippy => {
subcommand_help.push_str(
"\n
Arguments:
./x.py clippy library/core library/proc_macro",
);
}
- "fix" => {
+ Kind::Fix => {
subcommand_help.push_str(
"\n
Arguments:
./x.py fix library/core library/proc_macro",
);
}
- "fmt" => {
+ Kind::Format => {
subcommand_help.push_str(
"\n
Arguments:
./x.py fmt --check",
);
}
- "test" | "t" => {
+ Kind::Test => {
subcommand_help.push_str(
"\n
Arguments:
./x.py test --stage 1",
);
}
- "doc" | "d" => {
+ Kind::Doc => {
subcommand_help.push_str(
"\n
Arguments:
./x.py doc --stage 1",
);
}
- "run" | "r" => {
+ Kind::Run => {
subcommand_help.push_str(
"\n
Arguments:
At least a tool needs to be called.",
);
}
- "setup" => {
+ Kind::Setup => {
subcommand_help.push_str(&format!(
"\n
x.py setup creates a `config.toml` which changes the defaults for x.py itself.
Profile::all_for_help(" ").trim_end()
));
}
- _ => {}
+ Kind::Bench | Kind::Clean | Kind::Dist | Kind::Install => {}
};
// Get any optional paths which occur after the subcommand
let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
usage(0, &opts, verbose, &subcommand_help);
}
- let cmd = match subcommand.as_str() {
- "build" | "b" => Subcommand::Build { paths },
- "check" | "c" => {
+ let cmd = match subcommand {
+ Kind::Build => Subcommand::Build { paths },
+ Kind::Check => {
if matches.opt_present("all-targets") {
eprintln!(
"Warning: --all-targets is now on by default and does not need to be passed explicitly."
}
Subcommand::Check { paths }
}
- "clippy" => Subcommand::Clippy { paths, fix: matches.opt_present("fix") },
- "fix" => Subcommand::Fix { paths },
- "test" | "t" => Subcommand::Test {
+ Kind::Clippy => Subcommand::Clippy { paths, fix: matches.opt_present("fix") },
+ Kind::Fix => Subcommand::Fix { paths },
+ Kind::Test => Subcommand::Test {
paths,
bless: matches.opt_present("bless"),
force_rerun: matches.opt_present("force-rerun"),
DocTests::Yes
},
},
- "bench" => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
- "doc" | "d" => Subcommand::Doc { paths, open: matches.opt_present("open") },
- "clean" => {
+ Kind::Bench => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
+ Kind::Doc => Subcommand::Doc { paths, open: matches.opt_present("open") },
+ Kind::Clean => {
if !paths.is_empty() {
println!("\nclean does not take a path argument\n");
usage(1, &opts, verbose, &subcommand_help);
Subcommand::Clean { all: matches.opt_present("all") }
}
- "fmt" => Subcommand::Format { check: matches.opt_present("check"), paths },
- "dist" => Subcommand::Dist { paths },
- "install" => Subcommand::Install { paths },
- "run" | "r" => {
+ Kind::Format => Subcommand::Format { check: matches.opt_present("check"), paths },
+ Kind::Dist => Subcommand::Dist { paths },
+ Kind::Install => Subcommand::Install { paths },
+ Kind::Run => {
if paths.is_empty() {
println!("\nrun requires at least a path!\n");
usage(1, &opts, verbose, &subcommand_help);
}
Subcommand::Run { paths }
}
- "setup" => {
+ Kind::Setup => {
let profile = if paths.len() > 1 {
println!("\nat most one profile can be passed to setup\n");
usage(1, &opts, verbose, &subcommand_help)
};
Subcommand::Setup { profile }
}
- _ => {
- usage(1, &opts, verbose, &subcommand_help);
- }
};
if let Subcommand::Check { .. } = &cmd {
macro_rules! install {
(($sel:ident, $builder:ident, $_config:ident),
$($name:ident,
- $path:expr,
+ $condition_name: ident = $path_or_alias: literal,
$default_cond:expr,
only_hosts: $only_hosts:expr,
$run_item:block $(, $c:ident)*;)+) => {
#[allow(dead_code)]
fn should_build(config: &Config) -> bool {
config.extended && config.tools.as_ref()
- .map_or(true, |t| t.contains($path))
+ .map_or(true, |t| t.contains($path_or_alias))
}
}
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let $_config = &run.builder.config;
- run.path($path).default_condition($default_cond)
+ run.$condition_name($path_or_alias).default_condition($default_cond)
}
fn make_run(run: RunConfig<'_>) {
}
install!((self, builder, _config),
- Docs, "src/doc", _config.docs, only_hosts: false, {
+ Docs, path = "src/doc", _config.docs, only_hosts: false, {
let tarball = builder.ensure(dist::Docs { host: self.target }).expect("missing docs");
install_sh(builder, "docs", self.compiler.stage, Some(self.target), &tarball);
};
- Std, "library/std", true, only_hosts: false, {
+ Std, path = "library/std", true, only_hosts: false, {
for target in &builder.targets {
// `expect` should be safe, only None when host != build, but this
// only runs when host == build
install_sh(builder, "std", self.compiler.stage, Some(*target), &tarball);
}
};
- Cargo, "cargo", Self::should_build(_config), only_hosts: true, {
+ Cargo, alias = "cargo", Self::should_build(_config), only_hosts: true, {
let tarball = builder
.ensure(dist::Cargo { compiler: self.compiler, target: self.target })
.expect("missing cargo");
install_sh(builder, "cargo", self.compiler.stage, Some(self.target), &tarball);
};
- Rls, "rls", Self::should_build(_config), only_hosts: true, {
+ Rls, alias = "rls", Self::should_build(_config), only_hosts: true, {
if let Some(tarball) = builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }) {
install_sh(builder, "rls", self.compiler.stage, Some(self.target), &tarball);
} else {
);
}
};
- RustAnalyzer, "rust-analyzer", Self::should_build(_config), only_hosts: true, {
+ RustAnalyzer, alias = "rust-analyzer", Self::should_build(_config), only_hosts: true, {
if let Some(tarball) =
builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target })
{
);
}
};
- Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
+ Clippy, alias = "clippy", Self::should_build(_config), only_hosts: true, {
let tarball = builder
.ensure(dist::Clippy { compiler: self.compiler, target: self.target })
.expect("missing clippy");
install_sh(builder, "clippy", self.compiler.stage, Some(self.target), &tarball);
};
- Miri, "miri", Self::should_build(_config), only_hosts: true, {
+ Miri, alias = "miri", Self::should_build(_config), only_hosts: true, {
if let Some(tarball) = builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }) {
install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball);
} else {
);
}
};
- Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
+ Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, {
if let Some(tarball) = builder.ensure(dist::Rustfmt {
compiler: self.compiler,
target: self.target
);
}
};
- RustDemangler, "rust-demangler", Self::should_build(_config), only_hosts: true, {
+ RustDemangler, alias = "rust-demangler", Self::should_build(_config), only_hosts: true, {
// Note: Even though `should_build` may return true for `extended` default tools,
// dist::RustDemangler may still return None, unless the target-dependent `profiler` config
// is also true, or the `tools` array explicitly includes "rust-demangler".
);
}
};
- Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
+ Analysis, alias = "analysis", Self::should_build(_config), only_hosts: false, {
// `expect` should be safe, only None with host != build, but this
// only uses the `build` compiler
let tarball = builder.ensure(dist::Analysis {
}).expect("missing analysis");
install_sh(builder, "analysis", self.compiler.stage, Some(self.target), &tarball);
};
- Rustc, "src/librustc", true, only_hosts: true, {
+ Rustc, path = "compiler/rustc", true, only_hosts: true, {
let tarball = builder.ensure(dist::Rustc {
compiler: builder.compiler(builder.top_stage, self.target),
});
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/llvm-project").path("src/llvm-project/llvm").path("src/llvm")
+ run.path("src/llvm-project").path("src/llvm-project/llvm")
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/llvm-project/lld").path("src/tools/lld")
+ run.path("src/llvm-project/lld")
}
fn make_run(run: RunConfig<'_>) {
type Output = Vec<SanitizerRuntime>;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/llvm-project/compiler-rt").path("src/sanitizers")
+ run.alias("sanitizers")
}
fn make_run(run: RunConfig<'_>) {
fn make_run(run: RunConfig<'_>) {
let builder = run.builder;
- let compiler = builder.compiler(builder.top_stage, run.build_triple());
+ let host = run.build_triple();
+ let compiler = builder.compiler_for(builder.top_stage, host, host);
let krate = builder.crate_paths[&run.path];
let test_kind = builder.kind.into();
fn make_run(run: RunConfig<'_>) {
let builder = run.builder;
- let compiler = builder.compiler(builder.top_stage, run.build_triple());
+ let host = run.build_triple();
+ let compiler = builder.compiler_for(builder.top_stage, host, host);
let test_kind = builder.kind.into();
let krate = builder.crate_paths[&run.path];
type Output = ();
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("distcheck")
+ run.alias("distcheck")
}
fn make_run(run: RunConfig<'_>) {
}
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("check-tools")
+ run.alias("check-tools")
}
fn make_run(run: RunConfig<'_>) {
-Subproject commit ea90bbaf53ba64ef4e2da9ac2352b298aec6bec8
+Subproject commit de0dbffc5812fd885700874e8d258dd334733ac4
-Subproject commit a6de8b6e3ea5d4f0de8b7b9a7e5c1405dc2c2ddb
+Subproject commit f7cefbb995eec8c6148f213235e9e2e03268e775
-Subproject commit 11f1165e8a2f5840467e748c8108dc53c948ee9a
+Subproject commit c7d8467ca9158da58ef295ae65dbf00a308752d9
-Subproject commit c97d14fa6fed0baa9255432b8a93cb70614f80e3
+Subproject commit b5f6c2362baf932db9440fbfcb509b309237ee85
-Subproject commit ec954f35eedf592cd173b21c05a7f80a65b61d8a
+Subproject commit 44a80e8d8bfc5881c9bd69a2cb3a570776ee4181
-Subproject commit 155126b1d2e2cb01ddb1d7ba9489b90d7cd173ad
+Subproject commit 043e60f4f191651e9f8bf52fa32df14defbb23d9
+++ /dev/null
-# `extern-location`
-
-MCP for this feature: [#303]
-
-[#303]: https://github.com/rust-lang/compiler-team/issues/303
-
-------------------------
-
-The `unused-extern-crates` lint reports when a crate was specified on the rustc
-command-line with `--extern name=path` but no symbols were referenced in it.
-This is useful to know, but it's hard to map that back to a specific place a user
-or tool could fix (ie, to remove the unused dependency).
-
-The `--extern-location` flag allows the build system to associate a location with
-the `--extern` option, which is then emitted as part of the diagnostics. This location
-is abstract and just round-tripped through rustc; the compiler never attempts to
-interpret it in any way.
-
-There are two supported forms of location: a bare string, or a blob of json:
-- `--extern-location foo=raw:Makefile:123` would associate the raw string `Makefile:123`
-- `--extern-location 'bar=json:{"target":"//my_project:library","dep":"//common:serde"}` would
- associate the json structure with `--extern bar=<path>`, indicating which dependency of
- which rule introduced the unused extern crate.
-
-This primarily intended to be used with tooling - for example a linter which can automatically
-remove unused dependencies - rather than being directly presented to users.
-
-`raw` locations are presented as part of the normal rendered diagnostics and included in
-the json form. `json` locations are only included in the json form of diagnostics,
-as a `tool_metadata` field. For `raw` locations `tool_metadata` is simply a json string,
-whereas `json` allows the rustc invoker to fully control its form and content.
else:
actual_str = flatten(actual_tree)
+ # Conditions:
+ # 1. Is --bless
+ # 2. Are actual and expected tree different
+ # 3. Are actual and expected text different
if not expected_str \
- or (not normalize_to_text and
+ or (not normalize_to_text and \
not compare_tree(make_xml(actual_str), make_xml(expected_str), stderr)) \
or (normalize_to_text and actual_str != expected_str):
rustdoc-json-types = { path = "../rustdoc-json-types" }
tracing = "0.1"
tracing-tree = "0.2.0"
+once_cell = "1.10.0"
[dependencies.tracing-subscriber]
version = "0.3.3"
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::fold::TypeFolder;
// this is the ID of the `extern crate` statement
let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id).unwrap_or(LOCAL_CRATE);
// this is the ID of the crate itself
- let crate_def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+ let crate_def_id = cnum.as_def_id();
let attrs = cx.tcx.hir().attrs(krate.hir_id());
let ty_vis = cx.tcx.visibility(krate.def_id);
let please_inline = ty_vis.is_public()
} else {
if inline_attr.is_none() {
if let Res::Def(DefKind::Mod, did) = path.res {
- if !did.is_local() && did.index == CRATE_DEF_INDEX {
+ if !did.is_local() && did.is_crate_root() {
// if we're `pub use`ing an extern crate root, don't inline it unless we
// were specifically asked for it
denied = true;
use std::cell::RefCell;
use std::default::Default;
-use std::fmt;
use std::hash::Hash;
-use std::iter;
use std::lazy::SyncOnceCell as OnceCell;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
-use std::vec;
+use std::{cmp, fmt, iter};
use arrayvec::ArrayVec;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{BodyId, Mutability};
use rustc_index::vec::IndexVec;
};
crate use self::Visibility::{Inherited, Public};
+#[cfg(test)]
+mod tests;
+
crate type ItemIdSet = FxHashSet<ItemId>;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
ItemId::Primitive(_, krate) => krate,
}
}
-
- #[inline]
- crate fn index(self) -> Option<DefIndex> {
- match self {
- ItemId::DefId(id) => Some(id.index),
- _ => None,
- }
- }
}
impl From<DefId> for ItemId {
#[inline]
crate fn def_id(&self) -> DefId {
- DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }
+ self.crate_num.as_def_id()
}
crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
// Failing that, see if there's an attribute specifying where to find this
// external crate
- let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX };
+ let did = self.crate_num.as_def_id();
tcx.get_attrs(did)
.lists(sym::doc)
.filter(|a| a.has_name(sym::html_root_url))
}
crate fn is_crate(&self) -> bool {
- self.is_mod() && self.item_id.as_def_id().map_or(false, |did| did.index == CRATE_DEF_INDEX)
+ self.is_mod() && self.item_id.as_def_id().map_or(false, |did| did.is_crate_root())
}
crate fn is_mod(&self) -> bool {
self.type_() == ItemType::Module
acc
}
+/// Removes excess indentation on comments in order for the Markdown
+/// to be parsed correctly. This is necessary because the convention for
+/// writing documentation is to provide a space between the /// or //! marker
+/// and the doc text, but Markdown is whitespace-sensitive. For example,
+/// a block of text with four-space indentation is parsed as a code block,
+/// so if we didn't unindent comments, these list items
+///
+/// /// A list:
+/// ///
+/// /// - Foo
+/// /// - Bar
+///
+/// would be parsed as if they were in a code block, which is likely not what the user intended.
+fn unindent_doc_fragments(docs: &mut Vec<DocFragment>) {
+ // `add` is used in case the most common sugared doc syntax is used ("/// "). The other
+ // fragments kind's lines are never starting with a whitespace unless they are using some
+ // markdown formatting requiring it. Therefore, if the doc block have a mix between the two,
+ // we need to take into account the fact that the minimum indent minus one (to take this
+ // whitespace into account).
+ //
+ // For example:
+ //
+ // /// hello!
+ // #[doc = "another"]
+ //
+ // In this case, you want "hello! another" and not "hello! another".
+ let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind)
+ && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc)
+ {
+ // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to
+ // "decide" how much the minimum indent will be.
+ 1
+ } else {
+ 0
+ };
+
+ // `min_indent` is used to know how much whitespaces from the start of each lines must be
+ // removed. Example:
+ //
+ // /// hello!
+ // #[doc = "another"]
+ //
+ // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum
+ // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4
+ // (5 - 1) whitespaces.
+ let Some(min_indent) = docs
+ .iter()
+ .map(|fragment| {
+ fragment.doc.as_str().lines().fold(usize::MAX, |min_indent, line| {
+ if line.chars().all(|c| c.is_whitespace()) {
+ min_indent
+ } else {
+ // Compare against either space or tab, ignoring whether they are
+ // mixed or not.
+ let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
+ cmp::min(min_indent, whitespace)
+ + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }
+ }
+ })
+ })
+ .min()
+ else {
+ return;
+ };
+
+ for fragment in docs {
+ if fragment.doc == kw::Empty {
+ continue;
+ }
+
+ let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 {
+ min_indent - add
+ } else {
+ min_indent
+ };
+
+ fragment.indent = min_indent;
+ }
+}
+
/// A link that has not yet been rendered.
///
/// This link will be turned into a rendered link by [`Item::links`].
attrs: &[ast::Attribute],
additional_attrs: Option<(&[ast::Attribute], DefId)>,
) -> Attributes {
- let mut doc_strings: Vec<DocFragment> = vec![];
- let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
- if let Some((value, kind)) = attr.doc_str_and_comment_kind() {
- trace!("got doc_str={:?}", value);
- let value = beautify_doc_string(value, kind);
+ // Additional documentation should be shown before the original documentation.
+ let attrs1 = additional_attrs
+ .into_iter()
+ .flat_map(|(attrs, def_id)| attrs.iter().map(move |attr| (attr, Some(def_id))));
+ let attrs2 = attrs.iter().map(|attr| (attr, None));
+ Attributes::from_ast_iter(attrs1.chain(attrs2), false)
+ }
+
+ crate fn from_ast_iter<'a>(
+ attrs: impl Iterator<Item = (&'a ast::Attribute, Option<DefId>)>,
+ doc_only: bool,
+ ) -> Attributes {
+ let mut doc_strings = Vec::new();
+ let mut other_attrs = Vec::new();
+ for (attr, parent_module) in attrs {
+ if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
+ trace!("got doc_str={doc_str:?}");
+ let doc = beautify_doc_string(doc_str, comment_kind);
let kind = if attr.is_doc_comment() {
DocFragmentKind::SugaredDoc
} else {
DocFragmentKind::RawDoc
};
-
- let frag =
- DocFragment { span: attr.span, doc: value, kind, parent_module, indent: 0 };
-
- doc_strings.push(frag);
-
- None
- } else {
- Some(attr.clone())
+ let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 };
+ doc_strings.push(fragment);
+ } else if !doc_only {
+ other_attrs.push(attr.clone());
}
- };
+ }
- // Additional documentation should be shown before the original documentation
- let other_attrs = additional_attrs
- .into_iter()
- .flat_map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
- .chain(attrs.iter().map(|attr| (attr, None)))
- .filter_map(clean_attr)
- .collect();
+ unindent_doc_fragments(&mut doc_strings);
Attributes { doc_strings, other_attrs }
}
}
/// Return the doc-comments on this item, grouped by the module they came from.
- ///
/// The module can be different if this is a re-export with added documentation.
- crate fn collapsed_doc_value_by_module_level(&self) -> FxHashMap<Option<DefId>, String> {
- let mut ret = FxHashMap::default();
- if self.doc_strings.len() == 0 {
- return ret;
- }
- let last_index = self.doc_strings.len() - 1;
-
- for (i, new_frag) in self.doc_strings.iter().enumerate() {
- let out = ret.entry(new_frag.parent_module).or_default();
- add_doc_fragment(out, new_frag);
- if i == last_index {
- out.pop();
- }
+ ///
+ /// The last newline is not trimmed so the produced strings are reusable between
+ /// early and late doc link resolution regardless of their position.
+ crate fn prepare_to_doc_link_resolution(&self) -> FxHashMap<Option<DefId>, String> {
+ let mut res = FxHashMap::default();
+ for fragment in &self.doc_strings {
+ let out_str = res.entry(fragment.parent_module).or_default();
+ add_doc_fragment(out_str, fragment);
}
- ret
+ res
}
/// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
--- /dev/null
+use super::*;
+
+use crate::clean::collapse_doc_fragments;
+
+use rustc_span::create_default_session_globals_then;
+use rustc_span::source_map::DUMMY_SP;
+use rustc_span::symbol::Symbol;
+
+fn create_doc_fragment(s: &str) -> Vec<DocFragment> {
+ vec![DocFragment {
+ span: DUMMY_SP,
+ parent_module: None,
+ doc: Symbol::intern(s),
+ kind: DocFragmentKind::SugaredDoc,
+ indent: 0,
+ }]
+}
+
+#[track_caller]
+fn run_test(input: &str, expected: &str) {
+ create_default_session_globals_then(|| {
+ let mut s = create_doc_fragment(input);
+ unindent_doc_fragments(&mut s);
+ assert_eq!(collapse_doc_fragments(&s), expected);
+ });
+}
+
+#[test]
+fn should_unindent() {
+ run_test(" line1\n line2", "line1\nline2");
+}
+
+#[test]
+fn should_unindent_multiple_paragraphs() {
+ run_test(" line1\n\n line2", "line1\n\nline2");
+}
+
+#[test]
+fn should_leave_multiple_indent_levels() {
+ // Line 2 is indented another level beyond the
+ // base indentation and should be preserved
+ run_test(" line1\n\n line2", "line1\n\n line2");
+}
+
+#[test]
+fn should_ignore_first_line_indent() {
+ run_test("line1\n line2", "line1\n line2");
+}
+
+#[test]
+fn should_not_ignore_first_line_indent_in_a_single_line_para() {
+ run_test("line1\n\n line2", "line1\n\n line2");
+}
+
+#[test]
+fn should_unindent_tabs() {
+ run_test("\tline1\n\tline2", "line1\nline2");
+}
+
+#[test]
+fn should_trim_mixed_indentation() {
+ run_test("\t line1\n\t line2", "line1\nline2");
+ run_test(" \tline1\n \tline2", "line1\nline2");
+}
+
+#[test]
+fn should_not_trim() {
+ run_test("\t line1 \n\t line2", "line1 \nline2");
+ run_test(" \tline1 \n \tline2", "line1 \nline2");
+}
use rustc_errors::emitter::{Emitter, EmitterWriter};
use rustc_errors::json::JsonEmitter;
use rustc_feature::UnstableFeatures;
-use rustc_hir::def::Res;
+use rustc_hir::def::{Namespace, Res};
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{HirId, Path, TraitCandidate};
use crate::clean::{self, ItemId, TraitWithExtraInfo};
use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
use crate::formats::cache::Cache;
+use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink;
use crate::passes::{self, Condition::*};
crate use rustc_session::config::{DebuggingOptions, Input, Options};
crate struct ResolverCaches {
+ crate markdown_links: Option<FxHashMap<String, Vec<PreprocessedMarkdownLink>>>,
+ crate doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<NodeId>>>,
/// Traits in scope for a given module.
/// See `collect_intra_doc_links::traits_implemented_by` for more details.
crate traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
nested: F,
) {
let ast_attrs = self.tcx.hir().attrs(hir_id);
- let mut attrs = Attributes::from_ast(ast_attrs, None);
-
if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
if !cfg.matches(&self.sess.parse_sess, Some(self.sess.features_untracked())) {
return;
self.collector.names.push(name);
}
- attrs.unindent_doc_comments();
// The collapse-docs pass won't combine sugared/raw doc attributes, or included files with
// anything else, this will combine them for us.
+ let attrs = Attributes::from_ast(ast_attrs, None);
if let Some(doc) = attrs.collapsed_doc_value() {
// Use the outermost invocation, so that doctest names come from where the docs were written.
let span = ast_attrs
use std::mem;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId};
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::ty::TyCtxt;
use rustc_span::{sym, Symbol};
/// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`.
struct CacheBuilder<'a, 'tcx> {
cache: &'a mut Cache,
+ /// This field is used to prevent duplicated impl blocks.
+ impl_ids: FxHashMap<DefId, FxHashSet<DefId>>,
tcx: TyCtxt<'tcx>,
}
.insert(def_id, (vec![crate_name, prim.as_sym()], ItemType::Primitive));
}
- krate = CacheBuilder { tcx, cache: &mut cx.cache }.fold_crate(krate);
+ let (krate, mut impl_ids) = {
+ let mut cache_builder =
+ CacheBuilder { tcx, cache: &mut cx.cache, impl_ids: FxHashMap::default() };
+ krate = cache_builder.fold_crate(krate);
+ (krate, cache_builder.impl_ids)
+ };
for (trait_did, dids, impl_) in cx.cache.orphan_trait_impls.drain(..) {
if cx.cache.traits.contains_key(&trait_did) {
for did in dids {
- cx.cache.impls.entry(did).or_default().push(impl_.clone());
+ if impl_ids.entry(did).or_default().insert(impl_.def_id()) {
+ cx.cache.impls.entry(did).or_default().push(impl_.clone());
+ }
}
}
}
// A crate has a module at its root, containing all items,
// which should not be indexed. The crate-item itself is
// inserted later on when serializing the search-index.
- if item.item_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
+ if item.item_id.as_def_id().map_or(false, |idx| !idx.is_crate_root()) {
let desc = item.doc_value().map_or_else(String::new, |x| {
short_markdown_summary(x.as_str(), &item.link_names(self.cache))
});
let impl_item = Impl { impl_item: item };
if impl_item.trait_did().map_or(true, |d| self.cache.traits.contains_key(&d)) {
for did in dids {
- self.cache.impls.entry(did).or_insert_with(Vec::new).push(impl_item.clone());
+ if self.impl_ids.entry(did).or_default().insert(impl_item.def_id()) {
+ self.cache
+ .impls
+ .entry(did)
+ .or_insert_with(Vec::new)
+ .push(impl_item.clone());
+ }
}
} else {
let trait_did = impl_item.trait_did().expect("no trait did");
crate use renderer::{run_format, FormatRenderer};
-use crate::clean;
+use crate::clean::{self, ItemId};
/// Specifies whether rendering directly implemented trait items or ones from a certain Deref
/// impl.
crate fn trait_did(&self) -> Option<DefId> {
self.inner_impl().trait_.as_ref().map(|t| t.def_id())
}
+
+ /// This function is used to extract a `DefId` to be used as a key for the `Cache::impls` field.
+ ///
+ /// It allows to prevent having duplicated implementations showing up (the biggest issue was
+ /// with blanket impls).
+ ///
+ /// It panics if `self` is a `ItemId::Primitive`.
+ crate fn def_id(&self) -> DefId {
+ match self.impl_item.item_id {
+ ItemId::Blanket { impl_id, .. } => impl_id,
+ ItemId::Auto { trait_, .. } => trait_,
+ ItemId::DefId(def_id) => def_id,
+ ItemId::Primitive(_, _) => {
+ panic!(
+ "Unexpected ItemId::Primitive in expect_def_id: {:?}",
+ self.impl_item.item_id
+ )
+ }
+ }
+ }
}
use rustc_middle::ty;
use rustc_middle::ty::DefIdTree;
use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_span::{sym, Symbol};
use rustc_target::spec::abi::Abi;
indent: usize,
end_newline: bool,
) -> impl fmt::Display + 'a + Captures<'tcx> {
+ use fmt::Write;
+
display_fn(move |f| {
let mut where_predicates = gens.where_predicates.iter().filter(|pred| {
!matches!(pred, clean::WherePredicate::BoundPredicate { bounds, .. } if bounds.is_empty())
match pred {
clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
- let bounds = bounds;
- let for_prefix = if bound_params.is_empty() {
- String::new()
- } else if f.alternate() {
- format!(
- "for<{:#}> ",
- comma_sep(bound_params.iter().map(|lt| lt.print()), true)
- )
- } else {
- format!(
- "for<{}> ",
- comma_sep(bound_params.iter().map(|lt| lt.print()), true)
- )
- };
+ let ty_cx = ty.print(cx);
+ let generic_bounds = print_generic_bounds(bounds, cx);
- if f.alternate() {
- write!(
- f,
- "{}{:#}: {:#}",
- for_prefix,
- ty.print(cx),
- print_generic_bounds(bounds, cx)
- )
+ if bound_params.is_empty() {
+ if f.alternate() {
+ write!(f, "{ty_cx:#}: {generic_bounds:#}")
+ } else {
+ write!(f, "{ty_cx}: {generic_bounds}")
+ }
} else {
- write!(
- f,
- "{}{}: {}",
- for_prefix,
- ty.print(cx),
- print_generic_bounds(bounds, cx)
- )
+ if f.alternate() {
+ write!(
+ f,
+ "for<{:#}> {ty_cx:#}: {generic_bounds:#}",
+ comma_sep(bound_params.iter().map(|lt| lt.print()), true)
+ )
+ } else {
+ write!(
+ f,
+ "for<{}> {ty_cx}: {generic_bounds}",
+ comma_sep(bound_params.iter().map(|lt| lt.print()), true)
+ )
+ }
}
}
clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
- write!(
- f,
- "{}: {}",
- lifetime.print(),
- bounds
- .iter()
- .map(|b| b.print(cx).to_string())
- .collect::<Vec<_>>()
- .join(" + ")
- )
+ let mut bounds_display = String::new();
+ for bound in bounds.iter().map(|b| b.print(cx)) {
+ write!(bounds_display, "{bound} + ")?;
+ }
+ bounds_display.truncate(bounds_display.len() - " + ".len());
+ write!(f, "{}: {bounds_display}", lifetime.print())
}
clean::WherePredicate::EqPredicate { lhs, rhs } => {
if f.alternate() {
- write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx),)
+ write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
} else {
- write!(f, "{} == {}", lhs.print(cx), rhs.print(cx),)
+ write!(f, "{} == {}", lhs.print(cx), rhs.print(cx))
}
}
}
return Ok(());
}
- let mut clause = String::new();
-
- if f.alternate() {
- clause.push_str(" where");
- } else {
+ let where_preds = comma_sep(where_predicates, false);
+ let clause = if f.alternate() {
if end_newline {
- clause.push_str(" <span class=\"where fmt-newline\">where");
+ // add a space so stripping <br> tags and breaking spaces still renders properly
+ format!(" where{where_preds}, ")
} else {
- clause.push_str(" <span class=\"where\">where");
+ format!(" where{where_preds}")
}
- }
-
- clause.push_str(&comma_sep(where_predicates, false).to_string());
-
- if end_newline {
- clause.push(',');
- // add a space so stripping <br> tags and breaking spaces still renders properly
- if f.alternate() {
- clause.push(' ');
- } else {
- clause.push_str(" ");
+ } else {
+ let mut br_with_padding = String::with_capacity(6 * indent + 28);
+ br_with_padding.push_str("<br>");
+ for _ in 0..indent + 4 {
+ br_with_padding.push_str(" ");
}
- }
+ let where_preds = where_preds.to_string().replace("<br>", &br_with_padding);
- if !f.alternate() {
- clause.push_str("</span>");
- let padding = " ".repeat(indent + 4);
- clause = clause.replace("<br>", &format!("<br>{}", padding));
- clause.insert_str(0, &" ".repeat(indent.saturating_sub(1)));
- if !end_newline {
- clause.insert_str(0, "<br>");
+ if end_newline {
+ let mut clause = " ".repeat(indent.saturating_sub(1));
+ // add a space so stripping <br> tags and breaking spaces still renders properly
+ write!(
+ clause,
+ " <span class=\"where fmt-newline\">where{where_preds}, </span>"
+ )?;
+ clause
+ } else {
+ // insert a <br> tag after a single space but before multiple spaces at the start
+ if indent == 0 {
+ format!(" <br><span class=\"where\">where{where_preds}</span>")
+ } else {
+ let mut clause = br_with_padding;
+ clause.truncate(clause.len() - 5 * " ".len());
+ write!(clause, " <span class=\"where\">where{where_preds}</span>")?;
+ clause
+ }
}
- }
- write!(f, "{}", clause)
+ };
+ write!(f, "{clause}")
})
}
// visibility, so it shouldn't matter.
let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id());
- if vis_did.index == CRATE_DEF_INDEX {
+ if vis_did.is_crate_root() {
"pub(crate) ".to_owned()
} else if parent_module == Some(vis_did) {
// `pub(in foo)` where `foo` is the parent module
// visibility, so it shouldn't matter.
let parent_module = find_nearest_parent_module(tcx, item_did);
- if vis_did.index == CRATE_DEF_INDEX {
+ if vis_did.is_crate_root() {
"pub(crate) ".to_owned()
} else if parent_module == Some(vis_did) {
// `pub(in foo)` where `foo` is the parent module
use rustc_span::edition::Edition;
use rustc_span::Span;
+use once_cell::sync::Lazy;
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::VecDeque;
pub range: Range<usize>,
}
-crate fn markdown_links(md: &str) -> Vec<MarkdownLink> {
+crate fn markdown_links<R>(md: &str, filter_map: impl Fn(MarkdownLink) -> Option<R>) -> Vec<R> {
if md.is_empty() {
return vec![];
}
let mut push = |link: BrokenLink<'_>| {
let span = span_for_link(&link.reference, link.span);
- links.borrow_mut().push(MarkdownLink {
+ filter_map(MarkdownLink {
kind: LinkType::ShortcutUnknown,
link: link.reference.to_string(),
range: span,
- });
+ })
+ .map(|link| links.borrow_mut().push(link));
None
};
let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut push))
let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1));
for ev in iter {
- if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 {
+ if let Event::Start(Tag::Link(
+ // `<>` links cannot be intra-doc links so we skip them.
+ kind @ (LinkType::Inline
+ | LinkType::Reference
+ | LinkType::ReferenceUnknown
+ | LinkType::Collapsed
+ | LinkType::CollapsedUnknown
+ | LinkType::Shortcut
+ | LinkType::ShortcutUnknown),
+ dest,
+ _,
+ )) = ev.0
+ {
debug!("found link: {dest}");
let span = span_for_link(&dest, ev.1);
- links.borrow_mut().push(MarkdownLink { kind, link: dest.into_string(), range: span });
+ filter_map(MarkdownLink { kind, link: dest.into_string(), range: span })
+ .map(|link| links.borrow_mut().push(link));
}
}
#[derive(Clone, Default, Debug)]
pub struct IdMap {
- map: FxHashMap<String, usize>,
+ map: FxHashMap<Cow<'static, str>, usize>,
}
-fn init_id_map() -> FxHashMap<String, usize> {
+// The map is pre-initialized and cloned each time to avoid reinitializing it repeatedly.
+static DEFAULT_ID_MAP: Lazy<FxHashMap<Cow<'static, str>, usize>> = Lazy::new(|| init_id_map());
+
+fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
let mut map = FxHashMap::default();
// This is the list of IDs used in Javascript.
- map.insert("help".to_owned(), 1);
+ map.insert("help".into(), 1);
// This is the list of IDs used in HTML generated in Rust (including the ones
// used in tera template files).
- map.insert("mainThemeStyle".to_owned(), 1);
- map.insert("themeStyle".to_owned(), 1);
- map.insert("theme-picker".to_owned(), 1);
- map.insert("theme-choices".to_owned(), 1);
- map.insert("settings-menu".to_owned(), 1);
- map.insert("help-button".to_owned(), 1);
- map.insert("main-content".to_owned(), 1);
- map.insert("search".to_owned(), 1);
- map.insert("crate-search".to_owned(), 1);
- map.insert("render-detail".to_owned(), 1);
- map.insert("toggle-all-docs".to_owned(), 1);
- map.insert("all-types".to_owned(), 1);
- map.insert("default-settings".to_owned(), 1);
- map.insert("rustdoc-vars".to_owned(), 1);
- map.insert("sidebar-vars".to_owned(), 1);
- map.insert("copy-path".to_owned(), 1);
- map.insert("TOC".to_owned(), 1);
+ map.insert("mainThemeStyle".into(), 1);
+ map.insert("themeStyle".into(), 1);
+ map.insert("theme-picker".into(), 1);
+ map.insert("theme-choices".into(), 1);
+ map.insert("settings-menu".into(), 1);
+ map.insert("help-button".into(), 1);
+ map.insert("main-content".into(), 1);
+ map.insert("search".into(), 1);
+ map.insert("crate-search".into(), 1);
+ map.insert("render-detail".into(), 1);
+ map.insert("toggle-all-docs".into(), 1);
+ map.insert("all-types".into(), 1);
+ map.insert("default-settings".into(), 1);
+ map.insert("rustdoc-vars".into(), 1);
+ map.insert("sidebar-vars".into(), 1);
+ map.insert("copy-path".into(), 1);
+ map.insert("TOC".into(), 1);
// This is the list of IDs used by rustdoc sections (but still generated by
// rustdoc).
- map.insert("fields".to_owned(), 1);
- map.insert("variants".to_owned(), 1);
- map.insert("implementors-list".to_owned(), 1);
- map.insert("synthetic-implementors-list".to_owned(), 1);
- map.insert("foreign-impls".to_owned(), 1);
- map.insert("implementations".to_owned(), 1);
- map.insert("trait-implementations".to_owned(), 1);
- map.insert("synthetic-implementations".to_owned(), 1);
- map.insert("blanket-implementations".to_owned(), 1);
- map.insert("required-associated-types".to_owned(), 1);
- map.insert("provided-associated-types".to_owned(), 1);
- map.insert("provided-associated-consts".to_owned(), 1);
- map.insert("required-associated-consts".to_owned(), 1);
- map.insert("required-methods".to_owned(), 1);
- map.insert("provided-methods".to_owned(), 1);
- map.insert("implementors".to_owned(), 1);
- map.insert("synthetic-implementors".to_owned(), 1);
- map.insert("implementations-list".to_owned(), 1);
- map.insert("trait-implementations-list".to_owned(), 1);
- map.insert("synthetic-implementations-list".to_owned(), 1);
- map.insert("blanket-implementations-list".to_owned(), 1);
- map.insert("deref-methods".to_owned(), 1);
+ map.insert("fields".into(), 1);
+ map.insert("variants".into(), 1);
+ map.insert("implementors-list".into(), 1);
+ map.insert("synthetic-implementors-list".into(), 1);
+ map.insert("foreign-impls".into(), 1);
+ map.insert("implementations".into(), 1);
+ map.insert("trait-implementations".into(), 1);
+ map.insert("synthetic-implementations".into(), 1);
+ map.insert("blanket-implementations".into(), 1);
+ map.insert("required-associated-types".into(), 1);
+ map.insert("provided-associated-types".into(), 1);
+ map.insert("provided-associated-consts".into(), 1);
+ map.insert("required-associated-consts".into(), 1);
+ map.insert("required-methods".into(), 1);
+ map.insert("provided-methods".into(), 1);
+ map.insert("implementors".into(), 1);
+ map.insert("synthetic-implementors".into(), 1);
+ map.insert("implementations-list".into(), 1);
+ map.insert("trait-implementations-list".into(), 1);
+ map.insert("synthetic-implementations-list".into(), 1);
+ map.insert("blanket-implementations-list".into(), 1);
+ map.insert("deref-methods".into(), 1);
map
}
impl IdMap {
pub fn new() -> Self {
- IdMap { map: init_id_map() }
+ IdMap { map: DEFAULT_ID_MAP.clone() }
}
crate fn derive<S: AsRef<str> + ToString>(&mut self, candidate: S) -> String {
}
};
- self.map.insert(id.clone(), 1);
+ self.map.insert(id.clone().into(), 1);
id
}
}
/**
* @typedef {{
- * raw: string,
- * query: string,
- * type: string,
- * id: string,
+ * name: string,
+ * fullPath: Array<string>,
+ * pathWithoutLast: Array<string>,
+ * pathLast: string,
+ * generics: Array<QueryElement>,
+ * }}
+ */
+var QueryElement;
+
+/**
+ * @typedef {{
+ * pos: number,
+ * totalElems: number,
+ * typeFilter: (null|string),
+ * userQuery: string,
+ * }}
+ */
+var ParserState;
+
+/**
+ * @typedef {{
+ * original: string,
+ * userQuery: string,
+ * typeFilter: number,
+ * elems: Array<QueryElement>,
+ * args: Array<QueryElement>,
+ * returned: Array<QueryElement>,
+ * foundElems: number,
* }}
*/
var ParsedQuery;
* }}
*/
var Row;
+
+/**
+ * @typedef {{
+ * in_args: Array<Object>,
+ * returned: Array<Object>,
+ * others: Array<Object>,
+ * query: ParsedQuery,
+ * }}
+ */
+var ResultsTable;
+
+/**
+ * @typedef {{
+ * desc: string,
+ * displayPath: string,
+ * fullPath: string,
+ * href: string,
+ * id: number,
+ * lev: number,
+ * name: string,
+ * normalizedName: string,
+ * parent: (Object|undefined),
+ * path: string,
+ * ty: number,
+ * }}
+ */
+var Results;
});
}
-function removeEmptyStringsFromArray(x) {
- for (var i = 0, len = x.length; i < len; ++i) {
- if (x[i] === "") {
- x.splice(i, 1);
- i -= 1;
- }
- }
-}
-
/**
* A function to compute the Levenshtein distance between two strings
* Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
searchState.input.value = params.search || "";
}
+ function isWhitespace(c) {
+ return " \t\n\r".indexOf(c) !== -1;
+ }
+
+ function isSpecialStartCharacter(c) {
+ return "<\"".indexOf(c) !== -1;
+ }
+
+ function isEndCharacter(c) {
+ return ",>-".indexOf(c) !== -1;
+ }
+
+ function isStopCharacter(c) {
+ return isWhitespace(c) || isEndCharacter(c);
+ }
+
+ function isErrorCharacter(c) {
+ return "()".indexOf(c) !== -1;
+ }
+
+ function itemTypeFromName(typename) {
+ for (var i = 0, len = itemTypes.length; i < len; ++i) {
+ if (itemTypes[i] === typename) {
+ return i;
+ }
+ }
+
+ throw new Error("Unknown type filter `" + typename + "`");
+ }
+
+ /**
+ * If we encounter a `"`, then we try to extract the string from it until we find another `"`.
+ *
+ * This function will throw an error in the following cases:
+ * * There is already another string element.
+ * * We are parsing a generic argument.
+ * * There is more than one element.
+ * * There is no closing `"`.
+ *
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ * @param {boolean} isInGenerics
+ */
+ function getStringElem(query, parserState, isInGenerics) {
+ if (isInGenerics) {
+ throw new Error("`\"` cannot be used in generics");
+ } else if (query.literalSearch) {
+ throw new Error("Cannot have more than one literal search element");
+ } else if (parserState.totalElems - parserState.genericsElems > 0) {
+ throw new Error("Cannot use literal search when there is more than one element");
+ }
+ parserState.pos += 1;
+ var start = parserState.pos;
+ var end = getIdentEndPosition(parserState);
+ if (parserState.pos >= parserState.length) {
+ throw new Error("Unclosed `\"`");
+ } else if (parserState.userQuery[end] !== "\"") {
+ throw new Error(`Unexpected \`${parserState.userQuery[end]}\` in a string element`);
+ } else if (start === end) {
+ throw new Error("Cannot have empty string element");
+ }
+ // To skip the quote at the end.
+ parserState.pos += 1;
+ query.literalSearch = true;
+ }
+
+ /**
+ * Returns `true` if the current parser position is starting with "::".
+ *
+ * @param {ParserState} parserState
+ *
+ * @return {boolean}
+ */
+ function isPathStart(parserState) {
+ return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '::';
+ }
+
+ /**
+ * Returns `true` if the current parser position is starting with "->".
+ *
+ * @param {ParserState} parserState
+ *
+ * @return {boolean}
+ */
+ function isReturnArrow(parserState) {
+ return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '->';
+ }
+
+ /**
+ * Returns `true` if the given `c` character is valid for an ident.
+ *
+ * @param {string} c
+ *
+ * @return {boolean}
+ */
+ function isIdentCharacter(c) {
+ return (
+ c === '_' ||
+ (c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z'));
+ }
+
+ /**
+ * Returns `true` if the given `c` character is a separator.
+ *
+ * @param {string} c
+ *
+ * @return {boolean}
+ */
+ function isSeparatorCharacter(c) {
+ return c === "," || isWhitespaceCharacter(c);
+ }
+
+ /**
+ * Returns `true` if the given `c` character is a whitespace.
+ *
+ * @param {string} c
+ *
+ * @return {boolean}
+ */
+ function isWhitespaceCharacter(c) {
+ return c === " " || c === "\t";
+ }
+
+ /**
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ * @param {string} name - Name of the query element.
+ * @param {Array<QueryElement>} generics - List of generics of this query element.
+ *
+ * @return {QueryElement} - The newly created `QueryElement`.
+ */
+ function createQueryElement(query, parserState, name, generics, isInGenerics) {
+ if (name === '*' || (name.length === 0 && generics.length === 0)) {
+ return;
+ }
+ if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
+ throw new Error("You cannot have more than one element if you use quotes");
+ }
+ var pathSegments = name.split("::");
+ if (pathSegments.length > 1) {
+ for (var i = 0, len = pathSegments.length; i < len; ++i) {
+ var pathSegment = pathSegments[i];
+
+ if (pathSegment.length === 0) {
+ if (i === 0) {
+ throw new Error("Paths cannot start with `::`");
+ } else if (i + 1 === len) {
+ throw new Error("Paths cannot end with `::`");
+ }
+ throw new Error("Unexpected `::::`");
+ }
+ }
+ }
+ // In case we only have something like `<p>`, there is no name.
+ if (pathSegments.length === 0 || (pathSegments.length === 1 && pathSegments[0] === "")) {
+ throw new Error("Found generics without a path");
+ }
+ parserState.totalElems += 1;
+ if (isInGenerics) {
+ parserState.genericsElems += 1;
+ }
+ return {
+ name: name,
+ fullPath: pathSegments,
+ pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1),
+ pathLast: pathSegments[pathSegments.length - 1],
+ generics: generics,
+ };
+ }
+
+ /**
+ * This function goes through all characters until it reaches an invalid ident character or the
+ * end of the query. It returns the position of the last character of the ident.
+ *
+ * @param {ParserState} parserState
+ *
+ * @return {integer}
+ */
+ function getIdentEndPosition(parserState) {
+ var end = parserState.pos;
+ while (parserState.pos < parserState.length) {
+ var c = parserState.userQuery[parserState.pos];
+ if (!isIdentCharacter(c)) {
+ if (isErrorCharacter(c)) {
+ throw new Error(`Unexpected \`${c}\``);
+ } else if (
+ isStopCharacter(c) ||
+ isSpecialStartCharacter(c) ||
+ isSeparatorCharacter(c))
+ {
+ break;
+ }
+ // If we allow paths ("str::string" for example).
+ else if (c === ":") {
+ if (!isPathStart(parserState)) {
+ break;
+ }
+ // Skip current ":".
+ parserState.pos += 1;
+ } else {
+ throw new Error(`Unexpected \`${c}\``);
+ }
+ }
+ parserState.pos += 1;
+ end = parserState.pos;
+ }
+ return end;
+ }
+
+ /**
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+ * @param {boolean} isInGenerics
+ */
+ function getNextElem(query, parserState, elems, isInGenerics) {
+ var generics = [];
+
+ var start = parserState.pos;
+ var end;
+ // We handle the strings on their own mostly to make code easier to follow.
+ if (parserState.userQuery[parserState.pos] === "\"") {
+ start += 1;
+ getStringElem(query, parserState, isInGenerics);
+ end = parserState.pos - 1;
+ } else {
+ end = getIdentEndPosition(parserState);
+ }
+ if (parserState.pos < parserState.length &&
+ parserState.userQuery[parserState.pos] === "<")
+ {
+ if (isInGenerics) {
+ throw new Error("Unexpected `<` after `<`");
+ } else if (start >= end) {
+ throw new Error("Found generics without a path");
+ }
+ parserState.pos += 1;
+ getItemsBefore(query, parserState, generics, ">");
+ }
+ if (start >= end && generics.length === 0) {
+ return;
+ }
+ elems.push(
+ createQueryElement(
+ query,
+ parserState,
+ parserState.userQuery.slice(start, end),
+ generics,
+ isInGenerics
+ )
+ );
+ }
+
+ /**
+ * This function parses the next query element until it finds `endChar`, calling `getNextElem`
+ * to collect each element.
+ *
+ * If there is no `endChar`, this function will implicitly stop at the end without raising an
+ * error.
+ *
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+ * @param {string} endChar - This function will stop when it'll encounter this
+ * character.
+ */
+ function getItemsBefore(query, parserState, elems, endChar) {
+ var foundStopChar = true;
+
+ while (parserState.pos < parserState.length) {
+ var c = parserState.userQuery[parserState.pos];
+ if (c === endChar) {
+ break;
+ } else if (isSeparatorCharacter(c)) {
+ parserState.pos += 1;
+ foundStopChar = true;
+ continue;
+ } else if (c === ":" && isPathStart(parserState)) {
+ throw new Error("Unexpected `::`: paths cannot start with `::`");
+ } else if (c === ":" || isEndCharacter(c)) {
+ var extra = "";
+ if (endChar === ">") {
+ extra = "`<`";
+ } else if (endChar === "") {
+ extra = "`->`";
+ }
+ throw new Error("Unexpected `" + c + "` after " + extra);
+ }
+ if (!foundStopChar) {
+ if (endChar !== "") {
+ throw new Error(`Expected \`,\`, \` \` or \`${endChar}\`, found \`${c}\``);
+ }
+ throw new Error(`Expected \`,\` or \` \`, found \`${c}\``);
+ }
+ var posBefore = parserState.pos;
+ getNextElem(query, parserState, elems, endChar === ">");
+ // This case can be encountered if `getNextElem` encounted a "stop character" right from
+ // the start. For example if you have `,,` or `<>`. In this case, we simply move up the
+ // current position to continue the parsing.
+ if (posBefore === parserState.pos) {
+ parserState.pos += 1;
+ }
+ foundStopChar = false;
+ }
+ // We are either at the end of the string or on the `endChar`` character, let's move forward
+ // in any case.
+ parserState.pos += 1;
+ }
+
+ /**
+ * Checks that the type filter doesn't have unwanted characters like `<>` (which are ignored
+ * if empty).
+ *
+ * @param {ParserState} parserState
+ */
+ function checkExtraTypeFilterCharacters(parserState) {
+ var query = parserState.userQuery;
+
+ for (var pos = 0; pos < parserState.pos; ++pos) {
+ if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) {
+ throw new Error(`Unexpected \`${query[pos]}\` in type filter`);
+ }
+ }
+ }
+
+ /**
+ * Parses the provided `query` input to fill `parserState`. If it encounters an error while
+ * parsing `query`, it'll throw an error.
+ *
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ */
+ function parseInput(query, parserState) {
+ var c, before;
+ var foundStopChar = true;
+
+ while (parserState.pos < parserState.length) {
+ c = parserState.userQuery[parserState.pos];
+ if (isStopCharacter(c)) {
+ foundStopChar = true;
+ if (isSeparatorCharacter(c)) {
+ parserState.pos += 1;
+ continue;
+ } else if (c === "-" || c === ">") {
+ if (isReturnArrow(parserState)) {
+ break;
+ }
+ throw new Error(`Unexpected \`${c}\` (did you mean \`->\`?)`);
+ }
+ throw new Error(`Unexpected \`${c}\``);
+ } else if (c === ":" && !isPathStart(parserState)) {
+ if (parserState.typeFilter !== null) {
+ throw new Error("Unexpected `:`");
+ }
+ if (query.elems.length === 0) {
+ throw new Error("Expected type filter before `:`");
+ } else if (query.elems.length !== 1 || parserState.totalElems !== 1) {
+ throw new Error("Unexpected `:`");
+ } else if (query.literalSearch) {
+ throw new Error("You cannot use quotes on type filter");
+ }
+ checkExtraTypeFilterCharacters(parserState);
+ // The type filter doesn't count as an element since it's a modifier.
+ parserState.typeFilter = query.elems.pop().name;
+ parserState.pos += 1;
+ parserState.totalElems = 0;
+ query.literalSearch = false;
+ foundStopChar = true;
+ continue;
+ }
+ if (!foundStopChar) {
+ if (parserState.typeFilter !== null) {
+ throw new Error(`Expected \`,\`, \` \` or \`->\`, found \`${c}\``);
+ }
+ throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``);
+ }
+ before = query.elems.length;
+ getNextElem(query, parserState, query.elems, false);
+ if (query.elems.length === before) {
+ // Nothing was added, weird... Let's increase the position to not remain stuck.
+ parserState.pos += 1;
+ }
+ foundStopChar = false;
+ }
+ while (parserState.pos < parserState.length) {
+ c = parserState.userQuery[parserState.pos];
+ if (isReturnArrow(parserState)) {
+ parserState.pos += 2;
+ // Get returned elements.
+ getItemsBefore(query, parserState, query.returned, "");
+ // Nothing can come afterward!
+ if (query.returned.length === 0) {
+ throw new Error("Expected at least one item after `->`");
+ }
+ break;
+ } else {
+ parserState.pos += 1;
+ }
+ }
+ }
+
+ /**
+ * Takes the user search input and returns an empty `ParsedQuery`.
+ *
+ * @param {string} userQuery
+ *
+ * @return {ParsedQuery}
+ */
+ function newParsedQuery(userQuery) {
+ return {
+ original: userQuery,
+ userQuery: userQuery.toLowerCase(),
+ typeFilter: NO_TYPE_FILTER,
+ elems: [],
+ returned: [],
+ // Total number of "top" elements (does not include generics).
+ foundElems: 0,
+ literalSearch: false,
+ error: null,
+ };
+ }
+
/**
* Build an URL with search parameters.
*
* @param {string} search - The current search being performed.
* @param {string|null} filterCrates - The current filtering crate (if any).
+ *
* @return {string}
*/
function buildUrl(search, filterCrates) {
}
/**
- * Executes the query and returns a list of results for each results tab.
- * @param {Object} query - The user query
- * @param {Array<string>} searchWords - The list of search words to query against
- * @param {string} [filterCrates] - Crate to search in
- * @return {{
- * in_args: Array<?>,
- * returned: Array<?>,
- * others: Array<?>
- * }}
+ * Parses the query.
+ *
+ * The supported syntax by this parser is as follow:
+ *
+ * ident = *(ALPHA / DIGIT / "_")
+ * path = ident *(DOUBLE-COLON ident)
+ * arg = path [generics]
+ * arg-without-generic = path
+ * type-sep = COMMA/WS *(COMMA/WS)
+ * nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
+ * nonempty-arg-list-without-generics = *(type-sep) arg-without-generic
+ * *(type-sep arg-without-generic) *(type-sep)
+ * generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list-without-generics ] *(type-sep)
+ * CLOSE-ANGLE-BRACKET/EOF
+ * return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
+ *
+ * exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
+ * type-search = [type-filter *WS COLON] [ nonempty-arg-list ] [ return-args ]
+ *
+ * query = *WS (exact-search / type-search) *WS
+ *
+ * type-filter = (
+ * "mod" /
+ * "externcrate" /
+ * "import" /
+ * "struct" /
+ * "enum" /
+ * "fn" /
+ * "type" /
+ * "static" /
+ * "trait" /
+ * "impl" /
+ * "tymethod" /
+ * "method" /
+ * "structfield" /
+ * "variant" /
+ * "macro" /
+ * "primitive" /
+ * "associatedtype" /
+ * "constant" /
+ * "associatedconstant" /
+ * "union" /
+ * "foreigntype" /
+ * "keyword" /
+ * "existential" /
+ * "attr" /
+ * "derive" /
+ * "traitalias")
+ *
+ * OPEN-ANGLE-BRACKET = "<"
+ * CLOSE-ANGLE-BRACKET = ">"
+ * COLON = ":"
+ * DOUBLE-COLON = "::"
+ * QUOTE = %x22
+ * COMMA = ","
+ * RETURN-ARROW = "->"
+ *
+ * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+ * DIGIT = %x30-39
+ * WS = %x09 / " "
+ *
+ * @param {string} val - The user query
+ *
+ * @return {ParsedQuery} - The parsed query
*/
- function execQuery(query, searchWords, filterCrates) {
- function itemTypeFromName(typename) {
- for (var i = 0, len = itemTypes.length; i < len; ++i) {
- if (itemTypes[i] === typename) {
- return i;
+ function parseQuery(userQuery) {
+ userQuery = userQuery.trim();
+ var parserState = {
+ length: userQuery.length,
+ pos: 0,
+ // Total number of elements (includes generics).
+ totalElems: 0,
+ genericsElems: 0,
+ typeFilter: null,
+ userQuery: userQuery.toLowerCase(),
+ };
+ var query = newParsedQuery(userQuery);
+
+ try {
+ parseInput(query, parserState);
+ if (parserState.typeFilter !== null) {
+ var typeFilter = parserState.typeFilter;
+ if (typeFilter === "const") {
+ typeFilter = "constant";
}
+ query.typeFilter = itemTypeFromName(typeFilter);
}
- return NO_TYPE_FILTER;
+ } catch (err) {
+ query = newParsedQuery(userQuery);
+ query.error = err.message;
+ query.typeFilter = -1;
+ return query;
}
- var valLower = query.query.toLowerCase(),
- val = valLower,
- typeFilter = itemTypeFromName(query.type),
- results = {}, results_in_args = {}, results_returned = {},
- split = valLower.split("::");
+ if (!query.literalSearch) {
+ // If there is more than one element in the query, we switch to literalSearch in any
+ // case.
+ query.literalSearch = parserState.totalElems > 1;
+ }
+ query.foundElems = query.elems.length + query.returned.length;
+ return query;
+ }
- removeEmptyStringsFromArray(split);
+ /**
+ * Creates the query results.
+ *
+ * @param {Array<Result>} results_in_args
+ * @param {Array<Result>} results_returned
+ * @param {Array<Result>} results_in_args
+ * @param {ParsedQuery} parsedQuery
+ *
+ * @return {ResultsTable}
+ */
+ function createQueryResults(results_in_args, results_returned, results_others, parsedQuery) {
+ return {
+ "in_args": results_in_args,
+ "returned": results_returned,
+ "others": results_others,
+ "query": parsedQuery,
+ };
+ }
+
+ /**
+ * Executes the parsed query and builds a {ResultsTable}.
+ *
+ * @param {ParsedQuery} parsedQuery - The parsed user query
+ * @param {Object} searchWords - The list of search words to query against
+ * @param {Object} [filterCrates] - Crate to search in if defined
+ *
+ * @return {ResultsTable}
+ */
+ function execQuery(parsedQuery, searchWords, filterCrates) {
+ var results_others = {}, results_in_args = {}, results_returned = {};
function transformResults(results) {
var duplicates = {};
}
function sortResults(results, isType) {
+ var userQuery = parsedQuery.userQuery;
var ar = [];
for (var entry in results) {
if (hasOwnPropertyRustdoc(results, entry)) {
var a, b;
// sort by exact match with regard to the last word (mismatch goes later)
- a = (aaa.word !== val);
- b = (bbb.word !== val);
+ a = (aaa.word !== userQuery);
+ b = (bbb.word !== userQuery);
if (a !== b) { return a - b; }
// Sort by non levenshtein results and then levenshtein results by the distance
return 0;
});
+ var nameSplit = null;
+ if (parsedQuery.elems.length === 1) {
+ var hasPath = typeof parsedQuery.elems[0].path === "undefined";
+ nameSplit = hasPath ? null : parsedQuery.elems[0].path;
+ }
+
for (var i = 0, len = results.length; i < len; ++i) {
result = results[i];
path = result.item.path.toLowerCase(),
parent = result.item.parent;
- if (!isType && !validateResult(name, path, split, parent)) {
+ if (!isType && !validateResult(name, path, nameSplit, parent)) {
result.id = -1;
}
}
return transformResults(results);
}
- function extractGenerics(val) {
- val = val.toLowerCase();
- if (val.indexOf("<") !== -1) {
- var values = val.substring(val.indexOf("<") + 1, val.lastIndexOf(">"));
- return {
- name: val.substring(0, val.indexOf("<")),
- generics: values.split(/\s*,\s*/),
- };
+ /**
+ * This function checks if the object (`row`) generics match the given type (`elem`)
+ * generics. If there are no generics on `row`, `defaultLev` is returned.
+ *
+ * @param {Row} row - The object to check.
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {integer} defaultLev - This is the value to return in case there are no generics.
+ *
+ * @return {integer} - Returns the best match (if any) or `MAX_LEV_DISTANCE + 1`.
+ */
+ function checkGenerics(row, elem, defaultLev) {
+ if (row.length <= GENERICS_DATA || row[GENERICS_DATA].length === 0) {
+ return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
+ } else if (row[GENERICS_DATA].length > 0 && row[GENERICS_DATA][0][NAME] === "") {
+ if (row.length > GENERICS_DATA) {
+ return checkGenerics(row[GENERICS_DATA][0], elem, defaultLev);
+ }
+ return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
}
- return {
- name: val,
- generics: [],
- };
- }
-
- function checkGenerics(obj, val) {
// The names match, but we need to be sure that all generics kinda
// match as well.
- var tmp_lev, elem_name;
- if (val.generics.length > 0) {
- if (obj.length > GENERICS_DATA &&
- obj[GENERICS_DATA].length >= val.generics.length) {
- var elems = Object.create(null);
- var elength = obj[GENERICS_DATA].length;
- for (var x = 0; x < elength; ++x) {
- if (!elems[obj[GENERICS_DATA][x][NAME]]) {
- elems[obj[GENERICS_DATA][x][NAME]] = 0;
+ var elem_name;
+ if (elem.generics.length > 0 && row[GENERICS_DATA].length >= elem.generics.length) {
+ var elems = Object.create(null);
+ for (var x = 0, length = row[GENERICS_DATA].length; x < length; ++x) {
+ elem_name = row[GENERICS_DATA][x][NAME];
+ if (elem_name === "") {
+ // Pure generic, needs to check into it.
+ if (checkGenerics(
+ row[GENERICS_DATA][x], elem, MAX_LEV_DISTANCE + 1) !== 0) {
+ return MAX_LEV_DISTANCE + 1;
}
- elems[obj[GENERICS_DATA][x][NAME]] += 1;
+ continue;
+ }
+ if (elems[elem_name] === undefined) {
+ elems[elem_name] = 0;
}
- var total = 0;
- var done = 0;
- // We need to find the type that matches the most to remove it in order
- // to move forward.
- var vlength = val.generics.length;
- for (x = 0; x < vlength; ++x) {
- var lev = MAX_LEV_DISTANCE + 1;
- var firstGeneric = val.generics[x];
- var match = null;
- if (elems[firstGeneric]) {
- match = firstGeneric;
- lev = 0;
- } else {
- for (elem_name in elems) {
- tmp_lev = levenshtein(elem_name, firstGeneric);
- if (tmp_lev < lev) {
- lev = tmp_lev;
- match = elem_name;
- }
+ elems[elem_name] += 1;
+ }
+ // We need to find the type that matches the most to remove it in order
+ // to move forward.
+ for (x = 0, length = elem.generics.length; x < length; ++x) {
+ var generic = elem.generics[x];
+ var match = null;
+ if (elems[generic.name]) {
+ match = generic.name;
+ } else {
+ for (elem_name in elems) {
+ if (!hasOwnPropertyRustdoc(elems, elem_name)) {
+ continue;
}
- }
- if (match !== null) {
- elems[match] -= 1;
- if (elems[match] == 0) {
- delete elems[match];
+ if (elem_name === generic) {
+ match = elem_name;
+ break;
}
- total += lev;
- done += 1;
- } else {
- return MAX_LEV_DISTANCE + 1;
}
}
- return Math.ceil(total / done);
+ if (match === null) {
+ return MAX_LEV_DISTANCE + 1;
+ }
+ elems[match] -= 1;
+ if (elems[match] === 0) {
+ delete elems[match];
+ }
}
+ return 0;
}
return MAX_LEV_DISTANCE + 1;
}
/**
- * This function checks if the object (`obj`) matches the given type (`val`) and its
+ * This function checks if the object (`row`) matches the given type (`elem`) and its
+ * generics (if any).
+ *
+ * @param {Row} row
+ * @param {QueryElement} elem - The element from the parsed query.
+ *
+ * @return {integer} - Returns a Levenshtein distance to the best match.
+ */
+ function checkIfInGenerics(row, elem) {
+ var lev = MAX_LEV_DISTANCE + 1;
+ for (var x = 0, length = row[GENERICS_DATA].length; x < length && lev !== 0; ++x) {
+ lev = Math.min(
+ checkType(row[GENERICS_DATA][x], elem, true),
+ lev
+ );
+ }
+ return lev;
+ }
+
+ /**
+ * This function checks if the object (`row`) matches the given type (`elem`) and its
* generics (if any).
*
- * @param {Object} obj
- * @param {string} val
+ * @param {Row} row
+ * @param {QueryElement} elem - The element from the parsed query.
* @param {boolean} literalSearch
*
* @return {integer} - Returns a Levenshtein distance to the best match. If there is
* no match, returns `MAX_LEV_DISTANCE + 1`.
*/
- function checkType(obj, val, literalSearch) {
- var lev_distance = MAX_LEV_DISTANCE + 1;
- var tmp_lev = MAX_LEV_DISTANCE + 1;
- var len, x, firstGeneric;
- if (obj[NAME] === val.name) {
- if (literalSearch) {
- if (val.generics && val.generics.length !== 0) {
- if (obj.length > GENERICS_DATA &&
- obj[GENERICS_DATA].length > 0) {
- var elems = Object.create(null);
- len = obj[GENERICS_DATA].length;
- for (x = 0; x < len; ++x) {
- if (!elems[obj[GENERICS_DATA][x][NAME]]) {
- elems[obj[GENERICS_DATA][x][NAME]] = 0;
- }
- elems[obj[GENERICS_DATA][x][NAME]] += 1;
- }
+ function checkType(row, elem, literalSearch) {
+ if (row[NAME].length === 0) {
+ // This is a pure "generic" search, no need to run other checks.
+ if (row.length > GENERICS_DATA) {
+ return checkIfInGenerics(row, elem);
+ }
+ return MAX_LEV_DISTANCE + 1;
+ }
- len = val.generics.length;
- for (x = 0; x < len; ++x) {
- firstGeneric = val.generics[x];
- if (elems[firstGeneric]) {
- elems[firstGeneric] -= 1;
- } else {
- // Something wasn't found and this is a literal search so
- // abort and return a "failing" distance.
- return MAX_LEV_DISTANCE + 1;
- }
- }
- // Everything was found, success!
+ var lev = levenshtein(row[NAME], elem.name);
+ if (literalSearch) {
+ if (lev !== 0) {
+ // The name didn't match, let's try to check if the generics do.
+ if (elem.generics.length === 0) {
+ var checkGeneric = (row.length > GENERICS_DATA &&
+ row[GENERICS_DATA].length > 0);
+ if (checkGeneric && row[GENERICS_DATA].findIndex(function(tmp_elem) {
+ return tmp_elem[NAME] === elem.name;
+ }) !== -1) {
return 0;
}
- return MAX_LEV_DISTANCE + 1;
}
- return 0;
- } else {
- // If the type has generics but don't match, then it won't return at this point.
- // Otherwise, `checkGenerics` will return 0 and it'll return.
- if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
- tmp_lev = checkGenerics(obj, val);
- if (tmp_lev <= MAX_LEV_DISTANCE) {
- return tmp_lev;
- }
- }
- }
- } else if (literalSearch) {
- var found = false;
- if ((!val.generics || val.generics.length === 0) &&
- obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
- found = obj[GENERICS_DATA].some(
- function(gen) {
- return gen[NAME] === val.name;
- });
- }
- return found ? 0 : MAX_LEV_DISTANCE + 1;
- }
- lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance);
- if (lev_distance <= MAX_LEV_DISTANCE) {
- // The generics didn't match but the name kinda did so we give it
- // a levenshtein distance value that isn't *this* good so it goes
- // into the search results but not too high.
- lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
- }
- if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
- // We can check if the type we're looking for is inside the generics!
- var olength = obj[GENERICS_DATA].length;
- for (x = 0; x < olength; ++x) {
- tmp_lev = Math.min(levenshtein(obj[GENERICS_DATA][x][NAME], val.name), tmp_lev);
+ return MAX_LEV_DISTANCE + 1;
+ } else if (elem.generics.length > 0) {
+ return checkGenerics(row, elem, MAX_LEV_DISTANCE + 1);
}
- if (tmp_lev !== 0) {
- // If we didn't find a good enough result, we go check inside the generics of
- // the generics.
- for (x = 0; x < olength && tmp_lev !== 0; ++x) {
- tmp_lev = Math.min(
- checkType(obj[GENERICS_DATA][x], val, literalSearch),
- tmp_lev
- );
+ return 0;
+ } else if (row.length > GENERICS_DATA) {
+ if (elem.generics.length === 0) {
+ if (lev === 0) {
+ return 0;
+ }
+ // The name didn't match so we now check if the type we're looking for is inside
+ // the generics!
+ lev = checkIfInGenerics(row, elem);
+ // Now whatever happens, the returned distance is "less good" so we should mark
+ // it as such, and so we add 0.5 to the distance to make it "less good".
+ return lev + 0.5;
+ } else if (lev > MAX_LEV_DISTANCE) {
+ // So our item's name doesn't match at all and has generics.
+ //
+ // Maybe it's present in a sub generic? For example "f<A<B<C>>>()", if we're
+ // looking for "B<C>", we'll need to go down.
+ return checkIfInGenerics(row, elem);
+ } else {
+ // At this point, the name kinda match and we have generics to check, so
+ // let's go!
+ var tmp_lev = checkGenerics(row, elem, lev);
+ if (tmp_lev > MAX_LEV_DISTANCE) {
+ return MAX_LEV_DISTANCE + 1;
}
+ // We compute the median value of both checks and return it.
+ return (tmp_lev + lev) / 2;
}
+ } else if (elem.generics.length > 0) {
+ // In this case, we were expecting generics but there isn't so we simply reject this
+ // one.
+ return MAX_LEV_DISTANCE + 1;
}
- // Now whatever happens, the returned distance is "less good" so we should mark it
- // as such, and so we add 1 to the distance to make it "less good".
- return Math.min(lev_distance, tmp_lev) + 1;
+ // No generics on our query or on the target type so we can return without doing
+ // anything else.
+ return lev;
}
/**
- * This function checks if the object (`obj`) has an argument with the given type (`val`).
+ * This function checks if the object (`row`) has an argument with the given type (`elem`).
*
- * @param {Object} obj
- * @param {string} val
- * @param {boolean} literalSearch
+ * @param {Row} row
+ * @param {QueryElement} elem - The element from the parsed query.
* @param {integer} typeFilter
*
* @return {integer} - Returns a Levenshtein distance to the best match. If there is no
* match, returns `MAX_LEV_DISTANCE + 1`.
*/
- function findArg(obj, val, literalSearch, typeFilter) {
- var lev_distance = MAX_LEV_DISTANCE + 1;
+ function findArg(row, elem, typeFilter) {
+ var lev = MAX_LEV_DISTANCE + 1;
- if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
- var length = obj.type[INPUTS_DATA].length;
+ if (row && row.type && row.type[INPUTS_DATA] && row.type[INPUTS_DATA].length > 0) {
+ var length = row.type[INPUTS_DATA].length;
for (var i = 0; i < length; i++) {
- var tmp = obj.type[INPUTS_DATA][i];
+ var tmp = row.type[INPUTS_DATA][i];
if (!typePassesFilter(typeFilter, tmp[1])) {
continue;
}
- tmp = checkType(tmp, val, literalSearch);
- if (tmp === 0) {
+ lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
+ if (lev === 0) {
return 0;
- } else if (literalSearch) {
- continue;
}
- lev_distance = Math.min(tmp, lev_distance);
}
}
- return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
+ return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
}
- function checkReturned(obj, val, literalSearch, typeFilter) {
- var lev_distance = MAX_LEV_DISTANCE + 1;
+ /**
+ * This function checks if the object (`row`) returns the given type (`elem`).
+ *
+ * @param {Row} row
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {integer} typeFilter
+ *
+ * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
+ * match, returns `MAX_LEV_DISTANCE + 1`.
+ */
+ function checkReturned(row, elem, typeFilter) {
+ var lev = MAX_LEV_DISTANCE + 1;
- if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
- var ret = obj.type[OUTPUT_DATA];
+ if (row && row.type && row.type.length > OUTPUT_DATA) {
+ var ret = row.type[OUTPUT_DATA];
if (typeof ret[0] === "string") {
ret = [ret];
}
if (!typePassesFilter(typeFilter, tmp[1])) {
continue;
}
- tmp = checkType(tmp, val, literalSearch);
- if (tmp === 0) {
+ lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
+ if (lev === 0) {
return 0;
- } else if (literalSearch) {
- continue;
}
- lev_distance = Math.min(tmp, lev_distance);
}
}
- return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
+ return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
}
function checkPath(contains, lastElem, ty) {
}
function handleAliases(ret, query, filterCrates) {
+ var lowerQuery = query.toLowerCase();
// We separate aliases and crate aliases because we want to have current crate
// aliases to be before the others in the displayed results.
var aliases = [];
var crateAliases = [];
if (filterCrates !== null) {
- if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
- var query_aliases = ALIASES[filterCrates][query.search];
+ if (ALIASES[filterCrates] && ALIASES[filterCrates][lowerQuery]) {
+ var query_aliases = ALIASES[filterCrates][lowerQuery];
var len = query_aliases.length;
for (var i = 0; i < len; ++i) {
aliases.push(createAliasFromItem(searchIndex[query_aliases[i]]));
}
} else {
Object.keys(ALIASES).forEach(function(crate) {
- if (ALIASES[crate][query.search]) {
+ if (ALIASES[crate][lowerQuery]) {
var pushTo = crate === window.currentCrate ? crateAliases : aliases;
- var query_aliases = ALIASES[crate][query.search];
+ var query_aliases = ALIASES[crate][lowerQuery];
var len = query_aliases.length;
for (var i = 0; i < len; ++i) {
pushTo.push(createAliasFromItem(searchIndex[query_aliases[i]]));
aliases.sort(sortFunc);
var pushFunc = function(alias) {
- alias.alias = query.raw;
+ alias.alias = query;
var res = buildHrefAndPath(alias);
alias.displayPath = pathSplitter(res[0]);
alias.fullPath = alias.displayPath + alias.name;
}
/**
- * This function adds the given result into the provided `res` map if it matches the
+ * This function adds the given result into the provided `results` map if it matches the
* following condition:
*
- * * If it is a "literal search" (`isExact`), then `lev` must be 0.
+ * * If it is a "literal search" (`parsedQuery.literalSearch`), then `lev` must be 0.
* * If it is not a "literal search", `lev` must be <= `MAX_LEV_DISTANCE`.
*
- * The `res` map contains information which will be used to sort the search results:
+ * The `results` map contains information which will be used to sort the search results:
*
- * * `fullId` is a `string`` used as the key of the object we use for the `res` map.
+ * * `fullId` is a `string`` used as the key of the object we use for the `results` map.
* * `id` is the index in both `searchWords` and `searchIndex` arrays for this element.
* * `index` is an `integer`` used to sort by the position of the word in the item's name.
* * `lev` is the main metric used to sort the search results.
*
- * @param {boolean} isExact
- * @param {Object} res
+ * @param {Results} results
* @param {string} fullId
* @param {integer} id
* @param {integer} index
* @param {integer} lev
*/
- function addIntoResults(isExact, res, fullId, id, index, lev) {
- if (lev === 0 || (!isExact && lev <= MAX_LEV_DISTANCE)) {
- if (res[fullId] !== undefined) {
- var result = res[fullId];
+ function addIntoResults(results, fullId, id, index, lev) {
+ if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) {
+ if (results[fullId] !== undefined) {
+ var result = results[fullId];
if (result.dontValidate || result.lev <= lev) {
return;
}
}
- res[fullId] = {
+ results[fullId] = {
id: id,
index: index,
- dontValidate: isExact,
+ dontValidate: parsedQuery.literalSearch,
lev: lev,
};
}
}
- // quoted values mean literal search
- var nSearchWords = searchWords.length;
- var i, it;
- var ty;
- var fullId;
- var returned;
- var in_args;
- var len;
- if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
- val.charAt(val.length - 1) === val.charAt(0))
- {
- val = extractGenerics(val.substr(1, val.length - 2));
- for (i = 0; i < nSearchWords; ++i) {
- if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
- continue;
+ /**
+ * This function is called in case the query is only one element (with or without generics).
+ * This element will be compared to arguments' and returned values' items and also to items.
+ *
+ * Other important thing to note: since there is only one element, we use levenshtein
+ * distance for name comparisons.
+ *
+ * @param {Row} row
+ * @param {integer} pos - Position in the `searchIndex`.
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {Results} results_others - Unqualified results (not in arguments nor in
+ * returned values).
+ * @param {Results} results_in_args - Matching arguments results.
+ * @param {Results} results_returned - Matching returned arguments results.
+ */
+ function handleSingleArg(
+ row,
+ pos,
+ elem,
+ results_others,
+ results_in_args,
+ results_returned
+ ) {
+ if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
+ return;
+ }
+ var lev, lev_add = 0, index = -1;
+ var fullId = row.id;
+
+ var in_args = findArg(row, elem, parsedQuery.typeFilter);
+ var returned = checkReturned(row, elem, parsedQuery.typeFilter);
+
+ addIntoResults(results_in_args, fullId, pos, index, in_args);
+ addIntoResults(results_returned, fullId, pos, index, returned);
+
+ if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
+ return;
+ }
+ var searchWord = searchWords[pos];
+
+ if (parsedQuery.literalSearch) {
+ if (searchWord === elem.name) {
+ addIntoResults(results_others, fullId, pos, -1, 0);
}
- in_args = findArg(searchIndex[i], val, true, typeFilter);
- returned = checkReturned(searchIndex[i], val, true, typeFilter);
- ty = searchIndex[i];
- fullId = ty.id;
-
- if (searchWords[i] === val.name
- && typePassesFilter(typeFilter, searchIndex[i].ty)) {
- addIntoResults(true, results, fullId, i, -1, 0);
+ return;
+ }
+
+ // No need to check anything else if it's a "pure" generics search.
+ if (elem.name.length === 0) {
+ if (row.type !== null) {
+ lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1);
+ addIntoResults(results_others, fullId, pos, index, lev);
}
- addIntoResults(true, results_in_args, fullId, i, -1, in_args);
- addIntoResults(true, results_returned, fullId, i, -1, returned);
- }
- query.inputs = [val];
- query.output = val;
- query.search = val;
- // searching by type
- } else if (val.search("->") > -1) {
- var trimmer = function(s) { return s.trim(); };
- var parts = val.split("->").map(trimmer);
- var input = parts[0];
- // sort inputs so that order does not matter
- var inputs = input.split(",").map(trimmer).sort();
- for (i = 0, len = inputs.length; i < len; ++i) {
- inputs[i] = extractGenerics(inputs[i]);
- }
- var output = extractGenerics(parts[1]);
-
- for (i = 0; i < nSearchWords; ++i) {
- if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
- continue;
+ return;
+ }
+
+ if (elem.fullPath.length > 1) {
+ lev = checkPath(elem.pathWithoutLast, elem.pathLast, row);
+ if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
+ return;
+ } else if (lev > 0) {
+ lev_add = lev / 10;
}
- var type = searchIndex[i].type;
- ty = searchIndex[i];
- if (!type) {
- continue;
+ }
+
+ if (searchWord.indexOf(elem.pathLast) > -1 ||
+ row.normalizedName.indexOf(elem.pathLast) > -1)
+ {
+ // filter type: ... queries
+ if (!results_others[fullId] !== undefined) {
+ index = row.normalizedName.indexOf(elem.pathLast);
}
- fullId = ty.id;
+ }
+ lev = levenshtein(searchWord, elem.pathLast);
+ lev += lev_add;
+ if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1)
+ {
+ if (elem.pathLast.length < 6) {
+ lev = 1;
+ } else {
+ lev = 0;
+ }
+ }
+ if (lev > MAX_LEV_DISTANCE) {
+ return;
+ } else if (index !== -1 && elem.fullPath.length < 2) {
+ lev -= 1;
+ }
+ if (lev < 0) {
+ lev = 0;
+ }
+ addIntoResults(results_others, fullId, pos, index, lev);
+ }
- returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
- if (output.name === "*" || returned === 0) {
- in_args = false;
- var is_module = false;
+ /**
+ * This function is called in case the query has more than one element. In this case, it'll
+ * try to match the items which validates all the elements. For `aa -> bb` will look for
+ * functions which have a parameter `aa` and has `bb` in its returned values.
+ *
+ * @param {Row} row
+ * @param {integer} pos - Position in the `searchIndex`.
+ * @param {Object} results
+ */
+ function handleArgs(row, pos, results) {
+ if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
+ return;
+ }
- if (input === "*") {
- is_module = true;
+ var totalLev = 0;
+ var nbLev = 0;
+ var lev;
+
+ // If the result is too "bad", we return false and it ends this search.
+ function checkArgs(elems, callback) {
+ for (var i = 0, len = elems.length; i < len; ++i) {
+ var elem = elems[i];
+ // There is more than one parameter to the query so all checks should be "exact"
+ lev = callback(row, elem, NO_TYPE_FILTER);
+ if (lev <= 1) {
+ nbLev += 1;
+ totalLev += lev;
} else {
- var firstNonZeroDistance = 0;
- for (it = 0, len = inputs.length; it < len; it++) {
- var distance = checkType(type, inputs[it], true);
- if (distance > 0) {
- firstNonZeroDistance = distance;
- break;
- }
- }
- in_args = firstNonZeroDistance;
- }
- addIntoResults(true, results_in_args, fullId, i, -1, in_args);
- addIntoResults(true, results_returned, fullId, i, -1, returned);
- if (is_module) {
- addIntoResults(true, results, fullId, i, -1, 0);
+ return false;
}
}
+ return true;
+ }
+ if (!checkArgs(parsedQuery.elems, findArg)) {
+ return;
+ }
+ if (!checkArgs(parsedQuery.returned, checkReturned)) {
+ return;
}
- query.inputs = inputs.map(function(input) {
- return input.name;
- });
- query.output = output.name;
- } else {
- query.inputs = [val];
- query.output = val;
- query.search = val;
- // gather matching search results up to a certain maximum
- val = val.replace(/_/g, "");
-
- var valGenerics = extractGenerics(val);
-
- var paths = valLower.split("::");
- removeEmptyStringsFromArray(paths);
- val = paths[paths.length - 1];
- var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
-
- var lev, j;
- for (j = 0; j < nSearchWords; ++j) {
- ty = searchIndex[j];
- if (!ty || (filterCrates !== null && ty.crate !== filterCrates)) {
- continue;
- }
- var lev_add = 0;
- if (paths.length > 1) {
- lev = checkPath(contains, paths[paths.length - 1], ty);
- if (lev > MAX_LEV_DISTANCE) {
- continue;
- } else if (lev > 0) {
- lev_add = lev / 10;
- }
- }
- returned = MAX_LEV_DISTANCE + 1;
- in_args = MAX_LEV_DISTANCE + 1;
- var index = -1;
- // we want lev results to go lower than others
- lev = MAX_LEV_DISTANCE + 1;
- fullId = ty.id;
+ if (nbLev === 0) {
+ return;
+ }
+ lev = Math.round(totalLev / nbLev);
+ addIntoResults(results, row.id, pos, 0, lev);
+ }
- if (searchWords[j].indexOf(split[i]) > -1 ||
- searchWords[j].indexOf(val) > -1 ||
- ty.normalizedName.indexOf(val) > -1)
- {
- // filter type: ... queries
- if (typePassesFilter(typeFilter, ty.ty) && results[fullId] === undefined) {
- index = ty.normalizedName.indexOf(val);
+ function innerRunQuery() {
+ var elem, i, nSearchWords, in_returned, row;
+
+ if (parsedQuery.foundElems === 1) {
+ if (parsedQuery.elems.length === 1) {
+ elem = parsedQuery.elems[0];
+ for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+ // It means we want to check for this element everywhere (in names, args and
+ // returned).
+ handleSingleArg(
+ searchIndex[i],
+ i,
+ elem,
+ results_others,
+ results_in_args,
+ results_returned
+ );
}
- }
- if ((lev = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) {
- if (typePassesFilter(typeFilter, ty.ty)) {
- lev += 1;
- } else {
- lev = MAX_LEV_DISTANCE + 1;
+ } else if (parsedQuery.returned.length === 1) {
+ // We received one returned argument to check, so looking into returned values.
+ elem = parsedQuery.returned[0];
+ for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+ row = searchIndex[i];
+ in_returned = checkReturned(row, elem, parsedQuery.typeFilter);
+ addIntoResults(results_returned, row.id, i, -1, in_returned);
}
}
- in_args = findArg(ty, valGenerics, false, typeFilter);
- returned = checkReturned(ty, valGenerics, false, typeFilter);
-
- lev += lev_add;
- if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) {
- if (val.length < 6) {
- lev -= 1;
- } else {
- lev = 0;
- }
+ } else if (parsedQuery.foundElems > 0) {
+ var container = results_others;
+ // In the special case where only a "returned" information is available, we want to
+ // put the information into the "results_returned" dict.
+ if (parsedQuery.returned.length !== 0 && parsedQuery.elems.length === 0) {
+ container = results_returned;
}
- addIntoResults(false, results_in_args, fullId, j, index, in_args);
- addIntoResults(false, results_returned, fullId, j, index, returned);
- if (typePassesFilter(typeFilter, ty.ty) &&
- (index !== -1 || lev <= MAX_LEV_DISTANCE)) {
- if (index !== -1 && paths.length < 2) {
- lev = 0;
- }
- addIntoResults(false, results, fullId, j, index, lev);
+ for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+ handleArgs(searchIndex[i], i, container);
}
}
}
- var ret = {
- "in_args": sortResults(results_in_args, true),
- "returned": sortResults(results_returned, true),
- "others": sortResults(results, false),
- };
- handleAliases(ret, query, filterCrates);
+ if (parsedQuery.error === null) {
+ innerRunQuery();
+ }
+
+ var ret = createQueryResults(
+ sortResults(results_in_args, true),
+ sortResults(results_returned, true),
+ sortResults(results_others, false),
+ parsedQuery);
+ handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates);
+ if (parsedQuery.error !== null && ret.others.length !== 0) {
+ // It means some doc aliases were found so let's "remove" the error!
+ ret.query.error = null;
+ }
return ret;
}
* @param {string} path - The path of the result
* @param {string} keys - The keys to be used (["file", "open"])
* @param {Object} parent - The parent of the result
+ *
* @return {boolean} - Whether the result is valid or not
*/
function validateResult(name, path, keys, parent) {
+ if (!keys || !keys.length) {
+ return true;
+ }
for (var i = 0, len = keys.length; i < len; ++i) {
// each check is for validation so we negate the conditions and invalidate
if (!(
return true;
}
- /**
- * Parse a string into a query object.
- *
- * @param {string} raw - The text that the user typed.
- * @returns {ParsedQuery}
- */
- function getQuery(raw) {
- var matches, type = "", query;
- query = raw;
-
- matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
- if (matches) {
- type = matches[1].replace(/^const$/, "constant");
- query = query.substring(matches[0].length);
- }
-
- return {
- raw: raw,
- query: query,
- type: type,
- id: query + type
- };
- }
-
function nextTab(direction) {
var next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
searchState.focusedByTab[searchState.currentTab] = document.activeElement;
link.appendChild(wrapper);
output.appendChild(link);
});
- } else {
+ } else if (query.error === null) {
output.className = "search-failed" + extraClass;
output.innerHTML = "No results :(<br/>" +
"Try on <a href=\"https://duckduckgo.com/?q=" +
- encodeURIComponent("rust " + query.query) +
+ encodeURIComponent("rust " + query.userQuery) +
"\">DuckDuckGo</a>?<br/><br/>" +
"Or try looking in one of these:<ul><li>The <a " +
"href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
}
+ /**
+ * @param {ResultsTable} results
+ * @param {boolean} go_to_first
+ * @param {string} filterCrates
+ */
function showResults(results, go_to_first, filterCrates) {
var search = searchState.outputElement();
if (go_to_first || (results.others.length === 1
elem.click();
return;
}
- var query = getQuery(searchState.input.value);
+ if (results.query === undefined) {
+ results.query = parseQuery(searchState.input.value);
+ }
- currentResults = query.id;
+ currentResults = results.query.userQuery;
- var ret_others = addTab(results.others, query, true);
- var ret_in_args = addTab(results.in_args, query, false);
- var ret_returned = addTab(results.returned, query, false);
+ var ret_others = addTab(results.others, results.query, true);
+ var ret_in_args = addTab(results.in_args, results.query, false);
+ var ret_returned = addTab(results.returned, results.query, false);
// Navigate to the relevant tab if the current tab is empty, like in case users search
// for "-> String". If they had selected another tab previously, they have to click on
}
crates += `</select>`;
}
- var output = `<div id="search-settings">
- <h1 class="search-results-title">Results for ${escape(query.query)} ` +
- (query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
- crates +
- `</div><div id="titles">` +
+
+ var typeFilter = "";
+ if (results.query.typeFilter !== NO_TYPE_FILTER) {
+ typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
+ }
+
+ var output = `<div id="search-settings">` +
+ `<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
+ `${typeFilter}</h1> in ${crates} </div>`;
+ if (results.query.error !== null) {
+ output += `<h3>Query parser error: "${results.query.error}".</h3>`;
+ }
+ output += `<div id="titles">` +
makeTabHeader(0, "In Names", ret_others[1]) +
makeTabHeader(1, "In Parameters", ret_in_args[1]) +
makeTabHeader(2, "In Return Types", ret_returned[1]) +
printTab(currentTab);
}
- function execSearch(query, searchWords, filterCrates) {
- query = query.raw.trim();
- var results = {
- "in_args": [],
- "returned": [],
- "others": [],
- };
-
- if (query.length !== 0) {
- var tmp = execQuery(getQuery(query), searchWords, filterCrates);
-
- results.in_args.push(tmp.in_args);
- results.returned.push(tmp.returned);
- results.others.push(tmp.others);
- }
- return {
- "in_args": results.in_args[0],
- "returned": results.returned[0],
- "others": results.others[0],
- };
- }
-
/**
* Perform a search based on the current state of the search input element
* and display the results.
*/
function search(e, forced) {
var params = searchState.getQueryStringParams();
- var query = getQuery(searchState.input.value.trim());
+ var query = parseQuery(searchState.input.value.trim());
if (e) {
e.preventDefault();
}
- if (query.query.length === 0) {
- return;
- }
- if (!forced && query.id === currentResults) {
- if (query.query.length > 0) {
+ if (!forced && query.userQuery === currentResults) {
+ if (query.userQuery.length > 0) {
putBackSearch();
}
return;
}
// Update document title to maintain a meaningful browser history
- searchState.title = "Results for " + query.query + " - Rust";
+ searchState.title = "Results for " + query.original + " - Rust";
// Because searching is incremental by character, only the most
// recent search query is added to the browser history.
if (searchState.browserSupportsHistoryApi()) {
- var newURL = buildUrl(query.raw, filterCrates);
-
+ var newURL = buildUrl(query.original, filterCrates);
if (!history.state && !params.search) {
history.pushState(null, "", newURL);
} else {
}
}
- showResults(execSearch(query, searchWords, filterCrates),
- params["go_to_first"], filterCrates);
+ showResults(
+ execQuery(query, searchWords, filterCrates),
+ params.go_to_first,
+ filterCrates);
}
function buildIndex(rawSearchIndex) {
use rustc_ast::ast;
use rustc_hir::{def::CtorKind, def_id::DefId};
use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_span::Pos;
use rustc_target::spec::abi::Abi as RustcAbi;
match v {
Public => Visibility::Public,
Inherited => Visibility::Default,
- Restricted(did) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
+ Restricted(did) if did.is_crate_root() => Visibility::Crate,
Restricted(did) => Visibility::Restricted {
parent: from_item_id(did.into()),
path: self.tcx.def_path(did).to_string_no_crate_verbose(),
let resolver_caches = resolver.borrow_mut().access(|resolver| {
collect_intra_doc_links::early_resolve_intra_doc_links(
resolver,
+ sess,
krate,
externs,
document_private,
//! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md
use pulldown_cmark::LinkType;
+use rustc_ast::util::comments::may_have_doc_links;
use rustc_data_structures::{fx::FxHashMap, intern::Interned, stable_set::FxHashSet};
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir::def::Namespace::*;
}
/// A link failed to resolve.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
enum ResolutionFailure<'a> {
/// This resolved, but with the wrong namespace.
WrongNamespace {
Dummy,
}
-#[derive(Debug)]
+#[derive(Clone, Debug)]
enum MalformedGenerics {
/// This link has unbalanced angle brackets.
///
}
}
+#[derive(Clone, Copy)]
enum AnchorFailure {
/// User error: `[std#x#y]` is not valid
MultipleAnchors,
// Resolver doesn't know about true, false, and types that aren't paths (e.g. `()`).
let result = self
.cx
- .enter_resolver(|resolver| resolver.resolve_rustdoc_path(path_str, ns, module_id))
+ .resolver_caches
+ .doc_link_resolutions
+ .get(&(Symbol::intern(path_str), ns, module_id))
+ .copied()
+ .unwrap_or_else(|| {
+ self.cx.enter_resolver(|resolver| {
+ resolver.resolve_rustdoc_path(path_str, ns, module_id)
+ })
+ })
.and_then(|res| res.try_into().ok())
.or_else(|| resolve_primitive(path_str, ns))
.or_else(|| self.resolve_macro_rules(path_str, ns));
// In the presence of re-exports, this is not the same as the module of the item.
// Rather than merging all documentation into one, resolve it one attribute at a time
// so we know which module it came from.
- for (parent_module, doc) in item.attrs.collapsed_doc_value_by_module_level() {
+ for (parent_module, doc) in item.attrs.prepare_to_doc_link_resolution() {
+ if !may_have_doc_links(&doc) {
+ continue;
+ }
debug!("combined_docs={}", doc);
// NOTE: if there are links that start in one crate and end in another, this will not resolve them.
// This is a degenerate case and it's not supported by rustdoc.
let parent_node = parent_module.or(parent_node);
- for md_link in markdown_links(&doc) {
+ let mut tmp_links = self
+ .cx
+ .resolver_caches
+ .markdown_links
+ .take()
+ .expect("`markdown_links` are already borrowed");
+ if !tmp_links.contains_key(&doc) {
+ tmp_links.insert(doc.clone(), preprocessed_markdown_links(&doc));
+ }
+ for md_link in &tmp_links[&doc] {
let link = self.resolve_link(&item, &doc, parent_node, md_link);
if let Some(link) = link {
self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link);
}
}
+ self.cx.resolver_caches.markdown_links = Some(tmp_links);
}
if item.is_mod() {
}
}
-enum PreprocessingError<'a> {
+enum PreprocessingError {
Anchor(AnchorFailure),
Disambiguator(Range<usize>, String),
- Resolution(ResolutionFailure<'a>, String, Option<Disambiguator>),
+ Resolution(ResolutionFailure<'static>, String, Option<Disambiguator>),
}
-impl From<AnchorFailure> for PreprocessingError<'_> {
+impl From<AnchorFailure> for PreprocessingError {
fn from(err: AnchorFailure) -> Self {
Self::Anchor(err)
}
}
+#[derive(Clone)]
struct PreprocessingInfo {
path_str: String,
disambiguator: Option<Disambiguator>,
link_text: String,
}
+// Not a typedef to avoid leaking several private structures from this module.
+crate struct PreprocessedMarkdownLink(Result<PreprocessingInfo, PreprocessingError>, MarkdownLink);
+
/// Returns:
/// - `None` if the link should be ignored.
/// - `Some(Err)` if the link should emit an error
/// - `Some(Ok)` if the link is valid
///
/// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored.
-fn preprocess_link<'a>(
- ori_link: &'a MarkdownLink,
-) -> Option<Result<PreprocessingInfo, PreprocessingError<'a>>> {
+fn preprocess_link(
+ ori_link: &MarkdownLink,
+) -> Option<Result<PreprocessingInfo, PreprocessingError>> {
// [] is mostly likely not supposed to be a link
if ori_link.link.is_empty() {
return None;
}))
}
+fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> {
+ markdown_links(s, |link| {
+ preprocess_link(&link).map(|pp_link| PreprocessedMarkdownLink(pp_link, link))
+ })
+}
+
impl LinkCollector<'_, '_> {
/// This is the entry point for resolving an intra-doc link.
///
item: &Item,
dox: &str,
parent_node: Option<DefId>,
- ori_link: MarkdownLink,
+ link: &PreprocessedMarkdownLink,
) -> Option<ItemLink> {
+ let PreprocessedMarkdownLink(pp_link, ori_link) = link;
trace!("considering link '{}'", ori_link.link);
let diag_info = DiagnosticInfo {
link_range: ori_link.range.clone(),
};
- let PreprocessingInfo { ref path_str, disambiguator, extra_fragment, link_text } =
- match preprocess_link(&ori_link)? {
- Ok(x) => x,
- Err(err) => {
- match err {
- PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, err),
- PreprocessingError::Disambiguator(range, msg) => {
- disambiguator_error(self.cx, diag_info, range, &msg)
- }
- PreprocessingError::Resolution(err, path_str, disambiguator) => {
- resolution_failure(
- self,
- diag_info,
- &path_str,
- disambiguator,
- smallvec![err],
- );
- }
+ let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } = match pp_link
+ {
+ Ok(x) => x,
+ Err(err) => {
+ match err {
+ PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, *err),
+ PreprocessingError::Disambiguator(range, msg) => {
+ disambiguator_error(self.cx, diag_info, range.clone(), msg)
+ }
+ PreprocessingError::Resolution(err, path_str, disambiguator) => {
+ resolution_failure(
+ self,
+ diag_info,
+ path_str,
+ *disambiguator,
+ smallvec![err.clone()],
+ );
}
- return None;
}
- };
+ return None;
+ }
+ };
+ let disambiguator = *disambiguator;
let inner_docs = item.inner_docs(self.cx.tcx);
module_id,
dis: disambiguator,
path_str: path_str.to_owned(),
- extra_fragment,
+ extra_fragment: extra_fragment.clone(),
},
diag_info.clone(), // this struct should really be Copy, but Range is not :(
matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut),
}
Some(ItemLink {
- link: ori_link.link,
- link_text,
+ link: ori_link.link.clone(),
+ link_text: link_text.clone(),
did: res.def_id(self.cx.tcx),
fragment,
})
&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 })
+ Some(ItemLink {
+ link: ori_link.link.clone(),
+ link_text: link_text.clone(),
+ did: id,
+ fragment,
+ })
}
}
}
use crate::clean::Attributes;
use crate::core::ResolverCaches;
-use crate::html::markdown::markdown_links;
-use crate::passes::collect_intra_doc_links::preprocess_link;
+use crate::passes::collect_intra_doc_links::preprocessed_markdown_links;
+use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{self as ast, ItemKind};
use rustc_ast_lowering::ResolverAstLowering;
-use rustc_hir::def::Namespace::TypeNS;
-use rustc_hir::def::{DefKind, Res};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def::Namespace::*;
+use rustc_hir::def::{DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, CRATE_DEF_ID};
use rustc_hir::TraitCandidate;
use rustc_middle::ty::{DefIdTree, Visibility};
use rustc_resolve::{ParentScope, Resolver};
use rustc_session::config::Externs;
-use rustc_span::SyntaxContext;
+use rustc_session::Session;
+use rustc_span::{Symbol, SyntaxContext};
use std::collections::hash_map::Entry;
use std::mem;
crate fn early_resolve_intra_doc_links(
resolver: &mut Resolver<'_>,
+ sess: &Session,
krate: &ast::Crate,
externs: Externs,
document_private_items: bool,
) -> ResolverCaches {
let mut link_resolver = EarlyDocLinkResolver {
resolver,
+ sess,
current_mod: CRATE_DEF_ID,
visited_mods: Default::default(),
+ markdown_links: Default::default(),
+ doc_link_resolutions: Default::default(),
traits_in_scope: Default::default(),
all_traits: Default::default(),
all_trait_impls: Default::default(),
// Overridden `visit_item` below doesn't apply to the crate root,
// so we have to visit its attributes and reexports separately.
- link_resolver.load_links_in_attrs(&krate.attrs);
+ link_resolver.resolve_doc_links_local(&krate.attrs);
link_resolver.process_module_children_or_reexports(CRATE_DEF_ID.to_def_id());
visit::walk_crate(&mut link_resolver, krate);
link_resolver.process_extern_impls();
}
ResolverCaches {
+ markdown_links: Some(link_resolver.markdown_links),
+ doc_link_resolutions: link_resolver.doc_link_resolutions,
traits_in_scope: link_resolver.traits_in_scope,
all_traits: Some(link_resolver.all_traits),
all_trait_impls: Some(link_resolver.all_trait_impls),
}
}
+fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes {
+ Attributes::from_ast_iter(attrs.map(|attr| (attr, None)), true)
+}
+
struct EarlyDocLinkResolver<'r, 'ra> {
resolver: &'r mut Resolver<'ra>,
+ sess: &'r Session,
current_mod: LocalDefId,
visited_mods: DefIdSet,
+ markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>,
+ doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<ast::NodeId>>>,
traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
all_traits: Vec<DefId>,
all_trait_impls: Vec<DefId>,
}
}
- fn add_traits_in_parent_scope(&mut self, def_id: DefId) {
- if let Some(module_id) = self.resolver.parent(def_id) {
- self.add_traits_in_scope(module_id);
- }
- }
-
/// Add traits in scope for links in impls collected by the `collect-intra-doc-links` pass.
/// That pass filters impls using type-based information, but we don't yet have such
/// information here, so we just conservatively calculate traits in scope for *all* modules
/// having impls in them.
fn process_extern_impls(&mut self) {
- // FIXME: Need to resolve doc links on all these impl and trait items below.
// Resolving links in already existing crates may trigger loading of new crates.
let mut start_cnum = 0;
loop {
// the current crate, and links in their doc comments are not resolved.
for &def_id in &all_traits {
if self.resolver.cstore().visibility_untracked(def_id) == Visibility::Public {
- self.add_traits_in_parent_scope(def_id);
+ self.resolve_doc_links_extern_impl(def_id, false);
}
}
for &(trait_def_id, impl_def_id, simplified_self_ty) in &all_trait_impls {
== Visibility::Public
})
{
- self.add_traits_in_parent_scope(impl_def_id);
+ self.resolve_doc_links_extern_impl(impl_def_id, false);
}
}
for (ty_def_id, impl_def_id) in all_inherent_impls {
if self.resolver.cstore().visibility_untracked(ty_def_id) == Visibility::Public
{
- self.add_traits_in_parent_scope(impl_def_id);
+ self.resolve_doc_links_extern_impl(impl_def_id, true);
}
}
- for def_id in all_incoherent_impls {
- self.add_traits_in_parent_scope(def_id);
+ for impl_def_id in all_incoherent_impls {
+ self.resolve_doc_links_extern_impl(impl_def_id, true);
}
self.all_traits.extend(all_traits);
}
}
- fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute]) {
+ fn resolve_doc_links_extern_impl(&mut self, def_id: DefId, is_inherent: bool) {
+ self.resolve_doc_links_extern_outer(def_id, def_id);
+ let assoc_item_def_ids = Vec::from_iter(
+ self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.sess),
+ );
+ for assoc_def_id in assoc_item_def_ids {
+ if !is_inherent
+ || self.resolver.cstore().visibility_untracked(assoc_def_id) == Visibility::Public
+ {
+ self.resolve_doc_links_extern_outer(assoc_def_id, def_id);
+ }
+ }
+ }
+
+ fn resolve_doc_links_extern_outer(&mut self, def_id: DefId, scope_id: DefId) {
+ if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
+ return;
+ }
+ // FIXME: actually resolve links, not just add traits in scope.
+ if let Some(parent_id) = self.resolver.parent(scope_id) {
+ self.add_traits_in_scope(parent_id);
+ }
+ }
+
+ fn resolve_doc_links_extern_inner(&mut self, def_id: DefId) {
+ if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
+ return;
+ }
+ // FIXME: actually resolve links, not just add traits in scope.
+ self.add_traits_in_scope(def_id);
+ }
+
+ fn resolve_doc_links_local(&mut self, attrs: &[ast::Attribute]) {
+ if !attrs.iter().any(|attr| attr.may_have_doc_links()) {
+ return;
+ }
let module_id = self.current_mod.to_def_id();
+ self.resolve_doc_links(doc_attrs(attrs.iter()), module_id);
+ }
+
+ fn resolve_doc_links(&mut self, attrs: Attributes, module_id: DefId) {
let mut need_traits_in_scope = false;
- for (doc_module, doc) in
- Attributes::from_ast(attrs, None).collapsed_doc_value_by_module_level()
- {
+ for (doc_module, doc) in attrs.prepare_to_doc_link_resolution() {
assert_eq!(doc_module, None);
- for link in markdown_links(&doc.as_str()) {
- if let Some(Ok(pinfo)) = preprocess_link(&link) {
- self.resolver.resolve_rustdoc_path(&pinfo.path_str, TypeNS, module_id);
+ let links = self
+ .markdown_links
+ .entry(doc)
+ .or_insert_with_key(|doc| preprocessed_markdown_links(doc));
+ for PreprocessedMarkdownLink(pp_link, _) in links {
+ if let Ok(pinfo) = pp_link {
+ // FIXME: Resolve the path in all namespaces and resolve its prefixes too.
+ let ns = TypeNS;
+ self.doc_link_resolutions
+ .entry((Symbol::intern(&pinfo.path_str), ns, module_id))
+ .or_insert_with_key(|(path, ns, module_id)| {
+ self.resolver.resolve_rustdoc_path(path.as_str(), *ns, *module_id)
+ });
need_traits_in_scope = true;
}
}
&& module_id.is_local()
{
if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() {
- // FIXME: Need to resolve doc links on all these extern items
- // reached through reexports.
let scope_id = match child.res {
Res::Def(DefKind::Variant, ..) => self.resolver.parent(def_id).unwrap(),
_ => def_id,
};
- self.add_traits_in_parent_scope(scope_id); // Outer attribute scope
+ self.resolve_doc_links_extern_outer(def_id, scope_id); // Outer attribute scope
if let Res::Def(DefKind::Mod, ..) = child.res {
- self.add_traits_in_scope(def_id); // Inner attribute scope
+ self.resolve_doc_links_extern_inner(def_id); // Inner attribute scope
}
// Traits are processed in `add_extern_traits_in_scope`.
if let Res::Def(DefKind::Mod | DefKind::Enum, ..) = child.res {
impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
fn visit_item(&mut self, item: &ast::Item) {
- self.load_links_in_attrs(&item.attrs); // Outer attribute scope
+ self.resolve_doc_links_local(&item.attrs); // Outer attribute scope
if let ItemKind::Mod(..) = item.kind {
let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id));
- self.load_links_in_attrs(&item.attrs); // Inner attribute scope
+ self.resolve_doc_links_local(&item.attrs); // Inner attribute scope
self.process_module_children_or_reexports(self.current_mod.to_def_id());
visit::walk_item(self, item);
self.current_mod = old_mod;
}
fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: AssocCtxt) {
- self.load_links_in_attrs(&item.attrs);
+ self.resolve_doc_links_local(&item.attrs);
visit::walk_assoc_item(self, item, ctxt)
}
fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
- self.load_links_in_attrs(&item.attrs);
+ self.resolve_doc_links_local(&item.attrs);
visit::walk_foreign_item(self, item)
}
fn visit_variant(&mut self, v: &ast::Variant) {
- self.load_links_in_attrs(&v.attrs);
+ self.resolve_doc_links_local(&v.attrs);
visit::walk_variant(self, v)
}
fn visit_field_def(&mut self, field: &ast::FieldDef) {
- self.load_links_in_attrs(&field.attrs);
+ self.resolve_doc_links_local(&field.attrs);
visit::walk_field_def(self, field)
}
mod strip_priv_imports;
crate use self::strip_priv_imports::STRIP_PRIV_IMPORTS;
-mod unindent_comments;
-crate use self::unindent_comments::UNINDENT_COMMENTS;
-
mod propagate_doc_cfg;
crate use self::propagate_doc_cfg::PROPAGATE_DOC_CFG;
crate const PASSES: &[Pass] = &[
CHECK_DOC_TEST_VISIBILITY,
STRIP_HIDDEN,
- UNINDENT_COMMENTS,
STRIP_PRIVATE,
STRIP_PRIV_IMPORTS,
PROPAGATE_DOC_CFG,
/// The list of passes run by default.
crate const DEFAULT_PASSES: &[ConditionalPass] = &[
ConditionalPass::always(COLLECT_TRAIT_IMPLS),
- ConditionalPass::always(UNINDENT_COMMENTS),
ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY),
ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
+++ /dev/null
-//! Removes excess indentation on comments in order for the Markdown
-//! to be parsed correctly. This is necessary because the convention for
-//! writing documentation is to provide a space between the /// or //! marker
-//! and the doc text, but Markdown is whitespace-sensitive. For example,
-//! a block of text with four-space indentation is parsed as a code block,
-//! so if we didn't unindent comments, these list items
-//!
-//! /// A list:
-//! ///
-//! /// - Foo
-//! /// - Bar
-//!
-//! would be parsed as if they were in a code block, which is likely not what the user intended.
-use std::cmp;
-
-use rustc_span::symbol::kw;
-
-use crate::clean::{self, DocFragment, DocFragmentKind, Item};
-use crate::core::DocContext;
-use crate::fold::{self, DocFolder};
-use crate::passes::Pass;
-
-#[cfg(test)]
-mod tests;
-
-crate const UNINDENT_COMMENTS: Pass = Pass {
- name: "unindent-comments",
- run: unindent_comments,
- description: "removes excess indentation on comments in order for markdown to like it",
-};
-
-crate fn unindent_comments(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
- CommentCleaner.fold_crate(krate)
-}
-
-struct CommentCleaner;
-
-impl fold::DocFolder for CommentCleaner {
- fn fold_item(&mut self, mut i: Item) -> Option<Item> {
- i.attrs.unindent_doc_comments();
- Some(self.fold_item_recur(i))
- }
-}
-
-impl clean::Attributes {
- crate fn unindent_doc_comments(&mut self) {
- unindent_fragments(&mut self.doc_strings);
- }
-}
-
-fn unindent_fragments(docs: &mut Vec<DocFragment>) {
- // `add` is used in case the most common sugared doc syntax is used ("/// "). The other
- // fragments kind's lines are never starting with a whitespace unless they are using some
- // markdown formatting requiring it. Therefore, if the doc block have a mix between the two,
- // we need to take into account the fact that the minimum indent minus one (to take this
- // whitespace into account).
- //
- // For example:
- //
- // /// hello!
- // #[doc = "another"]
- //
- // In this case, you want "hello! another" and not "hello! another".
- let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind)
- && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc)
- {
- // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to
- // "decide" how much the minimum indent will be.
- 1
- } else {
- 0
- };
-
- // `min_indent` is used to know how much whitespaces from the start of each lines must be
- // removed. Example:
- //
- // /// hello!
- // #[doc = "another"]
- //
- // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum
- // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4
- // (5 - 1) whitespaces.
- let Some(min_indent) = docs
- .iter()
- .map(|fragment| {
- fragment.doc.as_str().lines().fold(usize::MAX, |min_indent, line| {
- if line.chars().all(|c| c.is_whitespace()) {
- min_indent
- } else {
- // Compare against either space or tab, ignoring whether they are
- // mixed or not.
- let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
- cmp::min(min_indent, whitespace)
- + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }
- }
- })
- })
- .min()
- else {
- return;
- };
-
- for fragment in docs {
- if fragment.doc == kw::Empty {
- continue;
- }
-
- let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 {
- min_indent - add
- } else {
- min_indent
- };
-
- fragment.indent = min_indent;
- }
-}
+++ /dev/null
-use super::*;
-
-use crate::clean::collapse_doc_fragments;
-
-use rustc_span::create_default_session_globals_then;
-use rustc_span::source_map::DUMMY_SP;
-use rustc_span::symbol::Symbol;
-
-fn create_doc_fragment(s: &str) -> Vec<DocFragment> {
- vec![DocFragment {
- span: DUMMY_SP,
- parent_module: None,
- doc: Symbol::intern(s),
- kind: DocFragmentKind::SugaredDoc,
- indent: 0,
- }]
-}
-
-#[track_caller]
-fn run_test(input: &str, expected: &str) {
- create_default_session_globals_then(|| {
- let mut s = create_doc_fragment(input);
- unindent_fragments(&mut s);
- assert_eq!(collapse_doc_fragments(&s), expected);
- });
-}
-
-#[test]
-fn should_unindent() {
- run_test(" line1\n line2", "line1\nline2");
-}
-
-#[test]
-fn should_unindent_multiple_paragraphs() {
- run_test(" line1\n\n line2", "line1\n\nline2");
-}
-
-#[test]
-fn should_leave_multiple_indent_levels() {
- // Line 2 is indented another level beyond the
- // base indentation and should be preserved
- run_test(" line1\n\n line2", "line1\n\n line2");
-}
-
-#[test]
-fn should_ignore_first_line_indent() {
- run_test("line1\n line2", "line1\n line2");
-}
-
-#[test]
-fn should_not_ignore_first_line_indent_in_a_single_line_para() {
- run_test("line1\n\n line2", "line1\n\n line2");
-}
-
-#[test]
-fn should_unindent_tabs() {
- run_test("\tline1\n\tline2", "line1\nline2");
-}
-
-#[test]
-fn should_trim_mixed_indentation() {
- run_test("\t line1\n\t line2", "line1\nline2");
- run_test(" \tline1\n \tline2", "line1\nline2");
-}
-
-#[test]
-fn should_not_trim() {
- run_test("\t line1 \n\t line2", "line1 \nline2");
- run_test(" \tline1 \n \tline2", "line1 \nline2");
-}
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId};
use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
use rustc_middle::ty::TyCtxt;
}
crate fn visit_lib(&mut self, cnum: CrateNum) {
- let did = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+ let did = cnum.as_def_id();
self.update(did, Some(AccessLevel::Public));
self.visit_mod(did);
}
-Subproject commit 9168e236c548d1d0e9938ee6dd4cdbd308fdfd72
+Subproject commit fd336816c3a6d228dcef22171c43140f6fa7656f
use std::arch::asm;
// CHECK-LABEL: @clobber_sysv64
-// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
#[no_mangle]
pub unsafe fn clobber_sysv64() {
asm!("", clobber_abi("sysv64"));
}
// CHECK-LABEL: @clobber_win64
-// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
#[no_mangle]
pub unsafe fn clobber_win64() {
asm!("", clobber_abi("win64"));
}
// CHECK-LABEL: @clobber_sysv64
-// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
#[no_mangle]
pub unsafe fn clobber_sysv64_edx() {
let foo: i32;
}
// CHECK-LABEL: @clobber_win64
-// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
#[no_mangle]
pub unsafe fn clobber_win64_edx() {
let foo: i32;
#[no_mangle]
fn into_error(self, error: Self::Source) -> Error {
Error::Api {
- source: (|v| v)(error),
+ source: error,
}
}
}
+// min-llvm-version: 14.0
// ignore-debug: the debug assertions get in the way
-// compile-flags: -O
+// compile-flags: -O -Z merge-functions=disabled
#![crate_type = "lib"]
// Ensure that trivial casts of vec elements are O(1)
-// CHECK-LABEL: @vec_iterator_cast
+pub struct Wrapper<T>(T);
+
+#[repr(C)]
+pub struct Foo {
+ a: u64,
+ b: u64,
+ c: u64,
+ d: u64,
+}
+
+// Going from an aggregate struct to another type currently requires Copy to
+// enable the TrustedRandomAccess specialization. Without it optimizations do not yet
+// reliably recognize the loops as noop for for repr(C) or non-Copy structs.
+#[derive(Copy, Clone)]
+pub struct Bar {
+ a: u64,
+ b: u64,
+ c: u64,
+ d: u64,
+}
+
+// CHECK-LABEL: @vec_iterator_cast_primitive
+#[no_mangle]
+pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
+ // CHECK-NOT: loop
+ // CHECK-NOT: call
+ vec.into_iter().map(|e| e as u8).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_wrapper
+#[no_mangle]
+pub fn vec_iterator_cast_wrapper(vec: Vec<u8>) -> Vec<Wrapper<u8>> {
+ // CHECK-NOT: loop
+ // CHECK-NOT: call
+ vec.into_iter().map(|e| Wrapper(e)).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_unwrap
+#[no_mangle]
+pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
+ // CHECK-NOT: loop
+ // CHECK-NOT: call
+ vec.into_iter().map(|e| e.0).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_aggregate
#[no_mangle]
-pub fn vec_iterator_cast(vec: Vec<isize>) -> Vec<usize> {
+pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> {
// CHECK-NOT: loop
// CHECK-NOT: call
- vec.into_iter().map(|e| e as usize).collect()
+ vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_deaggregate
+#[no_mangle]
+pub fn vec_iterator_cast_deaggregate(vec: Vec<Bar>) -> Vec<[u64; 4]> {
+ // CHECK-NOT: loop
+ // CHECK-NOT: call
+
+ // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4].
+ // This currently is not guaranteed for repr(Rust) types, but it happens to work here and
+ // the UCG may add additional guarantees for homogenous types in the future that would make this
+ // correct.
+ vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
}
fn h() -> () {
let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12
let _1: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+ let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+ let mut _9: (); // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16
-+ let mut _10: (); // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16
++ let mut _2: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++ let mut _3: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++ let mut _10: (); // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16
++ let mut _11: (); // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16
+ scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22
-+ debug f => _2; // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37
-+ let _3: !; // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
-+ let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+ let mut _6: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
-+ let mut _7: !; // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
-+ let mut _8: !; // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
++ debug f => _3; // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37
++ let _4: !; // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
++ let mut _5: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
++ let mut _7: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
++ let mut _8: !; // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
++ let mut _9: !; // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
+ scope 2 {
-+ debug a => _3; // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10
-+ let _5: !; // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
++ debug a => _4; // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10
++ let _6: !; // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
+ scope 3 {
-+ debug b => _5; // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
++ debug b => _6; // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
+ }
+ scope 6 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:28:13: 28:16
+ scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-- _1 = call_twice::<!, fn() -> ! {sleep}>(sleep) -> bb1; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+- call_twice::<!, fn() -> ! {sleep}>(sleep); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+ StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+ _2 = sleep; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++ StorageLive(_3); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++ _3 = sleep; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
// mir::Constant
- // + span: $DIR/inline-diverging.rs:22:5: 22:15
- // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice::<!, fn() -> ! {sleep}>}, val: Value(Scalar(<ZST>)) }
- // mir::Constant
// + span: $DIR/inline-diverging.rs:22:16: 22:21
// + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar(<ZST>)) }
-+ StorageLive(_3); // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
-+ StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+ _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+ StorageLive(_9); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
-+ _9 = const (); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
++ StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
++ StorageLive(_5); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
++ _5 = &_3; // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
++ StorageLive(_10); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
++ _10 = const (); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
+ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
- }
-
- bb1: {
-- StorageDead(_1); // scope 0 at $DIR/inline-diverging.rs:22:22: 22:23
-- _0 = const (); // scope 0 at $DIR/inline-diverging.rs:21:12: 23:2
-- return; // scope 0 at $DIR/inline-diverging.rs:23:2: 23:2
++ }
++
++ bb1: {
+ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
}
}
StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
_3 = (); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
- _2 = transmute::<(), Void>(move _3) -> [return: bb1, unwind: bb4]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
+ transmute::<(), Void>(move _3) -> bb4; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
// mir::Constant
// + span: $DIR/issue-72181-1.rs:17:9: 17:40
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value(Scalar(<ZST>)) }
| '_#2r live at {bb0[0..=1]}
| '_#3r live at {bb0[0..=1]}
| '_#4r live at {bb0[0..=1]}
-| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27)
-| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55)
-| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43)
-| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67)
-| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27)
-| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43)
-| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55)
-| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67)
+| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
+| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
+| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
+| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
+| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
+| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
+| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
+| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
|
fn use_x(_1: &'_#6r mut i32, _2: &'_#7r u32, _3: &'_#8r u32, _4: &'_#9r u32) -> bool {
debug w => _1; // in scope 0 at $DIR/named-lifetimes-basic.rs:12:26: 12:27
| '_#3r live at {bb1[0]}
| '_#4r live at {bb1[1..=3]}
| '_#5r live at {bb1[4..=7], bb2[0..=2]}
-| '_#3r: '_#4r due to Assignment at Single(bb1[0])
-| '_#4r: '_#5r due to Assignment at Single(bb1[3])
+| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
+| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
|
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
| '_#3r live at {bb1[0]}
| '_#4r live at {bb1[1..=3]}
| '_#5r live at {bb1[4..=7], bb2[0..=2]}
-| '_#3r: '_#4r due to Assignment at Single(bb1[0])
-| '_#4r: '_#5r due to Assignment at Single(bb1[3])
+| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
+| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
|
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
| '_#1r live at {bb0[0..=22]}
| '_#3r live at {bb0[10]}
| '_#4r live at {bb0[11]}
-| '_#3r: '_#4r due to Assignment at Single(bb0[10])
+| '_#3r: '_#4r due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0)
|
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/storage_ranges.rs:3:11: 3:11
// exact-check
-const QUERY = 'hashmap';
+const QUERY = '"hashmap"';
const FILTER_CRATE = 'core';
const EXPECTED = {
--- /dev/null
+const QUERY = [
+ '<P>',
+ '-> <P>',
+ 'a<"P">',
+ '"P" "P"',
+ 'P "P"',
+ '"p" p',
+ '"const": p',
+ "a<:a>",
+ "a<::a>",
+ "((a))",
+ "(p -> p",
+ "::a::b",
+ "a::::b",
+ "a::b::",
+ ":a",
+ "a b:",
+ "a (b:",
+ "_:",
+ "a-bb",
+ "a>bb",
+ "ab'",
+ "a->",
+ '"p" <a>',
+ '"p" a<a>',
+ "a,<",
+ "aaaaa<>b",
+ "fn:aaaaa<>b",
+ "->a<>b",
+ "a<->",
+ "a:: a",
+ "a ::a",
+ "a<a>:",
+ "a<>:",
+ "a,:",
+ " a<> :",
+ "mod : :",
+];
+
+const PARSED = [
+ {
+ elems: [],
+ foundElems: 0,
+ original: "<P>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "<p>",
+ error: "Found generics without a path",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "-> <P>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "-> <p>",
+ error: "Found generics without a path",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<\"P\">",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<\"p\">",
+ error: "`\"` cannot be used in generics",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "\"P\" \"P\"",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "\"p\" \"p\"",
+ error: "Cannot have more than one literal search element",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "P \"P\"",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "p \"p\"",
+ error: "Cannot use literal search when there is more than one element",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "\"p\" p",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "\"p\" p",
+ error: "You cannot have more than one element if you use quotes",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "\"const\": p",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "\"const\": p",
+ error: "You cannot use quotes on type filter",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<:a>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<:a>",
+ error: "Unexpected `:` after `<`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<::a>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<::a>",
+ error: "Unexpected `::`: paths cannot start with `::`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "((a))",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "((a))",
+ error: "Unexpected `(`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "(p -> p",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "(p -> p",
+ error: "Unexpected `(`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "::a::b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "::a::b",
+ error: "Paths cannot start with `::`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a::::b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a::::b",
+ error: "Unexpected `::::`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a::b::",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a::b::",
+ error: "Paths cannot end with `::`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: ":a",
+ returned: [],
+ typeFilter: -1,
+ userQuery: ":a",
+ error: "Expected type filter before `:`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a b:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a b:",
+ error: "Unexpected `:`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a (b:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a (b:",
+ error: "Unexpected `(`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "_:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "_:",
+ error: "Unknown type filter `_`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a-bb",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a-bb",
+ error: "Unexpected `-` (did you mean `->`?)",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a>bb",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a>bb",
+ error: "Unexpected `>` (did you mean `->`?)",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "ab'",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "ab'",
+ error: "Unexpected `'`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a->",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a->",
+ error: "Expected at least one item after `->`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"p" <a>',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p" <a>',
+ error: "Found generics without a path",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"p" a<a>',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p" a<a>',
+ error: "You cannot have more than one element if you use quotes",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'a,<',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a,<',
+ error: 'Found generics without a path',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'aaaaa<>b',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'aaaaa<>b',
+ error: 'Expected `,`, ` `, `:` or `->`, found `b`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'fn:aaaaa<>b',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'fn:aaaaa<>b',
+ error: 'Expected `,`, ` ` or `->`, found `b`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '->a<>b',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '->a<>b',
+ error: 'Expected `,` or ` `, found `b`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'a<->',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a<->',
+ error: 'Unexpected `-` after `<`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'a:: a',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a:: a',
+ error: 'Paths cannot end with `::`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'a ::a',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a ::a',
+ error: 'Paths cannot start with `::`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<a>:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<a>:",
+ error: 'Unexpected `:`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<>:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<>:",
+ error: 'Unexpected `<` in type filter',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a,:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a,:",
+ error: 'Unexpected `,` in type filter',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<> :",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<> :",
+ error: 'Unexpected `<` in type filter',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "mod : :",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "mod : :",
+ error: 'Unexpected `:`',
+ },
+];
--- /dev/null
+const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo'];
+
+const PARSED = [
+ {
+ elems: [{
+ name: "foo",
+ fullPath: ["foo"],
+ pathWithoutLast: [],
+ pathLast: "foo",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "fn:foo",
+ returned: [],
+ typeFilter: 5,
+ userQuery: "fn:foo",
+ error: null,
+ },
+ {
+ elems: [{
+ name: "foo",
+ fullPath: ["foo"],
+ pathWithoutLast: [],
+ pathLast: "foo",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "enum : foo",
+ returned: [],
+ typeFilter: 4,
+ userQuery: "enum : foo",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "macro<f>:foo",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "macro<f>:foo",
+ error: "Unexpected `:`",
+ },
+];
--- /dev/null
+const QUERY = ['A<B<C<D>, E>', 'p<> u8', '"p"<a>'];
+
+const PARSED = [
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'A<B<C<D>, E>',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a<b<c<d>, e>',
+ error: 'Unexpected `<` after `<`',
+ },
+ {
+ elems: [
+ {
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ },
+ {
+ name: "u8",
+ fullPath: ["u8"],
+ pathWithoutLast: [],
+ pathLast: "u8",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "p<> u8",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "p<> u8",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [
+ {
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ },
+ ],
+ },
+ ],
+ foundElems: 1,
+ original: '"p"<a>',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p"<a>',
+ error: null,
+ },
+];
--- /dev/null
+const QUERY = ['R<P>'];
+
+const PARSED = [
+ {
+ elems: [{
+ name: "r",
+ fullPath: ["r"],
+ pathWithoutLast: [],
+ pathLast: "r",
+ generics: [
+ {
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ },
+ ],
+ }],
+ foundElems: 1,
+ original: "R<P>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "r<p>",
+ error: null,
+ }
+];
--- /dev/null
+const QUERY = ['A::B', 'A::B,C', 'A::B<f>,C', 'mod::a'];
+
+const PARSED = [
+ {
+ elems: [{
+ name: "a::b",
+ fullPath: ["a", "b"],
+ pathWithoutLast: ["a"],
+ pathLast: "b",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "A::B",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a::b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: "a::b",
+ fullPath: ["a", "b"],
+ pathWithoutLast: ["a"],
+ pathLast: "b",
+ generics: [],
+ },
+ {
+ name: "c",
+ fullPath: ["c"],
+ pathWithoutLast: [],
+ pathLast: "c",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: 'A::B,C',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a::b,c',
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: "a::b",
+ fullPath: ["a", "b"],
+ pathWithoutLast: ["a"],
+ pathLast: "b",
+ generics: [
+ {
+ name: "f",
+ fullPath: ["f"],
+ pathWithoutLast: [],
+ pathLast: "f",
+ generics: [],
+ },
+ ],
+ },
+ {
+ name: "c",
+ fullPath: ["c"],
+ pathWithoutLast: [],
+ pathLast: "c",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: 'A::B<f>,C',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a::b<f>,c',
+ error: null,
+ },
+ {
+ elems: [{
+ name: "mod::a",
+ fullPath: ["mod", "a"],
+ pathWithoutLast: ["mod"],
+ pathLast: "a",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "mod::a",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "mod::a",
+ error: null,
+ },
+];
--- /dev/null
+const QUERY = [
+ '-> "p"',
+ '"p",',
+ '"p" -> a',
+ '"a" -> "p"',
+ '->"-"',
+ '"a',
+ '""',
+];
+
+const PARSED = [
+ {
+ elems: [],
+ foundElems: 1,
+ original: '-> "p"',
+ returned: [{
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: '-> "p"',
+ error: null,
+ },
+ {
+ elems: [{
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: '"p",',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p",',
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"p" -> a',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p" -> a',
+ error: "You cannot have more than one element if you use quotes",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"a" -> "p"',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"a" -> "p"',
+ error: "Cannot have more than one literal search element",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '->"-"',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '->"-"',
+ error: 'Unexpected `-` in a string element',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"a',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"a',
+ error: 'Unclosed `"`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '""',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '""',
+ error: 'Cannot have empty string element',
+ },
+];
--- /dev/null
+const QUERY = ['-> F<P>', '-> P', '->,a', 'aaaaa->a'];
+
+const PARSED = [
+ {
+ elems: [],
+ foundElems: 1,
+ original: "-> F<P>",
+ returned: [{
+ name: "f",
+ fullPath: ["f"],
+ pathWithoutLast: [],
+ pathLast: "f",
+ generics: [
+ {
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ },
+ ],
+ }],
+ typeFilter: -1,
+ userQuery: "-> f<p>",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 1,
+ original: "-> P",
+ returned: [{
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: "-> p",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 1,
+ original: "->,a",
+ returned: [{
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: "->,a",
+ error: null,
+ },
+ {
+ elems: [{
+ name: "aaaaa",
+ fullPath: ["aaaaa"],
+ pathWithoutLast: [],
+ pathLast: "aaaaa",
+ generics: [],
+ }],
+ foundElems: 2,
+ original: "aaaaa->a",
+ returned: [{
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: "aaaaa->a",
+ error: null,
+ },
+];
--- /dev/null
+// ignore-tidy-tab
+
+const QUERY = [
+ 'aaaaaa b',
+ 'a b',
+ 'a,b',
+ 'a\tb',
+ 'a<b c>',
+ 'a<b,c>',
+ 'a<b\tc>',
+];
+
+const PARSED = [
+ {
+ elems: [
+ {
+ name: 'aaaaaa',
+ fullPath: ['aaaaaa'],
+ pathWithoutLast: [],
+ pathLast: 'aaaaaa',
+ generics: [],
+ },
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "aaaaaa b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "aaaaaa b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [],
+ },
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [],
+ },
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a,b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a,b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [],
+ },
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a\tb",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a\tb",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ {
+ name: 'c',
+ fullPath: ['c'],
+ pathWithoutLast: [],
+ pathLast: 'c',
+ generics: [],
+ },
+ ],
+ },
+ ],
+ foundElems: 1,
+ original: "a<b c>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<b c>",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ {
+ name: 'c',
+ fullPath: ['c'],
+ pathWithoutLast: [],
+ pathLast: 'c',
+ generics: [],
+ },
+ ],
+ },
+ ],
+ foundElems: 1,
+ original: "a<b,c>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<b,c>",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ {
+ name: 'c',
+ fullPath: ['c'],
+ pathWithoutLast: [],
+ pathLast: 'c',
+ generics: [],
+ },
+ ],
+ },
+ ],
+ foundElems: 1,
+ original: "a<b\tc>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<b\tc>",
+ error: null,
+ },
+];
--- /dev/null
+// This test is mostly to check that the parser still kinda outputs something
+// (and doesn't enter an infinite loop!) even though the query is completely
+// invalid.
+const QUERY = [
+ 'a b',
+ 'a b',
+ 'a,b(c)',
+ 'aaa,a',
+ ',,,,',
+ 'mod :',
+ 'mod\t:',
+];
+
+const PARSED = [
+ {
+ elems: [
+ {
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ },
+ {
+ name: "b",
+ fullPath: ["b"],
+ pathWithoutLast: [],
+ pathLast: "b",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ },
+ {
+ name: "b",
+ fullPath: ["b"],
+ pathWithoutLast: [],
+ pathLast: "b",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a b",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a,b(c)",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a,b(c)",
+ error: "Unexpected `(`",
+ },
+ {
+ elems: [
+ {
+ name: "aaa",
+ fullPath: ["aaa"],
+ pathWithoutLast: [],
+ pathLast: "aaa",
+ generics: [],
+ },
+ {
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "aaa,a",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "aaa,a",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: ",,,,",
+ returned: [],
+ typeFilter: -1,
+ userQuery: ",,,,",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'mod :',
+ returned: [],
+ typeFilter: 0,
+ userQuery: 'mod :',
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'mod\t:',
+ returned: [],
+ typeFilter: 0,
+ userQuery: 'mod\t:',
+ error: null,
+ },
+];
+// ignore-order
+
const QUERY = '"error"';
+const FILTER_CRATE = 'std';
const EXPECTED = {
'others': [
{ 'path': 'std::fmt', 'name': 'Error' },
{ 'path': 'std::io', 'name': 'Error' },
],
- 'in_args': [],
+ 'in_args': [
+ { 'path': 'std::fmt::Error', 'name': 'eq' },
+ { 'path': 'std::fmt::Error', 'name': 'cmp' },
+ { 'path': 'std::fmt::Error', 'name': 'partial_cmp' },
+
+ ],
'returned': [
{ 'path': 'std::fmt::LowerExp', 'name': 'fmt' },
],
-const QUERY = 'struct:Vec';
+const QUERY = 'struct:VecD';
const EXPECTED = {
'others': [
- { 'path': 'std::vec', 'name': 'Vec' },
{ 'path': 'std::collections', 'name': 'VecDeque' },
+ { 'path': 'std::vec', 'name': 'Vec' },
],
};
// exact-check
const QUERY = 'macro:print';
+const FILTER_CRATE = 'std';
const EXPECTED = {
'others': [
{ 'path': 'std', 'name': 'println' },
{ 'path': 'std', 'name': 'eprintln' },
{ 'path': 'std::pin', 'name': 'pin' },
- { 'path': 'core::pin', 'name': 'pin' },
+ { 'path': 'std::future', 'name': 'join' },
+ { 'path': 'std', 'name': 'line' },
+ { 'path': 'std', 'name': 'write' },
],
};
'others': [
{ 'path': 'std::vec::Vec', 'name': 'new' },
{ 'path': 'std::vec::Vec', 'name': 'ne' },
- { 'path': 'std::rc::Rc', 'name': 'ne' },
+ { 'path': 'alloc::vec::Vec', 'name': 'ne' },
],
};
// exact-check
-const QUERY = 'true';
+const QUERY = '"true"';
const FILTER_CRATE = 'doc_alias_filter';
const EXPECTED = [
{
+ // StructItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // StructFieldItem
'others': [
{
'path': 'doc_alias::Struct',
],
},
{
+ // StructMethodItem
'others': [
{
'path': 'doc_alias::Struct',
],
},
{
+ // ImplTraitFunction
'others': [
{
'path': 'doc_alias::Struct',
],
},
{
+ // EnumItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // VariantItem
'others': [
{
'path': 'doc_alias::Enum',
],
},
{
+ // EnumMethodItem
'others': [
{
'path': 'doc_alias::Enum',
],
},
{
+ // TypedefItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // TraitItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // TraitTypeItem
'others': [
{
'path': 'doc_alias::Trait',
],
},
{
+ // AssociatedConstItem
'others': [
{
'path': 'doc_alias::Trait',
],
},
{
+ // TraitFunctionItem
'others': [
{
'path': 'doc_alias::Trait',
],
},
{
+ // FunctionItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // ModuleItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // ConstItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // StaticItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // UnionItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // UnionFieldItem
'others': [
{
'path': 'doc_alias::Union',
],
},
{
+ // UnionMethodItem
'others': [
{
'path': 'doc_alias::Union',
],
},
{
+ // MacroItem
'others': [
{
'path': 'doc_alias',
// exact-check
const QUERY = [
- '"R<P>"',
+ 'R<P>',
'"P"',
'P',
- '"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
+ 'ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>',
'TraitCat',
'TraitDog',
+ 'Result<String>',
];
const EXPECTED = [
{
+ // R<P>
'returned': [
{ 'path': 'generics', 'name': 'alef' },
],
],
},
{
+ // "P"
'others': [
{ 'path': 'generics', 'name': 'P' },
],
],
},
{
+ // P
'returned': [
{ 'path': 'generics', 'name': 'alef' },
- { 'path': 'generics', 'name': 'bet' },
],
'in_args': [
{ 'path': 'generics', 'name': 'alpha' },
- { 'path': 'generics', 'name': 'beta' },
],
},
{
+ // "ExtraCreditStructMulti"<ExtraCreditInnerMulti, ExtraCreditInnerMulti>
'in_args': [
{ 'path': 'generics', 'name': 'extracreditlabhomework' },
],
'returned': [],
},
{
+ // TraitCat
'in_args': [
{ 'path': 'generics', 'name': 'gamma' },
],
},
{
+ // TraitDog
'in_args': [
{ 'path': 'generics', 'name': 'gamma' },
],
},
+ {
+ // Result<String>
+ 'others': [],
+ 'returned': [
+ { 'path': 'generics', 'name': 'super_soup' },
+ ],
+ 'in_args': [
+ { 'path': 'generics', 'name': 'super_soup' },
+ ],
+ },
];
pub trait TraitDog {}
pub fn gamma<T: TraitCat + TraitDog>(t: T) {}
+
+pub fn super_soup(s: Result<String, i32>) -> Result<String, i32> { s }
// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
+// check-pass
#![deny(warnings)]
//! Email me at <hello@localhost>.
-//~^ ERROR unknown disambiguator `hello`
//! This should *not* warn: <hello@example.com>.
+++ /dev/null
-error: unknown disambiguator `hello`
- --> $DIR/email-address-localhost.rs:4:18
- |
-LL | //! Email me at <hello@localhost>.
- | ^^^^^
- |
-note: the lint level is defined here
- --> $DIR/email-address-localhost.rs:2:9
- |
-LL | #![deny(warnings)]
- | ^^^^^^^^
- = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
- = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
-
-error: aborting due to previous error
-
Available passes for running rustdoc:
check_doc_test_visibility - run various visibility-related lints on doctests
strip-hidden - strips all `#[doc(hidden)]` items from the output
- unindent-comments - removes excess indentation on comments in order for markdown to like it
strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports
strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate
propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items
Default passes for rustdoc:
collect-trait-impls
- unindent-comments
check_doc_test_visibility
strip-hidden (when not --document-hidden-items)
strip-private (when not --document-private-items)
--- /dev/null
+// This test ensures that the same implementation doesn't show more than once.
+// It's a regression test for https://github.com/rust-lang/rust/issues/96036.
+
+#![crate_name = "foo"]
+
+// We check that there is only one "impl<T> Something<Whatever> for T" listed in the
+// blanket implementations.
+
+// @has 'foo/struct.Whatever.html'
+// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl has-srclink"]' 1
+
+pub trait Something<T> { }
+pub struct Whatever;
+impl<T> Something<Whatever> for T {}
--- /dev/null
+// This is a regression for https://github.com/rust-lang/rust/issues/96079.
+
+#![crate_name = "foo"]
+
+pub mod app {
+ pub struct S;
+
+ impl S {
+ // @has 'foo/app/struct.S.html'
+ // @has - '//a[@href="../enums/enum.Foo.html#method.by_name"]' 'Foo::by_name'
+ /**
+ Doc comment hello! [`Foo::by_name`](`crate::enums::Foo::by_name`).
+ */
+ pub fn whatever(&self) {}
+ }
+}
+
+pub mod enums {
+ pub enum Foo {
+ Bar,
+ }
+
+ impl Foo {
+ pub fn by_name(&self) {}
+ }
+}
--- /dev/null
+<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Simd<T>(_) <br /><span class="where">where<br />    T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre></div>
\ No newline at end of file
--- /dev/null
+<div class="docblock item-decl"><pre class="rust trait"><code>pub trait TraitWhere {
+ type <a href="#associatedtype.Item" class="associatedtype">Item</a><'a><br />    <span class="where">where<br />        Self: 'a</span>;
+}</code></pre></div>
\ No newline at end of file
+#![feature(generic_associated_types)]
#![crate_name = "foo"]
pub trait MyTrait { fn dummy(&self) { } }
pub struct Echo<E>(E);
+// @has 'foo/struct.Simd.html'
+// @snapshot SWhere_Simd_item-decl - '//div[@class="docblock item-decl"]'
+pub struct Simd<T>([T; 1])
+where
+ T: MyTrait;
+
+// @has 'foo/trait.TraitWhere.html'
+// @snapshot SWhere_TraitWhere_item-decl - '//div[@class="docblock item-decl"]'
+pub trait TraitWhere {
+ type Item<'a> where Self: 'a;
+}
+
// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<E> MyTrait for Echo<E> where E: MyTrait"
// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
//~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand
asm!("", in("ip") foo);
//~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand
- asm!("", in("k0") foo);
- //~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
asm!("", in("st(2)") foo);
//~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
asm!("", in("mm0") foo);
//~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
+ asm!("", in("k0") foo);
+ //~^ ERROR register class `kreg0` can only be used as a clobber, not as an input or output
asm!("", out("st(2)") _);
asm!("", out("mm0") _);
asm!("{}", in(x87_reg) foo);
LL | asm!("", in("ip") foo);
| ^^^^^^^^^^^^
-error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:32:18
- |
-LL | asm!("", in("k0") foo);
- | ^^^^^^^^^^^^
-
error: register class `x87_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:35:18
+ --> $DIR/bad-reg.rs:33:18
|
LL | asm!("", in("st(2)") foo);
| ^^^^^^^^^^^^^^^
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:37:18
+ --> $DIR/bad-reg.rs:35:18
|
LL | asm!("", in("mm0") foo);
| ^^^^^^^^^^^^^
+error: register class `kreg0` can only be used as a clobber, not as an input or output
+ --> $DIR/bad-reg.rs:37:18
+ |
+LL | asm!("", in("k0") foo);
+ | ^^^^^^^^^^^^
+
error: register class `x87_reg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:41:20
|
--> $DIR/async-fn-path-elision.rs:5:20
|
LL | async fn error(lt: HasLifetime) {
- | ^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^^^^^^^^^ expected lifetime parameter
|
= note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+ |
+LL | async fn error(lt: HasLifetime<'_>) {
+ | ++++
error: aborting due to previous error
fn main() {
g(issue_67893::run())
- //~^ ERROR generator cannot be sent between threads safely
+ //~^ ERROR future cannot be sent between threads safely
}
-error: generator cannot be sent between threads safely
+error: future cannot be sent between threads safely
--> $DIR/issue-67893.rs:9:7
|
LL | g(issue_67893::run())
- | ^^^^^^^^^^^^^^^^^^ generator is not `Send`
+ | ^^^^^^^^^^^^^^^^^^ future is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+note: future is not `Send` as this value is used across an await
+ --> $DIR/auxiliary/issue_67893.rs:9:26
+ |
+LL | f(*x.lock().unwrap()).await;
+ | ----------------- ^^^^^^ await occurs here, with `x.lock().unwrap()` maybe used later
+ | |
+ | has type `MutexGuard<'_, ()>` which is not `Send`
+note: `x.lock().unwrap()` is later dropped here
+ --> $DIR/auxiliary/issue_67893.rs:9:32
+ |
+LL | f(*x.lock().unwrap()).await;
+ | ^
note: required by a bound in `g`
--> $DIR/issue-67893.rs:6:14
|
--> $DIR/issue-87493.rs:8:8
|
LL | T: MyTrait<Assoc == S::Assoc>,
- | ^^^^^^^------------------- help: remove these generics
+ | ^^^^^^^ ----------------- help: replace the generic bound with the associated type: `Assoc = Assoc == S::Assoc`
| |
| expected 0 generic arguments
|
78 00 00 00 ff ff ff ff │ x.......
}
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:92:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-enum.rs:92:77
|
LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 00 00 00 00 00 00 00 00 │ ........
- }
+ | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:94:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-enum.rs:94:77
|
LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 00 00 00 00 00 00 00 00 │ ........
- }
+ | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
error: aborting due to 13 previous errors
78 00 00 00 ff ff ff ff │ x.......
}
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:92:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-enum.rs:92:77
|
LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 00 00 00 00 00 00 00 00 │ ........
- }
+ | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:94:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-enum.rs:94:77
|
LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 00 00 00 00 00 00 00 00 │ ........
- }
+ | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
error: aborting due to 13 previous errors
// All variants are uninhabited but also have data.
// Use `0` as constant to make behavior endianess-independent.
const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
-//~^ ERROR is undefined behavior
+//~^ ERROR evaluation of constant value failed
const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
-//~^ ERROR is undefined behavior
+//~^ ERROR evaluation of constant value failed
fn main() {
}
LL | const FOO: [Empty; 3] = [foo(); 3];
| ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/validate_uninhabited_zsts.rs:16:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/validate_uninhabited_zsts.rs:16:35
|
LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 0, align: 1) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
warning: the type `!` does not permit zero-initialization
--> $DIR/validate_uninhabited_zsts.rs:4:14
LL | const FOO: [Empty; 3] = [foo(); 3];
| ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/validate_uninhabited_zsts.rs:16:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/validate_uninhabited_zsts.rs:16:35
|
LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 0, align: 1) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
warning: the type `!` does not permit zero-initialization
--> $DIR/validate_uninhabited_zsts.rs:4:14
#[warn(const_err)]
const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-//~^ ERROR it is undefined behavior to use this value
+//~^ ERROR evaluation of constant value failed
//~| WARN the type `Empty` does not permit zero-initialization
fn main() {
//~| HELP remove this lifetime argument
}
+pub trait T {
+ type A;
+ type B;
+}
+
+fn trait_bound_generic<I: T<u8, u16>>(_i: I) {
+ //~^ ERROR this trait takes 0 generic arguments
+ //~| HELP replace the generic bounds with the associated types
+}
+
fn main() {}
LL | struct Quux<T>(T);
| ^^^^
-error: aborting due to 9 previous errors
+error[E0107]: this trait takes 0 generic arguments but 2 generic arguments were supplied
+ --> $DIR/E0107.rs:55:27
+ |
+LL | fn trait_bound_generic<I: T<u8, u16>>(_i: I) {
+ | ^ expected 0 generic arguments
+ |
+note: trait defined here, with 0 generic parameters
+ --> $DIR/E0107.rs:50:11
+ |
+LL | pub trait T {
+ | ^
+help: replace the generic bounds with the associated types
+ |
+LL | fn trait_bound_generic<I: T<A = u8, B = u16>>(_i: I) {
+ | ~~~~~~ ~~~~~~~
+
+error: aborting due to 10 previous errors
For more information about this error, try `rustc --explain E0107`.
// edition:2021
// run-pass
+// compile-flags: -Zdrop-tracking
#![feature(never_type)]
}
async fn includes_never(crash: bool, x: u32) -> u32 {
- let mut result = async { x * x }.await;
+ let result = async { x * x }.await;
if !crash {
return result;
}
--> $DIR/gat-in-trait-path-undeclared-lifetime.rs:8:35
|
LL | fn _f(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {}
- | - ^^ undeclared lifetime
- | |
- | help: consider introducing lifetime `'x` here: `<'x>`
+ | ^^ undeclared lifetime
+ |
+ = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'x` lifetime
+ |
+LL | fn _f(arg : Box<dyn for<'x, 'a> X<Y<'x> = &'a [u32]>>) {}
+ | +++
+help: consider introducing lifetime `'x` here
+ |
+LL | fn _f<'x>(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {}
+ | ++++
error[E0582]: binding for associated type `Y` references lifetime `'a`, which does not appear in the trait input types
--> $DIR/gat-in-trait-path-undeclared-lifetime.rs:8:33
LL | + Deref<Target = Self::Item<'b>>;
| ^^ undeclared lifetime
|
-help: consider introducing lifetime `'b` here
+ = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'b` lifetime
|
-LL | trait Iterable<'b> {
- | ++++
+LL | + for<'b> Deref<Target = Self::Item<'b>>;
+ | +++++++
help: consider introducing lifetime `'b` here
|
LL | type Iter<'b, 'a>: Iterator<Item = Self::Item<'a>>
| +++
+help: consider introducing lifetime `'b` here
+ |
+LL | trait Iterable<'b> {
+ | ++++
error[E0261]: use of undeclared lifetime name `'undeclared`
--> $DIR/generic_associated_type_undeclared_lifetimes.rs:11:41
|
help: consider introducing lifetime `'undeclared` here
|
-LL | trait Iterable<'undeclared> {
- | +++++++++++++
-help: consider introducing lifetime `'undeclared` here
- |
LL | fn iter<'undeclared, 'a>(&'a self) -> Self::Iter<'undeclared>;
| ++++++++++++
+help: consider introducing lifetime `'undeclared` here
+ |
+LL | trait Iterable<'undeclared> {
+ | +++++++++++++
error: aborting due to 2 previous errors
type Y<'a>;
}
-fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
- //~^ ERROR: use of undeclared lifetime name `'a`
- //~| ERROR: use of undeclared lifetime name `'a`
-
+fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+//~^ ERROR: use of undeclared lifetime name `'a`
+//~| ERROR: use of undeclared lifetime name `'a`
+//~| ERROR: the trait `X` cannot be made into an object [E0038]
fn main() {}
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/issue-67510.rs:7:21
|
-LL | fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
- | - ^^ undeclared lifetime
- | |
- | help: consider introducing lifetime `'a` here: `<'a>`
+LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+ | ^^ undeclared lifetime
+ |
+ = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | fn f(x: Box<dyn for<'a> X<Y<'a> = &'a ()>>) {}
+ | +++++++
+help: consider introducing lifetime `'a` here
+ |
+LL | fn f<'a>(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+ | ++++
error[E0261]: use of undeclared lifetime name `'a`
- --> $DIR/issue-67510.rs:7:26
+ --> $DIR/issue-67510.rs:7:28
+ |
+LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+ | ^^ undeclared lifetime
+ |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | fn f(x: Box<dyn for<'a> X<Y<'a> = &'a ()>>) {}
+ | +++++++
+help: consider introducing lifetime `'a` here
+ |
+LL | fn f<'a>(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+ | ++++
+
+error[E0038]: the trait `X` cannot be made into an object
+ --> $DIR/issue-67510.rs:7:13
+ |
+LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+ | ^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+ |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+ --> $DIR/issue-67510.rs:4:10
|
-LL | fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
- | - ^^ undeclared lifetime
- | |
- | help: consider introducing lifetime `'a` here: `<'a>`
+LL | trait X {
+ | - this trait cannot be made into an object...
+LL | type Y<'a>;
+ | ^ ...because it contains the generic associated type `Y`
+ = help: consider moving `Y` to another trait
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0038, E0261.
+For more information about an error, try `rustc --explain E0038`.
type Cursor<'a> = DocCursorImpl<'a>;
fn cursor(&self) -> Self::Cursor<'_> {
- DocCursorImpl {
- document: &self,
- }
+ DocCursorImpl { document: &self }
}
}
-
trait DocCursor<'a> {}
struct DocCursorImpl<'a> {
_phantom: std::marker::PhantomData<&'d ()>,
}
-
impl<'d, Cursor> Lexer<'d, Cursor>
where
Cursor: DocCursor<'d>,
where
Doc: Document<Cursor<'d> = Cursor>,
{
- Lexer {
- cursor: document.cursor(),
- _phantom: std::marker::PhantomData,
- }
+ Lexer { cursor: document.cursor(), _phantom: std::marker::PhantomData }
}
}
fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
- //~^ ERROR: missing lifetime specifier
+ //~^ ERROR: missing lifetime specifier
DocumentImpl {}
}
error[E0106]: missing lifetime specifier
- --> $DIR/issue-70304.rs:54:41
+ --> $DIR/issue-70304.rs:47:41
|
LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
| ^^ expected named lifetime parameter
--> $DIR/generic-extern-lifetime.rs:6:26
|
LL | pub fn life2<'b>(x: &'a i32, y: &'b i32);
- | ^^ undeclared lifetime
+ | - ^^ undeclared lifetime
+ | |
+ | help: consider introducing lifetime `'a` here: `'a,`
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/generic-extern-lifetime.rs:8:37
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the type lifetime-generic with a new `'a` lifetime
|
-LL | pub fn life4<'b>(x: for<'c, 'a> fn(&'a i32));
- | ++++
+LL | pub fn life4<'b>(x: for<'a, 'c> fn(&'a i32));
+ | +++
+help: consider introducing lifetime `'a` here
+ |
+LL | pub fn life4<'a, 'b>(x: for<'c> fn(&'a i32));
+ | +++
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/generic-extern-lifetime.rs:11:39
LL | pub fn life7<'b>() -> for<'c> fn(&'a i32);
| ^^ undeclared lifetime
|
- = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the type lifetime-generic with a new `'a` lifetime
|
-LL | pub fn life7<'b>() -> for<'c, 'a> fn(&'a i32);
- | ++++
+LL | pub fn life7<'b>() -> for<'a, 'c> fn(&'a i32);
+ | +++
+help: consider introducing lifetime `'a` here
+ |
+LL | pub fn life7<'a, 'b>() -> for<'c> fn(&'a i32);
+ | +++
error: aborting due to 3 previous errors
--> $DIR/path-elided.rs:7:18
|
LL | impl MyTrait for Foo {
- | ^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^ expected lifetime parameter
|
= note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+ |
+LL | impl MyTrait for Foo<'_> {
+ | ++++
error: aborting due to previous error
#![allow(warnings)]
-trait MyTrait<'a> { }
+trait MyTrait<'a> {}
-impl MyTrait for u32 {
- //~^ ERROR implicit elided lifetime not allowed here
-}
+impl MyTrait for u32 {}
+//~^ ERROR implicit elided lifetime not allowed here
fn main() {}
error[E0726]: implicit elided lifetime not allowed here
--> $DIR/trait-elided.rs:5:6
|
-LL | impl MyTrait for u32 {
- | ^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+LL | impl MyTrait for u32 {}
+ | ^^^^^^^ expected lifetime parameter
|
= note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+ |
+LL | impl MyTrait<'_> for u32 {}
+ | ++++
error: aborting due to previous error
-trait Serializable<'self, T> { //~ ERROR lifetimes cannot use keyword names
- fn serialize(val : &'self T) -> Vec<u8>; //~ ERROR lifetimes cannot use keyword names
- fn deserialize(repr : &[u8]) -> &'self T; //~ ERROR lifetimes cannot use keyword names
+trait Serializable<'self, T> {
+ //~^ ERROR lifetimes cannot use keyword names
+ fn serialize(val: &'self T) -> Vec<u8>; //~ ERROR lifetimes cannot use keyword names
+ fn deserialize(repr: &[u8]) -> &'self T; //~ ERROR lifetimes cannot use keyword names
}
-impl<'self> Serializable<str> for &'self str { //~ ERROR lifetimes cannot use keyword names
+impl<'self> Serializable<str> for &'self str {
//~^ ERROR lifetimes cannot use keyword names
+ //~| ERROR lifetimes cannot use keyword names
//~| ERROR implicit elided lifetime not allowed here
- //~| ERROR the size for values of type `str` cannot be known at compilation time
- fn serialize(val : &'self str) -> Vec<u8> { //~ ERROR lifetimes cannot use keyword names
+ //~| ERROR the size for values of type `str` cannot be known at compilation time [E0277]
+ fn serialize(val: &'self str) -> Vec<u8> {
+ //~^ ERROR lifetimes cannot use keyword names
vec![1]
}
- fn deserialize(repr: &[u8]) -> &'self str { //~ ERROR lifetimes cannot use keyword names
+ fn deserialize(repr: &[u8]) -> &'self str {
+ //~^ ERROR lifetimes cannot use keyword names
"hi"
}
}
| ^^^^^
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:2:25
+ --> $DIR/issue-10412.rs:3:24
|
-LL | fn serialize(val : &'self T) -> Vec<u8>;
- | ^^^^^
+LL | fn serialize(val: &'self T) -> Vec<u8>;
+ | ^^^^^
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:3:38
+ --> $DIR/issue-10412.rs:4:37
|
-LL | fn deserialize(repr : &[u8]) -> &'self T;
- | ^^^^^
+LL | fn deserialize(repr: &[u8]) -> &'self T;
+ | ^^^^^
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:6:6
+ --> $DIR/issue-10412.rs:7:6
|
LL | impl<'self> Serializable<str> for &'self str {
| ^^^^^
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:6:36
+ --> $DIR/issue-10412.rs:7:36
|
LL | impl<'self> Serializable<str> for &'self str {
| ^^^^^
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:10:25
+ --> $DIR/issue-10412.rs:12:24
|
-LL | fn serialize(val : &'self str) -> Vec<u8> {
- | ^^^^^
+LL | fn serialize(val: &'self str) -> Vec<u8> {
+ | ^^^^^
error: lifetimes cannot use keyword names
- --> $DIR/issue-10412.rs:13:37
+ --> $DIR/issue-10412.rs:16:37
|
LL | fn deserialize(repr: &[u8]) -> &'self str {
| ^^^^^
error[E0726]: implicit elided lifetime not allowed here
- --> $DIR/issue-10412.rs:6:13
+ --> $DIR/issue-10412.rs:7:13
|
LL | impl<'self> Serializable<str> for &'self str {
- | ^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Serializable<'_, str>`
+ | ^^^^^^^^^^^^^^^^^ expected lifetime parameter
|
= note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+ |
+LL | impl<'self> Serializable<'_, str> for &'self str {
+ | +++
error[E0277]: the size for values of type `str` cannot be known at compilation time
- --> $DIR/issue-10412.rs:6:13
+ --> $DIR/issue-10412.rs:7:13
|
LL | impl<'self> Serializable<str> for &'self str {
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
--> $DIR/issue-91763.rs:8:20
|
LL | fn f() -> Ptr<Thing>;
- | ^ expected named lifetime parameter
+ | ^ expected lifetime parameter
|
note: the lint level is defined here
--> $DIR/issue-91763.rs:3:9
|
LL | #![deny(elided_lifetimes_in_paths)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: indicate the anonymous lifetime
+ |
+LL | fn f() -> Ptr<Thing><'_>;
+ | ++++
error: aborting due to previous error
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9
|
+LL | #[derive(Eq, PartialEq)]
+ | -- lifetime `'b` is missing in item created through this procedural macro
LL | struct Test {
| - help: consider introducing lifetime `'b` here: `<'b>`
LL | a: &'b str,
|
help: consider introducing lifetime `'b` here
|
-LL | impl<'b> T for Test {
- | ++++
-help: consider introducing lifetime `'b` here
- |
LL | fn foo<'b>(&'b self) {}
| ++++
+help: consider introducing lifetime `'b` here
+ |
+LL | impl<'b> T for Test {
+ | ++++
error: aborting due to 3 previous errors
--> $DIR/allowed-by-default-lint.rs:9:12
|
LL | fn foo(x: &Foo) {}
- | ^^^ expected named lifetime parameter
+ | ^^^ expected lifetime parameter
|
= note: requested on the command line with `--force-warn elided-lifetimes-in-paths`
-help: consider using the `'_` lifetime
+help: indicate the anonymous lifetime
|
LL | fn foo(x: &Foo<'_>) {}
- | ~~~~~~~
+ | ++++
warning: 1 warning emitted
impl fmt::Debug for CheaterDetectionMechanism {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
//~^ WARN hidden lifetime parameters in types are deprecated
- //~| NOTE expected named lifetime parameter
+ //~| NOTE expected lifetime parameter
//~| NOTE explicit anonymous lifetimes aid
- //~| HELP consider using the `'_` lifetime
+ //~| HELP indicate the anonymous lifetime
fmt.debug_struct("CheaterDetectionMechanism").finish()
}
}
--> $DIR/reasons.rs:20:34
|
LL | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- | ^^^^^^^^^ expected named lifetime parameter
+ | -----^^^^^^^^^
+ | |
+ | expected lifetime parameter
|
= note: explicit anonymous lifetimes aid reasoning about ownership
note: the lint level is defined here
|
LL | #![warn(elided_lifetimes_in_paths,
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-help: consider using the `'_` lifetime
+help: indicate the anonymous lifetime
|
LL | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- | ~~~~~~~~~~~~~
+ | ++++
warning: variable `Social_exchange_psychology` should have a snake case name
--> $DIR/reasons.rs:30:9
fn main() {
- 0.clone::<'a>(); //~ ERROR use of undeclared lifetime name `'a`
+ 0.clone::<'a>();
+ //~^ ERROR use of undeclared lifetime name `'a`
+ //~| WARN cannot specify lifetime arguments explicitly if late bound
+ //~| WARN this was previously accepted by the compiler
}
LL | 0.clone::<'a>();
| ^^ undeclared lifetime
-error: aborting due to previous error
+warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+ --> $DIR/method-call-lifetime-args-unresolved.rs:2:15
+ |
+LL | 0.clone::<'a>();
+ | ^^
+ |
+ ::: $SRC_DIR/core/src/clone.rs:LL:COL
+ |
+LL | fn clone(&self) -> Self;
+ | - the late bound lifetime parameter is introduced here
+ |
+ = note: `#[warn(late_bound_lifetime_arguments)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
+
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0261`.
-struct Foo<'static> { //~ ERROR invalid lifetime parameter name: `'static`
- x: &'static isize
+struct Foo<'static> {
+ //~^ ERROR invalid lifetime parameter name: `'static`
+ x: &'static isize,
}
fn main() {}
let y: &'a isize = x;
// &'a is not visible to *items*:
- type X = Option<&'a isize>; //~ ERROR undeclared lifetime
+ type X = Option<&'a isize>; //~ ERROR can't use generic parameters from outer item
enum E {
- E1(&'a isize) //~ ERROR undeclared lifetime
+ E1(&'a isize) //~ ERROR can't use generic parameters from outer item
}
struct S {
- f: &'a isize //~ ERROR undeclared lifetime
+ f: &'a isize //~ ERROR can't use generic parameters from outer item
}
- fn f(a: &'a isize) { } //~ ERROR undeclared lifetime
+ fn f(a: &'a isize) { } //~ ERROR can't use generic parameters from outer item
// &'a CAN be declared on functions and used then:
fn g<'a>(a: &'a isize) { } // OK
-error[E0261]: use of undeclared lifetime name `'a`
- --> $DIR/regions-name-undeclared.rs:28:13
- |
-LL | enum E {
- | - help: consider introducing lifetime `'a` here: `<'a>`
-LL | E1(&'a isize)
- | ^^ undeclared lifetime
-
-error[E0261]: use of undeclared lifetime name `'a`
- --> $DIR/regions-name-undeclared.rs:31:13
- |
-LL | struct S {
- | - help: consider introducing lifetime `'a` here: `<'a>`
-LL | f: &'a isize
- | ^^ undeclared lifetime
-
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/regions-name-undeclared.rs:16:24
|
|
help: consider introducing lifetime `'b` here
|
-LL | impl<'b, 'a> Foo<'a> {
- | +++
-help: consider introducing lifetime `'b` here
- |
LL | fn m4<'b>(&self, arg: &'b isize) { }
| ++++
+help: consider introducing lifetime `'b` here
+ |
+LL | impl<'b, 'a> Foo<'a> {
+ | +++
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/regions-name-undeclared.rs:17:12
|
help: consider introducing lifetime `'b` here
|
-LL | impl<'b, 'a> Foo<'a> {
- | +++
-help: consider introducing lifetime `'b` here
- |
LL | fn m5<'b>(&'b self) { }
| ++++
+help: consider introducing lifetime `'b` here
+ |
+LL | impl<'b, 'a> Foo<'a> {
+ | +++
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/regions-name-undeclared.rs:18:27
|
help: consider introducing lifetime `'b` here
|
-LL | impl<'b, 'a> Foo<'a> {
- | +++
-help: consider introducing lifetime `'b` here
- |
LL | fn m6<'b>(&self, arg: Foo<'b>) { }
| ++++
+help: consider introducing lifetime `'b` here
+ |
+LL | impl<'b, 'a> Foo<'a> {
+ | +++
-error[E0261]: use of undeclared lifetime name `'a`
+error[E0401]: can't use generic parameters from outer item
--> $DIR/regions-name-undeclared.rs:26:22
|
+LL | fn bar<'a>(x: &'a isize) {
+ | -- lifetime parameter from outer item
+...
LL | type X = Option<&'a isize>;
- | - ^^ undeclared lifetime
+ | - ^^ use of generic parameter from outer item
| |
| help: consider introducing lifetime `'a` here: `<'a>`
-error[E0261]: use of undeclared lifetime name `'a`
+error[E0401]: can't use generic parameters from outer item
+ --> $DIR/regions-name-undeclared.rs:28:13
+ |
+LL | fn bar<'a>(x: &'a isize) {
+ | -- lifetime parameter from outer item
+...
+LL | enum E {
+ | - help: consider introducing lifetime `'a` here: `<'a>`
+LL | E1(&'a isize)
+ | ^^ use of generic parameter from outer item
+
+error[E0401]: can't use generic parameters from outer item
+ --> $DIR/regions-name-undeclared.rs:31:13
+ |
+LL | fn bar<'a>(x: &'a isize) {
+ | -- lifetime parameter from outer item
+...
+LL | struct S {
+ | - help: consider introducing lifetime `'a` here: `<'a>`
+LL | f: &'a isize
+ | ^^ use of generic parameter from outer item
+
+error[E0401]: can't use generic parameters from outer item
--> $DIR/regions-name-undeclared.rs:33:14
|
+LL | fn bar<'a>(x: &'a isize) {
+ | -- lifetime parameter from outer item
+...
LL | fn f(a: &'a isize) { }
- | - ^^ undeclared lifetime
+ | - ^^ use of generic parameter from outer item
| |
| help: consider introducing lifetime `'a` here: `<'a>`
| ^^ undeclared lifetime
|
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+ |
+LL | b: Box<dyn for<'b, 'a> FnOnce(&'a isize,
+ | +++
help: consider introducing lifetime `'b` here
|
LL | fn fn_types<'b>(a: &'a isize,
| ++++
-help: consider making the bound lifetime-generic with a new `'b` lifetime
- |
-LL | b: Box<dyn for<'a, 'b> FnOnce(&'a isize,
- | ++++
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/regions-name-undeclared.rs:46:36
LL | ... &'b isize)>,
| ^^ undeclared lifetime
|
- = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+ |
+LL | b: Box<dyn for<'b, 'a> FnOnce(&'a isize,
+ | +++
help: consider introducing lifetime `'b` here
|
LL | fn fn_types<'b>(a: &'a isize,
| ++++
-help: consider making the bound lifetime-generic with a new `'b` lifetime
- |
-LL | b: Box<dyn for<'a, 'b> FnOnce(&'a isize,
- | ++++
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-name-undeclared.rs:47:17
|
help: consider introducing lifetime `'a` here
|
-LL | impl<'a> Bug {
- | ++++
-help: consider introducing lifetime `'a` here
- |
LL | async fn buggy<'a>(&self) -> &'a str {
| ++++
+help: consider introducing lifetime `'a` here
+ |
+LL | impl<'a> Bug {
+ | ++++
error: aborting due to 12 previous errors
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0261, E0401.
+For more information about an error, try `rustc --explain E0261`.
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:36:8
+ --> $DIR/rfc1623.rs:32:8
|
LL | f: &id,
| ^^^ implementation of `FnOnce` is not general enough
error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:29:35
+ --> $DIR/rfc1623.rs:32:8
|
-LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
- | ___________________________________^
-LL | |
-LL | |
-LL | |
-... |
-LL | |
-LL | | };
- | |_^ one type is more general than the other
+LL | f: &id,
+ | ^^^ one type is more general than the other
|
= note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
found type `Fn<(&Foo<'_>,)>`
error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:29:35
+ --> $DIR/rfc1623.rs:32:8
|
-LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
- | ___________________________________^
-LL | |
-LL | |
-LL | |
-... |
-LL | |
-LL | | };
- | |_^ one type is more general than the other
+LL | f: &id,
+ | ^^^ one type is more general than the other
|
= note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
found type `Fn<(&Foo<'_>,)>`
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:29:35
+ --> $DIR/rfc1623.rs:32:8
|
-LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
- | ___________________________________^
-LL | |
-LL | |
-LL | |
-... |
-LL | |
-LL | | };
- | |_^ implementation of `FnOnce` is not general enough
+LL | f: &id,
+ | ^^^ implementation of `FnOnce` is not general enough
|
= note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:29:35
+ --> $DIR/rfc1623.rs:32:8
|
-LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
- | ___________________________________^
-LL | |
-LL | |
-LL | |
-... |
-LL | |
-LL | | };
- | |_^ implementation of `FnOnce` is not general enough
+LL | f: &id,
+ | ^^^ implementation of `FnOnce` is not general enough
|
= note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
}
static SOME_STRUCT: &SomeStruct = &SomeStruct {
- //[nll]~^ ERROR mismatched types
- //[nll]~| ERROR mismatched types
- //[nll]~| ERROR implementation of `FnOnce` is not general enough
- //[nll]~| ERROR implementation of `FnOnce` is not general enough
foo: &Foo { bools: &[false, true] },
bar: &Bar { bools: &[true, true] },
f: &id,
//[base]~^ ERROR implementation of `FnOnce` is not general enough
+ //[nll]~^^ ERROR mismatched types
+ //[nll]~| ERROR mismatched types
+ //[nll]~| ERROR implementation of `FnOnce` is not general enough
+ //[nll]~| ERROR implementation of `FnOnce` is not general enough
};
// very simple test for a 'static static with default lifetime
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:52
+ |
+LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+ | ---- ---- ^ ...but data from `f` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:82
+ |
+LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+ | ---- ----------------- ^ ...but data from `f` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:22:64
+ |
+LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+ | ------ --- ^^^ ...but data from `arg` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:52
|
LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
| - - ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
| let's call the lifetime of this reference `'2`
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:75
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:75
|
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| - - ^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
| let's call the lifetime of this reference `'2`
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:22:64
|
LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
| -- - ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
// edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
use std::pin::Pin;
impl Foo {
async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
- //~^ ERROR lifetime mismatch
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ lifetime may not live long enough
async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
- //~^ ERROR lifetime mismatch
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ lifetime may not live long enough
}
type Alias<T> = Pin<T>;
impl Foo {
- async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } //~ ERROR E0623
+ async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+ //[base]~^ ERROR E0623
+ //[nll]~^^ lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
- |
-LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
- | ---- ---- ^ ...but data from `f` is returned here
- | |
- | this parameter and the return type are declared with different lifetimes...
-
-error[E0623]: lifetime mismatch
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:82
- |
-LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
- | ---- ----------------- ^ ...but data from `f` is returned here
- | |
- | this parameter and the return type are declared with different lifetimes...
-
-error[E0623]: lifetime mismatch
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
- |
-LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
- | ------ --- ^^^ ...but data from `arg` is returned here
- | |
- | this parameter and the return type are declared with different lifetimes...
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:46
+ |
+LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+ | ---- ---- ^ ...but data from `f` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:14:76
+ |
+LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+ | ---- ----------------- ^ ...but data from `f` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:21:58
+ |
+LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+ | ------ --- ^^^ ...but data from `arg` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:6:46
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:46
|
LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
| - - ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
| let's call the lifetime of this reference `'2`
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:69
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:14:69
|
LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| - - ^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
| let's call the lifetime of this reference `'2`
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:13:58
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:21:58
|
LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
| -- ---- has type `Pin<&'1 Foo>` ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
use std::pin::Pin;
struct Foo;
impl Foo {
- fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0623
+ fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+ //[base]~^ ERROR E0623
+ //[nll]~^^ lifetime may not live long enough
- fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } //~ ERROR E0623
+ fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+ //[base]~^ ERROR E0623
+ //[nll]~^^ lifetime may not live long enough
}
type Alias<T> = Pin<T>;
impl Foo {
- fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } //~ ERROR E0623
+ fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+ //[base]~^ ERROR E0623
+ //[nll]~^^ lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:6:46
- |
-LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
- | ---- ---- ^ ...but data from `f` is returned here
- | |
- | this parameter and the return type are declared with different lifetimes...
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:76
- |
-LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
- | ---- ----------------- ^ ...but data from `f` is returned here
- | |
- | this parameter and the return type are declared with different lifetimes...
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:13:58
- |
-LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
- | ------ --- ^^^ ...but data from `arg` is returned here
- | |
- | this parameter and the return type are declared with different lifetimes...
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self-async.rs:16:9
+ |
+LL | async fn ref_self(&self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self-async.rs:24:9
+ |
+LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self-async.rs:30:9
+ |
+LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self-async.rs:36:9
+ |
+LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self-async.rs:42:9
+ |
+LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self-async.rs:48:9
+ |
+LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/lt-ref-self-async.rs:13:9
+ --> $DIR/lt-ref-self-async.rs:16:9
|
LL | async fn ref_self(&self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self-async.rs:19:9
+ --> $DIR/lt-ref-self-async.rs:24:9
|
LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self-async.rs:23:9
+ --> $DIR/lt-ref-self-async.rs:30:9
|
LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self-async.rs:27:9
+ --> $DIR/lt-ref-self-async.rs:36:9
|
LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self-async.rs:31:9
+ --> $DIR/lt-ref-self-async.rs:42:9
|
LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self-async.rs:35:9
+ --> $DIR/lt-ref-self-async.rs:48:9
|
LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
// edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
#![allow(non_snake_case)]
// Test using `&self` sugar:
async fn ref_self(&self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// Test using `&Self` explicitly:
async fn ref_Self(self: &Self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self-async.rs:13:9
- |
-LL | async fn ref_self(&self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self-async.rs:19:9
- |
-LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self-async.rs:23:9
- |
-LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self-async.rs:27:9
- |
-LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self-async.rs:31:9
- |
-LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self-async.rs:35:9
- |
-LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:15:9
+ |
+LL | fn ref_self(&self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:23:9
+ |
+LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:29:9
+ |
+LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:35:9
+ |
+LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:41:9
+ |
+LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:47:9
+ |
+LL | fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/lt-ref-self.rs:11:9
+ --> $DIR/lt-ref-self.rs:15:9
|
LL | fn ref_self(&self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self.rs:17:9
+ --> $DIR/lt-ref-self.rs:23:9
|
LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self.rs:21:9
+ --> $DIR/lt-ref-self.rs:29:9
|
LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self.rs:25:9
+ --> $DIR/lt-ref-self.rs:35:9
|
LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self.rs:29:9
+ --> $DIR/lt-ref-self.rs:41:9
|
LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self.rs:33:9
+ --> $DIR/lt-ref-self.rs:47:9
|
LL | fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![allow(non_snake_case)]
use std::pin::Pin;
// Test using `&self` sugar:
fn ref_self(&self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// Test using `&Self` explicitly:
fn ref_Self(self: &Self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self.rs:11:9
- |
-LL | fn ref_self(&self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self.rs:17:9
- |
-LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self.rs:21:9
- |
-LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self.rs:25:9
- |
-LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self.rs:29:9
- |
-LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self.rs:33:9
- |
-LL | fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self-async.rs:16:9
+ |
+LL | async fn ref_self(&mut self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self-async.rs:24:9
+ |
+LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self-async.rs:30:9
+ |
+LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self-async.rs:36:9
+ |
+LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self-async.rs:42:9
+ |
+LL | async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self-async.rs:48:9
+ |
+LL | async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-mut-self-async.rs:13:9
+ --> $DIR/ref-mut-self-async.rs:16:9
|
LL | async fn ref_self(&mut self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self-async.rs:19:9
+ --> $DIR/ref-mut-self-async.rs:24:9
|
LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self-async.rs:23:9
+ --> $DIR/ref-mut-self-async.rs:30:9
|
LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self-async.rs:27:9
+ --> $DIR/ref-mut-self-async.rs:36:9
|
LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self-async.rs:31:9
+ --> $DIR/ref-mut-self-async.rs:42:9
|
LL | async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self-async.rs:35:9
+ --> $DIR/ref-mut-self-async.rs:48:9
|
LL | async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
// edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
#![allow(non_snake_case)]
// Test using `&mut self` sugar:
async fn ref_self(&mut self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// Test using `&mut Self` explicitly:
async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self-async.rs:13:9
- |
-LL | async fn ref_self(&mut self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self-async.rs:19:9
- |
-LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self-async.rs:23:9
- |
-LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self-async.rs:27:9
- |
-LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self-async.rs:31:9
- |
-LL | async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self-async.rs:35:9
- |
-LL | async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:15:9
+ |
+LL | fn ref_self(&mut self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:23:9
+ |
+LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:29:9
+ |
+LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:35:9
+ |
+LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:41:9
+ |
+LL | fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:47:9
+ |
+LL | fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-mut-self.rs:11:9
+ --> $DIR/ref-mut-self.rs:15:9
|
LL | fn ref_self(&mut self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self.rs:17:9
+ --> $DIR/ref-mut-self.rs:23:9
|
LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self.rs:21:9
+ --> $DIR/ref-mut-self.rs:29:9
|
LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self.rs:25:9
+ --> $DIR/ref-mut-self.rs:35:9
|
LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self.rs:29:9
+ --> $DIR/ref-mut-self.rs:41:9
|
LL | fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self.rs:33:9
+ --> $DIR/ref-mut-self.rs:47:9
|
LL | fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![allow(non_snake_case)]
use std::pin::Pin;
// Test using `&mut self` sugar:
fn ref_self(&mut self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// Test using `&mut Self` explicitly:
fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self.rs:11:9
- |
-LL | fn ref_self(&mut self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self.rs:17:9
- |
-LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self.rs:21:9
- |
-LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self.rs:25:9
- |
-LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self.rs:29:9
- |
-LL | fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self.rs:33:9
- |
-LL | fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct-async.rs:16:9
+ |
+LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct-async.rs:22:9
+ |
+LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct-async.rs:28:9
+ |
+LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct-async.rs:34:9
+ |
+LL | async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct-async.rs:40:9
+ |
+LL | async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct-async.rs:13:9
+ --> $DIR/ref-mut-struct-async.rs:16:9
|
LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct-async.rs:17:9
+ --> $DIR/ref-mut-struct-async.rs:22:9
|
LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct-async.rs:21:9
+ --> $DIR/ref-mut-struct-async.rs:28:9
|
LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct-async.rs:25:9
+ --> $DIR/ref-mut-struct-async.rs:34:9
|
LL | async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct-async.rs:29:9
+ --> $DIR/ref-mut-struct-async.rs:40:9
|
LL | async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
// edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
#![allow(non_snake_case)]
// Test using `&mut Struct` explicitly:
async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct-async.rs:13:9
- |
-LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct-async.rs:17:9
- |
-LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct-async.rs:21:9
- |
-LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct-async.rs:25:9
- |
-LL | async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct-async.rs:29:9
- |
-LL | async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:15:9
+ |
+LL | fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:21:9
+ |
+LL | fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:27:9
+ |
+LL | fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:33:9
+ |
+LL | fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:39:9
+ |
+LL | fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct.rs:11:9
+ --> $DIR/ref-mut-struct.rs:15:9
|
LL | fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct.rs:15:9
+ --> $DIR/ref-mut-struct.rs:21:9
|
LL | fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct.rs:19:9
+ --> $DIR/ref-mut-struct.rs:27:9
|
LL | fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct.rs:23:9
+ --> $DIR/ref-mut-struct.rs:33:9
|
LL | fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct.rs:27:9
+ --> $DIR/ref-mut-struct.rs:39:9
|
LL | fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![allow(non_snake_case)]
use std::pin::Pin;
// Test using `&mut Struct` explicitly:
fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct.rs:11:9
- |
-LL | fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct.rs:15:9
- |
-LL | fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct.rs:19:9
- |
-LL | fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct.rs:23:9
- |
-LL | fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct.rs:27:9
- |
-LL | fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:26:9
+ |
+LL | async fn ref_self(&self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:34:9
+ |
+LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:40:9
+ |
+LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:46:9
+ |
+LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:52:9
+ |
+LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:58:9
+ |
+LL | async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:64:9
+ |
+LL | async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
+ | --- ---
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:23:9
+ --> $DIR/ref-self-async.rs:26:9
|
LL | async fn ref_self(&self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:29:9
+ --> $DIR/ref-self-async.rs:34:9
|
LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:33:9
+ --> $DIR/ref-self-async.rs:40:9
|
LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:37:9
+ --> $DIR/ref-self-async.rs:46:9
|
LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:41:9
+ --> $DIR/ref-self-async.rs:52:9
|
LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:45:9
+ --> $DIR/ref-self-async.rs:58:9
|
LL | async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:49:9
+ --> $DIR/ref-self-async.rs:64:9
|
LL | async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
| - - let's call the lifetime of this reference `'1`
// edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
#![allow(non_snake_case)]
#![feature(arbitrary_self_types)]
// Test using `&self` sugar:
async fn ref_self(&self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// Test using `&Self` explicitly:
async fn ref_Self(self: &Self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:23:9
- |
-LL | async fn ref_self(&self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:29:9
- |
-LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:33:9
- |
-LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:37:9
- |
-LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:41:9
- |
-LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:45:9
- |
-LL | async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:49:9
- |
-LL | async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
- | --- ---
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:25:9
+ |
+LL | fn ref_self(&self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:33:9
+ |
+LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:39:9
+ |
+LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:45:9
+ |
+LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:51:9
+ |
+LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:57:9
+ |
+LL | fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:63:9
+ |
+LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
+ | --- ---
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
+ | ++++ ++ ++
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:21:9
+ --> $DIR/ref-self.rs:25:9
|
LL | fn ref_self(&self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:27:9
+ --> $DIR/ref-self.rs:33:9
|
LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:31:9
+ --> $DIR/ref-self.rs:39:9
|
LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:35:9
+ --> $DIR/ref-self.rs:45:9
|
LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:39:9
+ --> $DIR/ref-self.rs:51:9
|
LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:43:9
+ --> $DIR/ref-self.rs:57:9
|
LL | fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:47:9
+ --> $DIR/ref-self.rs:63:9
|
LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
| - - let's call the lifetime of this reference `'1`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]
// Test using `&self` sugar:
fn ref_self(&self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// Test using `&Self` explicitly:
fn ref_Self(self: &Self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:21:9
- |
-LL | fn ref_self(&self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:27:9
- |
-LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:31:9
- |
-LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:35:9
- |
-LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:39:9
- |
-LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:43:9
- |
-LL | fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:47:9
- |
-LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
- | --- ---
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
- | ++++ ++ ++
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct-async.rs:16:9
+ |
+LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct-async.rs:22:9
+ |
+LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct-async.rs:28:9
+ |
+LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct-async.rs:34:9
+ |
+LL | async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct-async.rs:40:9
+ |
+LL | async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-struct-async.rs:13:9
+ --> $DIR/ref-struct-async.rs:16:9
|
LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct-async.rs:17:9
+ --> $DIR/ref-struct-async.rs:22:9
|
LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct-async.rs:21:9
+ --> $DIR/ref-struct-async.rs:28:9
|
LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct-async.rs:25:9
+ --> $DIR/ref-struct-async.rs:34:9
|
LL | async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct-async.rs:29:9
+ --> $DIR/ref-struct-async.rs:40:9
|
LL | async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
// edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
#![allow(non_snake_case)]
// Test using `&Struct` explicitly:
async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct-async.rs:13:9
- |
-LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct-async.rs:17:9
- |
-LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct-async.rs:21:9
- |
-LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct-async.rs:25:9
- |
-LL | async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct-async.rs:29:9
- |
-LL | async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:15:9
+ |
+LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:21:9
+ |
+LL | fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:27:9
+ |
+LL | fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:33:9
+ |
+LL | fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:39:9
+ |
+LL | fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-struct.rs:11:9
+ --> $DIR/ref-struct.rs:15:9
|
LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct.rs:15:9
+ --> $DIR/ref-struct.rs:21:9
|
LL | fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct.rs:19:9
+ --> $DIR/ref-struct.rs:27:9
|
LL | fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct.rs:23:9
+ --> $DIR/ref-struct.rs:33:9
|
LL | fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct.rs:27:9
+ --> $DIR/ref-struct.rs:39:9
|
LL | fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![allow(non_snake_case)]
use std::pin::Pin;
// Test using `&Struct` explicitly:
fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct.rs:11:9
- |
-LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct.rs:15:9
- |
-LL | fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct.rs:19:9
- |
-LL | fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct.rs:23:9
- |
-LL | fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct.rs:27:9
- |
-LL | fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
static VOID2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
-//~| ERROR undefined behavior to use this value
+//~| ERROR could not evaluate static initializer
//~| WARN: type `Void` does not permit zero-initialization
static NEVER2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
-//~| ERROR undefined behavior to use this value
+//~| ERROR could not evaluate static initializer
//~| WARN: type `Void` does not permit zero-initialization
fn main() {}
= note: for more information, see issue #74840 <https://github.com/rust-lang/rust/issues/74840>
= note: uninhabited statics cannot be initialized, and any access would be an immediate error
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/uninhabited-static.rs:12:1
+error[E0080]: could not evaluate static initializer
+ --> $DIR/uninhabited-static.rs:12:31
|
LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 0, align: 1) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/uninhabited-static.rs:16:1
+error[E0080]: could not evaluate static initializer
+ --> $DIR/uninhabited-static.rs:16:32
|
LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 0, align: 1) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
warning: the type `Void` does not permit zero-initialization
--> $DIR/uninhabited-static.rs:12:31
| ^^ undeclared lifetime
|
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
-help: consider introducing lifetime `'a` here
- |
-LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F);
- | +++
help: consider making the bound lifetime-generic with a new `'a` lifetime
|
LL | struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
| +++++++
+help: consider introducing lifetime `'a` here
+ |
+LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F);
+ | +++
error[E0106]: missing lifetime specifier
--> $DIR/fn-missing-lifetime-in-item.rs:2:32
--- /dev/null
+error[E0261]: use of undeclared lifetime name `'a`
+ --> $DIR/missing-lifetimes-in-signature.rs:38:11
+ |
+LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | - ^^ undeclared lifetime
+ | |
+ | help: consider introducing lifetime `'a` here: `'a,`
+
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/missing-lifetimes-in-signature.rs:19:5
+ |
+LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
+ | ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 22:6]` captures the anonymous lifetime defined here
+...
+LL | / move || {
+LL | |
+LL | | *dest = g.get();
+LL | | }
+ | |_____^
+ |
+help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:32:5
+ |
+LL | / move || {
+LL | | *dest = g.get();
+LL | | }
+ | |_____^
+ |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+ --> $DIR/missing-lifetimes-in-signature.rs:26:26
+ |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | ^^^^^^
+
+error[E0311]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:55:5
+ |
+LL | / move || {
+LL | | *dest = g.get();
+LL | | }
+ | |_____^
+ |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+ --> $DIR/missing-lifetimes-in-signature.rs:49:34
+ |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | ^^^^^^
+
+error[E0311]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:65:9
+ |
+LL | / move || {
+LL | | *dest = g.get();
+LL | | }
+ | |_________^
+ |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+ --> $DIR/missing-lifetimes-in-signature.rs:62:47
+ |
+LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+ | ^^^^^^
+
+error[E0311]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:77:5
+ |
+LL | / move || {
+LL | | *dest = g.get();
+LL | | }
+ | |_____^
+ |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+ --> $DIR/missing-lifetimes-in-signature.rs:72:34
+ |
+LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+ | ^^^^^^
+
+error[E0621]: explicit lifetime required in the type of `dest`
+ --> $DIR/missing-lifetimes-in-signature.rs:77:5
+ |
+LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+ | ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T`
+...
+LL | / move || {
+LL | | *dest = g.get();
+LL | | }
+ | |_____^ lifetime `'a` required
+
+error[E0309]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:89:5
+ |
+LL | / move || {
+LL | | *dest = g.get();
+LL | | }
+ | |_____^
+ |
+ = help: consider adding an explicit lifetime bound `G: 'a`...
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0261, E0309, E0621, E0700.
+For more information about an error, try `rustc --explain E0261`.
fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
where
- G: Get<T>
+ G: Get<T>,
{
move || {
+ //~^ ERROR hidden type for `impl Trait` captures lifetime
*dest = g.get();
}
}
// After applying suggestion for `foo`:
fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+//~^ ERROR the parameter type `G` may not live long enough
where
- G: Get<T>
+ G: Get<T>,
{
+ //~^ ERROR the parameter type `G` may not live long enough
move || {
*dest = g.get();
}
}
-
// After applying suggestion for `bar`:
-fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ //~ ERROR undeclared lifetime
+fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+//~^ ERROR undeclared lifetime name `'a`
where
- G: Get<T>
+ G: Get<T>,
{
move || {
*dest = g.get();
// After applying suggestion for `baz`:
fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+//~^ ERROR the parameter type `G` may not live long enough
where
- G: Get<T>
+ G: Get<T>,
{
+ //~^ ERROR the parameter type `G` may not live long enough
move || {
*dest = g.get();
}
// Same as above, but show that we pay attention to lifetime names from parent item
impl<'a> Foo {
fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+ //~^ ERROR the parameter type `G` may not live long enough
+ //~| ERROR the parameter type `G` may not live long enough
move || {
*dest = g.get();
}
// After applying suggestion for `qux`:
fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+//~^ ERROR explicit lifetime required in the type of `dest`
where
- G: Get<T>
+ G: Get<T>,
{
move || {
*dest = g.get();
// Potential incorrect attempt:
fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
+//~^ ERROR the parameter type `G` may not live long enough
where
- G: Get<T>
+ G: Get<T>,
{
+ //~^ ERROR the parameter type `G` may not live long enough
move || {
*dest = g.get();
}
}
-
// We need to tie the lifetime of `G` with the lifetime of `&mut T` and the returned closure:
fn ok<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
where
- G: Get<T>
+ G: Get<T>,
{
move || {
*dest = g.get();
// This also works. The `'_` isn't necessary but it's where we arrive to following the suggestions:
fn ok2<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a
where
- G: Get<T>
+ G: Get<T>,
{
move || {
*dest = g.get();
error[E0261]: use of undeclared lifetime name `'a`
- --> $DIR/missing-lifetimes-in-signature.rs:36:11
+ --> $DIR/missing-lifetimes-in-signature.rs:38:11
|
LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'a` here: `'a,`
-error: aborting due to previous error
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/missing-lifetimes-in-signature.rs:19:5
+ |
+LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
+ | ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 22:6]` captures the anonymous lifetime defined here
+...
+LL | / move || {
+LL | |
+LL | | *dest = g.get();
+LL | | }
+ | |_____^
+ |
+help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:26:37
+ |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | ^^^^^^^^^^^^^^^^^^
+ |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+ --> $DIR/missing-lifetimes-in-signature.rs:26:26
+ |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:32:5: 34:6]` will meet its required lifetime bounds
+ --> $DIR/missing-lifetimes-in-signature.rs:26:37
+ |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | ^^^^^^^^^^^^^^^^^^
+help: consider introducing an explicit lifetime bound
+ |
+LL | fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+ | ~~~~~ ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:30:1
+ |
+LL | / {
+LL | |
+LL | | move || {
+LL | | *dest = g.get();
+LL | | }
+LL | | }
+ | |_^
+ |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+ --> $DIR/missing-lifetimes-in-signature.rs:26:26
+ |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:32:5: 34:6]` will meet its required lifetime bounds
+ --> $DIR/missing-lifetimes-in-signature.rs:30:1
+ |
+LL | / {
+LL | |
+LL | | move || {
+LL | | *dest = g.get();
+LL | | }
+LL | | }
+ | |_^
+help: consider introducing an explicit lifetime bound
+ |
+LL ~ fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+LL |
+LL | where
+LL | G: Get<T>,
+LL | {
+LL |
+ ...
+
+error[E0311]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:49:45
+ |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | ^^^^^^^^^^^^^^^^^^
+ |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+ --> $DIR/missing-lifetimes-in-signature.rs:49:34
+ |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:55:5: 57:6]` will meet its required lifetime bounds
+ --> $DIR/missing-lifetimes-in-signature.rs:49:45
+ |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | ^^^^^^^^^^^^^^^^^^
+help: consider introducing an explicit lifetime bound
+ |
+LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b
+ | +++ ~~~~~~~ ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:53:1
+ |
+LL | / {
+LL | |
+LL | | move || {
+LL | | *dest = g.get();
+LL | | }
+LL | | }
+ | |_^
+ |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+ --> $DIR/missing-lifetimes-in-signature.rs:49:34
+ |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:55:5: 57:6]` will meet its required lifetime bounds
+ --> $DIR/missing-lifetimes-in-signature.rs:53:1
+ |
+LL | / {
+LL | |
+LL | | move || {
+LL | | *dest = g.get();
+LL | | }
+LL | | }
+ | |_^
+help: consider introducing an explicit lifetime bound
+ |
+LL ~ fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+LL |
+LL | where
+LL | G: Get<T>,
+LL | {
+LL |
+ ...
+
+error[E0311]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:62:58
+ |
+LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+ | ^^^^^^^^^^^^^^^^^^
+ |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+ --> $DIR/missing-lifetimes-in-signature.rs:62:47
+ |
+LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+ | ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:65:9: 67:10]` will meet its required lifetime bounds
+ --> $DIR/missing-lifetimes-in-signature.rs:62:58
+ |
+LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+ | ^^^^^^^^^^^^^^^^^^
+help: consider introducing an explicit lifetime bound
+ |
+LL | fn qux<'c, 'b, G: 'c + Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c {
+ | +++ ~~~~~~~ ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:62:77
+ |
+LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+ | _____________________________________________________________________________^
+LL | |
+LL | |
+LL | | move || {
+LL | | *dest = g.get();
+LL | | }
+LL | | }
+ | |_____^
+ |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+ --> $DIR/missing-lifetimes-in-signature.rs:62:47
+ |
+LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+ | ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:65:9: 67:10]` will meet its required lifetime bounds
+ --> $DIR/missing-lifetimes-in-signature.rs:62:77
+ |
+LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+ | _____________________________________________________________________________^
+LL | |
+LL | |
+LL | | move || {
+LL | | *dest = g.get();
+LL | | }
+LL | | }
+ | |_____^
+help: consider introducing an explicit lifetime bound
+ |
+LL ~ fn qux<'c, 'b, G: 'c + Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+LL |
+LL |
+LL | move || {
+LL | *dest = g.get();
+LL | }
+ ...
+
+error[E0621]: explicit lifetime required in the type of `dest`
+ --> $DIR/missing-lifetimes-in-signature.rs:72:45
+ |
+LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+ | ------ ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
+ | |
+ | help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T`
+
+error[E0309]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:83:44
+ |
+LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
+ | - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:89:5: 91:6]` will meet its required lifetime bounds
+ | |
+ | help: consider adding an explicit lifetime bound...: `G: 'a`
+
+error[E0309]: the parameter type `G` may not live long enough
+ --> $DIR/missing-lifetimes-in-signature.rs:87:1
+ |
+LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
+ | - help: consider adding an explicit lifetime bound...: `G: 'a`
+...
+LL | / {
+LL | |
+LL | | move || {
+LL | | *dest = g.get();
+LL | | }
+LL | | }
+ | |_^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:89:5: 91:6]` will meet its required lifetime bounds
+
+error: aborting due to 11 previous errors
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0261, E0309, E0621, E0700.
+For more information about an error, try `rustc --explain E0261`.
--- /dev/null
+use std::ops::Deref;
+
+struct Foo {
+ v: Vec<u32>,
+}
+
+struct Bar {
+ v: Vec<u32>,
+}
+
+impl Deref for Bar {
+ type Target = Vec<u32>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.v
+ }
+}
+
+fn f(foo: &Foo) {
+ match foo {
+ Foo { v: [1, 2] } => {}
+ //~^ ERROR expected an array or slice, found `Vec<u32>
+ _ => {}
+ }
+}
+
+fn bar(bar: &Bar) {
+ match bar {
+ Bar { v: [1, 2] } => {}
+ //~^ ERROR expected an array or slice, found `Vec<u32>
+ _ => {}
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0529]: expected an array or slice, found `Vec<u32>`
+ --> $DIR/pattern-struct-with-slice-vec-field.rs:21:18
+ |
+LL | Foo { v: [1, 2] } => {}
+ | ^^^^^^ pattern cannot match with input type `Vec<u32>`
+
+error[E0529]: expected an array or slice, found `Vec<u32>`
+ --> $DIR/pattern-struct-with-slice-vec-field.rs:29:18
+ |
+LL | Bar { v: [1, 2] } => {}
+ | ^^^^^^ pattern cannot match with input type `Vec<u32>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0529`.
--> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16
|
LL | i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
- | ^ ------------ help: remove these generic arguments
- | |
- | expected 2 generic arguments
+ | ^ expected 2 generic arguments
|
note: trait defined here, with 2 generic parameters: `X`, `Y`
--> $DIR/use-type-argument-instead-of-assoc-type.rs:1:11
|
LL | pub trait T<X, Y> {
| ^ - -
+help: replace the generic bounds with the associated types
+ |
+LL | i: Box<dyn T<usize, usize, A = usize, C = usize, B=usize>>,
+ | ~~~~~~~~~ ~~~~~~~~~
error[E0191]: the value of the associated types `A` (from trait `T`), `C` (from trait `T`) must be specified
--> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16
...
LL | i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified
- |
-help: specify the associated types
- |
-LL | i: Box<dyn T<usize, usize, A = usize, C = usize, B=usize>>,
- | ~~~~~~~~~ ~~~~~~~~~
error: aborting due to 2 previous errors
//~^ ERROR use of undeclared lifetime name `'a`
fn my_fun() -> Return<()> {}
+//~^ ERROR non-defining opaque type use in defining scope
+//~| ERROR non-defining opaque type use in defining scope
fn main() {}
--> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:65
|
LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
- | - ^^ undeclared lifetime
- | |
- | help: consider introducing lifetime `'a` here: `'a,`
+ | ^^ undeclared lifetime
+ |
+ = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | type Return<A> = impl for<'a> WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+ | +++++++
+help: consider introducing lifetime `'a` here
+ |
+LL | type Return<'a, A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+ | +++
+
+error: non-defining opaque type use in defining scope
+ --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27
+ |
+LL | fn my_fun() -> Return<()> {}
+ | ^^
+ |
+note: used non-generic type `()` for generic parameter
+ --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13
+ |
+LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+ | ^
+
+error: non-defining opaque type use in defining scope
+ --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27
+ |
+LL | fn my_fun() -> Return<()> {}
+ | ^^
+ |
+note: used non-generic type `()` for generic parameter
+ --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13
+ |
+LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+ | ^
-error: aborting due to previous error
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0261`.
//~^ ERROR `'_` cannot be used here
struct Struct<'_> {
-//~^ ERROR `'_` cannot be used here
+ //~^ ERROR `'_` cannot be used here
v: Vec<&'static char>
}
enum Enum<'_> {
-//~^ ERROR `'_` cannot be used here
+ //~^ ERROR `'_` cannot be used here
Variant
}
union Union<'_> {
-//~^ ERROR `'_` cannot be used here
+ //~^ ERROR `'_` cannot be used here
a: u32
}
trait Trait<'_> {
-//~^ ERROR `'_` cannot be used here
+ //~^ ERROR `'_` cannot be used here
}
fn foo<'_>() {
--- /dev/null
+// Verifies that MIR building for a call expression respects
+// privacy when checking if a call return type is uninhabited.
+
+pub mod widget {
+ enum Unimplemented {}
+ pub struct Widget(Unimplemented);
+
+ impl Widget {
+ pub fn new() -> Widget {
+ todo!();
+ }
+ }
+
+ pub fn f() {
+ let x: &mut u32;
+ Widget::new();
+ // Ok. Widget type returned from new is known to be uninhabited
+ // and the following code is considered unreachable.
+ *x = 1;
+ }
+}
+
+fn main() {
+ let y: &mut u32;
+ widget::Widget::new();
+ // Error. Widget type is not known to be uninhabited here,
+ // so the following code is considered reachable.
+ *y = 2; //~ ERROR use of possibly-uninitialized variable
+}
--- /dev/null
+error[E0381]: use of possibly-uninitialized variable: `y`
+ --> $DIR/privately-uninhabited-mir-call.rs:28:5
+ |
+LL | *y = 2;
+ | ^^^^^^ use of possibly-uninitialized `y`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
- --> $DIR/issue-45087-unreachable-unsafe.rs:6:5
+ --> $DIR/issue-45087-unreachable-unsafe.rs:7:5
|
LL | *(1 as *mut u32) = 42;
| ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
|
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-error: aborting due to previous error
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-45087-unreachable-unsafe.rs:17:5
+ |
+LL | *a = 1;
+ | ^^^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-45087-unreachable-unsafe.rs:29:5
+ |
+LL | *b = 1;
+ | ^^^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0133`.
+// Verify that unreachable code undergoes unsafety checks.
// revisions: mir thir
// [thir]compile-flags: -Z thir-unsafeck
*(1 as *mut u32) = 42;
//~^ ERROR dereference of raw pointer is unsafe
}
+
+fn panic() -> ! {
+ panic!();
+}
+
+fn f(a: *mut u32) {
+ panic();
+ *a = 1;
+ //~^ ERROR dereference of raw pointer is unsafe
+}
+
+enum Void {}
+
+fn uninhabited() -> Void {
+ panic!();
+}
+
+fn g(b: *mut u32) {
+ uninhabited();
+ *b = 1;
+ //~^ ERROR dereference of raw pointer is unsafe
+}
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
- --> $DIR/issue-45087-unreachable-unsafe.rs:6:5
+ --> $DIR/issue-45087-unreachable-unsafe.rs:7:5
|
LL | *(1 as *mut u32) = 42;
| ^^^^^^^^^^^^^^^^ dereference of raw pointer
|
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-error: aborting due to previous error
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-45087-unreachable-unsafe.rs:17:5
+ |
+LL | *a = 1;
+ | ^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-45087-unreachable-unsafe.rs:29:5
+ |
+LL | *b = 1;
+ | ^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-// --extern-location with bad location type
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=badloc:in-the-test-file -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
+++ /dev/null
-error: unknown location type `badloc`: use `raw` or `json`
-
+++ /dev/null
-// Default extern location from name and path if one isn't specified
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--error-format json
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
+++ /dev/null
-{"message":"external crate `bar` unused in `extern_loc_defl_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-defl-json.rs","byte_start":146,"byte_end":146,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-defl-json.rs","byte_start":154,"byte_end":179,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"name":"bar"}}],"rendered":"warning: external crate `bar` unused in `extern_loc_defl_json`: remove the dependency or add `use bar as _;`
- --> $DIR/extern-loc-defl-json.rs:7:1
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^
- |
-note: the lint level is defined here
- --> $DIR/extern-loc-defl-json.rs:7:9
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `bar`
-
-"}
-{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted
-
-"}
+++ /dev/null
-// --extern-location with a raw reference
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:[{"malformed -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
+++ /dev/null
-error: `--extern-location`: malformed json location `[{"malformed`
-
+++ /dev/null
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:{"key":123,"value":{}} --error-format json -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
+++ /dev/null
-{"message":"external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":189,"byte_end":189,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":197,"byte_end":222,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"key":123,"value":{}}}],"rendered":"warning: external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`
- --> $DIR/extern-loc-json-json.rs:7:1
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^
- |
-note: the lint level is defined here
- --> $DIR/extern-loc-json-json.rs:7:9
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `bar`
-
-"}
-{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted
-
-"}
+++ /dev/null
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:{"key":123,"value":{}} -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
+++ /dev/null
-warning: external crate `bar` unused in `extern_loc_json`: remove the dependency or add `use bar as _;`
- --> $DIR/extern-loc-json.rs:7:1
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^
- |
-note: the lint level is defined here
- --> $DIR/extern-loc-json.rs:7:9
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `bar`
-
-warning: 1 warning emitted
-
+++ /dev/null
-// --extern-location with a raw reference
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar -Zunstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
+++ /dev/null
-error: `--extern-location`: specify location for extern crate `bar`
-
+++ /dev/null
-// --extern-location with no type
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=missing-loc-type -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
+++ /dev/null
-error: unknown location type `missing-loc-type`: use `raw` or `json`
-
+++ /dev/null
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw:in-the-test-file --error-format json -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
+++ /dev/null
-{"message":"external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":182,"byte_end":182,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":190,"byte_end":215,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar` at `in-the-test-file`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"raw extern location","code":null,"level":"help","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"in-the-test-file","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":"in-the-test-file"}],"rendered":"warning: external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`
- --> $DIR/extern-loc-raw-json.rs:7:1
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^
- |
-note: the lint level is defined here
- --> $DIR/extern-loc-raw-json.rs:7:9
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `bar` at `in-the-test-file`
-
-"}
-{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted
-
-"}
+++ /dev/null
-// --extern-location with a raw reference
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
+++ /dev/null
-error: `--extern-location`: missing `raw` location
-
+++ /dev/null
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw:in-the-test-file -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
+++ /dev/null
-warning: external crate `bar` unused in `extern_loc_raw`: remove the dependency or add `use bar as _;`
- --> $DIR/extern-loc-raw.rs:7:1
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^
- |
-note: the lint level is defined here
- --> $DIR/extern-loc-raw.rs:7:9
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `bar` at `in-the-test-file`
-
-warning: 1 warning emitted
-
| ^
|
= note: requested on the command line with `-W unused-crate-dependencies`
- = help: remove unnecessary dependency `bar`
warning: 1 warning emitted
|
LL | #![warn(unused_crate_dependencies)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `barbar`
warning: 1 warning emitted
|
LL | #![warn(unused_crate_dependencies)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `bar`
warning: 1 warning emitted
| ^
|
= note: requested on the command line with `-W unused-crate-dependencies`
- = help: remove unnecessary dependency `bar`
warning: 1 warning emitted
| ^
|
= note: requested on the command line with `-W unused-crate-dependencies`
- = help: remove unnecessary dependency `bar`
warning: 1 warning emitted
--> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:13:16
|
LL | impl Trait for Ref {}
- | ^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^ expected lifetime parameter
|
= note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+ |
+LL | impl Trait for Ref<'_> {}
+ | ++++
error: incompatible lifetime on type
--> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:21
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/where-lifetime-resolution.rs:6:38
|
-LL | fn f() where
- | - help: consider introducing lifetime `'a` here: `<'a>`
-LL | for<'a> dyn Trait1<'a>: Trait1<'a>, // OK
LL | (dyn for<'a> Trait1<'a>): Trait1<'a>,
| ^^ undeclared lifetime
+ |
+ = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | (dyn for<'a> Trait1<'a>): for<'a> Trait1<'a>,
+ | +++++++
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | for<'a> (dyn for<'a> Trait1<'a>): Trait1<'a>,
+ | +++++++
+help: consider introducing lifetime `'a` here
+ |
+LL | fn f<'a>() where
+ | ++++
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/where-lifetime-resolution.rs:8:52
|
-LL | fn f() where
- | - help: consider introducing lifetime `'b` here: `<'b>`
-...
LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
| ^^ undeclared lifetime
+ |
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+ |
+LL | for<'a> dyn for<'b> Trait2<'a, 'b>: for<'b> Trait2<'a, 'b>,
+ | +++++++
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+ |
+LL | for<'b, 'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
+ | +++
+help: consider introducing lifetime `'b` here
+ |
+LL | fn f<'b>() where
+ | ++++
error: aborting due to 2 previous errors
-Subproject commit dba5baf4345858c591517b24801902a062c399f8
+Subproject commit edffc4ada3d77799e5a04eeafd9b2f843d29fc23
use rustc_ast::ast;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, DefIdTree};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::source_map::Span;
hir::ItemKind::Fn(..) => {
// ignore main()
if it.ident.name == sym::main {
- let def_key = cx.tcx.hir().def_key(it.def_id);
- if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) {
+ let at_root = cx.tcx.local_parent(it.def_id) == Some(CRATE_DEF_ID);
+ if at_root {
return;
}
}
error: unneeded unit return type
- --> $DIR/unused_unit.rs:19:28
+ --> $DIR/unused_unit.rs:19:58
|
LL | pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
- | ^^^^^^ help: remove the `-> ()`
+ | ^^^^^^ help: remove the `-> ()`
|
note: the lint level is defined here
--> $DIR/unused_unit.rs:12:9
| ^^^^^^^^^^^^^^^^^^^
error: unneeded unit return type
- --> $DIR/unused_unit.rs:20:18
+ --> $DIR/unused_unit.rs:19:28
|
-LL | where G: Fn() -> () {
- | ^^^^^^ help: remove the `-> ()`
+LL | pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+ | ^^^^^^ help: remove the `-> ()`
error: unneeded unit return type
- --> $DIR/unused_unit.rs:19:58
+ --> $DIR/unused_unit.rs:20:18
|
-LL | pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
- | ^^^^^^ help: remove the `-> ()`
+LL | where G: Fn() -> () {
+ | ^^^^^^ help: remove the `-> ()`
error: unneeded unit return type
--> $DIR/unused_unit.rs:21:26
-Subproject commit 1ef91e122775060acb1fbda2c9a366891af3ea89
+Subproject commit edd4858846003dc96020a0de07a1499e3224e633
} while (pos < content.length && content[pos] !== '/' && content[pos - 1] !== '*');
// Eat quoted strings
- } else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") {
+ } else if ((content[pos] === '"' || content[pos] === "'" || content[pos] === "`") &&
+ (pos === 0 || content[pos - 1] !== '/')) {
stop = content[pos];
do {
if (content[pos] === '\\') {
// execQuery last parameter is built in buildIndex.
// buildIndex requires the hashmap from search-index.
var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
- "handleAliases", "getQuery", "buildIndex", "execQuery", "execSearch",
- "removeEmptyStringsFromArray"];
+ "buildIndex", "execQuery", "parseQuery", "createQueryResults",
+ "isWhitespace", "isSpecialStartCharacter", "isStopCharacter",
+ "parseInput", "getItemsBefore", "getNextElem", "createQueryElement",
+ "isReturnArrow", "isPathStart", "getStringElem", "newParsedQuery",
+ "itemTypeFromName", "isEndCharacter", "isErrorCharacter",
+ "isIdentCharacter", "isSeparatorCharacter", "getIdentEndPosition",
+ "checkExtraTypeFilterCharacters", "isWhitespaceCharacter"];
const functions = ["hasOwnPropertyRustdoc", "onEach"];
ALIASES = {};
return [loaded, index];
}
+// This function checks if `expected` has all the required fields needed for the checks.
+function checkNeededFields(fullPath, expected, error_text, queryName, position) {
+ let fieldsToCheck;
+ if (fullPath.length === 0) {
+ fieldsToCheck = [
+ "foundElems",
+ "original",
+ "returned",
+ "typeFilter",
+ "userQuery",
+ "error",
+ ];
+ } else if (fullPath.endsWith("elems") || fullPath.endsWith("generics")) {
+ fieldsToCheck = [
+ "name",
+ "fullPath",
+ "pathWithoutLast",
+ "pathLast",
+ "generics",
+ ];
+ } else {
+ fieldsToCheck = [];
+ }
+ for (var i = 0; i < fieldsToCheck.length; ++i) {
+ const field = fieldsToCheck[i];
+ if (!expected.hasOwnProperty(field)) {
+ let text = `${queryName}==> Mandatory key \`${field}\` is not present`;
+ if (fullPath.length > 0) {
+ text += ` in field \`${fullPath}\``;
+ if (position != null) {
+ text += ` (position ${position})`;
+ }
+ }
+ error_text.push(text);
+ }
+ }
+}
+
+function valueCheck(fullPath, expected, result, error_text, queryName) {
+ if (Array.isArray(expected)) {
+ for (var i = 0; i < expected.length; ++i) {
+ checkNeededFields(fullPath, expected[i], error_text, queryName, i);
+ if (i >= result.length) {
+ error_text.push(`${queryName}==> EXPECTED has extra value in array from field ` +
+ `\`${fullPath}\` (position ${i}): \`${JSON.stringify(expected[i])}\``);
+ } else {
+ valueCheck(fullPath + '[' + i + ']', expected[i], result[i], error_text, queryName);
+ }
+ }
+ for (; i < result.length; ++i) {
+ error_text.push(`${queryName}==> RESULT has extra value in array from field ` +
+ `\`${fullPath}\` (position ${i}): \`${JSON.stringify(result[i])}\` ` +
+ 'compared to EXPECTED');
+ }
+ } else if (expected !== null && typeof expected !== "undefined" &&
+ expected.constructor == Object)
+ {
+ for (const key in expected) {
+ if (!expected.hasOwnProperty(key)) {
+ continue;
+ }
+ if (!result.hasOwnProperty(key)) {
+ error_text.push('==> Unknown key "' + key + '"');
+ break;
+ }
+ const obj_path = fullPath + (fullPath.length > 0 ? '.' : '') + key;
+ valueCheck(obj_path, expected[key], result[key], error_text, queryName);
+ }
+ } else {
+ expectedValue = JSON.stringify(expected);
+ resultValue = JSON.stringify(result);
+ if (expectedValue != resultValue) {
+ error_text.push(`${queryName}==> Different values for field \`${fullPath}\`:\n` +
+ `EXPECTED: \`${expectedValue}\`\nRESULT: \`${resultValue}\``);
+ }
+ }
+}
+
+function runParser(query, expected, loaded, loadedFile, queryName) {
+ var error_text = [];
+ checkNeededFields("", expected, error_text, queryName, null);
+ if (error_text.length === 0) {
+ valueCheck('', expected, loaded.parseQuery(query), error_text, queryName);
+ }
+ return error_text;
+}
+
function runSearch(query, expected, index, loaded, loadedFile, queryName) {
const filter_crate = loadedFile.FILTER_CRATE;
const ignore_order = loadedFile.ignore_order;
const exact_check = loadedFile.exact_check;
- var results = loaded.execSearch(loaded.getQuery(query), index, filter_crate);
+ var results = loaded.execQuery(loaded.parseQuery(query), index, filter_crate);
var error_text = [];
for (var key in expected) {
return 1;
}
-function runChecks(testFile, loaded, index) {
- var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;';
- if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
- testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
- } else {
- testFileContent += "exports.FILTER_CRATE = null;";
- }
- var loadedFile = loadContent(testFileContent);
-
- const expected = loadedFile.EXPECTED;
+function runCheck(loadedFile, key, callback) {
+ const expected = loadedFile[key];
const query = loadedFile.QUERY;
if (Array.isArray(query)) {
if (!Array.isArray(expected)) {
console.log("FAILED");
- console.log("==> If QUERY variable is an array, EXPECTED should be an array too");
+ console.log(`==> If QUERY variable is an array, ${key} should be an array too`);
return 1;
} else if (query.length !== expected.length) {
console.log("FAILED");
- console.log("==> QUERY variable should have the same length as EXPECTED");
+ console.log(`==> QUERY variable should have the same length as ${key}`);
return 1;
}
for (var i = 0; i < query.length; ++i) {
- var error_text = runSearch(query[i], expected[i], index, loaded, loadedFile,
- "[ query `" + query[i] + "`]");
+ var error_text = callback(query[i], expected[i], "[ query `" + query[i] + "`]");
if (checkResult(error_text, loadedFile, false) !== 0) {
return 1;
}
}
console.log("OK");
- return 0;
+ } else {
+ var error_text = callback(query, expected, "");
+ if (checkResult(error_text, loadedFile, true) !== 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+function runChecks(testFile, loaded, index) {
+ var checkExpected = false;
+ var checkParsed = false;
+ var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;';
+
+ if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
+ testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
+ } else {
+ testFileContent += "exports.FILTER_CRATE = null;";
+ }
+
+ if (testFileContent.indexOf("\nconst EXPECTED") !== -1) {
+ testFileContent += 'exports.EXPECTED = EXPECTED;';
+ checkExpected = true;
+ }
+ if (testFileContent.indexOf("\nconst PARSED") !== -1) {
+ testFileContent += 'exports.PARSED = PARSED;';
+ checkParsed = true;
+ }
+ if (!checkParsed && !checkExpected) {
+ console.log("FAILED");
+ console.log("==> At least `PARSED` or `EXPECTED` is needed!");
+ return 1;
+ }
+
+ const loadedFile = loadContent(testFileContent);
+ var res = 0;
+
+ if (checkExpected) {
+ res += runCheck(loadedFile, "EXPECTED", (query, expected, text) => {
+ return runSearch(query, expected, index, loaded, loadedFile, text);
+ });
+ }
+ if (checkParsed) {
+ res += runCheck(loadedFile, "PARSED", (query, expected, text) => {
+ return runParser(query, expected, loaded, loadedFile, text);
+ });
}
- var error_text = runSearch(query, expected, index, loaded, loadedFile, "");
- return checkResult(error_text, loadedFile, true);
+ return res;
}
function load_files(doc_folder, resource_suffix, crate) {
pub(crate) fn from_fn_kind(
fn_kind: &'a visit::FnKind<'_>,
- generics: &'a ast::Generics,
decl: &'a ast::FnDecl,
defaultness: ast::Defaultness,
) -> FnSig<'a> {
match *fn_kind {
- visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, _) => match fn_ctxt {
+ visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, generics, _) => match fn_ctxt {
visit::FnCtxt::Assoc(..) => {
let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
fn_sig.defaultness = defaultness;
let inner_attrs = inner_attributes(&self.attrs);
let fn_ctxt = visit::FnCtxt::Foreign;
visitor.visit_fn(
- visit::FnKind::Fn(fn_ctxt, self.ident, sig, &self.vis, Some(body)),
- generics,
+ visit::FnKind::Fn(
+ fn_ctxt,
+ self.ident,
+ sig,
+ &self.vis,
+ generics,
+ Some(body),
+ ),
&sig.decl,
self.span,
defaultness,
pub(crate) fn visit_fn(
&mut self,
fk: visit::FnKind<'_>,
- generics: &ast::Generics,
fd: &ast::FnDecl,
s: Span,
defaultness: ast::Defaultness,
let indent = self.block_indent;
let block;
let rewrite = match fk {
- visit::FnKind::Fn(_, ident, _, _, Some(ref b)) => {
+ visit::FnKind::Fn(_, ident, _, _, _, Some(ref b)) => {
block = b;
self.rewrite_fn_before_block(
indent,
ident,
- &FnSig::from_fn_kind(&fk, generics, fd, defaultness),
+ &FnSig::from_fn_kind(&fk, fd, defaultness),
mk_sp(s.lo(), b.span.lo()),
)
}
_ => visit::FnCtxt::Foreign,
};
self.visit_fn(
- visit::FnKind::Fn(fn_ctxt, item.ident, sig, &item.vis, Some(body)),
- generics,
+ visit::FnKind::Fn(
+ fn_ctxt,
+ item.ident,
+ sig,
+ &item.vis,
+ generics,
+ Some(body),
+ ),
&sig.decl,
item.span,
defaultness,
let inner_attrs = inner_attributes(&ai.attrs);
let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt);
self.visit_fn(
- visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, Some(body)),
- generics,
+ visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, Some(body)),
&sig.decl,
ai.span,
defaultness,
("self_cell", "Apache-2.0"), // rustc (fluent translations)
// FIXME: this dependency violates the documentation comment above:
("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
+ ("dunce", "CC0-1.0"), // cargo (dev dependency)
+ ("similar", "Apache-2.0"), // cargo (dev dependency)
+ ("normalize-line-endings", "Apache-2.0"), // cargo (dev dependency)
];
const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[