"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"
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"
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 {
Assoc(AssocCtxt),
}
+#[derive(Copy, Clone, Debug)]
+pub enum BoundKind {
+ /// Trait bounds in generics bounds and type/trait alias.
+ /// E.g., `<T: Bound>`, `type A: Bound`, or `where T: Bound`.
+ Bound,
+
+ /// Trait bounds in `impl` type.
+ /// E.g., `type Foo = impl Bound1 + Bound2 + Bound3`.
+ Impl,
+
+ /// Trait bounds in trait object type.
+ /// E.g., `dyn Bound1 + Bound2 + Bound3`.
+ TraitObject,
+
+ /// Super traits of a trait.
+ /// E.g., `trait A: B`
+ SuperTraits,
+}
+
#[derive(Copy, Clone, Debug)]
pub enum FnKind<'a> {
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
fn visit_trait_ref(&mut self, t: &'ast TraitRef) {
walk_trait_ref(self, t)
}
- fn visit_param_bound(&mut self, bounds: &'ast GenericBound) {
+ fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) {
walk_param_bound(self, bounds)
}
fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm),
ItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
visitor.visit_generics(generics);
- walk_list!(visitor, visit_param_bound, bounds);
+ walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
walk_list!(visitor, visit_ty, ty);
}
ItemKind::Enum(ref enum_definition, ref generics) => {
ref items,
}) => {
visitor.visit_generics(generics);
- walk_list!(visitor, visit_param_bound, bounds);
+ walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits);
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
}
ItemKind::TraitAlias(ref generics, ref bounds) => {
visitor.visit_generics(generics);
- walk_list!(visitor, visit_param_bound, bounds);
+ walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
}
ItemKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id),
visitor.visit_ty(ty);
visitor.visit_anon_const(length)
}
- TyKind::TraitObject(ref bounds, ..) | TyKind::ImplTrait(_, ref bounds) => {
- walk_list!(visitor, visit_param_bound, bounds);
+ TyKind::TraitObject(ref bounds, ..) => {
+ walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject);
+ }
+ TyKind::ImplTrait(_, ref bounds) => {
+ walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl);
}
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
Term::Const(c) => visitor.visit_anon_const(c),
},
AssocConstraintKind::Bound { ref bounds } => {
- walk_list!(visitor, visit_param_bound, bounds);
+ walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
}
}
}
}
ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
visitor.visit_generics(generics);
- walk_list!(visitor, visit_param_bound, bounds);
+ walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
walk_list!(visitor, visit_ty, ty);
}
ForeignItemKind::MacCall(mac) => {
pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a GenericParam) {
visitor.visit_ident(param.ident);
walk_list!(visitor, visit_attribute, param.attrs.iter());
- walk_list!(visitor, visit_param_bound, ¶m.bounds);
+ walk_list!(visitor, visit_param_bound, ¶m.bounds, BoundKind::Bound);
match param.kind {
GenericParamKind::Lifetime => (),
GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
..
}) => {
visitor.visit_ty(bounded_ty);
- walk_list!(visitor, visit_param_bound, bounds);
+ walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
walk_list!(visitor, visit_generic_param, bound_generic_params);
}
WherePredicate::RegionPredicate(WhereRegionPredicate {
ref lifetime, ref bounds, ..
}) => {
visitor.visit_lifetime(lifetime);
- walk_list!(visitor, visit_param_bound, bounds);
+ walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
}
WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => {
visitor.visit_ty(lhs_ty);
}
AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
visitor.visit_generics(generics);
- walk_list!(visitor, visit_param_bound, bounds);
+ walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
walk_list!(visitor, visit_ty, ty);
}
AssocItemKind::MacCall(mac) => {
self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
}
- fn visit_vis(&mut self, visibility: &'hir Visibility<'hir>) {
- match visibility.node {
- VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {}
- VisibilityKind::Restricted { hir_id, .. } => {
- self.insert(visibility.span, hir_id, Node::Visibility(visibility));
- self.with_parent(hir_id, |this| {
- intravisit::walk_vis(this, visibility);
- });
- }
- }
- }
-
fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
self.insert(v.span, v.id, Node::Variant(v));
self.with_parent(v.id, |this| {
use rustc_index::vec::{Idx, IndexVec};
use rustc_session::utils::NtToTokenstream;
use rustc_session::Session;
-use rustc_span::source_map::{respan, DesugaringKind};
+use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
use rustc_target::spec::abi;
fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
let mut ident = i.ident;
- let mut vis = self.lower_visibility(&i.vis);
+ let vis_span = self.lower_span(i.vis.span);
let hir_id = self.lower_node_id(i.id);
let attrs = self.lower_attrs(hir_id, &i.attrs);
- let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, &mut vis, &i.kind);
+ let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind);
let item = hir::Item {
def_id: hir_id.expect_owner(),
ident: self.lower_ident(ident),
kind,
- vis,
+ vis_span,
span: self.lower_span(i.span),
};
self.arena.alloc(item)
hir_id: hir::HirId,
ident: &mut Ident,
attrs: Option<&'hir [Attribute]>,
- vis: &mut hir::Visibility<'hir>,
+ vis_span: Span,
i: &ItemKind,
) -> hir::ItemKind<'hir> {
match *i {
// Start with an empty prefix.
let prefix = Path { segments: vec![], span: use_tree.span, tokens: None };
- self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs)
+ self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
}
ItemKind::Static(ref t, m, ref e) => {
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
tree: &UseTree,
prefix: &Path,
id: NodeId,
- vis: &mut hir::Visibility<'hir>,
+ vis_span: Span,
ident: &mut Ident,
attrs: Option<&'hir [Attribute]>,
) -> hir::ItemKind<'hir> {
debug!("lower_use_tree(tree={:?})", tree);
- debug!("lower_use_tree: vis = {:?}", vis);
let path = &tree.prefix;
let segments = prefix.segments.iter().chain(path.segments.iter()).cloned().collect();
let res = this.lower_res(res);
let path = this.lower_path_extra(res, &path, ParamMode::Explicit);
let kind = hir::ItemKind::Use(path, hir::UseKind::Single);
- let vis = this.rebuild_vis(&vis);
if let Some(attrs) = attrs {
this.attrs.insert(hir::ItemLocalId::new(0), attrs);
}
def_id: new_id,
ident: this.lower_ident(ident),
kind,
- vis,
+ vis_span,
span: this.lower_span(span),
};
hir::OwnerNode::Item(this.arena.alloc(item))
// own its own names, we have to adjust the owner before
// lowering the rest of the import.
self.with_hir_id_owner(id, |this| {
- let mut vis = this.rebuild_vis(&vis);
let mut ident = *ident;
let kind =
- this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs);
+ this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs);
if let Some(attrs) = attrs {
this.attrs.insert(hir::ItemLocalId::new(0), attrs);
}
def_id: new_hir_id,
ident: this.lower_ident(ident),
kind,
- vis,
+ vis_span,
span: this.lower_span(use_tree.span),
};
hir::OwnerNode::Item(this.arena.alloc(item))
});
}
- // Subtle and a bit hacky: we lower the privacy level
- // of the list stem to "private" most of the time, but
- // not for "restricted" paths. The key thing is that
- // we don't want it to stay as `pub` (with no caveats)
- // because that affects rustdoc and also the lints
- // about `pub` items. But we can't *always* make it
- // private -- particularly not for restricted paths --
- // because it contains node-ids that would then be
- // unused, failing the check that HirIds are "densely
- // assigned".
- match vis.node {
- hir::VisibilityKind::Public
- | hir::VisibilityKind::Crate(_)
- | hir::VisibilityKind::Inherited => {
- *vis = respan(
- self.lower_span(prefix.span.shrink_to_lo()),
- hir::VisibilityKind::Inherited,
- );
- }
- hir::VisibilityKind::Restricted { .. } => {
- // Do nothing here, as described in the comment on the match.
- }
- }
-
let res = self.expect_full_res_from_use(id).next().unwrap_or(Res::Err);
let res = self.lower_res(res);
let path = self.lower_path_extra(res, &prefix, ParamMode::Explicit);
}
}
- /// Paths like the visibility path in `pub(super) use foo::{bar, baz}` are repeated
- /// many times in the HIR tree; for each occurrence, we need to assign distinct
- /// `NodeId`s. (See, e.g., #56128.)
- fn rebuild_use_path(&mut self, path: &hir::Path<'hir>) -> &'hir hir::Path<'hir> {
- debug!("rebuild_use_path(path = {:?})", path);
- let segments =
- self.arena.alloc_from_iter(path.segments.iter().map(|seg| hir::PathSegment {
- ident: seg.ident,
- hir_id: seg.hir_id.map(|_| self.next_id()),
- res: seg.res,
- args: None,
- infer_args: seg.infer_args,
- }));
- self.arena.alloc(hir::Path { span: path.span, res: path.res, segments })
- }
-
- fn rebuild_vis(&mut self, vis: &hir::Visibility<'hir>) -> hir::Visibility<'hir> {
- let vis_kind = match vis.node {
- hir::VisibilityKind::Public => hir::VisibilityKind::Public,
- hir::VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
- hir::VisibilityKind::Inherited => hir::VisibilityKind::Inherited,
- hir::VisibilityKind::Restricted { ref path, hir_id: _ } => {
- hir::VisibilityKind::Restricted {
- path: self.rebuild_use_path(path),
- hir_id: self.next_id(),
- }
- }
- };
- respan(self.lower_span(vis.span), vis_kind)
- }
-
fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> {
let hir_id = self.lower_node_id(i.id);
let def_id = hir_id.expect_owner();
ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"),
},
- vis: self.lower_visibility(&i.vis),
+ vis_span: self.lower_span(i.vis.span),
span: self.lower_span(i.span),
};
self.arena.alloc(item)
// FIXME(jseyfried): positional field hygiene.
None => Ident::new(sym::integer(index), self.lower_span(f.span)),
},
- vis: self.lower_visibility(&f.vis),
+ vis_span: self.lower_span(f.vis.span),
ty,
}
}
def_id: hir_id.expect_owner(),
ident: self.lower_ident(i.ident),
generics,
- vis: self.lower_visibility(&i.vis),
kind,
+ vis_span: self.lower_span(i.vis.span),
span: self.lower_span(i.span),
};
self.arena.alloc(item)
}
}
- /// If an `explicit_owner` is given, this method allocates the `HirId` in
- /// the address space of that item instead of the item currently being
- /// lowered. This can happen during `lower_impl_item_ref()` where we need to
- /// lower a `Visibility` value although we haven't lowered the owning
- /// `ImplItem` in question yet.
- fn lower_visibility(&mut self, v: &Visibility) -> hir::Visibility<'hir> {
- let node = match v.kind {
- VisibilityKind::Public => hir::VisibilityKind::Public,
- VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
- VisibilityKind::Restricted { ref path, id } => {
- debug!("lower_visibility: restricted path id = {:?}", id);
- let lowered_id = self.lower_node_id(id);
- hir::VisibilityKind::Restricted {
- path: self.lower_path(id, path, ParamMode::Explicit),
- hir_id: lowered_id,
- }
- }
- VisibilityKind::Inherited => hir::VisibilityKind::Inherited,
- };
- respan(self.lower_span(v.span), node)
- }
-
fn lower_defaultness(
&self,
d: Defaultness,
use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
use rustc_session::Session;
use rustc_span::hygiene::{ExpnId, MacroKind};
-use rustc_span::source_map::{respan, DesugaringKind};
+use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
def_id: opaque_ty_id,
ident: Ident::empty(),
kind: opaque_ty_item_kind,
- vis: respan(self.lower_span(span.shrink_to_lo()), hir::VisibilityKind::Inherited),
+ vis_span: self.lower_span(span.shrink_to_lo()),
span: self.lower_span(opaque_ty_span),
};
hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
use itertools::{Either, Itertools};
use rustc_ast::ptr::P;
-use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
+use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
use rustc_ast::walk_list;
use rustc_ast::*;
use rustc_ast_pretty::pprust::{self, State};
}
}
- // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
- fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
- for bound in bounds {
- if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
- let mut err = self.err_handler().struct_span_err(
- poly.span,
- &format!("`?Trait` is not permitted in {}", where_),
- );
- if is_trait {
- let path_str = pprust::path_to_string(&poly.trait_ref.path);
- err.note(&format!("traits are `?{}` by default", path_str));
- }
- err.emit();
- }
- }
- }
-
fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
// Check only lifetime parameters are present and that the lifetime
// parameters that are present have no bounds.
any_lifetime_bounds = true;
}
}
- self.no_questions_in_bounds(bounds, "trait object types", false);
}
TyKind::ImplTrait(_, ref bounds) => {
if self.is_impl_trait_banned {
self.deny_where_clause(&generics.where_clause, item.ident.span);
self.deny_items(items, item.ident.span);
}
- self.no_questions_in_bounds(bounds, "supertraits", true);
// Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
// context for the supertraits.
self.visit_vis(&item.vis);
self.visit_ident(item.ident);
self.visit_generics(generics);
- self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
+ self.with_banned_tilde_const(|this| {
+ walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
+ });
walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
walk_list!(self, visit_attribute, &item.attrs);
return;
visit::walk_generic_param(self, param);
}
- fn visit_param_bound(&mut self, bound: &'a GenericBound) {
- match bound {
- GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
- if !self.is_tilde_const_allowed {
+ fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
+ if let GenericBound::Trait(ref poly, modify) = *bound {
+ match (ctxt, modify) {
+ (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
+ let mut err = self.err_handler().struct_span_err(
+ poly.span,
+ &format!("`?Trait` is not permitted in supertraits"),
+ );
+ let path_str = pprust::path_to_string(&poly.trait_ref.path);
+ err.note(&format!("traits are `?{}` by default", path_str));
+ err.emit();
+ }
+ (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
+ let mut err = self.err_handler().struct_span_err(
+ poly.span,
+ &format!("`?Trait` is not permitted in trait object types"),
+ );
+ err.emit();
+ }
+ (_, TraitBoundModifier::MaybeConst) => {
+ if !self.is_tilde_const_allowed {
+ self.err_handler()
+ .struct_span_err(bound.span(), "`~const` is not allowed here")
+ .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
+ .emit();
+ }
+ }
+ (_, TraitBoundModifier::MaybeConstMaybe) => {
self.err_handler()
- .struct_span_err(bound.span(), "`~const` is not allowed here")
- .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
- .emit();
+ .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
}
+ _ => {}
}
-
- GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
- self.err_handler()
- .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
- }
-
- _ => {}
}
visit::walk_param_bound(self, bound)
walk_list!(self, visit_attribute, &item.attrs);
self.with_tilde_const_allowed(|this| {
this.visit_generics(generics);
- walk_list!(this, visit_param_bound, bounds);
+ walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
});
walk_list!(self, visit_ty, ty);
}
self.count += 1;
walk_trait_ref(self, t)
}
- fn visit_param_bound(&mut self, bounds: &GenericBound) {
+ fn visit_param_bound(&mut self, bounds: &GenericBound, _ctxt: BoundKind) {
self.count += 1;
walk_param_bound(self, bounds)
}
sup: self.static_region,
sub: next_static_idx.into(),
locations: Locations::All(DUMMY_SP),
+ span: DUMMY_SP,
category: ConstraintCategory::Internal,
variance_info: VarianceDiagInfo::default(),
})
/// Given a region `R`, iterate over all regions `R1` such that
/// there exists a constraint `R: R1`.
- crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, 'tcx, D> {
+ crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'s, 'tcx, D> {
Successors {
edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region),
}
}
}
-impl<'s, 'graph, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph>
- for RegionGraph<'s, 'tcx, D>
-{
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'_> for RegionGraph<'s, 'tcx, D> {
type Item = RegionVid;
- // FIXME - why can't this be `'graph, 'tcx`
- type Iter = Successors<'graph, 'graph, D>;
+ type Iter = Successors<'s, 'tcx, D>;
}
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,
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::ObligationCause;
+use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
use crate::borrow_set::TwoPhaseActivation;
use crate::borrowck_errors;
+use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
use crate::diagnostics::find_all_local_uses;
use crate::{
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
err.span_suggestion_hidden(
return_span,
"use `.collect()` to allocate the iterator",
- format!("{}{}", snippet, ".collect::<Vec<_>>()"),
+ format!("{snippet}.collect::<Vec<_>>()"),
Applicability::MaybeIncorrect,
);
}
fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
let tcx = self.infcx.tcx;
- match place.last_projection() {
- None => StorageDeadOrDrop::LocalStorageDead,
- Some((place_base, elem)) => {
- // FIXME(spastorino) make this iterate
- let base_access = self.classify_drop_access_kind(place_base);
- match elem {
- ProjectionElem::Deref => match base_access {
- StorageDeadOrDrop::LocalStorageDead
- | StorageDeadOrDrop::BoxedStorageDead => {
- assert!(
- place_base.ty(self.body, tcx).ty.is_box(),
- "Drop of value behind a reference or raw pointer"
- );
- StorageDeadOrDrop::BoxedStorageDead
- }
- StorageDeadOrDrop::Destructor(_) => base_access,
- },
- ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
- let base_ty = place_base.ty(self.body, tcx).ty;
- match base_ty.kind() {
- ty::Adt(def, _) if def.has_dtor(tcx) => {
- // Report the outermost adt with a destructor
- match base_access {
- StorageDeadOrDrop::Destructor(_) => base_access,
- StorageDeadOrDrop::LocalStorageDead
- | StorageDeadOrDrop::BoxedStorageDead => {
- StorageDeadOrDrop::Destructor(base_ty)
+ let (kind, _place_ty) = place.projection.iter().fold(
+ (LocalStorageDead, PlaceTy::from_ty(self.body.local_decls[place.local].ty)),
+ |(kind, place_ty), &elem| {
+ (
+ match elem {
+ ProjectionElem::Deref => match kind {
+ StorageDeadOrDrop::LocalStorageDead
+ | StorageDeadOrDrop::BoxedStorageDead => {
+ assert!(
+ place_ty.ty.is_box(),
+ "Drop of value behind a reference or raw pointer"
+ );
+ StorageDeadOrDrop::BoxedStorageDead
+ }
+ StorageDeadOrDrop::Destructor(_) => kind,
+ },
+ ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
+ match place_ty.ty.kind() {
+ ty::Adt(def, _) if def.has_dtor(tcx) => {
+ // Report the outermost adt with a destructor
+ match kind {
+ StorageDeadOrDrop::Destructor(_) => kind,
+ StorageDeadOrDrop::LocalStorageDead
+ | StorageDeadOrDrop::BoxedStorageDead => {
+ StorageDeadOrDrop::Destructor(place_ty.ty)
+ }
}
}
+ _ => kind,
}
- _ => base_access,
}
- }
- ProjectionElem::ConstantIndex { .. }
- | ProjectionElem::Subslice { .. }
- | ProjectionElem::Index(_) => base_access,
- }
- }
- }
+ ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::Subslice { .. }
+ | ProjectionElem::Index(_) => kind,
+ },
+ place_ty.projection_ty(tcx, elem),
+ )
+ },
+ );
+ kind
}
/// Describe the reason for the fake borrow that was assigned to `place`.
crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
crate use region_name::{RegionName, RegionNameSource};
crate use rustc_const_eval::util::CallKind;
+use rustc_middle::mir::tcx::PlaceTy;
pub(super) struct IncludingDowncast(pub(super) bool);
/// End-user visible description of the `field`nth field of `base`
fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
- // FIXME Place2 Make this work iteratively
- match place {
- PlaceRef { local, projection: [] } => {
- let local = &self.body.local_decls[local];
- self.describe_field_from_ty(local.ty, field, None)
- }
+ let place_ty = match place {
+ PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty),
PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
- ProjectionElem::Deref => {
- self.describe_field(PlaceRef { local, projection: proj_base }, field)
- }
- ProjectionElem::Downcast(_, variant_index) => {
- let base_ty = place.ty(self.body, self.infcx.tcx).ty;
- self.describe_field_from_ty(base_ty, field, Some(*variant_index))
- }
- ProjectionElem::Field(_, field_type) => {
- self.describe_field_from_ty(*field_type, field, None)
- }
- ProjectionElem::Index(..)
+ ProjectionElem::Deref
+ | ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
- self.describe_field(PlaceRef { local, projection: proj_base }, field)
+ PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
}
+ ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
+ ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
},
- }
+ };
+ self.describe_field_from_ty(place_ty.ty, field, place_ty.variant_index)
}
/// End-user visible description of the `field_index`nth field of `ty`
//! Error reporting machinery for lifetime errors.
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_infer::infer::{
- error_reporting::nice_region_error::NiceRegionError,
- error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin,
+ error_reporting::nice_region_error::{self, find_param_with_region, NiceRegionError},
+ error_reporting::unexpected_hidden_region_diagnostic,
+ NllRegionVariableOrigin, RelateParamBound,
};
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, RegionVid, Ty};
-use rustc_span::symbol::{kw, sym};
-use rustc_span::{BytePos, Span};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
use crate::borrowck_errors;
let type_test_span = type_test.locations.span(&self.body);
if let Some(lower_bound_region) = lower_bound_region {
+ let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx);
+ let origin = RelateParamBound(type_test_span, generic_ty, None);
self.buffer_error(self.infcx.construct_generic_bound_failure(
type_test_span,
- None,
+ Some(origin),
type_test.generic_kind,
lower_bound_region,
+ self.body.source.def_id().as_local(),
));
} else {
// FIXME. We should handle this case better. It
fr_name: RegionName,
outlived_fr: RegionVid,
) {
- if let (Some(f), Some(ty::ReStatic)) =
- (self.to_error_region(fr), self.to_error_region(outlived_fr).as_deref())
+ if let (Some(f), Some(outlived_f)) =
+ (self.to_error_region(fr), self.to_error_region(outlived_fr))
{
- if let Some(&ty::Opaque(did, substs)) = self
+ if *outlived_f != ty::ReStatic {
+ return;
+ }
+
+ let fn_returns = self
.infcx
.tcx
.is_suitable_region(f)
- .map(|r| r.def_id)
- .and_then(|id| self.infcx.tcx.return_type_impl_trait(id))
- .map(|(ty, _)| ty.kind())
- {
- // Check whether or not the impl trait return type is intended to capture
- // data with the static lifetime.
- //
- // eg. check for `impl Trait + 'static` instead of `impl Trait`.
- let has_static_predicate = {
- let bounds = self.infcx.tcx.explicit_item_bounds(did);
-
- let mut found = false;
- for (bound, _) in bounds {
- if let ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_, r)) =
- bound.kind().skip_binder()
- {
- let r = r.subst(self.infcx.tcx, substs);
- if r.is_static() {
- found = true;
- break;
- } else {
- // If there's already a lifetime bound, don't
- // suggest anything.
- return;
- }
- }
- }
-
- found
- };
+ .map(|r| self.infcx.tcx.return_type_impl_or_dyn_traits(r.def_id))
+ .unwrap_or_default();
- debug!(
- "add_static_impl_trait_suggestion: has_static_predicate={:?}",
- has_static_predicate
- );
- let static_str = kw::StaticLifetime;
- // If there is a static predicate, then the only sensible suggestion is to replace
- // fr with `'static`.
- if has_static_predicate {
- diag.help(&format!("consider replacing `{fr_name}` with `{static_str}`"));
- } else {
- // Otherwise, we should suggest adding a constraint on the return type.
- let span = self.infcx.tcx.def_span(did);
- if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
- let suggestable_fr_name = if fr_name.was_named() {
- fr_name.to_string()
- } else {
- "'_".to_string()
- };
- let span = if snippet.ends_with(';') {
- // `type X = impl Trait;`
- span.with_hi(span.hi() - BytePos(1))
- } else {
- span
- };
- let suggestion = format!(" + {suggestable_fr_name}");
- let span = span.shrink_to_hi();
- diag.span_suggestion(
- span,
- &format!(
- "to allow this `impl Trait` to capture borrowed data with lifetime \
- `{fr_name}`, add `{suggestable_fr_name}` as a bound",
- ),
- suggestion,
- Applicability::MachineApplicable,
- );
- }
- }
+ if fn_returns.is_empty() {
+ return;
}
+
+ let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) {
+ param
+ } else {
+ return;
+ };
+
+ let lifetime = if f.has_name() { fr_name.to_string() } else { "'_".to_string() };
+
+ let arg = match param.param.pat.simple_ident() {
+ Some(simple_ident) => format!("argument `{}`", simple_ident),
+ None => "the argument".to_string(),
+ };
+ let captures = format!("captures data from {}", arg);
+
+ return nice_region_error::suggest_new_region_bound(
+ self.infcx.tcx,
+ diag,
+ fn_returns,
+ lifetime,
+ Some(arg),
+ captures,
+ Some((param.param_ty_span, param.param_ty.to_string())),
+ );
}
}
}
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,
},
[[package]]
name = "cranelift-bforest"
-version = "0.82.1"
+version = "0.83.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d16922317bd7dd104d509a373887822caa0242fc1def00de66abb538db221db4"
+checksum = "ed44413e7e2fe3260d0ed73e6956ab188b69c10ee92b892e401e0f4f6808c68b"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
-version = "0.82.1"
+version = "0.83.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b80bf40380256307b68a3dcbe1b91cac92a533e212b5b635abc3e4525781a0a"
+checksum = "0b5d83f0f26bf213f971f45589d17e5b65e4861f9ed22392b0cbb6eaa5bd329c"
dependencies = [
"cranelift-bforest",
"cranelift-codegen-meta",
[[package]]
name = "cranelift-codegen-meta"
-version = "0.82.1"
+version = "0.83.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "703d0ed7d3bc6c7a814ca12858175bf4e93167a3584127858c686e4b5dd6e432"
+checksum = "6800dc386177df6ecc5a32680607ed8ba1fa0d31a2a59c8c61fbf44826b8191d"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
-version = "0.82.1"
+version = "0.83.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80f52311e1c90de12dcf8c4b9999c6ebfd1ed360373e88c357160936844511f6"
+checksum = "c961f85070985ebc8fcdb81b838a5cf842294d1e6ed4852446161c7e246fd455"
[[package]]
name = "cranelift-entity"
-version = "0.82.1"
+version = "0.83.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66bc82ef522c1f643baf7d4d40b7c52643ee4549d8960b0e6a047daacb83f897"
+checksum = "2347b2b8d1d5429213668f2a8e36c85ee3c73984a2f6a79007e365d3e575e7ed"
[[package]]
name = "cranelift-frontend"
-version = "0.82.1"
+version = "0.83.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3cc35e4251864b17515845ba47447bca88fec9ca1a4186b19fe42526e36140e8"
+checksum = "4cbcdbf7bed29e363568b778649b69dabc3d727256d5d25236096ef693757654"
dependencies = [
"cranelift-codegen",
"log",
[[package]]
name = "cranelift-jit"
-version = "0.82.1"
+version = "0.83.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93c66d594ad3bfe4e58b1fbd8d17877a7c6564a5f2d6f78cbbf4b0182af1927f"
+checksum = "7c769d4e0d76f59c8b2a3bf0477d89ee149bb0731b53fbb245ee081d49063095"
dependencies = [
"anyhow",
"cranelift-codegen",
[[package]]
name = "cranelift-module"
-version = "0.82.1"
+version = "0.83.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf356697c40232aa09e1e3fb8a350ee894e849ccecc4eac56ff0570a4575c325"
+checksum = "0ab57d399a2401074bb0cc40b3031e420f3d66d46ec0cf21eeae53ac04bd73e2"
dependencies = [
"anyhow",
"cranelift-codegen",
[[package]]
name = "cranelift-native"
-version = "0.82.1"
+version = "0.83.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b882b2251c9845d509d92aebfdb6c8bb3b3b48e207ac951f21fbd20cfe7f90b3"
+checksum = "8f4cdf93552e5ceb2e3c042829ebb4de4378492705f769eadc6a7c6c5251624c"
dependencies = [
"cranelift-codegen",
"libc",
[[package]]
name = "cranelift-object"
-version = "0.82.1"
+version = "0.83.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d3f1a88e654e567d2591169239ed157ab290811a729a6468f53999c01001263"
+checksum = "cf8e65f4839c26e6237fc0744911d79b0a2ac5e76b4e4eebd14db2b8d849fd31"
dependencies = [
"anyhow",
"cranelift-codegen",
[dependencies]
# These have to be in sync with each other
-cranelift-codegen = { version = "0.82.1", features = ["unwind", "all-arch"] }
-cranelift-frontend = "0.82.1"
-cranelift-module = "0.82.1"
-cranelift-native = "0.82.1"
-cranelift-jit = { version = "0.82.1", optional = true }
-cranelift-object = "0.82.1"
+cranelift-codegen = { version = "0.83.0", features = ["unwind", "all-arch"] }
+cranelift-frontend = "0.83.0"
+cranelift-module = "0.83.0"
+cranelift-native = "0.83.0"
+cranelift-jit = { version = "0.83.0", optional = true }
+cranelift-object = "0.83.0"
target-lexicon = "0.12.0"
gimli = { version = "0.26.0", default-features = false, features = ["write"]}
object = { version = "0.27.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
[[package]]
name = "compiler_builtins"
-version = "0.1.71"
+version = "0.1.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "163437f05ca8f29d7e9128ea728dedf5eb620e445fbca273641d3a3050305f23"
+checksum = "afdbb35d279238cf77f0c9e8d90ad50d6c7bff476ab342baafa29440f0f10bff"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "libc"
-version = "0.2.121"
+version = "0.2.124"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
+checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
dependencies = [
"rustc-std-workspace-core",
]
name = "proc_macro"
version = "0.0.0"
dependencies = [
+ "core",
"std",
]
--- /dev/null
+// Copied from https://github.com/rust-lang/rust/blob/3fe3b89cd57229343eeca753fdd8c63d9b03c65c/src/test/ui/simd/intrinsic/float-minmax-pass.rs
+// run-pass
+// ignore-emscripten
+
+// Test that the simd_f{min,max} intrinsics produce the correct results.
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_fmin<T>(x: T, y: T) -> T;
+ fn simd_fmax<T>(x: T, y: T) -> T;
+}
+
+fn main() {
+ let x = f32x4(1.0, 2.0, 3.0, 4.0);
+ let y = f32x4(2.0, 1.0, 4.0, 3.0);
+
+ #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
+ let nan = f32::NAN;
+ // MIPS hardware treats f32::NAN as SNAN. Clear the signaling bit.
+ // See https://github.com/rust-lang/rust/issues/52746.
+ #[cfg(any(target_arch = "mips", target_arch = "mips64"))]
+ let nan = f32::from_bits(f32::NAN.to_bits() - 1);
+
+ let n = f32x4(nan, nan, nan, nan);
+
+ unsafe {
+ let min0 = simd_fmin(x, y);
+ let min1 = simd_fmin(y, x);
+ assert_eq!(min0, min1);
+ let e = f32x4(1.0, 1.0, 3.0, 3.0);
+ assert_eq!(min0, e);
+ let minn = simd_fmin(x, n);
+ assert_eq!(minn, x);
+ let minn = simd_fmin(y, n);
+ assert_eq!(minn, y);
+
+ let max0 = simd_fmax(x, y);
+ let max1 = simd_fmax(y, x);
+ assert_eq!(max0, max1);
+ let e = f32x4(2.0, 2.0, 4.0, 4.0);
+ assert_eq!(max0, e);
+ let maxn = simd_fmax(x, n);
+ assert_eq!(maxn, x);
+ let maxn = simd_fmax(y, n);
+ assert_eq!(maxn, y);
+ }
+}
#[lang = "sized"]
pub trait Sized {}
+#[lang = "destruct"]
+pub trait Destruct {}
+
#[lang = "unsize"]
pub trait Unsize<T: ?Sized> {}
fn deref(&self) -> &Self::Target;
}
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(1)]
+#[rustc_nonnull_optimization_guaranteed]
+pub struct NonNull<T: ?Sized>(pub *mut T);
+
+impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
+
pub struct Unique<T: ?Sized> {
- pub pointer: *const T,
+ pub pointer: NonNull<T>,
pub _marker: PhantomData<T>,
}
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
-
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
#[lang = "owned_box"]
#[lang = "box_free"]
unsafe fn box_free<T: ?Sized>(ptr: Unique<T>, alloc: ()) {
- libc::free(ptr.pointer as *mut u8);
+ libc::free(ptr.pointer.0 as *mut u8);
}
#[lang = "drop"]
#[allow(unreachable_code)] // FIXME false positive
fn main() {
take_unique(Unique {
- pointer: 0 as *const (),
+ pointer: unsafe { NonNull(1 as *mut ()) },
_marker: PhantomData,
});
take_f32(0.1);
assert!(intrinsics::needs_drop::<NoisyDrop>());
Unique {
- pointer: 0 as *const &str,
+ pointer: NonNull(1 as *mut &str),
_marker: PhantomData,
} as Unique<dyn SomeTrait>;
-#![feature(core_intrinsics, generators, generator_trait, is_sorted)]
+#![feature(core_intrinsics, generators, generator_trait, is_sorted, bench_black_box)]
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
+use std::hint::black_box;
use std::io::Write;
use std::ops::Generator;
assert_eq!(houndred_f64 as i128, 100);
assert_eq!(1u128.rotate_left(2), 4);
+ assert_eq!(black_box(f32::NAN) as i128, 0);
+ assert_eq!(black_box(f32::NAN) as u128, 0);
+
// Test signed 128bit comparing
let max = usize::MAX as i128;
if 100i128 < 0i128 || 100i128 > max {
}
}
}
-diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs
-index 31b7ee2..bd04b3c 100644
---- a/crates/core_simd/tests/ops_macros.rs
-+++ b/crates/core_simd/tests/ops_macros.rs
-@@ -567,6 +567,7 @@ macro_rules! impl_float_tests {
- });
- }
-
-+ /*
- fn horizontal_max<const LANES: usize>() {
- test_helpers::test_1(&|x| {
- let vmax = Vector::<LANES>::from_array(x).horizontal_max();
-@@ -590,6 +591,7 @@ macro_rules! impl_float_tests {
- Ok(())
- });
- }
-+ */
- }
-
- #[cfg(feature = "std")]
-@@ -604,6 +606,7 @@ macro_rules! impl_float_tests {
- )
- }
-
-+ /*
- fn mul_add<const LANES: usize>() {
- test_helpers::test_ternary_elementwise(
- &Vector::<LANES>::mul_add,
-@@ -611,6 +614,7 @@ macro_rules! impl_float_tests {
- &|_, _, _| true,
- )
- }
-+ */
- }
- }
- }
--
2.26.2.7.g19db9cfb68
[toolchain]
-channel = "nightly-2022-03-19"
+channel = "nightly-2022-04-21"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
-#!/bin/bash
+#!/usr/bin/env bash
#![forbid(unsafe_code)]/* This line is ignored by bash
# This block is ignored by rustc
pushd $(dirname "$0")/../
-#!/bin/bash
+#!/usr/bin/env bash
set -e
./y.rs build --no-unstable-features
-#!/bin/bash
+#!/usr/bin/env bash
set -e
cd $(dirname "$0")/../
command -v rg >/dev/null 2>&1 || cargo install ripgrep
rm -r src/test/ui/{extern/,unsized-locals/,lto/,linkage*} || true
-for test in $(rg --files-with-matches "asm!|lto|// needs-asm-support|// needs-unwind" src/test/{ui,incremental}); do
+for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" src/test/{ui,incremental}); do
rm $test
done
# ================
# requires stack unwinding
-rm src/test/ui/backtrace.rs
-rm src/test/ui/process/multi-panic.rs
-rm src/test/ui/numbers-arithmetic/issue-8460.rs
rm src/test/incremental/change_crate_dep_kind.rs
rm src/test/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort instead of exit(101)
-rm src/test/ui/panic-while-printing.rs
-rm src/test/ui/test-attrs/test-panic-while-printing.rs
-rm src/test/ui/test-attrs/test-type.rs
# requires compiling with -Cpanic=unwind
rm src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs # "Cannot run dynamic test fn out-of-process"
# giving different but possibly correct results
# =============================================
-rm src/test/ui/numbers-arithmetic/saturating-float-casts.rs # intrinsic gives different but valid result
-rm src/test/ui/simd/intrinsic/float-minmax-pass.rs # same
rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
rm src/test/ui/mir/mir_raw_fat_ptr.rs # same
rm src/test/ui/consts/issue-33537.rs # same
rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
+rm src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs # wrong result from `Location::caller()`
+
# bugs in the test suite
# ======================
-rm src/test/ui/unsafe/union.rs # has UB caught by cg_clif. see rust-lang/rust#95075
+rm src/test/ui/backtrace.rs # TODO warning
+rm src/test/ui/empty_global_asm.rs # TODO add needs-asm-support
+rm src/test/ui/simple_global_asm.rs # TODO add needs-asm-support
+rm src/test/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout
echo "[TEST] rustc test suite"
RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
$MY_RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
$RUN_WRAPPER ./target/out/track-caller-attribute
+ echo "[AOT] float-minmax-pass"
+ $MY_RUSTC example/float-minmax-pass.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
+ $RUN_WRAPPER ./target/out/float-minmax-pass
+
echo "[AOT] mod_bench"
$MY_RUSTC example/mod_bench.rs --crate-type bin --target "$TARGET_TRIPLE"
$RUN_WRAPPER ./target/out/mod_bench
if cplace.layout().ty.is_box() {
cplace = cplace
.place_field(fx, Field::new(0)) // Box<T> -> Unique<T>
- .place_field(fx, Field::new(0)) // Unique<T> -> *const T
+ .place_field(fx, Field::new(0)) // Unique<T> -> NonNull<T>
+ .place_field(fx, Field::new(0)) // NonNull<T> -> *mut T
.place_deref(fx);
} else {
cplace = cplace.place_deref(fx);
fx.bcx.ins().fcvt_from_uint(to_ty, from)
}
} else if from_ty.is_float() && to_ty.is_int() {
- if to_ty == types::I128 {
+ let val = if to_ty == types::I128 {
// _____sssf___
// __fix sfti: f32 -> i128
// __fix dfti: f64 -> i128
let to_rust_ty = if to_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
- return fx
- .easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty)
- .load_scalar(fx);
- }
-
- // float -> int-like
- if to_ty == types::I8 || to_ty == types::I16 {
+ fx.easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty)
+ .load_scalar(fx)
+ } else if to_ty == types::I8 || to_ty == types::I16 {
// FIXME implement fcvt_to_*int_sat.i8/i16
let val = if to_signed {
fx.bcx.ins().fcvt_to_sint_sat(types::I32, from)
fx.bcx.ins().fcvt_to_sint_sat(to_ty, from)
} else {
fx.bcx.ins().fcvt_to_uint_sat(to_ty, from)
+ };
+
+ if let Some(false) = fx.tcx.sess.opts.debugging_opts.saturating_float_casts {
+ return val;
+ }
+
+ let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from);
+ if to_ty == types::I128 {
+ // FIXME(bytecodealliance/wasmtime#3963): select.i128 on fcmp eq miscompiles
+ let (lsb, msb) = fx.bcx.ins().isplit(val);
+ let zero = fx.bcx.ins().iconst(types::I64, 0);
+ let lsb = fx.bcx.ins().select(is_not_nan, lsb, zero);
+ let msb = fx.bcx.ins().select(is_not_nan, msb, zero);
+ fx.bcx.ins().iconcat(lsb, msb)
+ } else {
+ let zero = fx.bcx.ins().iconst(to_ty, 0);
+ fx.bcx.ins().select(is_not_nan, val, zero)
}
} else if from_ty.is_float() && to_ty.is_float() {
// float -> float
/// Can be set using `-Cllvm-args=display_cg_time=...`.
pub display_cg_time: bool,
- /// The register allocator to use.
- ///
- /// Defaults to the value of `CG_CLIF_REGALLOC` or `backtracking` otherwise. Can be set using
- /// `-Cllvm-args=regalloc=...`.
- pub regalloc: String,
-
/// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run
/// once before passing the clif ir to Cranelift for compilation.
///
args.split(' ').map(|arg| arg.to_string()).collect()
},
display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"),
- regalloc: std::env::var("CG_CLIF_REGALLOC")
- .unwrap_or_else(|_| "backtracking".to_string()),
enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
}
match name {
"mode" => config.codegen_mode = value.parse()?,
"display_cg_time" => config.display_cg_time = parse_bool(name, value)?,
- "regalloc" => config.regalloc = value.to_string(),
"enable_verifier" => config.enable_verifier = parse_bool(name, value)?,
"disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?,
_ => return Err(format!("Unknown option `{}`", name)),
let relative_discr = if niche_start == 0 {
tag
} else {
- // FIXME handle niche_start > i64::MAX
- fx.bcx.ins().iadd_imm(tag, -i64::try_from(niche_start).unwrap())
+ let niche_start = match fx.bcx.func.dfg.value_type(tag) {
+ types::I128 => {
+ let lsb = fx.bcx.ins().iconst(types::I64, niche_start as u64 as i64);
+ let msb =
+ fx.bcx.ins().iconst(types::I64, (niche_start >> 64) as u64 as i64);
+ fx.bcx.ins().iconcat(lsb, msb)
+ }
+ ty => fx.bcx.ins().iconst(ty, niche_start as i64),
+ };
+ fx.bcx.ins().isub(tag, niche_start)
};
let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
let is_niche = {
ret.write_cvalue(fx, old);
};
- // In Rust floating point min and max don't propagate NaN. In Cranelift they do however.
- // For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for `minnumf*`
- // and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing
- // a float against itself. Only in case of NaN is it not equal to itself.
minnumf32, (v a, v b) {
- let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
- let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
- let temp = fx.bcx.ins().select(a_ge_b, b, a);
- let val = fx.bcx.ins().select(a_is_nan, b, temp);
+ let val = crate::num::codegen_float_min(fx, a, b);
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
ret.write_cvalue(fx, val);
};
minnumf64, (v a, v b) {
- let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
- let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
- let temp = fx.bcx.ins().select(a_ge_b, b, a);
- let val = fx.bcx.ins().select(a_is_nan, b, temp);
+ let val = crate::num::codegen_float_min(fx, a, b);
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
ret.write_cvalue(fx, val);
};
maxnumf32, (v a, v b) {
- let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
- let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
- let temp = fx.bcx.ins().select(a_le_b, b, a);
- let val = fx.bcx.ins().select(a_is_nan, b, temp);
+ let val = crate::num::codegen_float_max(fx, a, b);
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
ret.write_cvalue(fx, val);
};
maxnumf64, (v a, v b) {
- let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
- let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
- let temp = fx.bcx.ins().select(a_le_b, b, a);
- let val = fx.bcx.ins().select(a_is_nan, b, temp);
+ let val = crate::num::codegen_float_max(fx, a, b);
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
ret.write_cvalue(fx, val);
};
}
assert_eq!(a.layout(), b.layout());
assert_eq!(a.layout(), c.layout());
- let layout = a.layout();
+ assert_eq!(a.layout(), ret.layout());
- let (lane_count, _lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
- let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
- assert_eq!(lane_count, ret_lane_count);
- let ret_lane_layout = fx.layout_of(ret_lane_ty);
+ let layout = a.layout();
+ let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
for lane in 0..lane_count {
- let a_lane = a.value_lane(fx, lane).load_scalar(fx);
- let b_lane = b.value_lane(fx, lane).load_scalar(fx);
- let c_lane = c.value_lane(fx, lane).load_scalar(fx);
+ let a_lane = a.value_lane(fx, lane);
+ let b_lane = b.value_lane(fx, lane);
+ let c_lane = c.value_lane(fx, lane);
- let mul_lane = fx.bcx.ins().fmul(a_lane, b_lane);
- let res_lane = CValue::by_val(fx.bcx.ins().fadd(mul_lane, c_lane), ret_lane_layout);
+ let res_lane = match lane_ty.kind() {
+ ty::Float(FloatTy::F32) => fx.easy_call("fmaf", &[a_lane, b_lane, c_lane], lane_ty),
+ ty::Float(FloatTy::F64) => fx.easy_call("fma", &[a_lane, b_lane, c_lane], lane_ty),
+ _ => unreachable!(),
+ };
ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
}
_ => unreachable!("{:?}", lane_ty),
}
match intrinsic {
- sym::simd_fmin => fx.bcx.ins().fmin(x_lane, y_lane),
- sym::simd_fmax => fx.bcx.ins().fmax(x_lane, y_lane),
+ sym::simd_fmin => crate::num::codegen_float_min(fx, x_lane, y_lane),
+ sym::simd_fmax => crate::num::codegen_float_max(fx, x_lane, y_lane),
_ => unreachable!(),
}
});
let lt = match ty.kind() {
ty::Int(_) => fx.bcx.ins().icmp(IntCC::SignedLessThan, a, b),
ty::Uint(_) => fx.bcx.ins().icmp(IntCC::UnsignedLessThan, a, b),
- ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::LessThan, a, b),
+ ty::Float(_) => return crate::num::codegen_float_min(fx, a, b),
_ => unreachable!(),
};
fx.bcx.ins().select(lt, a, b)
let gt = match ty.kind() {
ty::Int(_) => fx.bcx.ins().icmp(IntCC::SignedGreaterThan, a, b),
ty::Uint(_) => fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, a, b),
- ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::GreaterThan, a, b),
+ ty::Float(_) => return crate::num::codegen_float_max(fx, a, b),
_ => unreachable!(),
};
fx.bcx.ins().select(gt, a, b)
flags_builder.set("enable_llvm_abi_extensions", "true").unwrap();
- flags_builder.set("regalloc", &backend_config.regalloc).unwrap();
-
use rustc_session::config::OptLevel;
match sess.opts.optimize {
OptLevel::No => {
CValue::by_val(fx.bcx.ins().bint(types::I8, res), fx.layout_of(fx.tcx.types.bool))
}
}
+
+// In Rust floating point min and max don't propagate NaN. In Cranelift they do however.
+// For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for `minnumf*`
+// and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing
+// a float against itself. Only in case of NaN is it not equal to itself.
+pub(crate) fn codegen_float_min(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value {
+ let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
+ let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
+ let temp = fx.bcx.ins().select(a_ge_b, b, a);
+ fx.bcx.ins().select(a_is_nan, b, temp)
+}
+
+pub(crate) fn codegen_float_max(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value {
+ let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
+ let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
+ let temp = fx.bcx.ins().select(a_le_b, b, a);
+ fx.bcx.ins().select(a_is_nan, b, temp)
+}
| 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(),
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::bug;
use rustc_middle::dep_graph::WorkProduct;
-use rustc_middle::middle::exported_symbols::SymbolExportLevel;
+use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{self, CrateType, Lto};
use tracing::{debug, info};
Lto::No => panic!("didn't request LTO but we're doing LTO"),
};
- let symbol_filter = &|&(ref name, level): &(String, SymbolExportLevel)| {
- if level.is_below_threshold(export_threshold) {
+ let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| {
+ if info.level.is_below_threshold(export_threshold) || info.used {
Some(CString::new(name.as_str()).unwrap())
} else {
None
if thin {
llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm);
} else {
- llvm::LLVMPassManagerBuilderPopulateLTOPassManager(
+ llvm::LLVMRustPassManagerBuilderPopulateLTOPassManager(
b, pm, /* Internalize = */ False, /* RunInliner = */ True,
);
}
let module_name = module.name.clone();
let module_name = Some(&module_name[..]);
+ if let Some(false) = config.new_llvm_pass_manager && llvm_util::get_version() >= (15, 0, 0) {
+ diag_handler.warn(
+ "ignoring `-Z new-llvm-pass-manager=no`, which is no longer supported with LLVM 15",
+ );
+ }
+
if config.emit_no_opt_bc {
let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name);
let out = path_to_c_string(&out);
extra_passes.as_ptr(),
extra_passes.len() as size_t,
);
- llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
- llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
+ llvm::LLVMRustPassManagerBuilderPopulateFunctionPassManager(b, fpm);
+ llvm::LLVMRustPassManagerBuilderPopulateModulePassManager(b, mpm);
});
have_name_anon_globals_pass = have_name_anon_globals_pass || prepare_for_thin_lto;
// Create the PassManagerBuilder for LLVM. We configure it with
// reasonable defaults and prepare it to actually populate the pass
// manager.
- let builder = llvm::LLVMPassManagerBuilderCreate();
+ let builder = llvm::LLVMRustPassManagerBuilderCreate();
let opt_size = config.opt_size.map_or(llvm::CodeGenOptSizeNone, |x| to_llvm_opt_settings(x).1);
let inline_threshold = config.inline_threshold;
let pgo_gen_path = get_pgo_gen_path(config);
pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
pgo_sample_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
+ opt_size as c_int,
);
- llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32);
-
- if opt_size != llvm::CodeGenOptSizeNone {
- llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1);
- }
-
llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins);
// Here we match what clang does (kinda). For O0 we only inline
// thresholds copied from clang.
match (opt_level, opt_size, inline_threshold) {
(.., Some(t)) => {
- llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t);
+ llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, t);
}
(llvm::CodeGenOptLevel::Aggressive, ..) => {
- llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
+ llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 275);
}
(_, llvm::CodeGenOptSizeDefault, _) => {
- llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 75);
+ llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 75);
}
(_, llvm::CodeGenOptSizeAggressive, _) => {
- llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
+ llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 25);
}
(llvm::CodeGenOptLevel::None, ..) => {
llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
}
(llvm::CodeGenOptLevel::Default, ..) => {
- llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
+ llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 225);
}
}
f(builder);
- llvm::LLVMPassManagerBuilderDispose(builder);
+ llvm::LLVMRustPassManagerBuilderDispose(builder);
}
// Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
let DINodeCreationResult { di_node, already_stored_in_typemap } = match *t.kind() {
ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
- DINodeCreationResult::new(build_basic_type_di_node(cx, t), false)
- }
- ty::Tuple(elements) if elements.is_empty() => {
- DINodeCreationResult::new(build_basic_type_di_node(cx, t), false)
+ build_basic_type_di_node(cx, t)
}
+ ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t),
ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t),
ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id),
ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id),
}
}
-fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
+fn build_basic_type_di_node<'ll, 'tcx>(
+ cx: &CodegenCx<'ll, 'tcx>,
+ t: Ty<'tcx>,
+) -> DINodeCreationResult<'ll> {
debug!("build_basic_type_di_node: {:?}", t);
// When targeting MSVC, emit MSVC style type names for compatibility with
let (name, encoding) = match t.kind() {
ty::Never => ("!", DW_ATE_unsigned),
- ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned),
+ ty::Tuple(elements) if elements.is_empty() => {
+ if cpp_like_debuginfo {
+ return build_tuple_type_di_node(cx, UniqueTypeId::for_ty(cx.tcx, t));
+ } else {
+ ("()", DW_ATE_unsigned)
+ }
+ }
ty::Bool => ("bool", DW_ATE_boolean),
ty::Char => ("char", DW_ATE_UTF),
ty::Int(int_ty) if cpp_like_debuginfo => (int_ty.msvc_basic_name(), DW_ATE_signed),
};
if !cpp_like_debuginfo {
- return ty_di_node;
+ return DINodeCreationResult::new(ty_di_node, false);
}
let typedef_name = match t.kind() {
ty::Int(int_ty) => int_ty.name_str(),
ty::Uint(uint_ty) => uint_ty.name_str(),
ty::Float(float_ty) => float_ty.name_str(),
- _ => return ty_di_node,
+ _ => return DINodeCreationResult::new(ty_di_node, false),
};
let typedef_di_node = unsafe {
)
};
- typedef_di_node
+ DINodeCreationResult::new(typedef_di_node, false)
}
fn build_foreign_type_di_node<'ll, 'tcx>(
pub fn LLVMAddAnalysisPasses<'a>(T: &'a TargetMachine, PM: &PassManager<'a>);
- pub fn LLVMPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;
- pub fn LLVMPassManagerBuilderDispose(PMB: &'static mut PassManagerBuilder);
- pub fn LLVMPassManagerBuilderSetSizeLevel(PMB: &PassManagerBuilder, Value: Bool);
- pub fn LLVMPassManagerBuilderSetDisableUnrollLoops(PMB: &PassManagerBuilder, Value: Bool);
- pub fn LLVMPassManagerBuilderUseInlinerWithThreshold(
+ pub fn LLVMRustPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;
+ pub fn LLVMRustPassManagerBuilderDispose(PMB: &'static mut PassManagerBuilder);
+ pub fn LLVMRustPassManagerBuilderUseInlinerWithThreshold(
PMB: &PassManagerBuilder,
threshold: c_uint,
);
- pub fn LLVMPassManagerBuilderPopulateModulePassManager(
+ pub fn LLVMRustPassManagerBuilderPopulateModulePassManager(
PMB: &PassManagerBuilder,
PM: &PassManager<'_>,
);
- pub fn LLVMPassManagerBuilderPopulateFunctionPassManager(
+ pub fn LLVMRustPassManagerBuilderPopulateFunctionPassManager(
PMB: &PassManagerBuilder,
PM: &PassManager<'_>,
);
- pub fn LLVMPassManagerBuilderPopulateLTOPassManager(
+ pub fn LLVMRustPassManagerBuilderPopulateLTOPassManager(
PMB: &PassManagerBuilder,
PM: &PassManager<'_>,
Internalize: Bool,
PGOGenPath: *const c_char,
PGOUsePath: *const c_char,
PGOSampleUsePath: *const c_char,
+ SizeLevel: c_int,
);
pub fn LLVMRustAddLibraryInfo<'a>(
PM: &PassManager<'a>,
// The new pass manager is enabled by default for LLVM >= 13.
// This matches Clang, which also enables it since Clang 13.
+ // Since LLVM 15, the legacy pass manager is no longer supported.
+ if llvm_util::get_version() >= (15, 0, 0) {
+ return true;
+ }
+
// There are some perf issues with the new pass manager when targeting
// s390x with LLVM 13, so enable the new pass manager only with LLVM 14.
// See https://github.com/rust-lang/rust/issues/89609.
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc_hir::def_id::CrateNum;
use rustc_middle::middle::dependency_format::Linkage;
+use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
use rustc_session::cstore::DllImport;
// 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.
//
}
}
+/// Add a synthetic object file that contains reference to all symbols that we want to expose to
+/// the linker.
+///
+/// Background: we implement rlibs as static library (archives). Linkers treat archives
+/// differently from object files: all object files participate in linking, while archives will
+/// only participate in linking if they can satisfy at least one undefined reference (version
+/// scripts doesn't count). This causes `#[no_mangle]` or `#[used]` items to be ignored by the
+/// linker, and since they never participate in the linking, using `KEEP` in the linker scripts
+/// can't keep them either. This causes #47384.
+///
+/// To keep them around, we could use `--whole-archive` and equivalents to force rlib to
+/// participate in linking like object files, but this proves to be expensive (#93791). Therefore
+/// we instead just introduce an undefined reference to them. This could be done by `-u` command
+/// line option to the linker or `EXTERN(...)` in linker scripts, however they does not only
+/// introduce an undefined reference, but also make them the GC roots, preventing `--gc-sections`
+/// from removing them, and this is especially problematic for embedded programming where every
+/// byte counts.
+///
+/// This method creates a synthetic object file, which contains undefined references to all symbols
+/// that are necessary for the linking. They are only present in symbol table but not actually
+/// used in any sections, so the linker will therefore pick relevant rlibs for linking, but
+/// unused `#[no_mangle]` or `#[used]` can still be discard by GC sections.
+fn add_linked_symbol_object(
+ cmd: &mut dyn Linker,
+ sess: &Session,
+ tmpdir: &Path,
+ symbols: &[(String, SymbolExportKind)],
+) {
+ if symbols.is_empty() {
+ return;
+ }
+
+ let Some(mut file) = super::metadata::create_object_file(sess) else {
+ return;
+ };
+
+ // NOTE(nbdd0121): MSVC will hang if the input object file contains no sections,
+ // so add an empty section.
+ if file.format() == object::BinaryFormat::Coff {
+ file.add_section(Vec::new(), ".text".into(), object::SectionKind::Text);
+ }
+
+ for (sym, kind) in symbols.iter() {
+ file.add_symbol(object::write::Symbol {
+ name: sym.clone().into(),
+ value: 0,
+ size: 0,
+ kind: match kind {
+ SymbolExportKind::Text => object::SymbolKind::Text,
+ SymbolExportKind::Data => object::SymbolKind::Data,
+ SymbolExportKind::Tls => object::SymbolKind::Tls,
+ },
+ scope: object::SymbolScope::Unknown,
+ weak: false,
+ section: object::write::SymbolSection::Undefined,
+ flags: object::SymbolFlags::None,
+ });
+ }
+
+ let path = tmpdir.join("symbols.o");
+ let result = std::fs::write(&path, file.write().unwrap());
+ if let Err(e) = result {
+ sess.fatal(&format!("failed to write {}: {}", path.display(), e));
+ }
+ cmd.add_object(&path);
+}
+
/// Add object files containing code from the current crate.
fn add_local_crate_regular_objects(cmd: &mut dyn Linker, codegen_results: &CodegenResults) {
for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
// Pre-link CRT objects.
add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
+ add_linked_symbol_object(
+ cmd,
+ sess,
+ tmpdir,
+ &codegen_results.crate_info.linked_symbols[&crate_type],
+ );
+
// Sanitizer libraries.
add_sanitizer_libraries(sess, crate_type, cmd);
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_middle::middle::dependency_format::Linkage;
+use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
use rustc_middle::ty::TyCtxt;
use rustc_serialize::{json, Encoder};
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
}
}
+fn for_each_exported_symbols_include_dep<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ crate_type: CrateType,
+ mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum),
+) {
+ for &(symbol, info) in tcx.exported_symbols(LOCAL_CRATE).iter() {
+ callback(symbol, info, LOCAL_CRATE);
+ }
+
+ let formats = tcx.dependency_formats(());
+ let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap();
+
+ for (index, dep_format) in deps.iter().enumerate() {
+ let cnum = CrateNum::new(index + 1);
+ // For each dependency that we are linking to statically ...
+ if *dep_format == Linkage::Static {
+ for &(symbol, info) in tcx.exported_symbols(cnum).iter() {
+ callback(symbol, info, cnum);
+ }
+ }
+ }
+}
+
pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
if let Some(ref exports) = tcx.sess.target.override_export_symbols {
return exports.iter().map(ToString::to_string).collect();
let mut symbols = Vec::new();
let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
- for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
- if level.is_below_threshold(export_threshold) {
- symbols.push(symbol_export::symbol_name_for_instance_in_crate(
- tcx,
- symbol,
- LOCAL_CRATE,
- ));
+ for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
+ if info.level.is_below_threshold(export_threshold) {
+ symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum));
}
- }
+ });
- let formats = tcx.dependency_formats(());
- let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap();
-
- for (index, dep_format) in deps.iter().enumerate() {
- let cnum = CrateNum::new(index + 1);
- // For each dependency that we are linking to statically ...
- if *dep_format == Linkage::Static {
- // ... we add its symbol list to our export list.
- for &(symbol, level) in tcx.exported_symbols(cnum).iter() {
- if !level.is_below_threshold(export_threshold) {
- continue;
- }
+ symbols
+}
- symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum));
- }
+pub(crate) fn linked_symbols(
+ tcx: TyCtxt<'_>,
+ crate_type: CrateType,
+) -> Vec<(String, SymbolExportKind)> {
+ match crate_type {
+ CrateType::Executable | CrateType::Cdylib => (),
+ CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib | CrateType::Dylib => {
+ return Vec::new();
}
}
+ let mut symbols = Vec::new();
+
+ let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
+ for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
+ if info.level.is_below_threshold(export_threshold) || info.used {
+ symbols.push((
+ symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum),
+ info.kind,
+ ));
+ }
+ });
+
symbols
}
.map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
}
-fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
+pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
let endianness = match sess.target.options.endian {
Endian::Little => Endianness::Little,
Endian::Big => Endianness::Big,
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,
+ metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
};
use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
}
}
-fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<SymbolExportLevel> {
+fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<SymbolExportInfo> {
assert_eq!(cnum, LOCAL_CRATE);
if !tcx.sess.opts.output_types.should_codegen() {
}
})
.map(|def_id| {
- let export_level = if special_runtime_crate {
+ let (export_level, used) = if special_runtime_crate {
let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name;
- // We can probably do better here by just ensuring that
- // it has hidden visibility rather than public
- // visibility, as this is primarily here to ensure it's
- // not stripped during LTO.
- //
- // In general though we won't link right if these
- // symbols are stripped, and LTO currently strips them.
- match name {
+ // We won't link right if these symbols are stripped during LTO.
+ let used = match name {
"rust_eh_personality"
| "rust_eh_register_frames"
- | "rust_eh_unregister_frames" =>
- SymbolExportLevel::C,
- _ => SymbolExportLevel::Rust,
- }
+ | "rust_eh_unregister_frames" => true,
+ _ => false,
+ };
+ (SymbolExportLevel::Rust, used)
} else {
- symbol_export_level(tcx, def_id.to_def_id())
+ (symbol_export_level(tcx, def_id.to_def_id()), false)
};
+ let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id());
debug!(
"EXPORTED SYMBOL (local): {} ({:?})",
tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())),
export_level
);
- (def_id.to_def_id(), export_level)
+ (def_id.to_def_id(), SymbolExportInfo {
+ level: export_level,
+ kind: if tcx.is_static(def_id.to_def_id()) {
+ if codegen_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
+ SymbolExportKind::Tls
+ } else {
+ SymbolExportKind::Data
+ }
+ } else {
+ SymbolExportKind::Text
+ },
+ used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
+ || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) || used,
+ })
})
.collect();
if let Some(id) = tcx.proc_macro_decls_static(()) {
- reachable_non_generics.insert(id.to_def_id(), SymbolExportLevel::C);
+ reachable_non_generics.insert(
+ id.to_def_id(),
+ SymbolExportInfo {
+ level: SymbolExportLevel::C,
+ kind: SymbolExportKind::Data,
+ used: false,
+ },
+ );
}
reachable_non_generics
fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
let export_threshold = threshold(tcx);
- if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) {
- level.is_below_threshold(export_threshold)
+ if let Some(&info) = tcx.reachable_non_generics(def_id.krate).get(&def_id) {
+ info.level.is_below_threshold(export_threshold)
} else {
false
}
fn exported_symbols_provider_local<'tcx>(
tcx: TyCtxt<'tcx>,
cnum: CrateNum,
-) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
+) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
assert_eq!(cnum, LOCAL_CRATE);
if !tcx.sess.opts.output_types.should_codegen() {
let mut symbols: Vec<_> = tcx
.reachable_non_generics(LOCAL_CRATE)
.iter()
- .map(|(&def_id, &level)| (ExportedSymbol::NonGeneric(def_id), level))
+ .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info))
.collect();
if tcx.entry_fn(()).is_some() {
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, "main"));
- symbols.push((exported_symbol, SymbolExportLevel::C));
+ symbols.push((
+ exported_symbol,
+ SymbolExportInfo {
+ level: SymbolExportLevel::C,
+ kind: SymbolExportKind::Text,
+ used: false,
+ },
+ ));
}
if tcx.allocator_kind(()).is_some() {
let symbol_name = format!("__rust_{}", method.name);
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
- symbols.push((exported_symbol, SymbolExportLevel::Rust));
+ symbols.push((
+ exported_symbol,
+ SymbolExportInfo {
+ level: SymbolExportLevel::Rust,
+ kind: SymbolExportKind::Text,
+ used: false,
+ },
+ ));
}
}
symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| {
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
- (exported_symbol, SymbolExportLevel::C)
+ (
+ exported_symbol,
+ SymbolExportInfo {
+ level: SymbolExportLevel::C,
+ kind: SymbolExportKind::Data,
+ used: false,
+ },
+ )
}));
}
if tcx.sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::MEMORY) {
+ let mut msan_weak_symbols = Vec::new();
+
// Similar to profiling, preserve weak msan symbol during LTO.
- const MSAN_WEAK_SYMBOLS: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"];
+ if tcx.sess.opts.debugging_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) {
+ msan_weak_symbols.push("__msan_keep_going");
+ }
- symbols.extend(MSAN_WEAK_SYMBOLS.iter().map(|sym| {
+ if tcx.sess.opts.debugging_opts.sanitizer_memory_track_origins != 0 {
+ msan_weak_symbols.push("__msan_track_origins");
+ }
+
+ symbols.extend(msan_weak_symbols.into_iter().map(|sym| {
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
- (exported_symbol, SymbolExportLevel::C)
+ (
+ exported_symbol,
+ SymbolExportInfo {
+ level: SymbolExportLevel::C,
+ kind: SymbolExportKind::Data,
+ used: false,
+ },
+ )
}));
}
let symbol_name = metadata_symbol_name(tcx);
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
- symbols.push((exported_symbol, SymbolExportLevel::Rust));
+ symbols.push((
+ exported_symbol,
+ SymbolExportInfo {
+ level: SymbolExportLevel::Rust,
+ kind: SymbolExportKind::Data,
+ used: false,
+ },
+ ));
}
if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() {
MonoItem::Fn(Instance { def: InstanceDef::Item(def), substs }) => {
if substs.non_erasable_generics().next().is_some() {
let symbol = ExportedSymbol::Generic(def.did, substs);
- symbols.push((symbol, SymbolExportLevel::Rust));
+ symbols.push((
+ symbol,
+ SymbolExportInfo {
+ level: SymbolExportLevel::Rust,
+ kind: SymbolExportKind::Text,
+ used: false,
+ },
+ ));
}
}
MonoItem::Fn(Instance { def: InstanceDef::DropGlue(_, Some(ty)), substs }) => {
substs.non_erasable_generics().next(),
Some(GenericArgKind::Type(ty))
);
- symbols.push((ExportedSymbol::DropGlue(ty), SymbolExportLevel::Rust));
+ symbols.push((
+ ExportedSymbol::DropGlue(ty),
+ SymbolExportInfo {
+ level: SymbolExportLevel::Rust,
+ kind: SymbolExportKind::Text,
+ used: false,
+ },
+ ));
}
_ => {
// Any other symbols don't qualify for sharing
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);
}
}
};
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::exported_symbols::SymbolExportLevel;
+use rustc_middle::middle::exported_symbols::SymbolExportInfo;
use rustc_middle::ty::TyCtxt;
use rustc_session::cgu_reuse_tracker::CguReuseTracker;
use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType};
+ Sync,
>;
-pub type ExportedSymbols = FxHashMap<CrateNum, Arc<Vec<(String, SymbolExportLevel)>>>;
+pub type ExportedSymbols = FxHashMap<CrateNum, Arc<Vec<(String, SymbolExportInfo)>>>;
/// Additional resources used by optimize_and_codegen (not module specific)
#[derive(Clone)]
.iter()
.map(|&c| (c, crate::back::linker::exported_symbols(tcx, c)))
.collect();
+ let linked_symbols = tcx
+ .sess
+ .crate_types()
+ .iter()
+ .map(|&c| (c, crate::back::linker::linked_symbols(tcx, c)))
+ .collect();
let local_crate_name = tcx.crate_name(LOCAL_CRATE);
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
let mut info = CrateInfo {
target_cpu,
exported_symbols,
+ linked_symbols,
local_crate_name,
compiler_builtins: None,
profiler_runtime: None,
use rustc_hir::LangItem;
use rustc_middle::dep_graph::WorkProduct;
use rustc_middle::middle::dependency_format::Dependencies;
+use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_serialize::{opaque, Decodable, Decoder, Encoder};
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
pub struct CrateInfo {
pub target_cpu: String,
pub exported_symbols: FxHashMap<CrateType, Vec<String>>,
+ pub linked_symbols: FxHashMap<CrateType, Vec<(String, SymbolExportKind)>>,
pub local_crate_name: Symbol,
pub compiler_builtins: Option<CrateNum>,
pub profiler_runtime: Option<CrateNum>,
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 visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
// This check is somewhat expensive, so only run it when -Zvalidate-mir is passed.
- if self.tcx.sess.opts.debugging_opts.validate_mir {
+ if self.tcx.sess.opts.debugging_opts.validate_mir && self.mir_phase < MirPhase::DropsLowered
+ {
// `Operand::Copy` is only supposed to be used with `Copy` types.
if let Operand::Copy(place) = operand {
let ty = place.ty(&self.body.local_decls, self.tcx).ty;
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() {
/// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes
/// it easy to declare such methods on the builder.
macro_rules! forward {
- // Forward pattern for &self -> &Self
- (
- $(#[$attrs:meta])*
- pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)?) -> &Self
- ) => {
- $(#[$attrs])*
- #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")]
- pub fn $n(&self, $($name: $ty),*) -> &Self {
- self.diagnostic.$n($($name),*);
- self
- }
- };
-
// Forward pattern for &mut self -> &mut Self
(
$(#[$attrs:meta])*
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)]
/// 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 rustc_errors::ErrorGuaranteed;
use rustc_parse::nt_to_tokenstream;
use rustc_parse::parser::ForceCollect;
+use rustc_span::profiling::SpannedEventArgRecorder;
use rustc_span::{Span, DUMMY_SP};
const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
input: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
let _timer =
- ecx.sess.prof.generic_activity_with_arg("expand_proc_macro", ecx.expansion_descr());
+ ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
+ recorder.record_arg_with_span(ecx.expansion_descr(), span);
+ });
+
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace).map_err(|e| {
annotated: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
let _timer =
- ecx.sess.prof.generic_activity_with_arg("expand_proc_macro", ecx.expansion_descr());
+ ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
+ recorder.record_arg_with_span(ecx.expansion_descr(), span);
+ });
+
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
self.client
let stream = {
let _timer =
- ecx.sess.prof.generic_activity_with_arg("expand_proc_macro", ecx.expansion_descr());
+ ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
+ recorder.record_arg_with_span(ecx.expansion_descr(), span);
+ });
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
match self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace) {
-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,
use crate::intravisit::FnKind;
use crate::LangItem;
+use rustc_ast as ast;
use rustc_ast::util::parser::ExprPrecedence;
-use rustc_ast::{self as ast, CrateSugar};
use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy};
pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
pub use rustc_ast::{CaptureBy, Movability, Mutability};
pub struct ImplItem<'hir> {
pub ident: Ident,
pub def_id: LocalDefId,
- pub vis: Visibility<'hir>,
pub generics: Generics<'hir>,
pub kind: ImplItemKind<'hir>,
pub span: Span,
+ pub vis_span: Span,
}
impl ImplItem<'_> {
pub span: Span,
}
-pub type Visibility<'hir> = Spanned<VisibilityKind<'hir>>;
-
-#[derive(Copy, Clone, Debug, HashStable_Generic)]
-pub enum VisibilityKind<'hir> {
- Public,
- Crate(CrateSugar),
- Restricted { path: &'hir Path<'hir>, hir_id: HirId },
- Inherited,
-}
-
-impl VisibilityKind<'_> {
- pub fn is_pub(&self) -> bool {
- matches!(*self, VisibilityKind::Public)
- }
-
- pub fn is_pub_restricted(&self) -> bool {
- match *self {
- VisibilityKind::Public | VisibilityKind::Inherited => false,
- VisibilityKind::Crate(..) | VisibilityKind::Restricted { .. } => true,
- }
- }
-}
-
#[derive(Debug, HashStable_Generic)]
pub struct FieldDef<'hir> {
pub span: Span,
+ pub vis_span: Span,
pub ident: Ident,
- pub vis: Visibility<'hir>,
pub hir_id: HirId,
pub ty: &'hir Ty<'hir>,
}
pub ident: Ident,
pub def_id: LocalDefId,
pub kind: ItemKind<'hir>,
- pub vis: Visibility<'hir>,
pub span: Span,
+ pub vis_span: Span,
}
impl Item<'_> {
pub kind: ForeignItemKind<'hir>,
pub def_id: LocalDefId,
pub span: Span,
- pub vis: Visibility<'hir>,
+ pub vis_span: Span,
}
impl ForeignItem<'_> {
Lifetime(&'hir Lifetime),
GenericParam(&'hir GenericParam<'hir>),
- Visibility(&'hir Visibility<'hir>),
Crate(&'hir Mod<'hir>),
| Node::Binding(..)
| Node::Arm(..)
| Node::Local(..)
- | Node::Visibility(..)
| Node::Crate(..)
| Node::Ty(..)
| Node::TraitRef(..)
match self {
Node::Item(i) => match i.kind {
ItemKind::Fn(ref sig, ref generics, _) => {
- Some(FnKind::ItemFn(i.ident, generics, sig.header, &i.vis))
+ Some(FnKind::ItemFn(i.ident, generics, sig.header))
}
_ => None,
},
Node::TraitItem(ti) => match ti.kind {
TraitItemKind::Fn(ref sig, TraitFn::Provided(_)) => {
- Some(FnKind::Method(ti.ident, sig, None))
+ Some(FnKind::Method(ti.ident, sig))
}
_ => None,
},
Node::ImplItem(ii) => match ii.kind {
- ImplItemKind::Fn(ref sig, _) => Some(FnKind::Method(ii.ident, sig, Some(&ii.vis))),
+ ImplItemKind::Fn(ref sig, _) => Some(FnKind::Method(ii.ident, sig)),
_ => None,
},
Node::Expr(e) => match e.kind {
_ => None,
}
}
+
+ /// Get the fields for the tuple-constructor,
+ /// if this node is a tuple constructor, otherwise None
+ pub fn tuple_fields(&self) -> Option<&'hir [FieldDef<'hir>]> {
+ if let Node::Ctor(&VariantData::Tuple(fields, _)) = self { Some(fields) } else { None }
+ }
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
- rustc_data_structures::static_assert_size!(super::Item<'static>, 184);
+ rustc_data_structures::static_assert_size!(super::Item<'static>, 160);
rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128);
- rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 144);
- rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 136);
+ rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 120);
+ rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 112);
}
-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) };
#[derive(Copy, Clone, Debug)]
pub enum FnKind<'a> {
/// `#[xxx] pub async/const/extern "Abi" fn foo()`
- ItemFn(Ident, &'a Generics<'a>, FnHeader, &'a Visibility<'a>),
+ ItemFn(Ident, &'a Generics<'a>, FnHeader),
/// `fn foo(&self)`
- Method(Ident, &'a FnSig<'a>, Option<&'a Visibility<'a>>),
+ Method(Ident, &'a FnSig<'a>),
/// `|x, y| {}`
Closure,
impl<'a> FnKind<'a> {
pub fn header(&self) -> Option<&FnHeader> {
match *self {
- FnKind::ItemFn(_, _, ref header, _) => Some(header),
- FnKind::Method(_, ref sig, _) => Some(&sig.header),
+ FnKind::ItemFn(_, _, ref header) => Some(header),
+ FnKind::Method(_, ref sig) => Some(&sig.header),
FnKind::Closure => None,
}
}
walk_assoc_type_binding(self, type_binding)
}
fn visit_attribute(&mut self, _id: HirId, _attr: &'v Attribute) {}
- fn visit_vis(&mut self, vis: &'v Visibility<'v>) {
- walk_vis(self, vis)
- }
fn visit_associated_item_kind(&mut self, kind: &'v AssocItemKind) {
walk_associated_item_kind(self, kind);
}
}
pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
- visitor.visit_vis(&item.vis);
visitor.visit_ident(item.ident);
match item.kind {
ItemKind::ExternCrate(orig_name) => {
visitor.visit_nested_body(body);
}
ItemKind::Fn(ref sig, ref generics, body_id) => visitor.visit_fn(
- FnKind::ItemFn(item.ident, generics, sig.header, &item.vis),
+ FnKind::ItemFn(item.ident, generics, sig.header),
&sig.decl,
body_id,
item.span,
pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem<'v>) {
visitor.visit_id(foreign_item.hir_id());
- visitor.visit_vis(&foreign_item.vis);
visitor.visit_ident(foreign_item.ident);
match foreign_item.kind {
}
TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => {
visitor.visit_fn(
- FnKind::Method(trait_item.ident, sig, None),
+ FnKind::Method(trait_item.ident, sig),
&sig.decl,
body_id,
trait_item.span,
pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
// N.B., deliberately force a compilation error if/when new fields are added.
- let ImplItem { def_id: _, ident, ref vis, ref generics, ref kind, span: _ } = *impl_item;
+ let ImplItem { def_id: _, ident, ref generics, ref kind, span: _, vis_span: _ } = *impl_item;
visitor.visit_ident(ident);
- visitor.visit_vis(vis);
visitor.visit_generics(generics);
match *kind {
ImplItemKind::Const(ref ty, body) => {
}
ImplItemKind::Fn(ref sig, body_id) => {
visitor.visit_fn(
- FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis)),
+ FnKind::Method(impl_item.ident, sig),
&sig.decl,
body_id,
impl_item.span,
pub fn walk_field_def<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v FieldDef<'v>) {
visitor.visit_id(field.hir_id);
- visitor.visit_vis(&field.vis);
visitor.visit_ident(field.ident);
visitor.visit_ty(&field.ty);
}
visitor.visit_expr(&arm.body);
}
-pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility<'v>) {
- if let VisibilityKind::Restricted { ref path, hir_id } = vis.node {
- visitor.visit_id(hir_id);
- visitor.visit_path(path, hir_id)
- }
-}
-
pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssocItemKind) {
// No visitable content here: this fn exists so you can call it if
// the right thing to do, should content be added in the future,
use rustc_hir as hir;
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term};
use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
-use rustc_span::source_map::{SourceMap, Spanned};
+use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol};
use rustc_span::{self, FileName};
use rustc_target::spec::abi::Abi;
-use std::borrow::Cow;
use std::cell::Cell;
use std::vec;
self.print_block(&a)
}
Node::Lifetime(a) => self.print_lifetime(&a),
- Node::Visibility(a) => self.print_visibility(&a),
Node::GenericParam(_) => panic!("cannot print Node::GenericParam"),
Node::Field(_) => panic!("cannot print Node::Field"),
// These cases do not carry enough information in the
printer.s.eof()
}
-pub fn visibility_qualified<S: Into<Cow<'static, str>>>(vis: &hir::Visibility<'_>, w: S) -> String {
- to_string(NO_ANN, |s| {
- s.print_visibility(vis);
- s.word(w)
- })
-}
-
pub fn generic_params_to_string(generic_params: &[GenericParam<'_>]) -> String {
to_string(NO_ANN, |s| s.print_generic_params(generic_params))
}
header: hir::FnHeader,
name: Option<Symbol>,
generics: &hir::Generics<'_>,
- vis: &hir::Visibility<'_>,
arg_names: &[Ident],
body_id: Option<hir::BodyId>,
) -> String {
- to_string(NO_ANN, |s| s.print_fn(decl, header, name, generics, vis, arg_names, body_id))
+ to_string(NO_ANN, |s| s.print_fn(decl, header, name, generics, arg_names, body_id))
}
pub fn enum_def_to_string(
generics: &hir::Generics<'_>,
name: Symbol,
span: rustc_span::Span,
- visibility: &hir::Visibility<'_>,
) -> String {
- to_string(NO_ANN, |s| s.print_enum_def(enum_definition, generics, name, span, visibility))
+ to_string(NO_ANN, |s| s.print_enum_def(enum_definition, generics, name, span))
}
impl<'a> State<'a> {
},
Some(item.ident.name),
generics,
- &item.vis,
arg_names,
None,
);
self.end() // end the outer fn box
}
hir::ForeignItemKind::Static(ref t, m) => {
- self.head(visibility_qualified(&item.vis, "static"));
+ self.head("static");
if m == hir::Mutability::Mut {
self.word_space("mut");
}
self.end() // end the outer cbox
}
hir::ForeignItemKind::Type => {
- self.head(visibility_qualified(&item.vis, "type"));
+ self.head("type");
self.print_ident(item.ident);
self.word(";");
self.end(); // end the head-ibox
ident: Ident,
ty: &hir::Ty<'_>,
default: Option<hir::BodyId>,
- vis: &hir::Visibility<'_>,
) {
- self.word(visibility_qualified(vis, ""));
+ self.head("");
self.word_space("const");
self.print_ident(ident);
self.word_space(":");
generics: &hir::Generics<'_>,
inner: impl Fn(&mut Self),
) {
- self.head(visibility_qualified(&item.vis, "type"));
+ self.head("type");
self.print_ident(item.ident);
self.print_generic_params(&generics.params);
self.end(); // end the inner ibox
self.ann.pre(self, AnnNode::Item(item));
match item.kind {
hir::ItemKind::ExternCrate(orig_name) => {
- self.head(visibility_qualified(&item.vis, "extern crate"));
+ self.head("extern crate");
if let Some(orig_name) = orig_name {
self.print_name(orig_name);
self.space();
self.end(); // end outer head-block
}
hir::ItemKind::Use(ref path, kind) => {
- self.head(visibility_qualified(&item.vis, "use"));
+ self.head("use");
self.print_path(path, false);
match kind {
self.end(); // end outer head-block
}
hir::ItemKind::Static(ref ty, m, expr) => {
- self.head(visibility_qualified(&item.vis, "static"));
+ self.head("static");
if m == hir::Mutability::Mut {
self.word_space("mut");
}
self.end(); // end the outer cbox
}
hir::ItemKind::Const(ref ty, expr) => {
- self.head(visibility_qualified(&item.vis, "const"));
+ self.head("const");
self.print_ident(item.ident);
self.word_space(":");
self.print_type(&ty);
sig.header,
Some(item.ident.name),
param_names,
- &item.vis,
&[],
Some(body),
);
self.ann.nested(self, Nested::Body(body));
}
hir::ItemKind::Macro(ref macro_def, _) => {
- self.print_mac_def(macro_def, &item.ident, item.span, |state| {
- state.print_visibility(&item.vis)
- });
+ self.print_mac_def(macro_def, &item.ident, item.span, |_| {});
}
hir::ItemKind::Mod(ref _mod) => {
- self.head(visibility_qualified(&item.vis, "mod"));
+ self.head("mod");
self.print_ident(item.ident);
self.nbsp();
self.bopen();
self.bclose(item.span);
}
hir::ItemKind::GlobalAsm(ref asm) => {
- self.head(visibility_qualified(&item.vis, "global_asm!"));
+ self.head("global_asm!");
self.print_inline_asm(asm);
self.end()
}
});
}
hir::ItemKind::Enum(ref enum_definition, ref params) => {
- self.print_enum_def(enum_definition, params, item.ident.name, item.span, &item.vis);
+ self.print_enum_def(enum_definition, params, item.ident.name, item.span);
}
hir::ItemKind::Struct(ref struct_def, ref generics) => {
- self.head(visibility_qualified(&item.vis, "struct"));
+ self.head("struct");
self.print_struct(struct_def, generics, item.ident.name, item.span, true);
}
hir::ItemKind::Union(ref struct_def, ref generics) => {
- self.head(visibility_qualified(&item.vis, "union"));
+ self.head("union");
self.print_struct(struct_def, generics, item.ident.name, item.span, true);
}
hir::ItemKind::Impl(hir::Impl {
items,
}) => {
self.head("");
- self.print_visibility(&item.vis);
self.print_defaultness(defaultness);
self.print_unsafety(unsafety);
self.word_nbsp("impl");
}
hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, trait_items) => {
self.head("");
- self.print_visibility(&item.vis);
self.print_is_auto(is_auto);
self.print_unsafety(unsafety);
self.word_nbsp("trait");
self.bclose(item.span);
}
hir::ItemKind::TraitAlias(ref generics, ref bounds) => {
- self.head(visibility_qualified(&item.vis, "trait"));
+ self.head("trait");
self.print_ident(item.ident);
self.print_generic_params(&generics.params);
let mut real_bounds = Vec::with_capacity(bounds.len());
generics: &hir::Generics<'_>,
name: Symbol,
span: rustc_span::Span,
- visibility: &hir::Visibility<'_>,
) {
- self.head(visibility_qualified(visibility, "enum"));
+ self.head("enum");
self.print_name(name);
self.print_generic_params(&generics.params);
self.print_where_clause(&generics.where_clause);
self.bclose(span)
}
- pub fn print_visibility(&mut self, vis: &hir::Visibility<'_>) {
- match vis.node {
- hir::VisibilityKind::Public => self.word_nbsp("pub"),
- hir::VisibilityKind::Crate(ast::CrateSugar::JustCrate) => self.word_nbsp("crate"),
- hir::VisibilityKind::Crate(ast::CrateSugar::PubCrate) => self.word_nbsp("pub(crate)"),
- hir::VisibilityKind::Restricted { ref path, .. } => {
- self.word("pub(");
- if path.segments.len() == 1 && path.segments[0].ident.name == kw::Super {
- // Special case: `super` can print like `pub(super)`.
- self.word("super");
- } else {
- // Everything else requires `in` at present.
- self.word_nbsp("in");
- self.print_path(path, false);
- }
- self.word_nbsp(")");
- }
- hir::VisibilityKind::Inherited => (),
- }
- }
-
pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) {
match defaultness {
hir::Defaultness::Default { .. } => self.word_nbsp("default"),
self.commasep(Inconsistent, struct_def.fields(), |s, field| {
s.maybe_print_comment(field.span.lo());
s.print_outer_attributes(s.attrs(field.hir_id));
- s.print_visibility(&field.vis);
s.print_type(&field.ty)
});
self.pclose();
self.hardbreak_if_not_bol();
self.maybe_print_comment(field.span.lo());
self.print_outer_attributes(self.attrs(field.hir_id));
- self.print_visibility(&field.vis);
self.print_ident(field.ident);
self.word_nbsp(":");
self.print_type(&field.ty);
ident: Ident,
m: &hir::FnSig<'_>,
generics: &hir::Generics<'_>,
- vis: &hir::Visibility<'_>,
arg_names: &[Ident],
body_id: Option<hir::BodyId>,
) {
- self.print_fn(&m.decl, m.header, Some(ident.name), generics, vis, arg_names, body_id)
+ self.print_fn(&m.decl, m.header, Some(ident.name), generics, arg_names, body_id)
}
pub fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) {
self.print_outer_attributes(self.attrs(ti.hir_id()));
match ti.kind {
hir::TraitItemKind::Const(ref ty, default) => {
- let vis =
- Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited };
- self.print_associated_const(ti.ident, &ty, default, &vis);
+ self.print_associated_const(ti.ident, &ty, default);
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref arg_names)) => {
- let vis =
- Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited };
- self.print_method_sig(ti.ident, sig, &ti.generics, &vis, arg_names, None);
+ self.print_method_sig(ti.ident, sig, &ti.generics, arg_names, None);
self.word(";");
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
- let vis =
- Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited };
self.head("");
- self.print_method_sig(ti.ident, sig, &ti.generics, &vis, &[], Some(body));
+ self.print_method_sig(ti.ident, sig, &ti.generics, &[], Some(body));
self.nbsp();
self.end(); // need to close a box
self.end(); // need to close a box
match ii.kind {
hir::ImplItemKind::Const(ref ty, expr) => {
- self.print_associated_const(ii.ident, &ty, Some(expr), &ii.vis);
+ self.print_associated_const(ii.ident, &ty, Some(expr));
}
hir::ImplItemKind::Fn(ref sig, body) => {
self.head("");
- self.print_method_sig(ii.ident, sig, &ii.generics, &ii.vis, &[], Some(body));
+ self.print_method_sig(ii.ident, sig, &ii.generics, &[], Some(body));
self.nbsp();
self.end(); // need to close a box
self.end(); // need to close a box
header: hir::FnHeader,
name: Option<Symbol>,
generics: &hir::Generics<'_>,
- vis: &hir::Visibility<'_>,
arg_names: &[Ident],
body_id: Option<hir::BodyId>,
) {
- self.print_fn_header_info(header, vis);
+ self.print_fn_header_info(header);
if let Some(name) = name {
self.nbsp();
},
name,
&generics,
- &Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited },
arg_names,
None,
);
self.end();
}
- pub fn print_fn_header_info(&mut self, header: hir::FnHeader, vis: &hir::Visibility<'_>) {
- self.word(visibility_qualified(vis, ""));
-
+ pub fn print_fn_header_info(&mut self, header: hir::FnHeader) {
match header.constness {
hir::Constness::NotConst => {}
hir::Constness::Const => self.word_nbsp("const"),
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>>(
use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Item, ItemKind, Node};
use rustc_middle::dep_graph::DepContext;
bound_kind: GenericKind<'tcx>,
sub: Region<'tcx>,
) {
- self.construct_generic_bound_failure(span, origin, bound_kind, sub).emit();
+ let owner =
+ self.in_progress_typeck_results.map(|typeck_results| typeck_results.borrow().hir_owner);
+ self.construct_generic_bound_failure(span, origin, bound_kind, sub, owner).emit();
}
pub fn construct_generic_bound_failure(
origin: Option<SubregionOrigin<'tcx>>,
bound_kind: GenericKind<'tcx>,
sub: Region<'tcx>,
+ owner: Option<LocalDefId>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let hir = self.tcx.hir();
// Attempt to obtain the span of the parameter so we can
// suggest adding an explicit lifetime bound to it.
- let generics = self
- .in_progress_typeck_results
- .map(|typeck_results| typeck_results.borrow().hir_owner)
- .map(|owner| {
- let hir_id = hir.local_def_id_to_hir_id(owner);
- let parent_id = hir.get_parent_item(hir_id);
- (
- // Parent item could be a `mod`, so we check the HIR before calling:
- if let Some(Node::Item(Item {
- kind: ItemKind::Trait(..) | ItemKind::Impl { .. },
- ..
- })) = hir.find_by_def_id(parent_id)
- {
- Some(self.tcx.generics_of(parent_id))
- } else {
- None
- },
- self.tcx.generics_of(owner.to_def_id()),
- hir.span(hir_id),
- )
- });
+ let generics = owner.map(|owner| {
+ let hir_id = hir.local_def_id_to_hir_id(owner);
+ let parent_id = hir.get_parent_item(hir_id);
+ (
+ // Parent item could be a `mod`, so we check the HIR before calling:
+ if let Some(Node::Item(Item {
+ kind: ItemKind::Trait(..) | ItemKind::Impl { .. },
+ ..
+ })) = hir.find_by_def_id(parent_id)
+ {
+ Some(self.tcx.generics_of(parent_id))
+ } else {
+ None
+ },
+ self.tcx.generics_of(owner.to_def_id()),
+ hir.span(hir_id),
+ )
+ });
let span = match generics {
// This is to get around the trait identity obligation, that has a `DUMMY_SP` as signal
None,
);
if let Some(infer::RelateParamBound(_, t, _)) = origin {
- let return_impl_trait = self
- .in_progress_typeck_results
- .map(|typeck_results| typeck_results.borrow().hir_owner)
- .and_then(|owner| self.tcx.return_type_impl_trait(owner))
- .is_some();
+ let return_impl_trait =
+ owner.and_then(|owner| self.tcx.return_type_impl_trait(owner)).is_some();
let t = self.resolve_vars_if_possible(t);
match t.kind() {
// We've got:
mod util;
pub use static_impl_trait::suggest_new_region_bound;
+pub use util::find_param_with_region;
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
//! anonymous regions.
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
+use crate::infer::TyCtxt;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeFoldable};
/// Information about the anonymous region we are searching for.
#[derive(Debug)]
-pub(super) struct AnonymousParamInfo<'tcx> {
+pub struct AnonymousParamInfo<'tcx> {
/// The parameter corresponding to the anonymous region.
pub param: &'tcx hir::Param<'tcx>,
/// The type corresponding to the anonymous region parameter.
pub is_first: bool,
}
+// This method walks the Type of the function body parameters using
+// `fold_regions()` function and returns the
+// &hir::Param of the function parameter corresponding to the anonymous
+// region and the Ty corresponding to the named region.
+// Currently only the case where the function declaration consists of
+// one named region and one anonymous region is handled.
+// Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
+// Here, we would return the hir::Param for y, we return the type &'a
+// i32, which is the type of y but with the anonymous region replaced
+// with 'a, the corresponding bound region and is_first which is true if
+// the hir::Param is the first parameter in the function declaration.
+pub fn find_param_with_region<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ anon_region: Region<'tcx>,
+ replace_region: Region<'tcx>,
+) -> Option<AnonymousParamInfo<'tcx>> {
+ let (id, bound_region) = match *anon_region {
+ ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
+ ty::ReEarlyBound(ebr) => {
+ (tcx.parent(ebr.def_id).unwrap(), ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name))
+ }
+ _ => return None, // not a free region
+ };
+
+ let hir = &tcx.hir();
+ let hir_id = hir.local_def_id_to_hir_id(id.as_local()?);
+ let body_id = hir.maybe_body_owned_by(hir_id)?;
+ let body = hir.body(body_id);
+ let owner_id = hir.body_owner(body_id);
+ let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
+ let poly_fn_sig = tcx.fn_sig(id);
+ let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig);
+ body.params
+ .iter()
+ .take(if fn_sig.c_variadic {
+ fn_sig.inputs().len()
+ } else {
+ assert_eq!(fn_sig.inputs().len(), body.params.len());
+ body.params.len()
+ })
+ .enumerate()
+ .find_map(|(index, param)| {
+ // May return None; sometimes the tables are not yet populated.
+ let ty = fn_sig.inputs()[index];
+ let mut found_anon_region = false;
+ let new_param_ty = tcx.fold_regions(ty, &mut false, |r, _| {
+ if r == anon_region {
+ found_anon_region = true;
+ replace_region
+ } else {
+ r
+ }
+ });
+ if found_anon_region {
+ let ty_hir_id = fn_decl.inputs[index].hir_id;
+ let param_ty_span = hir.span(ty_hir_id);
+ let is_first = index == 0;
+ Some(AnonymousParamInfo {
+ param,
+ param_ty: new_param_ty,
+ param_ty_span,
+ bound_region,
+ is_first,
+ })
+ } else {
+ None
+ }
+ })
+}
+
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
- // This method walks the Type of the function body parameters using
- // `fold_regions()` function and returns the
- // &hir::Param of the function parameter corresponding to the anonymous
- // region and the Ty corresponding to the named region.
- // Currently only the case where the function declaration consists of
- // one named region and one anonymous region is handled.
- // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
- // Here, we would return the hir::Param for y, we return the type &'a
- // i32, which is the type of y but with the anonymous region replaced
- // with 'a, the corresponding bound region and is_first which is true if
- // the hir::Param is the first parameter in the function declaration.
pub(super) fn find_param_with_region(
&self,
anon_region: Region<'tcx>,
replace_region: Region<'tcx>,
) -> Option<AnonymousParamInfo<'_>> {
- let (id, bound_region) = match *anon_region {
- ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
- ty::ReEarlyBound(ebr) => (
- self.tcx().parent(ebr.def_id).unwrap(),
- ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name),
- ),
- _ => return None, // not a free region
- };
-
- let hir = &self.tcx().hir();
- let hir_id = hir.local_def_id_to_hir_id(id.as_local()?);
- let body_id = hir.maybe_body_owned_by(hir_id)?;
- let body = hir.body(body_id);
- let owner_id = hir.body_owner(body_id);
- let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
- let poly_fn_sig = self.tcx().fn_sig(id);
- let fn_sig = self.tcx().liberate_late_bound_regions(id, poly_fn_sig);
- body.params
- .iter()
- .take(if fn_sig.c_variadic {
- fn_sig.inputs().len()
- } else {
- assert_eq!(fn_sig.inputs().len(), body.params.len());
- body.params.len()
- })
- .enumerate()
- .find_map(|(index, param)| {
- // May return None; sometimes the tables are not yet populated.
- let ty = fn_sig.inputs()[index];
- let mut found_anon_region = false;
- let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| {
- if r == anon_region {
- found_anon_region = true;
- replace_region
- } else {
- r
- }
- });
- if found_anon_region {
- let ty_hir_id = fn_decl.inputs[index].hir_id;
- let param_ty_span = hir.span(ty_hir_id);
- let is_first = index == 0;
- Some(AnonymousParamInfo {
- param,
- param_ty: new_param_ty,
- param_ty_span,
- bound_region,
- is_first,
- })
- } else {
- None
- }
- })
+ find_param_with_region(self.tcx(), anon_region, replace_region)
}
// Here, we check for the case where the anonymous region
location: ExternLocation::ExactPaths(locations),
is_private_dep: false,
add_prelude: true,
+ nounused_dep: false,
}
}
tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
tracked!(merge_functions, Some(MergeFunctions::Disabled));
tracked!(mir_emit_retag, true);
+ tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
tracked!(mir_opt_level, Some(4));
tracked!(move_size_limit, Some(4096));
tracked!(mutable_noalias, Some(true));
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" }
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
-use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind};
-use rustc_hir::{HirId, Node};
+use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind};
use rustc_index::vec::Idx;
use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
pub struct MissingDoc {
/// Stack of whether `#[doc(hidden)]` is set at each level which has lint attributes.
doc_hidden_stack: Vec<bool>,
-
- /// Private traits or trait items that leaked through. Don't check their methods.
- private_traits: FxHashSet<hir::HirId>,
}
impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
impl MissingDoc {
pub fn new() -> MissingDoc {
- MissingDoc { doc_hidden_stack: vec![false], private_traits: FxHashSet::default() }
+ MissingDoc { doc_hidden_stack: vec![false] }
}
fn doc_hidden(&self) -> bool {
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
match it.kind {
- hir::ItemKind::Trait(.., trait_item_refs) => {
+ hir::ItemKind::Trait(..) => {
// Issue #11592: traits are always considered exported, even when private.
- if let hir::VisibilityKind::Inherited = it.vis.node {
- self.private_traits.insert(it.hir_id());
- for trait_item_ref in trait_item_refs {
- self.private_traits.insert(trait_item_ref.id.hir_id());
- }
+ if cx.tcx.visibility(it.def_id)
+ == ty::Visibility::Restricted(
+ cx.tcx.parent_module_from_def_id(it.def_id).to_def_id(),
+ )
+ {
return;
}
}
- hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), items, .. }) => {
- // If the trait is private, add the impl items to `private_traits` so they don't get
- // reported for missing docs.
- let real_trait = trait_ref.path.res.def_id();
- let Some(def_id) = real_trait.as_local() else { return };
- let Some(Node::Item(item)) = cx.tcx.hir().find_by_def_id(def_id) else { return };
- if let hir::VisibilityKind::Inherited = item.vis.node {
- for impl_item_ref in items {
- self.private_traits.insert(impl_item_ref.id.hir_id());
- }
- }
- return;
- }
-
hir::ItemKind::TyAlias(..)
| hir::ItemKind::Fn(..)
| hir::ItemKind::Macro(..)
}
fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
- if self.private_traits.contains(&trait_item.hir_id()) {
- return;
- }
-
let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
self.check_missing_docs_attrs(cx, trait_item.def_id, trait_item.span, article, desc);
cx: &LateContext<'_>,
what: &str,
def_id: LocalDefId,
- vis: &hir::Visibility<'_>,
span: Span,
+ vis_span: Span,
exportable: bool,
) {
let mut applicability = Applicability::MachineApplicable;
- match vis.node {
- hir::VisibilityKind::Public if !cx.access_levels.is_reachable(def_id) => {
- if span.from_expansion() {
- applicability = Applicability::MaybeIncorrect;
+ if cx.tcx.visibility(def_id).is_public() && !cx.access_levels.is_reachable(def_id) {
+ if vis_span.from_expansion() {
+ applicability = Applicability::MaybeIncorrect;
+ }
+ let def_span = cx.tcx.sess.source_map().guess_head_span(span);
+ cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
+ let mut err = lint.build(&format!("unreachable `pub` {}", what));
+ let replacement = if cx.tcx.features().crate_visibility_modifier {
+ "crate"
+ } else {
+ "pub(crate)"
}
- let def_span = cx.tcx.sess.source_map().guess_head_span(span);
- cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
- let mut err = lint.build(&format!("unreachable `pub` {}", what));
- let replacement = if cx.tcx.features().crate_visibility_modifier {
- "crate"
- } else {
- "pub(crate)"
- }
- .to_owned();
+ .to_owned();
- err.span_suggestion(
- vis.span,
- "consider restricting its visibility",
- replacement,
- applicability,
- );
- if exportable {
- err.help("or consider exporting it for use by other crates");
- }
- err.emit();
- });
- }
- _ => {}
+ err.span_suggestion(
+ vis_span,
+ "consider restricting its visibility",
+ replacement,
+ applicability,
+ );
+ if exportable {
+ err.help("or consider exporting it for use by other crates");
+ }
+ err.emit();
+ });
}
}
}
impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- self.perform_lint(cx, "item", item.def_id, &item.vis, item.span, true);
+ // Do not warn for fake `use` statements.
+ if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
+ return;
+ }
+ self.perform_lint(cx, "item", item.def_id, item.span, item.vis_span, true);
}
fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
cx,
"item",
foreign_item.def_id,
- &foreign_item.vis,
foreign_item.span,
+ foreign_item.vis_span,
true,
);
}
fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
let def_id = cx.tcx.hir().local_def_id(field.hir_id);
- self.perform_lint(cx, "field", def_id, &field.vis, field.span, false);
+ self.perform_lint(cx, "field", def_id, field.span, field.vis_span, false);
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
- self.perform_lint(cx, "item", impl_item.def_id, &impl_item.vis, impl_item.span, false);
+ // Only lint inherent impl items.
+ if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() {
+ self.perform_lint(
+ cx,
+ "item",
+ impl_item.def_id,
+ impl_item.span,
+ impl_item.vis_span,
+ false,
+ );
+ }
}
}
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;
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);
}
}
_ => (),
},
- FnKind::ItemFn(ident, _, header, _) => {
+ FnKind::ItemFn(ident, _, header) => {
// Skip foreign-ABI #[no_mangle] functions (Issue #31924)
if header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) {
return;
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)]
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 "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) {
+#if LLVM_VERSION_LT(15, 0)
StringRef SR(PassName);
PassRegistry *PR = PassRegistry::getPassRegistry();
return wrap(PI->createPass());
}
return nullptr;
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
}
extern "C" LLVMPassRef LLVMRustCreateAddressSanitizerFunctionPass(bool Recover) {
+#if LLVM_VERSION_LT(15, 0)
const bool CompileKernel = false;
const bool UseAfterScope = true;
return wrap(createAddressSanitizerFunctionPass(CompileKernel, Recover, UseAfterScope));
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
}
extern "C" LLVMPassRef LLVMRustCreateModuleAddressSanitizerPass(bool Recover) {
+#if LLVM_VERSION_LT(15, 0)
const bool CompileKernel = false;
return wrap(createModuleAddressSanitizerLegacyPassPass(CompileKernel, Recover));
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
}
extern "C" LLVMPassRef LLVMRustCreateMemorySanitizerPass(int TrackOrigins, bool Recover) {
+#if LLVM_VERSION_LT(15, 0)
const bool CompileKernel = false;
return wrap(createMemorySanitizerLegacyPassPass(
MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel}));
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
}
extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() {
+#if LLVM_VERSION_LT(15, 0)
return wrap(createThreadSanitizerLegacyPassPass());
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
}
extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) {
+#if LLVM_VERSION_LT(15, 0)
const bool CompileKernel = false;
return wrap(createHWAddressSanitizerLegacyPassPass(CompileKernel, Recover));
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
}
extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
}
extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) {
+#if LLVM_VERSION_LT(15, 0)
assert(RustPass);
Pass *Pass = unwrap(RustPass);
PassManagerBase *PMB = unwrap(PMR);
PMB->add(Pass);
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
+}
+
+extern "C" LLVMPassManagerBuilderRef LLVMRustPassManagerBuilderCreate() {
+#if LLVM_VERSION_LT(15, 0)
+ return LLVMPassManagerBuilderCreate();
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
+}
+
+extern "C" void LLVMRustPassManagerBuilderDispose(LLVMPassManagerBuilderRef PMB) {
+#if LLVM_VERSION_LT(15, 0)
+ LLVMPassManagerBuilderDispose(PMB);
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
+}
+
+extern "C" void LLVMRustPassManagerBuilderPopulateFunctionPassManager(
+ LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) {
+#if LLVM_VERSION_LT(15, 0)
+ LLVMPassManagerBuilderPopulateFunctionPassManager(PMB, PM);
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
+}
+
+extern "C" void LLVMRustPassManagerBuilderPopulateModulePassManager(
+ LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) {
+#if LLVM_VERSION_LT(15, 0)
+ LLVMPassManagerBuilderPopulateModulePassManager(PMB, PM);
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
+}
+
+extern "C" void LLVMRustPassManagerBuilderPopulateLTOPassManager(
+ LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM, bool Internalize, bool RunInliner) {
+#if LLVM_VERSION_LT(15, 0)
+ LLVMPassManagerBuilderPopulateLTOPassManager(PMB, PM, Internalize, RunInliner);
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
}
extern "C"
LLVMPassManagerBuilderRef PMBR,
LLVMPassManagerRef PMR
) {
+#if LLVM_VERSION_LT(15, 0)
unwrap(PMBR)->populateThinLTOPassManager(*unwrap(PMR));
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
+}
+
+extern "C" void LLVMRustPassManagerBuilderUseInlinerWithThreshold(
+ LLVMPassManagerBuilderRef PMB, unsigned Threshold) {
+#if LLVM_VERSION_LT(15, 0)
+ LLVMPassManagerBuilderUseInlinerWithThreshold(PMB, Threshold);
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
}
extern "C"
void LLVMRustAddLastExtensionPasses(
LLVMPassManagerBuilderRef PMBR, LLVMPassRef *Passes, size_t NumPasses) {
+#if LLVM_VERSION_LT(15, 0)
auto AddExtensionPasses = [Passes, NumPasses](
const PassManagerBuilder &Builder, PassManagerBase &PM) {
for (size_t I = 0; I < NumPasses; I++) {
AddExtensionPasses);
unwrap(PMBR)->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
AddExtensionPasses);
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
}
#ifdef LLVM_COMPONENT_X86
extern "C" void LLVMRustConfigurePassManagerBuilder(
LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
- const char* PGOGenPath, const char* PGOUsePath, const char* PGOSampleUsePath) {
+ const char* PGOGenPath, const char* PGOUsePath, const char* PGOSampleUsePath,
+ int SizeLevel) {
+#if LLVM_VERSION_LT(15, 0)
unwrap(PMBR)->MergeFunctions = MergeFunctions;
unwrap(PMBR)->SLPVectorize = SLPVectorize;
unwrap(PMBR)->OptLevel = fromRust(OptLevel);
unwrap(PMBR)->LoopVectorize = LoopVectorize;
unwrap(PMBR)->PrepareForThinLTO = PrepareForThinLTO;
+ unwrap(PMBR)->SizeLevel = SizeLevel;
+ unwrap(PMBR)->DisableUnrollLoops = SizeLevel != 0;
if (PGOGenPath) {
assert(!PGOUsePath && !PGOSampleUsePath);
} else if (PGOSampleUsePath) {
unwrap(PMBR)->PGOSampleUse = PGOSampleUsePath;
}
+#else
+ report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
}
// Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo`
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Mangler.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/ObjectFile.h"
/// # 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};
// Don't worry about pathless `--extern foo` sysroot references
continue;
}
+ if entry.nounused_dep {
+ // We're not worried about this one
+ continue;
+ }
let name_interned = Symbol::intern(name);
if self.used_extern_options.contains(&name_interned) {
continue;
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_index::vec::{Idx, IndexVec};
use rustc_middle::arena::ArenaAllocatable;
use rustc_middle::metadata::ModChild;
-use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
+use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
use rustc_middle::middle::stability::DeprecationEntry;
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
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::{
fn exported_symbols(
self,
tcx: TyCtxt<'tcx>,
- ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
+ ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
tcx.arena.alloc_from_iter(self.root.exported_symbols.decode((self, tcx)))
}
.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;
let reachable_non_generics = tcx
.exported_symbols(cdata.cnum)
.iter()
- .filter_map(|&(exported_symbol, export_level)| {
+ .filter_map(|&(exported_symbol, export_info)| {
if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
- Some((def_id, export_level))
+ Some((def_id, export_info))
} else {
None
}
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 {
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::{
- metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
+ metadata_symbol_name, ExportedSymbol, SymbolExportInfo,
};
use rustc_middle::mir::interpret;
use rustc_middle::thir;
}
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);
// definition (as that's not defined in this crate).
fn encode_exported_symbols(
&mut self,
- exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportLevel)],
- ) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportLevel)]> {
+ exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportInfo)],
+ ) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportInfo)]> {
empty_proc_macro!(self);
// The metadata symbol name is special. It should not show up in
// downstream crates.
use rustc_hir::lang_items;
use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
use rustc_middle::metadata::ModChild;
-use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
+use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
use rustc_middle::mir;
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;
tables: LazyTables<'tcx>,
- exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportLevel)]),
+ exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportInfo)]),
syntax_contexts: SyntaxContextTable,
expn_data: ExpnDataTable,
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_index::vec::Idx;
use rustc_middle::hir::nested_filter;
use rustc_span::def_id::StableCrateId;
-use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
| Node::Param(_)
| Node::Arm(_)
| Node::Lifetime(_)
- | Node::Visibility(_)
| Node::Block(_) => return None,
};
Some(def_kind)
},
Node::Lifetime(lifetime) => lifetime.span,
Node::GenericParam(param) => param.span,
- Node::Visibility(&Spanned {
- node: VisibilityKind::Restricted { ref path, .. },
- ..
- }) => path.span,
Node::Infer(i) => i.span,
- Node::Visibility(v) => bug!("unexpected Visibility {:?}", v),
Node::Local(local) => local.span,
Node::Crate(item) => item.spans.inner_span,
};
}
tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
+ // Hash visibility information since it does not appear in HIR.
+ let resolutions = tcx.resolutions(());
+ resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher);
+ resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher);
let crate_hash: Fingerprint = stable_hasher.finish();
Svh::new(crate_hash.to_smaller_hash())
Some(Node::Ctor(..)) => format!("ctor {}{}", path_str(), id_str),
Some(Node::Lifetime(_)) => node_str("lifetime"),
Some(Node::GenericParam(ref param)) => format!("generic_param {:?}{}", param, id_str),
- Some(Node::Visibility(ref vis)) => format!("visibility {:?}{}", vis, id_str),
Some(Node::Crate(..)) => String::from("root_crate"),
None => format!("unknown node{}", id_str),
}
}
}
+/// Kind of exported symbols.
+#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable)]
+pub enum SymbolExportKind {
+ Text,
+ Data,
+ Tls,
+}
+
+/// The `SymbolExportInfo` of a symbols specifies symbol-related information
+/// that is relevant to code generation and linking.
+#[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
+pub struct SymbolExportInfo {
+ pub level: SymbolExportLevel,
+ pub kind: SymbolExportKind,
+ pub used: bool,
+}
+
#[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
pub enum ExportedSymbol<'tcx> {
NonGeneric(DefId),
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;
/// * [`StatementKind::Retag`]
///
/// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop`
- /// terminator means that the auto-generated drop glue will be invoked.
+ /// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands
+ /// are allowed for non-`Copy` types.
DropsLowered = 3,
/// Beginning with this phase, the following variant is disallowed:
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
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,
/// validator.
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum Operand<'tcx> {
- /// Creates a value by loading the given place. The type of the place must be `Copy`
+ /// Creates a value by loading the given place.
+ ///
+ /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there
+ /// is no such requirement.
Copy(Place<'tcx>),
/// Creates a value by performing loading the place, just like the `Copy` operand.
/// This is different from a normal transmute because dataflow analysis will treat the box as
/// initialized but its content as uninitialized. Like other pointer casts, this in general
/// affects alias analysis.
- ///
- /// Disallowed after drop elaboration.
ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
}
let mut delta = 0;
let mut last_bb = START_BLOCK;
+ let mut stmts_and_targets: Vec<(Statement<'_>, BasicBlock)> = Vec::new();
for (mut loc, stmt) in new_statements {
if loc.block != last_bb {
delta = 0;
debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta);
loc.statement_index += delta;
let source_info = Self::source_info_for_index(&body[loc.block], loc);
+
+ // For mir-opt `Derefer` to work in all cases we need to
+ // get terminator's targets and apply the statement to all of them.
+ if loc.statement_index > body[loc.block].statements.len() {
+ let term = body[loc.block].terminator();
+ let successors = term.successors().clone();
+
+ for i in successors {
+ stmts_and_targets
+ .push((Statement { source_info, kind: stmt.clone() }, i.clone()));
+ }
+ delta += 1;
+ continue;
+ }
+
body[loc.block]
.statements
.insert(loc.statement_index, Statement { source_info, kind: stmt });
delta += 1;
}
+
+ for (stmt, target) in stmts_and_targets.into_iter().rev() {
+ body[target].statements.insert(0, stmt);
+ }
}
pub fn source_info_for_index(data: &BasicBlockData<'_>, loc: Location) -> SourceInfo {
}
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());
// Does not include external symbols that don't have a corresponding DefId,
// like the compiler-generated `main` function and so on.
query reachable_non_generics(_: CrateNum)
- -> DefIdMap<SymbolExportLevel> {
+ -> DefIdMap<SymbolExportInfo> {
storage(ArenaCacheSelector<'tcx>)
desc { "looking up the exported symbols of a crate" }
separate_provide_extern
/// correspond to a publicly visible symbol in `cnum` machine code.
/// - The `exported_symbols` sets of different crates do not intersect.
query exported_symbols(_: CrateNum)
- -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
+ -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
desc { "exported_symbols" }
separate_provide_extern
}
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
+ }
}
/// A container for a THIR body.
///
/// This can be indexed directly by any THIR index (e.g. [`ExprId`]).
- #[derive(Debug, HashStable)]
+ #[derive(Debug, HashStable, Clone)]
pub struct Thir<'tcx> {
$(
pub $name: IndexVec<$id, $value>,
Explicit(hir::HirId),
}
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
pub struct Block {
/// Whether the block itself has a label. Used by `label: {}`
/// and `try` blocks.
pub safety_mode: BlockSafety,
}
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
pub struct Adt<'tcx> {
/// The ADT we're constructing.
pub adt_def: AdtDef<'tcx>,
ExplicitUnsafe(hir::HirId),
}
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
pub struct Stmt<'tcx> {
pub kind: StmtKind<'tcx>,
pub opt_destruction_scope: Option<region::Scope>,
}
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
pub enum StmtKind<'tcx> {
/// An expression with a trailing semicolon.
Expr {
rustc_data_structures::static_assert_size!(Expr<'_>, 104);
/// A THIR expression.
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
pub struct Expr<'tcx> {
/// The type of this expression
pub ty: Ty<'tcx>,
pub kind: ExprKind<'tcx>,
}
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
pub enum ExprKind<'tcx> {
/// `Scope`s are used to explicitly mark destruction scopes,
/// and to track the `HirId` of the expressions within the scope.
/// Represents the association of a field identifier and an expression.
///
/// This is used in struct constructors.
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
pub struct FieldExpr {
pub name: Field,
pub expr: ExprId,
}
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
pub struct FruInfo<'tcx> {
pub base: ExprId,
pub field_types: Box<[Ty<'tcx>]>,
}
/// A `match` arm.
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
pub struct Arm<'tcx> {
pub pattern: Pat<'tcx>,
pub guard: Option<Guard<'tcx>>,
}
/// A `match` guard.
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
pub enum Guard<'tcx> {
If(ExprId),
IfLet(Pat<'tcx>, ExprId),
Or,
}
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
pub enum InlineAsmOperand<'tcx> {
In {
reg: InlineAsmRegOrRegClass,
}
}
};
- ([$ignore:ident $(, $attrs:ident)*]$args:tt) => {
- impl_arena_allocatable_decoder!([$($attrs),*]$args);
- };
}
macro_rules! impl_arena_allocatable_decoders {
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)))
match st[i].abi() {
Abi::Scalar(_) => Abi::Scalar(niche_scalar),
Abi::ScalarPair(first, second) => {
- // We need to use scalar_unit to reset the
- // valid range to the maximal one for that
- // primitive, because only the niche is
- // guaranteed to be initialised, not the
- // other primitive.
+ // Only the niche is guaranteed to be initialised,
+ // so use union layout for the other primitive.
if offset.bytes() == 0 {
- Abi::ScalarPair(
- niche_scalar,
- scalar_unit(second.primitive()),
- )
+ Abi::ScalarPair(niche_scalar, second.to_union())
} else {
- Abi::ScalarPair(
- scalar_unit(first.primitive()),
- niche_scalar,
- )
+ Abi::ScalarPair(first.to_union(), niche_scalar)
}
}
_ => Abi::Aggregate { sized: true },
} else {
// Try to use a ScalarPair for all tagged enums.
let mut common_prim = None;
+ let mut common_prim_initialized_in_all_variants = true;
for (field_layouts, layout_variant) in iter::zip(&variants, &layout_variants) {
let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else {
bug!();
let mut fields =
iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst());
let (field, offset) = match (fields.next(), fields.next()) {
- (None, None) => continue,
+ (None, None) => {
+ common_prim_initialized_in_all_variants = false;
+ continue;
+ }
(Some(pair), None) => pair,
_ => {
common_prim = None;
}
};
let prim = match field.abi {
- Abi::Scalar(scalar) => scalar.primitive(),
+ Abi::Scalar(scalar) => {
+ common_prim_initialized_in_all_variants &=
+ matches!(scalar, Scalar::Initialized { .. });
+ scalar.primitive()
+ }
_ => {
common_prim = None;
break;
}
}
if let Some((prim, offset)) = common_prim {
- let pair = self.scalar_pair(tag, scalar_unit(prim));
+ let prim_scalar = if common_prim_initialized_in_all_variants {
+ scalar_unit(prim)
+ } else {
+ // Common prim might be uninit.
+ Scalar::Union { value: prim }
+ };
+ let pair = self.scalar_pair(tag, prim_scalar);
let pair_offsets = match pair.fields {
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
assert_eq!(memory_index, &[0, 1]);
pointee_info
}
+
+ fn is_adt(this: TyAndLayout<'tcx>) -> bool {
+ matches!(this.ty.kind(), ty::Adt(..))
+ }
+
+ fn is_never(this: TyAndLayout<'tcx>) -> bool {
+ this.ty.kind() == &ty::Never
+ }
+
+ fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
+ matches!(this.ty.kind(), ty::Tuple(..))
+ }
+
+ fn is_unit(this: TyAndLayout<'tcx>) -> bool {
+ matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
+ }
}
impl<'tcx> ty::Instance<'tcx> {
static EMPTY_SLICE: InOrder<usize, MaxAlign> = InOrder(0, MaxAlign);
unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) }
}
+
+ pub fn len(&self) -> usize {
+ self.len
+ }
}
impl<T: Copy> List<T> {
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};
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 definitions: rustc_hir::definitions::Definitions,
pub cstore: Box<CrateStoreDyn>,
pub visibilities: FxHashMap<LocalDefId, Visibility>,
+ /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error.
+ pub has_pub_restricted: bool,
pub access_levels: AccessLevels,
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
}
impl Visibility {
- 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::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.
- Res::Err => Visibility::Public,
- def => Visibility::Restricted(def.def_id()),
- },
- hir::VisibilityKind::Inherited => {
- Visibility::Restricted(tcx.parent_module(id).to_def_id())
- }
- }
- }
-
/// Returns `true` if an item with this visibility is accessible from the given block.
pub fn is_accessible_from<T: DefIdTree>(self, module: DefId, tree: T) -> bool {
let restriction = match self {
}
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::lint::LintLevelMap;
use crate::metadata::ModChild;
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
-use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
+use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
use crate::middle::lib_features::LibFeatures;
use crate::middle::privacy::AccessLevels;
use crate::middle::region;
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_span::symbol::Symbol;
use rustc_span::Span;
+use std::borrow::Cow;
use std::ops::Bound;
struct UnsafetyVisitor<'a, 'tcx> {
}
fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
- let (description, note) = kind.description_and_note();
let unsafe_op_in_unsafe_fn_allowed = self.unsafe_op_in_unsafe_fn_allowed();
match self.safety_context {
SafetyContext::BuiltinUnsafeBlock => {}
}
SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
SafetyContext::UnsafeFn => {
+ let (description, note) = kind.description_and_note(self.tcx);
// unsafe_op_in_unsafe_fn is disallowed
self.tcx.struct_span_lint_hir(
UNSAFE_OP_IN_UNSAFE_FN,
"{} is unsafe and requires unsafe block (error E0133)",
description,
))
- .span_label(span, description)
+ .span_label(span, kind.simple_description())
.note(note)
.emit();
},
)
}
SafetyContext::Safe => {
+ let (description, note) = kind.description_and_note(self.tcx);
let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" };
struct_span_err!(
self.tcx.sess,
description,
fn_sugg,
)
- .span_label(span, description)
+ .span_label(span, kind.simple_description())
.note(note)
.emit();
}
}
ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
- self.requires_unsafe(expr.span, CallToUnsafeFunction);
+ let func_id = if let ty::FnDef(func_id, _) = self.thir[fun].ty.kind() {
+ Some(*func_id)
+ } else {
+ None
+ };
+ self.requires_unsafe(expr.span, CallToUnsafeFunction(func_id));
} else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
// If the called function has target features the calling function hasn't,
// the call requires `unsafe`. Don't check this on wasm
.iter()
.all(|feature| self.body_target_features.contains(feature))
{
- self.requires_unsafe(expr.span, CallToFunctionWith);
+ self.requires_unsafe(expr.span, CallToFunctionWith(func_did));
}
}
}
#[derive(Clone, Copy, PartialEq)]
enum UnsafeOpKind {
- CallToUnsafeFunction,
+ CallToUnsafeFunction(Option<DefId>),
UseOfInlineAssembly,
InitializingTypeWith,
UseOfMutableStatic,
AccessToUnionField,
MutationOfLayoutConstrainedField,
BorrowOfLayoutConstrainedField,
- CallToFunctionWith,
+ CallToFunctionWith(DefId),
}
use UnsafeOpKind::*;
impl UnsafeOpKind {
- pub fn description_and_note(&self) -> (&'static str, &'static str) {
+ pub fn simple_description(&self) -> &'static str {
match self {
- CallToUnsafeFunction => (
- "call to unsafe function",
+ CallToUnsafeFunction(..) => "call to unsafe function",
+ UseOfInlineAssembly => "use of inline assembly",
+ InitializingTypeWith => "initializing type with `rustc_layout_scalar_valid_range` attr",
+ UseOfMutableStatic => "use of mutable static",
+ UseOfExternStatic => "use of extern static",
+ DerefOfRawPointer => "dereference of raw pointer",
+ AssignToDroppingUnionField => "assignment to union field that might need dropping",
+ AccessToUnionField => "access to union field",
+ MutationOfLayoutConstrainedField => "mutation of layout constrained field",
+ BorrowOfLayoutConstrainedField => {
+ "borrow of layout constrained field with interior mutability"
+ }
+ CallToFunctionWith(..) => "call to function with `#[target_feature]`",
+ }
+ }
+
+ pub fn description_and_note(&self, tcx: TyCtxt<'_>) -> (Cow<'static, str>, &'static str) {
+ match self {
+ CallToUnsafeFunction(did) => (
+ if let Some(did) = did {
+ Cow::from(format!("call to unsafe function `{}`", tcx.def_path_str(*did)))
+ } else {
+ Cow::Borrowed(self.simple_description())
+ },
"consult the function's documentation for information on how to avoid undefined \
behavior",
),
UseOfInlineAssembly => (
- "use of inline assembly",
+ Cow::Borrowed(self.simple_description()),
"inline assembly is entirely unchecked and can cause undefined behavior",
),
InitializingTypeWith => (
- "initializing type with `rustc_layout_scalar_valid_range` attr",
+ Cow::Borrowed(self.simple_description()),
"initializing a layout restricted type's field with a value outside the valid \
range is undefined behavior",
),
UseOfMutableStatic => (
- "use of mutable static",
+ Cow::Borrowed(self.simple_description()),
"mutable statics can be mutated by multiple threads: aliasing violations or data \
races will cause undefined behavior",
),
UseOfExternStatic => (
- "use of extern static",
+ Cow::Borrowed(self.simple_description()),
"extern statics are not controlled by the Rust type system: invalid data, \
aliasing violations or data races will cause undefined behavior",
),
DerefOfRawPointer => (
- "dereference of raw pointer",
+ Cow::Borrowed(self.simple_description()),
"raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
and cause data races: all of these are undefined behavior",
),
AssignToDroppingUnionField => (
- "assignment to union field that might need dropping",
+ Cow::Borrowed(self.simple_description()),
"the previous content of the field will be dropped, which causes undefined \
behavior if the field was not properly initialized",
),
AccessToUnionField => (
- "access to union field",
+ Cow::Borrowed(self.simple_description()),
"the field may not be properly initialized: using uninitialized data will cause \
undefined behavior",
),
MutationOfLayoutConstrainedField => (
- "mutation of layout constrained field",
+ Cow::Borrowed(self.simple_description()),
"mutating layout constrained fields cannot statically be checked for valid values",
),
BorrowOfLayoutConstrainedField => (
- "borrow of layout constrained field with interior mutability",
+ Cow::Borrowed(self.simple_description()),
"references to fields of layout constrained fields lose the constraints. Coupled \
with interior mutability, the field can be changed to invalid values",
),
- CallToFunctionWith => (
- "call to function with `#[target_feature]`",
+ CallToFunctionWith(did) => (
+ Cow::from(format!(
+ "call to function `{}` with `#[target_feature]`",
+ tcx.def_path_str(*did)
+ )),
"can only be called if the required target features are available",
),
}
TerminatorKind::Call { ref func, .. } => {
let func_ty = func.ty(self.body, self.tcx);
+ let func_id =
+ if let ty::FnDef(func_id, _) = func_ty.kind() { Some(func_id) } else { None };
let sig = func_ty.fn_sig(self.tcx);
if let hir::Unsafety::Unsafe = sig.unsafety() {
self.require_unsafe(
)
}
- if let ty::FnDef(func_id, _) = func_ty.kind() {
+ if let Some(func_id) = func_id {
self.check_target_features(*func_id);
}
}
ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
- // FIXME(eddyb) avoid cloning this field more than once,
- // by accessing it through `ecx` instead.
- local_decls: IndexVec<Local, LocalDecl<'tcx>>,
+ local_decls: &'mir IndexVec<Local, LocalDecl<'tcx>>,
// Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
// the last known `SourceInfo` here and just keep revisiting it.
source_info: Option<SourceInfo>,
let substs = &InternalSubsts::identity_for_item(tcx, def_id);
let param_env = tcx.param_env_reveal_all_normalized(def_id);
- let span = tcx.def_span(def_id);
- // FIXME: `CanConstProp::check` computes the layout of all locals, return those layouts
- // so we can write them to `ecx.frame_mut().locals.layout, reducing the duplication in
- // `layout_of` query invocations.
let can_const_prop = CanConstProp::check(tcx, param_env, body);
let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len());
for (l, mode) in can_const_prop.iter_enumerated() {
}
let mut ecx = InterpCx::new(
tcx,
- span,
+ tcx.def_span(def_id),
param_env,
ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop),
);
ecx,
tcx,
param_env,
- // FIXME(eddyb) avoid cloning this field more than once,
- // by accessing it through `ecx` instead.
- //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
- local_decls: body.local_decls.clone(),
+ local_decls: &dummy_body.local_decls,
source_info: None,
}
}
let r = r?;
// We need the type of the LHS. We cannot use `place_layout` as that is the type
// of the result, which for checked binops is not the same!
- let left_ty = left.ty(&self.local_decls, self.tcx);
+ let left_ty = left.ty(self.local_decls, self.tcx);
let left_size = self.ecx.layout_of(left_ty).ok()?.size;
let right_size = r.layout.size;
let r_bits = r.to_scalar().ok();
ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
- // FIXME(eddyb) avoid cloning these two fields more than once,
- // by accessing them through `ecx` instead.
- source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
- local_decls: IndexVec<Local, LocalDecl<'tcx>>,
+ source_scopes: &'mir IndexVec<SourceScope, SourceScopeData<'tcx>>,
+ local_decls: &'mir IndexVec<Local, LocalDecl<'tcx>>,
// Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
// the last known `SourceInfo` here and just keep revisiting it.
source_info: Option<SourceInfo>,
let substs = &InternalSubsts::identity_for_item(tcx, def_id);
let param_env = tcx.param_env_reveal_all_normalized(def_id);
- let span = tcx.def_span(def_id);
- // FIXME: `CanConstProp::check` computes the layout of all locals, return those layouts
- // so we can write them to `ecx.frame_mut().locals.layout, reducing the duplication in
- // `layout_of` query invocations.
let can_const_prop = CanConstProp::check(tcx, param_env, body);
let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len());
for (l, mode) in can_const_prop.iter_enumerated() {
}
let mut ecx = InterpCx::new(
tcx,
- span,
+ tcx.def_span(def_id),
param_env,
ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop),
);
ecx,
tcx,
param_env,
- // FIXME(eddyb) avoid cloning these two fields more than once,
- // by accessing them through `ecx` instead.
- source_scopes: body.source_scopes.clone(),
- //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
- local_decls: body.local_decls.clone(),
+ source_scopes: &dummy_body.source_scopes,
+ local_decls: &dummy_body.local_decls,
source_info: None,
}
}
}
fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> {
- source_info.scope.lint_root(&self.source_scopes)
+ source_info.scope.lint_root(self.source_scopes)
}
fn use_ecx<F, T>(&mut self, f: F) -> Option<T>
let r = r?;
// We need the type of the LHS. We cannot use `place_layout` as that is the type
// of the result, which for checked binops is not the same!
- let left_ty = left.ty(&self.local_decls, self.tcx);
+ let left_ty = left.ty(self.local_decls, self.tcx);
let left_size = self.ecx.layout_of(left_ty).ok()?.size;
let right_size = r.layout.size;
let r_bits = r.to_scalar().ok();
use crate::MirPass;
+use rustc_index::vec::IndexVec;
use rustc_middle::mir::patch::MirPatch;
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext};
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
pub struct Derefer;
-pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let mut patch = MirPatch::new(body);
- let (basic_blocks, local_decl) = body.basic_blocks_and_local_decls_mut();
- for (block, data) in basic_blocks.iter_enumerated_mut() {
- for (i, stmt) in data.statements.iter_mut().enumerate() {
- match stmt.kind {
- StatementKind::Assign(box (og_place, Rvalue::Ref(region, borrow_knd, place))) => {
- let mut place_local = place.local;
- let mut last_len = 0;
- for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
- if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
- // The type that we are derefing.
- let ty = p_ref.ty(local_decl, tcx).ty;
- let temp = patch.new_temp(ty, stmt.source_info.span);
-
- // Because we are assigning this right before original statement
- // we are using index i of statement.
- let loc = Location { block: block, statement_index: i };
- patch.add_statement(loc, StatementKind::StorageLive(temp));
-
- // We are adding current p_ref's projections to our
- // temp value, excluding projections we already covered.
- let deref_place = Place::from(place_local)
- .project_deeper(&p_ref.projection[last_len..], tcx);
- patch.add_assign(
- loc,
- Place::from(temp),
- Rvalue::Use(Operand::Move(deref_place)),
- );
-
- place_local = temp;
- last_len = p_ref.projection.len();
-
- // We are creating a place by using our temp value's location
- // and copying derefed values which we need to create new statement.
- let temp_place =
- Place::from(temp).project_deeper(&place.projection[idx..], tcx);
- let new_stmt = Statement {
- source_info: stmt.source_info,
- kind: StatementKind::Assign(Box::new((
- og_place,
- Rvalue::Ref(region, borrow_knd, temp_place),
- ))),
- };
-
- // Replace current statement with newly created one.
- *stmt = new_stmt;
-
- // Since our job with the temp is done it should be gone
- let loc = Location { block: block, statement_index: i + 1 };
- patch.add_statement(loc, StatementKind::StorageDead(temp));
- }
- }
+pub struct DerefChecker<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ patcher: MirPatch<'tcx>,
+ local_decls: IndexVec<Local, LocalDecl<'tcx>>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Location) {
+ let mut place_local = place.local;
+ let mut last_len = 0;
+ let mut last_deref_idx = 0;
+
+ let mut prev_temp: Option<Local> = None;
+
+ for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
+ if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
+ last_deref_idx = idx;
+ }
+ }
+
+ for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
+ if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
+ let ty = p_ref.ty(&self.local_decls, self.tcx).ty;
+ let temp =
+ self.patcher.new_temp(ty, self.local_decls[p_ref.local].source_info.span);
+
+ self.patcher.add_statement(loc, StatementKind::StorageLive(temp));
+
+ // We are adding current p_ref's projections to our
+ // temp value, excluding projections we already covered.
+ let deref_place = Place::from(place_local)
+ .project_deeper(&p_ref.projection[last_len..], self.tcx);
+ self.patcher.add_assign(
+ loc,
+ Place::from(temp),
+ Rvalue::Use(Operand::Move(deref_place)),
+ );
+
+ place_local = temp;
+ last_len = p_ref.projection.len();
+
+ // Change `Place` only if we are actually at the Place's last deref
+ if idx == last_deref_idx {
+ let temp_place =
+ Place::from(temp).project_deeper(&place.projection[idx..], self.tcx);
+ *place = temp_place;
+ }
+
+ // We are destroying last temp since it's no longer used.
+ if let Some(prev_temp) = prev_temp {
+ self.patcher.add_statement(loc, StatementKind::StorageDead(prev_temp));
}
- _ => (),
+
+ prev_temp = Some(temp);
}
}
+
+ // Since we won't be able to reach final temp, we destroy it outside the loop.
+ if let Some(prev_temp) = prev_temp {
+ let last_loc = Location { block: loc.block, statement_index: loc.statement_index + 1 };
+ self.patcher.add_statement(last_loc, StatementKind::StorageDead(prev_temp));
+ }
}
- patch.apply(body);
+}
+
+pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ let patch = MirPatch::new(body);
+ let mut checker = DerefChecker { tcx, patcher: patch, local_decls: body.local_decls.clone() };
+
+ for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() {
+ checker.visit_basic_block_data(bb, data);
+ }
+
+ checker.patcher.apply(body);
}
impl<'tcx> MirPass<'tcx> for Derefer {
let mut cnt = 0;
let validate = tcx.sess.opts.debugging_opts.validate_mir;
+ let overridden_passes = &tcx.sess.opts.debugging_opts.mir_enable_passes;
+ trace!(?overridden_passes);
if validate {
validate_body(tcx, body, format!("start of phase transition from {:?}", start_phase));
}
for pass in passes {
- if !pass.is_enabled(&tcx.sess) {
- continue;
- }
-
let name = pass.name();
+
+ if let Some((_, polarity)) = overridden_passes.iter().rev().find(|(s, _)| s == &*name) {
+ trace!(
+ pass = %name,
+ "{} as requested by flag",
+ if *polarity { "Running" } else { "Not running" },
+ );
+ if !polarity {
+ continue;
+ }
+ } else {
+ if !pass.is_enabled(&tcx.sess) {
+ continue;
+ }
+ }
let dump_enabled = pass.is_mir_dump_enabled();
if dump_enabled {
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;
+use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility};
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
use rustc_middle::ty::print::characteristic_def_id_of_type;
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 {
// C-export level items remain at `Default`, all other internal
// items become `Hidden`.
match tcx.reachable_non_generics(id.krate).get(&id) {
- Some(SymbolExportLevel::C) => Visibility::Default,
+ Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default,
_ => Visibility::Hidden,
}
}
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);
return Ok(true);
} else if self.look_ahead(0, |t| {
t == &token::CloseDelim(token::Brace)
- || (
- t.can_begin_expr() && t != &token::Semi && t != &token::Pound
- // Avoid triggering with too many trailing `#` in raw string.
- )
+ || (t.can_begin_expr() && t != &token::Semi && t != &token::Pound)
+ // Avoid triggering with too many trailing `#` in raw string.
+ || (sm.is_multiline(
+ self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo())
+ ) && t == &token::Pound)
}) {
// Missing semicolon typo. This is triggered if the next token could either start a
// new statement or is a block close. For example:
}
if self.check_too_many_raw_str_terminators(&mut err) {
- return Err(err);
+ if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) {
+ err.emit();
+ return Ok(true);
+ } else {
+ return Err(err);
+ }
}
if self.prev_token.span == DUMMY_SP {
}
fn check_too_many_raw_str_terminators(&mut self, err: &mut Diagnostic) -> bool {
+ let sm = self.sess.source_map();
match (&self.prev_token.kind, &self.token.kind) {
(
TokenKind::Literal(Lit {
..
}),
TokenKind::Pound,
- ) => {
+ ) if !sm.is_multiline(
+ self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()),
+ ) =>
+ {
+ let n_hashes: u8 = *n_hashes;
err.set_primary_message("too many `#` when terminating raw string");
+ let str_span = self.prev_token.span;
+ let mut span = self.token.span;
+ let mut count = 0;
+ while self.token.kind == TokenKind::Pound
+ && !sm.is_multiline(span.shrink_to_hi().until(self.token.span.shrink_to_lo()))
+ {
+ span = span.with_hi(self.token.span.hi());
+ self.bump();
+ count += 1;
+ }
+ err.set_span(span);
err.span_suggestion(
- self.token.span,
- "remove the extra `#`",
+ span,
+ &format!("remove the extra `#`{}", pluralize!(count)),
String::new(),
Applicability::MachineApplicable,
);
- err.note(&format!("the raw string started with {n_hashes} `#`s"));
+ err.span_label(
+ str_span,
+ &format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)),
+ );
true
}
_ => false,
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.
live_symbols: FxHashSet<LocalDefId>,
repr_has_repr_c: bool,
in_pat: bool,
- inherited_pub_visibility: bool,
- pub_visibility: bool,
ignore_variant_stack: Vec<DefId>,
// maps from tuple struct constructors to tuple struct items
struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
}
let had_repr_c = self.repr_has_repr_c;
- let had_inherited_pub_visibility = self.inherited_pub_visibility;
- let had_pub_visibility = self.pub_visibility;
self.repr_has_repr_c = false;
- self.inherited_pub_visibility = false;
- self.pub_visibility = false;
match node {
- Node::Item(item) => {
- self.pub_visibility = item.vis.node.is_pub();
+ Node::Item(item) => match item.kind {
+ hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
+ let def = self.tcx.adt_def(item.def_id);
+ self.repr_has_repr_c = def.repr().c();
- match item.kind {
- hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
- let def = self.tcx.adt_def(item.def_id);
- self.repr_has_repr_c = def.repr().c();
-
- intravisit::walk_item(self, &item);
- }
- hir::ItemKind::Enum(..) => {
- self.inherited_pub_visibility = self.pub_visibility;
-
- intravisit::walk_item(self, &item);
- }
- hir::ItemKind::ForeignMod { .. } => {}
- _ => {
- intravisit::walk_item(self, &item);
- }
+ intravisit::walk_item(self, &item);
}
- }
+ hir::ItemKind::Enum(..) => {
+ intravisit::walk_item(self, &item);
+ }
+ hir::ItemKind::ForeignMod { .. } => {}
+ _ => {
+ intravisit::walk_item(self, &item);
+ }
+ },
Node::TraitItem(trait_item) => {
intravisit::walk_trait_item(self, trait_item);
}
}
_ => {}
}
- self.pub_visibility = had_pub_visibility;
- self.inherited_pub_visibility = had_inherited_pub_visibility;
self.repr_has_repr_c = had_repr_c;
}
_: hir::HirId,
_: rustc_span::Span,
) {
+ let tcx = self.tcx;
let has_repr_c = self.repr_has_repr_c;
- let inherited_pub_visibility = self.inherited_pub_visibility;
- let pub_visibility = self.pub_visibility;
- let live_fields = def.fields().iter().filter(|f| {
- has_repr_c || (pub_visibility && (inherited_pub_visibility || f.vis.node.is_pub()))
+ let live_fields = def.fields().iter().filter_map(|f| {
+ let def_id = tcx.hir().local_def_id(f.hir_id);
+ if has_repr_c {
+ return Some(def_id);
+ }
+ if !tcx.visibility(f.hir_id.owner).is_public() {
+ return None;
+ }
+ if tcx.visibility(def_id).is_public() { Some(def_id) } else { None }
});
- let hir = self.tcx.hir();
- self.live_symbols.extend(live_fields.map(|f| hir.local_def_id(f.hir_id)));
+ self.live_symbols.extend(live_fields);
intravisit::walk_struct_def(self, def);
}
live_symbols: Default::default(),
repr_has_repr_c: false,
in_pat: false,
- inherited_pub_visibility: false,
- pub_visibility: false,
ignore_variant_stack: vec![],
struct_constructors,
ignored_derived_traits: FxHashMap::default(),
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;
}
// completely accurate (some things might be counted twice, others missed).
use rustc_ast::visit as ast_visit;
+use rustc_ast::visit::BoundKind;
use rustc_ast::{self as ast, AttrId, NodeId};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
ast_visit::walk_assoc_item(self, item, ctxt);
}
- fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound) {
+ fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound, _ctxt: BoundKind) {
self.record("GenericBound", Id::None, bounds);
ast_visit::walk_param_bound(self, bounds)
}
let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
if codegen_attrs.contains_extern_indicator()
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
+ // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
+ // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
+ // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
+ || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
+ || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
{
self.worklist.push(def_id);
}
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);
}
if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
}
-////////////////////////////////////////////////////////////////////////////////
-/// Visitor used to determine if pub(restricted) is used anywhere in the crate.
-///
-/// This is done so that `private_in_public` warnings can be turned into hard errors
-/// in crates that have been updated to use pub(restricted).
-////////////////////////////////////////////////////////////////////////////////
-struct PubRestrictedVisitor<'tcx> {
- tcx: TyCtxt<'tcx>,
- has_pub_restricted: bool,
-}
-
-impl<'tcx> Visitor<'tcx> for PubRestrictedVisitor<'tcx> {
- type NestedFilter = nested_filter::All;
-
- fn nested_visit_map(&mut self) -> Self::Map {
- self.tcx.hir()
- }
- fn visit_vis(&mut self, vis: &'tcx hir::Visibility<'tcx>) {
- self.has_pub_restricted = self.has_pub_restricted || vis.node.is_pub_restricted();
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
/// Visitor used to determine impl visibility and reachability.
////////////////////////////////////////////////////////////////////////////////
self.update_with_hir_id(ctor_hir_id, item_level);
}
for field in def.fields() {
- if field.vis.node.is_pub() {
+ let def_id = self.tcx.hir().local_def_id(field.hir_id);
+ let vis = self.tcx.visibility(def_id);
+ if vis.is_public() {
self.update_with_hir_id(field.hir_id, item_level);
}
}
// .. and it corresponds to a private type in the AST (this returns
// `None` for type parameters).
match self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(did)) {
- Some(Node::Item(item)) => !item.vis.node.is_pub(),
+ Some(Node::Item(_)) => !self.tcx.visibility(did).is_public(),
Some(_) | None => false,
}
} else {
}
}
- fn item_is_public(&self, def_id: LocalDefId, vis: &hir::Visibility<'_>) -> bool {
- self.access_levels.is_reachable(def_id) || vis.node.is_pub()
+ fn item_is_public(&self, def_id: LocalDefId) -> bool {
+ self.access_levels.is_reachable(def_id) || self.tcx.visibility(def_id).is_public()
}
}
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item.kind {
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..)
- if self
- .item_is_public(impl_item.def_id, &impl_item.vis) =>
+ if self.item_is_public(impl_item.def_id) =>
{
intravisit::walk_impl_item(self, impl_item)
}
hir::ItemKind::TyAlias(..) => return,
// Not at all public, so we don't care.
- _ if !self.item_is_public(item.def_id, &item.vis) => {
+ _ if !self.item_is_public(item.def_id) => {
return;
}
}
fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
- if s.vis.node.is_pub() || self.in_variant {
+ let def_id = self.tcx.hir().local_def_id(s.hir_id);
+ let vis = self.tcx.visibility(def_id);
+ if vis.is_public() || self.in_variant {
intravisit::walk_field_def(self, s);
}
}
item_def_id: LocalDefId,
/// The visitor checks that each component type is at least this visible.
required_visibility: ty::Visibility,
- has_pub_restricted: bool,
has_old_errors: bool,
in_assoc_ty: bool,
}
};
let make_msg = || format!("{} {} `{}` in public interface", vis_descr, kind, descr);
let span = self.tcx.def_span(self.item_def_id.to_def_id());
- if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
+ if self.has_old_errors
+ || self.in_assoc_ty
+ || self.tcx.resolutions(()).has_pub_restricted
+ {
let mut err = if kind == "trait" {
struct_span_err!(self.tcx.sess, span, E0445, "{}", make_msg())
} else {
struct PrivateItemsInPublicInterfacesVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
- has_pub_restricted: bool,
old_error_set_ancestry: LocalDefIdSet,
}
tcx: self.tcx,
item_def_id: def_id,
required_visibility,
- has_pub_restricted: self.has_pub_restricted,
has_old_errors: self.old_error_set_ancestry.contains(&def_id),
in_assoc_ty: false,
}
match tcx.hir().get(hir_id) {
// Unique types created for closures participate in type privacy checking.
// They have visibilities inherited from the module they are defined in.
- Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
- ty::Visibility::Restricted(tcx.parent_module(hir_id).to_def_id())
- }
- // - AST lowering may clone `use` items and the clones don't
+ Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. })
+ // - AST lowering creates dummy `use` items which don't
// get their entries in the resolver's visibility table.
// - AST lowering also creates opaque type items with inherited visibilities.
// Visibility on them should have no effect, but to avoid the visibility
// query failing on some items, we provide it for opaque types as well.
- Node::Item(hir::Item {
- vis,
- kind: hir::ItemKind::Use(..) | hir::ItemKind::OpaqueTy(..),
+ | Node::Item(hir::Item {
+ kind: hir::ItemKind::Use(_, hir::UseKind::ListStem) | hir::ItemKind::OpaqueTy(..),
..
- }) => ty::Visibility::from_hir(vis, hir_id, tcx),
+ }) => ty::Visibility::Restricted(tcx.parent_module(hir_id).to_def_id()),
// Visibilities of trait impl items are inherited from their traits
// and are not filled in resolve.
Node::ImplItem(impl_item) => {
};
tcx.hir().walk_toplevel_module(&mut visitor);
- let has_pub_restricted = {
- let mut pub_restricted_visitor = PubRestrictedVisitor { tcx, has_pub_restricted: false };
- tcx.hir().walk_toplevel_module(&mut pub_restricted_visitor);
- pub_restricted_visitor.has_pub_restricted
- };
-
let mut old_error_set_ancestry = HirIdSet::default();
for mut id in visitor.old_error_set.iter().copied() {
loop {
// Check for private types and traits in public interfaces.
let mut visitor = PrivateItemsInPublicInterfacesVisitor {
tcx,
- has_pub_restricted,
// Only definition IDs are ever searched in `old_error_set_ancestry`,
// so we can filter away all non-definition IDs at this point.
old_error_set_ancestry: old_error_set_ancestry
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 {
})
}
ast::VisibilityKind::Restricted { ref path, id, .. } => {
+ // Make `PRIVATE_IN_PUBLIC` lint a hard error.
+ self.r.has_pub_restricted = true;
// For visibilities we are not ready to provide correct implementation of "uniform
// paths" right now, so on 2018 edition we only allow module-relative paths for now.
// On 2015 edition visibilities are resolved as crate-relative by default,
let mut source = module_path.pop().unwrap();
let mut type_ns_only = false;
+ self.r.visibilities.insert(self.r.local_def_id(id), vis);
+ if id1 != ast::DUMMY_NODE_ID {
+ self.r.visibilities.insert(self.r.local_def_id(id1), vis);
+ }
+ if id2 != ast::DUMMY_NODE_ID {
+ self.r.visibilities.insert(self.r.local_def_id(id2), vis);
+ }
+
if nested {
// Correctly handle `self`
if source.ident.name == kw::SelfLower {
is_prelude: self.r.session.contains_name(&item.attrs, sym::prelude_import),
max_vis: Cell::new(ty::Visibility::Invisible),
};
+ self.r.visibilities.insert(self.r.local_def_id(id), vis);
self.add_import(prefix, kind, use_tree.span, id, item, root_span, item.id, vis);
}
ast::UseTreeKind::Nested(ref items) => {
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
};
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))
}));
}
use crate::{ResolutionError, Resolver, Segment, UseError};
use rustc_ast::ptr::P;
-use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
+use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
use rustc_ast::*;
use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
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};
this.visit_generic_param_vec(&bound_generic_params, false);
this.visit_ty(bounded_ty);
for bound in bounds {
- this.visit_param_bound(bound)
+ this.visit_param_bound(bound, BoundKind::Bound)
}
},
);
match param.kind {
GenericParamKind::Lifetime => {
for bound in ¶m.bounds {
- this.visit_param_bound(bound);
+ this.visit_param_bound(bound, BoundKind::Bound);
}
}
GenericParamKind::Type { ref default } => {
for bound in ¶m.bounds {
- this.visit_param_bound(bound);
+ this.visit_param_bound(bound, BoundKind::Bound);
}
if let Some(ref ty) = default {
Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
|this| {
this.visit_generics(generics);
- walk_list!(this, visit_param_bound, bounds);
+ walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits);
let walk_assoc_item =
|this: &mut Self,
Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
|this| {
this.visit_generics(generics);
- walk_list!(this, visit_param_bound, bounds);
+ walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
},
);
},
"invalid lifetime parameter name: `{}`",
param.ident,
)
- .span_label(param.ident.span, format!("'static is a reserved lifetime name"))
+ .span_label(param.ident.span, "'static is a reserved lifetime name")
.emit();
continue;
}
// 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(),
)));
}
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(
hir_id: hir::HirId,
) {
let name = match fk {
- intravisit::FnKind::ItemFn(id, _, _, _) => id.name,
- intravisit::FnKind::Method(id, _, _) => id.name,
+ intravisit::FnKind::ItemFn(id, _, _) => id.name,
+ intravisit::FnKind::Method(id, _) => id.name,
intravisit::FnKind::Closure => sym::closure,
};
let name = name.as_str();
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;
NameBindingKind::Module(&ModuleData {
kind: ModuleKind::Def(DefKind::Mod, def_id, _),
..
- }) => def_id.index == CRATE_DEF_INDEX,
+ }) => def_id.is_crate_root(),
_ => false,
}
}
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
/// Visibilities in "lowered" form, for all entities that have them.
visibilities: FxHashMap<LocalDefId, ty::Visibility>,
+ has_pub_restricted: bool,
used_imports: FxHashSet<NodeId>,
maybe_unused_trait_imports: FxHashSet<LocalDefId>,
maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
);
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
glob_map: Default::default(),
visibilities,
+ has_pub_restricted: false,
used_imports: FxHashSet::default(),
maybe_unused_trait_imports: Default::default(),
maybe_unused_extern_crates: Vec::new(),
let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
let definitions = self.definitions;
let visibilities = self.visibilities;
+ let has_pub_restricted = self.has_pub_restricted;
let extern_crate_map = self.extern_crate_map;
let reexport_map = self.reexport_map;
let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
definitions,
cstore: Box::new(self.crate_loader.into_cstore()),
visibilities,
+ has_pub_restricted,
access_levels,
extern_crate_map,
reexport_map,
access_levels: self.access_levels.clone(),
cstore: Box::new(self.cstore().clone()),
visibilities: self.visibilities.clone(),
+ has_pub_restricted: self.has_pub_restricted,
extern_crate_map: self.extern_crate_map.clone(),
reexport_map: self.reexport_map.clone(),
glob_map: self.glob_map.clone(),
use rustc_middle::span_bug;
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_session::config::Input;
-use rustc_span::source_map::respan;
use rustc_span::symbol::Ident;
use rustc_span::*;
}
macro_rules! access_from {
- ($save_ctxt:expr, $item:expr, $id:expr) => {
+ ($save_ctxt:expr, $id:expr) => {
Access {
- public: $item.vis.node.is_pub(),
+ public: $save_ctxt.tcx.visibility($id).is_public(),
reachable: $save_ctxt.access_levels.is_reachable($id),
}
};
}
-macro_rules! access_from_vis {
- ($save_ctxt:expr, $vis:expr, $id:expr) => {
- Access { public: $vis.node.is_pub(), reachable: $save_ctxt.access_levels.is_reachable($id) }
- };
-}
-
pub struct DumpVisitor<'tcx> {
pub save_ctxt: SaveContext<'tcx>,
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
ident: Ident,
generics: &'tcx hir::Generics<'tcx>,
- vis: &hir::Visibility<'tcx>,
span: Span,
) {
debug!("process_method: {:?}:{}", def_id, ident);
v.process_generic_params(&generics, &method_data.qualname, hir_id);
method_data.value =
- fn_to_string(sig.decl, sig.header, Some(ident.name), generics, vis, &[], None);
+ fn_to_string(sig.decl, sig.header, Some(ident.name), generics, &[], None);
method_data.sig = sig::method_signature(hir_id, ident, generics, sig, &v.save_ctxt);
- v.dumper.dump_def(&access_from_vis!(v.save_ctxt, vis, def_id), method_data);
+ v.dumper.dump_def(&access_from!(v.save_ctxt, def_id), method_data);
}
// walk arg and return types
let field_data = self.save_ctxt.get_field_data(field, parent_id);
if let Some(field_data) = field_data {
self.dumper.dump_def(
- &access_from!(self.save_ctxt, field, self.tcx.hir().local_def_id(field.hir_id)),
+ &access_from!(self.save_ctxt, self.tcx.hir().local_def_id(field.hir_id)),
field_data,
);
}
v.process_formals(body.params, &fn_data.qualname);
v.process_generic_params(ty_params, &fn_data.qualname, item.hir_id());
- v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.def_id), fn_data);
+ v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id), fn_data);
}
for arg in decl.inputs {
self.nest_typeck_results(item.def_id, |v| {
if let Some(var_data) = v.save_ctxt.get_item_data(item) {
down_cast_data!(var_data, DefData, item.span);
- v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.def_id), var_data);
+ v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id), var_data);
}
v.visit_ty(&typ);
v.visit_expr(expr);
typ: &'tcx hir::Ty<'tcx>,
expr: Option<&'tcx hir::Expr<'tcx>>,
parent_id: DefId,
- vis: &hir::Visibility<'tcx>,
attrs: &'tcx [ast::Attribute],
) {
let qualname = format!("::{}", self.tcx.def_path_str(def_id.to_def_id()));
let span = self.span_from_span(ident.span);
self.dumper.dump_def(
- &access_from_vis!(self.save_ctxt, vis, def_id),
+ &access_from!(self.save_ctxt, def_id),
Def {
kind: DefKind::Const,
id: id_from_hir_id(hir_id, &self.save_ctxt),
let fields_str = fields
.iter()
.filter_map(|f| {
- if include_priv_fields || f.vis.node.is_pub() {
+ if include_priv_fields {
+ return Some(f.ident.to_string());
+ }
+ let def_id = self.save_ctxt.tcx.hir().local_def_id(f.hir_id);
+ if self.save_ctxt.tcx.visibility(def_id).is_public() {
Some(f.ident.to_string())
} else {
None
let span = self.span_from_span(item.ident.span);
let attrs = self.tcx.hir().attrs(item.hir_id());
self.dumper.dump_def(
- &access_from!(self.save_ctxt, item, item.def_id),
+ &access_from!(self.save_ctxt, item.def_id),
Def {
kind,
id: id_from_def_id(item.def_id.to_def_id()),
};
down_cast_data!(enum_data, DefData, item.span);
- let access = access_from!(self.save_ctxt, item, item.def_id);
+ let access = access_from!(self.save_ctxt, item.def_id);
for variant in enum_definition.variants {
let name = variant.ident.name.to_string();
methods.iter().map(|i| id_from_def_id(i.id.def_id.to_def_id())).collect();
let attrs = self.tcx.hir().attrs(item.hir_id());
self.dumper.dump_def(
- &access_from!(self.save_ctxt, item, item.def_id),
+ &access_from!(self.save_ctxt, item.def_id),
Def {
kind: DefKind::Trait,
id,
fn process_mod(&mut self, item: &'tcx hir::Item<'tcx>) {
if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
down_cast_data!(mod_data, DefData, item.span);
- self.dumper.dump_def(&access_from!(self.save_ctxt, item, item.def_id), mod_data);
+ self.dumper.dump_def(&access_from!(self.save_ctxt, item.def_id), mod_data);
}
}
fn process_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>, trait_id: DefId) {
self.process_macro_use(trait_item.span);
- let vis_span = trait_item.span.shrink_to_lo();
match trait_item.kind {
hir::TraitItemKind::Const(ref ty, body) => {
let body = body.map(|b| &self.tcx.hir().body(b).value);
- let respan = respan(vis_span, hir::VisibilityKind::Public);
let attrs = self.tcx.hir().attrs(trait_item.hir_id());
self.process_assoc_const(
trait_item.def_id,
&ty,
body,
trait_id,
- &respan,
attrs,
);
}
hir::TraitItemKind::Fn(ref sig, ref trait_fn) => {
let body =
if let hir::TraitFn::Provided(body) = trait_fn { Some(*body) } else { None };
- let respan = respan(vis_span, hir::VisibilityKind::Public);
self.process_method(
sig,
body,
trait_item.def_id,
trait_item.ident,
&trait_item.generics,
- &respan,
trait_item.span,
);
}
&ty,
Some(&body.value),
impl_id,
- &impl_item.vis,
attrs,
);
}
impl_item.def_id,
impl_item.ident,
&impl_item.generics,
- &impl_item.vis,
impl_item.span,
);
}
hir::ItemKind::Use(path, hir::UseKind::Single) => {
let sub_span = path.segments.last().unwrap().ident.span;
if !self.span.filter_generated(sub_span) {
- let access = access_from!(self.save_ctxt, item, item.def_id);
+ let access = access_from!(self.save_ctxt, item.def_id);
let ref_id = self.lookup_def_id(item.hir_id()).map(id_from_def_id);
let span = self.span_from_span(sub_span);
let parent =
// we don't want to track anyway, since it's probably macro-internal `use`
if let Some(sub_span) = self.span.sub_span_of_star(item.span) {
if !self.span.filter_generated(item.span) {
- let access = access_from!(self.save_ctxt, item, item.def_id);
+ let access = access_from!(self.save_ctxt, item.def_id);
let span = self.span_from_span(sub_span);
let parent =
self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
let attrs = self.tcx.hir().attrs(item.hir_id());
self.dumper.dump_def(
- &access_from!(self.save_ctxt, item, item.def_id),
+ &access_from!(self.save_ctxt, item.def_id),
Def {
kind: DefKind::Type,
id,
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
- let access = access_from!(self.save_ctxt, item, item.def_id);
+ let access = access_from!(self.save_ctxt, item.def_id);
match item.kind {
hir::ForeignItemKind::Fn(decl, _, ref generics) => {
use rustc_session::config::{CrateType, Input, OutputType};
use rustc_session::cstore::ExternCrate;
use rustc_session::output::{filename_for_metadata, out_filename};
-use rustc_span::source_map::Spanned;
use rustc_span::symbol::Ident;
use rustc_span::*;
},
Some(item.ident.name),
generics,
- &item.vis,
arg_names,
None,
),
sig.header,
Some(item.ident.name),
generics,
- &item.vis,
&[],
None,
),
let qualname = format!("::{}", self.tcx.def_path_str(def_id));
filter!(self.span_utils, item.ident.span);
let value =
- enum_def_to_string(def, generics, item.ident.name, item.span, &item.vis);
+ enum_def_to_string(def, generics, item.ident.name, item.span);
Some(Data::DefData(Def {
kind: DefKind::Enum,
id: id_from_def_id(def_id),
Node::TraitRef(tr) => tr.path.res,
Node::Item(&hir::Item { kind: hir::ItemKind::Use(path, _), .. }) => path.res,
- Node::Visibility(&Spanned {
- node: hir::VisibilityKind::Restricted { ref path, .. },
- ..
- }) => path.res,
-
Node::PathSegment(seg) => match seg.res {
Some(res) if res != Res::Err => res,
_ => {
/// Therefore, the recursion depth is the binary logarithm of the number of
/// tokens to count, and the expanded tree is likewise very small.
macro_rules! count {
- () => (0usize);
($one:tt) => (1usize);
($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize);
($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize);
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,
/// This can be disabled with the `noprelude` option like
/// `--extern noprelude:name`.
pub add_prelude: bool,
+ /// The extern entry shouldn't be considered for unused dependency warnings.
+ ///
+ /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
+ /// suppress `unused-crate-dependencies` warnings.
+ pub nounused_dep: bool,
}
#[derive(Clone, Debug)]
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 ExternEntry {
fn new(location: ExternLocation) -> ExternEntry {
- ExternEntry { location, is_private_dep: false, add_prelude: false }
+ ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
}
pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
}
}
-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(
let mut is_private_dep = false;
let mut add_prelude = true;
+ let mut nounused_dep = false;
if let Some(opts) = options {
if !is_unstable_enabled {
early_error(
);
}
}
+ "nounused" => nounused_dep = true,
_ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
}
}
// Crates start out being not private, and go to being private `priv`
// is specified.
entry.is_private_dep |= is_private_dep;
+ // likewise `nounused`
+ entry.nounused_dep |= nounused_dep;
// If any flag is missing `noprelude`, then add to the prelude.
entry.add_prelude |= add_prelude;
}
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 const parse_opt_langid: &str = "a language identifier";
pub const parse_opt_pathbuf: &str = "a path";
pub const parse_list: &str = "a space-separated list of strings";
+ pub const parse_list_with_polarity: &str =
+ "a comma-separated list of strings, with elements beginning with + or -";
pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
pub const parse_number: &str = "a number";
pub const parse_opt_number: &str = parse_number;
}
}
+ crate fn parse_list_with_polarity(slot: &mut Vec<(String, bool)>, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => {
+ for s in s.split(",") {
+ let Some(pass_name) = s.strip_prefix(&['+', '-'][..]) else { return false };
+ slot.push((pass_name.to_string(), &s[..1] == "+"));
+ }
+ true
+ }
+ None => false,
+ }
+ }
+
crate fn parse_location_detail(ld: &mut LocationDetail, v: Option<&str>) -> bool {
if let Some(v) = v {
ld.line = false;
mir_emit_retag: bool = (false, parse_bool, [TRACKED],
"emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
(default: no)"),
+ mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED],
+ "use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \
+ enabled, overriding all other checks. Passes that are not specified are enabled or \
+ disabled by other flags as usual."),
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
move_size_limit: Option<usize> = (None, parse_opt_number, [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
}
}
mod analyze_source_file;
pub mod fatal_error;
+pub mod profiling;
+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{Lock, Lrc};
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)]
--- /dev/null
+use std::borrow::Borrow;
+
+use rustc_data_structures::profiling::EventArgRecorder;
+
+/// Extension trait for self-profiling purposes: allows to record spans within a generic activity's
+/// event arguments.
+pub trait SpannedEventArgRecorder {
+ /// Records the following event arguments within the current generic activity being profiled:
+ /// - the provided `event_arg`
+ /// - a string representation of the provided `span`
+ ///
+ /// Note: when self-profiling with costly event arguments, at least one argument
+ /// needs to be recorded. A panic will be triggered if that doesn't happen.
+ fn record_arg_with_span<A>(&mut self, event_arg: A, span: crate::Span)
+ where
+ A: Borrow<str> + Into<String>;
+}
+
+impl SpannedEventArgRecorder for EventArgRecorder<'_> {
+ fn record_arg_with_span<A>(&mut self, event_arg: A, span: crate::Span)
+ where
+ A: Borrow<str> + Into<String>,
+ {
+ self.record_arg(event_arg);
+
+ let span_arg = crate::with_session_globals(|session_globals| {
+ if let Some(source_map) = &*session_globals.source_map.borrow() {
+ source_map.span_to_embeddable_string(span)
+ } else {
+ format!("{:?}", span)
+ }
+ });
+ self.record_arg(span_arg);
+ }
+}
keyword,
kind,
kreg,
+ kreg0,
label,
label_break_value,
lang,
"sparc" => sparc::compute_abi_info(cx, self),
"sparc64" => sparc64::compute_abi_info(cx, self),
"nvptx" => nvptx::compute_abi_info(self),
- "nvptx64" => nvptx64::compute_abi_info(self),
+ "nvptx64" => {
+ if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::PtxKernel {
+ nvptx64::compute_ptx_kernel_abi_info(cx, self)
+ } else {
+ nvptx64::compute_abi_info(self)
+ }
+ }
"hexagon" => hexagon::compute_abi_info(self),
"riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
"wasm32" | "wasm64" => {
-// Reference: PTX Writer's Guide to Interoperability
-// https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
-
-use crate::abi::call::{ArgAbi, FnAbi};
+use crate::abi::call::{ArgAbi, FnAbi, PassMode, Reg, Size, Uniform};
+use crate::abi::{HasDataLayout, TyAbiInterface};
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
if ret.layout.is_aggregate() && ret.layout.size.bits() > 64 {
ret.make_indirect();
- } else {
- ret.extend_integer_width_to(64);
}
}
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 {
arg.make_indirect();
- } else {
- arg.extend_integer_width_to(64);
+ }
+}
+
+fn classify_arg_kernel<'a, Ty, C>(_cx: &C, arg: &mut ArgAbi<'a, Ty>)
+where
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
+{
+ if matches!(arg.mode, PassMode::Pair(..)) && (arg.layout.is_adt() || arg.layout.is_tuple()) {
+ let align_bytes = arg.layout.align.abi.bytes();
+
+ let unit = match align_bytes {
+ 1 => Reg::i8(),
+ 2 => Reg::i16(),
+ 4 => Reg::i32(),
+ 8 => Reg::i64(),
+ 16 => Reg::i128(),
+ _ => unreachable!("Align is given as power of 2 no larger than 16 bytes"),
+ };
+ arg.cast_to(Uniform { unit, total: Size::from_bytes(2 * align_bytes) });
}
}
classify_arg(arg);
}
}
+
+pub fn compute_ptx_kernel_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
+where
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
+{
+ if !fn_abi.ret.layout.is_unit() && !fn_abi.ret.layout.is_never() {
+ panic!("Kernels should not return anything other than () or !");
+ }
+
+ for arg in &mut fn_abi.args {
+ if arg.is_ignore() {
+ continue;
+ }
+ classify_arg_kernel(cx, arg);
+ }
+}
cx: &C,
offset: Size,
) -> Option<PointeeInfo>;
+ fn is_adt(this: TyAndLayout<'a, Self>) -> bool;
+ fn is_never(this: TyAndLayout<'a, Self>) -> bool;
+ fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
+ fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
}
impl<'a, Ty> TyAndLayout<'a, Ty> {
_ => false,
}
}
+
+ pub fn is_adt<C>(self) -> bool
+ where
+ Ty: TyAbiInterface<'a, C>,
+ {
+ Ty::is_adt(self)
+ }
+
+ pub fn is_never<C>(self) -> bool
+ where
+ Ty: TyAbiInterface<'a, C>,
+ {
+ Ty::is_never(self)
+ }
+
+ pub fn is_tuple<C>(self) -> bool
+ where
+ Ty: TyAbiInterface<'a, C>,
+ {
+ Ty::is_tuple(self)
+ }
+
+ pub fn is_unit<C>(self) -> bool
+ where
+ Ty: TyAbiInterface<'a, C>,
+ {
+ Ty::is_unit(self)
+ }
}
impl<'a, Ty> TyAndLayout<'a, Ty> {
}
}
-// The reserved registers are somewhat taken from <https://git.io/JUR1k#L150>.
+// The reserved registers are somewhat taken from
+// <https://github.com/llvm/llvm-project/blob/deb8f8bcf31540c657716ea5242183b0792702a1/llvm/lib/Target/Mips/MipsRegisterInfo.cpp#L150>.
def_regs! {
Mips MipsInlineAsmReg MipsInlineAsmRegClass {
r2: reg = ["$2"],
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",
}
}
let name = (stringify!($attr)).replace("_", "-");
d.insert(name, self.$attr.to_json());
}};
- ($attr:ident, $key_name:expr) => {{
- let name = $key_name;
- d.insert(name.into(), self.$attr.to_json());
- }};
}
macro_rules! target_option_val {
} else if cat_a == cat_b {
match (a.kind(), b.kind()) {
(ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b,
+ (ty::Foreign(def_a), ty::Foreign(def_b)) => def_a == def_b,
// Matching on references results in a lot of unhelpful
// suggestions, so let's just not do that for now.
//
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();
// We proactively collect all the inferred type params to emit a single error per fn def.
let mut visitor = HirPlaceholderCollector::default();
- for ty in decl.inputs {
- visitor.visit_ty(ty);
- }
+ let mut infer_replacements = vec![];
+
walk_generics(&mut visitor, generics);
- let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None));
+ let input_tys: Vec<_> = decl
+ .inputs
+ .iter()
+ .enumerate()
+ .map(|(i, a)| {
+ if let hir::TyKind::Infer = a.kind && !self.allow_ty_infer() {
+ if let Some(suggested_ty) =
+ self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
+ {
+ infer_replacements.push((a.span, suggested_ty.to_string()));
+ return suggested_ty;
+ }
+ }
+
+ // Only visit the type looking for `_` if we didn't fix the type above
+ visitor.visit_ty(a);
+ self.ty_of_arg(a, None)
+ })
+ .collect();
+
let output_ty = match decl.output {
hir::FnRetTy::Return(output) => {
- visitor.visit_ty(output);
- self.ast_ty_to_ty(output)
+ if let hir::TyKind::Infer = output.kind
+ && !self.allow_ty_infer()
+ && let Some(suggested_ty) =
+ self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
+ {
+ infer_replacements.push((output.span, suggested_ty.to_string()));
+ suggested_ty
+ } else {
+ visitor.visit_ty(output);
+ self.ast_ty_to_ty(output)
+ }
}
hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(),
};
debug!("ty_of_fn: output_ty={:?}", output_ty);
- let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi);
+ let fn_ty = tcx.mk_fn_sig(input_tys.into_iter(), output_ty, decl.c_variadic, unsafety, abi);
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
- if !self.allow_ty_infer() {
+ if !self.allow_ty_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) {
// We always collect the spans for placeholder types when evaluating `fn`s, but we
// only want to emit an error complaining about them if infer types (`_`) are not
// allowed. `allow_ty_infer` gates this behavior. We check for the presence of
// `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
- crate::collect::placeholder_type_error(
+ let mut diag = crate::collect::placeholder_type_error_diag(
tcx,
ident_span.map(|sp| sp.shrink_to_hi()),
generics.params,
visitor.0,
+ infer_replacements.iter().map(|(s, _)| *s).collect(),
true,
hir_ty,
"function",
);
+
+ if !infer_replacements.is_empty() {
+ diag.multipart_suggestion(&format!(
+ "try replacing `_` with the type{} in the corresponding trait method signature",
+ rustc_errors::pluralize!(infer_replacements.len()),
+ ), infer_replacements, Applicability::MachineApplicable);
+ }
+
+ diag.emit();
}
// Find any late-bound regions declared in return type that do
bare_fn_ty
}
+ /// Given a fn_hir_id for a impl function, suggest the type that is found on the
+ /// corresponding function in the trait that the impl implements, if it exists.
+ /// If arg_idx is Some, then it corresponds to an input type index, otherwise it
+ /// corresponds to the return type.
+ fn suggest_trait_fn_ty_for_impl_fn_infer(
+ &self,
+ fn_hir_id: hir::HirId,
+ arg_idx: Option<usize>,
+ ) -> Option<Ty<'tcx>> {
+ let tcx = self.tcx();
+ let hir = tcx.hir();
+
+ let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) =
+ hir.get(fn_hir_id) else { return None };
+ let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
+ hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
+
+ let trait_ref =
+ self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));
+
+ let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
+ tcx,
+ *ident,
+ ty::AssocKind::Fn,
+ trait_ref.def_id,
+ )?;
+
+ let fn_sig = tcx.fn_sig(assoc.def_id).subst(
+ tcx,
+ trait_ref.substs.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)),
+ );
+
+ let ty = if let Some(arg_idx) = arg_idx { fn_sig.input(arg_idx) } else { fn_sig.output() };
+
+ Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty))
+ }
+
fn validate_late_bound_regions(
&self,
constrained_regions: FxHashSet<ty::BoundRegionKind>,
};
use crate::type_error_struct;
+use super::suggest_call_constructor;
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::Diagnostic;
+use rustc_errors::EmissionGuarantee;
use rustc_errors::ErrorGuaranteed;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
use rustc_hir as hir;
// While we don't allow *arbitrary* coercions here, we *do* allow
// coercions from ! to `expected`.
if ty.is_never() {
- assert!(
- !self.typeck_results.borrow().adjustments().contains_key(expr.hir_id),
- "expression with never type wound up being adjusted"
- );
+ if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
+ self.tcx().sess.delay_span_bug(
+ expr.span,
+ "expression with never type wound up being adjusted",
+ );
+ return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] {
+ target.to_owned()
+ } else {
+ self.tcx().ty_error()
+ };
+ }
+
let adj_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::AdjustmentType,
span: expr.span,
self.tcx().ty_error()
}
+ fn check_call_constructor<G: EmissionGuarantee>(
+ &self,
+ err: &mut DiagnosticBuilder<'_, G>,
+ base: &'tcx hir::Expr<'tcx>,
+ def_id: DefId,
+ ) {
+ let local_id = def_id.expect_local();
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id);
+ let node = self.tcx.hir().get(hir_id);
+
+ if let Some(fields) = node.tuple_fields() {
+ let kind = match self.tcx.opt_def_kind(local_id) {
+ Some(DefKind::Ctor(of, _)) => of,
+ _ => return,
+ };
+
+ suggest_call_constructor(base.span, kind, fields.len(), err);
+ }
+ }
+
fn suggest_await_on_field_access(
&self,
err: &mut Diagnostic,
ty::Opaque(_, _) => {
self.suggest_await_on_field_access(&mut err, field, base, expr_t.peel_refs());
}
+ ty::FnDef(def_id, _) => {
+ self.check_call_constructor(&mut err, base, def_id);
+ }
_ => {}
}
// try to add a suggestion in case the field is a nested field of a field of the Adt
if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) {
for candidate_field in fields.iter() {
- if let Some(field_path) = self.check_for_nested_field(
+ if let Some(mut field_path) = self.check_for_nested_field_satisfying(
span,
- field,
+ &|candidate_field, _| candidate_field.ident(self.tcx()) == field,
candidate_field,
substs,
vec![],
self.tcx.parent_module(id).to_def_id(),
) {
+ // field_path includes `field` that we're looking for, so pop it.
+ field_path.pop();
+
let field_path_str = field_path
.iter()
.map(|id| id.name.to_ident_string())
err
}
- fn get_field_candidates(
+ crate fn get_field_candidates(
&self,
span: Span,
base_t: Ty<'tcx>,
/// This method is called after we have encountered a missing field error to recursively
/// search for the field
- fn check_for_nested_field(
+ crate fn check_for_nested_field_satisfying(
&self,
span: Span,
- target_field: Ident,
+ matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool,
candidate_field: &ty::FieldDef,
subst: SubstsRef<'tcx>,
mut field_path: Vec<Ident>,
id: DefId,
) -> Option<Vec<Ident>> {
debug!(
- "check_for_nested_field(span: {:?}, candidate_field: {:?}, field_path: {:?}",
+ "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}",
span, candidate_field, field_path
);
- if candidate_field.ident(self.tcx) == target_field {
- Some(field_path)
- } else if field_path.len() > 3 {
+ if field_path.len() > 3 {
// For compile-time reasons and to avoid infinite recursion we only check for fields
// up to a depth of three
None
} else {
// recursively search fields of `candidate_field` if it's a ty::Adt
-
field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0());
let field_ty = candidate_field.ty(self.tcx, subst);
if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) {
for field in nested_fields.iter() {
- let accessible = field.vis.is_accessible_from(id, self.tcx);
- if accessible {
- let ident = field.ident(self.tcx).normalize_to_macros_2_0();
- if ident == target_field {
+ if field.vis.is_accessible_from(id, self.tcx) {
+ if matches(candidate_field, field_ty) {
return Some(field_path);
- }
- let field_path = field_path.clone();
- if let Some(path) = self.check_for_nested_field(
+ } else if let Some(field_path) = self.check_for_nested_field_satisfying(
span,
- target_field,
+ matches,
field,
subst,
- field_path,
+ field_path.clone(),
id,
) {
- return Some(path);
+ return Some(field_path);
}
}
}
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();
| hir::Node::Ctor(..)
| hir::Node::Lifetime(..)
| hir::Node::GenericParam(..)
- | hir::Node::Visibility(..)
| hir::Node::Crate(..)
| hir::Node::Infer(..) => bug!("Unsupported branch target: {:?}", node),
}
MultiSpan,
};
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, Node, QPath};
use std::cmp::Ordering;
use std::iter;
-use super::probe::Mode;
-use super::{CandidateSource, MethodError, NoMatchData};
+use super::probe::{Mode, ProbeScope};
+use super::{super::suggest_call_constructor, CandidateSource, MethodError, NoMatchData};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
(None, true) => "variant",
}
};
- // FIXME(eddyb) this indentation is probably unnecessary.
- let mut err = {
- // Suggest clamping down the type if the method that is being attempted to
- // be used exists at all, and the type is an ambiguous numeric type
- // ({integer}/{float}).
- let mut candidates = all_traits(self.tcx)
- .into_iter()
- .filter_map(|info| self.associated_value(info.def_id, item_name));
- // There are methods that are defined on the primitive types and won't be
- // found when exploring `all_traits`, but we also need them to be accurate on
- // our suggestions (#47759).
- let found_assoc = |ty: Ty<'tcx>| {
- simplify_type(tcx, ty, TreatParams::AsPlaceholders)
- .and_then(|simp| {
- tcx.incoherent_impls(simp)
- .iter()
- .find_map(|&id| self.associated_value(id, item_name))
- })
- .is_some()
- };
- let found_candidate = candidates.next().is_some()
- || found_assoc(tcx.types.i8)
- || found_assoc(tcx.types.i16)
- || found_assoc(tcx.types.i32)
- || found_assoc(tcx.types.i64)
- || found_assoc(tcx.types.i128)
- || found_assoc(tcx.types.u8)
- || found_assoc(tcx.types.u16)
- || found_assoc(tcx.types.u32)
- || found_assoc(tcx.types.u64)
- || found_assoc(tcx.types.u128)
- || found_assoc(tcx.types.f32)
- || found_assoc(tcx.types.f32);
- if let (true, false, SelfSource::MethodCall(expr), true) = (
- actual.is_numeric(),
- actual.has_concrete_skeleton(),
- source,
- found_candidate,
- ) {
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0689,
- "can't call {} `{}` on ambiguous numeric type `{}`",
- item_kind,
- item_name,
- ty_str
- );
- let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
- match expr.kind {
- ExprKind::Lit(ref lit) => {
- // numeric literal
- let snippet = tcx
- .sess
- .source_map()
- .span_to_snippet(lit.span)
- .unwrap_or_else(|_| "<numeric literal>".to_owned());
-
- // If this is a floating point literal that ends with '.',
- // get rid of it to stop this from becoming a member access.
- let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
- err.span_suggestion(
- lit.span,
- &format!(
- "you must specify a concrete type for this numeric value, \
- like `{}`",
- concrete_type
- ),
- format!("{snippet}_{concrete_type}"),
- Applicability::MaybeIncorrect,
- );
- }
- ExprKind::Path(QPath::Resolved(_, path)) => {
- // local binding
- if let hir::def::Res::Local(hir_id) = path.res {
- let span = tcx.hir().span(hir_id);
- let snippet = tcx.sess.source_map().span_to_snippet(span);
- let filename = tcx.sess.source_map().span_to_filename(span);
-
- let parent_node =
- self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id));
- let msg = format!(
- "you must specify a type for this binding, like `{}`",
- concrete_type,
- );
-
- match (filename, parent_node, snippet) {
- (
- FileName::Real(_),
- Node::Local(hir::Local {
- source: hir::LocalSource::Normal,
- ty,
- ..
- }),
- Ok(ref snippet),
- ) => {
- err.span_suggestion(
- // account for `let x: _ = 42;`
- // ^^^^
- span.to(ty
- .as_ref()
- .map(|ty| ty.span)
- .unwrap_or(span)),
- &msg,
- format!("{}: {}", snippet, concrete_type),
- Applicability::MaybeIncorrect,
- );
- }
- _ => {
- err.span_label(span, msg);
- }
- }
- }
+ if self.suggest_constraining_numerical_ty(
+ tcx, actual, source, span, item_kind, item_name, &ty_str,
+ ) {
+ return None;
+ }
+
+ span = item_name.span;
+
+ // Don't show generic arguments when the method can't be found in any implementation (#81576).
+ let mut ty_str_reported = ty_str.clone();
+ if let ty::Adt(_, generics) = actual.kind() {
+ if generics.len() > 0 {
+ let mut autoderef = self.autoderef(span, actual);
+ let candidate_found = autoderef.any(|(ty, _)| {
+ if let ty::Adt(adt_deref, _) = ty.kind() {
+ self.tcx
+ .inherent_impls(adt_deref.did())
+ .iter()
+ .filter_map(|def_id| self.associated_value(*def_id, item_name))
+ .count()
+ >= 1
+ } else {
+ false
}
- _ => {}
- }
- err.emit();
- return None;
- } else {
- span = item_name.span;
-
- // Don't show generic arguments when the method can't be found in any implementation (#81576).
- let mut ty_str_reported = ty_str.clone();
- if let ty::Adt(_, generics) = actual.kind() {
- if generics.len() > 0 {
- let mut autoderef = self.autoderef(span, actual);
- let candidate_found = autoderef.any(|(ty, _)| {
- if let ty::Adt(adt_deref, _) = ty.kind() {
- self.tcx
- .inherent_impls(adt_deref.did())
- .iter()
- .filter_map(|def_id| {
- self.associated_value(*def_id, item_name)
- })
- .count()
- >= 1
- } else {
- false
- }
- });
- let has_deref = autoderef.step_count() > 0;
- if !candidate_found
- && !has_deref
- && unsatisfied_predicates.is_empty()
- {
- if let Some((path_string, _)) = ty_str.split_once('<') {
- ty_str_reported = path_string.to_string();
- }
- }
+ });
+ let has_deref = autoderef.step_count() > 0;
+ if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
+ if let Some((path_string, _)) = ty_str.split_once('<') {
+ ty_str_reported = path_string.to_string();
}
}
+ }
+ }
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0599,
- "no {} named `{}` found for {} `{}` in the current scope",
- item_kind,
- item_name,
- actual.prefix_string(self.tcx),
- ty_str_reported,
- );
- if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
- self.suggest_await_before_method(
- &mut err, item_name, actual, cal, span,
- );
- }
- if let Some(span) =
- tcx.resolutions(()).confused_type_with_std_module.get(&span)
- {
- if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
- err.span_suggestion(
- *span,
- "you are looking for the module in `std`, \
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0599,
+ "no {} named `{}` found for {} `{}` in the current scope",
+ item_kind,
+ item_name,
+ actual.prefix_string(self.tcx),
+ ty_str_reported,
+ );
+ if actual.references_error() {
+ err.downgrade_to_delayed_bug();
+ }
+
+ if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
+ self.suggest_await_before_method(
+ &mut err, item_name, actual, cal, span,
+ );
+ }
+ if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) {
+ if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
+ err.span_suggestion(
+ *span,
+ "you are looking for the module in `std`, \
not the primitive type",
- format!("std::{}", snippet),
- Applicability::MachineApplicable,
- );
- }
- }
- if let ty::RawPtr(_) = &actual.kind() {
- err.note(
- "try using `<*const T>::as_ref()` to get a reference to the \
+ format!("std::{}", snippet),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ if let ty::RawPtr(_) = &actual.kind() {
+ err.note(
+ "try using `<*const T>::as_ref()` to get a reference to the \
type behind the pointer: https://doc.rust-lang.org/std/\
primitive.pointer.html#method.as_ref",
- );
- err.note(
- "using `<*const T>::as_ref()` on a pointer \
+ );
+ err.note(
+ "using `<*const T>::as_ref()` on a pointer \
which is unaligned or points to invalid \
or uninitialized memory is undefined behavior",
- );
- }
- err
- }
- };
-
- if actual.references_error() {
- err.downgrade_to_delayed_bug();
+ );
}
if let Some(def) = actual.ty_adt_def() {
}
if self.is_fn_ty(rcvr_ty, span) {
- fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) {
- err.note(
- &format!("`{}` is a function, perhaps you wish to call it", name,),
- );
- }
-
if let SelfSource::MethodCall(expr) = source {
- if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
- report_function(&mut err, expr_string);
- } else if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind {
- if let Some(segment) = path.segments.last() {
- report_function(&mut err, segment.ident);
+ let suggest = if let ty::FnDef(def_id, _) = rcvr_ty.kind() {
+ let local_id = def_id.expect_local();
+ let hir_id = tcx.hir().local_def_id_to_hir_id(local_id);
+ let node = tcx.hir().get(hir_id);
+ let fields = node.tuple_fields();
+
+ if let Some(fields) = fields
+ && let Some(DefKind::Ctor(of, _)) = self.tcx.opt_def_kind(local_id) {
+ Some((fields, of))
+ } else {
+ None
}
+ } else {
+ None
+ };
+
+ // If the function is a tuple constructor, we recommend that they call it
+ if let Some((fields, kind)) = suggest {
+ suggest_call_constructor(expr.span, kind, fields.len(), &mut err);
+ } else {
+ // General case
+ err.span_label(
+ expr.span,
+ "this is a function, perhaps you wish to call it",
+ );
}
}
}
}
}
- let mut label_span_not_found = || {
+ let label_span_not_found = |err: &mut DiagnosticBuilder<'_, _>| {
if unsatisfied_predicates.is_empty() {
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
let is_string_or_ref_str = match actual.kind() {
// If the method name is the name of a field with a function or closure type,
// give a helping note that it has to be called as `(x.f)(...)`.
if let SelfSource::MethodCall(expr) = source {
- let field_receiver =
- self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
- ty::Adt(def, substs) if !def.is_enum() => {
- let variant = &def.non_enum_variant();
- self.tcx.find_field_index(item_name, variant).map(|index| {
- let field = &variant.fields[index];
- let field_ty = field.ty(tcx, substs);
- (field, field_ty)
- })
- }
- _ => None,
- });
+ if !self.suggest_field_call(span, rcvr_ty, expr, item_name, &mut err)
+ && lev_candidate.is_none()
+ && !custom_span_label
+ {
+ label_span_not_found(&mut err);
+ }
+ } else if !custom_span_label {
+ label_span_not_found(&mut err);
+ }
- if let Some((field, field_ty)) = field_receiver {
- let scope = self.tcx.parent_module(self.body_id).to_def_id();
- let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
+ if let SelfSource::MethodCall(expr) = source
+ && let Some((fields, substs)) = self.get_field_candidates(span, actual)
+ {
+ let call_expr =
+ self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+ for candidate_field in fields.iter() {
+ if let Some(field_path) = self.check_for_nested_field_satisfying(
+ span,
+ &|_, field_ty| {
+ self.lookup_probe(
+ span,
+ item_name,
+ field_ty,
+ call_expr,
+ ProbeScope::AllTraits,
+ )
+ .is_ok()
+ },
+ candidate_field,
+ substs,
+ vec![],
+ self.tcx.parent_module(expr.hir_id).to_def_id(),
+ ) {
+ let field_path_str = field_path
+ .iter()
+ .map(|id| id.name.to_ident_string())
+ .collect::<Vec<String>>()
+ .join(".");
+ debug!("field_path_str: {:?}", field_path_str);
- if is_accessible {
- if self.is_fn_ty(field_ty, span) {
- let expr_span = expr.span.to(item_name.span);
- err.multipart_suggestion(
- &format!(
- "to call the function stored in `{}`, \
- surround the field access with parentheses",
- item_name,
- ),
- vec![
- (expr_span.shrink_to_lo(), '('.to_string()),
- (expr_span.shrink_to_hi(), ')'.to_string()),
- ],
- Applicability::MachineApplicable,
- );
- } else {
- let call_expr = self
- .tcx
- .hir()
- .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-
- if let Some(span) = call_expr.span.trim_start(item_name.span) {
- err.span_suggestion(
- span,
- "remove the arguments",
- String::new(),
- Applicability::MaybeIncorrect,
- );
- }
- }
+ err.span_suggestion_verbose(
+ item_name.span.shrink_to_lo(),
+ "one of the expressions' fields has a method of the same name",
+ format!("{field_path_str}."),
+ Applicability::MaybeIncorrect,
+ );
}
-
- let field_kind = if is_accessible { "field" } else { "private field" };
- err.span_label(item_name.span, format!("{}, not a method", field_kind));
- } else if lev_candidate.is_none() && !custom_span_label {
- label_span_not_found();
}
- } else if !custom_span_label {
- label_span_not_found();
}
bound_spans.sort();
None
}
+ fn suggest_field_call(
+ &self,
+ span: Span,
+ rcvr_ty: Ty<'tcx>,
+ expr: &hir::Expr<'_>,
+ item_name: Ident,
+ err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ ) -> bool {
+ let tcx = self.tcx;
+ let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
+ ty::Adt(def, substs) if !def.is_enum() => {
+ let variant = &def.non_enum_variant();
+ tcx.find_field_index(item_name, variant).map(|index| {
+ let field = &variant.fields[index];
+ let field_ty = field.ty(tcx, substs);
+ (field, field_ty)
+ })
+ }
+ _ => None,
+ });
+ if let Some((field, field_ty)) = field_receiver {
+ let scope = tcx.parent_module(self.body_id).to_def_id();
+ let is_accessible = field.vis.is_accessible_from(scope, tcx);
+
+ if is_accessible {
+ if self.is_fn_ty(field_ty, span) {
+ let expr_span = expr.span.to(item_name.span);
+ err.multipart_suggestion(
+ &format!(
+ "to call the function stored in `{}`, \
+ surround the field access with parentheses",
+ item_name,
+ ),
+ vec![
+ (expr_span.shrink_to_lo(), '('.to_string()),
+ (expr_span.shrink_to_hi(), ')'.to_string()),
+ ],
+ Applicability::MachineApplicable,
+ );
+ } else {
+ let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
+
+ if let Some(span) = call_expr.span.trim_start(item_name.span) {
+ err.span_suggestion(
+ span,
+ "remove the arguments",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+
+ let field_kind = if is_accessible { "field" } else { "private field" };
+ err.span_label(item_name.span, format!("{}, not a method", field_kind));
+ return true;
+ }
+ false
+ }
+
+ fn suggest_constraining_numerical_ty(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ actual: Ty<'tcx>,
+ source: SelfSource<'_>,
+ span: Span,
+ item_kind: &str,
+ item_name: Ident,
+ ty_str: &str,
+ ) -> bool {
+ let found_candidate = all_traits(self.tcx)
+ .into_iter()
+ .any(|info| self.associated_value(info.def_id, item_name).is_some());
+ let found_assoc = |ty: Ty<'tcx>| {
+ simplify_type(tcx, ty, TreatParams::AsPlaceholders)
+ .and_then(|simp| {
+ tcx.incoherent_impls(simp)
+ .iter()
+ .find_map(|&id| self.associated_value(id, item_name))
+ })
+ .is_some()
+ };
+ let found_candidate = found_candidate
+ || found_assoc(tcx.types.i8)
+ || found_assoc(tcx.types.i16)
+ || found_assoc(tcx.types.i32)
+ || found_assoc(tcx.types.i64)
+ || found_assoc(tcx.types.i128)
+ || found_assoc(tcx.types.u8)
+ || found_assoc(tcx.types.u16)
+ || found_assoc(tcx.types.u32)
+ || found_assoc(tcx.types.u64)
+ || found_assoc(tcx.types.u128)
+ || found_assoc(tcx.types.f32)
+ || found_assoc(tcx.types.f32);
+ if found_candidate
+ && actual.is_numeric()
+ && !actual.has_concrete_skeleton()
+ && let SelfSource::MethodCall(expr) = source
+ {
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0689,
+ "can't call {} `{}` on ambiguous numeric type `{}`",
+ item_kind,
+ item_name,
+ ty_str
+ );
+ let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
+ match expr.kind {
+ ExprKind::Lit(ref lit) => {
+ // numeric literal
+ let snippet = tcx
+ .sess
+ .source_map()
+ .span_to_snippet(lit.span)
+ .unwrap_or_else(|_| "<numeric literal>".to_owned());
+
+ // If this is a floating point literal that ends with '.',
+ // get rid of it to stop this from becoming a member access.
+ let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
+
+ err.span_suggestion(
+ lit.span,
+ &format!(
+ "you must specify a concrete type for this numeric value, \
+ like `{}`",
+ concrete_type
+ ),
+ format!("{snippet}_{concrete_type}"),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ ExprKind::Path(QPath::Resolved(_, path)) => {
+ // local binding
+ if let hir::def::Res::Local(hir_id) = path.res {
+ let span = tcx.hir().span(hir_id);
+ let snippet = tcx.sess.source_map().span_to_snippet(span);
+ let filename = tcx.sess.source_map().span_to_filename(span);
+
+ let parent_node =
+ self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id));
+ let msg = format!(
+ "you must specify a type for this binding, like `{}`",
+ concrete_type,
+ );
+
+ match (filename, parent_node, snippet) {
+ (
+ FileName::Real(_),
+ Node::Local(hir::Local {
+ source: hir::LocalSource::Normal,
+ ty,
+ ..
+ }),
+ Ok(ref snippet),
+ ) => {
+ err.span_suggestion(
+ // account for `let x: _ = 42;`
+ // ^^^^
+ span.to(ty.as_ref().map(|ty| ty.span).unwrap_or(span)),
+ &msg,
+ format!("{}: {}", snippet, concrete_type),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {
+ err.span_label(span, msg);
+ }
+ }
+ }
+ }
+ _ => {}
+ }
+ err.emit();
+ return true;
+ }
+ false
+ }
+
crate fn note_unmet_impls_on_type(
&self,
err: &mut Diagnostic,
pub use diverges::Diverges;
pub use expectation::Expectation;
pub use fn_ctxt::*;
+use hir::def::CtorOf;
pub use inherited::{Inherited, InheritedBuilder};
use crate::astconv::AstConv;
use crate::check::gather_locals::GatherLocalsVisitor;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
+use rustc_errors::{
+ pluralize, struct_span_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan,
+};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, LocalDefId};
generics.count() == expected + if generics.has_self { 1 } else { 0 }
})
}
+
+/// Suggests calling the constructor of a tuple struct or enum variant
+///
+/// * `snippet` - The snippet of code that references the constructor
+/// * `span` - The span of the snippet
+/// * `params` - The number of parameters the constructor accepts
+/// * `err` - A mutable diagnostic builder to add the suggestion to
+fn suggest_call_constructor<G: EmissionGuarantee>(
+ span: Span,
+ kind: CtorOf,
+ params: usize,
+ err: &mut DiagnosticBuilder<'_, G>,
+) {
+ // Note: tuple-structs don't have named fields, so just use placeholders
+ let args = vec!["_"; params].join(", ");
+ let applicable = if params > 0 {
+ Applicability::HasPlaceholders
+ } else {
+ // When n = 0, it's an empty-tuple struct/enum variant
+ // so we trivially know how to construct it
+ Applicability::MachineApplicable
+ };
+ let kind = match kind {
+ CtorOf::Struct => "a struct",
+ CtorOf::Variant => "an enum variant",
+ };
+ err.span_label(span, &format!("this is the constructor of {kind}"));
+ err.multipart_suggestion(
+ "call the constructor",
+ vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), format!(")({args})"))],
+ applicable,
+ );
+}
};
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint};
-use rustc_middle::ty::{
- self, suggest_constraining_type_param, Ty, TyCtxt, TypeFoldable, TypeVisitor,
-};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as _;
use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
use std::ops::ControlFlow;
Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(),
Err(errors) => {
let source_map = self.tcx.sess.source_map();
- let (mut err, missing_trait, use_output) = match is_assign {
+ let (mut err, missing_trait, _use_output) = match is_assign {
IsAssign::Yes => {
let mut err = struct_span_err!(
self.tcx.sess,
// concatenation (e.g., "Hello " + "World!"). This means
// we don't want the note in the else clause to be emitted
} else if let [ty] = &visitor.0[..] {
- if let ty::Param(p) = *ty.kind() {
- // Check if the method would be found if the type param wasn't
- // involved. If so, it means that adding a trait bound to the param is
- // enough. Otherwise we do not give the suggestion.
- let mut eraser = TypeParamEraser(self, expr.span);
- let needs_bound = self
- .lookup_op_method(
- eraser.fold_ty(lhs_ty),
- Some(eraser.fold_ty(rhs_ty)),
- Some(rhs_expr),
- Op::Binary(op, is_assign),
- )
- .is_ok();
- if needs_bound {
- suggest_constraining_param(
- self.tcx,
- self.body_id,
+ // Look for a TraitPredicate in the Fulfillment errors,
+ // and use it to generate a suggestion.
+ //
+ // Note that lookup_op_method must be called again but
+ // with a specific rhs_ty instead of a placeholder so
+ // the resulting predicate generates a more specific
+ // suggestion for the user.
+ let errors = self
+ .lookup_op_method(
+ lhs_ty,
+ Some(rhs_ty),
+ Some(rhs_expr),
+ Op::Binary(op, is_assign),
+ )
+ .unwrap_err();
+ let predicates = errors
+ .into_iter()
+ .filter_map(|error| error.obligation.predicate.to_opt_poly_trait_pred())
+ .collect::<Vec<_>>();
+ if !predicates.is_empty() {
+ for pred in predicates {
+ self.infcx.suggest_restricting_param_bound(
&mut err,
- *ty,
- rhs_ty,
- missing_trait,
- p,
- use_output,
+ pred,
+ self.body_id,
);
- } else if *ty != lhs_ty {
- // When we know that a missing bound is responsible, we don't show
- // this note as it is redundant.
- err.note(&format!(
- "the trait `{missing_trait}` is not implemented for `{lhs_ty}`"
- ));
}
- } else {
- bug!("type param visitor stored a non type param: {:?}", ty.kind());
+ } else if *ty != lhs_ty {
+ // When we know that a missing bound is responsible, we don't show
+ // this note as it is redundant.
+ err.note(&format!(
+ "the trait `{missing_trait}` is not implemented for `{lhs_ty}`"
+ ));
}
}
}
ex.span,
format!("cannot apply unary operator `{}`", op.as_str()),
);
- let missing_trait = match op {
- hir::UnOp::Deref => unreachable!("check unary op `-` or `!` only"),
- hir::UnOp::Not => "std::ops::Not",
- hir::UnOp::Neg => "std::ops::Neg",
- };
+
let mut visitor = TypeParamVisitor(vec![]);
visitor.visit_ty(operand_ty);
- if let [ty] = &visitor.0[..] && let ty::Param(p) = *operand_ty.kind() {
- suggest_constraining_param(
- self.tcx,
- self.body_id,
- &mut err,
- *ty,
- operand_ty,
- missing_trait,
- p,
- true,
- );
+ if let [_] = &visitor.0[..] && let ty::Param(_) = *operand_ty.kind() {
+ let predicates = errors
+ .iter()
+ .filter_map(|error| {
+ error.obligation.predicate.clone().to_opt_poly_trait_pred()
+ });
+ for pred in predicates {
+ self.infcx.suggest_restricting_param_bound(
+ &mut err,
+ pred,
+ self.body_id,
+ );
+ }
}
let sp = self.tcx.sess.source_map().start_point(ex.span);
}
}
-fn suggest_constraining_param(
- tcx: TyCtxt<'_>,
- body_id: hir::HirId,
- mut err: &mut Diagnostic,
- lhs_ty: Ty<'_>,
- rhs_ty: Ty<'_>,
- missing_trait: &str,
- p: ty::ParamTy,
- set_output: bool,
-) {
- let hir = tcx.hir();
- let msg = &format!("`{lhs_ty}` might need a bound for `{missing_trait}`");
- // Try to find the def-id and details for the parameter p. We have only the index,
- // so we have to find the enclosing function's def-id, then look through its declared
- // generic parameters to get the declaration.
- let def_id = hir.body_owner_def_id(hir::BodyId { hir_id: body_id });
- let generics = tcx.generics_of(def_id);
- let param_def_id = generics.type_param(&p, tcx).def_id;
- if let Some(generics) = param_def_id
- .as_local()
- .map(|id| hir.local_def_id_to_hir_id(id))
- .and_then(|id| hir.find_by_def_id(hir.get_parent_item(id)))
- .as_ref()
- .and_then(|node| node.generics())
- {
- let output = if set_output { format!("<Output = {rhs_ty}>") } else { String::new() };
- suggest_constraining_type_param(
- tcx,
- generics,
- &mut err,
- &lhs_ty.to_string(),
- &format!("{missing_trait}{output}"),
- None,
- );
- } else {
- let span = tcx.def_span(param_def_id);
- err.span_label(span, msg);
- }
-}
-
struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>);
impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
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),
+ }
+ }
}
for id in tcx.hir().items() {
if matches!(tcx.hir().def_kind(id.def_id), DefKind::Use) {
+ if tcx.visibility(id.def_id).is_public() {
+ continue;
+ }
let item = tcx.hir().item(id);
- if item.vis.node.is_pub() || item.span.is_dummy() {
+ if item.span.is_dummy() {
continue;
}
if let hir::ItemKind::Use(path, _) = item.kind {
Some(orig_name) => format!("use {} as {};", orig_name, item.ident.name),
None => format!("use {};", item.ident.name),
};
- let vis = tcx.sess.source_map().span_to_snippet(item.vis.span).unwrap_or_default();
+ let vis = tcx.sess.source_map().span_to_snippet(item.vis_span).unwrap_or_default();
let add_vis = |to| if vis.is_empty() { to } else { format!("{} {}", vis, to) };
lint.build("`extern crate` is not idiomatic in the new edition")
.span_suggestion_short(
tcx,
sp,
tr.path.span,
+ trait_ref.self_ty(),
impl_.self_ty.span,
&impl_.generics,
err,
tcx: TyCtxt<'tcx>,
sp: Span,
trait_span: Span,
+ self_ty: Ty<'tcx>,
self_ty_span: Span,
generics: &hir::Generics<'tcx>,
err: traits::OrphanCheckErr<'tcx>,
) -> Result<!, ErrorGuaranteed> {
Err(match err {
traits::OrphanCheckErr::NonLocalInputType(tys) => {
+ let msg = match self_ty.kind() {
+ ty::Adt(..) => "can be implemented for types defined outside of the crate",
+ _ if self_ty.is_primitive() => "can be implemented for primitive types",
+ _ => "can be implemented for arbitrary types",
+ };
let mut err = struct_span_err!(
tcx.sess,
sp,
E0117,
- "only traits defined in the current crate can be implemented for \
- arbitrary types"
+ "only traits defined in the current crate {msg}"
);
err.span_label(sp, "impl doesn't use only types from inside the current crate");
for (ty, is_target_ty) in &tys {
return;
}
+ placeholder_type_error_diag(
+ tcx,
+ span,
+ generics,
+ placeholder_types,
+ vec![],
+ suggest,
+ hir_ty,
+ kind,
+ )
+ .emit();
+}
+
+crate fn placeholder_type_error_diag<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ span: Option<Span>,
+ generics: &[hir::GenericParam<'_>],
+ placeholder_types: Vec<Span>,
+ additional_spans: Vec<Span>,
+ suggest: bool,
+ hir_ty: Option<&hir::Ty<'_>>,
+ kind: &'static str,
+) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ if placeholder_types.is_empty() {
+ return bad_placeholder(tcx, additional_spans, kind);
+ }
+
let type_name = generics.next_type_param_name(None);
let mut sugg: Vec<_> =
placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
sugg.push((span, format!(", {}", type_name)));
}
- let mut err = bad_placeholder(tcx, placeholder_types, kind);
+ let mut err =
+ bad_placeholder(tcx, placeholder_types.into_iter().chain(additional_spans).collect(), kind);
// Suggest, but only if it is not a function in const or static
if suggest {
);
}
}
- err.emit();
+
+ err
}
fn reject_placeholder_type_signatures_in_item<'tcx>(
generics,
..
})
- | ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), ident, generics, .. })
| Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), ident, .. }) => {
- match get_infer_ret_ty(&sig.decl.output) {
- Some(ty) => {
- let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
- // Typeck doesn't expect erased regions to be returned from `type_of`.
- let fn_sig = tcx.fold_regions(fn_sig, &mut false, |r, _| match *r {
- ty::ReErased => tcx.lifetimes.re_static,
- _ => r,
- });
- let fn_sig = ty::Binder::dummy(fn_sig);
-
- let mut visitor = HirPlaceholderCollector::default();
- visitor.visit_ty(ty);
- let mut diag = bad_placeholder(tcx, visitor.0, "return type");
- let ret_ty = fn_sig.skip_binder().output();
- if !ret_ty.references_error() {
- if !ret_ty.is_closure() {
- let ret_ty_str = match ret_ty.kind() {
- // Suggest a function pointer return type instead of a unique function definition
- // (e.g. `fn() -> i32` instead of `fn() -> i32 { f }`, the latter of which is invalid
- // syntax)
- ty::FnDef(..) => ret_ty.fn_sig(tcx).to_string(),
- _ => ret_ty.to_string(),
- };
- diag.span_suggestion(
- ty.span,
- "replace with the correct return type",
- ret_ty_str,
- Applicability::MaybeIncorrect,
- );
- } else {
- // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
- // to prevent the user from getting a papercut while trying to use the unique closure
- // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
- diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
- diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
- }
- }
- diag.emit();
+ infer_return_ty_for_fn_sig(tcx, sig, *ident, generics, def_id, &icx)
+ }
- fn_sig
- }
- None => <dyn AstConv<'_>>::ty_of_fn(
+ ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), ident, generics, .. }) => {
+ // Do not try to inference the return type for a impl method coming from a trait
+ if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
+ tcx.hir().get(tcx.hir().get_parent_node(hir_id))
+ && i.of_trait.is_some()
+ {
+ <dyn AstConv<'_>>::ty_of_fn(
&icx,
hir_id,
sig.header.unsafety,
generics,
Some(ident.span),
None,
- ),
+ )
+ } else {
+ infer_return_ty_for_fn_sig(tcx, sig, *ident, generics, def_id, &icx)
}
}
}
}
+fn infer_return_ty_for_fn_sig<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ sig: &hir::FnSig<'_>,
+ ident: Ident,
+ generics: &hir::Generics<'_>,
+ def_id: LocalDefId,
+ icx: &ItemCtxt<'tcx>,
+) -> ty::PolyFnSig<'tcx> {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+ match get_infer_ret_ty(&sig.decl.output) {
+ Some(ty) => {
+ let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
+ // Typeck doesn't expect erased regions to be returned from `type_of`.
+ let fn_sig = tcx.fold_regions(fn_sig, &mut false, |r, _| match *r {
+ ty::ReErased => tcx.lifetimes.re_static,
+ _ => r,
+ });
+ let fn_sig = ty::Binder::dummy(fn_sig);
+
+ let mut visitor = HirPlaceholderCollector::default();
+ visitor.visit_ty(ty);
+ let mut diag = bad_placeholder(tcx, visitor.0, "return type");
+ let ret_ty = fn_sig.skip_binder().output();
+ if !ret_ty.references_error() {
+ if !ret_ty.is_closure() {
+ let ret_ty_str = match ret_ty.kind() {
+ // Suggest a function pointer return type instead of a unique function definition
+ // (e.g. `fn() -> i32` instead of `fn() -> i32 { f }`, the latter of which is invalid
+ // syntax)
+ ty::FnDef(..) => ret_ty.fn_sig(tcx).to_string(),
+ _ => ret_ty.to_string(),
+ };
+ diag.span_suggestion(
+ ty.span,
+ "replace with the correct return type",
+ ret_ty_str,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
+ // to prevent the user from getting a papercut while trying to use the unique closure
+ // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
+ diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
+ diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
+ }
+ }
+ diag.emit();
+
+ fn_sig
+ }
+ None => <dyn AstConv<'_>>::ty_of_fn(
+ icx,
+ hir_id,
+ sig.header.unsafety,
+ sig.header.abi,
+ sig.decl,
+ generics,
+ Some(ident.span),
+ None,
+ ),
+ }
+}
+
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
let icx = ItemCtxt::new(tcx, def_id);
match tcx.hir().expect_item(def_id.expect_local()).kind {
#[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
///
/// # Examples
///
- /// Calling `into_owned` on a `Cow::Borrowed` clones the underlying data
- /// and becomes a `Cow::Owned`:
+ /// Calling `into_owned` on a `Cow::Borrowed` returns a clone of the borrowed data:
///
/// ```
/// use std::borrow::Cow;
/// );
/// ```
///
- /// Calling `into_owned` on a `Cow::Owned` is a no-op:
+ /// Calling `into_owned` on a `Cow::Owned` returns the owned data. The data is moved out of the
+ /// `Cow` without being cloned.
///
/// ```
/// use std::borrow::Cow;
/// Returns `true` if the `LinkedList` contains an element equal to the
/// given value.
///
- /// This operation should compute in *O*(*n*) time.
+ /// This operation should compute linearly in *O*(*n*) time.
///
/// # Examples
///
/// Appends an element to the front of the cursor's parent list. The node
/// that the cursor points to is unchanged, even if it is the "ghost" node.
///
- /// This operation should compute in O(1) time.
+ /// This operation should compute in *O*(1) time.
// `push_front` continues to point to "ghost" when it addes a node to mimic
// the behavior of `insert_before` on an empty list.
#[unstable(feature = "linked_list_cursors", issue = "58533")]
/// Appends an element to the back of the cursor's parent list. The node
/// that the cursor points to is unchanged, even if it is the "ghost" node.
///
- /// This operation should compute in O(1) time.
+ /// This operation should compute in *O*(1) time.
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn push_back(&mut self, elt: T) {
// Safety: We know that `push_back` does not change the position in
/// unchanged, unless it was pointing to the front element. In that case, it
/// points to the new front element.
///
- /// This operation should compute in O(1) time.
+ /// This operation should compute in *O*(1) time.
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn pop_front(&mut self) -> Option<T> {
// We can't check if current is empty, we must check the list directly.
/// unchanged, unless it was pointing to the back element. In that case, it
/// points to the "ghost" element.
///
- /// This operation should compute in O(1) time.
+ /// This operation should compute in *O*(1) time.
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn pop_back(&mut self) -> Option<T> {
if self.list.is_empty() {
/// Returns `true` if the deque contains an element equal to the
/// given value.
///
+ /// This operation is *O*(*n*).
+ ///
+ /// Note that if you have a sorted `VecDeque`, [`binary_search`] may be faster.
+ ///
+ /// [`binary_search`]: VecDeque::binary_search
+ ///
/// # Examples
///
/// ```
}
}
- /// Binary searches the sorted deque for a given element.
+ /// Binary searches this `VecDeque` for a given element.
+ /// This behaves similarly to [`contains`] if this `VecDeque` is sorted.
///
/// If the value is found then [`Result::Ok`] is returned, containing the
/// index of the matching element. If there are multiple matches, then any
///
/// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`].
///
+ /// [`contains`]: VecDeque::contains
/// [`binary_search_by`]: VecDeque::binary_search_by
/// [`binary_search_by_key`]: VecDeque::binary_search_by_key
/// [`partition_point`]: VecDeque::partition_point
self.binary_search_by(|e| e.cmp(x))
}
- /// Binary searches the sorted deque with a comparator function.
+ /// Binary searches this `VecDeque` with a comparator function.
+ /// This behaves similarly to [`contains`] if this `VecDeque` is sorted.
///
/// The comparator function should implement an order consistent
/// with the sort order of the deque, returning an order code that
///
/// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`].
///
+ /// [`contains`]: VecDeque::contains
/// [`binary_search`]: VecDeque::binary_search
/// [`binary_search_by_key`]: VecDeque::binary_search_by_key
/// [`partition_point`]: VecDeque::partition_point
}
}
- /// Binary searches the sorted deque with a key extraction function.
+ /// Binary searches this `VecDeque` with a key extraction function.
+ /// This behaves similarly to [`contains`] if this `VecDeque` is sorted.
///
/// Assumes that the deque is sorted by the key, for instance with
/// [`make_contiguous().sort_by_key()`] using the same key extraction function.
///
/// See also [`binary_search`], [`binary_search_by`], and [`partition_point`].
///
+ /// [`contains`]: VecDeque::contains
/// [`make_contiguous().sort_by_key()`]: VecDeque::make_contiguous
/// [`binary_search`]: VecDeque::binary_search
/// [`binary_search_by`]: VecDeque::binary_search_by
}
}
+#[test]
+fn test_get() {
+ let mut tester = VecDeque::new();
+ tester.push_back(1);
+ tester.push_back(2);
+ tester.push_back(3);
+
+ assert_eq!(tester.len(), 3);
+
+ assert_eq!(tester.get(1), Some(&2));
+ assert_eq!(tester.get(2), Some(&3));
+ assert_eq!(tester.get(0), Some(&1));
+ assert_eq!(tester.get(3), None);
+
+ tester.remove(0);
+
+ assert_eq!(tester.len(), 2);
+ assert_eq!(tester.get(0), Some(&2));
+ assert_eq!(tester.get(1), Some(&3));
+ assert_eq!(tester.get(2), None);
+}
+
+#[test]
+fn test_get_mut() {
+ let mut tester = VecDeque::new();
+ tester.push_back(1);
+ tester.push_back(2);
+ tester.push_back(3);
+
+ assert_eq!(tester.len(), 3);
+
+ if let Some(elem) = tester.get_mut(0) {
+ assert_eq!(*elem, 1);
+ *elem = 10;
+ }
+
+ if let Some(elem) = tester.get_mut(2) {
+ assert_eq!(*elem, 3);
+ *elem = 30;
+ }
+
+ assert_eq!(tester.get(0), Some(&10));
+ assert_eq!(tester.get(2), Some(&30));
+ assert_eq!(tester.get_mut(3), None);
+
+ tester.remove(2);
+
+ assert_eq!(tester.len(), 2);
+ assert_eq!(tester.get(0), Some(&10));
+ assert_eq!(tester.get(1), Some(&2));
+ assert_eq!(tester.get(2), None);
+}
+
+#[test]
+fn test_swap() {
+ let mut tester = VecDeque::new();
+ tester.push_back(1);
+ tester.push_back(2);
+ tester.push_back(3);
+
+ assert_eq!(tester, [1, 2, 3]);
+
+ tester.swap(0, 0);
+ assert_eq!(tester, [1, 2, 3]);
+ tester.swap(0, 1);
+ assert_eq!(tester, [2, 1, 3]);
+ tester.swap(2, 1);
+ assert_eq!(tester, [2, 3, 1]);
+ tester.swap(1, 2);
+ assert_eq!(tester, [2, 1, 3]);
+ tester.swap(0, 2);
+ assert_eq!(tester, [3, 1, 2]);
+ tester.swap(2, 2);
+ assert_eq!(tester, [3, 1, 2]);
+}
+
+#[test]
+#[should_panic = "assertion failed: j < self.len()"]
+fn test_swap_panic() {
+ let mut tester = VecDeque::new();
+ tester.push_back(1);
+ tester.push_back(2);
+ tester.push_back(3);
+ tester.swap(2, 3);
+}
+
+#[test]
+fn test_reserve_exact() {
+ let mut tester: VecDeque<i32> = VecDeque::with_capacity(1);
+ assert!(tester.capacity() == 1);
+ tester.reserve_exact(50);
+ assert!(tester.capacity() >= 51);
+ tester.reserve_exact(40);
+ assert!(tester.capacity() >= 51);
+ tester.reserve_exact(200);
+ assert!(tester.capacity() >= 200);
+}
+
+#[test]
+#[should_panic = "capacity overflow"]
+fn test_reserve_exact_panic() {
+ let mut tester: VecDeque<i32> = VecDeque::new();
+ tester.reserve_exact(usize::MAX);
+}
+
+#[test]
+fn test_try_reserve_exact() {
+ let mut tester: VecDeque<i32> = VecDeque::with_capacity(1);
+ assert!(tester.capacity() == 1);
+ assert_eq!(tester.try_reserve_exact(100), Ok(()));
+ assert!(tester.capacity() >= 100);
+ assert_eq!(tester.try_reserve_exact(50), Ok(()));
+ assert!(tester.capacity() >= 100);
+ assert_eq!(tester.try_reserve_exact(200), Ok(()));
+ assert!(tester.capacity() >= 200);
+ assert_eq!(tester.try_reserve_exact(0), Ok(()));
+ assert!(tester.capacity() >= 200);
+ assert!(tester.try_reserve_exact(usize::MAX).is_err());
+}
+
+#[test]
+fn test_try_reserve() {
+ let mut tester: VecDeque<i32> = VecDeque::with_capacity(1);
+ assert!(tester.capacity() == 1);
+ assert_eq!(tester.try_reserve(100), Ok(()));
+ assert!(tester.capacity() >= 100);
+ assert_eq!(tester.try_reserve(50), Ok(()));
+ assert!(tester.capacity() >= 100);
+ assert_eq!(tester.try_reserve(200), Ok(()));
+ assert!(tester.capacity() >= 200);
+ assert_eq!(tester.try_reserve(0), Ok(()));
+ assert!(tester.capacity() >= 200);
+ assert!(tester.try_reserve(usize::MAX).is_err());
+}
+
+#[test]
+fn test_contains() {
+ let mut tester = VecDeque::new();
+ tester.push_back(1);
+ tester.push_back(2);
+ tester.push_back(3);
+
+ assert!(tester.contains(&1));
+ assert!(tester.contains(&3));
+ assert!(!tester.contains(&0));
+ assert!(!tester.contains(&4));
+ tester.remove(0);
+ assert!(!tester.contains(&1));
+ assert!(tester.contains(&2));
+ assert!(tester.contains(&3));
+}
+
+#[test]
+fn test_rotate_left_right() {
+ let mut tester: VecDeque<_> = (1..=10).collect();
+
+ assert_eq!(tester.len(), 10);
+
+ tester.rotate_left(0);
+ assert_eq!(tester, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+
+ tester.rotate_right(0);
+ assert_eq!(tester, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+
+ tester.rotate_left(3);
+ assert_eq!(tester, [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]);
+
+ tester.rotate_right(5);
+ assert_eq!(tester, [9, 10, 1, 2, 3, 4, 5, 6, 7, 8]);
+
+ tester.rotate_left(tester.len());
+ assert_eq!(tester, [9, 10, 1, 2, 3, 4, 5, 6, 7, 8]);
+
+ tester.rotate_right(tester.len());
+ assert_eq!(tester, [9, 10, 1, 2, 3, 4, 5, 6, 7, 8]);
+
+ tester.rotate_left(1);
+ assert_eq!(tester, [10, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+}
+
+#[test]
+#[should_panic = "assertion failed: mid <= self.len()"]
+fn test_rotate_left_panic() {
+ let mut tester: VecDeque<_> = (1..=10).collect();
+ tester.rotate_left(tester.len() + 1);
+}
+
+#[test]
+#[should_panic = "assertion failed: k <= self.len()"]
+fn test_rotate_right_panic() {
+ let mut tester: VecDeque<_> = (1..=10).collect();
+ tester.rotate_right(tester.len() + 1);
+}
+
+#[test]
+fn test_binary_search() {
+ // If the givin VecDeque is not sorted, the returned result is unspecified and meaningless,
+ // as this method performs a binary search.
+
+ let tester: VecDeque<_> = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+
+ assert_eq!(tester.binary_search(&0), Ok(0));
+ assert_eq!(tester.binary_search(&5), Ok(5));
+ assert_eq!(tester.binary_search(&55), Ok(10));
+ assert_eq!(tester.binary_search(&4), Err(5));
+ assert_eq!(tester.binary_search(&-1), Err(0));
+ assert!(matches!(tester.binary_search(&1), Ok(1..=2)));
+
+ let tester: VecDeque<_> = [1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3].into();
+ assert_eq!(tester.binary_search(&1), Ok(0));
+ assert!(matches!(tester.binary_search(&2), Ok(1..=4)));
+ assert!(matches!(tester.binary_search(&3), Ok(5..=13)));
+ assert_eq!(tester.binary_search(&-2), Err(0));
+ assert_eq!(tester.binary_search(&0), Err(0));
+ assert_eq!(tester.binary_search(&4), Err(14));
+ assert_eq!(tester.binary_search(&5), Err(14));
+}
+
+#[test]
+fn test_binary_search_by() {
+ // If the givin VecDeque is not sorted, the returned result is unspecified and meaningless,
+ // as this method performs a binary search.
+
+ let tester: VecDeque<_> = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+
+ assert_eq!(tester.binary_search_by(|x| x.cmp(&0)), Ok(0));
+ assert_eq!(tester.binary_search_by(|x| x.cmp(&5)), Ok(5));
+ assert_eq!(tester.binary_search_by(|x| x.cmp(&55)), Ok(10));
+ assert_eq!(tester.binary_search_by(|x| x.cmp(&4)), Err(5));
+ assert_eq!(tester.binary_search_by(|x| x.cmp(&-1)), Err(0));
+ assert!(matches!(tester.binary_search_by(|x| x.cmp(&1)), Ok(1..=2)));
+}
+
+#[test]
+fn test_binary_search_key() {
+ // If the givin VecDeque is not sorted, the returned result is unspecified and meaningless,
+ // as this method performs a binary search.
+
+ let tester: VecDeque<_> = [
+ (-1, 0),
+ (2, 10),
+ (6, 5),
+ (7, 1),
+ (8, 10),
+ (10, 2),
+ (20, 3),
+ (24, 5),
+ (25, 18),
+ (28, 13),
+ (31, 21),
+ (32, 4),
+ (54, 25),
+ ]
+ .into();
+
+ assert_eq!(tester.binary_search_by_key(&-1, |&(a, _b)| a), Ok(0));
+ assert_eq!(tester.binary_search_by_key(&8, |&(a, _b)| a), Ok(4));
+ assert_eq!(tester.binary_search_by_key(&25, |&(a, _b)| a), Ok(8));
+ assert_eq!(tester.binary_search_by_key(&54, |&(a, _b)| a), Ok(12));
+ assert_eq!(tester.binary_search_by_key(&-2, |&(a, _b)| a), Err(0));
+ assert_eq!(tester.binary_search_by_key(&1, |&(a, _b)| a), Err(1));
+ assert_eq!(tester.binary_search_by_key(&4, |&(a, _b)| a), Err(2));
+ assert_eq!(tester.binary_search_by_key(&13, |&(a, _b)| a), Err(6));
+ assert_eq!(tester.binary_search_by_key(&55, |&(a, _b)| a), Err(13));
+ assert_eq!(tester.binary_search_by_key(&100, |&(a, _b)| a), Err(13));
+
+ let tester: VecDeque<_> = [
+ (0, 0),
+ (2, 1),
+ (6, 1),
+ (5, 1),
+ (3, 1),
+ (1, 2),
+ (2, 3),
+ (4, 5),
+ (5, 8),
+ (8, 13),
+ (1, 21),
+ (2, 34),
+ (4, 55),
+ ]
+ .into();
+
+ assert_eq!(tester.binary_search_by_key(&0, |&(_a, b)| b), Ok(0));
+ assert!(matches!(tester.binary_search_by_key(&1, |&(_a, b)| b), Ok(1..=4)));
+ assert_eq!(tester.binary_search_by_key(&8, |&(_a, b)| b), Ok(8));
+ assert_eq!(tester.binary_search_by_key(&13, |&(_a, b)| b), Ok(9));
+ assert_eq!(tester.binary_search_by_key(&55, |&(_a, b)| b), Ok(12));
+ assert_eq!(tester.binary_search_by_key(&-1, |&(_a, b)| b), Err(0));
+ assert_eq!(tester.binary_search_by_key(&4, |&(_a, b)| b), Err(7));
+ assert_eq!(tester.binary_search_by_key(&56, |&(_a, b)| b), Err(13));
+ assert_eq!(tester.binary_search_by_key(&100, |&(_a, b)| b), Err(13));
+}
+
#[test]
fn make_contiguous_big_tail() {
let mut tester = VecDeque::with_capacity(15);
/// 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()
// implements the unary operator "op &T"
// based on "op T" where T is expected to be `Copy`able
macro_rules! forward_ref_unop {
- (impl $imp:ident, $method:ident for $t:ty) => {
- forward_ref_unop!(impl $imp, $method for $t,
- #[stable(feature = "rust1", since = "1.0.0")]);
- };
(impl const $imp:ident, $method:ident for $t:ty) => {
forward_ref_unop!(impl const $imp, $method for $t,
#[stable(feature = "rust1", since = "1.0.0")]);
// implements binary operators "&T op U", "T op &U", "&T op &U"
// based on "T op U" where T and U are expected to be `Copy`able
macro_rules! forward_ref_binop {
- (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
- forward_ref_binop!(impl $imp, $method for $t, $u,
- #[stable(feature = "rust1", since = "1.0.0")]);
- };
(impl const $imp:ident, $method:ident for $t:ty, $u:ty) => {
forward_ref_binop!(impl const $imp, $method for $t, $u,
#[stable(feature = "rust1", since = "1.0.0")]);
}
};
- // match if/else chains lacking a final `else`
- (
- if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* }
- $(
- else if #[cfg( $e_meta:meta )] { $( $e_tokens:tt )* }
- )*
- ) => {
- cfg_if! {
- @__items () ;
- (( $i_meta ) ( $( $i_tokens )* )) ,
- $(
- (( $e_meta ) ( $( $e_tokens )* )) ,
- )*
- }
- };
-
// Internal and recursive macro to emit all the items
//
// Collects all the previous cfgs in a list at the beginning, so they can be
//! 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
fn into_iter(self) -> Self::IntoIter;
}
+#[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator> IntoIterator for I {
+impl<I: ~const Iterator> const IntoIterator for I {
type Item = I::Item;
type IntoIter = I;
#[inline]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub(crate) const fn abs_private(self) -> f32 {
- f32::from_bits(self.to_bits() & 0x7fff_ffff)
+ // SAFETY: This transmutation is fine. Probably. For the reasons std is using it.
+ unsafe { mem::transmute::<u32, f32>(mem::transmute::<f32, u32>(self) & 0x7fff_ffff) }
}
/// Returns `true` if this value is positive infinity or negative infinity, and
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[inline]
pub const fn is_infinite(self) -> bool {
- self.abs_private() == Self::INFINITY
+ // Getting clever with transmutation can result in incorrect answers on some FPUs
+ // FIXME: alter the Rust <-> Rust calling convention to prevent this problem.
+ // See https://github.com/rust-lang/rust/issues/72327
+ (self == f32::INFINITY) | (self == f32::NEG_INFINITY)
}
/// Returns `true` if this number is neither infinite nor `NaN`.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub const fn classify(self) -> FpCategory {
+ // A previous implementation tried to only use bitmask-based checks,
+ // using f32::to_bits to transmute the float to its bit repr and match on that.
+ // Unfortunately, floating point numbers can be much worse than that.
+ // This also needs to not result in recursive evaluations of f64::to_bits.
+ //
+ // On some processors, in some cases, LLVM will "helpfully" lower floating point ops,
+ // in spite of a request for them using f32 and f64, to things like x87 operations.
+ // These have an f64's mantissa, but can have a larger than normal exponent.
+ // FIXME(jubilee): Using x87 operations is never necessary in order to function
+ // on x86 processors for Rust-to-Rust calls, so this issue should not happen.
+ // Code generation should be adjusted to use non-C calling conventions, avoiding this.
+ //
+ if self.is_infinite() {
+ // Thus, a value may compare unequal to infinity, despite having a "full" exponent mask.
+ FpCategory::Infinite
+ } else if self.is_nan() {
+ // And it may not be NaN, as it can simply be an "overextended" finite value.
+ FpCategory::Nan
+ } else {
+ // However, std can't simply compare to zero to check for zero, either,
+ // as correctness requires avoiding equality tests that may be Subnormal == -0.0
+ // because it may be wrong under "denormals are zero" and "flush to zero" modes.
+ // Most of std's targets don't use those, but they are used for thumbv7neon.
+ // So, this does use bitpattern matching for the rest.
+
+ // SAFETY: f32 to u32 is fine. Usually.
+ // If classify has gotten this far, the value is definitely in one of these categories.
+ unsafe { f32::partial_classify(self) }
+ }
+ }
+
+ // This doesn't actually return a right answer for NaN on purpose,
+ // seeing as how it cannot correctly discern between a floating point NaN,
+ // and some normal floating point numbers truncated from an x87 FPU.
+ // FIXME(jubilee): This probably could at least answer things correctly for Infinity,
+ // like the f64 version does, but I need to run more checks on how things go on x86.
+ // I fear losing mantissa data that would have answered that differently.
+ //
+ // # Safety
+ // This requires making sure you call this function for values it answers correctly on,
+ // otherwise it returns a wrong answer. This is not important for memory safety per se,
+ // but getting floats correct is important for not accidentally leaking const eval
+ // runtime-deviating logic which may or may not be acceptable.
+ #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+ const unsafe fn partial_classify(self) -> FpCategory {
const EXP_MASK: u32 = 0x7f800000;
const MAN_MASK: u32 = 0x007fffff;
- let bits = self.to_bits();
- match (bits & MAN_MASK, bits & EXP_MASK) {
+ // SAFETY: The caller is not asking questions for which this will tell lies.
+ let b = unsafe { mem::transmute::<f32, u32>(self) };
+ match (b & MAN_MASK, b & EXP_MASK) {
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
+ _ => FpCategory::Normal,
+ }
+ }
+
+ // This operates on bits, and only bits, so it can ignore concerns about weird FPUs.
+ // FIXME(jubilee): In a just world, this would be the entire impl for classify,
+ // plus a transmute. We do not live in a just world, but we can make it more so.
+ #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+ const fn classify_bits(b: u32) -> FpCategory {
+ const EXP_MASK: u32 = 0x7f800000;
+ const MAN_MASK: u32 = 0x007fffff;
+
+ match (b & MAN_MASK, b & EXP_MASK) {
(0, EXP_MASK) => FpCategory::Infinite,
(_, EXP_MASK) => FpCategory::Nan,
+ (0, 0) => FpCategory::Zero,
+ (_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
}
}
pub const fn is_sign_negative(self) -> bool {
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
// applies to zeros and NaNs as well.
- self.to_bits() & 0x8000_0000 != 0
+ // SAFETY: This is just transmuting to get the sign bit, it's fine.
+ unsafe { mem::transmute::<f32, u32>(self) & 0x8000_0000 != 0 }
}
/// Takes the reciprocal (inverse) of a number, `1/x`.
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
#[inline]
pub const fn to_bits(self) -> u32 {
- // SAFETY: `u32` is a plain old datatype so we can always transmute to it
- unsafe { mem::transmute(self) }
+ // SAFETY: `u32` is a plain old datatype so we can always transmute to it.
+ // ...sorta.
+ //
+ // It turns out that at runtime, it is possible for a floating point number
+ // to be subject to a floating point mode that alters nonzero subnormal numbers
+ // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
+ // This is not a problem per se, but at least one tier2 platform for Rust
+ // actually exhibits this behavior by default.
+ //
+ // In addition, on x86 targets with SSE or SSE2 disabled and the x87 FPU enabled,
+ // i.e. not soft-float, the way Rust does parameter passing can actually alter
+ // a number that is "not infinity" to have the same exponent as infinity,
+ // in a slightly unpredictable manner.
+ //
+ // And, of course evaluating to a NaN value is fairly nondeterministic.
+ // More precisely: when NaN should be returned is knowable, but which NaN?
+ // So far that's defined by a combination of LLVM and the CPU, not Rust.
+ // This function, however, allows observing the bitstring of a NaN,
+ // thus introspection on CTFE.
+ //
+ // In order to preserve, at least for the moment, const-to-runtime equivalence,
+ // we reject any of these possible situations from happening.
+ #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+ const fn ct_f32_to_u32(ct: f32) -> u32 {
+ match ct.classify() {
+ FpCategory::Nan => {
+ panic!("const-eval error: cannot use f32::to_bits on a NaN")
+ }
+ FpCategory::Subnormal => {
+ panic!("const-eval error: cannot use f32::to_bits on a subnormal number")
+ }
+ FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
+ // SAFETY: We have a normal floating point number. Now we transmute, i.e. do a bitcopy.
+ unsafe { mem::transmute::<f32, u32>(ct) }
+ }
+ }
+ }
+ // SAFETY: `u32` is a plain old datatype so we can always... uh...
+ // ...look, just pretend you forgot what you just read.
+ // Stability concerns.
+ let rt_f32_to_u32 = |rt| unsafe { mem::transmute::<f32, u32>(rt) };
+ // SAFETY: We use internal implementations that either always work or fail at compile time.
+ unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
}
/// Raw transmutation from `u32`.
#[must_use]
#[inline]
pub const fn from_bits(v: u32) -> Self {
- // SAFETY: `u32` is a plain old datatype so we can always transmute from it
// It turns out the safety issues with sNaN were overblown! Hooray!
- unsafe { mem::transmute(v) }
+ // SAFETY: `u32` is a plain old datatype so we can always transmute from it
+ // ...sorta.
+ //
+ // It turns out that at runtime, it is possible for a floating point number
+ // to be subject to floating point modes that alter nonzero subnormal numbers
+ // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
+ // This is not a problem usually, but at least one tier2 platform for Rust
+ // actually exhibits this behavior by default: thumbv7neon
+ // aka "the Neon FPU in AArch32 state"
+ //
+ // In addition, on x86 targets with SSE or SSE2 disabled and the x87 FPU enabled,
+ // i.e. not soft-float, the way Rust does parameter passing can actually alter
+ // a number that is "not infinity" to have the same exponent as infinity,
+ // in a slightly unpredictable manner.
+ //
+ // And, of course evaluating to a NaN value is fairly nondeterministic.
+ // More precisely: when NaN should be returned is knowable, but which NaN?
+ // So far that's defined by a combination of LLVM and the CPU, not Rust.
+ // This function, however, allows observing the bitstring of a NaN,
+ // thus introspection on CTFE.
+ //
+ // In order to preserve, at least for the moment, const-to-runtime equivalence,
+ // reject any of these possible situations from happening.
+ #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+ const fn ct_u32_to_f32(ct: u32) -> f32 {
+ match f32::classify_bits(ct) {
+ FpCategory::Subnormal => {
+ panic!("const-eval error: cannot use f32::from_bits on a subnormal number")
+ }
+ FpCategory::Nan => {
+ panic!("const-eval error: cannot use f32::from_bits on NaN")
+ }
+ FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
+ // SAFETY: It's not a frumious number
+ unsafe { mem::transmute::<u32, f32>(ct) }
+ }
+ }
+ }
+ // SAFETY: `u32` is a plain old datatype so we can always... uh...
+ // ...look, just pretend you forgot what you just read.
+ // Stability concerns.
+ let rt_u32_to_f32 = |rt| unsafe { mem::transmute::<u32, f32>(rt) };
+ // SAFETY: We use internal implementations that either always work or fail at compile time.
+ unsafe { intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) }
}
/// Return the memory representation of this floating point number as a byte array in
#[inline]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub(crate) const fn abs_private(self) -> f64 {
- f64::from_bits(self.to_bits() & 0x7fff_ffff_ffff_ffff)
+ // SAFETY: This transmutation is fine. Probably. For the reasons std is using it.
+ unsafe {
+ mem::transmute::<u64, f64>(mem::transmute::<f64, u64>(self) & 0x7fff_ffff_ffff_ffff)
+ }
}
/// Returns `true` if this value is positive infinity or negative infinity, and
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[inline]
pub const fn is_infinite(self) -> bool {
- self.abs_private() == Self::INFINITY
+ // Getting clever with transmutation can result in incorrect answers on some FPUs
+ // FIXME: alter the Rust <-> Rust calling convention to prevent this problem.
+ // See https://github.com/rust-lang/rust/issues/72327
+ (self == f64::INFINITY) | (self == f64::NEG_INFINITY)
}
/// Returns `true` if this number is neither infinite nor `NaN`.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub const fn classify(self) -> FpCategory {
+ // A previous implementation tried to only use bitmask-based checks,
+ // using f64::to_bits to transmute the float to its bit repr and match on that.
+ // Unfortunately, floating point numbers can be much worse than that.
+ // This also needs to not result in recursive evaluations of f64::to_bits.
+ //
+ // On some processors, in some cases, LLVM will "helpfully" lower floating point ops,
+ // in spite of a request for them using f32 and f64, to things like x87 operations.
+ // These have an f64's mantissa, but can have a larger than normal exponent.
+ // FIXME(jubilee): Using x87 operations is never necessary in order to function
+ // on x86 processors for Rust-to-Rust calls, so this issue should not happen.
+ // Code generation should be adjusted to use non-C calling conventions, avoiding this.
+ //
+ // Thus, a value may compare unequal to infinity, despite having a "full" exponent mask.
+ // And it may not be NaN, as it can simply be an "overextended" finite value.
+ if self.is_nan() {
+ FpCategory::Nan
+ } else {
+ // However, std can't simply compare to zero to check for zero, either,
+ // as correctness requires avoiding equality tests that may be Subnormal == -0.0
+ // because it may be wrong under "denormals are zero" and "flush to zero" modes.
+ // Most of std's targets don't use those, but they are used for thumbv7neon.
+ // So, this does use bitpattern matching for the rest.
+
+ // SAFETY: f64 to u64 is fine. Usually.
+ // If control flow has gotten this far, the value is definitely in one of the categories
+ // that f64::partial_classify can correctly analyze.
+ unsafe { f64::partial_classify(self) }
+ }
+ }
+
+ // This doesn't actually return a right answer for NaN on purpose,
+ // seeing as how it cannot correctly discern between a floating point NaN,
+ // and some normal floating point numbers truncated from an x87 FPU.
+ #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+ const unsafe fn partial_classify(self) -> FpCategory {
const EXP_MASK: u64 = 0x7ff0000000000000;
const MAN_MASK: u64 = 0x000fffffffffffff;
- let bits = self.to_bits();
- match (bits & MAN_MASK, bits & EXP_MASK) {
+ // SAFETY: The caller is not asking questions for which this will tell lies.
+ let b = unsafe { mem::transmute::<f64, u64>(self) };
+ match (b & MAN_MASK, b & EXP_MASK) {
+ (0, EXP_MASK) => FpCategory::Infinite,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
+ _ => FpCategory::Normal,
+ }
+ }
+
+ // This operates on bits, and only bits, so it can ignore concerns about weird FPUs.
+ // FIXME(jubilee): In a just world, this would be the entire impl for classify,
+ // plus a transmute. We do not live in a just world, but we can make it more so.
+ #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+ const fn classify_bits(b: u64) -> FpCategory {
+ const EXP_MASK: u64 = 0x7ff0000000000000;
+ const MAN_MASK: u64 = 0x000fffffffffffff;
+
+ match (b & MAN_MASK, b & EXP_MASK) {
(0, EXP_MASK) => FpCategory::Infinite,
(_, EXP_MASK) => FpCategory::Nan,
+ (0, 0) => FpCategory::Zero,
+ (_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
}
}
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[inline]
pub const fn is_sign_negative(self) -> bool {
- self.to_bits() & 0x8000_0000_0000_0000 != 0
+ // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
+ // applies to zeros and NaNs as well.
+ // SAFETY: This is just transmuting to get the sign bit, it's fine.
+ unsafe { mem::transmute::<f64, u64>(self) & 0x8000_0000_0000_0000 != 0 }
}
#[must_use]
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
#[inline]
pub const fn to_bits(self) -> u64 {
- // SAFETY: `u64` is a plain old datatype so we can always transmute to it
- unsafe { mem::transmute(self) }
+ // SAFETY: `u64` is a plain old datatype so we can always transmute to it.
+ // ...sorta.
+ //
+ // See the SAFETY comment in f64::from_bits for more.
+ #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+ const fn ct_f64_to_u64(ct: f64) -> u64 {
+ match ct.classify() {
+ FpCategory::Nan => {
+ panic!("const-eval error: cannot use f64::to_bits on a NaN")
+ }
+ FpCategory::Subnormal => {
+ panic!("const-eval error: cannot use f64::to_bits on a subnormal number")
+ }
+ FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
+ // SAFETY: We have a normal floating point number. Now we transmute, i.e. do a bitcopy.
+ unsafe { mem::transmute::<f64, u64>(ct) }
+ }
+ }
+ }
+ // SAFETY: `u64` is a plain old datatype so we can always... uh...
+ // ...look, just pretend you forgot what you just read.
+ // Stability concerns.
+ let rt_f64_to_u64 = |rt| unsafe { mem::transmute::<f64, u64>(rt) };
+ // SAFETY: We use internal implementations that either always work or fail at compile time.
+ unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
}
/// Raw transmutation from `u64`.
#[must_use]
#[inline]
pub const fn from_bits(v: u64) -> Self {
- // SAFETY: `u64` is a plain old datatype so we can always transmute from it
// It turns out the safety issues with sNaN were overblown! Hooray!
- unsafe { mem::transmute(v) }
+ // SAFETY: `u64` is a plain old datatype so we can always transmute from it
+ // ...sorta.
+ //
+ // It turns out that at runtime, it is possible for a floating point number
+ // to be subject to floating point modes that alter nonzero subnormal numbers
+ // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
+ // This is not a problem usually, but at least one tier2 platform for Rust
+ // actually exhibits an FTZ behavior by default: thumbv7neon
+ // aka "the Neon FPU in AArch32 state"
+ //
+ // Even with this, not all instructions exhibit the FTZ behaviors on thumbv7neon,
+ // so this should load the same bits if LLVM emits the "correct" instructions,
+ // but LLVM sometimes makes interesting choices about float optimization,
+ // and other FPUs may do similar. Thus, it is wise to indulge luxuriously in caution.
+ //
+ // In addition, on x86 targets with SSE or SSE2 disabled and the x87 FPU enabled,
+ // i.e. not soft-float, the way Rust does parameter passing can actually alter
+ // a number that is "not infinity" to have the same exponent as infinity,
+ // in a slightly unpredictable manner.
+ //
+ // And, of course evaluating to a NaN value is fairly nondeterministic.
+ // More precisely: when NaN should be returned is knowable, but which NaN?
+ // So far that's defined by a combination of LLVM and the CPU, not Rust.
+ // This function, however, allows observing the bitstring of a NaN,
+ // thus introspection on CTFE.
+ //
+ // In order to preserve, at least for the moment, const-to-runtime equivalence,
+ // reject any of these possible situations from happening.
+ #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+ const fn ct_u64_to_f64(ct: u64) -> f64 {
+ match f64::classify_bits(ct) {
+ FpCategory::Subnormal => {
+ panic!("const-eval error: cannot use f64::from_bits on a subnormal number")
+ }
+ FpCategory::Nan => {
+ panic!("const-eval error: cannot use f64::from_bits on NaN")
+ }
+ FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
+ // SAFETY: It's not a frumious number
+ unsafe { mem::transmute::<u64, f64>(ct) }
+ }
+ }
+ }
+ // SAFETY: `u64` is a plain old datatype so we can always... uh...
+ // ...look, just pretend you forgot what you just read.
+ // Stability concerns.
+ let rt_u64_to_f64 = |rt| unsafe { mem::transmute::<u64, f64>(rt) };
+ // SAFETY: We use internal implementations that either always work or fail at compile time.
+ unsafe { intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) }
}
/// Return the memory representation of this floating point number as a byte array in
}
}
+#[stable(feature = "assertunwindsafe_default", since = "1.62.0")]
+impl<T: Default> Default for AssertUnwindSafe<T> {
+ fn default() -> Self {
+ Self(Default::default())
+ }
+}
+
#[stable(feature = "futures_api", since = "1.36.0")]
impl<F: Future> Future for AssertUnwindSafe<F> {
type Output = F::Output;
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")]
/// Returns `true` if the slice contains an element with the given value.
///
+ /// This operation is *O*(*n*).
+ ///
+ /// Note that if you have a sorted slice, [`binary_search`] may be faster.
+ ///
+ /// [`binary_search`]: slice::binary_search
+ ///
/// # Examples
///
/// ```
None
}
- /// Binary searches this sorted slice for a given element.
+ /// Binary searches this slice for a given element.
+ /// This behaves similary to [`contains`] if this slice is sorted.
///
/// If the value is found then [`Result::Ok`] is returned, containing the
/// index of the matching element. If there are multiple matches, then any
///
/// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`].
///
+ /// [`contains`]: slice::contains
/// [`binary_search_by`]: slice::binary_search_by
/// [`binary_search_by_key`]: slice::binary_search_by_key
/// [`partition_point`]: slice::partition_point
self.binary_search_by(|p| p.cmp(x))
}
- /// Binary searches this sorted slice with a comparator function.
+ /// Binary searches this slice with a comparator function.
+ /// This behaves similarly to [`contains`] if this slice is sorted.
///
/// The comparator function should implement an order consistent
/// with the sort order of the underlying slice, returning an
///
/// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`].
///
+ /// [`contains`]: slice::contains
/// [`binary_search`]: slice::binary_search
/// [`binary_search_by_key`]: slice::binary_search_by_key
/// [`partition_point`]: slice::partition_point
Err(left)
}
- /// Binary searches this sorted slice with a key extraction function.
+ /// Binary searches this slice with a key extraction function.
+ /// This behaves similarly to [`contains`] if this slice is sorted.
///
/// Assumes that the slice is sorted by the key, for instance with
/// [`sort_by_key`] using the same key extraction function.
///
/// See also [`binary_search`], [`binary_search_by`], and [`partition_point`].
///
+ /// [`contains`]: slice::contains
/// [`sort_by_key`]: slice::sort_by_key
/// [`binary_search`]: slice::binary_search
/// [`binary_search_by`]: slice::binary_search_by
#![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)]
}
macro_rules! test_op {
- ($fn_name:ident, $op:ident::$method:ident($lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {
- #[test]
- fn $fn_name() {
- impls_defined!($op, $method($lhs, $rhs), $result, $($t),+);
- }
- };
- ($fn_name:ident, $op:ident::$method:ident(&mut $lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {
- #[test]
- fn $fn_name() {
- impls_defined!($op, $method(&mut $lhs, $rhs), $result, $($t),+);
- }
- };
($fn_name:ident, $op:ident::$method:ident($lhs:literal), $result:literal, $($t:ty),+) => {
#[test]
fn $fn_name() {
}
}
+#[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" }
({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) };
(,) => { Punct::new(',', Spacing::Alone) };
(.) => { Punct::new('.', Spacing::Alone) };
- (:) => { Punct::new(':', Spacing::Alone) };
(;) => { Punct::new(';', Spacing::Alone) };
(!) => { Punct::new('!', Spacing::Alone) };
(<) => { Punct::new('<', Spacing::Alone) };
#![feature(exhaustive_patterns)]
#![feature(intra_doc_pointers)]
#![feature(lang_items)]
+#![feature(let_chains)]
#![feature(linkage)]
#![feature(min_specialization)]
#![feature(must_not_suspend)]
/// 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",
+ }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
fn uid(
&mut self,
- #[cfg(not(target_os = "vxworks"))] id: u32,
- #[cfg(target_os = "vxworks")] id: u16,
+ #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
+ #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
) -> &mut process::Command;
/// Similar to `uid`, but sets the group ID of the child process. This has
#[stable(feature = "rust1", since = "1.0.0")]
fn gid(
&mut self,
- #[cfg(not(target_os = "vxworks"))] id: u32,
- #[cfg(target_os = "vxworks")] id: u16,
+ #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
+ #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
) -> &mut process::Command;
/// Sets the supplementary group IDs for the calling process. Translates to
#[unstable(feature = "setgroups", issue = "90747")]
fn groups(
&mut self,
- #[cfg(not(target_os = "vxworks"))] groups: &[u32],
- #[cfg(target_os = "vxworks")] groups: &[u16],
+ #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] groups: &[u32],
+ #[cfg(any(target_os = "vxworks", target_os = "espidf"))] groups: &[u16],
) -> &mut process::Command;
/// Schedules a closure to be run just before the `exec` function is
impl CommandExt for process::Command {
fn uid(
&mut self,
- #[cfg(not(target_os = "vxworks"))] id: u32,
- #[cfg(target_os = "vxworks")] id: u16,
+ #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
+ #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
) -> &mut process::Command {
self.as_inner_mut().uid(id);
self
fn gid(
&mut self,
- #[cfg(not(target_os = "vxworks"))] id: u32,
- #[cfg(target_os = "vxworks")] id: u16,
+ #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
+ #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
) -> &mut process::Command {
self.as_inner_mut().gid(id);
self
fn groups(
&mut self,
- #[cfg(not(target_os = "vxworks"))] groups: &[u32],
- #[cfg(target_os = "vxworks")] groups: &[u16],
+ #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] groups: &[u32],
+ #[cfg(any(target_os = "vxworks", target_os = "espidf"))] groups: &[u16],
) -> &mut process::Command {
self.as_inner_mut().groups(groups);
self
/// Device namespace prefix, e.g., `\\.\COM42`.
///
- /// Device namespace prefixes consist of `\\.\` immediately followed by the
- /// device name.
+ /// Device namespace prefixes consist of `\\.\` (possibly using `/`
+ /// instead of `\`), immediately followed by the device name.
#[stable(feature = "rust1", since = "1.0.0")]
DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr),
fn len(&self) -> usize {
use self::Prefix::*;
fn os_str_len(s: &OsStr) -> usize {
- os_str_as_u8_slice(s).len()
+ s.bytes().len()
}
match *self {
Verbatim(x) => 4 + os_str_len(x),
}
}
-// See note at the top of this module to understand why these are used:
-//
-// These casts are safe as OsStr is internally a wrapper around [u8] on all
-// platforms.
-//
-// Note that currently this relies on the special knowledge that libstd has;
-// these types are single-element structs but are not marked repr(transparent)
-// or repr(C) which would make these casts allowable outside std.
-fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
- unsafe { &*(s as *const OsStr as *const [u8]) }
-}
unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
- // SAFETY: see the comment of `os_str_as_u8_slice`
+ // SAFETY: See note at the top of this module to understand why this and
+ // `OsStr::bytes` are used:
+ //
+ // This casts are safe as OsStr is internally a wrapper around [u8] on all
+ // platforms.
+ //
+ // Note that currently this relies on the special knowledge that libstd has;
+ // these types are single-element structs but are not marked
+ // repr(transparent) or repr(C) which would make these casts not allowable
+ // outside std.
unsafe { &*(s as *const [u8] as *const OsStr) }
}
// basic workhorse for splitting stem and extension
fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
- if os_str_as_u8_slice(file) == b".." {
+ if file.bytes() == b".." {
return (Some(file), None);
}
// and back. This is safe to do because (1) we only look at ASCII
// contents of the encoding and (2) new &OsStr values are produced
// only from ASCII-bounded slices of existing &OsStr values.
- let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.');
+ let mut iter = file.bytes().rsplitn(2, |b| *b == b'.');
let after = iter.next();
let before = iter.next();
if before == Some(b"") {
}
fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) {
- let slice = os_str_as_u8_slice(file);
+ let slice = file.bytes();
if slice == b".." {
return (file, None);
}
fn _set_extension(&mut self, extension: &OsStr) -> bool {
let file_stem = match self.file_stem() {
None => return false,
- Some(f) => os_str_as_u8_slice(f),
+ Some(f) => f.bytes(),
};
// truncate until right after the file stem
let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr();
- let start = os_str_as_u8_slice(&self.inner).as_ptr().addr();
+ let start = self.inner.bytes().as_ptr().addr();
let v = self.as_mut_vec();
v.truncate(end_file_stem.wrapping_sub(start));
// add the new extension, if any
- let new = os_str_as_u8_slice(extension);
+ let new = extension.bytes();
if !new.is_empty() {
v.reserve_exact(new.len() + 1);
v.push(b'.');
}
// The following (private!) function reveals the byte encoding used for OsStr.
fn as_u8_slice(&self) -> &[u8] {
- os_str_as_u8_slice(&self.inner)
+ self.inner.bytes()
}
/// Directly wraps a string slice as a `Path` slice.
file_prefix: None
);
- t!("\\\\?\\C:/foo",
- iter: ["\\\\?\\C:/foo"],
+ t!("\\\\?\\C:/foo/bar",
+ iter: ["\\\\?\\C:", "\\", "foo/bar"],
has_root: true,
is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
+ parent: Some("\\\\?\\C:/"),
+ file_name: Some("foo/bar"),
+ file_stem: Some("foo/bar"),
extension: None,
- file_prefix: None
+ file_prefix: Some("foo/bar")
);
t!("\\\\.\\foo\\bar",
assert!(output.status.success());
assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "Hello, fellow Rustaceans!");
}
+
+// See issue #95178
+#[test]
+#[cfg(windows)]
+fn run_canonical_bat_script() {
+ let tempdir = crate::sys_common::io::test::tmpdir();
+ let script_path = tempdir.join("hello.cmd");
+
+ crate::fs::write(&script_path, "@echo Hello, %~1!").unwrap();
+
+ // Try using a canonical path
+ let output = Command::new(&script_path.canonicalize().unwrap())
+ .arg("fellow Rustaceans")
+ .stdout(crate::process::Stdio::piped())
+ .spawn()
+ .unwrap()
+ .wait_with_output()
+ .unwrap();
+ assert!(output.status.success());
+ assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "Hello, fellow Rustaceans!");
+}
use libc::{c_int, c_void};
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "emscripten",
+ target_os = "l4re"
+))]
+use libc::off64_t;
+#[cfg(not(any(
+ target_os = "linux",
+ target_os = "emscripten",
+ target_os = "l4re",
+ target_os = "android"
+)))]
+use libc::off_t as off64_t;
+
#[derive(Debug)]
pub struct FileDesc(OwnedFd);
self.as_raw_fd(),
buf.as_mut_ptr() as *mut c_void,
cmp::min(buf.len(), READ_LIMIT),
- offset as i64,
+ offset as off64_t,
))
.map(|n| n as usize)
}
self.as_raw_fd(),
buf.as_ptr() as *const c_void,
cmp::min(buf.len(), READ_LIMIT),
- offset as i64,
+ offset as off64_t,
))
.map(|n| n as usize)
}
SeekFrom::End(off) => (libc::SEEK_END, off),
SeekFrom::Current(off) => (libc::SEEK_CUR, off),
};
- let n = cvt(unsafe { lseek64(self.as_raw_fd(), pos, whence) })?;
+ let n = cvt(unsafe { lseek64(self.as_raw_fd(), pos as off64_t, whence) })?;
Ok(n as u64)
}
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) };
+}
if #[cfg(any(
target_os = "linux",
target_os = "android",
+ all(target_os = "emscripten", target_feature = "atomics"),
))] {
mod futex;
mod futex_rwlock;
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)>,
}
// Android with api less than 21 define sig* functions inline, so it is not
// available for dynamic link. Implementing sigemptyset and sigaddset allow us
// to support older Android version (independent of libc version).
-// The following implementations are based on https://git.io/vSkNf
+// The following implementations are based on
+// https://github.com/aosp-mirror/platform_bionic/blob/ad8dcd6023294b646e5a8288c0ed431b0845da49/libc/include/android/legacy_signal_inlines.h
cfg_if::cfg_if! {
if #[cfg(target_os = "android")] {
pub unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
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")))]
+++ /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::mem;
-use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-
-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
- }
-}
+++ /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;
use crate::ffi::OsString;
use crate::fmt;
+use crate::io;
use crate::marker::PhantomData;
use crate::num::NonZeroU16;
use crate::os::windows::prelude::*;
use crate::path::PathBuf;
use crate::ptr::NonNull;
use crate::sys::c;
+use crate::sys::process::ensure_no_nuls;
use crate::sys::windows::os::current_exe;
use crate::vec;
}
}
}
+
+#[derive(Debug)]
+pub(crate) enum Arg {
+ /// Add quotes (if needed)
+ Regular(OsString),
+ /// Append raw string without quoting
+ Raw(OsString),
+}
+
+enum Quote {
+ // Every arg is quoted
+ Always,
+ // Whitespace and empty args are quoted
+ Auto,
+ // Arg appended without any changes (#29494)
+ Never,
+}
+
+pub(crate) fn append_arg(cmd: &mut Vec<u16>, arg: &Arg, force_quotes: bool) -> io::Result<()> {
+ let (arg, quote) = match arg {
+ Arg::Regular(arg) => (arg, if force_quotes { Quote::Always } else { Quote::Auto }),
+ Arg::Raw(arg) => (arg, Quote::Never),
+ };
+
+ // If an argument has 0 characters then we need to quote it to ensure
+ // that it actually gets passed through on the command line or otherwise
+ // it will be dropped entirely when parsed on the other end.
+ ensure_no_nuls(arg)?;
+ let arg_bytes = arg.bytes();
+ let (quote, escape) = match quote {
+ Quote::Always => (true, true),
+ Quote::Auto => {
+ (arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t') || arg_bytes.is_empty(), true)
+ }
+ Quote::Never => (false, false),
+ };
+ if quote {
+ cmd.push('"' as u16);
+ }
+
+ let mut backslashes: usize = 0;
+ for x in arg.encode_wide() {
+ if escape {
+ if x == '\\' as u16 {
+ backslashes += 1;
+ } else {
+ if x == '"' as u16 {
+ // Add n+1 backslashes to total 2n+1 before internal '"'.
+ cmd.extend((0..=backslashes).map(|_| '\\' as u16));
+ }
+ backslashes = 0;
+ }
+ }
+ cmd.push(x);
+ }
+
+ if quote {
+ // Add n backslashes to total 2n before ending '"'.
+ cmd.extend((0..backslashes).map(|_| '\\' as u16));
+ cmd.push('"' as u16);
+ }
+ Ok(())
+}
+
+pub(crate) fn make_bat_command_line(
+ script: &[u16],
+ args: &[Arg],
+ force_quotes: bool,
+) -> io::Result<Vec<u16>> {
+ // Set the start of the command line to `cmd.exe /c "`
+ // It is necessary to surround the command in an extra pair of quotes,
+ // hence the trailing quote here. It will be closed after all arguments
+ // have been added.
+ let mut cmd: Vec<u16> = "cmd.exe /c \"".encode_utf16().collect();
+
+ // Push the script name surrounded by its quote pair.
+ cmd.push(b'"' as u16);
+ // Windows file names cannot contain a `"` character or end with `\\`.
+ // If the script name does then return an error.
+ if script.contains(&(b'"' as u16)) || script.last() == Some(&(b'\\' as u16)) {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "Windows file names may not contain `\"` or end with `\\`"
+ ));
+ }
+ cmd.extend_from_slice(script.strip_suffix(&[0]).unwrap_or(script));
+ cmd.push(b'"' as u16);
+
+ // Append the arguments.
+ // FIXME: This needs tests to ensure that the arguments are properly
+ // reconstructed by the batch script by default.
+ for arg in args {
+ cmd.push(' ' as u16);
+ append_arg(&mut cmd, arg, force_quotes)?;
+ }
+
+ // Close the quote we left opened earlier.
+ cmd.push(b'"' as u16);
+
+ Ok(cmd)
+}
+
+/// Takes a path and tries to return a non-verbatim path.
+///
+/// This is necessary because cmd.exe does not support verbatim paths.
+pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
+ use crate::ptr;
+ use crate::sys::windows::fill_utf16_buf;
+
+ // UTF-16 encoded code points, used in parsing and building UTF-16 paths.
+ // All of these are in the ASCII range so they can be cast directly to `u16`.
+ const SEP: u16 = b'\\' as _;
+ const QUERY: u16 = b'?' as _;
+ const COLON: u16 = b':' as _;
+ const U: u16 = b'U' as _;
+ const N: u16 = b'N' as _;
+ const C: u16 = b'C' as _;
+
+ // Early return if the path is too long to remove the verbatim prefix.
+ const LEGACY_MAX_PATH: usize = 260;
+ if path.len() > LEGACY_MAX_PATH {
+ return Ok(path);
+ }
+
+ match &path[..] {
+ // `\\?\C:\...` => `C:\...`
+ [SEP, SEP, QUERY, SEP, _, COLON, SEP, ..] => unsafe {
+ let lpfilename = path[4..].as_ptr();
+ fill_utf16_buf(
+ |buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()),
+ |full_path: &[u16]| {
+ if full_path == &path[4..path.len() - 1] { full_path.into() } else { path }
+ },
+ )
+ },
+ // `\\?\UNC\...` => `\\...`
+ [SEP, SEP, QUERY, SEP, U, N, C, SEP, ..] => unsafe {
+ // Change the `C` in `UNC\` to `\` so we can get a slice that starts with `\\`.
+ path[6] = b'\\' as u16;
+ let lpfilename = path[6..].as_ptr();
+ fill_utf16_buf(
+ |buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()),
+ |full_path: &[u16]| {
+ if full_path == &path[6..path.len() - 1] {
+ full_path.into()
+ } else {
+ // Restore the 'C' in "UNC".
+ path[6] = b'C' as u16;
+ path
+ }
+ },
+ )
+ },
+ // For everything else, leave the path unchanged.
+ _ => Ok(path),
+ }
+}
pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
- let mut maybe_result: Vec<u16> = s.encode_wide().collect();
+ // Most paths are ASCII, so reserve capacity for as much as there are bytes
+ // in the OsStr plus one for the null-terminating character. We are not
+ // wasting bytes here as paths created by this function are primarily used
+ // in an ephemeral fashion.
+ let mut maybe_result = Vec::with_capacity(s.len() + 1);
+ maybe_result.extend(s.encode_wide());
+
if unrolled_find_u16s(0, &maybe_result).is_some() {
return Err(crate::io::const_io_error!(
ErrorKind::InvalidInput,
{
// Start off with a stack buf but then spill over to the heap if we end up
// needing more space.
+ //
+ // This initial size also works around `GetFullPathNameW` returning
+ // incorrect size hints for some short paths:
+ // https://github.com/dylni/normpath/issues/5
let mut stack_buf = [0u16; 512];
let mut heap_buf = Vec::new();
unsafe {
path.into()
}
+struct PrefixParser<'a, const LEN: usize> {
+ path: &'a OsStr,
+ prefix: [u8; LEN],
+}
+
+impl<'a, const LEN: usize> PrefixParser<'a, LEN> {
+ #[inline]
+ fn get_prefix(path: &OsStr) -> [u8; LEN] {
+ let mut prefix = [0; LEN];
+ // SAFETY: Only ASCII characters are modified.
+ for (i, &ch) in path.bytes().iter().take(LEN).enumerate() {
+ prefix[i] = if ch == b'/' { b'\\' } else { ch };
+ }
+ prefix
+ }
+
+ fn new(path: &'a OsStr) -> Self {
+ Self { path, prefix: Self::get_prefix(path) }
+ }
+
+ fn as_slice(&self) -> PrefixParserSlice<'a, '_> {
+ PrefixParserSlice {
+ path: self.path,
+ prefix: &self.prefix[..LEN.min(self.path.len())],
+ index: 0,
+ }
+ }
+}
+
+struct PrefixParserSlice<'a, 'b> {
+ path: &'a OsStr,
+ prefix: &'b [u8],
+ index: usize,
+}
+
+impl<'a> PrefixParserSlice<'a, '_> {
+ fn strip_prefix(&self, prefix: &str) -> Option<Self> {
+ self.prefix[self.index..]
+ .starts_with(prefix.as_bytes())
+ .then(|| Self { index: self.index + prefix.len(), ..*self })
+ }
+
+ fn prefix_bytes(&self) -> &'a [u8] {
+ &self.path.bytes()[..self.index]
+ }
+
+ fn finish(self) -> &'a OsStr {
+ // SAFETY: The unsafety here stems from converting between &OsStr and
+ // &[u8] and back. This is safe to do because (1) we only look at ASCII
+ // contents of the encoding and (2) new &OsStr values are produced only
+ // from ASCII-bounded slices of existing &OsStr values.
+ unsafe { bytes_as_os_str(&self.path.bytes()[self.index..]) }
+ }
+}
+
pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> {
use Prefix::{DeviceNS, Disk, Verbatim, VerbatimDisk, VerbatimUNC, UNC};
- if let Some(path) = strip_prefix(path, r"\\") {
+ let parser = PrefixParser::<8>::new(path);
+ let parser = parser.as_slice();
+ if let Some(parser) = parser.strip_prefix(r"\\") {
// \\
- if let Some(path) = strip_prefix(path, r"?\") {
+
+ // The meaning of verbatim paths can change when they use a different
+ // separator.
+ if let Some(parser) = parser.strip_prefix(r"?\") && !parser.prefix_bytes().iter().any(|&x| x == b'/') {
// \\?\
- if let Some(path) = strip_prefix(path, r"UNC\") {
+ if let Some(parser) = parser.strip_prefix(r"UNC\") {
// \\?\UNC\server\share
+ let path = parser.finish();
let (server, path) = parse_next_component(path, true);
let (share, _) = parse_next_component(path, true);
Some(VerbatimUNC(server, share))
} else {
- let (prefix, _) = parse_next_component(path, true);
+ let path = parser.finish();
// in verbatim paths only recognize an exact drive prefix
- if let Some(drive) = parse_drive_exact(prefix) {
+ if let Some(drive) = parse_drive_exact(path) {
// \\?\C:
Some(VerbatimDisk(drive))
} else {
// \\?\prefix
+ let (prefix, _) = parse_next_component(path, true);
Some(Verbatim(prefix))
}
}
- } else if let Some(path) = strip_prefix(path, r".\") {
+ } else if let Some(parser) = parser.strip_prefix(r".\") {
// \\.\COM42
+ let path = parser.finish();
let (prefix, _) = parse_next_component(path, false);
Some(DeviceNS(prefix))
} else {
+ let path = parser.finish();
let (server, path) = parse_next_component(path, false);
let (share, _) = parse_next_component(path, false);
}
// Parses a drive prefix, e.g. "C:" and "C:\whatever"
-fn parse_drive(prefix: &OsStr) -> Option<u8> {
+fn parse_drive(path: &OsStr) -> Option<u8> {
// In most DOS systems, it is not possible to have more than 26 drive letters.
// See <https://en.wikipedia.org/wiki/Drive_letter_assignment#Common_assignments>.
fn is_valid_drive_letter(drive: &u8) -> bool {
drive.is_ascii_alphabetic()
}
- match prefix.bytes() {
+ match path.bytes() {
[drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()),
_ => None,
}
}
// Parses a drive prefix exactly, e.g. "C:"
-fn parse_drive_exact(prefix: &OsStr) -> Option<u8> {
+fn parse_drive_exact(path: &OsStr) -> Option<u8> {
// only parse two bytes: the drive letter and the drive separator
- if prefix.len() == 2 { parse_drive(prefix) } else { None }
-}
-
-fn strip_prefix<'a>(path: &'a OsStr, prefix: &str) -> Option<&'a OsStr> {
- // `path` and `prefix` are valid wtf8 and utf8 encoded slices respectively, `path[prefix.len()]`
- // is thus a code point boundary and `path[prefix.len()..]` is a valid wtf8 encoded slice.
- match path.bytes().strip_prefix(prefix.as_bytes()) {
- Some(path) => unsafe { Some(bytes_as_os_str(path)) },
- None => None,
+ if path.bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) {
+ parse_drive(path)
+ } else {
+ None
}
}
// SAFETY: `fill_utf16_buf` ensures the `buffer` and `size` are valid.
// `lpfilename` is a pointer to a null terminated string that is not
// invalidated until after `GetFullPathNameW` returns successfully.
- |buffer, size| unsafe {
- // While the docs for `GetFullPathNameW` have the standard note
- // about needing a `\\?\` path for a long lpfilename, this does not
- // appear to be true in practice.
- // See:
- // https://stackoverflow.com/questions/38036943/getfullpathnamew-and-long-windows-file-paths
- // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
- c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut())
- },
+ |buffer, size| unsafe { c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()) },
|mut absolute| {
path.clear();
/// Make a Windows path absolute.
pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
- if path.as_os_str().bytes().starts_with(br"\\?\") {
- return Ok(path.into());
+ let path = path.as_os_str();
+ let prefix = parse_prefix(path);
+ // Verbatim paths should not be modified.
+ if prefix.map(|x| x.is_verbatim()).unwrap_or(false) {
+ // NULs in verbatim paths are rejected for consistency.
+ if path.bytes().contains(&0) {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "strings passed to WinAPI cannot contain NULs",
+ ));
+ }
+ return Ok(path.to_owned().into());
}
+
let path = to_u16s(path)?;
let lpfilename = path.as_ptr();
fill_utf16_buf(
// A path that contains null is not a valid path.
assert!(maybe_verbatim(Path::new("\0")).is_err());
}
+
+fn parse_prefix(path: &str) -> Option<Prefix<'_>> {
+ super::parse_prefix(OsStr::new(path))
+}
+
+#[test]
+fn test_parse_prefix_verbatim() {
+ let prefix = Some(Prefix::VerbatimDisk(b'C'));
+ assert_eq!(prefix, parse_prefix(r"\\?\C:/windows/system32/notepad.exe"));
+ assert_eq!(prefix, parse_prefix(r"\\?\C:\windows\system32\notepad.exe"));
+}
+
+#[test]
+fn test_parse_prefix_verbatim_device() {
+ let prefix = Some(Prefix::UNC(OsStr::new("?"), OsStr::new("C:")));
+ assert_eq!(prefix, parse_prefix(r"//?/C:/windows/system32/notepad.exe"));
+ assert_eq!(prefix, parse_prefix(r"//?/C:\windows\system32\notepad.exe"));
+ assert_eq!(prefix, parse_prefix(r"/\?\C:\windows\system32\notepad.exe"));
+ assert_eq!(prefix, parse_prefix(r"\\?/C:\windows\system32\notepad.exe"));
+}
use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle};
use crate::path::{Path, PathBuf};
use crate::ptr;
+use crate::sys::args::{self, Arg};
use crate::sys::c;
use crate::sys::c::NonZeroDWORD;
use crate::sys::cvt;
use crate::sys::stdio;
use crate::sys_common::mutex::StaticMutex;
use crate::sys_common::process::{CommandEnv, CommandEnvs};
-use crate::sys_common::{AsInner, IntoInner};
+use crate::sys_common::IntoInner;
use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
}
}
-fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
+pub(crate) fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
if str.as_ref().encode_wide().any(|b| b == 0) {
Err(io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data"))
} else {
pub stderr: Option<AnonPipe>,
}
-#[derive(Debug)]
-enum Arg {
- /// Add quotes (if needed)
- Regular(OsString),
- /// Append raw string without quoting
- Raw(OsString),
-}
-
impl Command {
pub fn new(program: &OsStr) -> Command {
Command {
program.len().checked_sub(5).and_then(|i| program.get(i..)),
Some([46, 98 | 66, 97 | 65, 116 | 84, 0] | [46, 99 | 67, 109 | 77, 100 | 68, 0])
);
- let mut cmd_str =
- make_command_line(&program, &self.args, self.force_quotes_enabled, is_batch_file)?;
+ let (program, mut cmd_str) = if is_batch_file {
+ (
+ command_prompt()?,
+ args::make_bat_command_line(
+ &args::to_user_path(program)?,
+ &self.args,
+ self.force_quotes_enabled,
+ )?,
+ )
+ } else {
+ let cmd_str = make_command_line(&self.program, &self.args, self.force_quotes_enabled)?;
+ (program, cmd_str)
+ };
cmd_str.push(0); // add null terminator
// stolen from the libuv code.
}
}
-enum Quote {
- // Every arg is quoted
- Always,
- // Whitespace and empty args are quoted
- Auto,
- // Arg appended without any changes (#29494)
- Never,
-}
-
// Produces a wide string *without terminating null*; returns an error if
// `prog` or any of the `args` contain a nul.
-fn make_command_line(
- prog: &[u16],
- args: &[Arg],
- force_quotes: bool,
- is_batch_file: bool,
-) -> io::Result<Vec<u16>> {
+fn make_command_line(argv0: &OsStr, args: &[Arg], force_quotes: bool) -> io::Result<Vec<u16>> {
// Encode the command and arguments in a command line string such
// that the spawned process may recover them using CommandLineToArgvW.
let mut cmd: Vec<u16> = Vec::new();
- // CreateFileW has special handling for .bat and .cmd files, which means we
- // need to add an extra pair of quotes surrounding the whole command line
- // so they are properly passed on to the script.
- // See issue #91991.
- if is_batch_file {
- cmd.push(b'"' as u16);
- }
-
// Always quote the program name so CreateProcess to avoid ambiguity when
// the child process parses its arguments.
// Note that quotes aren't escaped here because they can't be used in arg0.
// But that's ok because file paths can't contain quotes.
cmd.push(b'"' as u16);
- cmd.extend_from_slice(prog.strip_suffix(&[0]).unwrap_or(prog));
+ cmd.extend(argv0.encode_wide());
cmd.push(b'"' as u16);
for arg in args {
cmd.push(' ' as u16);
- let (arg, quote) = match arg {
- Arg::Regular(arg) => (arg, if force_quotes { Quote::Always } else { Quote::Auto }),
- Arg::Raw(arg) => (arg, Quote::Never),
- };
- append_arg(&mut cmd, arg, quote)?;
- }
- if is_batch_file {
- cmd.push(b'"' as u16);
- }
- return Ok(cmd);
-
- fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, quote: Quote) -> io::Result<()> {
- // If an argument has 0 characters then we need to quote it to ensure
- // that it actually gets passed through on the command line or otherwise
- // it will be dropped entirely when parsed on the other end.
- ensure_no_nuls(arg)?;
- let arg_bytes = &arg.as_inner().inner.as_inner();
- let (quote, escape) = match quote {
- Quote::Always => (true, true),
- Quote::Auto => {
- (arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t') || arg_bytes.is_empty(), true)
- }
- Quote::Never => (false, false),
- };
- if quote {
- cmd.push('"' as u16);
- }
-
- let mut backslashes: usize = 0;
- for x in arg.encode_wide() {
- if escape {
- if x == '\\' as u16 {
- backslashes += 1;
- } else {
- if x == '"' as u16 {
- // Add n+1 backslashes to total 2n+1 before internal '"'.
- cmd.extend((0..=backslashes).map(|_| '\\' as u16));
- }
- backslashes = 0;
- }
- }
- cmd.push(x);
- }
-
- if quote {
- // Add n backslashes to total 2n before ending '"'.
- cmd.extend((0..backslashes).map(|_| '\\' as u16));
- cmd.push('"' as u16);
- }
- Ok(())
+ args::append_arg(&mut cmd, arg, force_quotes)?;
}
+ Ok(cmd)
+}
+
+// Get `cmd.exe` for use with bat scripts, encoded as a UTF-16 string.
+fn command_prompt() -> io::Result<Vec<u16>> {
+ let mut system: Vec<u16> = super::fill_utf16_buf(
+ |buf, size| unsafe { c::GetSystemDirectoryW(buf, size) },
+ |buf| buf.into(),
+ )?;
+ system.extend("\\cmd.exe".encode_utf16().chain([0]));
+ Ok(system)
}
fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>) -> io::Result<(*mut c_void, Vec<u16>)> {
use crate::env;
use crate::ffi::{OsStr, OsString};
use crate::process::Command;
-use crate::sys::to_u16s;
#[test]
fn test_raw_args() {
let command_line = &make_command_line(
- &to_u16s("quoted exe").unwrap(),
+ OsStr::new("quoted exe"),
&[
Arg::Regular(OsString::from("quote me")),
Arg::Raw(OsString::from("quote me *not*")),
Arg::Regular(OsString::from("optional-quotes")),
],
false,
- false,
)
.unwrap();
assert_eq!(
fn test_make_command_line() {
fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
let command_line = &make_command_line(
- &to_u16s(prog).unwrap(),
+ OsStr::new(prog),
&args.iter().map(|a| Arg::Regular(OsString::from(a))).collect::<Vec<_>>(),
force_quotes,
- false,
)
.unwrap();
String::from_utf16(command_line).unwrap()
let mut cmd = Command::new(rustdoc);
- // I am not actually sure why it's necessary to pass the sysroot for `--test`,
- // but `test --doc --stage 0` is broken without it :(
+ // cfg(bootstrap)
+ // NOTE: the `--test` special-casing can be removed when https://github.com/rust-lang/cargo/pull/10594 lands on beta.
if target.is_some() || args.iter().any(|x| x == "--test") {
// The stage0 compiler has a special sysroot distinct from what we
// actually downloaded, so we just always pass the `--sysroot` option,
}
}
- // Needed to be able to run all rustdoc tests.
- if let Some(ref x) = env::var_os("RUSTDOC_RESOURCE_SUFFIX") {
- // This "unstable-options" can be removed when `--resource-suffix` is stabilized
- cmd.arg("-Z").arg("unstable-options");
- cmd.arg("--resource-suffix").arg(x);
- }
-
if verbose > 1 {
eprintln!(
"rustdoc command: {:?}={:?} {:?}",
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::any::Any;
+use std::any::{type_name, Any};
use std::cell::{Cell, RefCell};
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());
}
}
paths
.iter()
.map(|p| {
- 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
- );
+ // 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(),
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() {
};
if self.config.print_step_timings && !self.config.dry_run {
- println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), dur.subsec_millis());
+ let step_string = format!("{:?}", step);
+ let brace_index = step_string.find("{").unwrap_or(0);
+ let type_string = type_name::<S>();
+ println!(
+ "[TIMING] {} {} -- {}.{:03}",
+ &type_string.strip_prefix("bootstrap::").unwrap_or(type_string),
+ &step_string[brace_index..],
+ dur.as_secs(),
+ dur.subsec_millis()
+ );
}
{
// don't save toolstates
config.save_toolstates = None;
config.dry_run = true;
+ config.submodules = Some(false);
config.ninja_in_file = false;
// try to avoid spurious failures in dist where we create/delete each others file
// HACK: rather than pull in `tempdir`, use the one that cargo has conveniently created for us
v.into_iter().map(|(a, _)| a).collect::<Vec<_>>()
}
+fn run_build(paths: &[PathBuf], config: Config) -> Cache {
+ let kind = config.cmd.kind();
+ let build = Build::new(config);
+ let builder = Builder::new(&build);
+ builder.run_step_descriptions(&Builder::get_step_descriptions(kind), paths);
+ builder.cache
+}
+
+#[test]
+fn test_exclude() {
+ let mut config = configure("test", &["A"], &["A"]);
+ config.exclude = vec![TaskPath::parse("src/tools/tidy")];
+ let cache = run_build(&[], config);
+
+ // Ensure we have really excluded tidy
+ assert!(!cache.contains::<test::Tidy>());
+
+ // Ensure other tests are not affected.
+ assert!(cache.contains::<test::RustdocUi>());
+}
+
+#[test]
+fn test_exclude_kind() {
+ let path = PathBuf::from("src/tools/cargotest");
+ let exclude = TaskPath::parse("test::src/tools/cargotest");
+ assert_eq!(exclude, TaskPath { kind: Some(Kind::Test), path: path.clone() });
+
+ let mut config = configure("test", &["A"], &["A"]);
+ // Ensure our test is valid, and `test::Cargotest` would be run without the exclude.
+ assert!(run_build(&[path.clone()], config.clone()).contains::<test::Cargotest>());
+ // Ensure tests for cargotest are skipped.
+ config.exclude = vec![exclude.clone()];
+ assert!(!run_build(&[path.clone()], config).contains::<test::Cargotest>());
+
+ // Ensure builds for cargotest are not skipped.
+ let mut config = configure("build", &["A"], &["A"]);
+ config.exclude = vec![exclude];
+ assert!(run_build(&[path], config).contains::<tool::CargoTest>());
+}
+
mod defaults {
- use super::{configure, first};
+ use super::{configure, first, run_build};
use crate::builder::*;
use crate::Config;
use pretty_assertions::assert_eq;
#[test]
fn build_default() {
- let build = Build::new(configure("build", &["A"], &["A"]));
- let mut builder = Builder::new(&build);
- builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
+ let mut cache = run_build(&[], configure("build", &["A"], &["A"]));
let a = TargetSelection::from_user("A");
assert_eq!(
- first(builder.cache.all::<compile::Std>()),
+ first(cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
]
);
- assert!(!builder.cache.all::<compile::Assemble>().is_empty());
+ assert!(!cache.all::<compile::Assemble>().is_empty());
// Make sure rustdoc is only built once.
assert_eq!(
- first(builder.cache.all::<tool::Rustdoc>()),
+ first(cache.all::<tool::Rustdoc>()),
// Recall that rustdoc stages are off-by-one
// - this is the compiler it's _linked_ to, not built with.
&[tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }],
);
assert_eq!(
- first(builder.cache.all::<compile::Rustc>()),
+ first(cache.all::<compile::Rustc>()),
&[compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },]
);
}
#[test]
fn build_stage_0() {
let config = Config { stage: 0, ..configure("build", &["A"], &["A"]) };
- let build = Build::new(config);
- let mut builder = Builder::new(&build);
- builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
+ let mut cache = run_build(&[], config);
let a = TargetSelection::from_user("A");
assert_eq!(
- first(builder.cache.all::<compile::Std>()),
+ first(cache.all::<compile::Std>()),
&[compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },]
);
- assert!(!builder.cache.all::<compile::Assemble>().is_empty());
+ assert!(!cache.all::<compile::Assemble>().is_empty());
assert_eq!(
- first(builder.cache.all::<tool::Rustdoc>()),
+ first(cache.all::<tool::Rustdoc>()),
// This is the beta rustdoc.
// Add an assert here to make sure this is the only rustdoc built.
&[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } }],
);
- assert!(builder.cache.all::<compile::Rustc>().is_empty());
+ assert!(cache.all::<compile::Rustc>().is_empty());
}
#[test]
fn build_cross_compile() {
let config = Config { stage: 1, ..configure("build", &["A", "B"], &["A", "B"]) };
- let build = Build::new(config);
- let mut builder = Builder::new(&build);
- builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
+ let mut cache = run_build(&[], config);
let a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
// (since we're producing stage 1 libraries/binaries). But currently
// rustbuild is just a bit buggy here; this should be fixed though.
assert_eq!(
- first(builder.cache.all::<compile::Std>()),
+ first(cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
]
);
assert_eq!(
- first(builder.cache.all::<compile::Assemble>()),
+ first(cache.all::<compile::Assemble>()),
&[
compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
]
);
assert_eq!(
- first(builder.cache.all::<tool::Rustdoc>()),
+ first(cache.all::<tool::Rustdoc>()),
&[
tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } },
tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } },
],
);
assert_eq!(
- first(builder.cache.all::<compile::Rustc>()),
+ first(cache.all::<compile::Rustc>()),
&[
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b },
let mut config = configure("doc", &["A"], &["A"]);
config.compiler_docs = true;
config.cmd = Subcommand::Doc { paths: Vec::new(), open: false };
- let build = Build::new(config);
- let mut builder = Builder::new(&build);
- builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]);
+ let mut cache = run_build(&[], config);
let a = TargetSelection::from_user("A");
// error_index_generator uses stage 0 to share rustdoc artifacts with the
// rustdoc tool.
+ assert_eq!(first(cache.all::<doc::ErrorIndex>()), &[doc::ErrorIndex { target: a },]);
assert_eq!(
- first(builder.cache.all::<doc::ErrorIndex>()),
- &[doc::ErrorIndex { target: a },]
- );
- assert_eq!(
- first(builder.cache.all::<tool::ErrorIndex>()),
+ first(cache.all::<tool::ErrorIndex>()),
&[tool::ErrorIndex { compiler: Compiler { host: a, stage: 0 } }]
);
// docs should be built with the beta compiler, not with the stage0 artifacts.
// recall that rustdoc is off-by-one: `stage` is the compiler rustdoc is _linked_ to,
// not the one it was built by.
assert_eq!(
- first(builder.cache.all::<tool::Rustdoc>()),
+ first(cache.all::<tool::Rustdoc>()),
&[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } },]
);
}
}
mod dist {
- use super::{first, Config};
+ use super::{first, run_build, Config};
use crate::builder::*;
use pretty_assertions::assert_eq;
#[test]
fn dist_baseline() {
- let build = Build::new(configure(&["A"], &["A"]));
- let mut builder = Builder::new(&build);
- builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+ let mut cache = run_build(&[], configure(&["A"], &["A"]));
let a = TargetSelection::from_user("A");
- assert_eq!(first(builder.cache.all::<dist::Docs>()), &[dist::Docs { host: a },]);
- assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[dist::Mingw { host: a },]);
+ assert_eq!(first(cache.all::<dist::Docs>()), &[dist::Docs { host: a },]);
+ assert_eq!(first(cache.all::<dist::Mingw>()), &[dist::Mingw { host: a },]);
assert_eq!(
- first(builder.cache.all::<dist::Rustc>()),
+ first(cache.all::<dist::Rustc>()),
&[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },]
);
assert_eq!(
- first(builder.cache.all::<dist::Std>()),
+ first(cache.all::<dist::Std>()),
&[dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },]
);
- assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+ assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
// Make sure rustdoc is only built once.
assert_eq!(
- first(builder.cache.all::<tool::Rustdoc>()),
+ first(cache.all::<tool::Rustdoc>()),
&[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },]
);
}
#[test]
fn dist_with_targets() {
- let build = Build::new(configure(&["A"], &["A", "B"]));
- let mut builder = Builder::new(&build);
- builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+ let mut cache = run_build(&[], configure(&["A"], &["A", "B"]));
let a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
assert_eq!(
- first(builder.cache.all::<dist::Docs>()),
+ first(cache.all::<dist::Docs>()),
&[dist::Docs { host: a }, dist::Docs { host: b },]
);
assert_eq!(
- first(builder.cache.all::<dist::Mingw>()),
+ first(cache.all::<dist::Mingw>()),
&[dist::Mingw { host: a }, dist::Mingw { host: b },]
);
assert_eq!(
- first(builder.cache.all::<dist::Rustc>()),
+ first(cache.all::<dist::Rustc>()),
&[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },]
);
assert_eq!(
- first(builder.cache.all::<dist::Std>()),
+ first(cache.all::<dist::Std>()),
&[
dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
dist::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
]
);
- assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+ assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
}
#[test]
fn dist_with_hosts() {
- let build = Build::new(configure(&["A", "B"], &["A", "B"]));
- let mut builder = Builder::new(&build);
- builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+ let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B"]));
let a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
assert_eq!(
- first(builder.cache.all::<dist::Docs>()),
+ first(cache.all::<dist::Docs>()),
&[dist::Docs { host: a }, dist::Docs { host: b },]
);
assert_eq!(
- first(builder.cache.all::<dist::Mingw>()),
+ first(cache.all::<dist::Mingw>()),
&[dist::Mingw { host: a }, dist::Mingw { host: b },]
);
assert_eq!(
- first(builder.cache.all::<dist::Rustc>()),
+ first(cache.all::<dist::Rustc>()),
&[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
]
);
assert_eq!(
- first(builder.cache.all::<dist::Std>()),
+ first(cache.all::<dist::Std>()),
&[
dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
]
);
assert_eq!(
- first(builder.cache.all::<compile::Std>()),
+ first(cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
],
);
- assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+ assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
}
#[test]
fn dist_only_cross_host() {
let a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
- let mut build = Build::new(configure(&["A", "B"], &["A", "B"]));
- build.config.docs = false;
- build.config.extended = true;
- build.hosts = vec![b];
- let mut builder = Builder::new(&build);
- builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+ let mut config = configure(&["A", "B"], &["A", "B"]);
+ config.docs = false;
+ config.extended = true;
+ config.hosts = vec![b];
+ let mut cache = run_build(&[], config);
assert_eq!(
- first(builder.cache.all::<dist::Rustc>()),
+ first(cache.all::<dist::Rustc>()),
&[dist::Rustc { compiler: Compiler { host: b, stage: 2 } },]
);
assert_eq!(
- first(builder.cache.all::<compile::Rustc>()),
+ first(cache.all::<compile::Rustc>()),
&[
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
#[test]
fn dist_with_targets_and_hosts() {
- let build = Build::new(configure(&["A", "B"], &["A", "B", "C"]));
- let mut builder = Builder::new(&build);
- builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+ let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B", "C"]));
let a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
let c = TargetSelection::from_user("C");
assert_eq!(
- first(builder.cache.all::<dist::Docs>()),
+ first(cache.all::<dist::Docs>()),
&[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },]
);
assert_eq!(
- first(builder.cache.all::<dist::Mingw>()),
+ first(cache.all::<dist::Mingw>()),
&[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },]
);
assert_eq!(
- first(builder.cache.all::<dist::Rustc>()),
+ first(cache.all::<dist::Rustc>()),
&[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
]
);
assert_eq!(
- first(builder.cache.all::<dist::Std>()),
+ first(cache.all::<dist::Std>()),
&[
dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
]
);
- assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+ assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
}
#[test]
fn dist_with_empty_host() {
let config = configure(&[], &["C"]);
- let build = Build::new(config);
- let mut builder = Builder::new(&build);
- builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+ let mut cache = run_build(&[], config);
let a = TargetSelection::from_user("A");
let c = TargetSelection::from_user("C");
- assert_eq!(first(builder.cache.all::<dist::Docs>()), &[dist::Docs { host: c },]);
- assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[dist::Mingw { host: c },]);
+ assert_eq!(first(cache.all::<dist::Docs>()), &[dist::Docs { host: c },]);
+ assert_eq!(first(cache.all::<dist::Mingw>()), &[dist::Mingw { host: c },]);
assert_eq!(
- first(builder.cache.all::<dist::Std>()),
+ first(cache.all::<dist::Std>()),
&[dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },]
);
}
#[test]
fn dist_with_same_targets_and_hosts() {
- let build = Build::new(configure(&["A", "B"], &["A", "B"]));
- let mut builder = Builder::new(&build);
- builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+ let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B"]));
let a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
assert_eq!(
- first(builder.cache.all::<dist::Docs>()),
+ first(cache.all::<dist::Docs>()),
&[dist::Docs { host: a }, dist::Docs { host: b },]
);
assert_eq!(
- first(builder.cache.all::<dist::Mingw>()),
+ first(cache.all::<dist::Mingw>()),
&[dist::Mingw { host: a }, dist::Mingw { host: b },]
);
assert_eq!(
- first(builder.cache.all::<dist::Rustc>()),
+ first(cache.all::<dist::Rustc>()),
&[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
]
);
assert_eq!(
- first(builder.cache.all::<dist::Std>()),
+ first(cache.all::<dist::Std>()),
&[
dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
]
);
- assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+ assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
assert_eq!(
- first(builder.cache.all::<compile::Std>()),
+ first(cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
]
);
assert_eq!(
- first(builder.cache.all::<compile::Assemble>()),
+ first(cache.all::<compile::Assemble>()),
&[
compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
);
}
- #[test]
- fn test_exclude() {
- let mut config = configure(&["A"], &["A"]);
- config.exclude = vec![TaskPath::parse("src/tools/tidy")];
- config.cmd = Subcommand::Test {
- paths: Vec::new(),
- test_args: Vec::new(),
- rustc_args: Vec::new(),
- fail_fast: true,
- doc_tests: DocTests::No,
- bless: false,
- force_rerun: false,
- compare_mode: None,
- rustfix_coverage: false,
- pass: None,
- run: None,
- };
-
- let build = Build::new(config);
- let builder = Builder::new(&build);
- builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
-
- // Ensure we have really excluded tidy
- assert!(!builder.cache.contains::<test::Tidy>());
-
- // Ensure other tests are not affected.
- assert!(builder.cache.contains::<test::RustdocUi>());
- }
-
#[test]
fn doc_ci() {
let mut config = configure(&["A"], &["A"]);
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.all_krates("test")
+ run.all_krates("test").path("library")
}
fn make_run(run: RunConfig<'_>) {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.all_krates("rustc-main")
+ run.all_krates("rustc-main").path("compiler")
}
fn make_run(run: RunConfig<'_>) {
// When downloading stage1, the standard library has already been copied to the sysroot, so
// there's no need to rebuild it.
let download_rustc = run.builder.config.download_rustc;
- run.all_krates("test").default_condition(!download_rustc)
+ run.all_krates("test").path("library").default_condition(!download_rustc)
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("compiler/rustc")
+ run.path("compiler/rustc").path("compiler")
}
fn make_run(run: RunConfig<'_>) {
/// each field, see the corresponding fields in
/// `config.toml.example`.
#[derive(Default)]
+#[cfg_attr(test, derive(Clone))]
pub struct Config {
pub changelog_seen: Option<usize>,
pub ccache: Option<String>,
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>,
/// Per-target configuration stored in the global configuration structure.
#[derive(Default)]
+#[cfg_attr(test, derive(Clone))]
pub struct Target {
/// Some(path to llvm-config) if using an external LLVM.
pub llvm_config: Option<PathBuf>,
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 builder = run.builder;
- run.all_krates("test").default_condition(builder.config.docs)
+ run.all_krates("test").path("library").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig<'_>) {
.iter()
.map(components_simplified)
.filter_map(|path| {
- if path.get(0) == Some(&"library") {
+ if path.len() >= 2 && path.get(0) == Some(&"library") {
+ // single crate
Some(path[1].to_owned())
} else if !path.is_empty() {
+ // ??
Some(path[0].to_owned())
} else {
+ // all library crates
None
}
})
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;
use crate::{Build, DocTests};
+#[derive(Copy, Clone)]
pub enum Color {
Always,
Never,
pub llvm_profile_generate: bool,
}
+#[cfg_attr(test, derive(Clone))]
pub enum Subcommand {
Build {
paths: Vec<PathBuf>,
// 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 {
}
impl Subcommand {
+ pub fn kind(&self) -> Kind {
+ match self {
+ Subcommand::Bench { .. } => Kind::Bench,
+ Subcommand::Build { .. } => Kind::Build,
+ Subcommand::Check { .. } => Kind::Check,
+ Subcommand::Clippy { .. } => Kind::Clippy,
+ Subcommand::Doc { .. } => Kind::Doc,
+ Subcommand::Fix { .. } => Kind::Fix,
+ Subcommand::Format { .. } => Kind::Format,
+ Subcommand::Test { .. } => Kind::Test,
+ Subcommand::Clean { .. } => Kind::Clean,
+ Subcommand::Dist { .. } => Kind::Dist,
+ Subcommand::Install { .. } => Kind::Install,
+ Subcommand::Run { .. } => Kind::Run,
+ Subcommand::Setup { .. } => Kind::Setup,
+ }
+ }
+
pub fn test_args(&self) -> Vec<&str> {
match *self {
Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
t!(std::fs::rename(&self.image_dir, &dest));
self.run(|this, cmd| {
+ let distdir = crate::dist::distdir(this.builder);
+ t!(std::fs::create_dir_all(&distdir));
cmd.arg("tarball")
.arg("--input")
.arg(&dest)
.arg("--output")
- .arg(crate::dist::distdir(this.builder).join(this.package_name()));
+ .arg(distdir.join(this.package_name()));
})
}
targetflags.extend(builder.lld_flags(target));
cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
- cmd.arg("--docck-python").arg(builder.python());
-
- cmd.arg("--lldb-python").arg(builder.python());
+ cmd.arg("--python").arg(builder.python());
if let Some(ref gdb) = builder.config.gdb {
cmd.arg("--gdb").arg(gdb);
-Subproject commit 765318b844569a642ceef7bf1adab9639cbf6af3
+Subproject commit de0dbffc5812fd885700874e8d258dd334733ac4
-Subproject commit a6de8b6e3ea5d4f0de8b7b9a7e5c1405dc2c2ddb
+Subproject commit f7cefbb995eec8c6148f213235e9e2e03268e775
-Subproject commit c2a98d9fc5d29c481d42052fbeccfde15ed03116
+Subproject commit 44a80e8d8bfc5881c9bd69a2cb3a570776ee4181
-Subproject commit eeb5a83c15b6ae60df3e4f19207376b22c6fbc4c
+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.
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};
// 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))
});
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::symbol::kw;
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}")
})
}
if print_all {
for seg in &path.segments[..path.segments.len() - 1] {
- write!(w, "{}::", seg.name)?;
+ write!(w, "{}::", if seg.name == kw::PathRoot { "" } else { seg.name.as_str() })?;
}
}
if w.alternate() {
// 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
}
}
static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
map! {
- "FiraSans-Regular.woff2" => static_files::fira_sans::REGULAR2,
- "FiraSans-Medium.woff2" => static_files::fira_sans::MEDIUM2,
- "FiraSans-Regular.woff" => static_files::fira_sans::REGULAR,
- "FiraSans-Medium.woff" => static_files::fira_sans::MEDIUM,
+ "FiraSans-Regular.woff2" => static_files::fira_sans::REGULAR,
+ "FiraSans-Medium.woff2" => static_files::fira_sans::MEDIUM,
"FiraSans-LICENSE.txt" => static_files::fira_sans::LICENSE,
- "SourceSerif4-Regular.ttf.woff2" => static_files::source_serif_4::REGULAR2,
- "SourceSerif4-Bold.ttf.woff2" => static_files::source_serif_4::BOLD2,
- "SourceSerif4-It.ttf.woff2" => static_files::source_serif_4::ITALIC2,
- "SourceSerif4-Regular.ttf.woff" => static_files::source_serif_4::REGULAR,
- "SourceSerif4-Bold.ttf.woff" => static_files::source_serif_4::BOLD,
- "SourceSerif4-It.ttf.woff" => static_files::source_serif_4::ITALIC,
+ "SourceSerif4-Regular.ttf.woff2" => static_files::source_serif_4::REGULAR,
+ "SourceSerif4-Bold.ttf.woff2" => static_files::source_serif_4::BOLD,
+ "SourceSerif4-It.ttf.woff2" => static_files::source_serif_4::ITALIC,
"SourceSerif4-LICENSE.md" => static_files::source_serif_4::LICENSE,
- "SourceCodePro-Regular.ttf.woff2" => static_files::source_code_pro::REGULAR2,
- "SourceCodePro-Semibold.ttf.woff2" => static_files::source_code_pro::SEMIBOLD2,
- "SourceCodePro-It.ttf.woff2" => static_files::source_code_pro::ITALIC2,
- "SourceCodePro-Regular.ttf.woff" => static_files::source_code_pro::REGULAR,
- "SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD,
- "SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC,
+ "SourceCodePro-Regular.ttf.woff2" => static_files::source_code_pro::REGULAR,
+ "SourceCodePro-Semibold.ttf.woff2" => static_files::source_code_pro::SEMIBOLD,
+ "SourceCodePro-It.ttf.woff2" => static_files::source_code_pro::ITALIC,
"SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE,
- "NanumBarunGothic.ttf.woff2" => static_files::nanum_barun_gothic::REGULAR2,
- "NanumBarunGothic.ttf.woff" => static_files::nanum_barun_gothic::REGULAR,
+ "NanumBarunGothic.ttf.woff2" => static_files::nanum_barun_gothic::REGULAR,
"NanumBarunGothic-LICENSE.txt" => static_files::nanum_barun_gothic::LICENSE,
"LICENSE-MIT.txt" => static_files::LICENSE_MIT,
"LICENSE-APACHE.txt" => static_files::LICENSE_APACHE,
file applies only to those resources. The following third party resources are
included, and carry their own copyright notices and license terms:
-* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2,
- FiraSans-Regular.woff, FiraSans-Medium.woff):
+* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2):
Copyright (c) 2014, Mozilla Foundation https://mozilla.org/
with Reserved Font Name Fira Sans.
Licensed under the MIT license (see LICENSE-MIT.txt).
* Source Code Pro (SourceCodePro-Regular.ttf.woff2,
- SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2,
- SourceCodePro-Regular.ttf.woff, SourceCodePro-Semibold.ttf.woff,
- SourceCodePro-It.ttf.woff):
+ SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2):
Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/),
with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark
See SourceCodePro-LICENSE.txt.
* Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2,
- SourceSerif4-It.ttf.woff2, SourceSerif4-Regular.ttf.woff,
- SourceSerif4-Bold.ttf.woff, SourceSerif4-It.ttf.woff):
+ SourceSerif4-It.ttf.woff2):
Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name
'Source'. All Rights Reserved. Source is a trademark of Adobe in the United
font-style: normal;
font-weight: 400;
src: local('Fira Sans'),
- url("FiraSans-Regular.woff2") format("woff2"),
- url("FiraSans-Regular.woff") format('woff');
+ url("FiraSans-Regular.woff2") format("woff2");
font-display: swap;
}
@font-face {
font-style: normal;
font-weight: 500;
src: local('Fira Sans Medium'),
- url("FiraSans-Medium.woff2") format("woff2"),
- url("FiraSans-Medium.woff") format('woff');
+ url("FiraSans-Medium.woff2") format("woff2");
font-display: swap;
}
font-style: normal;
font-weight: 400;
src: local('Source Serif 4'),
- url("SourceSerif4-Regular.ttf.woff2") format("woff2"),
- url("SourceSerif4-Regular.ttf.woff") format("woff");
+ url("SourceSerif4-Regular.ttf.woff2") format("woff2");
font-display: swap;
}
@font-face {
font-style: italic;
font-weight: 400;
src: local('Source Serif 4 Italic'),
- url("SourceSerif4-It.ttf.woff2") format("woff2"),
- url("SourceSerif4-It.ttf.woff") format("woff");
+ url("SourceSerif4-It.ttf.woff2") format("woff2");
font-display: swap;
}
@font-face {
font-style: normal;
font-weight: 700;
src: local('Source Serif 4 Bold'),
- url("SourceSerif4-Bold.ttf.woff2") format("woff2"),
- url("SourceSerif4-Bold.ttf.woff") format("woff");
+ url("SourceSerif4-Bold.ttf.woff2") format("woff2");
font-display: swap;
}
font-weight: 400;
/* Avoid using locally installed font because bad versions are in circulation:
* see https://github.com/rust-lang/rust/issues/24355 */
- src: url("SourceCodePro-Regular.ttf.woff2") format("woff2"),
- url("SourceCodePro-Regular.ttf.woff") format("woff");
+ src: url("SourceCodePro-Regular.ttf.woff2") format("woff2");
font-display: swap;
}
@font-face {
font-family: 'Source Code Pro';
font-style: italic;
font-weight: 400;
- src: url("SourceCodePro-It.ttf.woff2") format("woff2"),
- url("SourceCodePro-It.ttf.woff") format("woff");
+ src: url("SourceCodePro-It.ttf.woff2") format("woff2");
font-display: swap;
}
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 600;
- src: url("SourceCodePro-Semibold.ttf.woff2") format("woff2"),
- url("SourceCodePro-Semibold.ttf.woff") format("woff");
+ src: url("SourceCodePro-Semibold.ttf.woff2") format("woff2");
font-display: swap;
}
/* Avoid using legacy CJK serif fonts in Windows like Batang. */
@font-face {
font-family: 'NanumBarunGothic';
- src: url("NanumBarunGothic.ttf.woff2") format("woff2"),
- url("NanumBarunGothic.ttf.woff") format("woff");
+ src: url("NanumBarunGothic.ttf.woff2") format("woff2");
font-display: swap;
unicode-range: U+AC00-D7AF, U+1100-11FF, U+3130-318F, U+A960-A97F, U+D7B0-D7FF;
}
/**
* @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;
+/* eslint-env es6 */
+/* eslint no-var: "error" */
+/* eslint prefer-const: "error" */
/* global addClass, getNakedUrl, getSettingValue, hasOwnPropertyRustdoc, initSearch, onEach */
/* global onEachLazy, removeClass, searchState, hasClass */
(function() {
// This mapping table should match the discriminants of
// `rustdoc::formats::item_type::ItemType` type in Rust.
-var itemTypes = [
+const itemTypes = [
"mod",
"externcrate",
"import",
];
// used for special search precedence
-var TY_PRIMITIVE = itemTypes.indexOf("primitive");
-var TY_KEYWORD = itemTypes.indexOf("keyword");
+const TY_PRIMITIVE = itemTypes.indexOf("primitive");
+const TY_KEYWORD = itemTypes.indexOf("keyword");
// In the search display, allows to switch between tabs.
function printTab(nb) {
if (nb === 0 || nb === 1 || nb === 2) {
searchState.currentTab = nb;
}
- var nb_copy = nb;
+ let nb_copy = nb;
onEachLazy(document.getElementById("titles").childNodes, function(elem) {
if (nb_copy === 0) {
addClass(elem, "selected");
});
}
-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
* This code is an unmodified version of the code written by Marco de Wit
* and was found at https://stackoverflow.com/a/18514751/745719
*/
-var levenshtein_row2 = [];
+const levenshtein_row2 = [];
function levenshtein(s1, s2) {
if (s1 === s2) {
return 0;
}
- var s1_len = s1.length, s2_len = s2.length;
+ const s1_len = s1.length, s2_len = s2.length;
if (s1_len && s2_len) {
- var i1 = 0, i2 = 0, a, b, c, c2, row = levenshtein_row2;
+ let i1 = 0, i2 = 0, a, b, c, c2;
+ const row = levenshtein_row2;
while (i1 < s1_len) {
row[i1] = ++i1;
}
}
window.initSearch = function(rawSearchIndex) {
- var MAX_LEV_DISTANCE = 3;
- var MAX_RESULTS = 200;
- var GENERICS_DATA = 2;
- var NAME = 0;
- var INPUTS_DATA = 0;
- var OUTPUT_DATA = 1;
- var NO_TYPE_FILTER = -1;
+ const MAX_LEV_DISTANCE = 3;
+ const MAX_RESULTS = 200;
+ const GENERICS_DATA = 2;
+ const NAME = 0;
+ const INPUTS_DATA = 0;
+ const OUTPUT_DATA = 1;
+ const NO_TYPE_FILTER = -1;
/**
* @type {Array<Row>}
*/
- var searchIndex;
+ let searchIndex;
/**
* @type {Array<string>}
*/
- var searchWords;
- var currentResults;
- var ALIASES = {};
- var params = searchState.getQueryStringParams();
+ let searchWords = [];
+ let currentResults;
+ const ALIASES = {};
+ const params = searchState.getQueryStringParams();
// Populate search bar with query string search term when provided,
// but only if the input bar is empty. This avoid the obnoxious issue
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 (let 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;
+ const start = parserState.pos;
+ const 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");
+ }
+ const pathSegments = name.split("::");
+ if (pathSegments.length > 1) {
+ for (let i = 0, len = pathSegments.length; i < len; ++i) {
+ const 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) {
+ let end = parserState.pos;
+ let foundExclamation = false;
+ while (parserState.pos < parserState.length) {
+ const c = parserState.userQuery[parserState.pos];
+ if (!isIdentCharacter(c)) {
+ if (c === "!") {
+ if (foundExclamation) {
+ throw new Error("Cannot have more than one `!` in an ident");
+ } else if (parserState.pos + 1 < parserState.length &&
+ isIdentCharacter(parserState.userQuery[parserState.pos + 1]))
+ {
+ throw new Error("`!` can only be at the end of an ident");
+ }
+ foundExclamation = true;
+ } else 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;
+ foundExclamation = false;
+ } 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) {
+ const generics = [];
+
+ let start = parserState.pos;
+ let 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) {
+ let foundStopChar = true;
+
+ while (parserState.pos < parserState.length) {
+ const 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)) {
+ let 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}\``);
+ }
+ const 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) {
+ const query = parserState.userQuery;
+
+ for (let 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) {
+ let c, before;
+ let 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) {
- var extra = "?search=" + encodeURIComponent(search);
+ let extra = "?search=" + encodeURIComponent(search);
if (filterCrates !== null) {
extra += "&filter-crate=" + encodeURIComponent(filterCrates);
* @return {string|null}
*/
function getFilterCrates() {
- var elem = document.getElementById("crate-search");
+ const elem = document.getElementById("crate-search");
if (elem &&
elem.value !== "All crates" &&
}
/**
- * 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();
+ const parserState = {
+ length: userQuery.length,
+ pos: 0,
+ // Total number of elements (includes generics).
+ totalElems: 0,
+ genericsElems: 0,
+ typeFilter: null,
+ userQuery: userQuery.toLowerCase(),
+ };
+ let query = newParsedQuery(userQuery);
+
+ try {
+ parseInput(query, parserState);
+ if (parserState.typeFilter !== null) {
+ let 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;
+ }
+
+ /**
+ * 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,
+ };
+ }
- removeEmptyStringsFromArray(split);
+ /**
+ * 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) {
+ const results_others = {}, results_in_args = {}, results_returned = {};
function transformResults(results) {
- var duplicates = {};
- var out = [];
-
- for (var i = 0, len = results.length; i < len; ++i) {
- var result = results[i];
+ const duplicates = {};
+ const out = [];
+ for (const result of results) {
if (result.id > -1) {
- var obj = searchIndex[result.id];
+ const obj = searchIndex[result.id];
obj.lev = result.lev;
- var res = buildHrefAndPath(obj);
+ const res = buildHrefAndPath(obj);
obj.displayPath = pathSplitter(res[0]);
obj.fullPath = obj.displayPath + obj.name;
// To be sure than it some items aren't considered as duplicate.
}
function sortResults(results, isType) {
- var ar = [];
- for (var entry in results) {
+ const userQuery = parsedQuery.userQuery;
+ const ar = [];
+ for (const entry in results) {
if (hasOwnPropertyRustdoc(results, entry)) {
- var result = results[entry];
+ const result = results[entry];
result.word = searchWords[result.id];
result.item = searchIndex[result.id] || {};
ar.push(result);
}
results.sort(function(aaa, bbb) {
- var a, b;
+ let 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;
});
- for (var i = 0, len = results.length; i < len; ++i) {
- result = results[i];
+ let nameSplit = null;
+ if (parsedQuery.elems.length === 1) {
+ const hasPath = typeof parsedQuery.elems[0].path === "undefined";
+ nameSplit = hasPath ? null : parsedQuery.elems[0].path;
+ }
+ for (const result of results) {
// this validation does not make sense when searching by types
if (result.dontValidate) {
continue;
}
- var name = result.item.name.toLowerCase(),
+ const name = result.item.name.toLowerCase(),
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;
+ let elem_name;
+ if (elem.generics.length > 0 && row[GENERICS_DATA].length >= elem.generics.length) {
+ const elems = Object.create(null);
+ for (const entry of row[GENERICS_DATA]) {
+ elem_name = entry[NAME];
+ if (elem_name === "") {
+ // Pure generic, needs to check into it.
+ if (checkGenerics(entry, 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 (const generic of elem.generics) {
+ let 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) {
+ let lev = MAX_LEV_DISTANCE + 1;
+ for (const entry of row[GENERICS_DATA]) {
+ lev = Math.min(checkType(entry, elem, true), lev);
+ if (lev === 0) {
+ break;
+ }
+ }
+ 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!
+ let 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) {
+ const 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 MAX_LEV_DISTANCE + 1;
+ } else if (elem.generics.length > 0) {
+ return checkGenerics(row, elem, MAX_LEV_DISTANCE + 1);
}
- 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);
- }
- 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!
+ const 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;
-
- if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
- var length = obj.type[INPUTS_DATA].length;
- for (var i = 0; i < length; i++) {
- var tmp = obj.type[INPUTS_DATA][i];
- if (!typePassesFilter(typeFilter, tmp[1])) {
+ function findArg(row, elem, typeFilter) {
+ let lev = MAX_LEV_DISTANCE + 1;
+
+ if (row && row.type && row.type[INPUTS_DATA] && row.type[INPUTS_DATA].length > 0) {
+ for (const input of row.type[INPUTS_DATA]) {
+ if (!typePassesFilter(typeFilter, input[1])) {
continue;
}
- tmp = checkType(tmp, val, literalSearch);
- if (tmp === 0) {
+ lev = Math.min(lev, checkType(input, 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) {
+ let 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) {
+ let ret = row.type[OUTPUT_DATA];
if (typeof ret[0] === "string") {
ret = [ret];
}
- for (var x = 0, len = ret.length; x < len; ++x) {
- var tmp = ret[x];
- if (!typePassesFilter(typeFilter, tmp[1])) {
+ for (const ret_ty of ret) {
+ if (!typePassesFilter(typeFilter, ret_ty[1])) {
continue;
}
- tmp = checkType(tmp, val, literalSearch);
- if (tmp === 0) {
+ lev = Math.min(lev, checkType(ret_ty, 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) {
if (contains.length === 0) {
return 0;
}
- var ret_lev = MAX_LEV_DISTANCE + 1;
- var path = ty.path.split("::");
+ let ret_lev = MAX_LEV_DISTANCE + 1;
+ const path = ty.path.split("::");
if (ty.parent && ty.parent.name) {
path.push(ty.parent.name.toLowerCase());
}
- var length = path.length;
- var clength = contains.length;
+ const length = path.length;
+ const clength = contains.length;
if (clength > length) {
return MAX_LEV_DISTANCE + 1;
}
- for (var i = 0; i < length; ++i) {
+ for (let i = 0; i < length; ++i) {
if (i + clength > length) {
break;
}
- var lev_total = 0;
- var aborted = false;
- for (var x = 0; x < clength; ++x) {
- var lev = levenshtein(path[i + x], contains[x]);
+ let lev_total = 0;
+ let aborted = false;
+ for (let x = 0; x < clength; ++x) {
+ const lev = levenshtein(path[i + x], contains[x]);
if (lev > MAX_LEV_DISTANCE) {
aborted = true;
break;
if (filter <= NO_TYPE_FILTER || filter === type) return true;
// Match related items
- var name = itemTypes[type];
+ const name = itemTypes[type];
switch (itemTypes[filter]) {
case "constant":
return name === "associatedconstant";
}
function handleAliases(ret, query, filterCrates) {
+ const 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 = [];
+ const aliases = [];
+ const crateAliases = [];
if (filterCrates !== null) {
- if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
- var query_aliases = ALIASES[filterCrates][query.search];
- var len = query_aliases.length;
- for (var i = 0; i < len; ++i) {
- aliases.push(createAliasFromItem(searchIndex[query_aliases[i]]));
+ if (ALIASES[filterCrates] && ALIASES[filterCrates][lowerQuery]) {
+ const query_aliases = ALIASES[filterCrates][lowerQuery];
+ for (const alias of query_aliases) {
+ aliases.push(createAliasFromItem(searchIndex[alias]));
}
}
} else {
Object.keys(ALIASES).forEach(function(crate) {
- if (ALIASES[crate][query.search]) {
- var pushTo = crate === window.currentCrate ? crateAliases : aliases;
- var query_aliases = ALIASES[crate][query.search];
- var len = query_aliases.length;
- for (var i = 0; i < len; ++i) {
- pushTo.push(createAliasFromItem(searchIndex[query_aliases[i]]));
+ if (ALIASES[crate][lowerQuery]) {
+ const pushTo = crate === window.currentCrate ? crateAliases : aliases;
+ const query_aliases = ALIASES[crate][lowerQuery];
+ for (const alias of query_aliases) {
+ pushTo.push(createAliasFromItem(searchIndex[alias]));
}
}
});
}
- var sortFunc = function(aaa, bbb) {
+ const sortFunc = function(aaa, bbb) {
if (aaa.path < bbb.path) {
return 1;
} else if (aaa.path === bbb.path) {
crateAliases.sort(sortFunc);
aliases.sort(sortFunc);
- var pushFunc = function(alias) {
- alias.alias = query.raw;
- var res = buildHrefAndPath(alias);
+ const pushFunc = function(alias) {
+ alias.alias = query;
+ const res = buildHrefAndPath(alias);
alias.displayPath = pathSplitter(res[0]);
alias.fullPath = alias.displayPath + alias.name;
alias.href = res[1];
}
/**
- * 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) {
+ const 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;
+ }
+ let lev, lev_add = 0, index = -1;
+ const fullId = row.id;
+
+ const in_args = findArg(row, elem, parsedQuery.typeFilter);
+ const 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;
+ }
+ const 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);
+ }
+ }
+ 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;
}
- fullId = ty.id;
+ }
+ 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;
+ let totalLev = 0;
+ let nbLev = 0;
+
+ // If the result is too "bad", we return false and it ends this search.
+ function checkArgs(elems, callback) {
+ for (const elem of elems) {
+ // There is more than one parameter to the query so all checks should be "exact"
+ const 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;
+ }
+ const 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() {
+ let 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) {
+ let 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();
+ }
+
+ const 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) {
- for (var i = 0, len = keys.length; i < len; ++i) {
+ if (!keys || !keys.length) {
+ return true;
+ }
+ for (const key of keys) {
// each check is for validation so we negate the conditions and invalidate
if (!(
// check for an exact name match
- name.indexOf(keys[i]) > -1 ||
+ name.indexOf(key) > -1 ||
// then an exact path match
- path.indexOf(keys[i]) > -1 ||
+ path.indexOf(key) > -1 ||
// next if there is a parent, check for exact parent match
(parent !== undefined && parent.name !== undefined &&
- parent.name.toLowerCase().indexOf(keys[i]) > -1) ||
+ parent.name.toLowerCase().indexOf(key) > -1) ||
// lastly check to see if the name was a levenshtein match
- levenshtein(name, keys[i]) <= MAX_LEV_DISTANCE)) {
+ levenshtein(name, key) <= MAX_LEV_DISTANCE)) {
return false;
}
}
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;
+ const next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
searchState.focusedByTab[searchState.currentTab] = document.activeElement;
printTab(next);
focusSearchResult();
// Focus the first search result on the active tab, or the result that
// was focused last time this tab was active.
function focusSearchResult() {
- var target = searchState.focusedByTab[searchState.currentTab] ||
+ const target = searchState.focusedByTab[searchState.currentTab] ||
document.querySelectorAll(".search-results.active a").item(0) ||
document.querySelectorAll("#titles > button").item(searchState.currentTab);
if (target) {
}
function buildHrefAndPath(item) {
- var displayPath;
- var href;
- var type = itemTypes[item.ty];
- var name = item.name;
- var path = item.path;
+ let displayPath;
+ let href;
+ const type = itemTypes[item.ty];
+ const name = item.name;
+ let path = item.path;
if (type === "mod") {
displayPath = path + "::";
displayPath = "";
href = window.rootPath + name + "/index.html";
} else if (item.parent !== undefined) {
- var myparent = item.parent;
- var anchor = "#" + type + "." + name;
- var parentType = itemTypes[myparent.ty];
- var pageType = parentType;
- var pageName = myparent.name;
+ const myparent = item.parent;
+ let anchor = "#" + type + "." + name;
+ const parentType = itemTypes[myparent.ty];
+ let pageType = parentType;
+ let pageName = myparent.name;
if (parentType === "primitive") {
displayPath = myparent.name + "::";
} else if (type === "structfield" && parentType === "variant") {
// Structfields belonging to variants are special: the
// final path element is the enum name.
- var enumNameIdx = item.path.lastIndexOf("::");
- var enumName = item.path.substr(enumNameIdx + 2);
+ const enumNameIdx = item.path.lastIndexOf("::");
+ const enumName = item.path.substr(enumNameIdx + 2);
path = item.path.substr(0, enumNameIdx);
displayPath = path + "::" + enumName + "::" + myparent.name + "::";
anchor = "#variant." + myparent.name + ".field." + name;
}
function escape(content) {
- var h1 = document.createElement("h1");
+ const h1 = document.createElement("h1");
h1.textContent = content;
return h1.innerHTML;
}
function pathSplitter(path) {
- var tmp = "<span>" + path.replace(/::/g, "::</span><span>");
+ const tmp = "<span>" + path.replace(/::/g, "::</span><span>");
if (tmp.endsWith("<span>")) {
return tmp.slice(0, tmp.length - 6);
}
* @param {boolean} display - True if this is the active tab
*/
function addTab(array, query, display) {
- var extraClass = "";
+ let extraClass = "";
if (display === true) {
extraClass = " active";
}
- var output = document.createElement("div");
- var length = 0;
+ const output = document.createElement("div");
+ let length = 0;
if (array.length > 0) {
output.className = "search-results " + extraClass;
array.forEach(function(item) {
- var name = item.name;
- var type = itemTypes[item.ty];
+ const name = item.name;
+ const type = itemTypes[item.ty];
length += 1;
- var extra = "";
+ let extra = "";
if (type === "primitive") {
extra = " <i>(primitive type)</i>";
} else if (type === "keyword") {
extra = " <i>(keyword)</i>";
}
- var link = document.createElement("a");
+ const link = document.createElement("a");
link.className = "result-" + type;
link.href = item.href;
- var wrapper = document.createElement("div");
- var resultName = document.createElement("div");
+ const wrapper = document.createElement("div");
+ const resultName = document.createElement("div");
resultName.className = "result-name";
if (item.is_alias) {
- var alias = document.createElement("span");
+ const alias = document.createElement("span");
alias.className = "alias";
- var bold = document.createElement("b");
+ const bold = document.createElement("b");
bold.innerText = item.alias;
alias.appendChild(bold);
item.displayPath + "<span class=\"" + type + "\">" + name + extra + "</span>");
wrapper.appendChild(resultName);
- var description = document.createElement("div");
+ const description = document.createElement("div");
description.className = "desc";
- var spanDesc = document.createElement("span");
+ const spanDesc = document.createElement("span");
spanDesc.insertAdjacentHTML("beforeend", item.desc);
description.appendChild(spanDesc);
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();
+ const search = searchState.outputElement();
if (go_to_first || (results.others.length === 1
&& getSettingValue("go-to-only-result") === "true"
// By default, the search DOM element is "empty" (meaning it has no children not
// ESC or empty the search input (which also "cancels" the search).
&& (!search.firstChild || search.firstChild.innerText !== searchState.loadingText)))
{
- var elem = document.createElement("a");
+ const elem = document.createElement("a");
elem.href = results.others[0].href;
removeClass(elem, "active");
// For firefox, we need the element to be in the DOM so it can be clicked.
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);
+ const ret_others = addTab(results.others, results.query, true);
+ const ret_in_args = addTab(results.in_args, results.query, false);
+ const 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
// it again.
- var currentTab = searchState.currentTab;
+ let currentTab = searchState.currentTab;
if ((currentTab === 0 && ret_others[1] === 0) ||
(currentTab === 1 && ret_in_args[1] === 0) ||
(currentTab === 2 && ret_returned[1] === 0)) {
let crates = "";
if (window.ALL_CRATES.length > 1) {
crates = ` in <select id="crate-search"><option value="All crates">All crates</option>`;
- for (let c of window.ALL_CRATES) {
+ for (const c of window.ALL_CRATES) {
crates += `<option value="${c}" ${c == filterCrates && "selected"}>${c}</option>`;
}
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">` +
+
+ let typeFilter = "";
+ if (results.query.typeFilter !== NO_TYPE_FILTER) {
+ typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
+ }
+
+ let 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]) +
"</div>";
- var resultsElem = document.createElement("div");
+ const resultsElem = document.createElement("div");
resultsElem.id = "results";
resultsElem.appendChild(ret_others[0]);
resultsElem.appendChild(ret_in_args[0]);
resultsElem.appendChild(ret_returned[0]);
search.innerHTML = output;
- let crateSearch = document.getElementById("crate-search");
+ const crateSearch = document.getElementById("crate-search");
if (crateSearch) {
crateSearch.addEventListener("input", updateCrate);
}
// Reset focused elements.
searchState.focusedByTab = [null, null, null];
searchState.showResults(search);
- var elems = document.getElementById("titles").childNodes;
+ const elems = document.getElementById("titles").childNodes;
elems[0].onclick = function() { printTab(0); };
elems[1].onclick = function() { printTab(1); };
elems[2].onclick = function() { printTab(2); };
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.
* @param {boolean} [forced]
*/
function search(e, forced) {
- var params = searchState.getQueryStringParams();
- var query = getQuery(searchState.input.value.trim());
+ const params = searchState.getQueryStringParams();
+ const 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;
}
- var filterCrates = getFilterCrates();
+ let filterCrates = getFilterCrates();
// In case we have no information about the saved crate and there is a URL query parameter,
// we override it with the URL query parameter.
}
// 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);
-
+ const 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) {
/**
* @type {Array<string>}
*/
- var searchWords = [];
- var i, word;
- var currentIndex = 0;
- var id = 0;
+ const searchWords = [];
+ let i, word;
+ let currentIndex = 0;
+ let id = 0;
- for (var crate in rawSearchIndex) {
+ for (const crate in rawSearchIndex) {
if (!hasOwnPropertyRustdoc(rawSearchIndex, crate)) {
continue;
}
- var crateSize = 0;
+ let crateSize = 0;
/**
* The raw search data for a given crate. `n`, `t`, `d`, and `q`, `i`, and `f`
* p: Array<Object>,
* }}
*/
- var crateCorpus = rawSearchIndex[crate];
+ const crateCorpus = rawSearchIndex[crate];
searchWords.push(crate);
// This object should have exactly the same set of fields as the "row"
// object defined below. Your JavaScript runtime will thank you.
// https://mathiasbynens.be/notes/shapes-ics
- var crateRow = {
+ const crateRow = {
crate: crate,
ty: 1, // == ExternCrate
name: crate,
currentIndex += 1;
// an array of (Number) item types
- var itemTypes = crateCorpus.t;
+ const itemTypes = crateCorpus.t;
// an array of (String) item names
- var itemNames = crateCorpus.n;
+ const itemNames = crateCorpus.n;
// an array of (String) full paths (or empty string for previous path)
- var itemPaths = crateCorpus.q;
+ const itemPaths = crateCorpus.q;
// an array of (String) descriptions
- var itemDescs = crateCorpus.d;
+ const itemDescs = crateCorpus.d;
// an array of (Number) the parent path index + 1 to `paths`, or 0 if none
- var itemParentIdxs = crateCorpus.i;
+ const itemParentIdxs = crateCorpus.i;
// an array of (Object | null) the type of the function, if any
- var itemFunctionSearchTypes = crateCorpus.f;
+ const itemFunctionSearchTypes = crateCorpus.f;
// an array of [(Number) item type,
// (String) name]
- var paths = crateCorpus.p;
+ const paths = crateCorpus.p;
// an array of [(String) alias name
// [Number] index to items]
- var aliases = crateCorpus.a;
+ const aliases = crateCorpus.a;
// convert `rawPaths` entries into object form
- var len = paths.length;
+ let len = paths.length;
for (i = 0; i < len; ++i) {
paths[i] = {ty: paths[i][0], name: paths[i][1]};
}
// all other search operations have access to this cached data for
// faster analysis operations
len = itemTypes.length;
- var lastPath = "";
+ let lastPath = "";
for (i = 0; i < len; ++i) {
// This object should have exactly the same set of fields as the "crateRow"
// object defined above.
word = "";
searchWords.push("");
}
- var row = {
+ const row = {
crate: crate,
ty: itemTypes[i],
name: itemNames[i],
if (aliases) {
ALIASES[crate] = {};
- var j, local_aliases;
- for (var alias_name in aliases) {
+ for (const alias_name in aliases) {
if (!hasOwnPropertyRustdoc(aliases, alias_name)) {
continue;
}
if (!hasOwnPropertyRustdoc(ALIASES[crate], alias_name)) {
ALIASES[crate][alias_name] = [];
}
- local_aliases = aliases[alias_name];
- for (j = 0, len = local_aliases.length; j < len; ++j) {
- ALIASES[crate][alias_name].push(local_aliases[j] + currentIndex);
+ for (const local_alias of aliases[alias_name]) {
+ ALIASES[crate][alias_name].push(local_alias + currentIndex);
}
}
}
}
function putBackSearch() {
- var search_input = searchState.input;
+ const search_input = searchState.input;
if (!searchState.input) {
return;
}
- var search = searchState.outputElement();
+ const search = searchState.outputElement();
if (search_input.value !== "" && hasClass(search, "hidden")) {
searchState.showResults(search);
if (searchState.browserSupportsHistoryApi()) {
}
function registerSearchEvents() {
- var searchAfter500ms = function() {
+ const searchAfter500ms = function() {
searchState.clearInputTimeout();
if (searchState.input.value.length === 0) {
if (searchState.browserSupportsHistoryApi()) {
// up and down arrow select next/previous search result, or the
// search box if we're already at the top.
if (e.which === 38) { // up
- var previous = document.activeElement.previousElementSibling;
+ const previous = document.activeElement.previousElementSibling;
if (previous) {
previous.focus();
} else {
}
e.preventDefault();
} else if (e.which === 40) { // down
- var next = document.activeElement.nextElementSibling;
+ const next = document.activeElement.nextElementSibling;
if (next) {
next.focus();
}
- var rect = document.activeElement.getBoundingClientRect();
+ const rect = document.activeElement.getBoundingClientRect();
if (window.innerHeight - rect.bottom < rect.height) {
window.scrollBy(0, rect.height);
}
// history.
if (searchState.browserSupportsHistoryApi()) {
// Store the previous <title> so we can revert back to it later.
- var previousTitle = document.title;
+ const previousTitle = document.title;
window.addEventListener("popstate", function(e) {
- var params = searchState.getQueryStringParams();
+ const params = searchState.getQueryStringParams();
// Revert to the previous title manually since the History
// API ignores the title parameter.
document.title = previousTitle;
// that try to sync state between the URL and the search input. To work around it,
// do a small amount of re-init on page show.
window.onpageshow = function(){
- var qSearch = searchState.getQueryStringParams().search;
+ const qSearch = searchState.getQueryStringParams().search;
if (searchState.input.value === "" && qSearch) {
searchState.input.value = qSearch;
}
function updateCrate(ev) {
if (ev.target.value === "All crates") {
// If we don't remove it from the URL, it'll be picked up again by the search.
- var params = searchState.getQueryStringParams();
- var query = searchState.input.value.trim();
+ const params = searchState.getQueryStringParams();
+ const query = searchState.input.value.trim();
if (!history.state && !params.search) {
history.pushState(null, "", buildUrl(query, null));
} else {
// Local js definitions:
+/* eslint-env es6 */
+/* eslint no-var: "error" */
+/* eslint prefer-const: "error" */
/* global getSettingValue, getVirtualKey, onEachLazy, updateLocalStorage, updateSystemTheme */
/* global addClass, removeClass */
function setEvents() {
updateLightAndDark();
onEachLazy(document.getElementsByClassName("slider"), function(elem) {
- var toggle = elem.previousElementSibling;
- var settingId = toggle.id;
- var settingValue = getSettingValue(settingId);
+ const toggle = elem.previousElementSibling;
+ const settingId = toggle.id;
+ const settingValue = getSettingValue(settingId);
if (settingValue !== null) {
toggle.checked = settingValue === "true";
}
toggle.onkeyrelease = handleKey;
});
onEachLazy(document.getElementsByClassName("select-wrapper"), function(elem) {
- var select = elem.getElementsByTagName("select")[0];
- var settingId = select.id;
- var settingValue = getSettingValue(settingId);
+ const select = elem.getElementsByTagName("select")[0];
+ const settingId = select.id;
+ const settingValue = getSettingValue(settingId);
if (settingValue !== null) {
select.value = settingValue;
}
/// Files related to the Fira Sans font.
crate mod fira_sans {
- /// The file `FiraSans-Regular.woff`, the Regular variant of the Fira Sans font.
- crate static REGULAR: &[u8] = include_bytes!("static/fonts/FiraSans-Regular.woff");
-
/// The file `FiraSans-Regular.woff2`, the Regular variant of the Fira Sans font in woff2.
- crate static REGULAR2: &[u8] = include_bytes!("static/fonts/FiraSans-Regular.woff2");
-
- /// The file `FiraSans-Medium.woff`, the Medium variant of the Fira Sans font.
- crate static MEDIUM: &[u8] = include_bytes!("static/fonts/FiraSans-Medium.woff");
+ crate static REGULAR: &[u8] = include_bytes!("static/fonts/FiraSans-Regular.woff2");
/// The file `FiraSans-Medium.woff2`, the Medium variant of the Fira Sans font in woff2.
- crate static MEDIUM2: &[u8] = include_bytes!("static/fonts/FiraSans-Medium.woff2");
+ crate static MEDIUM: &[u8] = include_bytes!("static/fonts/FiraSans-Medium.woff2");
/// The file `FiraSans-LICENSE.txt`, the license text for the Fira Sans font.
crate static LICENSE: &[u8] = include_bytes!("static/fonts/FiraSans-LICENSE.txt");
/// Files related to the Source Serif 4 font.
crate mod source_serif_4 {
- /// The file `SourceSerif4-Regular.ttf.woff`, the Regular variant of the Source Serif 4 font.
- crate static REGULAR: &[u8] = include_bytes!("static/fonts/SourceSerif4-Regular.ttf.woff");
-
/// The file `SourceSerif4-Regular.ttf.woff2`, the Regular variant of the Source Serif 4 font in
/// woff2.
- crate static REGULAR2: &[u8] = include_bytes!("static/fonts/SourceSerif4-Regular.ttf.woff2");
-
- /// The file `SourceSerif4-Bold.ttf.woff`, the Bold variant of the Source Serif 4 font.
- crate static BOLD: &[u8] = include_bytes!("static/fonts/SourceSerif4-Bold.ttf.woff");
+ crate static REGULAR: &[u8] = include_bytes!("static/fonts/SourceSerif4-Regular.ttf.woff2");
/// The file `SourceSerif4-Bold.ttf.woff2`, the Bold variant of the Source Serif 4 font in
/// woff2.
- crate static BOLD2: &[u8] = include_bytes!("static/fonts/SourceSerif4-Bold.ttf.woff2");
-
- /// The file `SourceSerif4-It.ttf.woff`, the Italic variant of the Source Serif 4 font.
- crate static ITALIC: &[u8] = include_bytes!("static/fonts/SourceSerif4-It.ttf.woff");
+ crate static BOLD: &[u8] = include_bytes!("static/fonts/SourceSerif4-Bold.ttf.woff2");
/// The file `SourceSerif4-It.ttf.woff2`, the Italic variant of the Source Serif 4 font in
/// woff2.
- crate static ITALIC2: &[u8] = include_bytes!("static/fonts/SourceSerif4-It.ttf.woff2");
+ crate static ITALIC: &[u8] = include_bytes!("static/fonts/SourceSerif4-It.ttf.woff2");
/// The file `SourceSerif4-LICENSE.txt`, the license text for the Source Serif 4 font.
crate static LICENSE: &[u8] = include_bytes!("static/fonts/SourceSerif4-LICENSE.md");
/// Files related to the Source Code Pro font.
crate mod source_code_pro {
- /// The file `SourceCodePro-Regular.ttf.woff`, the Regular variant of the Source Code Pro font.
- crate static REGULAR: &[u8] = include_bytes!("static/fonts/SourceCodePro-Regular.ttf.woff");
-
/// The file `SourceCodePro-Regular.ttf.woff2`, the Regular variant of the Source Code Pro font
/// in woff2.
- crate static REGULAR2: &[u8] = include_bytes!("static/fonts/SourceCodePro-Regular.ttf.woff2");
-
- /// The file `SourceCodePro-Semibold.ttf.woff`, the Semibold variant of the Source Code Pro
- /// font.
- crate static SEMIBOLD: &[u8] = include_bytes!("static/fonts/SourceCodePro-Semibold.ttf.woff");
+ crate static REGULAR: &[u8] = include_bytes!("static/fonts/SourceCodePro-Regular.ttf.woff2");
/// The file `SourceCodePro-Semibold.ttf.woff2`, the Semibold variant of the Source Code Pro
/// font in woff2.
- crate static SEMIBOLD2: &[u8] = include_bytes!("static/fonts/SourceCodePro-Semibold.ttf.woff2");
-
- /// The file `SourceCodePro-It.ttf.woff`, the Italic variant of the Source Code Pro font.
- crate static ITALIC: &[u8] = include_bytes!("static/fonts/SourceCodePro-It.ttf.woff");
+ crate static SEMIBOLD: &[u8] = include_bytes!("static/fonts/SourceCodePro-Semibold.ttf.woff2");
/// The file `SourceCodePro-It.ttf.woff2`, the Italic variant of the Source Code Pro font in
/// woff2.
- crate static ITALIC2: &[u8] = include_bytes!("static/fonts/SourceCodePro-It.ttf.woff2");
+ crate static ITALIC: &[u8] = include_bytes!("static/fonts/SourceCodePro-It.ttf.woff2");
/// The file `SourceCodePro-LICENSE.txt`, the license text of the Source Code Pro font.
crate static LICENSE: &[u8] = include_bytes!("static/fonts/SourceCodePro-LICENSE.txt");
/// ```sh
/// pyftsubset NanumBarunGothic.ttf \
/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
-/// --output-file=NanumBarunGothic.ttf.woff --flavor=woff
-/// ```
-/// ```sh
-/// pyftsubset NanumBarunGothic.ttf \
-/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
/// --output-file=NanumBarunGothic.ttf.woff2 --flavor=woff2
/// ```
crate mod nanum_barun_gothic {
- /// The file `NanumBarunGothic.ttf.woff`, the Regular variant of the Nanum Barun Gothic font.
- crate static REGULAR: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff");
-
/// The file `NanumBarunGothic.ttf.woff2`, the Regular variant of the Nanum Barun Gothic font.
- crate static REGULAR2: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff2");
+ crate static REGULAR: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff2");
/// The file `NanumBarunGothic-LICENSE.txt`, the license text of the Nanum Barun Gothic font.
crate static LICENSE: &[u8] = include_bytes!("static/fonts/NanumBarunGothic-LICENSE.txt");
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)
}
}
});
- // Also try to inline primitive impls from other crates.
cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
for def_id in PrimitiveType::all_impls(cx.tcx) {
+ // Try to inline primitive impls from other crates.
if !def_id.is_local() {
inline::build_impl(cx, None, def_id, None, &mut new_items);
-
- // FIXME(eddyb) is this `doc(hidden)` check needed?
- if !cx.tcx.is_doc_hidden(def_id) {
+ }
+ }
+ for (prim, did) in PrimitiveType::primitive_locations(cx.tcx) {
+ // Do not calculate blanket impl list for docs that are not going to be rendered.
+ // While the `impl` blocks themselves are only in `libcore`, the module with `doc`
+ // attached is directly included in `libstd` as well.
+ if did.is_local() {
+ for def_id in prim.impls(cx.tcx) {
let impls = get_auto_trait_and_blanket_impls(cx, def_id);
new_items.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
}
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 fd336816c3a6d228dcef22171c43140f6fa7656f
+Subproject commit 326efc90ac5bf79a8fdd90898addf86bb6a6e404
--- /dev/null
+// assembly-output: ptx-linker
+// compile-flags: --crate-type cdylib -C target-cpu=sm_86
+// only-nvptx64
+// ignore-nvptx64
+
+// The following ABI tests are made with nvcc 11.6 does.
+//
+// The PTX ABI stability is tied to major versions of the PTX ISA
+// These tests assume major version 7
+//
+//
+// The following correspondence between types are assumed:
+// u<N> - uint<N>_t
+// i<N> - int<N>_t
+// [T, N] - std::array<T, N>
+// &T - T const*
+// &mut T - T*
+
+// CHECK: .version 7
+
+#![feature(abi_ptx, lang_items, no_core)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+#[repr(C)]
+pub struct SingleU8 {
+ f: u8,
+}
+
+#[repr(C)]
+pub struct DoubleU8 {
+ f: u8,
+ g: u8,
+}
+
+#[repr(C)]
+pub struct TripleU8 {
+ f: u8,
+ g: u8,
+ h: u8,
+}
+
+#[repr(C)]
+pub struct TripleU16 {
+ f: u16,
+ g: u16,
+ h: u16,
+}
+#[repr(C)]
+pub struct TripleU32 {
+ f: u32,
+ g: u32,
+ h: u32,
+}
+#[repr(C)]
+pub struct TripleU64 {
+ f: u64,
+ g: u64,
+ h: u64,
+}
+
+#[repr(C)]
+pub struct DoubleFloat {
+ f: f32,
+ g: f32,
+}
+
+#[repr(C)]
+pub struct TripleFloat {
+ f: f32,
+ g: f32,
+ h: f32,
+}
+
+#[repr(C)]
+pub struct TripleDouble {
+ f: f64,
+ g: f64,
+ h: f64,
+}
+
+#[repr(C)]
+pub struct ManyIntegers {
+ f: u8,
+ g: u16,
+ h: u32,
+ i: u64,
+}
+
+#[repr(C)]
+pub struct ManyNumerics {
+ f: u8,
+ g: u16,
+ h: u32,
+ i: u64,
+ j: f32,
+ k: f64,
+}
+
+// CHECK: .visible .entry f_u8_arg(
+// CHECK: .param .u8 f_u8_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u8_arg(_a: u8) {}
+
+// CHECK: .visible .entry f_u16_arg(
+// CHECK: .param .u16 f_u16_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u16_arg(_a: u16) {}
+
+// CHECK: .visible .entry f_u32_arg(
+// CHECK: .param .u32 f_u32_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u32_arg(_a: u32) {}
+
+// CHECK: .visible .entry f_u64_arg(
+// CHECK: .param .u64 f_u64_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u64_arg(_a: u64) {}
+
+// CHECK: .visible .entry f_u128_arg(
+// CHECK: .param .align 16 .b8 f_u128_arg_param_0[16]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u128_arg(_a: u128) {}
+
+// CHECK: .visible .entry f_i8_arg(
+// CHECK: .param .u8 f_i8_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_i8_arg(_a: i8) {}
+
+// CHECK: .visible .entry f_i16_arg(
+// CHECK: .param .u16 f_i16_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_i16_arg(_a: i16) {}
+
+// CHECK: .visible .entry f_i32_arg(
+// CHECK: .param .u32 f_i32_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_i32_arg(_a: i32) {}
+
+// CHECK: .visible .entry f_i64_arg(
+// CHECK: .param .u64 f_i64_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_i64_arg(_a: i64) {}
+
+// CHECK: .visible .entry f_i128_arg(
+// CHECK: .param .align 16 .b8 f_i128_arg_param_0[16]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_i128_arg(_a: i128) {}
+
+// CHECK: .visible .entry f_f32_arg(
+// CHECK: .param .f32 f_f32_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_f32_arg(_a: f32) {}
+
+// CHECK: .visible .entry f_f64_arg(
+// CHECK: .param .f64 f_f64_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_f64_arg(_a: f64) {}
+
+// CHECK: .visible .entry f_single_u8_arg(
+// CHECK: .param .align 1 .b8 f_single_u8_arg_param_0[1]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_single_u8_arg(_a: SingleU8) {}
+
+// CHECK: .visible .entry f_double_u8_arg(
+// CHECK: .param .align 1 .b8 f_double_u8_arg_param_0[2]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_double_u8_arg(_a: DoubleU8) {}
+
+// CHECK: .visible .entry f_triple_u8_arg(
+// CHECK: .param .align 1 .b8 f_triple_u8_arg_param_0[3]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_triple_u8_arg(_a: TripleU8) {}
+
+// CHECK: .visible .entry f_triple_u16_arg(
+// CHECK: .param .align 2 .b8 f_triple_u16_arg_param_0[6]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_triple_u16_arg(_a: TripleU16) {}
+
+// CHECK: .visible .entry f_triple_u32_arg(
+// CHECK: .param .align 4 .b8 f_triple_u32_arg_param_0[12]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_triple_u32_arg(_a: TripleU32) {}
+
+// CHECK: .visible .entry f_triple_u64_arg(
+// CHECK: .param .align 8 .b8 f_triple_u64_arg_param_0[24]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_triple_u64_arg(_a: TripleU64) {}
+
+// CHECK: .visible .entry f_many_integers_arg(
+// CHECK: .param .align 8 .b8 f_many_integers_arg_param_0[16]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_many_integers_arg(_a: ManyIntegers) {}
+
+// CHECK: .visible .entry f_double_float_arg(
+// CHECK: .param .align 4 .b8 f_double_float_arg_param_0[8]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_double_float_arg(_a: DoubleFloat) {}
+
+// CHECK: .visible .entry f_triple_float_arg(
+// CHECK: .param .align 4 .b8 f_triple_float_arg_param_0[12]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_triple_float_arg(_a: TripleFloat) {}
+
+// CHECK: .visible .entry f_triple_double_arg(
+// CHECK: .param .align 8 .b8 f_triple_double_arg_param_0[24]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_triple_double_arg(_a: TripleDouble) {}
+
+// CHECK: .visible .entry f_many_numerics_arg(
+// CHECK: .param .align 8 .b8 f_many_numerics_arg_param_0[32]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_many_numerics_arg(_a: ManyNumerics) {}
+
+// CHECK: .visible .entry f_byte_array_arg(
+// CHECK: .param .align 1 .b8 f_byte_array_arg_param_0[5]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_byte_array_arg(_a: [u8; 5]) {}
+
+// CHECK: .visible .entry f_float_array_arg(
+// CHECK: .param .align 4 .b8 f_float_array_arg_param_0[20]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_float_array_arg(_a: [f32; 5]) {}
+
+// CHECK: .visible .entry f_u128_array_arg(
+// CHECK: .param .align 16 .b8 f_u128_array_arg_param_0[80]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u128_array_arg(_a: [u128; 5]) {}
+
+// CHECK: .visible .entry f_u32_slice_arg(
+// CHECK: .param .u64 f_u32_slice_arg_param_0
+// CHECK: .param .u64 f_u32_slice_arg_param_1
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u32_slice_arg(_a: &[u32]) {}
+
+// CHECK: .visible .entry f_tuple_u8_u8_arg(
+// CHECK: .param .align 1 .b8 f_tuple_u8_u8_arg_param_0[2]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_tuple_u8_u8_arg(_a: (u8, u8)) {}
+
+// CHECK: .visible .entry f_tuple_u32_u32_arg(
+// CHECK: .param .align 4 .b8 f_tuple_u32_u32_arg_param_0[8]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_tuple_u32_u32_arg(_a: (u32, u32)) {}
+
+
+// CHECK: .visible .entry f_tuple_u8_u8_u32_arg(
+// CHECK: .param .align 4 .b8 f_tuple_u8_u8_u32_arg_param_0[8]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_tuple_u8_u8_u32_arg(_a: (u8, u8, u32)) {}
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;
-// compile-flags: -Z panic-in-drop=abort -O -Z new-llvm-pass-manager=no
+// compile-flags: -Z panic-in-drop=abort -O
+// ignore-msvc
// Ensure that unwinding code paths are eliminated from the output after
// optimization.
-// This test uses -Z new-llvm-pass-manager=no, because the expected optimization does not happen
-// on targets using SEH exceptions (i.e. MSVC) anymore. The core issue is that Rust promises that
-// the drop_in_place() function can't unwind, but implements it in a way that *can*, because we
-// currently go out of our way to allow longjmps, which also use the unwinding mechanism on MSVC
-// targets. We should either forbid longjmps, or not assume nounwind, making this optimization
-// incompatible with the current behavior of running cleanuppads on longjmp unwinding.
+// This test uses ignore-msvc, because the expected optimization does not happen on targets using
+// SEH exceptions with the new LLVM pass manager anymore, see
+// https://github.com/llvm/llvm-project/issues/51311.
// CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output
#[no_mangle]
fn into_error(self, error: Self::Source) -> Error {
Error::Api {
- source: (|v| v)(error),
+ source: error,
}
}
}
--- /dev/null
+// compile-flags:-g
+
+// We only test Rust-aware versions of GDB:
+// min-gdb-version: 8.2
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command: run
+
+// gdb-command: print _ref
+// gdb-check: $1 = (*mut ()) 0x[...]
+
+// gdb-command: print _ptr
+// gdb-check: $2 = (*mut ()) 0x[...]
+
+// gdb-command: print _local
+// gdb-check: $3 = ()
+
+// gdb-command: print _field
+// gdb-check: $4 = unit_type::_TypeContainingUnitField {_a: 123, _unit: (), _b: 456}
+
+// Check that we can cast "void pointers" to their actual type in the debugger
+// gdb-command: print /x *(_ptr as *const u64)
+// gdb-check: $5 = 0x1122334455667788
+
+// === CDB TESTS ===================================================================================
+
+// cdb-command: g
+// cdb-check: Breakpoint 0 hit
+
+// cdb-command: dx _ref
+// cdb-check: _ref : 0x[...] : () [Type: tuple$<> *]
+
+// cdb-command: dx _ptr
+// cdb-check: _ptr : 0x[...] : () [Type: tuple$<> *]
+
+// cdb-command: dx _local
+// cdb-check: _local : () [Type: tuple$<>]
+
+// cdb-command: dx _field,d
+// cdb-check: _field,d [Type: unit_type::_TypeContainingUnitField]
+// cdb-check: [+0x[...]] _a : 123 [Type: unsigned int]
+// cdb-check: [+0x[...]] _unit : () [Type: tuple$<>]
+// cdb-check: [+0x[...]] _b : 456 [Type: unsigned __int64]
+
+// Check that we can cast "void pointers" to their actual type in the debugger
+// cdb-command: dx ((__int64 *)_ptr),x
+// cdb-check: ((__int64 *)_ptr),x : 0x[...] : 0x1122334455667788 [Type: __int64 *]
+// cdb-check: 0x1122334455667788 [Type: __int64]
+
+struct _TypeContainingUnitField {
+ _a: u32,
+ _unit: (),
+ _b: u64,
+}
+
+fn foo(_ref: &(), _ptr: *const ()) {
+ let _local = ();
+ let _field = _TypeContainingUnitField { _a: 123, _unit: (), _b: 456 };
+
+ zzz(); // #break
+}
+
+fn main() {
+ let pointee = 0x1122_3344_5566_7788i64;
+
+ foo(&(), &pointee as *const i64 as *const ());
+}
+
+#[inline(never)]
+fn zzz() {}
// Change enum visibility -----------------------------------------------------
#[cfg(any(cfail1,cfail4))]
-enum EnumVisibility { A }
+enum EnumVisibility { A }
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
-pub enum EnumVisibility {
- A
-}
+pub enum EnumVisibility { A }
// Change Method Privacy -------------------------------------------------------
#[cfg(any(cfail1,cfail4))]
impl Foo {
- //------------------------------------------------------------------------------
+ //----------------------------------------------------
//--------------------------
//------------------------------------------------------------------------------
//--------------------------
#[rustc_clean(cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
impl Foo {
- #[rustc_clean(cfg="cfail2", except="associated_item,hir_owner,hir_owner_nodes")]
+ #[rustc_clean(cfg="cfail2", except="associated_item")]
#[rustc_clean(cfg="cfail3")]
- #[rustc_clean(cfg="cfail5", except="associated_item,hir_owner,hir_owner_nodes")]
+ #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,associated_item")]
#[rustc_clean(cfg="cfail6")]
fn method_privacy() { }
}
// Change static visibility
#[cfg(any(cfail1,cfail4))]
-static STATIC_VISIBILITY: u8 = 0;
+static STATIC_VISIBILITY: u8 = 0;
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
// Tuple Struct Field Visibility -----------------------------------------------
#[cfg(any(cfail1,cfail4))]
-struct TupleStructFieldVisibility(char);
+struct TupleStructFieldVisibility( char);
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="type_of")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")]
#[rustc_clean(cfg="cfail6")]
struct TupleStructFieldVisibility(pub char);
// Record Struct Field Visibility ----------------------------------------------
#[cfg(any(cfail1,cfail4))]
-struct RecordStructFieldVisibility { x: f32 }
+struct RecordStructFieldVisibility { x: f32 }
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="type_of")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")]
#[rustc_clean(cfg="cfail6")]
-struct RecordStructFieldVisibility {
- pub x: f32
-}
+struct RecordStructFieldVisibility { pub x: f32 }
// Add Lifetime Parameter ------------------------------------------------------
// Visibility ------------------------------------------------------------------
#[cfg(any(cfail1,cfail4))]
-struct Visibility;
+struct Visibility;
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
pub struct Visibility;
trait TraitVisibility { }
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
pub trait TraitVisibility { }
-// compile-flags: -C opt-level=0 -Z inline_mir=no
+// unit-test: InstCombine
// ignore-wasm32 compiled with panic=abort by default
// EMIT_MIR combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
}
bb0: {
+ StorageLive(_2); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
_2 = &((*_1).0: T); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ StorageLive(_3); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
_3 = &((*_1).1: u64); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+ StorageLive(_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
_4 = &((*_1).2: [f32; 3]); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+ StorageLive(_5); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ StorageLive(_6); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ StorageLive(_7); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
- _7 = &(*_2); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
- _6 = &(*_7); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ _7 = _2; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
}
bb1: {
+ StorageDead(_6); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:8: 8:9
+ StorageLive(_8); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+ StorageLive(_9); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+ StorageLive(_10); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
- _10 = &(*_3); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
- _9 = &(*_10); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
- _8 = <u64 as Clone>::clone(move _9) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
}
bb2: {
+ StorageDead(_9); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:10: 9:11
+ StorageLive(_11); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+ StorageLive(_12); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+ StorageLive(_13); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
- _13 = &(*_4); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
- _12 = &(*_13); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
- _11 = <[f32; 3] as Clone>::clone(move _12) -> [return: bb3, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
}
bb3: {
+ StorageDead(_12); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:15: 10:16
Deinit(_0); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
(_0.0: T) = move _5; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
(_0.1: u64) = move _8; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
(_0.2: [f32; 3]) = move _11; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+ StorageDead(_13); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+ StorageDead(_11); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+ StorageDead(_10); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+ StorageDead(_8); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+ StorageDead(_7); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+ StorageDead(_5); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+ StorageDead(_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+ StorageDead(_3); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+ StorageDead(_2); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
return; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:15: 6:15
}
--- /dev/null
+- // MIR for `main` before Derefer
++ // MIR for `main` after Derefer
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/derefer_complex_case.rs:3:11: 3:11
+ let mut _1: std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ let mut _2: &[i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ let _3: [i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:4:18: 4:26
+ let mut _4: std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ let mut _5: (); // in scope 0 at $DIR/derefer_complex_case.rs:3:1: 5:2
+ let _6: (); // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ let mut _7: std::option::Option<&i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ let mut _8: &mut std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ let mut _9: &mut std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ let mut _10: isize; // in scope 0 at $DIR/derefer_complex_case.rs:4:5: 4:40
+ let mut _11: !; // in scope 0 at $DIR/derefer_complex_case.rs:4:5: 4:40
+ let mut _13: i32; // in scope 0 at $DIR/derefer_complex_case.rs:4:34: 4:37
+ let mut _14: &[i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
++ let mut _15: &i32; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ scope 1 {
+ debug iter => _4; // in scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ let _12: i32; // in scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
+ scope 2 {
+ debug foo => _12; // in scope 2 at $DIR/derefer_complex_case.rs:4:10: 4:13
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ StorageLive(_2); // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ _14 = const main::promoted[0]; // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ // mir::Constant
+ // + span: $DIR/derefer_complex_case.rs:4:17: 4:26
+ // + literal: Const { ty: &[i32; 2], val: Unevaluated(main, [], Some(promoted[0])) }
+ _2 = &(*_14); // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ _1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> bb1; // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ // mir::Constant
+ // + span: $DIR/derefer_complex_case.rs:4:17: 4:26
+ // + literal: Const { ty: fn(&[i32; 2]) -> <&[i32; 2] as IntoIterator>::IntoIter {<&[i32; 2] as IntoIterator>::into_iter}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+ StorageDead(_2); // scope 0 at $DIR/derefer_complex_case.rs:4:25: 4:26
+ StorageLive(_4); // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ _4 = move _1; // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ goto -> bb2; // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40
+ }
+
+ bb2: {
+ StorageLive(_6); // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ StorageLive(_7); // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ StorageLive(_8); // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ StorageLive(_9); // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ _9 = &mut _4; // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ _8 = &mut (*_9); // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ _7 = <std::slice::Iter<i32> as Iterator>::next(move _8) -> bb3; // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ // mir::Constant
+ // + span: $DIR/derefer_complex_case.rs:4:17: 4:26
+ // + literal: Const { ty: for<'r> fn(&'r mut std::slice::Iter<i32>) -> Option<<std::slice::Iter<i32> as Iterator>::Item> {<std::slice::Iter<i32> as Iterator>::next}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb3: {
+ StorageDead(_8); // scope 1 at $DIR/derefer_complex_case.rs:4:25: 4:26
+ _10 = discriminant(_7); // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ }
+
+ bb4: {
+ StorageLive(_12); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
+- _12 = (*((_7 as Some).0: &i32)); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
++ StorageLive(_15); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
++ _15 = move ((_7 as Some).0: &i32); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
++ _12 = (*_15); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
++ StorageDead(_15); // scope 2 at $DIR/derefer_complex_case.rs:4:34: 4:37
+ StorageLive(_13); // scope 2 at $DIR/derefer_complex_case.rs:4:34: 4:37
+ _13 = _12; // scope 2 at $DIR/derefer_complex_case.rs:4:34: 4:37
+ _6 = std::mem::drop::<i32>(move _13) -> bb7; // scope 2 at $DIR/derefer_complex_case.rs:4:29: 4:38
+ // mir::Constant
+ // + span: $DIR/derefer_complex_case.rs:4:29: 4:33
+ // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb5: {
+ unreachable; // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+ }
+
+ bb6: {
+ _0 = const (); // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40
+ StorageDead(_9); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+ StorageDead(_7); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+ StorageDead(_6); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+ StorageDead(_4); // scope 0 at $DIR/derefer_complex_case.rs:4:39: 4:40
+ StorageDead(_1); // scope 0 at $DIR/derefer_complex_case.rs:4:39: 4:40
+ return; // scope 0 at $DIR/derefer_complex_case.rs:5:2: 5:2
+ }
+
+ bb7: {
+ StorageDead(_13); // scope 2 at $DIR/derefer_complex_case.rs:4:37: 4:38
+ StorageDead(_12); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+ StorageDead(_9); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+ StorageDead(_7); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+ StorageDead(_6); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+ _5 = const (); // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40
+ goto -> bb2; // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40
++ }
++
++ bb8 (cleanup): {
++ resume; // scope 0 at $DIR/derefer_complex_case.rs:3:1: 5:2
+ }
+ }
+
--- /dev/null
+// EMIT_MIR derefer_complex_case.main.Derefer.diff
+
+fn main() {
+ for &foo in &[42, 43] { drop(foo) }
+}
--- /dev/null
+- // MIR for `main` before Derefer
++ // MIR for `main` after Derefer
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/derefer_terminator_test.rs:2:11: 2:11
+ let _1: bool; // in scope 0 at $DIR/derefer_terminator_test.rs:3:9: 3:10
+ let _3: (); // in scope 0 at $DIR/derefer_terminator_test.rs:5:5: 8:6
+ let mut _4: &&&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:15: 5:22
+ let _5: &&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:17: 5:21
+ let _6: &&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:18: 5:21
+ let _7: &bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:19: 5:21
++ let mut _10: &&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:15: 5:22
++ let mut _11: &&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:15: 5:22
++ let mut _12: &bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:15: 5:22
+ scope 1 {
+ debug b => _1; // in scope 1 at $DIR/derefer_terminator_test.rs:3:9: 3:10
+ let _2: bool; // in scope 1 at $DIR/derefer_terminator_test.rs:4:9: 4:10
+ scope 2 {
+ debug d => _2; // in scope 2 at $DIR/derefer_terminator_test.rs:4:9: 4:10
+ let _8: i32; // in scope 2 at $DIR/derefer_terminator_test.rs:6:22: 6:23
+ let _9: i32; // in scope 2 at $DIR/derefer_terminator_test.rs:9:9: 9:10
+ scope 3 {
+ debug x => _8; // in scope 3 at $DIR/derefer_terminator_test.rs:6:22: 6:23
+ }
+ scope 4 {
+ debug y => _9; // in scope 4 at $DIR/derefer_terminator_test.rs:9:9: 9:10
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/derefer_terminator_test.rs:3:9: 3:10
+ _1 = foo() -> bb1; // scope 0 at $DIR/derefer_terminator_test.rs:3:13: 3:18
+ // mir::Constant
+ // + span: $DIR/derefer_terminator_test.rs:3:13: 3:16
+ // + literal: Const { ty: fn() -> bool {foo}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+ StorageLive(_2); // scope 1 at $DIR/derefer_terminator_test.rs:4:9: 4:10
+ _2 = foo() -> bb2; // scope 1 at $DIR/derefer_terminator_test.rs:4:13: 4:18
+ // mir::Constant
+ // + span: $DIR/derefer_terminator_test.rs:4:13: 4:16
+ // + literal: Const { ty: fn() -> bool {foo}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb2: {
+ StorageLive(_3); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 8:6
+ StorageLive(_4); // scope 2 at $DIR/derefer_terminator_test.rs:5:15: 5:22
+ StorageLive(_5); // scope 2 at $DIR/derefer_terminator_test.rs:5:17: 5:21
+ StorageLive(_6); // scope 2 at $DIR/derefer_terminator_test.rs:5:18: 5:21
+ StorageLive(_7); // scope 2 at $DIR/derefer_terminator_test.rs:5:19: 5:21
+ _7 = &_1; // scope 2 at $DIR/derefer_terminator_test.rs:5:19: 5:21
+ _6 = &_7; // scope 2 at $DIR/derefer_terminator_test.rs:5:18: 5:21
+ _5 = &_6; // scope 2 at $DIR/derefer_terminator_test.rs:5:17: 5:21
+ _4 = &_5; // scope 2 at $DIR/derefer_terminator_test.rs:5:15: 5:22
+- switchInt((*(*(*(*_4))))) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++ StorageLive(_10); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++ _10 = move (*_4); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++ StorageLive(_11); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++ _11 = move (*_10); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++ StorageDead(_10); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++ StorageLive(_12); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++ _12 = move (*_11); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++ StorageDead(_11); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++ switchInt((*_12)) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
+ }
+
+ bb3: {
++ StorageDead(_12); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
+ _3 = const (); // scope 2 at $DIR/derefer_terminator_test.rs:7:18: 7:20
+ goto -> bb5; // scope 2 at $DIR/derefer_terminator_test.rs:7:18: 7:20
+ }
+
+ bb4: {
++ StorageDead(_12); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
+ StorageLive(_8); // scope 2 at $DIR/derefer_terminator_test.rs:6:22: 6:23
+ _8 = const 5_i32; // scope 2 at $DIR/derefer_terminator_test.rs:6:26: 6:27
+ _3 = const (); // scope 2 at $DIR/derefer_terminator_test.rs:6:17: 6:29
+ StorageDead(_8); // scope 2 at $DIR/derefer_terminator_test.rs:6:28: 6:29
+ goto -> bb5; // scope 2 at $DIR/derefer_terminator_test.rs:6:28: 6:29
+ }
+
+ bb5: {
+ StorageDead(_7); // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6
+ StorageDead(_6); // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6
+ StorageDead(_5); // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6
+ StorageDead(_4); // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6
+ StorageDead(_3); // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6
+ StorageLive(_9); // scope 2 at $DIR/derefer_terminator_test.rs:9:9: 9:10
+ _9 = const 42_i32; // scope 2 at $DIR/derefer_terminator_test.rs:9:13: 9:15
+ _0 = const (); // scope 0 at $DIR/derefer_terminator_test.rs:2:11: 10:2
+ StorageDead(_9); // scope 2 at $DIR/derefer_terminator_test.rs:10:1: 10:2
+ StorageDead(_2); // scope 1 at $DIR/derefer_terminator_test.rs:10:1: 10:2
+ StorageDead(_1); // scope 0 at $DIR/derefer_terminator_test.rs:10:1: 10:2
+ return; // scope 0 at $DIR/derefer_terminator_test.rs:10:2: 10:2
++ }
++
++ bb6 (cleanup): {
++ resume; // scope 0 at $DIR/derefer_terminator_test.rs:2:1: 10:2
+ }
+ }
+
--- /dev/null
+// EMIT_MIR derefer_terminator_test.main.Derefer.diff
+fn main() {
+ let b = foo();
+ let d = foo();
+ match ****(&&&&b) {
+ true => {let x = 5;},
+ false => {}
+ }
+ let y = 42;
+}
+
+fn foo() -> bool {
+ true
+}
let mut _0: (); // return place in scope 0 at $DIR/derefer_test.rs:2:11: 2:11
let mut _1: (i32, i32); // in scope 0 at $DIR/derefer_test.rs:3:9: 3:14
let mut _3: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:4:22: 4:28
-+ let mut _6: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:5:13: 5:26
-+ let mut _7: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:6:13: 6:26
++ let mut _6: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:4:9: 4:14
++ let mut _7: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:4:9: 4:14
scope 1 {
debug a => _1; // in scope 1 at $DIR/derefer_test.rs:3:9: 3:14
let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test.rs:4:9: 4:14
let mut _3: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:4:22: 4:28
let mut _5: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:5:22: 5:28
let mut _7: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:22: 6:28
-+ let mut _10: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30
-+ let mut _11: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30
-+ let mut _12: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30
-+ let mut _13: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30
-+ let mut _14: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30
-+ let mut _15: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++ let mut _10: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14
++ let mut _11: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14
++ let mut _12: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14
++ let mut _13: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14
++ let mut _14: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14
++ let mut _15: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14
scope 1 {
debug a => _1; // in scope 1 at $DIR/derefer_test_multiple.rs:3:9: 3:14
let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14
+ _10 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
+ StorageLive(_11); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
+ _11 = move ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++ StorageDead(_10); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
+ StorageLive(_12); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
+ _12 = move ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++ StorageDead(_11); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
+ _8 = &mut ((*_12).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
-+ StorageDead(_10); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
-+ StorageDead(_11); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
+ StorageDead(_12); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
StorageLive(_9); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
- _9 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
+ _13 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
+ StorageLive(_14); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
+ _14 = move ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++ StorageDead(_13); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
+ StorageLive(_15); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
+ _15 = move ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++ StorageDead(_14); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
+ _9 = &mut ((*_15).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
-+ StorageDead(_13); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
-+ StorageDead(_14); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
+ StorageDead(_15); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
_0 = const (); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
StorageDead(_9); // scope 5 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+ bb3: {
StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:8:1: 8:2
return; // scope 0 at $DIR/early_otherwise_branch.rs:8:2: 8:2
-+ }
-+
+ }
+
+- bb5 (cleanup): {
+- resume; // scope 0 at $DIR/early_otherwise_branch.rs:3:1: 8:2
+ bb4: {
+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
+ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17
StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17
_8 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17
-- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb7]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
+- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
+ _11 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
+ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
return; // scope 0 at $DIR/early_otherwise_branch.rs:17:2: 17:2
}
-- bb7: {
-- unreachable; // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15
+- bb7 (cleanup): {
+- resume; // scope 0 at $DIR/early_otherwise_branch.rs:11:1: 17:2
+ bb5: {
+ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
+ switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
+ bb3: {
StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:26:1: 26:2
return; // scope 0 at $DIR/early_otherwise_branch.rs:26:2: 26:2
-+ }
-+
+ }
+
+- bb5 (cleanup): {
+- resume; // scope 0 at $DIR/early_otherwise_branch.rs:21:1: 26:2
+ bb4: {
+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
+ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
-// compile-flags: -Z mir-opt-level=4 -Z unsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
// EMIT_MIR early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
fn opt1(x: Option<u32>, y: Option<u32>) -> u32 {
match (x, y) {
+ bb4: {
StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:1: 9:2
return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:2: 9:2
-+ }
-+
+ }
+
+- bb6 (cleanup): {
+- resume; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:1: 9:2
+ bb5: {
+ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
+ switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
-// compile-flags: -Z mir-opt-level=4 -Z unsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
// EMIT_MIR early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
fn opt1(x: Option<u32>, y: Option<u32>, z: Option<u32>) -> u32 {
let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28
let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
-+ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ let mut _34: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _35: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _36: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _37: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _38: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _39: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _40: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _41: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _42: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _43: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _44: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _45: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _46: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
scope 1 {
- debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
- debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
- _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb11]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ _35 = Ne(_11, move _34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _34 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
}
bb1: {
-- _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-- }
--
-- bb2: {
-+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _35 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _7 = discriminant((*_35)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ }
+
+ bb2: {
StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
-- nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
-- nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:27: 26:28
- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
}
-+ bb2: {
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-+ _15 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-+ _16 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
-+ ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
-+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
-+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+ }
-+
bb3: {
-- _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-+ _20 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-+ _21 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
-+ ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
-+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
-+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+ StorageLive(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _36 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _8 = discriminant((*_36)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ StorageDead(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
}
bb4: {
-- _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-+ _25 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-+ _26 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
-+ ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
-+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
-+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+ StorageLive(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _37 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _9 = discriminant((*_37)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ StorageDead(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
}
bb5: {
-- _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-+ _30 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-+ _31 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
-+ ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
-+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
-+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+ StorageLive(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _38 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _10 = discriminant((*_38)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ StorageDead(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
}
bb6: {
- StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-- _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+ StorageLive(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+ _39 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+- _12 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
++ _15 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+ StorageDead(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
- StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-- _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+ StorageLive(_40); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+ _40 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+- _13 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
++ _16 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+ StorageDead(_40); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
- StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
- StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
- _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
- StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
- StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
- StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-- }
--
-- bb7: {
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
++ ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
++ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
+ goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
+ }
+
+ bb7: {
- StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-- _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+ StorageLive(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+ _41 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+- _17 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
++ _20 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+ StorageDead(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
- StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-- _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+ StorageLive(_42); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+ _42 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+- _18 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
++ _21 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+ StorageDead(_42); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
- StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
- StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
- _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
- StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
- StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
- StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-- }
--
-- bb8: {
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
++ ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
++ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+ goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+ }
+
+ bb8: {
- StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-- _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+ StorageLive(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+ _43 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+- _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
++ _25 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+ StorageDead(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
- StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-- _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+ StorageLive(_44); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+ _44 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+- _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
++ _26 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+ StorageDead(_44); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
- StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
- StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
- _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
- StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
- StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
- StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-- }
--
-- bb9: {
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
++ ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
++ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+ goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+ }
+
+ bb9: {
- StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-- _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+ StorageLive(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+ _45 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+- _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
++ _30 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+ StorageDead(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
- StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-- _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+ StorageLive(_46); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+ _46 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+- _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
++ _31 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+ StorageDead(_46); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
- StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
- StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
- _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
- StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
- StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
- StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-- }
--
-- bb10: {
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
++ ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
++ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+ goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+ }
+
+ bb10: {
Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
- ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
}
-
-- bb11: {
-- unreachable; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
-+ bb7: {
-+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
- }
}
let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28
let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
-+ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ let mut _34: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _35: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _36: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _37: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _38: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _39: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _40: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _41: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _42: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _43: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _44: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _45: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _46: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
scope 1 {
debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
(_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
- _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb11]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ _35 = Ne(_11, move _34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _34 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
}
bb1: {
-- _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-- }
--
-- bb2: {
-+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _35 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _7 = discriminant((*_35)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ }
+
+ bb2: {
StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
-- nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
-- nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:27: 26:28
StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
}
-- bb3: {
-- _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-- }
--
-- bb4: {
-- _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-- }
--
-- bb5: {
-- _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-- }
--
-- bb6: {
-+ bb2: {
+ bb3: {
+ StorageLive(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _36 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _8 = discriminant((*_36)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ StorageDead(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ }
+
+ bb4: {
+ StorageLive(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _37 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _9 = discriminant((*_37)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ StorageDead(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ }
+
+ bb5: {
+ StorageLive(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _38 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ _10 = discriminant((*_38)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ StorageDead(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ }
+
+ bb6: {
StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
- _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+ StorageLive(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+ _39 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+ _12 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+ StorageDead(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
- _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+ StorageLive(_40); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+ _40 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+ _13 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+ StorageDead(_40); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
_15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
+ goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
}
-- bb7: {
-+ bb3: {
+ bb7: {
StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
- _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+ StorageLive(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+ _41 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+ _17 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+ StorageDead(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
- _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+ StorageLive(_42); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+ _42 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+ _18 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+ StorageDead(_42); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
_20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+ goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
}
-- bb8: {
-+ bb4: {
+ bb8: {
StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
- _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+ StorageLive(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+ _43 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+ _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+ StorageDead(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
- _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+ StorageLive(_44); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+ _44 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+ _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+ StorageDead(_44); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
_25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+ goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
}
-- bb9: {
-+ bb5: {
+ bb9: {
StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
- _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+ StorageLive(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+ _45 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+ _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+ StorageDead(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
- _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+ StorageLive(_46); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+ _46 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+ _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+ StorageDead(_46); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
_30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+ goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
}
-- bb10: {
-+ bb6: {
+ bb10: {
Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
}
-
-- bb11: {
-- unreachable; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
-+ bb7: {
-+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
- }
}
StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17
StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17
_8 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
- switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
+ switchInt(move _8) -> [0_isize: bb1, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
}
bb1: {
_6 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
- switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
+ switchInt(move _6) -> [0_isize: bb2, 1_isize: bb7, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
}
bb2: {
_0 = const 3_u32; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26
- goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26
+ goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26
}
bb3: {
- _7 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
- switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
+ unreachable; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
}
bb4: {
+ _7 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
+ switchInt(move _7) -> [0_isize: bb6, 1_isize: bb5, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
+ }
+
+ bb5: {
StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16
_9 = (((_3.0: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16
StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25
_0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
- goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
+ goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
}
- bb5: {
+ bb6: {
StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16
_11 = (((_3.0: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16
_0 = const 1_u32; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
- goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
+ goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
}
- bb6: {
+ bb7: {
StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22
_12 = (((_3.1: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22
_0 = const 2_u32; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
- goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
+ goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
}
- bb7: {
+ bb8: {
StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:1: 14:2
return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:2: 14:2
}
+
+ bb9 (cleanup): {
+ resume; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:1: 14:2
+ }
}
-// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
// must not optimize as it does not follow the pattern of
// left and right hand side being the same variant
bb1: {
_0 = const 0_i32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15
- return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15
+ goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15
}
bb2: {
bb3: {
_0 = const 0_i32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19
- return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19
+ goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19
}
bb4: {
_5 = (((*_2) as Some).0: i32); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19
_0 = _5; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
- return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
+ goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
+ }
+
+ bb5: {
+ return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:27:2: 27:2
+ }
+
+ bb6 (cleanup): {
+ resume; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:1: 27:2
}
}
let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:26: 12:29
let mut _2: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:20: 13:30
let mut _3: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+ let mut _4: &E; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:16: 12:17
bb0: {
_3 = discriminant((*_1)); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
}
bb1: {
- _2 = discriminant((*(((*_1) as Some).0: &E))); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+ StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+ _4 = move (((*_1) as Some).0: &E); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+ _2 = discriminant((*_4)); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+ StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
switchInt(move _2) -> [1_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
}
bb2: {
_0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:38: 13:39
- return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
+ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
}
bb3: {
_0 = const 2_u32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:49: 13:50
- return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
+ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
+ }
+
+ bb4: {
+ return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:14:2: 14:2
+ }
+
+ bb5 (cleanup): {
+ resume; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:1: 14:2
}
}
-// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
// Tests various cases that the `early_otherwise_branch` opt should *not* optimize
-// compile-flags: -O
+// unit-test: SimplifyComparisonIntegral
// EMIT_MIR if_condition_int.opt_u32.SimplifyComparisonIntegral.diff
// EMIT_MIR if_condition_int.opt_negative.SimplifyComparisonIntegral.diff
// EMIT_MIR if_condition_int.opt_char.SimplifyComparisonIntegral.diff
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:17:25: 17:26
return; // scope 0 at $DIR/if-condition-int.rs:18:2: 18:2
}
+
+ bb4 (cleanup): {
+ resume; // scope 0 at $DIR/if-condition-int.rs:16:1: 18:2
+ }
}
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:53:34: 53:35
return; // scope 0 at $DIR/if-condition-int.rs:54:2: 54:2
}
+
+ bb4 (cleanup): {
+ resume; // scope 0 at $DIR/if-condition-int.rs:52:1: 54:2
+ }
}
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:49:1: 49:2
return; // scope 0 at $DIR/if-condition-int.rs:49:2: 49:2
}
+
+ bb4 (cleanup): {
+ resume; // scope 0 at $DIR/if-condition-int.rs:43:1: 49:2
+ }
}
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:21:32: 21:33
return; // scope 0 at $DIR/if-condition-int.rs:22:2: 22:2
}
+
+ bb4 (cleanup): {
+ resume; // scope 0 at $DIR/if-condition-int.rs:20:1: 22:2
+ }
}
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:25:31: 25:32
return; // scope 0 at $DIR/if-condition-int.rs:26:2: 26:2
}
+
+ bb4 (cleanup): {
+ resume; // scope 0 at $DIR/if-condition-int.rs:24:1: 26:2
+ }
}
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:39:5: 39:6
return; // scope 0 at $DIR/if-condition-int.rs:40:2: 40:2
}
+
+ bb7 (cleanup): {
+ resume; // scope 0 at $DIR/if-condition-int.rs:32:1: 40:2
+ }
}
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:29:32: 29:33
return; // scope 0 at $DIR/if-condition-int.rs:30:2: 30:2
}
+
+ bb4 (cleanup): {
+ resume; // scope 0 at $DIR/if-condition-int.rs:28:1: 30:2
+ }
}
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:12:31: 12:32
return; // scope 0 at $DIR/if-condition-int.rs:13:2: 13:2
}
+
+ bb4 (cleanup): {
+ resume; // scope 0 at $DIR/if-condition-int.rs:11:1: 13:2
+ }
}
debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline-closure-captures.rs:10:17: 10:18
let mut _10: i32; // in scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
let mut _11: T; // in scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+ let mut _12: &i32; // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:24
+ let mut _13: &T; // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:24
}
}
StorageLive(_9); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
_9 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
StorageLive(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
- _10 = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
+ StorageLive(_12); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
+ _12 = move ((*_6).0: &i32); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
+ _10 = (*_12); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
+ StorageDead(_12); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
StorageLive(_11); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
- _11 = (*((*_6).1: &T)); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+ StorageLive(_13); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+ _13 = move ((*_6).1: &T); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+ _11 = (*_13); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+ StorageDead(_13); // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
Deinit(_0); // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
(_0.0: i32) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
(_0.1: T) = move _11; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
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>)) }
-// compile-flags: -Z mir-opt-level=3
+// unit-test: LowerSliceLenCalls
// EMIT_MIR lower_slice_len.bound.LowerSliceLenCalls.diff
pub fn bound(index: usize, slice: &[u8]) -> u8 {
| '_#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
-// compile-flags: -Zmir-opt-level=1
+// unit-test: RenameReturnPlace
// EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff
fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] {
- StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:8:1: 8:2
return; // scope 0 at $DIR/nrvo-simple.rs:8:2: 8:2
}
+
+ bb2 (cleanup): {
+ resume; // scope 0 at $DIR/nrvo-simple.rs:4:1: 8:2
+ }
}
| '_#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
// pretty-mode:hir
// pp-exact:hir-pretty-loop.pp
-pub fn foo() { loop { break; } }
+fn foo() { loop { break; } }
// #4264 fixed-length vector types
-pub fn foo(_: [i32; (3 as usize)]) ({ } as ())
+fn foo(_: [i32; (3 as usize)]) ({ } as ())
-pub fn bar() ({
+fn bar() ({
const FOO: usize = ((5 as usize) - (4 as usize) as usize);
let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]);
(res as String)
} as String);
} as ())
-pub type Foo = [i32; (3 as usize)];
-pub struct Bar {
- pub x: [i32; (3 as usize)],
+type Foo = [i32; (3 as usize)];
+struct Bar {
+ x: [i32; (3 as usize)],
}
-pub struct TupleBar([i32; (4 as usize)]);
-pub enum Baz { BazVariant([i32; (5 as usize)]), }
-pub fn id<T>(x: T) -> T ({ (x as T) } as T)
-pub fn use_id() ({
+struct TupleBar([i32; (4 as usize)]);
+enum Baz { BazVariant([i32; (5 as usize)]), }
+fn id<T>(x: T) -> T ({ (x as T) } as T)
+fn use_id() ({
let _ =
((id::<[i32; (3 as usize)]> as
fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32),
let mut contents = Vec::new();
File::open(path).unwrap().read_to_end(&mut contents).unwrap();
+ // This file is produced during linking in a temporary directory.
+ let arg = if arg.ends_with("/symbols.o") || arg.ends_with("\\symbols.o") {
+ "symbols.o"
+ } else {
+ &*arg
+ };
out.push_str(&format!("{}: {}\n", arg, hash(&contents)));
}
# Check that a Rust dylib does not export generics if -Zshare-generics=no
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_generic_function_from_rlib)" -eq "0" ]
+# FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
+ifndef IS_WINDOWS
# Check that an executable does not export any dynamic symbols
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "0" ]
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_rust_function_from_exe)" -eq "0" ]
+endif
# Check the combined case, where we generate a cdylib and an rlib in the same
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_rust_function_from_rlib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_generic_function_from_rlib)" -eq "1" ]
+ifndef IS_WINDOWS
# Check that an executable does not export any dynamic symbols
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "0" ]
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_rust_function_from_exe)" -eq "0" ]
+endif
[ -e $(INVOCATION_ONLY)/x/index.html ]
[ -e $(INVOCATION_ONLY)/theme-xxx.css ] # generated from z.css
! [ -e $(INVOCATION_ONLY)/storage-xxx.js ]
- ! [ -e $(INVOCATION_ONLY)/SourceSerif4-It.ttf.woff ]
+ ! [ -e $(INVOCATION_ONLY)/SourceSerif4-It.ttf.woff2 ]
# FIXME: this probably shouldn't have a suffix
[ -e $(INVOCATION_ONLY)/y-xxx.css ]
toolchain-only:
$(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources --output $(TOOLCHAIN_ONLY) --resource-suffix=-xxx --extend-css z.css x.rs
[ -e $(TOOLCHAIN_ONLY)/storage-xxx.js ]
- ! [ -e $(TOOLCHAIN_ONLY)/SourceSerif4-It.ttf.woff ]
+ ! [ -e $(TOOLCHAIN_ONLY)/SourceSerif4-It.ttf.woff2 ]
! [ -e $(TOOLCHAIN_ONLY)/search-index-xxx.js ]
! [ -e $(TOOLCHAIN_ONLY)/x/index.html ]
! [ -e $(TOOLCHAIN_ONLY)/theme.css ]
all-shared:
$(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources,unversioned-shared-resources --output $(ALL_SHARED) --resource-suffix=-xxx --extend-css z.css x.rs
[ -e $(ALL_SHARED)/storage-xxx.js ]
- [ -e $(ALL_SHARED)/SourceSerif4-It.ttf.woff ]
+ [ -e $(ALL_SHARED)/SourceSerif4-It.ttf.woff2 ]
! [ -e $(ALL_SHARED)/search-index-xxx.js ]
! [ -e $(ALL_SHARED)/settings.html ]
! [ -e $(ALL_SHARED)/x ]
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+# only-linux
+# ignore-cross-compile
+
+all: main.rs
+ $(RUSTC) --crate-type lib lib.rs
+ $(RUSTC) --crate-type cdylib -Clink-args="-Tlinker.ld" main.rs
+ # Ensure `#[used]` and `KEEP`-ed section is there
+ objdump -s -j".static" $(TMPDIR)/libmain.so
+ # Ensure `#[no_mangle]` symbol is there
+ nm $(TMPDIR)/libmain.so | $(CGREP) bar
--- /dev/null
+mod foo {
+ #[link_section = ".rodata.STATIC"]
+ #[used]
+ static STATIC: [u32; 10] = [1; 10];
+}
+
+mod bar {
+ #[no_mangle]
+ extern "C" fn bar() -> i32 {
+ 0
+ }
+}
--- /dev/null
+SECTIONS
+{
+ .static : ALIGN(4)
+ {
+ KEEP(*(.rodata.STATIC));
+ }
+}
--- /dev/null
+extern crate lib;
// 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 : :",
+ "a!a",
+ "a!!",
+];
+
+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 `:`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a!a",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a!a",
+ error: '`!` can only be at the end of an ident',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a!!",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a!!",
+ error: 'Cannot have more than one `!` in an ident',
+ },
+];
--- /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<!>",
+ "!",
+ "a!",
+ "a!::b",
+ "a!::b!",
+];
+
+const PARSED = [
+ {
+ elems: [{
+ name: "r",
+ fullPath: ["r"],
+ pathWithoutLast: [],
+ pathLast: "r",
+ generics: [
+ {
+ name: "!",
+ fullPath: ["!"],
+ pathWithoutLast: [],
+ pathLast: "!",
+ generics: [],
+ },
+ ],
+ }],
+ foundElems: 1,
+ original: "R<!>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "r<!>",
+ error: null,
+ },
+ {
+ elems: [{
+ name: "!",
+ fullPath: ["!"],
+ pathWithoutLast: [],
+ pathLast: "!",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "!",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "!",
+ error: null,
+ },
+ {
+ elems: [{
+ name: "a!",
+ fullPath: ["a!"],
+ pathWithoutLast: [],
+ pathLast: "a!",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "a!",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a!",
+ error: null,
+ },
+ {
+ 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: [],
+ }],
+ foundElems: 1,
+ original: "a!::b!",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a!::b!",
+ 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,
+ },
+ {
+ elems: [],
+ foundElems: 1,
+ original: "-> !",
+ returned: [{
+ name: "!",
+ fullPath: ["!"],
+ pathWithoutLast: [],
+ pathLast: "!",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: "-> !",
+ 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 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
+// @has issue_95873/index.html "//*[@class='item-left import-item']" "pub use ::std as x;"
+pub use ::std as x;
--- /dev/null
+// should-fail
+
+#![allow(unused)]
+
+trait Foo<T>: Sized {
+ fn bar(i: i32, t: T, s: &Self) -> (T, i32);
+}
+
+impl Foo<usize> for () {
+ fn bar(i: _, t: _, s: _) -> _ {
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+ (1, 2)
+ }
+}
+
+fn main() {}
--- /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"]' \
// ignore-cross-compile
use std::env;
+use std::ffi::OsStr;
use std::fs;
+use std::path::PathBuf;
use std::process;
use std::str;
-use std::path::PathBuf;
fn main() {
// If we're the child, make sure we were invoked correctly
// checking that it ends_with the executable name. This
// is needed because of Windows, which has a different behavior.
// See #15149 for more info.
- return assert!(args[0].ends_with(&format!("mytest{}",
- env::consts::EXE_SUFFIX)));
+ let my_path = env::current_exe().unwrap();
+ return assert_eq!(my_path.file_stem(), Some(OsStr::new("mytest")));
}
test();
fn test() {
// If we're the parent, copy our own binary to a new directory.
let my_path = env::current_exe().unwrap();
- let my_dir = my_path.parent().unwrap();
+ let my_dir = my_path.parent().unwrap();
let child_dir = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap());
let child_dir = child_dir.join("issue-15140-child");
fs::create_dir_all(&child_dir).unwrap();
- let child_path = child_dir.join(&format!("mytest{}",
- env::consts::EXE_SUFFIX));
+ let child_path = child_dir.join(&format!("mytest{}", env::consts::EXE_SUFFIX));
fs::copy(&my_path, &child_path).unwrap();
// Append the new directory to our own PATH.
env::join_paths(paths).unwrap()
};
- let child_output = process::Command::new("mytest").env("PATH", &path)
- .arg("child")
- .output().unwrap();
+ let child_output =
+ process::Command::new("mytest").env("PATH", &path).arg("child").output().unwrap();
- assert!(child_output.status.success(),
- "child assertion failed\n child stdout:\n {}\n child stderr:\n {}",
- str::from_utf8(&child_output.stdout).unwrap(),
- str::from_utf8(&child_output.stderr).unwrap());
+ assert!(
+ child_output.status.success(),
+ "child assertion failed\n child stdout:\n {}\n child stderr:\n {}",
+ str::from_utf8(&child_output.stdout).unwrap(),
+ str::from_utf8(&child_output.stderr).unwrap()
+ );
}
//~^ 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
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/async-unsafe-fn-call-in-safe.rs:15:5
+ --> $DIR/async-unsafe-fn-call-in-safe.rs:17:5
|
LL | f();
| ^^^ call to unsafe function
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/async-unsafe-fn-call-in-safe.rs:19:5
+ --> $DIR/async-unsafe-fn-call-in-safe.rs:23:5
|
LL | S::f();
| ^^^^^^ call to unsafe function
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/async-unsafe-fn-call-in-safe.rs:20:5
+ --> $DIR/async-unsafe-fn-call-in-safe.rs:24:5
|
LL | f();
| ^^^ call to unsafe function
async unsafe fn f() {}
async fn g() {
- S::f(); //~ ERROR call to unsafe function is unsafe
- f(); //~ ERROR call to unsafe function is unsafe
+ S::f();
+ //[mir]~^ ERROR call to unsafe function is unsafe
+ //[thir]~^^ ERROR call to unsafe function `S::f` is unsafe
+ f();
+ //[mir]~^ ERROR call to unsafe function is unsafe
+ //[thir]~^^ ERROR call to unsafe function `f` is unsafe
}
fn main() {
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `S::f` is unsafe and requires unsafe function or block
--> $DIR/async-unsafe-fn-call-in-safe.rs:14:5
|
LL | S::f();
|
= note: consult the function's documentation for information on how to avoid undefined behavior
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/async-unsafe-fn-call-in-safe.rs:15:5
+error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
+ --> $DIR/async-unsafe-fn-call-in-safe.rs:17:5
|
LL | f();
| ^^^ call to unsafe function
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
|
--- /dev/null
+// Regression test for #93927: suggested trait bound for T should be Eq, not PartialEq
+struct MyType<T>(T);
+
+impl<T> PartialEq for MyType<T>
+where
+ T: Eq,
+{
+ fn eq(&self, other: &Self) -> bool {
+ true
+ }
+}
+
+fn cond<T: PartialEq>(val: MyType<T>) -> bool {
+ val == val
+ //~^ ERROR binary operation `==` cannot be applied to type `MyType<T>`
+}
+
+fn main() {
+ cond(MyType(0));
+}
--- /dev/null
+error[E0369]: binary operation `==` cannot be applied to type `MyType<T>`
+ --> $DIR/issue-93927.rs:14:9
+ |
+LL | val == val
+ | --- ^^ --- MyType<T>
+ | |
+ | MyType<T>
+ |
+help: consider further restricting this bound
+ |
+LL | fn cond<T: PartialEq + std::cmp::Eq>(val: MyType<T>) -> bool {
+ | ++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0369`.
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `Pin::<P>::new_unchecked` is unsafe and requires unsafe function or block
--> $DIR/coerce-unsafe-closure-to-unsafe-fn-ptr.rs:5:31
|
LL | let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); };
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/coherence-cow.rs:18:1
|
LL | impl<T> Remote for Pair<T,Cover<T>> { }
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/coherence-cow.rs:22:1
|
LL | impl<T> Remote for Pair<Cover<T>,T> { }
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/coherence-cow.rs:26:1
|
LL | impl<T,U> Remote for Pair<Cover<T>,U> { }
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/coherence-impls-copy.rs:5:1
|
LL | impl Copy for i32 {}
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/coherence-orphan.rs:10:1
|
LL | impl TheTrait<usize> for isize { }
|
= note: define and implement a trait or new type instead
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/coherence-orphan.rs:17:1
|
LL | impl !Send for Vec<isize> { }
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/coherence-overlapping-pairs.rs:8:1
|
LL | impl<T> Remote for lib::Pair<T,Foo> { }
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/coherence-pair-covered-uncovered-1.rs:12:1
|
LL | impl<T, U> Remote1<Pair<T, Local<U>>> for i32 { }
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/coherence-pair-covered-uncovered.rs:8:1
|
LL | impl<T,U> Remote for Pair<T,Local<U>> { }
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/coherence-vec-local-2.rs:11:1
|
LL | impl<T> Remote for Vec<Local<T>> { }
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/coherence-vec-local.rs:11:1
|
LL | impl Remote for Vec<Local> { }
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/coherence_local_err_struct.rs:14:1
|
LL | impl lib::MyCopy for lib::MyStruct<MyType> { }
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/impl-foreign-for-foreign.rs:10:1
|
LL | impl Remote for i32 {
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/impl-foreign-for-foreign[foreign].rs:10:1
|
LL | impl Remote1<Rc<i32>> for i32 {
|
= note: define and implement a trait or new type instead
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/impl-foreign-for-foreign[foreign].rs:14:1
|
LL | impl Remote1<Rc<Local>> for f64 {
|
= note: define and implement a trait or new type instead
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/impl-foreign-for-foreign[foreign].rs:18:1
|
LL | impl<T> Remote1<Rc<T>> for f32 {
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/impl-foreign-for-fundamental[foreign].rs:10:1
|
LL | impl Remote for Box<i32> {
|
= note: define and implement a trait or new type instead
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/impl-foreign-for-fundamental[foreign].rs:14:1
|
LL | impl<T> Remote for Box<Rc<T>> {
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/impl-foreign[foreign]-for-foreign.rs:10:1
|
LL | impl Remote1<u32> for f64 {
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:11:1
|
LL | impl Remote1<Box<String>> for i32 {
|
= note: define and implement a trait or new type instead
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:15:1
|
LL | impl Remote1<Box<Rc<i32>>> for f64 {
|
= note: define and implement a trait or new type instead
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:19:1
|
LL | impl<T> Remote1<Box<Rc<T>>> for f32 {
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/impl[t]-foreign-for-foreign[t].rs:11:1
|
LL | impl Remote for Rc<Local> {
|
= note: define and implement a trait or new type instead
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/impl[t]-foreign-for-foreign[t].rs:16:1
|
LL | impl<T> Remote for Arc<T> {
--> $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() {
}
| transmuting to uninhabited type
| inside `foo` at $DIR/validate_uninhabited_zsts.rs:4:14
...
-LL | const FOO: [Empty; 3] = [foo(); 3];
- | ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26
+LL | const FOO: [empty::Empty; 3] = [foo(); 3];
+ | ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:20:33
error[E0080]: it is undefined behavior to use this value
- --> $DIR/validate_uninhabited_zsts.rs:16:1
+ --> $DIR/validate_uninhabited_zsts.rs:23:1
|
-LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
+LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0].0: encountered a value of uninhabited type empty::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) {}
= note: `#[warn(invalid_value)]` on by default
= note: the `!` type has no valid value
-warning: the type `Empty` does not permit zero-initialization
- --> $DIR/validate_uninhabited_zsts.rs:16:35
+warning: the type `empty::Empty` does not permit zero-initialization
+ --> $DIR/validate_uninhabited_zsts.rs:23:42
|
-LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
- | ^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | this code causes undefined behavior when executed
- | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | this code causes undefined behavior when executed
+ | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
- = note: enums with no variants have no valid value
+note: enums with no variants have no valid value (in this struct field)
+ --> $DIR/validate_uninhabited_zsts.rs:16:22
+ |
+LL | pub struct Empty(Void);
+ | ^^^^
error: aborting due to 2 previous errors; 2 warnings emitted
| transmuting to uninhabited type
| inside `foo` at $DIR/validate_uninhabited_zsts.rs:4:14
...
-LL | const FOO: [Empty; 3] = [foo(); 3];
- | ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26
+LL | const FOO: [empty::Empty; 3] = [foo(); 3];
+ | ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:20:33
error[E0080]: it is undefined behavior to use this value
- --> $DIR/validate_uninhabited_zsts.rs:16:1
+ --> $DIR/validate_uninhabited_zsts.rs:23:1
|
-LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
+LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0].0: encountered a value of uninhabited type empty::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) {}
= note: `#[warn(invalid_value)]` on by default
= note: the `!` type has no valid value
-warning: the type `Empty` does not permit zero-initialization
- --> $DIR/validate_uninhabited_zsts.rs:16:35
+warning: the type `empty::Empty` does not permit zero-initialization
+ --> $DIR/validate_uninhabited_zsts.rs:23:42
|
-LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
- | ^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | this code causes undefined behavior when executed
- | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | this code causes undefined behavior when executed
+ | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
- = note: enums with no variants have no valid value
+note: enums with no variants have no valid value (in this struct field)
+ --> $DIR/validate_uninhabited_zsts.rs:16:22
+ |
+LL | pub struct Empty(Void);
+ | ^^^^
error: aborting due to 2 previous errors; 2 warnings emitted
//~| WARN the type `!` does not permit zero-initialization [invalid_value]
}
-#[derive(Clone, Copy)]
-enum Empty { }
+// Type defined in a submodule, so that it is not "visibly"
+// uninhabited (which would change interpreter behavior).
+pub mod empty {
+ #[derive(Clone, Copy)]
+ enum Void {}
+
+ #[derive(Clone, Copy)]
+ pub struct Empty(Void);
+}
#[warn(const_err)]
-const FOO: [Empty; 3] = [foo(); 3];
+const FOO: [empty::Empty; 3] = [foo(); 3];
#[warn(const_err)]
-const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
//~^ ERROR it is undefined behavior to use this value
-//~| WARN the type `Empty` does not permit zero-initialization
+//~| WARN the type `empty::Empty` does not permit zero-initialization
fn main() {
FOO;
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/const-extern-fn-requires-unsafe.rs:11:5
+ --> $DIR/const-extern-fn-requires-unsafe.rs:12:5
|
LL | foo();
| ^^^^^ call to unsafe function
fn main() {
let a: [u8; foo()];
- //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+ //[mir]~^ call to unsafe function is unsafe and requires unsafe function or block
+ //[thir]~^^ call to unsafe function `foo` is unsafe and requires unsafe function or block
foo();
//[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
}
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
--> $DIR/const-extern-fn-requires-unsafe.rs:9:17
|
LL | let a: [u8; foo()];
const_assert!(f32::from_bits(0x44a72000), 1337.0);
const_assert!(f32::from_ne_bytes(0x44a72000u32.to_ne_bytes()), 1337.0);
const_assert!(f32::from_bits(0xc1640000), -14.25);
-
- // Check that NaNs roundtrip their bits regardless of signalingness
- // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
- const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA;
- const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
-
- const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
- const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
-
- // LLVM does not guarantee that loads and stores of NaNs preserve their exact bit pattern.
- // In practice, this seems to only cause a problem on x86, since the most widely used calling
- // convention mandates that floating point values are returned on the x87 FPU stack. See #73328.
- if !cfg!(target_arch = "x86") {
- const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
- const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
- }
}
fn f64() {
const_assert!(f64::from_bits(0x4094e40000000000), 1337.0);
const_assert!(f64::from_ne_bytes(0x4094e40000000000u64.to_ne_bytes()), 1337.0);
const_assert!(f64::from_bits(0xc02c800000000000), -14.25);
-
- // Check that NaNs roundtrip their bits regardless of signalingness
- // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
- const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
- const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
-
- const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
- const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
-
- // See comment above.
- if !cfg!(target_arch = "x86") {
- const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
- const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
- }
}
fn main() {
--- /dev/null
+// compile-flags: -Zmir-opt-level=0
+#![feature(const_float_bits_conv)]
+#![feature(const_float_classify)]
+
+// Don't promote
+const fn nop<T>(x: T) -> T { x }
+
+macro_rules! const_assert {
+ ($a:expr) => {
+ {
+ const _: () = assert!($a);
+ assert!(nop($a));
+ }
+ };
+ ($a:expr, $b:expr) => {
+ {
+ const _: () = assert!($a == $b);
+ assert_eq!(nop($a), nop($b));
+ }
+ };
+}
+
+fn f32() {
+ // Check that NaNs roundtrip their bits regardless of signalingness
+ // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+ // ...actually, let's just check that these break. :D
+ const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA;
+ const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
+
+ const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
+ const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
+
+ // LLVM does not guarantee that loads and stores of NaNs preserve their exact bit pattern.
+ // In practice, this seems to only cause a problem on x86, since the most widely used calling
+ // convention mandates that floating point values are returned on the x87 FPU stack. See #73328.
+ if !cfg!(target_arch = "x86") {
+ const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
+ const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
+ }
+}
+
+fn f64() {
+ // Check that NaNs roundtrip their bits regardless of signalingness
+ // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+ // ...actually, let's just check that these break. :D
+ const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
+ const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
+
+ const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
+ const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
+
+ // See comment above.
+ if !cfg!(target_arch = "x86") {
+ const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
+ const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
+ }
+}
+
+fn main() {
+ f32();
+ f64();
+}
--- /dev/null
+error[E0080]: evaluation of constant value failed
+ --> $SRC_DIR/core/src/num/f32.rs:LL:COL
+ |
+LL | panic!("const-eval error: cannot use f32::to_bits on a NaN")
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
+ | inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32` at $SRC_DIR/core/src/panic.rs:LL:COL
+...
+LL | unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
+ | -------------------------------------------------------------------- inside `core::f32::<impl f32>::to_bits` at $SRC_DIR/core/src/num/f32.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+ | ------------------------------------------------------------------ inside `<fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32} as FnOnce<(f32,)>>::call_once - shim(fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+LL | called_in_const.call_once(arg)
+ | ------------------------------ inside `const_eval_select::<(f32,), fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32}, [closure@core::f32::<impl f32>::to_bits::{closure#0}], u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+ ::: $DIR/const-float-bits-reject-conv.rs:27:30
+ |
+LL | const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA;
+ | ------------------ inside `f32::MASKED_NAN1` at $DIR/const-float-bits-reject-conv.rs:27:30
+ |
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: evaluation of constant value failed
+ --> $SRC_DIR/core/src/num/f32.rs:LL:COL
+ |
+LL | panic!("const-eval error: cannot use f32::to_bits on a NaN")
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
+ | inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32` at $SRC_DIR/core/src/panic.rs:LL:COL
+...
+LL | unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
+ | -------------------------------------------------------------------- inside `core::f32::<impl f32>::to_bits` at $SRC_DIR/core/src/num/f32.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+ | ------------------------------------------------------------------ inside `<fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32} as FnOnce<(f32,)>>::call_once - shim(fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+LL | called_in_const.call_once(arg)
+ | ------------------------------ inside `const_eval_select::<(f32,), fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32}, [closure@core::f32::<impl f32>::to_bits::{closure#0}], u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+ ::: $DIR/const-float-bits-reject-conv.rs:28:30
+ |
+LL | const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
+ | ------------------ inside `f32::MASKED_NAN2` at $DIR/const-float-bits-reject-conv.rs:28:30
+ |
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: evaluation of constant value failed
+ --> $SRC_DIR/core/src/num/f64.rs:LL:COL
+ |
+LL | panic!("const-eval error: cannot use f64::to_bits on a NaN")
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
+ | inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64` at $SRC_DIR/core/src/panic.rs:LL:COL
+...
+LL | unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
+ | -------------------------------------------------------------------- inside `core::f64::<impl f64>::to_bits` at $SRC_DIR/core/src/num/f64.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+ | ------------------------------------------------------------------ inside `<fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64} as FnOnce<(f64,)>>::call_once - shim(fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+LL | called_in_const.call_once(arg)
+ | ------------------------------ inside `const_eval_select::<(f64,), fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64}, [closure@core::f64::<impl f64>::to_bits::{closure#0}], u64>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+ ::: $DIR/const-float-bits-reject-conv.rs:46:30
+ |
+LL | const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
+ | ------------------ inside `f64::MASKED_NAN1` at $DIR/const-float-bits-reject-conv.rs:46:30
+ |
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: evaluation of constant value failed
+ --> $SRC_DIR/core/src/num/f64.rs:LL:COL
+ |
+LL | panic!("const-eval error: cannot use f64::to_bits on a NaN")
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
+ | inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64` at $SRC_DIR/core/src/panic.rs:LL:COL
+...
+LL | unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
+ | -------------------------------------------------------------------- inside `core::f64::<impl f64>::to_bits` at $SRC_DIR/core/src/num/f64.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+ | ------------------------------------------------------------------ inside `<fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64} as FnOnce<(f64,)>>::call_once - shim(fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+LL | called_in_const.call_once(arg)
+ | ------------------------------ inside `const_eval_select::<(f64,), fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64}, [closure@core::f64::<impl f64>::to_bits::{closure#0}], u64>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+ ::: $DIR/const-float-bits-reject-conv.rs:47:30
+ |
+LL | const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
+ | ------------------ inside `f64::MASKED_NAN2` at $DIR/const-float-bits-reject-conv.rs:47:30
+ |
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
-LL | impl<I: Iterator> IntoIterator for I {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<I: ~const Iterator> const IntoIterator for I {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
error[E0658]: mutable references are not allowed in constant functions
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
-LL | impl<I: Iterator> IntoIterator for I {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<I: ~const Iterator> const IntoIterator for I {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
--- /dev/null
+// run-rustfix
+#![allow(unused)]
+
+trait Foo<T>: Sized {
+ fn bar(i: i32, t: T, s: &Self) -> (T, i32);
+}
+
+impl Foo<usize> for () {
+ fn bar(i: i32, t: usize, s: &()) -> (usize, i32) {
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+ (1, 2)
+ }
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+#![allow(unused)]
+
+trait Foo<T>: Sized {
+ fn bar(i: i32, t: T, s: &Self) -> (T, i32);
+}
+
+impl Foo<usize> for () {
+ fn bar(i: _, t: _, s: _) -> _ {
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+ (1, 2)
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+ --> $DIR/replace-impl-infer-ty-from-trait.rs:9:15
+ |
+LL | fn bar(i: _, t: _, s: _) -> _ {
+ | ^ ^ ^ ^ not allowed in type signatures
+ | | | |
+ | | | not allowed in type signatures
+ | | not allowed in type signatures
+ | not allowed in type signatures
+ |
+help: try replacing `_` with the types in the corresponding trait method signature
+ |
+LL | fn bar(i: i32, t: usize, s: &()) -> (usize, i32) {
+ | ~~~ ~~~~~ ~~~ ~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
//~| 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`.
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/E0117.rs:1:1
|
LL | impl Drop for u32 {}
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
--> $DIR/E0133.rs:7:5
|
LL | f();
--- /dev/null
+// aux-crate:somedep=somedep.rs
+// compile-flags: -Zunstable-options -Dunused-crate-dependencies
+// edition:2018
+
+fn main() { //~ ERROR external crate `somedep` unused in `no_nounused`
+}
--- /dev/null
+error: external crate `somedep` unused in `no_nounused`: remove the dependency or add `use somedep as _;`
+ --> $DIR/no-nounused.rs:5:1
+ |
+LL | fn main() {
+ | ^
+ |
+ = note: requested on the command line with `-D unused-crate-dependencies`
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+// aux-crate:nounused:somedep=somedep.rs
+// compile-flags: -Zunstable-options -Dunused-crate-dependencies
+// edition:2018
+
+fn main() {
+}
--- /dev/null
+// We previously mentioned other extern types in the error message here.
+//
+// Two extern types shouldn't really be considered similar just
+// because they are both extern types.
+
+#![feature(extern_types)]
+extern {
+ type ShouldNotBeMentioned;
+}
+
+extern {
+ type Foo;
+}
+
+unsafe impl Send for ShouldNotBeMentioned {}
+
+fn assert_send<T: Send + ?Sized>() {}
+
+fn main() {
+ assert_send::<Foo>()
+ //~^ ERROR `Foo` cannot be sent between threads safely
+}
--- /dev/null
+error[E0277]: `Foo` cannot be sent between threads safely
+ --> $DIR/extern-type-diag-not-similar.rs:20:19
+ |
+LL | assert_send::<Foo>()
+ | ^^^ `Foo` cannot be sent between threads safely
+ |
+ = help: the trait `Send` is not implemented for `Foo`
+note: required by a bound in `assert_send`
+ --> $DIR/extern-type-diag-not-similar.rs:17:19
+ |
+LL | fn assert_send<T: Send + ?Sized>() {}
+ | ^^^^ required by this bound in `assert_send`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
fn main() {
test::free();
- //~^ ERROR call to unsafe function is unsafe
+ //[mir]~^ ERROR call to unsafe function is unsafe
+ //[thir]~^^ ERROR call to unsafe function `test::free` is unsafe
}
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `test::free` is unsafe and requires unsafe function or block
--> $DIR/foreign-unsafe-fn-called.rs:11:5
|
LL | test::free();
let arc = std::sync::Arc::new(oops);
//~^ ERROR cannot find value `oops` in this scope
//~| NOTE not found
- // The error "note: `arc` is a function, perhaps you wish to call it" MUST NOT appear.
+ // The error "note: this is a function, perhaps you wish to call it" MUST NOT appear.
arc.blablabla();
//~^ ERROR no method named `blablabla`
//~| NOTE method not found
let arc2 = std::sync::Arc::new(|| 1);
- // The error "note: `arc2` is a function, perhaps you wish to call it" SHOULD appear
+ // The error "note: this is a function, perhaps you wish to call it" SHOULD appear
arc2.blablabla();
//~^ ERROR no method named `blablabla`
//~| NOTE method not found
- //~| NOTE `arc2` is a function, perhaps you wish to call it
+ //~| NOTE this is a function, perhaps you wish to call it
}
--> $DIR/fn-help-with-err.rs:12:10
|
LL | arc2.blablabla();
- | ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>`
- |
- = note: `arc2` is a function, perhaps you wish to call it
+ | ---- ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>`
+ | |
+ | this is a function, perhaps you wish to call it
error: aborting due to 3 previous errors
// 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;
}
+++ /dev/null
-// run-rustfix
-
-use std::ops::Add;
-
-struct A<B>(B);
-
-impl<B> Add for A<B> where B: Add + Add<Output = B> {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- A(self.0 + rhs.0) //~ ERROR mismatched types
- }
-}
-
-struct C<B>(B);
-
-impl<B: Add + Add<Output = B>> Add for C<B> {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- Self(self.0 + rhs.0) //~ ERROR mismatched types
- }
-}
-
-struct D<B>(B);
-
-impl<B: std::ops::Add<Output = B>> Add for D<B> {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- Self(self.0 + rhs.0) //~ ERROR cannot add `B` to `B`
- }
-}
-
-struct E<B>(B);
-
-impl<B: Add> Add for E<B> where B: Add<Output = B>, B: Add<Output = B> {
- //~^ ERROR equality constraints are not yet supported in `where` clauses
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- Self(self.0 + rhs.0) //~ ERROR mismatched types
- }
-}
-
-fn main() {}
-// run-rustfix
-
use std::ops::Add;
struct A<B>(B);
error: equality constraints are not yet supported in `where` clauses
- --> $DIR/missing-bounds.rs:37:33
+ --> $DIR/missing-bounds.rs:35:33
|
LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
| ^^^^^^^^^^^^^^^^^^^^^^ not supported
| ~~~~~~~~~~~~~~~~~~
error[E0308]: mismatched types
- --> $DIR/missing-bounds.rs:11:11
+ --> $DIR/missing-bounds.rs:9:11
|
LL | impl<B> Add for A<B> where B: Add {
| - this type parameter
= note: expected type parameter `B`
found associated type `<B as Add>::Output`
note: tuple struct defined here
- --> $DIR/missing-bounds.rs:5:8
+ --> $DIR/missing-bounds.rs:3:8
|
LL | struct A<B>(B);
| ^
| +++++++++++++++++
error[E0308]: mismatched types
- --> $DIR/missing-bounds.rs:21:14
+ --> $DIR/missing-bounds.rs:19:14
|
LL | impl<B: Add> Add for C<B> {
| - this type parameter
= note: expected type parameter `B`
found associated type `<B as Add>::Output`
note: tuple struct defined here
- --> $DIR/missing-bounds.rs:15:8
+ --> $DIR/missing-bounds.rs:13:8
|
LL | struct C<B>(B);
| ^
| +++++++++++++++++
error[E0369]: cannot add `B` to `B`
- --> $DIR/missing-bounds.rs:31:21
+ --> $DIR/missing-bounds.rs:29:21
|
LL | Self(self.0 + rhs.0)
| ------ ^ ----- B
|
help: consider restricting type parameter `B`
|
-LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
- | +++++++++++++++++++++++++++
+LL | impl<B: std::ops::Add> Add for D<B> {
+ | +++++++++++++++
error[E0308]: mismatched types
- --> $DIR/missing-bounds.rs:42:14
+ --> $DIR/missing-bounds.rs:40:14
|
LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
| - this type parameter
= note: expected type parameter `B`
found associated type `<B as Add>::Output`
note: tuple struct defined here
- --> $DIR/missing-bounds.rs:35:8
+ --> $DIR/missing-bounds.rs:33:8
|
LL | struct E<B>(B);
| ^
--- /dev/null
+#![crate_type = "lib"]
+
+struct S<T = (), 'a>(&'a T);
+//~^ ERROR lifetime parameters must be declared prior to type parameters
--- /dev/null
+error: lifetime parameters must be declared prior to type parameters
+ --> $DIR/issue-80512-param-reordering-with-defaults.rs:3:18
+ |
+LL | struct S<T = (), 'a>(&'a T);
+ | ---------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T = ()>`
+
+error: aborting due to previous error
+
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| --------- - ^^^^^^ unsatisfied trait bound introduced here
+help: one of the expressions' fields has a method of the same name
+ |
+LL | let filter = map.stream.filterx(|x: &_| true);
+ | +++++++
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:140:24
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| --------- - ^^^^^^ unsatisfied trait bound introduced here
+help: one of the expressions' fields has a method of the same name
+ |
+LL | let count = filter.stream.countx();
+ | +++++++
error: aborting due to 2 previous errors
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| --------- - ^^^^^^ unsatisfied trait bound introduced here
+help: one of the expressions' fields has a method of the same name
+ |
+LL | let filter = map.stream.filterx(|x: &_| true);
+ | +++++++
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:140:24
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| --------- - ^^^^^^ unsatisfied trait bound introduced here
+help: one of the expressions' fields has a method of the same name
+ |
+LL | let count = filter.stream.countx();
+ | +++++++
error: aborting due to 2 previous errors
LL | x
| ^ returning this value requires that `'b` must outlive `'static`
|
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'b`, add `'b` as a bound
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'b` lifetime bound
|
LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b {
| ++++
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'b` lifetime bound
+ |
+LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a + 'b> {
+ | ++++
error: implementation of `Hrtb` is not general enough
--> $DIR/issue-88236-2.rs:20:5
| |
| let's call the lifetime of this reference `'1`
|
- = help: consider replacing `'1` with `'static`
+help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+ |
+LL | fn elided2(x: &i32) -> impl Copy + '_ { x }
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x }
+ | ~~~~~~~~~~~~
error: lifetime may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:11:55
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
|
- = help: consider replacing `'a` with `'static`
+help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+ |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x }
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x }
+ | ~~~~~~~~~~~~
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/must_outlive_least_region_or_bound.rs:13:41
| - ^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
| |
| let's call the lifetime of this reference `'1`
+ |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
+ | ++++
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
+ | ++++
error: lifetime may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:29:69
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
|
- = help: consider replacing `'a` with `'static`
+help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+ |
+LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x }
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x }
+ | ~~~~~~~~~~~~
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/must_outlive_least_region_or_bound.rs:34:5
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:41:5
|
+LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
+ | -- help: consider adding an explicit lifetime bound...: `T: 'static +`
+...
LL | x
- | ^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
+ | ^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to 9 previous errors
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/type_parameters_captured.rs:10:5
|
+LL | fn foo<T>(x: T) -> impl Any + 'static {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+...
LL | x
- | ^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
+ | ^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to previous error
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `unchecked_add` is unsafe and requires unsafe function or block
--> $DIR/unchecked_math_unsafe.rs:8:15
|
LL | let add = std::intrinsics::unchecked_add(x, y);
|
= note: consult the function's documentation for information on how to avoid undefined behavior
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `unchecked_sub` is unsafe and requires unsafe function or block
--> $DIR/unchecked_math_unsafe.rs:9:15
|
LL | let sub = std::intrinsics::unchecked_sub(x, y);
|
= note: consult the function's documentation for information on how to avoid undefined behavior
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `unchecked_mul` is unsafe and requires unsafe function or block
--> $DIR/unchecked_math_unsafe.rs:10:15
|
LL | let mul = std::intrinsics::unchecked_mul(x, y);
| - let's call the lifetime of this reference `'1`
LL | Box::new(value) as Box<dyn Any>
| ^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`
+ |
+help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn foo<T: Any>(value: &T) -> Box<dyn Any + '_> {
+ | ++++
error: aborting due to previous error
+++ /dev/null
-// build-pass
-#![allow(dead_code)]
-#![allow(non_camel_case_types)]
-#![warn(clashing_extern_declarations)]
-
-// pretty-expanded FIXME #23616
-
-mod a {
- pub type rust_task = usize;
- pub mod rustrt {
- use super::rust_task;
- extern "C" {
- pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
- }
- }
-}
-
-mod b {
- pub type rust_task = bool;
- pub mod rustrt {
- use super::rust_task;
- extern "C" {
- pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
- //~^ WARN `rust_task_is_unwinding` redeclared with a different signature
- }
- }
-}
-
-pub fn main() {}
+++ /dev/null
-warning: `rust_task_is_unwinding` redeclared with a different signature
- --> $DIR/issue-1866.rs:23:13
- |
-LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
- | ------------------------------------------------------------ `rust_task_is_unwinding` previously declared here
-...
-LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
- |
-note: the lint level is defined here
- --> $DIR/issue-1866.rs:4:9
- |
-LL | #![warn(clashing_extern_declarations)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: expected `unsafe extern "C" fn(*const usize) -> bool`
- found `unsafe extern "C" fn(*const bool) -> bool`
-
-warning: 1 warning emitted
-
+++ /dev/null
-// run-pass
-#![allow(unused_variables)]
-// Regression test for Issue #20343.
-
-// pretty-expanded FIXME #23616
-
-#![deny(dead_code)]
-
-struct B { b: u32 }
-struct C;
-struct D;
-
-trait T<A> { fn dummy(&self, a: A) { } }
-impl<A> T<A> for () {}
-
-impl B {
- // test for unused code in arguments
- fn foo(B { b }: B) -> u32 { b }
-
- // test for unused code in return type
- fn bar() -> C { unsafe { ::std::mem::transmute(()) } }
-
- // test for unused code in generics
- fn baz<A: T<D>>() {}
-}
-
-pub fn main() {
- let b = B { b: 3 };
- B::foo(b);
- B::bar();
- B::baz::<()>();
-}
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `std::ptr::write` is unsafe and requires unsafe function or block
--> $DIR/issue-28776.rs:7:5
|
LL | (&ptr::write)(1 as *mut _, 42);
--> $DIR/issue-29124.rs:15:15
|
LL | Obj::func.x();
- | ^ method not found in `fn() -> Ret {Obj::func}`
- |
- = note: `Obj::func` is a function, perhaps you wish to call it
+ | --------- ^ method not found in `fn() -> Ret {Obj::func}`
+ | |
+ | this is a function, perhaps you wish to call it
error[E0599]: no method named `x` found for fn item `fn() -> Ret {func}` in the current scope
--> $DIR/issue-29124.rs:17:10
|
LL | func.x();
- | ^ method not found in `fn() -> Ret {func}`
- |
- = note: `func` is a function, perhaps you wish to call it
+ | ---- ^ method not found in `fn() -> Ret {func}`
+ | |
+ | this is a function, perhaps you wish to call it
error: aborting due to 2 previous errors
+++ /dev/null
-// run-pass
-// ignore-emscripten no threads support
-
-use std::thread;
-
-struct Foo;
-
-impl Drop for Foo {
- fn drop(&mut self) {
- println!("test2");
- }
-}
-
-thread_local!(static FOO: Foo = Foo);
-
-fn main() {
- // Off the main thread due to #28129, be sure to initialize FOO first before
- // calling `println!`
- thread::spawn(|| {
- FOO.with(|_| {});
- println!("test1");
- }).join().unwrap();
-}
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `X::with` is unsafe and requires unsafe function or block
--> $DIR/issue-3080.rs:10:5
|
LL | X(()).with();
| |
| &T
|
-help: consider restricting type parameter `T`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
-LL | fn func<'a, T: std::ops::Mul<Output = &T>>(a: &'a [T]) -> impl Iterator<Item=&'a T> {
- | ++++++++++++++++++++++++++++
+LL | fn func<'a, T>(a: &'a [T]) -> impl Iterator<Item=&'a T> where &T: Mul<&T> {
+ | +++++++++++++++++
error: aborting due to previous error
+++ /dev/null
-fn main() {
- include!(line!()); //~ ERROR argument must be a string literal
-}
+++ /dev/null
-error: argument must be a string literal
- --> $DIR/issue-41776.rs:2:14
- |
-LL | include!(line!());
- | ^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-#![allow(unused)]
-
-fn main() {
-}
-
-fn foo() {
- let b = mk::<
- Forward<(Box<dyn Future<Error = u32>>,)>,
- >();
- b.map_err(|_| ()).join();
-}
-
-fn mk<T>() -> T {
- loop {}
-}
-
-impl<I: Future<Error = E>, E> Future for (I,) {
- type Error = E;
-}
-
-struct Forward<T: Future> {
- _a: T,
-}
-
-impl<T: Future> Future for Forward<T>
-where
- T::Error: From<u32>,
-{
- type Error = T::Error;
-}
-
-trait Future {
- type Error;
-
- fn map_err<F, E>(self, _: F) -> (Self, F)
- where
- F: FnOnce(Self::Error) -> E,
- Self: Sized,
- {
- loop {}
- }
-
- fn join(self) -> (MaybeDone<Self>, ())
- where
- Self: Sized,
- {
- loop {}
- }
-}
-
-impl<S: ?Sized + Future> Future for Box<S> {
- type Error = S::Error;
-}
-
-enum MaybeDone<A: Future> {
- _Done(A::Error),
-}
-
-impl<U, A: Future, F> Future for (A, F)
-where
- F: FnOnce(A::Error) -> U,
-{
- type Error = U;
-}
+++ /dev/null
-// run-pass
-
-#![feature(decl_macro)]
-
-pub struct Foo {
- bar: u32,
-}
-pub macro pattern($a:pat) {
- Foo { bar: $a }
-}
-
-fn main() {
- match (Foo { bar: 3 }) {
- pattern!(3) => println!("Test OK"),
- _ => unreachable!(),
- }
-}
+++ /dev/null
-fn main() {
- let items = vec![1, 2, 3];
- let ref_items: &[i32] = &items;
- let items_clone: Vec<i32> = ref_items.clone();
-//~^ ERROR mismatched types
-
- // in that case no suggestion will be triggered
- let items_clone_2:Vec<i32> = items.clone();
-
- let s = "hi";
- let string: String = s.clone();
-//~^ ERROR mismatched types
-
- // in that case no suggestion will be triggered
- let s2 = "hi";
- let string_2: String = s2.to_string();
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-53692.rs:4:37
- |
-LL | let items_clone: Vec<i32> = ref_items.clone();
- | -------- ^^^^^^^^^^^^^^^^^
- | | |
- | | expected struct `Vec`, found `&[i32]`
- | | help: try using a conversion method: `ref_items.to_vec()`
- | expected due to this
- |
- = note: expected struct `Vec<i32>`
- found reference `&[i32]`
-
-error[E0308]: mismatched types
- --> $DIR/issue-53692.rs:11:30
- |
-LL | let string: String = s.clone();
- | ------ ^^^^^^^^^
- | | |
- | | expected struct `String`, found `&str`
- | | help: try using a conversion method: `s.to_string()`
- | expected due to this
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
--> $DIR/issue-57362-1.rs:20:7
|
LL | a.f();
- | ^ method not found in `fn(&u8)`
+ | - ^ method not found in `fn(&u8)`
+ | |
+ | this is a function, perhaps you wish to call it
|
- = note: `a` is a function, perhaps you wish to call it
= help: items from traits can only be used if the trait is implemented and in scope
note: `Trait` defines an item `f`, perhaps you need to implement it
--> $DIR/issue-57362-1.rs:8:1
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `rand` is unsafe and requires unsafe function or block
--> $DIR/issue-5844.rs:8:5
|
LL | issue_5844_aux::rand();
+++ /dev/null
-fn main() {
- (if foobar) //~ ERROR expected `{`, found `)`
-}
+++ /dev/null
-error: expected `{`, found `)`
- --> $DIR/issue-61858.rs:2:15
- |
-LL | (if foobar)
- | -- ^ expected `{`
- | |
- | this `if` expression has a condition, but no block
-
-error: aborting due to previous error
-
+++ /dev/null
-#![feature(unsize, dispatch_from_dyn)]
-
-use std::marker::Unsize;
-use std::ops::DispatchFromDyn;
-
-#[allow(unused)]
-struct Foo<'a, T: ?Sized> {
- _inner: &'a &'a T,
-}
-
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {}
-//~^ ERROR the trait bound `&'a T: Unsize<&'a U>` is not satisfied
-//~| NOTE the trait `Unsize<&'a U>` is not implemented for `&'a T`
-//~| NOTE all implementations of `Unsize` are provided automatically by the compiler
-//~| NOTE required because of the requirements on the impl
-
-fn main() {}
+++ /dev/null
-error[E0277]: the trait bound `&'a T: Unsize<&'a U>` is not satisfied
- --> $DIR/issue-71036.rs:11:1
- |
-LL | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T`
- |
- = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
- = note: required because of the requirements on the impl of `DispatchFromDyn<&'a &'a U>` for `&'a &'a T`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-#![crate_type = "lib"]
-
-struct S<T = (), 'a>(&'a T);
-//~^ ERROR lifetime parameters must be declared prior to type parameters
+++ /dev/null
-error: lifetime parameters must be declared prior to type parameters
- --> $DIR/issue-80512-param-reordering-with-defaults.rs:3:18
- |
-LL | struct S<T = (), 'a>(&'a T);
- | ---------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T = ()>`
-
-error: aborting due to previous error
-
--- /dev/null
+// normalize-stderr-test "pref: Align \{\n *pow2: [1-3],\n *\}" -> "pref: $$PREF_ALIGN"
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+
+use std::mem::MaybeUninit;
+
+enum HasNiche {
+ A,
+ B,
+ C,
+}
+
+// This should result in ScalarPair(Initialized, Union),
+// since the u8 payload will be uninit for `None`.
+#[rustc_layout(debug)]
+pub enum MissingPayloadField { //~ ERROR: layout_of
+ Some(u8),
+ None
+}
+
+// This should result in ScalarPair(Initialized, Initialized),
+// since the u8 field is present in all variants,
+// and hence will always be initialized.
+#[rustc_layout(debug)]
+pub enum CommonPayloadField { //~ ERROR: layout_of
+ A(u8),
+ B(u8),
+}
+
+// This should result in ScalarPair(Initialized, Union),
+// since, though a u8-sized field is present in all variants, it might be uninit.
+#[rustc_layout(debug)]
+pub enum CommonPayloadFieldIsMaybeUninit { //~ ERROR: layout_of
+ A(u8),
+ B(MaybeUninit<u8>),
+}
+
+// This should result in ScalarPair(Initialized, Union),
+// since only the niche field (used for the tag) is guaranteed to be initialized.
+#[rustc_layout(debug)]
+pub enum NicheFirst { //~ ERROR: layout_of
+ A(HasNiche, u8),
+ B,
+ C
+}
+
+// This should result in ScalarPair(Union, Initialized),
+// since only the niche field (used for the tag) is guaranteed to be initialized.
+#[rustc_layout(debug)]
+pub enum NicheSecond { //~ ERROR: layout_of
+ A(u8, HasNiche),
+ B,
+ C,
+}
--- /dev/null
+error: layout_of(MissingPayloadField) = Layout {
+ fields: Arbitrary {
+ offsets: [
+ Size {
+ raw: 0,
+ },
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ fields: Arbitrary {
+ offsets: [
+ Size {
+ raw: 1,
+ },
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ variants: Single {
+ index: 0,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ largest_niche: None,
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 2,
+ },
+ },
+ Layout {
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ variants: Single {
+ index: 1,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ largest_niche: None,
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 1,
+ },
+ },
+ ],
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Union {
+ value: Int(
+ I8,
+ false,
+ ),
+ },
+ ),
+ largest_niche: Some(
+ Niche {
+ offset: Size {
+ raw: 0,
+ },
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ ),
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 2,
+ },
+ }
+ --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:16:1
+ |
+LL | / pub enum MissingPayloadField {
+LL | | Some(u8),
+LL | | None
+LL | | }
+ | |_^
+
+error: layout_of(CommonPayloadField) = Layout {
+ fields: Arbitrary {
+ offsets: [
+ Size {
+ raw: 0,
+ },
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ fields: Arbitrary {
+ offsets: [
+ Size {
+ raw: 1,
+ },
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ variants: Single {
+ index: 0,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ largest_niche: None,
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 2,
+ },
+ },
+ Layout {
+ fields: Arbitrary {
+ offsets: [
+ Size {
+ raw: 1,
+ },
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ variants: Single {
+ index: 1,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ largest_niche: None,
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 2,
+ },
+ },
+ ],
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ ),
+ largest_niche: Some(
+ Niche {
+ offset: Size {
+ raw: 0,
+ },
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ ),
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 2,
+ },
+ }
+ --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:25:1
+ |
+LL | / pub enum CommonPayloadField {
+LL | | A(u8),
+LL | | B(u8),
+LL | | }
+ | |_^
+
+error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
+ fields: Arbitrary {
+ offsets: [
+ Size {
+ raw: 0,
+ },
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ fields: Arbitrary {
+ offsets: [
+ Size {
+ raw: 1,
+ },
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ variants: Single {
+ index: 0,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ largest_niche: None,
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 2,
+ },
+ },
+ Layout {
+ fields: Arbitrary {
+ offsets: [
+ Size {
+ raw: 1,
+ },
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ variants: Single {
+ index: 1,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ largest_niche: None,
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 2,
+ },
+ },
+ ],
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Union {
+ value: Int(
+ I8,
+ false,
+ ),
+ },
+ ),
+ largest_niche: Some(
+ Niche {
+ offset: Size {
+ raw: 0,
+ },
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ ),
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 2,
+ },
+ }
+ --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:33:1
+ |
+LL | / pub enum CommonPayloadFieldIsMaybeUninit {
+LL | | A(u8),
+LL | | B(MaybeUninit<u8>),
+LL | | }
+ | |_^
+
+error: layout_of(NicheFirst) = Layout {
+ fields: Arbitrary {
+ offsets: [
+ Size {
+ raw: 0,
+ },
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=4,
+ },
+ tag_encoding: Niche {
+ dataful_variant: 0,
+ niche_variants: 1..=2,
+ niche_start: 3,
+ },
+ tag_field: 0,
+ variants: [
+ Layout {
+ fields: Arbitrary {
+ offsets: [
+ Size {
+ raw: 0,
+ },
+ Size {
+ raw: 1,
+ },
+ ],
+ memory_index: [
+ 0,
+ 1,
+ ],
+ },
+ variants: Single {
+ index: 0,
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=2,
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ ),
+ largest_niche: Some(
+ Niche {
+ offset: Size {
+ raw: 0,
+ },
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=2,
+ },
+ ),
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 2,
+ },
+ },
+ Layout {
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ variants: Single {
+ index: 1,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ largest_niche: None,
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 0,
+ },
+ },
+ Layout {
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ variants: Single {
+ index: 2,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ largest_niche: None,
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 0,
+ },
+ },
+ ],
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=4,
+ },
+ Union {
+ value: Int(
+ I8,
+ false,
+ ),
+ },
+ ),
+ largest_niche: Some(
+ Niche {
+ offset: Size {
+ raw: 0,
+ },
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=4,
+ },
+ ),
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 2,
+ },
+ }
+ --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:41:1
+ |
+LL | / pub enum NicheFirst {
+LL | | A(HasNiche, u8),
+LL | | B,
+LL | | C
+LL | | }
+ | |_^
+
+error: layout_of(NicheSecond) = Layout {
+ fields: Arbitrary {
+ offsets: [
+ Size {
+ raw: 1,
+ },
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=4,
+ },
+ tag_encoding: Niche {
+ dataful_variant: 0,
+ niche_variants: 1..=2,
+ niche_start: 3,
+ },
+ tag_field: 0,
+ variants: [
+ Layout {
+ fields: Arbitrary {
+ offsets: [
+ Size {
+ raw: 0,
+ },
+ Size {
+ raw: 1,
+ },
+ ],
+ memory_index: [
+ 0,
+ 1,
+ ],
+ },
+ variants: Single {
+ index: 0,
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=2,
+ },
+ ),
+ largest_niche: Some(
+ Niche {
+ offset: Size {
+ raw: 1,
+ },
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=2,
+ },
+ ),
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 2,
+ },
+ },
+ Layout {
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ variants: Single {
+ index: 1,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ largest_niche: None,
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 0,
+ },
+ },
+ Layout {
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ variants: Single {
+ index: 2,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ largest_niche: None,
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 0,
+ },
+ },
+ ],
+ },
+ abi: ScalarPair(
+ Union {
+ value: Int(
+ I8,
+ false,
+ ),
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=4,
+ },
+ ),
+ largest_niche: Some(
+ Niche {
+ offset: Size {
+ raw: 1,
+ },
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=4,
+ },
+ ),
+ align: AbiAndPrefAlign {
+ abi: Align {
+ pow2: 0,
+ },
+ pref: $PREF_ALIGN,
+ },
+ size: Size {
+ raw: 2,
+ },
+ }
+ --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:50:1
+ |
+LL | / pub enum NicheSecond {
+LL | | A(u8, HasNiche),
+LL | | B,
+LL | | C,
+LL | | }
+ | |_^
+
+error: aborting due to 5 previous errors
+
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/issue_74400.rs:12:5
|
+LL | fn g<T>(data: &[T]) {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
LL | f(data, identity)
- | ^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
+ | ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error[E0308]: mismatched types
--> $DIR/issue_74400.rs:12:5
--- /dev/null
+// build-pass
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+#![warn(clashing_extern_declarations)]
+
+// pretty-expanded FIXME #23616
+
+mod a {
+ pub type rust_task = usize;
+ pub mod rustrt {
+ use super::rust_task;
+ extern "C" {
+ pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+ }
+ }
+}
+
+mod b {
+ pub type rust_task = bool;
+ pub mod rustrt {
+ use super::rust_task;
+ extern "C" {
+ pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+ //~^ WARN `rust_task_is_unwinding` redeclared with a different signature
+ }
+ }
+}
+
+pub fn main() {}
--- /dev/null
+warning: `rust_task_is_unwinding` redeclared with a different signature
+ --> $DIR/issue-1866.rs:23:13
+ |
+LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+ | ------------------------------------------------------------ `rust_task_is_unwinding` previously declared here
+...
+LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ |
+note: the lint level is defined here
+ --> $DIR/issue-1866.rs:4:9
+ |
+LL | #![warn(clashing_extern_declarations)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `unsafe extern "C" fn(*const usize) -> bool`
+ found `unsafe extern "C" fn(*const bool) -> bool`
+
+warning: 1 warning emitted
+
--- /dev/null
+// run-pass
+#![allow(unused_variables)]
+// Regression test for Issue #20343.
+
+// pretty-expanded FIXME #23616
+
+#![deny(dead_code)]
+
+struct B { b: u32 }
+struct C;
+struct D;
+
+trait T<A> { fn dummy(&self, a: A) { } }
+impl<A> T<A> for () {}
+
+impl B {
+ // test for unused code in arguments
+ fn foo(B { b }: B) -> u32 { b }
+
+ // test for unused code in return type
+ fn bar() -> C { unsafe { ::std::mem::transmute(()) } }
+
+ // test for unused code in generics
+ fn baz<A: T<D>>() {}
+}
+
+pub fn main() {
+ let b = B { b: 3 };
+ B::foo(b);
+ B::bar();
+ B::baz::<()>();
+}
pub fn count_neutrons(&self) -> usize { self.neutrons } //~ WARNING unreachable_pub
pub(crate) fn count_electrons(&self) -> usize { self.electrons }
}
+ impl Clone for Hydrogen {
+ fn clone(&self) -> Hydrogen {
+ Hydrogen { neutrons: self.neutrons, electrons: self.electrons }
+ }
+ }
pub enum Helium {} //~ WARNING unreachable_pub
pub union Lithium { c1: usize, c2: u8 } //~ WARNING unreachable_pub
| help: consider restricting its visibility: `pub(crate)`
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:30:5
+ --> $DIR/unreachable_pub-pub_crate.rs:35:5
|
LL | pub enum Helium {}
| ---^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:31:5
+ --> $DIR/unreachable_pub-pub_crate.rs:36:5
|
LL | pub union Lithium { c1: usize, c2: u8 }
| ---^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:32:5
+ --> $DIR/unreachable_pub-pub_crate.rs:37:5
|
LL | pub fn beryllium() {}
| ---^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:33:5
+ --> $DIR/unreachable_pub-pub_crate.rs:38:5
|
LL | pub trait Boron {}
| ---^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:34:5
+ --> $DIR/unreachable_pub-pub_crate.rs:39:5
|
LL | pub const CARBON: usize = 1;
| ---^^^^^^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:35:5
+ --> $DIR/unreachable_pub-pub_crate.rs:40:5
|
LL | pub static NITROGEN: usize = 2;
| ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:36:5
+ --> $DIR/unreachable_pub-pub_crate.rs:41:5
|
LL | pub type Oxygen = bool;
| ---^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:39:47
+ --> $DIR/unreachable_pub-pub_crate.rs:44:47
|
LL | ($visibility: vis, $name: ident) => { $visibility struct $name {} }
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: this warning originates in the macro `define_empty_struct_with_visibility` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:45:9
+ --> $DIR/unreachable_pub-pub_crate.rs:50:9
|
LL | pub fn catalyze() -> bool;
| ---^^^^^^^^^^^^^^^^^^^^^^^
pub fn count_neutrons(&self) -> usize { self.neutrons } //~ WARNING unreachable_pub
crate fn count_electrons(&self) -> usize { self.electrons }
}
+ impl Clone for Hydrogen {
+ fn clone(&self) -> Hydrogen {
+ Hydrogen { neutrons: self.neutrons, electrons: self.electrons }
+ }
+ }
pub enum Helium {} //~ WARNING unreachable_pub
pub union Lithium { c1: usize, c2: u8 } //~ WARNING unreachable_pub
| help: consider restricting its visibility: `crate`
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:26:5
+ --> $DIR/unreachable_pub.rs:31:5
|
LL | pub enum Helium {}
| ---^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:27:5
+ --> $DIR/unreachable_pub.rs:32:5
|
LL | pub union Lithium { c1: usize, c2: u8 }
| ---^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:28:5
+ --> $DIR/unreachable_pub.rs:33:5
|
LL | pub fn beryllium() {}
| ---^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:29:5
+ --> $DIR/unreachable_pub.rs:34:5
|
LL | pub trait Boron {}
| ---^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:30:5
+ --> $DIR/unreachable_pub.rs:35:5
|
LL | pub const CARBON: usize = 1;
| ---^^^^^^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:31:5
+ --> $DIR/unreachable_pub.rs:36:5
|
LL | pub static NITROGEN: usize = 2;
| ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:32:5
+ --> $DIR/unreachable_pub.rs:37:5
|
LL | pub type Oxygen = bool;
| ---^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:35:47
+ --> $DIR/unreachable_pub.rs:40:47
|
LL | ($visibility: vis, $name: ident) => { $visibility struct $name {} }
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: this warning originates in the macro `define_empty_struct_with_visibility` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:41:9
+ --> $DIR/unreachable_pub.rs:46:9
|
LL | pub fn catalyze() -> bool;
| ---^^^^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+fn main() {
+ include!(line!()); //~ ERROR argument must be a string literal
+}
--- /dev/null
+error: argument must be a string literal
+ --> $DIR/issue-41776.rs:2:14
+ |
+LL | include!(line!());
+ | ^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+
+#![feature(decl_macro)]
+
+pub struct Foo {
+ bar: u32,
+}
+pub macro pattern($a:pat) {
+ Foo { bar: $a }
+}
+
+fn main() {
+ match (Foo { bar: 3 }) {
+ pattern!(3) => println!("Test OK"),
+ _ => unreachable!(),
+ }
+}
// compile-flags: -Zunpretty=hir,typed
// check-pass
-pub fn main() ({
+fn main() ({
(if (true as bool)
({ } as
()) else if (let Some(a) =
--- /dev/null
+fn main() {
+ let arr = &[0,1,2,3];
+ for _i in 0..arr.len().rev() { //~ERROR not an iterator
+ // The above error used to say “the method `rev` exists for type `usize`”.
+ // This regression test ensures it doesn't say that any more.
+ }
+}
--- /dev/null
+error[E0599]: `usize` is not an iterator
+ --> $DIR/issue-90315.rs:3:26
+ |
+LL | for _i in 0..arr.len().rev() {
+ | ^^^ `usize` is not an iterator
+ |
+ = note: the following trait bounds were not satisfied:
+ `usize: Iterator`
+ which is required by `&mut usize: Iterator`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
-LL | impl<I: Iterator> IntoIterator for I {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<I: ~const Iterator> const IntoIterator for I {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
error[E0658]: mutable references are not allowed in constants
--- /dev/null
+fn main() {
+ 0.....{loop{}1};
+ //~^ ERROR unexpected token
+ //~| ERROR mismatched types
+}
--- /dev/null
+error: unexpected token: `...`
+ --> $DIR/issue-96335.rs:2:6
+ |
+LL | 0.....{loop{}1};
+ | ^^^
+ |
+help: use `..` for an exclusive range
+ |
+LL | 0....{loop{}1};
+ | ~~
+help: or `..=` for an inclusive range
+ |
+LL | 0..=..{loop{}1};
+ | ~~~
+
+error[E0308]: mismatched types
+ --> $DIR/issue-96335.rs:2:9
+ |
+LL | 0.....{loop{}1};
+ | ----^^^^^^^^^^^
+ | | |
+ | | expected integer, found struct `RangeTo`
+ | arguments to this function are incorrect
+ |
+ = note: expected type `{integer}`
+ found struct `RangeTo<{integer}>`
+note: associated function defined here
+ --> $SRC_DIR/core/src/ops/range.rs:LL:COL
+ |
+LL | pub const fn new(start: Idx, end: Idx) -> Self {
+ | ^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/propagate-from-trait-match.rs:32:36
|
+LL | fn supply<'a, T>(value: T)
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | establish_relationships(value, |value| {
| ____________________________________^
LL | |
... |
LL | | require(value);
LL | | });
- | |_____^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | |_____^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to previous error
| -- lifetime `'a` defined here
LL | x
| ^ returning this value requires that `'a` must outlive `'static`
+ |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound
+ |
+LL | fn bar<'a>(x: &'a u32) -> &'static dyn Debug + 'a {
+ | ++++
error: aborting due to previous error
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/impl-trait-outlives.rs:11:5
|
+LL | fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | x
- | ^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^ ...so that the type `T` will meet its required lifetime bounds
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/impl-trait-outlives.rs:26:5
|
+LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | x
- | ^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to 2 previous errors
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/projection-implied-bounds.rs:30:18
|
+LL | fn generic2<T: Iterator>(value: T) {
+ | -- help: consider adding an explicit lifetime bound...: `T: 'static +`
LL | twice(value, |value_ref, item| invoke2(value_ref, item));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to previous error
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+ = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
note: external requirements
--> $DIR/projection-no-regions-closure.rs:34:23
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+ = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
note: external requirements
--> $DIR/projection-no-regions-closure.rs:52:23
| ^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+ = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
--> $DIR/projection-no-regions-fn.rs:28:5
| ^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+ = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
error: aborting due to 2 previous errors
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/projection-one-region-closure.rs:45:29
|
+LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error: lifetime may not live long enough
--> $DIR/projection-one-region-closure.rs:45:39
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/projection-one-region-closure.rs:56:29
|
+LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error: lifetime may not live long enough
--> $DIR/projection-one-region-closure.rs:56:39
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: 'a`...
+ = note: ...so that the type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` will meet its required lifetime bounds
note: external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:48:29
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: 'a`...
+ = note: ...so that the type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` will meet its required lifetime bounds
note: external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:61:29
| ^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
+ = note: ...so that the type `<T as MyTrait<'_>>::Output` will meet its required lifetime bounds
error: aborting due to previous error
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
+ = note: ...so that the type `<T as MyTrait<'_>>::Output` will meet its required lifetime bounds
error: aborting due to previous error
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/projection-where-clause-none.rs:16:5
|
+LL | fn foo<'a, T>() -> &'a ()
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | bar::<T::Output>()
- | ^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to previous error
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24
|
+LL | fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
LL | twice(cell, value, |a, b| invoke(a, b));
- | ^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to previous error
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-outlives-from-return-type.rs:26:23
|
+LL | fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a>
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | with_signature(x, |y| y)
- | ^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^^^^^ ...so that the type `T` will meet its required lifetime bounds
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-outlives-from-return-type.rs:41:5
|
+LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | x
- | ^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to 2 previous errors
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:27:26
|
+LL | fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
LL | with_signature(a, b, |x, y| {
| __________________________^
LL | |
... |
LL | | require(&x, &y)
LL | | })
- | |_____^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | |_____^ ...so that the type `T` will meet its required lifetime bounds
note: external requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:43:26
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:64:26
|
+LL | fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | with_signature(a, b, |x, y| {
| __________________________^
LL | |
LL | | // See `correct_region`
LL | | require(&x, &y)
LL | | })
- | |_____^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | |_____^ ...so that the type `T` will meet its required lifetime bounds
note: external requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:77:26
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-fn-body.rs:19:5
|
+LL | fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) {
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
LL | outlives(cell, t)
- | ^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to previous error
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-fn.rs:11:5
|
+LL | fn no_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | x
- | ^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^ ...so that the type `T` will meet its required lifetime bounds
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-fn.rs:26:5
|
+LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | x
- | ^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to 2 previous errors
...
LL | ss.r
| ^^^^ returning this value requires that `'1` must outlive `'static`
+ |
+help: to declare that the trait object captures data from argument `ss`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait + '_> {
+ | ++++
error[E0507]: cannot move out of `ss.r` which is behind a mutable reference
--> $DIR/object-lifetime-default-from-box-error.rs:18:5
--- /dev/null
+fn main() {
+ (if foobar) //~ ERROR expected `{`, found `)`
+}
--- /dev/null
+error: expected `{`, found `)`
+ --> $DIR/issue-61858.rs:2:15
+ |
+LL | (if foobar)
+ | -- ^ expected `{`
+ | |
+ | this `if` expression has a condition, but no block
+
+error: aborting due to previous error
+
static s: &'static str =
+ r#""## //~ ERROR too many `#` when terminating raw string
+;
+
+static s2: &'static str =
r#"
- "## //~ too many `#` when terminating raw string
+ "#### //~ ERROR too many `#` when terminating raw string
;
+
+const A: &'static str = r"" //~ ERROR expected `;`, found `#`
+
+// Test
+#[test]
+fn test() {}
+
+const B: &'static str = r""## //~ ERROR too many `#` when terminating raw string
+
+// Test
+#[test]
+fn test2() {}
+
+fn main() {}
error: too many `#` when terminating raw string
- --> $DIR/raw-str-unbalanced.rs:3:9
+ --> $DIR/raw-str-unbalanced.rs:2:10
|
-LL | "##
- | ^ help: remove the extra `#`
+LL | r#""##
+ | -----^ help: remove the extra `#`
+ | |
+ | this raw string started with 1 `#`
+
+error: too many `#` when terminating raw string
+ --> $DIR/raw-str-unbalanced.rs:7:9
+ |
+LL | / r#"
+LL | | "####
+ | | -^^^ help: remove the extra `#`s
+ | |________|
+ | this raw string started with 1 `#`
+
+error: expected `;`, found `#`
+ --> $DIR/raw-str-unbalanced.rs:10:28
+ |
+LL | const A: &'static str = r""
+ | ^ help: add `;` here
+...
+LL | #[test]
+ | - unexpected token
+
+error: too many `#` when terminating raw string
+ --> $DIR/raw-str-unbalanced.rs:16:28
|
- = note: the raw string started with 1 `#`s
+LL | const B: &'static str = r""##
+ | ---^^ help: remove the extra `#`s
+ | |
+ | this raw string started with 0 `#`s
-error: aborting due to previous error
+error: aborting due to 4 previous errors
--- /dev/null
+error[E0478]: lifetime bound not satisfied
+ --> $DIR/issue-28848.rs:14:5
+ |
+LL | Foo::<'a, 'b>::xmute(u)
+ | ^^^^^^^^^^^^^
+ |
+note: lifetime parameter instantiated with the lifetime `'b` as defined here
+ --> $DIR/issue-28848.rs:13:16
+ |
+LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
+ | ^^
+note: but lifetime parameter must outlive the lifetime `'a` as defined here
+ --> $DIR/issue-28848.rs:13:12
+ |
+LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0478`.
error: lifetime may not live long enough
- --> $DIR/issue-28848.rs:10:5
+ --> $DIR/issue-28848.rs:14:5
|
LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
| -- -- lifetime `'b` defined here
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
struct Foo<'a, 'b: 'a>(&'a &'b ());
impl<'a, 'b> Foo<'a, 'b> {
}
pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
- Foo::<'a, 'b>::xmute(u) //~ ERROR lifetime bound not satisfied
+ Foo::<'a, 'b>::xmute(u)
+ //[base]~^ ERROR lifetime bound not satisfied
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0478]: lifetime bound not satisfied
- --> $DIR/issue-28848.rs:10:5
- |
-LL | Foo::<'a, 'b>::xmute(u)
- | ^^^^^^^^^^^^^
- |
-note: lifetime parameter instantiated with the lifetime `'b` as defined here
- --> $DIR/issue-28848.rs:9:16
- |
-LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
- | ^^
-note: but lifetime parameter must outlive the lifetime `'a` as defined here
- --> $DIR/issue-28848.rs:9:12
- |
-LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
- | ^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0478`.
--- /dev/null
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/region-invariant-static-error-reporting.rs:21:9
+ |
+LL | let bad = if x.is_some() {
+ | _______________-
+LL | | x.unwrap()
+ | | ---------- expected because of this
+LL | | } else {
+LL | | mk_static()
+ | | ^^^^^^^^^^^ lifetime mismatch
+LL | | };
+ | |_____- `if` and `else` have incompatible types
+ |
+ = note: expected struct `Invariant<'a>`
+ found struct `Invariant<'static>`
+note: the lifetime `'a` as defined here...
+ --> $DIR/region-invariant-static-error-reporting.rs:17:10
+ |
+LL | fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
+ | ^^
+ = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
error[E0521]: borrowed data escapes outside of function
- --> $DIR/region-invariant-static-error-reporting.rs:15:9
+ --> $DIR/region-invariant-static-error-reporting.rs:19:9
|
LL | fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
| -- - `x` is a reference that is only valid in the function body
// over time, but this test used to exhibit some pretty bogus messages
// that were not remotely helpful.
-// error-pattern:the lifetime `'a`
-// error-pattern:the static lifetime
+// revisions: base nll
+// ignore-compare-mode-nll
+//[base] error-pattern:the lifetime `'a`
+//[base] error-pattern:the static lifetime
+//[nll] compile-flags: -Z borrowck=mir
+//[nll] error-pattern:argument requires that `'a` must outlive `'static`
struct Invariant<'a>(Option<&'a mut &'a mut ()>);
fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
let bad = if x.is_some() {
- x.unwrap()
+ x.unwrap() //[nll]~ ERROR borrowed data escapes outside of function [E0521]
} else {
- mk_static()
+ mk_static() //[base]~ ERROR `if` and `else` have incompatible types [E0308]
};
f(bad);
}
+++ /dev/null
-error[E0308]: `if` and `else` have incompatible types
- --> $DIR/region-invariant-static-error-reporting.rs:17:9
- |
-LL | let bad = if x.is_some() {
- | _______________-
-LL | | x.unwrap()
- | | ---------- expected because of this
-LL | | } else {
-LL | | mk_static()
- | | ^^^^^^^^^^^ lifetime mismatch
-LL | | };
- | |_____- `if` and `else` have incompatible types
- |
- = note: expected struct `Invariant<'a>`
- found struct `Invariant<'static>`
-note: the lifetime `'a` as defined here...
- --> $DIR/region-invariant-static-error-reporting.rs:13:10
- |
-LL | fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
- | ^^
- = note: ...does not necessarily outlive the static lifetime
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:12:10
+ |
+LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
+ | --------- --------- these two types are declared with different lifetimes...
+LL | // Illegal now because there is no `'b:'a` declaration.
+LL | *x = *y;
+ | ^^ ...but data from `y` flows into `x` here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:7
+ |
+LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
+ | --------- --------- these two types are declared with different lifetimes...
+...
+LL | a(x, y);
+ | ^ ...but data from `y` flows into `x` here
+
+error[E0308]: mismatched types
+ --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:28:43
+ |
+LL | let _: fn(&mut &isize, &mut &isize) = a;
+ | ^ one type is more general than the other
+ |
+ = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
+ found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0623.
+For more information about an error, try `rustc --explain E0308`.
error: lifetime may not live long enough
- --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:8:5
+ --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:12:5
|
LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'b: 'a`
error: lifetime may not live long enough
- --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:14:5
+ --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:5
|
LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
| -- -- lifetime `'b` defined here
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error[E0308]: mismatched types
- --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
+ --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:28:12
|
LL | let _: fn(&mut &isize, &mut &isize) = a;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
error[E0308]: mismatched types
- --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
+ --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:28:12
|
LL | let _: fn(&mut &isize, &mut &isize) = a;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
fn a<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) where 'b: 'a {
// Note: this is legal because of the `'b:'a` declaration.
*x = *y;
fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
// Illegal now because there is no `'b:'a` declaration.
- *x = *y; //~ ERROR E0623
+ *x = *y;
+ //[base]~^ ERROR E0623
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
// Here we try to call `foo` but do not know that `'a` and `'b` are
// related as required.
- a(x, y); //~ ERROR lifetime mismatch [E0623]
+ a(x, y);
+ //[base]~^ ERROR lifetime mismatch [E0623]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn d() {
// 'a and 'b are early bound in the function `a` because they appear
// inconstraints:
- let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR mismatched types
+ let _: fn(&mut &isize, &mut &isize) = a;
+ //~^ ERROR mismatched types [E0308]
+ //[nll]~^^ ERROR mismatched types [E0308]
}
fn e() {
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:8:10
- |
-LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
- | --------- --------- these two types are declared with different lifetimes...
-LL | // Illegal now because there is no `'b:'a` declaration.
-LL | *x = *y;
- | ^^ ...but data from `y` flows into `x` here
-
-error[E0623]: lifetime mismatch
- --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:14:7
- |
-LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
- | --------- --------- these two types are declared with different lifetimes...
-...
-LL | a(x, y);
- | ^ ...but data from `y` flows into `x` here
-
-error[E0308]: mismatched types
- --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43
- |
-LL | let _: fn(&mut &isize, &mut &isize) = a;
- | ^ one type is more general than the other
- |
- = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
- found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0308, E0623.
-For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:13:10
+ |
+LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+ | --------- --------- these two types are declared with different lifetimes...
+LL | // Illegal now because there is no `'b:'a` declaration.
+LL | *x = *y;
+ | ^^ ...but data from `y` flows into `x` here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:10
+ |
+LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+ | --------- ---------
+ | |
+ | these two types are declared with different lifetimes...
+...
+LL | *z = *y;
+ | ^^ ...but data from `y` flows into `z` here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:7
+ |
+LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+ | --------- --------- these two types are declared with different lifetimes...
+...
+LL | a(x, y, z);
+ | ^ ...but data from `y` flows into `x` here
+
+error[E0308]: mismatched types
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:30:56
+ |
+LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+ | ^ one type is more general than the other
+ |
+ = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
+ found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0308, E0623.
+For more information about an error, try `rustc --explain E0308`.
error: lifetime may not live long enough
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:9:5
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:13:5
|
LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'b: 'a`
error: lifetime may not live long enough
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:5
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:5
|
LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
| -- -- lifetime `'b` defined here
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error[E0308]: mismatched types
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:30:12
|
LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
error[E0308]: mismatched types
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:30:12
|
LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
error[E0308]: mismatched types
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:30:12
|
LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:9:5
- |
-LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | // Illegal now because there is no `'b:'a` declaration.
-LL | *x = *y;
- | ^^^^^^^ assignment requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: lifetime may not live long enough
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:10:5
- |
-LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
- | -- -- lifetime `'c` defined here
- | |
- | lifetime `'b` defined here
-...
-LL | *z = *y;
- | ^^^^^^^ assignment requires that `'b` must outlive `'c`
- |
- = help: consider adding the following bound: `'b: 'c`
-
-help: add bound `'b: 'a + 'c`
-
-error: lifetime may not live long enough
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:5
- |
-LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | a(x, y, z);
- | ^^^^^^^^^^ argument requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
- = note: requirement occurs because of a mutable reference to &isize
- = note: mutable references are invariant over their type parameter
- = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
-
-error: lifetime may not live long enough
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:5
- |
-LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
- | -- -- lifetime `'c` defined here
- | |
- | lifetime `'b` defined here
-...
-LL | a(x, y, z);
- | ^^^^^^^^^^ argument requires that `'b` must outlive `'c`
- |
- = help: consider adding the following bound: `'b: 'c`
- = note: requirement occurs because of a mutable reference to &isize
- = note: mutable references are invariant over their type parameter
- = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
-
-help: add bound `'b: 'a + 'c`
-
-error: higher-ranked subtype error
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
- |
-LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
- |
-LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
- |
-LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 7 previous errors
-
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
fn a<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) where 'b: 'a + 'c {
// Note: this is legal because of the `'b:'a` declaration.
*x = *y;
fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
// Illegal now because there is no `'b:'a` declaration.
- *x = *y; //~ ERROR E0623
- *z = *y; //~ ERROR E0623
+ *x = *y;
+ //[base]~^ ERROR E0623
+ //[nll]~^^ ERROR lifetime may not live long enough
+ *z = *y; //[base]~ ERROR E0623
}
fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
// Here we try to call `foo` but do not know that `'a` and `'b` are
// related as required.
- a(x, y, z); //~ ERROR lifetime mismatch [E0623]
+ a(x, y, z);
+ //[base]~^ ERROR lifetime mismatch [E0623]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn d() {
// 'a and 'b are early bound in the function `a` because they appear
// inconstraints:
- let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR E0308
+ let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+ //~^ ERROR E0308
+ //[nll]~^^ ERROR mismatched types [E0308]
+ //[nll]~| ERROR mismatched types [E0308]
}
fn e() {
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:9:10
- |
-LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
- | --------- --------- these two types are declared with different lifetimes...
-LL | // Illegal now because there is no `'b:'a` declaration.
-LL | *x = *y;
- | ^^ ...but data from `y` flows into `x` here
-
-error[E0623]: lifetime mismatch
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:10:10
- |
-LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
- | --------- ---------
- | |
- | these two types are declared with different lifetimes...
-...
-LL | *z = *y;
- | ^^ ...but data from `y` flows into `z` here
-
-error[E0623]: lifetime mismatch
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:7
- |
-LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
- | --------- --------- these two types are declared with different lifetimes...
-...
-LL | a(x, y, z);
- | ^ ...but data from `y` flows into `x` here
-
-error[E0308]: mismatched types
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56
- |
-LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
- | ^ one type is more general than the other
- |
- = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
- found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0308, E0623.
-For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
+ --> $DIR/region-object-lifetime-2.rs:14:7
+ |
+LL | x.borrowed()
+ | ^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+ --> $DIR/region-object-lifetime-2.rs:13:42
+ |
+LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
+ | ^^
+note: ...so that reference does not outlive borrowed content
+ --> $DIR/region-object-lifetime-2.rs:14:5
+ |
+LL | x.borrowed()
+ | ^
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+ --> $DIR/region-object-lifetime-2.rs:13:45
+ |
+LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
+ | ^^
+note: ...so that reference does not outlive borrowed content
+ --> $DIR/region-object-lifetime-2.rs:14:5
+ |
+LL | x.borrowed()
+ | ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
error: lifetime may not live long enough
- --> $DIR/region-object-lifetime-2.rs:10:5
+ --> $DIR/region-object-lifetime-2.rs:14:5
|
LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
| -- -- lifetime `'b` defined here
// Various tests related to testing how region inference works
// with respect to the object receivers.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait Foo {
fn borrowed<'a>(&'a self) -> &'a ();
}
// Borrowed receiver but two distinct lifetimes, we get an error.
fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
- x.borrowed() //~ ERROR cannot infer
+ x.borrowed()
+ //[base]~^ ERROR cannot infer
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
- --> $DIR/region-object-lifetime-2.rs:10:7
- |
-LL | x.borrowed()
- | ^^^^^^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
- --> $DIR/region-object-lifetime-2.rs:9:42
- |
-LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
- | ^^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/region-object-lifetime-2.rs:10:5
- |
-LL | x.borrowed()
- | ^
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
- --> $DIR/region-object-lifetime-2.rs:9:45
- |
-LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
- | ^^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/region-object-lifetime-2.rs:10:5
- |
-LL | x.borrowed()
- | ^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
--- /dev/null
+error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
+ --> $DIR/region-object-lifetime-4.rs:16:7
+ |
+LL | x.borrowed()
+ | ^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+ --> $DIR/region-object-lifetime-4.rs:15:41
+ |
+LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
+ | ^^
+note: ...so that reference does not outlive borrowed content
+ --> $DIR/region-object-lifetime-4.rs:16:5
+ |
+LL | x.borrowed()
+ | ^
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+ --> $DIR/region-object-lifetime-4.rs:15:44
+ |
+LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
+ | ^^
+note: ...so that reference does not outlive borrowed content
+ --> $DIR/region-object-lifetime-4.rs:16:5
+ |
+LL | x.borrowed()
+ | ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
error: lifetime may not live long enough
- --> $DIR/region-object-lifetime-4.rs:12:5
+ --> $DIR/region-object-lifetime-4.rs:16:5
|
LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
| -- -- lifetime `'b` defined here
// Various tests related to testing how region inference works
// with respect to the object receivers.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait Foo {
fn borrowed<'a>(&'a self) -> &'a ();
}
// with the longer lifetime when (from the signature) we only know
// that it lives as long as the shorter lifetime. Therefore, error.
fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
- x.borrowed() //~ ERROR cannot infer
+ x.borrowed()
+ //[base]~^ ERROR cannot infer
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
- --> $DIR/region-object-lifetime-4.rs:12:7
- |
-LL | x.borrowed()
- | ^^^^^^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
- --> $DIR/region-object-lifetime-4.rs:11:41
- |
-LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
- | ^^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/region-object-lifetime-4.rs:12:5
- |
-LL | x.borrowed()
- | ^
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
- --> $DIR/region-object-lifetime-4.rs:11:44
- |
-LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
- | ^^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/region-object-lifetime-4.rs:12:5
- |
-LL | x.borrowed()
- | ^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
--- /dev/null
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/region-object-lifetime-in-coercion.rs:12:46
+ |
+LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
+ | ----- this data with an anonymous lifetime `'_`...
+LL | let x: Box<dyn Foo + 'static> = Box::new(v);
+ | ^ ...is used and required to live as long as `'static` here
+ |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+ |
+LL | fn a(v: &[u8]) -> Box<dyn Foo + '_> {
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> {
+ | ~~~~~~~~~~~~~
+
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/region-object-lifetime-in-coercion.rs:19:14
+ |
+LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
+ | ----- this data with an anonymous lifetime `'_`...
+LL | Box::new(v)
+ | ^ ...is used and required to live as long as `'static` here
+ |
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/region-object-lifetime-in-coercion.rs:18:33
+ |
+LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
+ | ^^^^^^^ `'static` requirement introduced here
+LL | Box::new(v)
+ | ----------- because of this returned expression
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+ |
+LL | fn b(v: &[u8]) -> Box<dyn Foo + '_> {
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> {
+ | ~~~~~~~~~~~~~
+
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/region-object-lifetime-in-coercion.rs:27:14
+ |
+LL | fn c(v: &[u8]) -> Box<dyn Foo> {
+ | ----- this data with an anonymous lifetime `'_`...
+...
+LL | Box::new(v)
+ | ^ ...is used and required to live as long as `'static` here
+ |
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/region-object-lifetime-in-coercion.rs:24:23
+ |
+LL | fn c(v: &[u8]) -> Box<dyn Foo> {
+ | ^^^^^^^ `'static` requirement introduced here
+...
+LL | Box::new(v)
+ | ----------- because of this returned expression
+help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn c(v: &[u8]) -> Box<dyn Foo + '_> {
+ | ++++
+
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+ --> $DIR/region-object-lifetime-in-coercion.rs:33:14
+ |
+LL | Box::new(v)
+ | ^
+ |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+ --> $DIR/region-object-lifetime-in-coercion.rs:32:6
+ |
+LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
+ | ^^
+note: ...so that the expression is assignable
+ --> $DIR/region-object-lifetime-in-coercion.rs:33:14
+ |
+LL | Box::new(v)
+ | ^
+ = note: expected `&[u8]`
+ found `&'a [u8]`
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+ --> $DIR/region-object-lifetime-in-coercion.rs:32:9
+ |
+LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
+ | ^^
+note: ...so that the types are compatible
+ --> $DIR/region-object-lifetime-in-coercion.rs:33:5
+ |
+LL | Box::new(v)
+ | ^^^^^^^^^^^
+ = note: expected `Box<(dyn Foo + 'b)>`
+ found `Box<dyn Foo>`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0495, E0759.
+For more information about an error, try `rustc --explain E0495`.
error: lifetime may not live long enough
- --> $DIR/region-object-lifetime-in-coercion.rs:8:12
+ --> $DIR/region-object-lifetime-in-coercion.rs:12:12
|
LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
| - let's call the lifetime of this reference `'1`
LL | let x: Box<dyn Foo + 'static> = Box::new(v);
| ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
+ |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+ |
+LL | fn a(v: &[u8]) -> Box<dyn Foo + '_> {
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> {
+ | ~~~~~~~~~~~~~
error: lifetime may not live long enough
- --> $DIR/region-object-lifetime-in-coercion.rs:13:5
+ --> $DIR/region-object-lifetime-in-coercion.rs:19:5
|
LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
| - let's call the lifetime of this reference `'1`
LL | Box::new(v)
| ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+ |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+ |
+LL | fn b(v: &[u8]) -> Box<dyn Foo + '_> {
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> {
+ | ~~~~~~~~~~~~~
error: lifetime may not live long enough
- --> $DIR/region-object-lifetime-in-coercion.rs:19:5
+ --> $DIR/region-object-lifetime-in-coercion.rs:27:5
|
LL | fn c(v: &[u8]) -> Box<dyn Foo> {
| - let's call the lifetime of this reference `'1`
...
LL | Box::new(v)
| ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+ |
+help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn c(v: &[u8]) -> Box<dyn Foo + '_> {
+ | ++++
error: lifetime may not live long enough
- --> $DIR/region-object-lifetime-in-coercion.rs:23:5
+ --> $DIR/region-object-lifetime-in-coercion.rs:33:5
|
LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
| -- -- lifetime `'b` defined here
// Test that attempts to implicitly coerce a value into an
// object respect the lifetime bound on the object type.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait Foo {}
impl<'a> Foo for &'a [u8] {}
fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
- let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR E0759
+ let x: Box<dyn Foo + 'static> = Box::new(v);
+ //[base]~^ ERROR E0759
+ //[nll]~^^ ERROR lifetime may not live long enough
x
}
fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
- Box::new(v) //~ ERROR E0759
+ Box::new(v)
+ //[base]~^ ERROR E0759
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn c(v: &[u8]) -> Box<dyn Foo> {
// same as previous case due to RFC 599
- Box::new(v) //~ ERROR E0759
+ Box::new(v)
+ //[base]~^ ERROR E0759
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
- Box::new(v) //~ ERROR cannot infer an appropriate lifetime due to conflicting
+ Box::new(v)
+ //[base]~^ ERROR cannot infer an appropriate lifetime due to conflicting
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn e<'a:'b,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
+++ /dev/null
-error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/region-object-lifetime-in-coercion.rs:8:46
- |
-LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
- | ----- this data with an anonymous lifetime `'_`...
-LL | let x: Box<dyn Foo + 'static> = Box::new(v);
- | ^ ...is used and required to live as long as `'static` here
- |
-help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
- |
-LL | fn a(v: &[u8]) -> Box<dyn Foo + '_> {
- | ~~
-help: alternatively, add an explicit `'static` bound to this reference
- |
-LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> {
- | ~~~~~~~~~~~~~
-
-error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/region-object-lifetime-in-coercion.rs:13:14
- |
-LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
- | ----- this data with an anonymous lifetime `'_`...
-LL | Box::new(v)
- | ^ ...is used and required to live as long as `'static` here
- |
-note: `'static` lifetime requirement introduced by the return type
- --> $DIR/region-object-lifetime-in-coercion.rs:12:33
- |
-LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
- | ^^^^^^^ `'static` requirement introduced here
-LL | Box::new(v)
- | ----------- because of this returned expression
-help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
- |
-LL | fn b(v: &[u8]) -> Box<dyn Foo + '_> {
- | ~~
-help: alternatively, add an explicit `'static` bound to this reference
- |
-LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> {
- | ~~~~~~~~~~~~~
-
-error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/region-object-lifetime-in-coercion.rs:19:14
- |
-LL | fn c(v: &[u8]) -> Box<dyn Foo> {
- | ----- this data with an anonymous lifetime `'_`...
-...
-LL | Box::new(v)
- | ^ ...is used and required to live as long as `'static` here
- |
-note: `'static` lifetime requirement introduced by the return type
- --> $DIR/region-object-lifetime-in-coercion.rs:16:23
- |
-LL | fn c(v: &[u8]) -> Box<dyn Foo> {
- | ^^^^^^^ `'static` requirement introduced here
-...
-LL | Box::new(v)
- | ----------- because of this returned expression
-help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound
- |
-LL | fn c(v: &[u8]) -> Box<dyn Foo + '_> {
- | ++++
-
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
- --> $DIR/region-object-lifetime-in-coercion.rs:23:14
- |
-LL | Box::new(v)
- | ^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
- --> $DIR/region-object-lifetime-in-coercion.rs:22:6
- |
-LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
- | ^^
-note: ...so that the expression is assignable
- --> $DIR/region-object-lifetime-in-coercion.rs:23:14
- |
-LL | Box::new(v)
- | ^
- = note: expected `&[u8]`
- found `&'a [u8]`
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
- --> $DIR/region-object-lifetime-in-coercion.rs:22:9
- |
-LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
- | ^^
-note: ...so that the types are compatible
- --> $DIR/region-object-lifetime-in-coercion.rs:23:5
- |
-LL | Box::new(v)
- | ^^^^^^^^^^^
- = note: expected `Box<(dyn Foo + 'b)>`
- found `Box<dyn Foo>`
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0495, E0759.
-For more information about an error, try `rustc --explain E0495`.
--- /dev/null
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/regions-addr-of-self.rs:11:37
+ |
+LL | pub fn chase_cat(&mut self) {
+ | --------- this data with an anonymous lifetime `'_`...
+LL | let p: &'static mut usize = &mut self.cats_chased;
+ | ^^^^^^^^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0759`.
error: lifetime may not live long enough
- --> $DIR/regions-addr-of-self.rs:7:16
+ --> $DIR/regions-addr-of-self.rs:11:16
|
LL | pub fn chase_cat(&mut self) {
| - let's call the lifetime of this reference `'1`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
struct Dog {
cats_chased: usize,
}
impl Dog {
pub fn chase_cat(&mut self) {
- let p: &'static mut usize = &mut self.cats_chased; //~ ERROR E0759
+ let p: &'static mut usize = &mut self.cats_chased;
+ //[base]~^ ERROR E0759
+ //[nll]~^^ ERROR lifetime may not live long enough
*p += 1;
}
+++ /dev/null
-error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/regions-addr-of-self.rs:7:37
- |
-LL | pub fn chase_cat(&mut self) {
- | --------- this data with an anonymous lifetime `'_`...
-LL | let p: &'static mut usize = &mut self.cats_chased;
- | ^^^^^^^^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0759`.
--- /dev/null
+error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+ --> $DIR/regions-addr-of-upvar-self.rs:12:41
+ |
+LL | let p: &'static mut usize = &mut self.food;
+ | ^^^^^^^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
+ --> $DIR/regions-addr-of-upvar-self.rs:11:18
+ |
+LL | let _f = || {
+ | ^^
+note: ...so that closure can access `self`
+ --> $DIR/regions-addr-of-upvar-self.rs:12:41
+ |
+LL | let p: &'static mut usize = &mut self.food;
+ | ^^^^^^^^^^^^^^
+ = note: but, the lifetime must be valid for the static lifetime...
+note: ...so that reference does not outlive borrowed content
+ --> $DIR/regions-addr-of-upvar-self.rs:12:41
+ |
+LL | let p: &'static mut usize = &mut self.food;
+ | ^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
error: lifetime may not live long enough
- --> $DIR/regions-addr-of-upvar-self.rs:8:20
+ --> $DIR/regions-addr-of-upvar-self.rs:12:20
|
LL | let _f = || {
| -- lifetime `'1` represents this closure's body
= note: closure implements `FnMut`, so references to captured variables can't escape the closure
error: lifetime may not live long enough
- --> $DIR/regions-addr-of-upvar-self.rs:8:20
+ --> $DIR/regions-addr-of-upvar-self.rs:12:20
|
LL | pub fn chase_cat(&mut self) {
| - let's call the lifetime of this reference `'1`
| ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
error[E0597]: `self` does not live long enough
- --> $DIR/regions-addr-of-upvar-self.rs:8:46
+ --> $DIR/regions-addr-of-upvar-self.rs:12:46
|
LL | let _f = || {
| -- value captured here
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
struct Dog {
food: usize,
}
impl Dog {
pub fn chase_cat(&mut self) {
let _f = || {
- let p: &'static mut usize = &mut self.food; //~ ERROR cannot infer
+ let p: &'static mut usize = &mut self.food;
+ //[base]~^ ERROR cannot infer
+ //[nll]~^^ ERROR lifetime may not live long enough
+ //[nll]~^^^ ERROR lifetime may not live long enough
+ //[nll]~^^^^ ERROR E0597
*p = 3;
};
}
+++ /dev/null
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
- --> $DIR/regions-addr-of-upvar-self.rs:8:41
- |
-LL | let p: &'static mut usize = &mut self.food;
- | ^^^^^^^^^^^^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
- --> $DIR/regions-addr-of-upvar-self.rs:7:18
- |
-LL | let _f = || {
- | ^^
-note: ...so that closure can access `self`
- --> $DIR/regions-addr-of-upvar-self.rs:8:41
- |
-LL | let p: &'static mut usize = &mut self.food;
- | ^^^^^^^^^^^^^^
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that reference does not outlive borrowed content
- --> $DIR/regions-addr-of-upvar-self.rs:8:41
- |
-LL | let p: &'static mut usize = &mut self.food;
- | ^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
--- /dev/null
+error[E0477]: the type `&'a isize` does not fulfill the required lifetime
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5
+ |
+LL | assert_send::<&'a isize>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: type must satisfy the static lifetime as required by this binding
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:10:18
+ |
+LL | fn assert_send<T:'static>() { }
+ | ^^^^^^^
+
+error[E0477]: the type `&'a str` does not fulfill the required lifetime
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:32:5
+ |
+LL | assert_send::<&'a str>();
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: type must satisfy the static lifetime as required by this binding
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:10:18
+ |
+LL | fn assert_send<T:'static>() { }
+ | ^^^^^^^
+
+error[E0477]: the type `&'a [isize]` does not fulfill the required lifetime
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:38:5
+ |
+LL | assert_send::<&'a [isize]>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: type must satisfy the static lifetime as required by this binding
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:10:18
+ |
+LL | fn assert_send<T:'static>() { }
+ | ^^^^^^^
+
+error[E0477]: the type `Box<&'a isize>` does not fulfill the required lifetime
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:54:5
+ |
+LL | assert_send::<Box<&'a isize>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: type must satisfy the static lifetime as required by this binding
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:10:18
+ |
+LL | fn assert_send<T:'static>() { }
+ | ^^^^^^^
+
+error[E0477]: the type `*const &'a isize` does not fulfill the required lifetime
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:67:5
+ |
+LL | assert_send::<*const &'a isize>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: type must satisfy the static lifetime as required by this binding
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:10:18
+ |
+LL | fn assert_send<T:'static>() { }
+ | ^^^^^^^
+
+error[E0477]: the type `*mut &'a isize` does not fulfill the required lifetime
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:73:5
+ |
+LL | assert_send::<*mut &'a isize>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: type must satisfy the static lifetime as required by this binding
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:10:18
+ |
+LL | fn assert_send<T:'static>() { }
+ | ^^^^^^^
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0477`.
error: lifetime may not live long enough
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:22:5
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5
|
LL | fn param_not_ok<'a>(x: &'a isize) {
| -- lifetime `'a` defined here
| ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: lifetime may not live long enough
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:32:5
|
LL | fn param_not_ok1<'a>(_: &'a isize) {
| -- lifetime `'a` defined here
| ^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: lifetime may not live long enough
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:30:5
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:38:5
|
LL | fn param_not_ok2<'a>(_: &'a isize) {
| -- lifetime `'a` defined here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: lifetime may not live long enough
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:44:5
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:54:5
|
LL | fn box_with_region_not_ok<'a>() {
| -- lifetime `'a` defined here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: lifetime may not live long enough
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:55:5
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:67:5
|
LL | fn unsafe_ok2<'a>(_: &'a isize) {
| -- lifetime `'a` defined here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: lifetime may not live long enough
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:59:5
+ --> $DIR/regions-bounded-by-trait-requiring-static.rs:73:5
|
LL | fn unsafe_ok3<'a>(_: &'a isize) {
| -- lifetime `'a` defined here
// in this file all test region bound and lifetime violations that are
// detected during type check.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait Dummy : 'static { }
fn assert_send<T:'static>() { }
// otherwise lifetime pointers are not ok
fn param_not_ok<'a>(x: &'a isize) {
- assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime
+ assert_send::<&'a isize>();
+ //[base]~^ ERROR does not fulfill the required lifetime
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn param_not_ok1<'a>(_: &'a isize) {
- assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
+ assert_send::<&'a str>();
+ //[base]~^ ERROR does not fulfill the required lifetime
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn param_not_ok2<'a>(_: &'a isize) {
- assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime
+ assert_send::<&'a [isize]>();
+ //[base]~^ ERROR does not fulfill the required lifetime
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// boxes are ok
// but not if they own a bad thing
fn box_with_region_not_ok<'a>() {
- assert_send::<Box<&'a isize>>(); //~ ERROR does not fulfill the required lifetime
+ assert_send::<Box<&'a isize>>();
+ //[base]~^ ERROR does not fulfill the required lifetime
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// raw pointers are ok unless they point at unsendable things
}
fn unsafe_ok2<'a>(_: &'a isize) {
- assert_send::<*const &'a isize>(); //~ ERROR does not fulfill the required lifetime
+ assert_send::<*const &'a isize>();
+ //[base]~^ ERROR does not fulfill the required lifetime
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn unsafe_ok3<'a>(_: &'a isize) {
- assert_send::<*mut &'a isize>(); //~ ERROR does not fulfill the required lifetime
+ assert_send::<*mut &'a isize>();
+ //[base]~^ ERROR does not fulfill the required lifetime
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {
+++ /dev/null
-error[E0477]: the type `&'a isize` does not fulfill the required lifetime
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:22:5
- |
-LL | assert_send::<&'a isize>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: type must satisfy the static lifetime as required by this binding
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
- |
-LL | fn assert_send<T:'static>() { }
- | ^^^^^^^
-
-error[E0477]: the type `&'a str` does not fulfill the required lifetime
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5
- |
-LL | assert_send::<&'a str>();
- | ^^^^^^^^^^^^^^^^^^^^^^
- |
-note: type must satisfy the static lifetime as required by this binding
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
- |
-LL | fn assert_send<T:'static>() { }
- | ^^^^^^^
-
-error[E0477]: the type `&'a [isize]` does not fulfill the required lifetime
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:30:5
- |
-LL | assert_send::<&'a [isize]>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: type must satisfy the static lifetime as required by this binding
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
- |
-LL | fn assert_send<T:'static>() { }
- | ^^^^^^^
-
-error[E0477]: the type `Box<&'a isize>` does not fulfill the required lifetime
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:44:5
- |
-LL | assert_send::<Box<&'a isize>>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: type must satisfy the static lifetime as required by this binding
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
- |
-LL | fn assert_send<T:'static>() { }
- | ^^^^^^^
-
-error[E0477]: the type `*const &'a isize` does not fulfill the required lifetime
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:55:5
- |
-LL | assert_send::<*const &'a isize>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: type must satisfy the static lifetime as required by this binding
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
- |
-LL | fn assert_send<T:'static>() { }
- | ^^^^^^^
-
-error[E0477]: the type `*mut &'a isize` does not fulfill the required lifetime
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:59:5
- |
-LL | assert_send::<*mut &'a isize>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: type must satisfy the static lifetime as required by this binding
- --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
- |
-LL | fn assert_send<T:'static>() { }
- | ^^^^^^^
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0477`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:23:7
+ |
+LL | fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) {
+ | ------- ------- these two types are declared with different lifetimes...
+LL | // Here the value provided for 'y is 'y, and hence 'y:'x does not hold.
+LL | a.bigger_region(b)
+ | ^^^^^^^^^^^^^ ...but data from `b` flows into `a` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:20:5
+ --> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:23:5
|
LL | fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) {
| -- -- lifetime `'y` defined here
// aux-build:rbmtp_cross_crate_lib.rs
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
// Check explicit region bounds on methods in the cross crate case.
fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) {
// Here the value provided for 'y is 'y, and hence 'y:'x does not hold.
- a.bigger_region(b) //~ ERROR lifetime mismatch [E0623]
+ a.bigger_region(b)
+ //[base]~^ ERROR lifetime mismatch [E0623]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() { }
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:20:7
- |
-LL | fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) {
- | ------- ------- these two types are declared with different lifetimes...
-LL | // Here the value provided for 'y is 'y, and hence 'y:'x does not hold.
-LL | a.bigger_region(b)
- | ^^^^^^^^^^^^^ ...but data from `b` flows into `a` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:24:7
+ |
+LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
+ | ------- ------- these two types are declared with different lifetimes...
+LL | // Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
+LL | f.method(b);
+ | ^^^^^^ ...but data from `b` flows into `a` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:5
+ --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:24:5
|
LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
| -- -- lifetime `'b` defined here
// nominal types (but not on other types) and that they are type
// checked.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
struct Inv<'a> { // invariant w/r/t 'a
x: &'a mut &'a isize
}
fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
// Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
- f.method(b); //~ ERROR lifetime mismatch [E0623]
+ f.method(b);
+ //[base]~^ ERROR lifetime mismatch [E0623]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn caller3<'a,'b:'a,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:7
- |
-LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
- | ------- ------- these two types are declared with different lifetimes...
-LL | // Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
-LL | f.method(b);
- | ^^^^^^ ...but data from `b` flows into `a` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0477]: the type `&'a isize` does not fulfill the required lifetime
+ --> $DIR/regions-bounded-method-type-parameters.rs:16:9
+ |
+LL | Foo.some_method::<&'a isize>();
+ | ^^^^^^^^^^^
+ |
+note: type must satisfy the static lifetime as required by this binding
+ --> $DIR/regions-bounded-method-type-parameters.rs:12:22
+ |
+LL | fn some_method<A:'static>(self) { }
+ | ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0477`.
error: lifetime may not live long enough
- --> $DIR/regions-bounded-method-type-parameters.rs:12:9
+ --> $DIR/regions-bounded-method-type-parameters.rs:16:9
|
LL | fn caller<'a>(x: &isize) {
| -- lifetime `'a` defined here
// nominal types (but not on other types) and that they are type
// checked.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
struct Foo;
impl Foo {
fn caller<'a>(x: &isize) {
Foo.some_method::<&'a isize>();
- //~^ ERROR does not fulfill the required lifetime
+ //[base]~^ ERROR does not fulfill the required lifetime
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() { }
+++ /dev/null
-error[E0477]: the type `&'a isize` does not fulfill the required lifetime
- --> $DIR/regions-bounded-method-type-parameters.rs:12:9
- |
-LL | Foo.some_method::<&'a isize>();
- | ^^^^^^^^^^^
- |
-note: type must satisfy the static lifetime as required by this binding
- --> $DIR/regions-bounded-method-type-parameters.rs:8:22
- |
-LL | fn some_method<A:'static>(self) { }
- | ^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0477`.
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/regions-bounds.rs:13:12
+ |
+LL | return e;
+ | ^ lifetime mismatch
+ |
+ = note: expected struct `TupleStruct<'b>`
+ found struct `TupleStruct<'a>`
+note: the lifetime `'a` as defined here...
+ --> $DIR/regions-bounds.rs:12:10
+ |
+LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
+ | ^^
+note: ...does not necessarily outlive the lifetime `'b` as defined here
+ --> $DIR/regions-bounds.rs:12:13
+ |
+LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
+ | ^^
+
+error[E0308]: mismatched types
+ --> $DIR/regions-bounds.rs:19:12
+ |
+LL | return e;
+ | ^ lifetime mismatch
+ |
+ = note: expected struct `Struct<'b>`
+ found struct `Struct<'a>`
+note: the lifetime `'a` as defined here...
+ --> $DIR/regions-bounds.rs:18:10
+ |
+LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
+ | ^^
+note: ...does not necessarily outlive the lifetime `'b` as defined here
+ --> $DIR/regions-bounds.rs:18:13
+ |
+LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
+ | ^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
error: lifetime may not live long enough
- --> $DIR/regions-bounds.rs:9:12
+ --> $DIR/regions-bounds.rs:13:12
|
LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
- --> $DIR/regions-bounds.rs:13:12
+ --> $DIR/regions-bounds.rs:19:12
|
LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
| -- -- lifetime `'b` defined here
// nominal types (but not on other types) and that they are type
// checked.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
struct TupleStruct<'a>(&'a isize);
struct Struct<'a> { x:&'a isize }
fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
- return e; //~ ERROR mismatched types
+ return e;
+ //[base]~^ ERROR mismatched types
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
- return e; //~ ERROR mismatched types
+ return e;
+ //[base]~^ ERROR mismatched types
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() { }
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/regions-bounds.rs:9:12
- |
-LL | return e;
- | ^ lifetime mismatch
- |
- = note: expected struct `TupleStruct<'b>`
- found struct `TupleStruct<'a>`
-note: the lifetime `'a` as defined here...
- --> $DIR/regions-bounds.rs:8:10
- |
-LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
- | ^^
-note: ...does not necessarily outlive the lifetime `'b` as defined here
- --> $DIR/regions-bounds.rs:8:13
- |
-LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
- | ^^
-
-error[E0308]: mismatched types
- --> $DIR/regions-bounds.rs:13:12
- |
-LL | return e;
- | ^ lifetime mismatch
- |
- = note: expected struct `Struct<'b>`
- found struct `Struct<'a>`
-note: the lifetime `'a` as defined here...
- --> $DIR/regions-bounds.rs:12:10
- |
-LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
- | ^^
-note: ...does not necessarily outlive the lifetime `'b` as defined here
- --> $DIR/regions-bounds.rs:12:13
- |
-LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
- | ^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
+ --> $DIR/regions-close-associated-type-into-object.rs:19:5
+ |
+LL | Box::new(item)
+ | ^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
+ = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
+
+error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
+ --> $DIR/regions-close-associated-type-into-object.rs:26:5
+ |
+LL | Box::new(item)
+ | ^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
+ = note: ...so that the type `Box<<T as Iter>::Item>` will meet its required lifetime bounds
+
+error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
+ --> $DIR/regions-close-associated-type-into-object.rs:32:5
+ |
+LL | Box::new(item)
+ | ^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
+ = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
+
+error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
+ --> $DIR/regions-close-associated-type-into-object.rs:39:5
+ |
+LL | Box::new(item)
+ | ^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
+ = note: ...so that the type `Box<<T as Iter>::Item>` will meet its required lifetime bounds
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0309, E0310.
+For more information about an error, try `rustc --explain E0309`.
error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
- --> $DIR/regions-close-associated-type-into-object.rs:15:5
+ --> $DIR/regions-close-associated-type-into-object.rs:19:5
|
LL | Box::new(item)
| ^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
+ = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
- --> $DIR/regions-close-associated-type-into-object.rs:22:5
+ --> $DIR/regions-close-associated-type-into-object.rs:26:5
|
LL | Box::new(item)
| ^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
+ = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
- --> $DIR/regions-close-associated-type-into-object.rs:28:5
+ --> $DIR/regions-close-associated-type-into-object.rs:32:5
|
LL | Box::new(item)
| ^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
+ = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
- --> $DIR/regions-close-associated-type-into-object.rs:35:5
+ --> $DIR/regions-close-associated-type-into-object.rs:39:5
|
LL | Box::new(item)
| ^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
+ = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
error: aborting due to 4 previous errors
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait X {}
+++ /dev/null
-error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
- --> $DIR/regions-close-associated-type-into-object.rs:15:5
- |
-LL | Box::new(item)
- | ^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
- = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
-
-error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
- --> $DIR/regions-close-associated-type-into-object.rs:22:5
- |
-LL | Box::new(item)
- | ^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
- = note: ...so that the type `Box<<T as Iter>::Item>` will meet its required lifetime bounds
-
-error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
- --> $DIR/regions-close-associated-type-into-object.rs:28:5
- |
-LL | Box::new(item)
- | ^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
- = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
-
-error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
- --> $DIR/regions-close-associated-type-into-object.rs:35:5
- |
-LL | Box::new(item)
- | ^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
- = note: ...so that the type `Box<<T as Iter>::Item>` will meet its required lifetime bounds
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0309, E0310.
-For more information about an error, try `rustc --explain E0309`.
--- /dev/null
+error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/regions-close-object-into-object-2.rs:13:16
+ |
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
+ | ------------------ this data with lifetime `'a`...
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^ ...is used and required to live as long as `'static` here
+ |
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/regions-close-object-into-object-2.rs:12:60
+ |
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
+ | ^^^^^^^ `'static` requirement introduced here
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ------------------------------ because of this returned expression
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+ |
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'a> {
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn g<'a, T: 'static>(v: Box<(dyn A<T> + 'static)>) -> Box<dyn X + 'static> {
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0759`.
error: lifetime may not live long enough
- --> $DIR/regions-close-object-into-object-2.rs:9:5
+ --> $DIR/regions-close-object-into-object-2.rs:13:5
|
LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
| -- lifetime `'a` defined here
LL | Box::new(B(&*v)) as Box<dyn X>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+ |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+ |
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'a> {
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn g<'a, T: 'static>(v: Box<(dyn A<T> + 'static)>) -> Box<dyn X + 'static> {
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0515]: cannot return value referencing local data `*v`
- --> $DIR/regions-close-object-into-object-2.rs:9:5
+ --> $DIR/regions-close-object-into-object-2.rs:13:5
|
LL | Box::new(B(&*v)) as Box<dyn X>
| ^^^^^^^^^^^---^^^^^^^^^^^^^^^^
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait A<T> { }
struct B<'a, T:'a>(&'a (dyn A<T> + 'a));
impl<'a, T> X for B<'a, T> {}
fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
- Box::new(B(&*v)) as Box<dyn X> //~ ERROR E0759
+ Box::new(B(&*v)) as Box<dyn X>
+ //[base]~^ ERROR E0759
+ //[nll]~^^ ERROR lifetime may not live long enough
+ //[nll]~| ERROR cannot return value referencing local data `*v` [E0515]
}
fn main() { }
+++ /dev/null
-error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/regions-close-object-into-object-2.rs:9:16
- |
-LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
- | ------------------ this data with lifetime `'a`...
-LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^ ...is used and required to live as long as `'static` here
- |
-note: `'static` lifetime requirement introduced by the return type
- --> $DIR/regions-close-object-into-object-2.rs:8:60
- |
-LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
- | ^^^^^^^ `'static` requirement introduced here
-LL | Box::new(B(&*v)) as Box<dyn X>
- | ------------------------------ because of this returned expression
-help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
- |
-LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'a> {
- | ~~
-help: alternatively, add an explicit `'static` bound to this reference
- |
-LL | fn g<'a, T: 'static>(v: Box<(dyn A<T> + 'static)>) -> Box<dyn X + 'static> {
- | ~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0759`.
--- /dev/null
+error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/regions-close-object-into-object-4.rs:13:16
+ |
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+ | ---------------- this data with lifetime `'a`...
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^ ...is used and required to live as long as `'static` here
+ |
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/regions-close-object-into-object-4.rs:12:52
+ |
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+ | ^^^^^^^ `'static` requirement introduced here
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ------------------------------ because of this returned expression
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+ |
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'a> {
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn i<'a, T, U>(v: Box<(dyn A<U> + 'static)>) -> Box<dyn X + 'static> {
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0759`.
error[E0310]: the parameter type `U` may not live long enough
- --> $DIR/regions-close-object-into-object-4.rs:9:5
+ --> $DIR/regions-close-object-into-object-4.rs:13:5
|
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `U: 'static`
LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `U: 'static`...
+ | ^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
error[E0310]: the parameter type `U` may not live long enough
- --> $DIR/regions-close-object-into-object-4.rs:9:5
+ --> $DIR/regions-close-object-into-object-4.rs:13:5
|
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `U: 'static`
LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `U: 'static`...
+ | ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
error[E0310]: the parameter type `U` may not live long enough
- --> $DIR/regions-close-object-into-object-4.rs:9:5
+ --> $DIR/regions-close-object-into-object-4.rs:13:5
|
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `U: 'static`
LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `U: 'static`...
+ | ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
error: lifetime may not live long enough
- --> $DIR/regions-close-object-into-object-4.rs:9:5
+ --> $DIR/regions-close-object-into-object-4.rs:13:5
|
LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
| -- lifetime `'a` defined here
LL | Box::new(B(&*v)) as Box<dyn X>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+ |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+ |
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'a> {
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn i<'a, T, U>(v: Box<(dyn A<U> + 'static)>) -> Box<dyn X + 'static> {
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0515]: cannot return value referencing local data `*v`
- --> $DIR/regions-close-object-into-object-4.rs:9:5
+ --> $DIR/regions-close-object-into-object-4.rs:13:5
|
LL | Box::new(B(&*v)) as Box<dyn X>
| ^^^^^^^^^^^---^^^^^^^^^^^^^^^^
| returns a value referencing data owned by the current function
error[E0310]: the parameter type `U` may not live long enough
- --> $DIR/regions-close-object-into-object-4.rs:9:14
+ --> $DIR/regions-close-object-into-object-4.rs:13:14
|
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `U: 'static`
LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^^^^
- |
- = help: consider adding an explicit lifetime bound `U: 'static`...
+ | ^^^^^^ ...so that the type `U` will meet its required lifetime bounds
error: aborting due to 6 previous errors
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait A<T> { }
struct B<'a, T:'a>(&'a (dyn A<T> + 'a));
impl<'a, T> X for B<'a, T> {}
fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
- Box::new(B(&*v)) as Box<dyn X> //~ ERROR E0759
+ Box::new(B(&*v)) as Box<dyn X>
+ //[base]~^ ERROR E0759
+ //[nll]~^^ ERROR the parameter type `U` may not live long enough [E0310]
+ //[nll]~| ERROR the parameter type `U` may not live long enough [E0310]
+ //[nll]~| ERROR the parameter type `U` may not live long enough [E0310]
+ //[nll]~| ERROR lifetime may not live long enough
+ //[nll]~| ERROR cannot return value referencing local data `*v` [E0515]
+ //[nll]~| ERROR the parameter type `U` may not live long enough [E0310]
+
}
fn main() {}
+++ /dev/null
-error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/regions-close-object-into-object-4.rs:9:16
- |
-LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
- | ---------------- this data with lifetime `'a`...
-LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^ ...is used and required to live as long as `'static` here
- |
-note: `'static` lifetime requirement introduced by the return type
- --> $DIR/regions-close-object-into-object-4.rs:8:52
- |
-LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
- | ^^^^^^^ `'static` requirement introduced here
-LL | Box::new(B(&*v)) as Box<dyn X>
- | ------------------------------ because of this returned expression
-help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
- |
-LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'a> {
- | ~~
-help: alternatively, add an explicit `'static` bound to this reference
- |
-LL | fn i<'a, T, U>(v: Box<(dyn A<U> + 'static)>) -> Box<dyn X + 'static> {
- | ~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0759`.
--- /dev/null
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-object-into-object-5.rs:21:5
+ |
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | // oh dear!
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+ |
+note: ...that is required by this bound
+ --> $DIR/regions-close-object-into-object-5.rs:13:17
+ |
+LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
+ | ^^
+
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-object-into-object-5.rs:21:5
+ |
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | // oh dear!
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds
+
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-object-into-object-5.rs:21:14
+ |
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | // oh dear!
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^ ...so that the type `T` will meet its required lifetime bounds...
+ |
+note: ...that is required by this bound
+ --> $DIR/regions-close-object-into-object-5.rs:13:17
+ |
+LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
+ | ^^
+
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-object-into-object-5.rs:21:14
+ |
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | // oh dear!
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+ |
+note: ...that is required by this bound
+ --> $DIR/regions-close-object-into-object-5.rs:13:17
+ |
+LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
+ | ^^
+
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-object-into-object-5.rs:21:16
+ |
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | // oh dear!
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^ ...so that the reference type `&dyn A<T>` does not outlive the data it points at
+
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-object-into-object-5.rs:21:16
+ |
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | // oh dear!
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
+
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-object-into-object-5.rs:21:16
+ |
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | // oh dear!
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0310`.
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:5
+ --> $DIR/regions-close-object-into-object-5.rs:21:5
|
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | // oh dear!
LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
+ | ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:5
+ --> $DIR/regions-close-object-into-object-5.rs:21:5
|
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | // oh dear!
LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
+ | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:5
+ --> $DIR/regions-close-object-into-object-5.rs:21:5
|
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | // oh dear!
LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
+ | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error[E0515]: cannot return value referencing local data `*v`
- --> $DIR/regions-close-object-into-object-5.rs:17:5
+ --> $DIR/regions-close-object-into-object-5.rs:21:5
|
LL | Box::new(B(&*v)) as Box<dyn X>
| ^^^^^^^^^^^---^^^^^^^^^^^^^^^^
| returns a value referencing data owned by the current function
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:14
+ --> $DIR/regions-close-object-into-object-5.rs:21:14
|
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | // oh dear!
LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
+ | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to 5 previous errors
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![allow(warnings)]
//~| ERROR the parameter type `T` may not live long enough
//~| ERROR the parameter type `T` may not live long enough
//~| ERROR the parameter type `T` may not live long enough
- //~| ERROR the parameter type `T` may not live long enough
- //~| ERROR the parameter type `T` may not live long enough
- //~| ERROR the parameter type `T` may not live long enough
+ //[base]~| ERROR the parameter type `T` may not live long enough
+ //[base]~| ERROR the parameter type `T` may not live long enough
+ //[base]~| ERROR the parameter type `T` may not live long enough
+ //[nll]~| ERROR cannot return value referencing local data `*v` [E0515]
}
fn main() {}
+++ /dev/null
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:5
- |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
- | - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL | // oh dear!
-LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
- |
-note: ...that is required by this bound
- --> $DIR/regions-close-object-into-object-5.rs:9:17
- |
-LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
- | ^^
-
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:5
- |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
- | - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL | // oh dear!
-LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^^^^^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds
-
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:14
- |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
- | - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL | // oh dear!
-LL | Box::new(B(&*v)) as Box<dyn X>
- | ^ ...so that the type `T` will meet its required lifetime bounds...
- |
-note: ...that is required by this bound
- --> $DIR/regions-close-object-into-object-5.rs:9:17
- |
-LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
- | ^^
-
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:14
- |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
- | - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL | // oh dear!
-LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
- |
-note: ...that is required by this bound
- --> $DIR/regions-close-object-into-object-5.rs:9:17
- |
-LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
- | ^^
-
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:16
- |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
- | - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL | // oh dear!
-LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^ ...so that the reference type `&dyn A<T>` does not outlive the data it points at
-
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:16
- |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
- | - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL | // oh dear!
-LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
-
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:16
- |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
- | - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL | // oh dear!
-LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0310`.
--- /dev/null
+error[E0310]: the parameter type `A` may not live long enough
+ --> $DIR/regions-close-over-type-parameter-1.rs:15:5
+ |
+LL | fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
+ | -- help: consider adding an explicit lifetime bound...: `A: 'static +`
+LL | Box::new(v) as Box<dyn SomeTrait + 'static>
+ | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+
+error[E0309]: the parameter type `A` may not live long enough
+ --> $DIR/regions-close-over-type-parameter-1.rs:24:5
+ |
+LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
+ | -- help: consider adding an explicit lifetime bound...: `A: 'b +`
+LL | Box::new(v) as Box<dyn SomeTrait + 'b>
+ | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0309, E0310.
+For more information about an error, try `rustc --explain E0309`.
error[E0310]: the parameter type `A` may not live long enough
- --> $DIR/regions-close-over-type-parameter-1.rs:12:5
+ --> $DIR/regions-close-over-type-parameter-1.rs:15:5
|
+LL | fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
+ | -- help: consider adding an explicit lifetime bound...: `A: 'static +`
LL | Box::new(v) as Box<dyn SomeTrait + 'static>
- | ^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `A: 'static`...
+ | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
error[E0309]: the parameter type `A` may not live long enough
- --> $DIR/regions-close-over-type-parameter-1.rs:21:5
+ --> $DIR/regions-close-over-type-parameter-1.rs:24:5
|
+LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
+ | -- help: consider adding an explicit lifetime bound...: `A: 'b +`
LL | Box::new(v) as Box<dyn SomeTrait + 'b>
- | ^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `A: 'b`...
+ | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
error: aborting due to 2 previous errors
// an object. This should yield errors unless `A` (and the object)
// both have suitable bounds.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
trait SomeTrait {
fn get(&self) -> isize;
+++ /dev/null
-error[E0310]: the parameter type `A` may not live long enough
- --> $DIR/regions-close-over-type-parameter-1.rs:12:5
- |
-LL | fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
- | -- help: consider adding an explicit lifetime bound...: `A: 'static +`
-LL | Box::new(v) as Box<dyn SomeTrait + 'static>
- | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
-
-error[E0309]: the parameter type `A` may not live long enough
- --> $DIR/regions-close-over-type-parameter-1.rs:21:5
- |
-LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
- | -- help: consider adding an explicit lifetime bound...: `A: 'b +`
-LL | Box::new(v) as Box<dyn SomeTrait + 'b>
- | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0309, E0310.
-For more information about an error, try `rustc --explain E0309`.
--- /dev/null
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+ --> $DIR/regions-close-over-type-parameter-multiple.rs:23:5
+ |
+LL | Box::new(v) as Box<dyn SomeTrait + 'a>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+ --> $DIR/regions-close-over-type-parameter-multiple.rs:21:20
+ |
+LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
+ | ^^
+note: ...so that the declared lifetime parameter bounds are satisfied
+ --> $DIR/regions-close-over-type-parameter-multiple.rs:23:5
+ |
+LL | Box::new(v) as Box<dyn SomeTrait + 'a>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: but, the lifetime must be valid for the lifetime `'c` as defined here...
+ --> $DIR/regions-close-over-type-parameter-multiple.rs:21:26
+ |
+LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
+ | ^^
+note: ...so that the types are compatible
+ --> $DIR/regions-close-over-type-parameter-multiple.rs:23:5
+ |
+LL | Box::new(v) as Box<dyn SomeTrait + 'a>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `Box<(dyn SomeTrait + 'c)>`
+ found `Box<dyn SomeTrait>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
error: lifetime may not live long enough
- --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
+ --> $DIR/regions-close-over-type-parameter-multiple.rs:23:5
|
LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
| -- -- lifetime `'c` defined here
// Various tests where we over type parameters with multiple lifetime
// bounds.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
trait SomeTrait { fn get(&self) -> isize; }
fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
// A outlives 'a AND 'b...but not 'c.
- Box::new(v) as Box<dyn SomeTrait + 'a> //~ ERROR cannot infer an appropriate lifetime
+ Box::new(v) as Box<dyn SomeTrait + 'a>
+ //[base]~^ ERROR cannot infer an appropriate lifetime
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {
+++ /dev/null
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
- --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
- |
-LL | Box::new(v) as Box<dyn SomeTrait + 'a>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
- --> $DIR/regions-close-over-type-parameter-multiple.rs:18:20
- |
-LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
- | ^^
-note: ...so that the declared lifetime parameter bounds are satisfied
- --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
- |
-LL | Box::new(v) as Box<dyn SomeTrait + 'a>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: but, the lifetime must be valid for the lifetime `'c` as defined here...
- --> $DIR/regions-close-over-type-parameter-multiple.rs:18:26
- |
-LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
- | ^^
-note: ...so that the types are compatible
- --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
- |
-LL | Box::new(v) as Box<dyn SomeTrait + 'a>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: expected `Box<(dyn SomeTrait + 'c)>`
- found `Box<dyn SomeTrait>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
--- /dev/null
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-param-into-object.rs:10:5
+ |
+LL | fn p1<T>(v: T) -> Box<dyn X + 'static>
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+...
+LL | Box::new(v)
+ | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-param-into-object.rs:16:5
+ |
+LL | fn p2<T>(v: Box<T>) -> Box<dyn X + 'static>
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+...
+LL | Box::new(v)
+ | ^^^^^^^^^^^ ...so that the type `Box<T>` will meet its required lifetime bounds
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-param-into-object.rs:22:5
+ |
+LL | fn p3<'a,T>(v: T) -> Box<dyn X + 'a>
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
+LL | Box::new(v)
+ | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-param-into-object.rs:28:5
+ |
+LL | fn p4<'a,T>(v: Box<T>) -> Box<dyn X + 'a>
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
+LL | Box::new(v)
+ | ^^^^^^^^^^^ ...so that the type `Box<T>` will meet its required lifetime bounds
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0309, E0310.
+For more information about an error, try `rustc --explain E0309`.
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-param-into-object.rs:6:5
+ --> $DIR/regions-close-param-into-object.rs:10:5
|
+LL | fn p1<T>(v: T) -> Box<dyn X + 'static>
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+...
LL | Box::new(v)
- | ^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
+ | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-param-into-object.rs:12:5
+ --> $DIR/regions-close-param-into-object.rs:16:5
|
+LL | fn p2<T>(v: Box<T>) -> Box<dyn X + 'static>
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+...
LL | Box::new(v)
- | ^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
+ | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-param-into-object.rs:18:5
+ --> $DIR/regions-close-param-into-object.rs:22:5
|
+LL | fn p3<'a,T>(v: T) -> Box<dyn X + 'a>
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | Box::new(v)
- | ^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-param-into-object.rs:24:5
+ --> $DIR/regions-close-param-into-object.rs:28:5
|
+LL | fn p4<'a,T>(v: Box<T>) -> Box<dyn X + 'a>
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
LL | Box::new(v)
- | ^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'a`...
+ | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to 4 previous errors
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait X { fn foo(&self) {} }
fn p1<T>(v: T) -> Box<dyn X + 'static>
+++ /dev/null
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-param-into-object.rs:6:5
- |
-LL | fn p1<T>(v: T) -> Box<dyn X + 'static>
- | - help: consider adding an explicit lifetime bound...: `T: 'static`
-...
-LL | Box::new(v)
- | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-param-into-object.rs:12:5
- |
-LL | fn p2<T>(v: Box<T>) -> Box<dyn X + 'static>
- | - help: consider adding an explicit lifetime bound...: `T: 'static`
-...
-LL | Box::new(v)
- | ^^^^^^^^^^^ ...so that the type `Box<T>` will meet its required lifetime bounds
-
-error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-param-into-object.rs:18:5
- |
-LL | fn p3<'a,T>(v: T) -> Box<dyn X + 'a>
- | - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
-LL | Box::new(v)
- | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-
-error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-param-into-object.rs:24:5
- |
-LL | fn p4<'a,T>(v: Box<T>) -> Box<dyn X + 'a>
- | - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
-LL | Box::new(v)
- | ^^^^^^^^^^^ ...so that the type `Box<T>` will meet its required lifetime bounds
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0309, E0310.
-For more information about an error, try `rustc --explain E0309`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-creating-enums3.rs:11:5
+ |
+LL | fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> {
+ | ----------- -------
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | Ast::Add(x, y)
+ | ^^^^^^^^^^^^^^ ...but data from `y` is returned here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/regions-creating-enums3.rs:7:5
+ --> $DIR/regions-creating-enums3.rs:11:5
|
LL | fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> {
| -- -- lifetime `'b` defined here
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
enum Ast<'a> {
Num(usize),
Add(&'a Ast<'a>, &'a Ast<'a>)
}
fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> {
- Ast::Add(x, y) //~ ERROR lifetime mismatch [E0623]
+ Ast::Add(x, y)
+ //[base]~^ ERROR lifetime mismatch [E0623]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-creating-enums3.rs:7:5
- |
-LL | fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> {
- | ----------- -------
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | Ast::Add(x, y)
- | ^^^^^^^^^^^^^^ ...but data from `y` is returned here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+ --> $DIR/regions-creating-enums4.rs:11:5
+ |
+LL | Ast::Add(x, y)
+ | ^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+ --> $DIR/regions-creating-enums4.rs:10:16
+ |
+LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
+ | ^^
+note: ...so that the expression is assignable
+ --> $DIR/regions-creating-enums4.rs:11:14
+ |
+LL | Ast::Add(x, y)
+ | ^
+ = note: expected `&Ast<'_>`
+ found `&Ast<'a>`
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+ --> $DIR/regions-creating-enums4.rs:10:19
+ |
+LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
+ | ^^
+note: ...so that the types are compatible
+ --> $DIR/regions-creating-enums4.rs:11:5
+ |
+LL | Ast::Add(x, y)
+ | ^^^^^^^^^^^^^^
+ = note: expected `Ast<'b>`
+ found `Ast<'_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
error: lifetime may not live long enough
- --> $DIR/regions-creating-enums4.rs:7:5
+ --> $DIR/regions-creating-enums4.rs:11:5
|
LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
| -- -- lifetime `'b` defined here
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
enum Ast<'a> {
Num(usize),
Add(&'a Ast<'a>, &'a Ast<'a>)
}
fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
- Ast::Add(x, y) //~ ERROR cannot infer
+ Ast::Add(x, y)
+ //[base]~^ ERROR cannot infer
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {
+++ /dev/null
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
- --> $DIR/regions-creating-enums4.rs:7:5
- |
-LL | Ast::Add(x, y)
- | ^^^^^^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
- --> $DIR/regions-creating-enums4.rs:6:16
- |
-LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
- | ^^
-note: ...so that the expression is assignable
- --> $DIR/regions-creating-enums4.rs:7:14
- |
-LL | Ast::Add(x, y)
- | ^
- = note: expected `&Ast<'_>`
- found `&Ast<'a>`
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
- --> $DIR/regions-creating-enums4.rs:6:19
- |
-LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
- | ^^
-note: ...so that the types are compatible
- --> $DIR/regions-creating-enums4.rs:7:5
- |
-LL | Ast::Add(x, y)
- | ^^^^^^^^^^^^^^
- = note: expected `Ast<'b>`
- found `Ast<'_>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
--- /dev/null
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+ --> $DIR/regions-early-bound-error-method.rs:24:9
+ |
+LL | g2.get()
+ | ^^^^^^^^
+ |
+note: ...the reference is valid for the lifetime `'a` as defined here...
+ --> $DIR/regions-early-bound-error-method.rs:22:6
+ |
+LL | impl<'a> Box<'a> {
+ | ^^
+note: ...but the borrowed content is only valid for the lifetime `'b` as defined here
+ --> $DIR/regions-early-bound-error-method.rs:23:11
+ |
+LL | fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize {
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0312`.
error: lifetime may not live long enough
- --> $DIR/regions-early-bound-error-method.rs:20:9
+ --> $DIR/regions-early-bound-error-method.rs:24:9
|
LL | impl<'a> Box<'a> {
| -- lifetime `'a` defined here
// Tests that you can use a fn lifetime parameter as part of
// the value for a type parameter in a bound.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait GetRef<'a> {
fn get(&self) -> &'a isize;
}
impl<'a> Box<'a> {
fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize {
g2.get()
- //~^ ERROR E0312
+ //[base]~^ ERROR E0312
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0312]: lifetime of reference outlives lifetime of borrowed content...
- --> $DIR/regions-early-bound-error-method.rs:20:9
- |
-LL | g2.get()
- | ^^^^^^^^
- |
-note: ...the reference is valid for the lifetime `'a` as defined here...
- --> $DIR/regions-early-bound-error-method.rs:18:6
- |
-LL | impl<'a> Box<'a> {
- | ^^
-note: ...but the borrowed content is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-early-bound-error-method.rs:19:11
- |
-LL | fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize {
- | ^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0312`.
--- /dev/null
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+ --> $DIR/regions-early-bound-error.rs:23:5
+ |
+LL | g1.get()
+ | ^^^^^^^^
+ |
+note: ...the reference is valid for the lifetime `'b` as defined here...
+ --> $DIR/regions-early-bound-error.rs:22:11
+ |
+LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
+ | ^^
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined here
+ --> $DIR/regions-early-bound-error.rs:22:8
+ |
+LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0312`.
error: lifetime may not live long enough
- --> $DIR/regions-early-bound-error.rs:19:5
+ --> $DIR/regions-early-bound-error.rs:23:5
|
LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
| -- -- lifetime `'b` defined here
// Tests that you can use a fn lifetime parameter as part of
// the value for a type parameter in a bound.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait GetRef<'a, T> {
fn get(&self) -> &'a T;
}
fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
g1.get()
- //~^ ERROR E0312
+ //[base]~^ ERROR E0312
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {
+++ /dev/null
-error[E0312]: lifetime of reference outlives lifetime of borrowed content...
- --> $DIR/regions-early-bound-error.rs:19:5
- |
-LL | g1.get()
- | ^^^^^^^^
- |
-note: ...the reference is valid for the lifetime `'b` as defined here...
- --> $DIR/regions-early-bound-error.rs:18:11
- |
-LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
- | ^^
-note: ...but the borrowed content is only valid for the lifetime `'a` as defined here
- --> $DIR/regions-early-bound-error.rs:18:8
- |
-LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
- | ^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0312`.
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/regions-fn-subtyping-return-static-fail.rs:52:12
+ |
+LL | want_G(baz);
+ | ^^^ one type is more general than the other
+ |
+ = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S`
+ found fn pointer `for<'r> fn(&'r S) -> &'r S`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
error[E0308]: mismatched types
- --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:5
+ --> $DIR/regions-fn-subtyping-return-static-fail.rs:52:5
|
LL | want_G(baz);
| ^^^^^^^^^^^ one type is more general than the other
// This can safely be considered to be an instance of `F` because all
// lifetimes are sublifetimes of 'static.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![allow(dead_code)]
#![allow(unused_variables)]
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12
- |
-LL | want_G(baz);
- | ^^^ one type is more general than the other
- |
- = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S`
- found fn pointer `for<'r> fn(&'r S) -> &'r S`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-free-region-ordering-callee.rs:17:5
+ |
+LL | fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize {
+ | ------------- ---------
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | // However, it is not safe to assume that 'b <= 'a
+LL | &*y
+ | ^^^ ...but data from `x` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-free-region-ordering-callee.rs:24:24
+ |
+LL | fn ordering3<'a, 'b>(x: &'a usize, y: &'b usize) -> &'a &'b usize {
+ | --------- -------------
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | // Do not infer an ordering from the return value.
+LL | let z: &'b usize = &*x;
+ | ^^^ ...but data from `x` is returned here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-callee.rs:13:5
+ --> $DIR/regions-free-region-ordering-callee.rs:17:5
|
LL | fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-callee.rs:18:12
+ --> $DIR/regions-free-region-ordering-callee.rs:24:12
|
LL | fn ordering3<'a, 'b>(x: &'a usize, y: &'b usize) -> &'a &'b usize {
| -- -- lifetime `'b` defined here
// that appear in their parameter list. See also
// regions-free-region-ordering-caller.rs
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
fn ordering1<'a, 'b>(x: &'a &'b usize) -> &'a usize {
// It is safe to assume that 'a <= 'b due to the type of x
let y: &'b usize = &**x;
fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize {
// However, it is not safe to assume that 'b <= 'a
- &*y //~ ERROR lifetime mismatch [E0623]
+ &*y
+ //[base]~^ ERROR lifetime mismatch [E0623]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn ordering3<'a, 'b>(x: &'a usize, y: &'b usize) -> &'a &'b usize {
// Do not infer an ordering from the return value.
let z: &'b usize = &*x;
- //~^ ERROR lifetime mismatch [E0623]
+ //[base]~^ ERROR lifetime mismatch [E0623]
+ //[nll]~^^ ERROR lifetime may not live long enough
panic!();
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-free-region-ordering-callee.rs:13:5
- |
-LL | fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize {
- | ------------- ---------
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | // However, it is not safe to assume that 'b <= 'a
-LL | &*y
- | ^^^ ...but data from `x` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/regions-free-region-ordering-callee.rs:18:24
- |
-LL | fn ordering3<'a, 'b>(x: &'a usize, y: &'b usize) -> &'a &'b usize {
- | --------- -------------
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | // Do not infer an ordering from the return value.
-LL | let z: &'b usize = &*x;
- | ^^^ ...but data from `x` is returned here
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+ --> $DIR/regions-free-region-ordering-incorrect.rs:21:21
+ |
+LL | None => &self.val
+ | ^^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+ --> $DIR/regions-free-region-ordering-incorrect.rs:18:12
+ |
+LL | fn get<'a>(&'a self) -> &'b T {
+ | ^^
+note: ...so that reference does not outlive borrowed content
+ --> $DIR/regions-free-region-ordering-incorrect.rs:21:21
+ |
+LL | None => &self.val
+ | ^^^^^^^^^
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+ --> $DIR/regions-free-region-ordering-incorrect.rs:17:6
+ |
+LL | impl<'b, T> Node<'b, T> {
+ | ^^
+note: ...so that reference does not outlive borrowed content
+ --> $DIR/regions-free-region-ordering-incorrect.rs:19:9
+ |
+LL | / match self.next {
+LL | | Some(ref next) => next.get(),
+LL | | None => &self.val
+LL | | }
+ | |_________^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-incorrect.rs:15:9
+ --> $DIR/regions-free-region-ordering-incorrect.rs:19:9
|
LL | impl<'b, T> Node<'b, T> {
| -- lifetime `'b` defined here
//
// This test began its life as a test for issue #4325.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
struct Node<'b, T: 'b> {
val: T,
next: Option<&'b Node<'b, T>>
impl<'b, T> Node<'b, T> {
fn get<'a>(&'a self) -> &'b T {
- match self.next {
+ match self.next { //[nll]~ ERROR lifetime may not live long enough
Some(ref next) => next.get(),
- None => &self.val //~ ERROR cannot infer
+ None => &self.val //[base]~ ERROR cannot infer
}
}
}
+++ /dev/null
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
- --> $DIR/regions-free-region-ordering-incorrect.rs:17:21
- |
-LL | None => &self.val
- | ^^^^^^^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
- --> $DIR/regions-free-region-ordering-incorrect.rs:14:12
- |
-LL | fn get<'a>(&'a self) -> &'b T {
- | ^^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/regions-free-region-ordering-incorrect.rs:17:21
- |
-LL | None => &self.val
- | ^^^^^^^^^
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
- --> $DIR/regions-free-region-ordering-incorrect.rs:13:6
- |
-LL | impl<'b, T> Node<'b, T> {
- | ^^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/regions-free-region-ordering-incorrect.rs:15:9
- |
-LL | / match self.next {
-LL | | Some(ref next) => next.get(),
-LL | | None => &self.val
-LL | | }
- | |_________^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
--- /dev/null
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/regions-implied-bounds-projection-gap-1.rs:20:10
+ |
+LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo)
+ | -- help: consider adding an explicit lifetime bound...: `T: 'x +`
+LL | {
+LL | wf::<&'x T>();
+ | ^^^^^ ...so that the reference type `&'x T` does not outlive the data it points at
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/regions-implied-bounds-projection-gap-1.rs:16:5
+ --> $DIR/regions-implied-bounds-projection-gap-1.rs:20:5
|
+LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo)
+ | -- help: consider adding an explicit lifetime bound...: `T: 'x +`
+LL | {
LL | wf::<&'x T>();
- | ^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'x`...
+ | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to previous error
// there might be other ways for the caller of `func` to show that
// `T::Foo: 'x` holds (e.g., where-clause).
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait Trait1<'x> {
type Foo;
}
+++ /dev/null
-error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/regions-implied-bounds-projection-gap-1.rs:16:10
- |
-LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo)
- | -- help: consider adding an explicit lifetime bound...: `T: 'x +`
-LL | {
-LL | wf::<&'x T>();
- | ^^^^^ ...so that the reference type `&'x T` does not outlive the data it points at
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0309`.
--- /dev/null
+error[E0309]: the parameter type `Self` may not live long enough
+ --> $DIR/regions-infer-bound-from-trait-self.rs:50:9
+ |
+LL | check_bound(x, self)
+ | ^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `Self: 'a`...
+ = note: ...so that the type `Self` will meet its required lifetime bounds...
+note: ...that is required by this bound
+ --> $DIR/regions-infer-bound-from-trait-self.rs:16:21
+ |
+LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
error[E0309]: the parameter type `Self` may not live long enough
- --> $DIR/regions-infer-bound-from-trait-self.rs:46:9
+ --> $DIR/regions-infer-bound-from-trait-self.rs:50:9
|
LL | check_bound(x, self)
| ^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `Self: 'a`...
+ = note: ...so that the type `Self` will meet its required lifetime bounds
error: aborting due to previous error
// Test that we can derive lifetime bounds on `Self` from trait
// inheritance.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait Static : 'static { }
trait Is<'a> : 'a { }
+++ /dev/null
-error[E0309]: the parameter type `Self` may not live long enough
- --> $DIR/regions-infer-bound-from-trait-self.rs:46:9
- |
-LL | check_bound(x, self)
- | ^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `Self: 'a`...
- = note: ...so that the type `Self` will meet its required lifetime bounds...
-note: ...that is required by this bound
- --> $DIR/regions-infer-bound-from-trait-self.rs:12:21
- |
-LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
- | ^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0309`.
--- /dev/null
+error[E0309]: the parameter type `A` may not live long enough
+ --> $DIR/regions-infer-bound-from-trait.rs:37:5
+ |
+LL | fn bar1<'a,A>(x: Inv<'a>, a: A) {
+ | - help: consider adding an explicit lifetime bound...: `A: 'a`
+LL | check_bound(x, a)
+ | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds...
+ |
+note: ...that is required by this bound
+ --> $DIR/regions-infer-bound-from-trait.rs:16:21
+ |
+LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
+ | ^^
+
+error[E0309]: the parameter type `A` may not live long enough
+ --> $DIR/regions-infer-bound-from-trait.rs:41:5
+ |
+LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) {
+ | -- help: consider adding an explicit lifetime bound...: `A: 'a +`
+LL | check_bound(x, a)
+ | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds...
+ |
+note: ...that is required by this bound
+ --> $DIR/regions-infer-bound-from-trait.rs:16:21
+ |
+LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
+ | ^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
error[E0309]: the parameter type `A` may not live long enough
- --> $DIR/regions-infer-bound-from-trait.rs:33:5
+ --> $DIR/regions-infer-bound-from-trait.rs:37:5
|
+LL | fn bar1<'a,A>(x: Inv<'a>, a: A) {
+ | - help: consider adding an explicit lifetime bound...: `A: 'a`
LL | check_bound(x, a)
- | ^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `A: 'a`...
+ | ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
error[E0309]: the parameter type `A` may not live long enough
- --> $DIR/regions-infer-bound-from-trait.rs:37:5
+ --> $DIR/regions-infer-bound-from-trait.rs:41:5
|
+LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) {
+ | -- help: consider adding an explicit lifetime bound...: `A: 'a +`
LL | check_bound(x, a)
- | ^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `A: 'a`...
+ | ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
error: aborting due to 2 previous errors
// Test that we can derive lifetime bounds on type parameters
// from trait inheritance.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait Static : 'static { }
trait Is<'a> : 'a { }
+++ /dev/null
-error[E0309]: the parameter type `A` may not live long enough
- --> $DIR/regions-infer-bound-from-trait.rs:33:5
- |
-LL | fn bar1<'a,A>(x: Inv<'a>, a: A) {
- | - help: consider adding an explicit lifetime bound...: `A: 'a`
-LL | check_bound(x, a)
- | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds...
- |
-note: ...that is required by this bound
- --> $DIR/regions-infer-bound-from-trait.rs:12:21
- |
-LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
- | ^^
-
-error[E0309]: the parameter type `A` may not live long enough
- --> $DIR/regions-infer-bound-from-trait.rs:37:5
- |
-LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) {
- | -- help: consider adding an explicit lifetime bound...: `A: 'a +`
-LL | check_bound(x, a)
- | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds...
- |
-note: ...that is required by this bound
- --> $DIR/regions-infer-bound-from-trait.rs:12:21
- |
-LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
- | ^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0309`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-infer-contravariance-due-to-decl.rs:29:35
+ |
+LL | fn use_<'short,'long>(c: Contravariant<'short>,
+ | --------------------- these two types are declared with different lifetimes...
+LL | s: &'short isize,
+LL | l: &'long isize,
+ | ------------
+...
+LL | let _: Contravariant<'long> = c;
+ | ^ ...but data from `c` flows into `l` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/regions-infer-contravariance-due-to-decl.rs:25:12
+ --> $DIR/regions-infer-contravariance-due-to-decl.rs:29:12
|
LL | fn use_<'short,'long>(c: Contravariant<'short>,
| ------ ----- lifetime `'long` defined here
// Note: see variance-regions-*.rs for the tests that check that the
// variance inference works in the first place.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
use std::marker;
// This is contravariant with respect to 'a, meaning that
// 'short <= 'long, this would be true if the Contravariant type were
// covariant with respect to its parameter 'a.
- let _: Contravariant<'long> = c; //~ ERROR E0623
+ let _: Contravariant<'long> = c;
+ //[base]~^ ERROR E0623
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-infer-contravariance-due-to-decl.rs:25:35
- |
-LL | fn use_<'short,'long>(c: Contravariant<'short>,
- | --------------------- these two types are declared with different lifetimes...
-LL | s: &'short isize,
-LL | l: &'long isize,
- | ------------
-...
-LL | let _: Contravariant<'long> = c;
- | ^ ...but data from `c` flows into `l` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-infer-covariance-due-to-decl.rs:26:32
+ |
+LL | fn use_<'short,'long>(c: Covariant<'long>,
+ | ----------------
+LL | s: &'short isize,
+ | ------------- these two types are declared with different lifetimes...
+...
+LL | let _: Covariant<'short> = c;
+ | ^ ...but data from `s` flows into `c` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/regions-infer-covariance-due-to-decl.rs:22:12
+ --> $DIR/regions-infer-covariance-due-to-decl.rs:26:12
|
LL | fn use_<'short,'long>(c: Covariant<'long>,
| ------ ----- lifetime `'long` defined here
// Note: see variance-regions-*.rs for the tests that check that the
// variance inference works in the first place.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
use std::marker;
struct Covariant<'a> {
// 'short <= 'long, this would be true if the Covariant type were
// contravariant with respect to its parameter 'a.
- let _: Covariant<'short> = c; //~ ERROR E0623
+ let _: Covariant<'short> = c;
+ //[base]~^ ERROR E0623
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-infer-covariance-due-to-decl.rs:22:32
- |
-LL | fn use_<'short,'long>(c: Covariant<'long>,
- | ----------------
-LL | s: &'short isize,
- | ------------- these two types are declared with different lifetimes...
-...
-LL | let _: Covariant<'short> = c;
- | ^ ...but data from `s` flows into `c` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/regions-infer-invariance-due-to-decl.rs:16:5
+ |
+LL | b_isize
+ | ^^^^^^^ lifetime mismatch
+ |
+ = note: expected struct `Invariant<'static>`
+ found struct `Invariant<'r>`
+note: the lifetime `'r` as defined here...
+ --> $DIR/regions-infer-invariance-due-to-decl.rs:15:23
+ |
+LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
+ | ^^
+ = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
error: lifetime may not live long enough
- --> $DIR/regions-infer-invariance-due-to-decl.rs:12:5
+ --> $DIR/regions-infer-invariance-due-to-decl.rs:16:5
|
LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
| -- lifetime `'r` defined here
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
use std::marker;
struct Invariant<'a> {
}
fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
- b_isize //~ ERROR mismatched types
+ b_isize
+ //[base]~^ ERROR mismatched types
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/regions-infer-invariance-due-to-decl.rs:12:5
- |
-LL | b_isize
- | ^^^^^^^ lifetime mismatch
- |
- = note: expected struct `Invariant<'static>`
- found struct `Invariant<'r>`
-note: the lifetime `'r` as defined here...
- --> $DIR/regions-infer-invariance-due-to-decl.rs:11:23
- |
-LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
- | ^^
- = note: ...does not necessarily outlive the static lifetime
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:14:5
+ |
+LL | b_isize
+ | ^^^^^^^ lifetime mismatch
+ |
+ = note: expected struct `Invariant<'static>`
+ found struct `Invariant<'r>`
+note: the lifetime `'r` as defined here...
+ --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:13:23
+ |
+LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
+ | ^^
+ = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
error: lifetime may not live long enough
- --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:10:5
+ --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:14:5
|
LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
| -- lifetime `'r` defined here
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
struct Invariant<'a> {
f: Box<dyn FnOnce(&mut &'a isize) + 'static>,
}
}
fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
- b_isize //~ ERROR mismatched types
+ b_isize
+ //[base]~^ ERROR mismatched types
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:10:5
- |
-LL | b_isize
- | ^^^^^^^ lifetime mismatch
- |
- = note: expected struct `Invariant<'static>`
- found struct `Invariant<'r>`
-note: the lifetime `'r` as defined here...
- --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:9:23
- |
-LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
- | ^^
- = note: ...does not necessarily outlive the static lifetime
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:14:5
+ |
+LL | b_isize
+ | ^^^^^^^ lifetime mismatch
+ |
+ = note: expected struct `Invariant<'static>`
+ found struct `Invariant<'r>`
+note: the lifetime `'r` as defined here...
+ --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:13:23
+ |
+LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
+ | ^^
+ = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
error: lifetime may not live long enough
- --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:10:5
+ --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:14:5
|
LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
| -- lifetime `'r` defined here
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
struct Invariant<'a> {
f: Box<dyn FnOnce() -> *mut &'a isize + 'static>,
}
}
fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
- b_isize //~ ERROR mismatched types
+ b_isize
+ //[base]~^ ERROR mismatched types
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:10:5
- |
-LL | b_isize
- | ^^^^^^^ lifetime mismatch
- |
- = note: expected struct `Invariant<'static>`
- found struct `Invariant<'r>`
-note: the lifetime `'r` as defined here...
- --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:9:23
- |
-LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
- | ^^
- = note: ...does not necessarily outlive the static lifetime
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/regions-infer-not-param.rs:19:54
+ |
+LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
+ | ^ lifetime mismatch
+ |
+ = note: expected struct `Direct<'b>`
+ found struct `Direct<'a>`
+note: the lifetime `'a` as defined here...
+ --> $DIR/regions-infer-not-param.rs:19:16
+ |
+LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
+ | ^^
+note: ...does not necessarily outlive the lifetime `'b` as defined here
+ --> $DIR/regions-infer-not-param.rs:19:19
+ |
+LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
+ | ^^
+
+error[E0308]: mismatched types
+ --> $DIR/regions-infer-not-param.rs:25:63
+ |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+ | ^ lifetime mismatch
+ |
+ = note: expected struct `Indirect2<'b>`
+ found struct `Indirect2<'a>`
+note: the lifetime `'a` as defined here...
+ --> $DIR/regions-infer-not-param.rs:25:19
+ |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+ | ^^
+note: ...does not necessarily outlive the lifetime `'b` as defined here
+ --> $DIR/regions-infer-not-param.rs:25:22
+ |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+ | ^^
+
+error[E0308]: mismatched types
+ --> $DIR/regions-infer-not-param.rs:25:63
+ |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+ | ^ lifetime mismatch
+ |
+ = note: expected struct `Indirect2<'b>`
+ found struct `Indirect2<'a>`
+note: the lifetime `'b` as defined here...
+ --> $DIR/regions-infer-not-param.rs:25:22
+ |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+ | ^^
+note: ...does not necessarily outlive the lifetime `'a` as defined here
+ --> $DIR/regions-infer-not-param.rs:25:19
+ |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+ | ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
error: lifetime may not live long enough
- --> $DIR/regions-infer-not-param.rs:15:54
+ --> $DIR/regions-infer-not-param.rs:19:54
|
LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
| -- -- lifetime `'b` defined here ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
- --> $DIR/regions-infer-not-param.rs:19:63
+ --> $DIR/regions-infer-not-param.rs:25:63
|
LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
| -- -- lifetime `'b` defined here ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
- --> $DIR/regions-infer-not-param.rs:19:63
+ --> $DIR/regions-infer-not-param.rs:25:63
|
LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
| -- -- lifetime `'b` defined here ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
struct Direct<'a> {
f: &'a isize
}
g: Box<dyn FnOnce(Direct<'a>) + 'static>
}
-fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } //~ ERROR mismatched types
+fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
+//[base]~^ ERROR mismatched types
+//[nll]~^^ ERROR lifetime may not live long enough
fn take_indirect1(p: Indirect1) -> Indirect1 { p }
-fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } //~ ERROR mismatched types
-//~| expected struct `Indirect2<'b>`
-//~| found struct `Indirect2<'a>`
-//~| ERROR mismatched types
-//~| expected struct `Indirect2<'b>`
-//~| found struct `Indirect2<'a>`
+fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+//[base]~^ ERROR mismatched types
+//[base]~| expected struct `Indirect2<'b>`
+//[base]~| found struct `Indirect2<'a>`
+//[base]~| ERROR mismatched types
+//[base]~| expected struct `Indirect2<'b>`
+//[base]~| found struct `Indirect2<'a>`
+//[nll]~^^^^^^^ ERROR lifetime may not live long enough
+//[nll]~| ERROR lifetime may not live long enough
fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/regions-infer-not-param.rs:15:54
- |
-LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
- | ^ lifetime mismatch
- |
- = note: expected struct `Direct<'b>`
- found struct `Direct<'a>`
-note: the lifetime `'a` as defined here...
- --> $DIR/regions-infer-not-param.rs:15:16
- |
-LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
- | ^^
-note: ...does not necessarily outlive the lifetime `'b` as defined here
- --> $DIR/regions-infer-not-param.rs:15:19
- |
-LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
- | ^^
-
-error[E0308]: mismatched types
- --> $DIR/regions-infer-not-param.rs:19:63
- |
-LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
- | ^ lifetime mismatch
- |
- = note: expected struct `Indirect2<'b>`
- found struct `Indirect2<'a>`
-note: the lifetime `'a` as defined here...
- --> $DIR/regions-infer-not-param.rs:19:19
- |
-LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
- | ^^
-note: ...does not necessarily outlive the lifetime `'b` as defined here
- --> $DIR/regions-infer-not-param.rs:19:22
- |
-LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
- | ^^
-
-error[E0308]: mismatched types
- --> $DIR/regions-infer-not-param.rs:19:63
- |
-LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
- | ^ lifetime mismatch
- |
- = note: expected struct `Indirect2<'b>`
- found struct `Indirect2<'a>`
-note: the lifetime `'b` as defined here...
- --> $DIR/regions-infer-not-param.rs:19:22
- |
-LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
- | ^^
-note: ...does not necessarily outlive the lifetime `'a` as defined here
- --> $DIR/regions-infer-not-param.rs:19:19
- |
-LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
- | ^^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/regions-infer-paramd-indirect.rs:26:18
+ |
+LL | self.f = b;
+ | ^ lifetime mismatch
+ |
+ = note: expected struct `Box<Box<&'a isize>>`
+ found struct `Box<Box<&isize>>`
+note: the anonymous lifetime defined here...
+ --> $DIR/regions-infer-paramd-indirect.rs:25:36
+ |
+LL | fn set_f_bad(&mut self, b: Box<B>) {
+ | ^
+note: ...does not necessarily outlive the lifetime `'a` as defined here
+ --> $DIR/regions-infer-paramd-indirect.rs:20:6
+ |
+LL | impl<'a> SetF<'a> for C<'a> {
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
error: lifetime may not live long enough
- --> $DIR/regions-infer-paramd-indirect.rs:22:9
+ --> $DIR/regions-infer-paramd-indirect.rs:26:9
|
LL | impl<'a> SetF<'a> for C<'a> {
| -- lifetime `'a` defined here
// Check that we correctly infer that b and c must be region
// parameterized because they reference a which requires a region.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
type A<'a> = &'a isize;
type B<'a> = Box<A<'a>>;
fn set_f_bad(&mut self, b: Box<B>) {
self.f = b;
- //~^ ERROR mismatched types
- //~| expected struct `Box<Box<&'a isize>>`
- //~| found struct `Box<Box<&isize>>`
- //~| lifetime mismatch
+ //[base]~^ ERROR mismatched types
+ //[base]~| expected struct `Box<Box<&'a isize>>`
+ //[base]~| found struct `Box<Box<&isize>>`
+ //[base]~| lifetime mismatch
+ //[nll]~^^^^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/regions-infer-paramd-indirect.rs:22:18
- |
-LL | self.f = b;
- | ^ lifetime mismatch
- |
- = note: expected struct `Box<Box<&'a isize>>`
- found struct `Box<Box<&isize>>`
-note: the anonymous lifetime defined here...
- --> $DIR/regions-infer-paramd-indirect.rs:21:36
- |
-LL | fn set_f_bad(&mut self, b: Box<B>) {
- | ^
-note: ...does not necessarily outlive the lifetime `'a` as defined here
- --> $DIR/regions-infer-paramd-indirect.rs:16:6
- |
-LL | impl<'a> SetF<'a> for C<'a> {
- | ^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-lifetime-bounds-on-fns.rs:12:10
+ |
+LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
+ | --------- --------- these two types are declared with different lifetimes...
+LL | // Illegal now because there is no `'b:'a` declaration.
+LL | *x = *y;
+ | ^^ ...but data from `y` flows into `x` here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-lifetime-bounds-on-fns.rs:20:7
+ |
+LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
+ | --------- --------- these two types are declared with different lifetimes...
+...
+LL | a(x, y);
+ | ^ ...but data from `y` flows into `x` here
+
+error[E0308]: mismatched types
+ --> $DIR/regions-lifetime-bounds-on-fns.rs:28:43
+ |
+LL | let _: fn(&mut &isize, &mut &isize) = a;
+ | ^ one type is more general than the other
+ |
+ = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
+ found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0623.
+For more information about an error, try `rustc --explain E0308`.
error: lifetime may not live long enough
- --> $DIR/regions-lifetime-bounds-on-fns.rs:8:5
+ --> $DIR/regions-lifetime-bounds-on-fns.rs:12:5
|
LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'b: 'a`
error: lifetime may not live long enough
- --> $DIR/regions-lifetime-bounds-on-fns.rs:14:5
+ --> $DIR/regions-lifetime-bounds-on-fns.rs:20:5
|
LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
| -- -- lifetime `'b` defined here
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error[E0308]: mismatched types
- --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
+ --> $DIR/regions-lifetime-bounds-on-fns.rs:28:12
|
LL | let _: fn(&mut &isize, &mut &isize) = a;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
error[E0308]: mismatched types
- --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
+ --> $DIR/regions-lifetime-bounds-on-fns.rs:28:12
|
LL | let _: fn(&mut &isize, &mut &isize) = a;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
fn a<'a, 'b:'a>(x: &mut &'a isize, y: &mut &'b isize) {
// Note: this is legal because of the `'b:'a` declaration.
*x = *y;
fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
// Illegal now because there is no `'b:'a` declaration.
- *x = *y; //~ ERROR E0623
+ *x = *y;
+ //[base]~^ ERROR lifetime mismatch [E0623]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
// Here we try to call `foo` but do not know that `'a` and `'b` are
// related as required.
- a(x, y); //~ ERROR lifetime mismatch [E0623]
+ a(x, y);
+ //[base]~^ ERROR lifetime mismatch [E0623]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn d() {
// 'a and 'b are early bound in the function `a` because they appear
// inconstraints:
- let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0308
+ let _: fn(&mut &isize, &mut &isize) = a;
+ //~^ ERROR mismatched types [E0308]
+ //[nll]~^^ ERROR mismatched types [E0308]
}
fn e() {
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-lifetime-bounds-on-fns.rs:8:10
- |
-LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
- | --------- --------- these two types are declared with different lifetimes...
-LL | // Illegal now because there is no `'b:'a` declaration.
-LL | *x = *y;
- | ^^ ...but data from `y` flows into `x` here
-
-error[E0623]: lifetime mismatch
- --> $DIR/regions-lifetime-bounds-on-fns.rs:14:7
- |
-LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
- | --------- --------- these two types are declared with different lifetimes...
-...
-LL | a(x, y);
- | ^ ...but data from `y` flows into `x` here
-
-error[E0308]: mismatched types
- --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
- |
-LL | let _: fn(&mut &isize, &mut &isize) = a;
- | ^ one type is more general than the other
- |
- = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
- found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0308, E0623.
-For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+ --> $DIR/regions-nested-fns.rs:9:18
+ |
+LL | let mut ay = &y;
+ | ^^
+ |
+note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
+ --> $DIR/regions-nested-fns.rs:13:58
+ |
+LL | ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| {
+ | __________________________________________________________^
+LL | | ay = x;
+LL | | ay = &y;
+LL | |
+LL | | ay = z;
+LL | |
+LL | | }));
+ | |_____^
+note: ...so that reference does not outlive borrowed content
+ --> $DIR/regions-nested-fns.rs:17:14
+ |
+LL | ay = z;
+ | ^
+note: but, the lifetime must be valid for the anonymous lifetime #1 defined here...
+ --> $DIR/regions-nested-fns.rs:21:72
+ |
+LL | ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
+ | ________________________________________________________________________^
+LL | | if false { return x; }
+LL | |
+LL | |
+LL | | if false { return ay; }
+LL | | return z;
+LL | | }));
+ | |_____^
+note: ...so that the types are compatible
+ --> $DIR/regions-nested-fns.rs:21:76
+ |
+LL | ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
+ | ____________________________________________________________________________^
+LL | | if false { return x; }
+LL | |
+LL | |
+LL | | if false { return ay; }
+LL | | return z;
+LL | | }));
+ | |_____^
+ = note: expected `&isize`
+ found `&isize`
+
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+ --> $DIR/regions-nested-fns.rs:22:27
+ |
+LL | if false { return x; }
+ | ^
+ |
+note: ...the reference is valid for the anonymous lifetime #1 defined here...
+ --> $DIR/regions-nested-fns.rs:21:72
+ |
+LL | ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
+ | ________________________________________________________________________^
+LL | | if false { return x; }
+LL | |
+LL | |
+LL | | if false { return ay; }
+LL | | return z;
+LL | | }));
+ | |_____^
+note: ...but the borrowed content is only valid for the lifetime `'x` as defined here
+ --> $DIR/regions-nested-fns.rs:7:11
+ |
+LL | fn nested<'x>(x: &'x isize) {
+ | ^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0312, E0495.
+For more information about an error, try `rustc --explain E0312`.
error[E0521]: borrowed data escapes outside of closure
- --> $DIR/regions-nested-fns.rs:10:9
+ --> $DIR/regions-nested-fns.rs:17:9
|
LL | let mut ay = &y;
| ------ `ay` declared here, outside of the closure body
-LL |
+...
LL | ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| {
| - `z` is a reference that is only valid in the closure body
...
| ^^^^^^ `z` escapes the closure body here
error[E0597]: `y` does not live long enough
- --> $DIR/regions-nested-fns.rs:5:18
+ --> $DIR/regions-nested-fns.rs:9:18
|
LL | let mut ay = &y;
| ^^ borrowed value does not live long enough
| - `y` dropped here while still borrowed
error[E0597]: `y` does not live long enough
- --> $DIR/regions-nested-fns.rs:9:15
+ --> $DIR/regions-nested-fns.rs:15:15
|
LL | ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| {
| --- value captured here
| - `y` dropped here while still borrowed
error: lifetime may not live long enough
- --> $DIR/regions-nested-fns.rs:14:27
+ --> $DIR/regions-nested-fns.rs:22:27
|
LL | fn nested<'x>(x: &'x isize) {
| -- lifetime `'x` defined here
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
fn ignore<T>(t: T) {}
fn nested<'x>(x: &'x isize) {
let y = 3;
- let mut ay = &y; //~ ERROR E0495
+ let mut ay = &y;
+ //[base]~^ ERROR E0495
+ //[nll]~^^ ERROR `y` does not live long enough [E0597]
ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| {
ay = x;
ay = &y;
+ //[nll]~^ ERROR `y` does not live long enough
ay = z;
+ //[nll]~^ ERROR borrowed data escapes outside of closure [E0521]
}));
ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
- if false { return x; } //~ ERROR E0312
+ if false { return x; }
+ //[base]~^ ERROR E0312
+ //[nll]~^^ ERROR lifetime may not live long enough
if false { return ay; }
return z;
}));
+++ /dev/null
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
- --> $DIR/regions-nested-fns.rs:5:18
- |
-LL | let mut ay = &y;
- | ^^
- |
-note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
- --> $DIR/regions-nested-fns.rs:7:58
- |
-LL | ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| {
- | __________________________________________________________^
-LL | | ay = x;
-LL | | ay = &y;
-LL | | ay = z;
-LL | | }));
- | |_____^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/regions-nested-fns.rs:10:14
- |
-LL | ay = z;
- | ^
-note: but, the lifetime must be valid for the anonymous lifetime #1 defined here...
- --> $DIR/regions-nested-fns.rs:13:72
- |
-LL | ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
- | ________________________________________________________________________^
-LL | | if false { return x; }
-LL | | if false { return ay; }
-LL | | return z;
-LL | | }));
- | |_____^
-note: ...so that the types are compatible
- --> $DIR/regions-nested-fns.rs:13:76
- |
-LL | ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
- | ____________________________________________________________________________^
-LL | | if false { return x; }
-LL | | if false { return ay; }
-LL | | return z;
-LL | | }));
- | |_____^
- = note: expected `&isize`
- found `&isize`
-
-error[E0312]: lifetime of reference outlives lifetime of borrowed content...
- --> $DIR/regions-nested-fns.rs:14:27
- |
-LL | if false { return x; }
- | ^
- |
-note: ...the reference is valid for the anonymous lifetime #1 defined here...
- --> $DIR/regions-nested-fns.rs:13:72
- |
-LL | ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
- | ________________________________________________________________________^
-LL | | if false { return x; }
-LL | | if false { return ay; }
-LL | | return z;
-LL | | }));
- | |_____^
-note: ...but the borrowed content is only valid for the lifetime `'x` as defined here
- --> $DIR/regions-nested-fns.rs:3:11
- |
-LL | fn nested<'x>(x: &'x isize) {
- | ^^
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0312, E0495.
-For more information about an error, try `rustc --explain E0312`.
--- /dev/null
+error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
+ --> $DIR/regions-outlives-projection-container.rs:40:13
+ |
+LL | let _x: &'a WithAssoc<TheType<'b>> = loop { };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the pointer is valid for the lifetime `'a` as defined here
+ --> $DIR/regions-outlives-projection-container.rs:32:15
+ |
+LL | fn with_assoc<'a,'b>() {
+ | ^^
+note: but the referenced data is only valid for the lifetime `'b` as defined here
+ --> $DIR/regions-outlives-projection-container.rs:32:18
+ |
+LL | fn with_assoc<'a,'b>() {
+ | ^^
+
+error[E0491]: in type `&'a WithoutAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
+ --> $DIR/regions-outlives-projection-container.rs:59:13
+ |
+LL | let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the pointer is valid for the lifetime `'a` as defined here
+ --> $DIR/regions-outlives-projection-container.rs:55:18
+ |
+LL | fn without_assoc<'a,'b>() {
+ | ^^
+note: but the referenced data is only valid for the lifetime `'b` as defined here
+ --> $DIR/regions-outlives-projection-container.rs:55:21
+ |
+LL | fn without_assoc<'a,'b>() {
+ | ^^
+
+error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
+ --> $DIR/regions-outlives-projection-container.rs:69:12
+ |
+LL | call::<&'a WithAssoc<TheType<'b>>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the pointer is valid for the lifetime `'a` as defined here
+ --> $DIR/regions-outlives-projection-container.rs:64:20
+ |
+LL | fn call_with_assoc<'a,'b>() {
+ | ^^
+note: but the referenced data is only valid for the lifetime `'b` as defined here
+ --> $DIR/regions-outlives-projection-container.rs:64:23
+ |
+LL | fn call_with_assoc<'a,'b>() {
+ | ^^
+
+error[E0491]: in type `&'a WithoutAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
+ --> $DIR/regions-outlives-projection-container.rs:77:12
+ |
+LL | call::<&'a WithoutAssoc<TheType<'b>>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the pointer is valid for the lifetime `'a` as defined here
+ --> $DIR/regions-outlives-projection-container.rs:74:23
+ |
+LL | fn call_without_assoc<'a,'b>() {
+ | ^^
+note: but the referenced data is only valid for the lifetime `'b` as defined here
+ --> $DIR/regions-outlives-projection-container.rs:74:26
+ |
+LL | fn call_without_assoc<'a,'b>() {
+ | ^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0491`.
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container.rs:36:13
+ --> $DIR/regions-outlives-projection-container.rs:40:13
|
LL | fn with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'b: 'a`
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container.rs:54:13
+ --> $DIR/regions-outlives-projection-container.rs:59:13
|
LL | fn without_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'b: 'a`
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container.rs:63:5
+ --> $DIR/regions-outlives-projection-container.rs:69:5
|
LL | fn call_with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'b: 'a`
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container.rs:70:5
+ --> $DIR/regions-outlives-projection-container.rs:77:5
|
LL | fn call_without_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
// type of a bound that appears in the where clause on a struct must
// outlive the location in which the type appears. Issue #22246.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![allow(dead_code)]
#![feature(rustc_attrs)]
// FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if
// `_x` is changed to `_`
let _x: &'a WithAssoc<TheType<'b>> = loop { };
- //~^ ERROR reference has a longer lifetime
+ //[base]~^ ERROR reference has a longer lifetime
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn with_assoc1<'a,'b>() where 'b : 'a {
// that `'b:'a` holds because the `'b` appears in `TheType<'b>`.
let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
- //~^ ERROR reference has a longer lifetime
+ //[base]~^ ERROR reference has a longer lifetime
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn call_with_assoc<'a,'b>() {
// no data.
call::<&'a WithAssoc<TheType<'b>>>();
- //~^ ERROR reference has a longer lifetime
+ //[base]~^ ERROR reference has a longer lifetime
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn call_without_assoc<'a,'b>() {
// As `without_assoc`, but in a distinct scenario.
- call::<&'a WithoutAssoc<TheType<'b>>>(); //~ ERROR reference has a longer lifetime
+ call::<&'a WithoutAssoc<TheType<'b>>>();
+ //[base]~^ ERROR reference has a longer lifetime
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn call<T>() { }
+++ /dev/null
-error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container.rs:36:13
- |
-LL | let _x: &'a WithAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container.rs:28:15
- |
-LL | fn with_assoc<'a,'b>() {
- | ^^
-note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container.rs:28:18
- |
-LL | fn with_assoc<'a,'b>() {
- | ^^
-
-error[E0491]: in type `&'a WithoutAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container.rs:54:13
- |
-LL | let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container.rs:50:18
- |
-LL | fn without_assoc<'a,'b>() {
- | ^^
-note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container.rs:50:21
- |
-LL | fn without_assoc<'a,'b>() {
- | ^^
-
-error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container.rs:63:12
- |
-LL | call::<&'a WithAssoc<TheType<'b>>>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container.rs:58:20
- |
-LL | fn call_with_assoc<'a,'b>() {
- | ^^
-note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container.rs:58:23
- |
-LL | fn call_with_assoc<'a,'b>() {
- | ^^
-
-error[E0491]: in type `&'a WithoutAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container.rs:70:12
- |
-LL | call::<&'a WithoutAssoc<TheType<'b>>>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container.rs:67:23
- |
-LL | fn call_without_assoc<'a,'b>() {
- | ^^
-note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container.rs:67:26
- |
-LL | fn call_without_assoc<'a,'b>() {
- | ^^
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0491`.
--- /dev/null
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/regions-proc-bound-capture.rs:13:14
+ |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+ | ------ this data with an anonymous lifetime `'_`...
+LL | // This is illegal, because the region bound on `proc` is 'static.
+LL | Box::new(move || { *x })
+ | ^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here
+ |
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/regions-proc-bound-capture.rs:11:59
+ |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+ | ^^^^^^^ `'static` requirement introduced here
+LL | // This is illegal, because the region bound on `proc` is 'static.
+LL | Box::new(move || { *x })
+ | ------------------------ because of this returned expression
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
+ |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + '_> {
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn static_proc(x: &'static isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+ | ~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0759`.
error: lifetime may not live long enough
- --> $DIR/regions-proc-bound-capture.rs:9:5
+ --> $DIR/regions-proc-bound-capture.rs:13:5
|
LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
| - let's call the lifetime of this reference `'1`
LL | // This is illegal, because the region bound on `proc` is 'static.
LL | Box::new(move || { *x })
| ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+ |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
+ |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + '_> {
+ | ~~
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn static_proc(x: &'static isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+ | ~~~~~~~~~~~~~~
error: aborting due to previous error
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
fn borrowed_proc<'a>(x: &'a isize) -> Box<dyn FnMut()->(isize) + 'a> {
// This is legal, because the region bound on `proc`
// states that it captures `x`.
fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
// This is illegal, because the region bound on `proc` is 'static.
- Box::new(move || { *x }) //~ ERROR E0759
+ Box::new(move || { *x })
+ //[base]~^ ERROR E0759
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() { }
+++ /dev/null
-error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/regions-proc-bound-capture.rs:9:14
- |
-LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
- | ------ this data with an anonymous lifetime `'_`...
-LL | // This is illegal, because the region bound on `proc` is 'static.
-LL | Box::new(move || { *x })
- | ^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here
- |
-note: `'static` lifetime requirement introduced by the return type
- --> $DIR/regions-proc-bound-capture.rs:7:59
- |
-LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
- | ^^^^^^^ `'static` requirement introduced here
-LL | // This is illegal, because the region bound on `proc` is 'static.
-LL | Box::new(move || { *x })
- | ------------------------ because of this returned expression
-help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
- |
-LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + '_> {
- | ~~
-help: alternatively, add an explicit `'static` bound to this reference
- |
-LL | fn static_proc(x: &'static isize) -> Box<dyn FnMut() -> (isize) + 'static> {
- | ~~~~~~~~~~~~~~
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0759`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:8:5
+ |
+LL | fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize {
+ | ----------------------------- -------------
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | &mut ***p
+ | ^^^^^^^^^ ...but data from `p` is returned here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:4:5
+ --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:8:5
|
LL | fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize {
| -- -- lifetime `'b` defined here
// Issue #8624. Test for reborrowing with 3 levels, not just two.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize {
- &mut ***p //~ ERROR lifetime mismatch [E0623]
+ &mut ***p
+ //[base]~^ ERROR lifetime mismatch [E0623]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:4:5
- |
-LL | fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize {
- | ----------------------------- -------------
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | &mut ***p
- | ^^^^^^^^^ ...but data from `p` is returned here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:10:5
+ |
+LL | fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize {
+ | --------------------- -------------
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | &mut **p
+ | ^^^^^^^^ ...but data from `p` is returned here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:6:5
+ --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:10:5
|
LL | fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize {
| -- -- lifetime `'b` defined here
// pointer which is backed by another `&'a mut` can only be done
// for `'a` (which must be a sublifetime of `'b`).
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize {
- &mut **p //~ ERROR lifetime mismatch [E0623]
+ &mut **p
+ //[base]~^ ERROR lifetime mismatch [E0623]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:6:5
- |
-LL | fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize {
- | --------------------- -------------
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | &mut **p
- | ^^^^^^^^ ...but data from `p` is returned here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+ --> $DIR/regions-ret-borrowed-1.rs:14:14
+ |
+LL | with(|o| o)
+ | ^
+ |
+note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
+ --> $DIR/regions-ret-borrowed-1.rs:14:10
+ |
+LL | with(|o| o)
+ | ^^^^^
+note: ...so that the types are compatible
+ --> $DIR/regions-ret-borrowed-1.rs:14:14
+ |
+LL | with(|o| o)
+ | ^
+ = note: expected `&isize`
+ found `&isize`
+note: but, the lifetime must be valid for the lifetime `'a` as defined here...
+ --> $DIR/regions-ret-borrowed-1.rs:13:14
+ |
+LL | fn return_it<'a>() -> &'a isize {
+ | ^^
+note: ...so that reference does not outlive borrowed content
+ --> $DIR/regions-ret-borrowed-1.rs:14:5
+ |
+LL | with(|o| o)
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
error: lifetime may not live long enough
- --> $DIR/regions-ret-borrowed-1.rs:10:14
+ --> $DIR/regions-ret-borrowed-1.rs:14:14
|
LL | with(|o| o)
| -- ^ returning this value requires that `'1` must outlive `'2`
// some point regions-ret-borrowed reported an error but this file did
// not, due to special hardcoding around the anonymous region.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
fn with<R, F>(f: F) -> R where F: for<'a> FnOnce(&'a isize) -> R {
f(&3)
}
fn return_it<'a>() -> &'a isize {
with(|o| o)
- //~^ ERROR cannot infer
+ //[base]~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements [E0495]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {
+++ /dev/null
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
- --> $DIR/regions-ret-borrowed-1.rs:10:14
- |
-LL | with(|o| o)
- | ^
- |
-note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
- --> $DIR/regions-ret-borrowed-1.rs:10:10
- |
-LL | with(|o| o)
- | ^^^^^
-note: ...so that the types are compatible
- --> $DIR/regions-ret-borrowed-1.rs:10:14
- |
-LL | with(|o| o)
- | ^
- = note: expected `&isize`
- found `&isize`
-note: but, the lifetime must be valid for the lifetime `'a` as defined here...
- --> $DIR/regions-ret-borrowed-1.rs:9:14
- |
-LL | fn return_it<'a>() -> &'a isize {
- | ^^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/regions-ret-borrowed-1.rs:10:5
- |
-LL | with(|o| o)
- | ^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
--- /dev/null
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+ --> $DIR/regions-ret-borrowed.rs:17:14
+ |
+LL | with(|o| o)
+ | ^
+ |
+note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
+ --> $DIR/regions-ret-borrowed.rs:17:10
+ |
+LL | with(|o| o)
+ | ^^^^^
+note: ...so that the types are compatible
+ --> $DIR/regions-ret-borrowed.rs:17:14
+ |
+LL | with(|o| o)
+ | ^
+ = note: expected `&isize`
+ found `&isize`
+note: but, the lifetime must be valid for the lifetime `'a` as defined here...
+ --> $DIR/regions-ret-borrowed.rs:16:14
+ |
+LL | fn return_it<'a>() -> &'a isize {
+ | ^^
+note: ...so that reference does not outlive borrowed content
+ --> $DIR/regions-ret-borrowed.rs:17:5
+ |
+LL | with(|o| o)
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
error: lifetime may not live long enough
- --> $DIR/regions-ret-borrowed.rs:13:14
+ --> $DIR/regions-ret-borrowed.rs:17:14
|
LL | with(|o| o)
| -- ^ returning this value requires that `'1` must outlive `'2`
// used to successfully compile because we failed to account for the
// fact that fn(x: &isize) rebound the region &.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
fn with<R, F>(f: F) -> R where F: FnOnce(&isize) -> R {
f(&3)
}
fn return_it<'a>() -> &'a isize {
with(|o| o)
- //~^ ERROR cannot infer
+ //[base]~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements [E0495]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {
+++ /dev/null
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
- --> $DIR/regions-ret-borrowed.rs:13:14
- |
-LL | with(|o| o)
- | ^
- |
-note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
- --> $DIR/regions-ret-borrowed.rs:13:10
- |
-LL | with(|o| o)
- | ^^^^^
-note: ...so that the types are compatible
- --> $DIR/regions-ret-borrowed.rs:13:14
- |
-LL | with(|o| o)
- | ^
- = note: expected `&isize`
- found `&isize`
-note: but, the lifetime must be valid for the lifetime `'a` as defined here...
- --> $DIR/regions-ret-borrowed.rs:12:14
- |
-LL | fn return_it<'a>() -> &'a isize {
- | ^^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/regions-ret-borrowed.rs:13:5
- |
-LL | with(|o| o)
- | ^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
--- /dev/null
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+ --> $DIR/regions-static-bound.rs:10:5
+ |
+LL | t
+ | ^
+ |
+ = note: ...the reference is valid for the static lifetime...
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined here
+ --> $DIR/regions-static-bound.rs:9:24
+ |
+LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
+ | ^^
+
+error[E0759]: `u` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/regions-static-bound.rs:16:5
+ |
+LL | fn error(u: &(), v: &()) {
+ | --- this data with an anonymous lifetime `'_`...
+LL | static_id(&u);
+ | ^^^^^^^^^ -- ...is used here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/regions-static-bound.rs:16:5
+ |
+LL | static_id(&u);
+ | ^^^^^^^^^
+
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/regions-static-bound.rs:19:5
+ |
+LL | fn error(u: &(), v: &()) {
+ | --- this data with an anonymous lifetime `'_`...
+...
+LL | static_id_indirect(&v);
+ | ^^^^^^^^^^^^^^^^^^ -- ...is used here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/regions-static-bound.rs:19:5
+ |
+LL | static_id_indirect(&v);
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0312, E0759.
+For more information about an error, try `rustc --explain E0312`.
error: lifetime may not live long enough
- --> $DIR/regions-static-bound.rs:6:5
+ --> $DIR/regions-static-bound.rs:10:5
|
LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
| -- lifetime `'a` defined here
| ^ returning this value requires that `'a` must outlive `'static`
error[E0521]: borrowed data escapes outside of function
- --> $DIR/regions-static-bound.rs:10:5
+ --> $DIR/regions-static-bound.rs:16:5
|
LL | fn error(u: &(), v: &()) {
| - - let's call the lifetime of this reference `'1`
| argument requires that `'1` must outlive `'static`
error[E0521]: borrowed data escapes outside of function
- --> $DIR/regions-static-bound.rs:11:5
+ --> $DIR/regions-static-bound.rs:19:5
|
LL | fn error(u: &(), v: &()) {
| - - let's call the lifetime of this reference `'2`
| |
| `v` is a reference that is only valid in the function body
-LL | static_id(&u);
+...
LL | static_id_indirect(&v);
| ^^^^^^^^^^^^^^^^^^^^^^
| |
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
fn static_id<'a,'b>(t: &'a ()) -> &'static ()
where 'a: 'static { t }
fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
where 'a: 'b, 'b: 'static { t }
fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
- t //~ ERROR E0312
+ t
+ //[base]~^ ERROR E0312
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn error(u: &(), v: &()) {
- static_id(&u); //~ ERROR `u` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
- static_id_indirect(&v); //~ ERROR `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
+ static_id(&u);
+ //[base]~^ ERROR `u` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
+ //[nll]~^^ ERROR borrowed data escapes outside of function [E0521]
+ static_id_indirect(&v);
+ //[base]~^ ERROR `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
+ //[nll]~^^ ERROR borrowed data escapes outside of function [E0521]
}
fn main() {}
+++ /dev/null
-error[E0312]: lifetime of reference outlives lifetime of borrowed content...
- --> $DIR/regions-static-bound.rs:6:5
- |
-LL | t
- | ^
- |
- = note: ...the reference is valid for the static lifetime...
-note: ...but the borrowed content is only valid for the lifetime `'a` as defined here
- --> $DIR/regions-static-bound.rs:5:24
- |
-LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
- | ^^
-
-error[E0759]: `u` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/regions-static-bound.rs:10:5
- |
-LL | fn error(u: &(), v: &()) {
- | --- this data with an anonymous lifetime `'_`...
-LL | static_id(&u);
- | ^^^^^^^^^ -- ...is used here...
- |
-note: ...and is required to live as long as `'static` here
- --> $DIR/regions-static-bound.rs:10:5
- |
-LL | static_id(&u);
- | ^^^^^^^^^
-
-error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/regions-static-bound.rs:11:5
- |
-LL | fn error(u: &(), v: &()) {
- | --- this data with an anonymous lifetime `'_`...
-LL | static_id(&u);
-LL | static_id_indirect(&v);
- | ^^^^^^^^^^^^^^^^^^ -- ...is used here...
- |
-note: ...and is required to live as long as `'static` here
- --> $DIR/regions-static-bound.rs:11:5
- |
-LL | static_id_indirect(&v);
- | ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0312, E0759.
-For more information about an error, try `rustc --explain E0312`.
--- /dev/null
+error[E0478]: lifetime bound not satisfied
+ --> $DIR/regions-trait-object-subtyping.rs:19:5
+ |
+LL | x
+ | ^
+ |
+note: lifetime parameter instantiated with the lifetime `'a` as defined here
+ --> $DIR/regions-trait-object-subtyping.rs:17:9
+ |
+LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
+ | ^^
+note: but lifetime parameter must outlive the lifetime `'b` as defined here
+ --> $DIR/regions-trait-object-subtyping.rs:17:12
+ |
+LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
+ | ^^
+
+error[E0495]: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements
+ --> $DIR/regions-trait-object-subtyping.rs:19:5
+ |
+LL | x
+ | ^
+ |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+ --> $DIR/regions-trait-object-subtyping.rs:17:9
+ |
+LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
+ | ^^
+note: ...so that reference does not outlive borrowed content
+ --> $DIR/regions-trait-object-subtyping.rs:19:5
+ |
+LL | x
+ | ^
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+ --> $DIR/regions-trait-object-subtyping.rs:17:12
+ |
+LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
+ | ^^
+note: ...so that the types are compatible
+ --> $DIR/regions-trait-object-subtyping.rs:19:5
+ |
+LL | x
+ | ^
+ = note: expected `&'b mut (dyn Dummy + 'b)`
+ found `&mut (dyn Dummy + 'b)`
+
+error[E0308]: mismatched types
+ --> $DIR/regions-trait-object-subtyping.rs:28:5
+ |
+LL | x
+ | ^ lifetime mismatch
+ |
+ = note: expected struct `Wrapper<&'b mut (dyn Dummy + 'b)>`
+ found struct `Wrapper<&'a mut (dyn Dummy + 'a)>`
+note: the lifetime `'b` as defined here...
+ --> $DIR/regions-trait-object-subtyping.rs:26:15
+ |
+LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
+ | ^^
+note: ...does not necessarily outlive the lifetime `'a` as defined here
+ --> $DIR/regions-trait-object-subtyping.rs:26:9
+ |
+LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
+ | ^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0478, E0495.
+For more information about an error, try `rustc --explain E0308`.
error: lifetime may not live long enough
- --> $DIR/regions-trait-object-subtyping.rs:15:5
+ --> $DIR/regions-trait-object-subtyping.rs:19:5
|
LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
| -- -- lifetime `'b` defined here
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
- --> $DIR/regions-trait-object-subtyping.rs:22:5
+ --> $DIR/regions-trait-object-subtyping.rs:28:5
|
LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
| -- -- lifetime `'b` defined here
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
trait Dummy { fn dummy(&self); }
fn foo1<'a:'b,'b>(x: &'a mut (dyn Dummy+'a)) -> &'b mut (dyn Dummy+'b) {
fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
// Without knowing 'a:'b, we can't coerce
- x //~ ERROR lifetime bound not satisfied
- //~^ ERROR cannot infer an appropriate lifetime
+ x
+ //[base]~^ ERROR lifetime bound not satisfied
+ //[base]~| ERROR cannot infer an appropriate lifetime
+ //[nll]~^^^ ERROR lifetime may not live long enough
}
struct Wrapper<T>(T);
fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
// We can't coerce because it is packed in `Wrapper`
- x //~ ERROR mismatched types
+ x
+ //[base]~^ ERROR mismatched types
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0478]: lifetime bound not satisfied
- --> $DIR/regions-trait-object-subtyping.rs:15:5
- |
-LL | x
- | ^
- |
-note: lifetime parameter instantiated with the lifetime `'a` as defined here
- --> $DIR/regions-trait-object-subtyping.rs:13:9
- |
-LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
- | ^^
-note: but lifetime parameter must outlive the lifetime `'b` as defined here
- --> $DIR/regions-trait-object-subtyping.rs:13:12
- |
-LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
- | ^^
-
-error[E0495]: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements
- --> $DIR/regions-trait-object-subtyping.rs:15:5
- |
-LL | x
- | ^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
- --> $DIR/regions-trait-object-subtyping.rs:13:9
- |
-LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
- | ^^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/regions-trait-object-subtyping.rs:15:5
- |
-LL | x
- | ^
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
- --> $DIR/regions-trait-object-subtyping.rs:13:12
- |
-LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
- | ^^
-note: ...so that the types are compatible
- --> $DIR/regions-trait-object-subtyping.rs:15:5
- |
-LL | x
- | ^
- = note: expected `&'b mut (dyn Dummy + 'b)`
- found `&mut (dyn Dummy + 'b)`
-
-error[E0308]: mismatched types
- --> $DIR/regions-trait-object-subtyping.rs:22:5
- |
-LL | x
- | ^ lifetime mismatch
- |
- = note: expected struct `Wrapper<&'b mut (dyn Dummy + 'b)>`
- found struct `Wrapper<&'a mut (dyn Dummy + 'a)>`
-note: the lifetime `'b` as defined here...
- --> $DIR/regions-trait-object-subtyping.rs:20:15
- |
-LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
- | ^^
-note: ...does not necessarily outlive the lifetime `'a` as defined here
- --> $DIR/regions-trait-object-subtyping.rs:20:9
- |
-LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
- | ^^
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0308, E0478, E0495.
-For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:29:30
+ |
+LL | fn use_<'short,'long>(c: S<'long, 'short>,
+ | ---------------- this type is declared with multiple lifetimes...
+...
+LL | let _: S<'long, 'long> = c;
+ | ^ ...but data with one lifetime flows into the other here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:25:12
+ --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:29:12
|
LL | fn use_<'short,'long>(c: S<'long, 'short>,
| ------ ----- lifetime `'long` defined here
// Note: see variance-regions-*.rs for the tests that check that the
// variance inference works in the first place.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
// `S` is contravariant with respect to both parameters.
struct S<'a, 'b> {
f: &'a isize,
// 'short <= 'long, this would be true if the Contravariant type were
// covariant with respect to its parameter 'a.
- let _: S<'long, 'long> = c; //~ ERROR E0623
+ let _: S<'long, 'long> = c;
+ //[base]~^ ERROR E0623
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:25:30
- |
-LL | fn use_<'short,'long>(c: S<'long, 'short>,
- | ---------------- this type is declared with multiple lifetimes...
-...
-LL | let _: S<'long, 'long> = c;
- | ^ ...but data with one lifetime flows into the other here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-variance-contravariant-use-covariant.rs:27:35
+ |
+LL | fn use_<'short,'long>(c: Contravariant<'short>,
+ | --------------------- these two types are declared with different lifetimes...
+LL | s: &'short isize,
+LL | l: &'long isize,
+ | ------------
+...
+LL | let _: Contravariant<'long> = c;
+ | ^ ...but data from `c` flows into `l` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/regions-variance-contravariant-use-covariant.rs:23:12
+ --> $DIR/regions-variance-contravariant-use-covariant.rs:27:12
|
LL | fn use_<'short,'long>(c: Contravariant<'short>,
| ------ ----- lifetime `'long` defined here
// Note: see variance-regions-*.rs for the tests that check that the
// variance inference works in the first place.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
// This is contravariant with respect to 'a, meaning that
// Contravariant<'long> <: Contravariant<'short> iff
// 'short <= 'long
// 'short <= 'long, this would be true if the Contravariant type were
// covariant with respect to its parameter 'a.
- let _: Contravariant<'long> = c; //~ ERROR E0623
+ let _: Contravariant<'long> = c;
+ //[base]~^ ERROR E0623
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-variance-contravariant-use-covariant.rs:23:35
- |
-LL | fn use_<'short,'long>(c: Contravariant<'short>,
- | --------------------- these two types are declared with different lifetimes...
-LL | s: &'short isize,
-LL | l: &'long isize,
- | ------------
-...
-LL | let _: Contravariant<'long> = c;
- | ^ ...but data from `c` flows into `l` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-variance-covariant-use-contravariant.rs:27:32
+ |
+LL | fn use_<'short,'long>(c: Covariant<'long>,
+ | ----------------
+LL | s: &'short isize,
+ | ------------- these two types are declared with different lifetimes...
+...
+LL | let _: Covariant<'short> = c;
+ | ^ ...but data from `s` flows into `c` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/regions-variance-covariant-use-contravariant.rs:23:12
+ --> $DIR/regions-variance-covariant-use-contravariant.rs:27:12
|
LL | fn use_<'short,'long>(c: Covariant<'long>,
| ------ ----- lifetime `'long` defined here
// Note: see variance-regions-*.rs for the tests that check that the
// variance inference works in the first place.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
// This is covariant with respect to 'a, meaning that
// Covariant<'foo> <: Covariant<'static> because
// 'foo <= 'static
// 'short <= 'long, this would be true if the Covariant type were
// contravariant with respect to its parameter 'a.
- let _: Covariant<'short> = c; //~ ERROR E0623
+ let _: Covariant<'short> = c;
+ //[base]~^ ERROR E0623
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-variance-covariant-use-contravariant.rs:23:32
- |
-LL | fn use_<'short,'long>(c: Covariant<'long>,
- | ----------------
-LL | s: &'short isize,
- | ------------- these two types are declared with different lifetimes...
-...
-LL | let _: Covariant<'short> = c;
- | ^ ...but data from `s` flows into `c` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/regions-variance-invariant-use-contravariant.rs:24:32
+ |
+LL | fn use_<'short,'long>(c: Invariant<'long>,
+ | ----------------
+LL | s: &'short isize,
+ | ------------- these two types are declared with different lifetimes...
+...
+LL | let _: Invariant<'short> = c;
+ | ^ ...but data from `s` flows into `c` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/regions-variance-invariant-use-contravariant.rs:20:12
+ --> $DIR/regions-variance-invariant-use-contravariant.rs:24:12
|
LL | fn use_<'short,'long>(c: Invariant<'long>,
| ------ ----- lifetime `'long` defined here
// Note: see variance-regions-*.rs for the tests that check that the
// variance inference works in the first place.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
struct Invariant<'a> {
f: &'a mut &'a isize
}
// 'short <= 'long, this would be true if the Invariant type were
// contravariant with respect to its parameter 'a.
- let _: Invariant<'short> = c; //~ ERROR E0623
+ let _: Invariant<'short> = c;
+ //[base]~^ ERROR E0623
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() { }
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/regions-variance-invariant-use-contravariant.rs:20:32
- |
-LL | fn use_<'short,'long>(c: Invariant<'long>,
- | ----------------
-LL | s: &'short isize,
- | ------------- these two types are declared with different lifetimes...
-...
-LL | let _: Invariant<'short> = c;
- | ^ ...but data from `s` flows into `c` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/regions-variance-invariant-use-covariant.rs:21:33
+ |
+LL | let _: Invariant<'static> = c;
+ | ^ lifetime mismatch
+ |
+ = note: expected struct `Invariant<'static>`
+ found struct `Invariant<'b>`
+note: the lifetime `'b` as defined here...
+ --> $DIR/regions-variance-invariant-use-covariant.rs:15:9
+ |
+LL | fn use_<'b>(c: Invariant<'b>) {
+ | ^^
+ = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
error: lifetime may not live long enough
- --> $DIR/regions-variance-invariant-use-covariant.rs:17:12
+ --> $DIR/regions-variance-invariant-use-covariant.rs:21:12
|
LL | fn use_<'b>(c: Invariant<'b>) {
| -- lifetime `'b` defined here
// Note: see variance-regions-*.rs for the tests that check that the
// variance inference works in the first place.
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
struct Invariant<'a> {
f: &'a mut &'a isize
}
// Since 'b <= 'static, this would be true if Invariant were covariant
// with respect to its parameter 'a.
- let _: Invariant<'static> = c; //~ ERROR mismatched types
+ let _: Invariant<'static> = c;
+ //[base]~^ ERROR mismatched types [E0308]
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn main() { }
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/regions-variance-invariant-use-covariant.rs:17:33
- |
-LL | let _: Invariant<'static> = c;
- | ^ lifetime mismatch
- |
- = note: expected struct `Invariant<'static>`
- found struct `Invariant<'b>`
-note: the lifetime `'b` as defined here...
- --> $DIR/regions-variance-invariant-use-covariant.rs:11:9
- |
-LL | fn use_<'b>(c: Invariant<'b>) {
- | ^^
- = note: ...does not necessarily outlive the static lifetime
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
pub struct Int(i32);
impl const std::ops::Add for i32 { //~ ERROR type annotations needed
- //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+ //~^ ERROR only traits defined in the current crate can be implemented for primitive types
type Output = Self;
fn add(self, rhs: Self) -> Self {
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/const-and-non-const-impl.rs:5:1
|
LL | impl const std::ops::Add for i32 {
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
= note: can only be called if the required target features are available
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:24:5
+ --> $DIR/safe-calls.rs:26:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
= note: can only be called if the required target features are available
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:25:5
+ --> $DIR/safe-calls.rs:29:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
= note: can only be called if the required target features are available
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:30:5
+ --> $DIR/safe-calls.rs:36:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
= note: can only be called if the required target features are available
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:31:5
+ --> $DIR/safe-calls.rs:39:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
= note: can only be called if the required target features are available
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:36:5
+ --> $DIR/safe-calls.rs:46:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
= note: can only be called if the required target features are available
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:37:5
+ --> $DIR/safe-calls.rs:49:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
= note: can only be called if the required target features are available
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:38:5
+ --> $DIR/safe-calls.rs:52:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
= note: can only be called if the required target features are available
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:44:5
+ --> $DIR/safe-calls.rs:60:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
= note: can only be called if the required target features are available
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:47:18
+ --> $DIR/safe-calls.rs:65:18
|
LL | const name: () = sse2();
| ^^^^^^ call to function with `#[target_feature]`
}
fn foo() {
- sse2(); //~ ERROR call to function with `#[target_feature]` is unsafe
- avx_bmi2(); //~ ERROR call to function with `#[target_feature]` is unsafe
- Quux.avx_bmi2(); //~ ERROR call to function with `#[target_feature]` is unsafe
+ sse2();
+ //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+ //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
+ avx_bmi2();
+ //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+ //[thir]~^^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
+ Quux.avx_bmi2();
+ //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+ //[thir]~^^ ERROR call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe
}
#[target_feature(enable = "sse2")]
fn bar() {
- avx_bmi2(); //~ ERROR call to function with `#[target_feature]` is unsafe
- Quux.avx_bmi2(); //~ ERROR call to function with `#[target_feature]` is unsafe
+ avx_bmi2();
+ //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+ //[thir]~^^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
+ Quux.avx_bmi2();
+ //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+ //[thir]~^^ ERROR call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe
}
#[target_feature(enable = "avx")]
fn baz() {
- sse2(); //~ ERROR call to function with `#[target_feature]` is unsafe
- avx_bmi2(); //~ ERROR call to function with `#[target_feature]` is unsafe
- Quux.avx_bmi2(); //~ ERROR call to function with `#[target_feature]` is unsafe
+ sse2();
+ //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+ //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
+ avx_bmi2();
+ //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+ //[thir]~^^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
+ Quux.avx_bmi2();
+ //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+ //[thir]~^^ ERROR call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe
}
#[target_feature(enable = "avx")]
#[target_feature(enable = "bmi2")]
fn qux() {
- sse2(); //~ ERROR call to function with `#[target_feature]` is unsafe
+ sse2();
+ //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+ //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
}
-const name: () = sse2(); //~ ERROR call to function with `#[target_feature]` is unsafe
+const name: () = sse2();
+//[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+//[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
fn main() {}
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:23:5
|
LL | sse2();
|
= note: can only be called if the required target features are available
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:24:5
+error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
+ --> $DIR/safe-calls.rs:26:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:25:5
+error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
+ --> $DIR/safe-calls.rs:29:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:30:5
+error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
+ --> $DIR/safe-calls.rs:36:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:31:5
+error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
+ --> $DIR/safe-calls.rs:39:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:36:5
+error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
+ --> $DIR/safe-calls.rs:46:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:37:5
+error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
+ --> $DIR/safe-calls.rs:49:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:38:5
+error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
+ --> $DIR/safe-calls.rs:52:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:44:5
+error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
+ --> $DIR/safe-calls.rs:60:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:47:18
+error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
+ --> $DIR/safe-calls.rs:65:18
|
LL | const name: () = sse2();
| ^^^^^^ call to function with `#[target_feature]`
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
--- /dev/null
+struct Kind;
+
+struct Ty {
+ kind: Kind,
+}
+
+impl Ty {
+ fn kind(&self) -> Kind {
+ todo!()
+ }
+}
+
+struct InferOk<T> {
+ value: T,
+ predicates: Vec<()>,
+}
+
+fn foo(i: InferOk<Ty>) {
+ let k = i.kind();
+ //~^ no method named `kind` found for struct `InferOk` in the current scope
+}
+
+fn main() {}
--- /dev/null
+error[E0599]: no method named `kind` found for struct `InferOk` in the current scope
+ --> $DIR/field-has-method.rs:19:15
+ |
+LL | struct InferOk<T> {
+ | ----------------- method `kind` not found for this
+...
+LL | let k = i.kind();
+ | ^^^^ method not found in `InferOk<Ty>`
+ |
+help: one of the expressions' fields has a method of the same name
+ |
+LL | let k = i.value.kind();
+ | ++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
|
LL | struct S<T>(T);
| ^^^^^^^^^^^^^^^ must implement `PartialEq<_>`
- = note: the trait `std::cmp::PartialEq` is not implemented for `S<T>`
help: consider annotating `S<T>` with `#[derive(PartialEq)]`
|
LL | #[derive(PartialEq)]
|
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+ |
+LL | pub fn foo<T>(s: S<T>, t: S<T>) where S<T>: PartialEq {
+ | +++++++++++++++++++++
error: aborting due to previous error
--- /dev/null
+fn main() {
+ let items = vec![1, 2, 3];
+ let ref_items: &[i32] = &items;
+ let items_clone: Vec<i32> = ref_items.clone();
+//~^ ERROR mismatched types
+
+ // in that case no suggestion will be triggered
+ let items_clone_2:Vec<i32> = items.clone();
+
+ let s = "hi";
+ let string: String = s.clone();
+//~^ ERROR mismatched types
+
+ // in that case no suggestion will be triggered
+ let s2 = "hi";
+ let string_2: String = s2.to_string();
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-53692.rs:4:37
+ |
+LL | let items_clone: Vec<i32> = ref_items.clone();
+ | -------- ^^^^^^^^^^^^^^^^^
+ | | |
+ | | expected struct `Vec`, found `&[i32]`
+ | | help: try using a conversion method: `ref_items.to_vec()`
+ | expected due to this
+ |
+ = note: expected struct `Vec<i32>`
+ found reference `&[i32]`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-53692.rs:11:30
+ |
+LL | let string: String = s.clone();
+ | ------ ^^^^^^^^^
+ | | |
+ | | expected struct `String`, found `&str`
+ | | help: try using a conversion method: `s.to_string()`
+ | expected due to this
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
error[E0311]: the parameter type `T` may not live long enough
--> $DIR/missing-lifetimes-in-signature-2.rs:20:5
|
+LL | fn func<T: Test>(foo: &Foo, t: T) {
+ | -- help: consider adding an explicit lifetime bound...: `T: 'a +`
LL | / foo.bar(move |_| {
LL | |
LL | | t.test();
|
LL | fn func<T: Test>(foo: &Foo, t: T) {
| ^^^
+note: ...so that the type `T` will meet its required lifetime bounds
+ --> $DIR/missing-lifetimes-in-signature-2.rs:20:5
+ |
+LL | / foo.bar(move |_| {
+LL | |
+LL | | t.test();
+LL | | });
+ | |______^
error: aborting due to previous error
error[E0311]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:32:5
|
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | - help: consider adding an explicit lifetime bound...: `G: 'a`
+...
LL | / move || {
LL | | *dest = g.get();
LL | | }
|
LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
| ^^^^^^
+note: ...so that the type `G` will meet its required lifetime bounds
+ --> $DIR/missing-lifetimes-in-signature.rs:32:5
+ |
+LL | / move || {
+LL | | *dest = g.get();
+LL | | }
+ | |_____^
error[E0311]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:55:5
|
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+ | -- help: consider adding an explicit lifetime bound...: `G: 'b +`
+...
LL | / move || {
LL | | *dest = g.get();
LL | | }
|
LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
| ^^^^^^
+note: ...so that the type `G` will meet its required lifetime bounds
+ --> $DIR/missing-lifetimes-in-signature.rs:55:5
+ |
+LL | / move || {
+LL | | *dest = g.get();
+LL | | }
+ | |_____^
error[E0311]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:65:9
|
+LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+ | -- help: consider adding an explicit lifetime bound...: `G: 'c +`
+...
LL | / move || {
LL | | *dest = g.get();
LL | | }
|
LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
| ^^^^^^
+note: ...so that the type `G` will meet its required lifetime bounds
+ --> $DIR/missing-lifetimes-in-signature.rs:65:9
+ |
+LL | / move || {
+LL | | *dest = g.get();
+LL | | }
+ | |_________^
error[E0311]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:77:5
|
+LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+ | -- help: consider adding an explicit lifetime bound...: `G: 'b +`
+...
LL | / move || {
LL | | *dest = g.get();
LL | | }
|
LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
| ^^^^^^
+note: ...so that the type `G` will meet its required lifetime bounds
+ --> $DIR/missing-lifetimes-in-signature.rs:77:5
+ |
+LL | / move || {
+LL | | *dest = g.get();
+LL | | }
+ | |_____^
error[E0621]: explicit lifetime required in the type of `dest`
--> $DIR/missing-lifetimes-in-signature.rs:77:5
error[E0309]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:89:5
|
+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 | / move || {
LL | | *dest = g.get();
LL | | }
- | |_____^
- |
- = help: consider adding an explicit lifetime bound `G: 'a`...
+ | |_____^ ...so that the type `G` will meet its required lifetime bounds
error: aborting due to 8 previous errors
LL | | }
| |_________^ returning this value requires that `'1` must outlive `'static`
|
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
|
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
| ++++
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> {
+ | ++++
error: lifetime may not live long enough
--> $DIR/trait-object-nested-in-impl-trait.rs:39:9
LL | | remaining: self.0.iter(),
LL | | }
| |_________^ returning this value requires that `'1` must outlive `'static`
+ |
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> + '_ {
+ | ++++
error: lifetime may not live long enough
--> $DIR/trait-object-nested-in-impl-trait.rs:50:9
LL | | remaining: self.0.iter(),
LL | | }
| |_________^ returning this value requires that `'a` must outlive `'static`
+ |
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
+ |
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> + 'a {
+ | ++++
error: lifetime may not live long enough
--> $DIR/trait-object-nested-in-impl-trait.rs:61:9
LL | | }
| |_________^ returning this value requires that `'a` must outlive `'static`
|
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
|
LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
| ++++
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
+ |
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> {
+ | ++++
error: aborting due to 4 previous errors
--- /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`.
error[E0310]: the parameter type `impl Debug` may not live long enough
--> $DIR/suggest-impl-trait-lifetime.rs:7:5
|
+LL | fn foo(d: impl Debug) {
+ | ---------- help: consider adding an explicit lifetime bound...: `impl Debug + 'static`
+LL |
LL | bar(d);
- | ^^^^^^
- |
- = help: consider adding an explicit lifetime bound `impl Debug: 'static`...
+ | ^^^^^^ ...so that the type `impl Debug` will meet its required lifetime bounds
error: aborting due to previous error
--> $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
--- /dev/null
+// run-pass
+// ignore-emscripten no threads support
+
+use std::thread;
+
+struct Foo;
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("test2");
+ }
+}
+
+thread_local!(static FOO: Foo = Foo);
+
+fn main() {
+ // Off the main thread due to #28129, be sure to initialize FOO first before
+ // calling `println!`
+ thread::spawn(|| {
+ FOO.with(|_| {});
+ println!("test1");
+ }).join().unwrap();
+}
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/issue-43733.rs:19:5
+ --> $DIR/issue-43733.rs:21:5
|
LL | __KEY.get(Default::default)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/issue-43733.rs:22:42
+ --> $DIR/issue-43733.rs:26:42
|
LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
// revisions: mir thir
// [thir]compile-flags: -Z thir-unsafeck
+// normalize-stderr-test: "__FastLocalKeyInner::<T>::get" -> "$$LOCALKEYINNER::<T>::get"
+// normalize-stderr-test: "__OsLocalKeyInner::<T>::get" -> "$$LOCALKEYINNER::<T>::get"
#![feature(thread_local)]
#![feature(cfg_target_thread_local, thread_local_internals)]
static __KEY: std::thread::__OsLocalKeyInner<Foo> = std::thread::__OsLocalKeyInner::new();
fn __getit(_: Option<&mut Option<RefCell<String>>>) -> std::option::Option<&'static Foo> {
- __KEY.get(Default::default) //~ ERROR call to unsafe function is unsafe
+ __KEY.get(Default::default)
+ //[mir]~^ ERROR call to unsafe function is unsafe
+ //[thir]~^^ ERROR call to unsafe function `__
}
static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
-//~^ ERROR call to unsafe function is unsafe
+//[mir]~^ ERROR call to unsafe function is unsafe
+//[thir]~^^ ERROR call to unsafe function `LocalKey::<T>::new`
fn main() {
FOO.with(|foo| println!("{}", foo.borrow()));
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/issue-43733.rs:19:5
+error[E0133]: call to unsafe function `$LOCALKEYINNER::<T>::get` is unsafe and requires unsafe function or block
+ --> $DIR/issue-43733.rs:21:5
|
LL | __KEY.get(Default::default)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/issue-43733.rs:22:42
+error[E0133]: call to unsafe function `LocalKey::<T>::new` is unsafe and requires unsafe function or block
+ --> $DIR/issue-43733.rs:26:42
|
LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
--- /dev/null
+// run-pass
+#![allow(unused)]
+
+fn main() {
+}
+
+fn foo() {
+ let b = mk::<
+ Forward<(Box<dyn Future<Error = u32>>,)>,
+ >();
+ b.map_err(|_| ()).join();
+}
+
+fn mk<T>() -> T {
+ loop {}
+}
+
+impl<I: Future<Error = E>, E> Future for (I,) {
+ type Error = E;
+}
+
+struct Forward<T: Future> {
+ _a: T,
+}
+
+impl<T: Future> Future for Forward<T>
+where
+ T::Error: From<u32>,
+{
+ type Error = T::Error;
+}
+
+trait Future {
+ type Error;
+
+ fn map_err<F, E>(self, _: F) -> (Self, F)
+ where
+ F: FnOnce(Self::Error) -> E,
+ Self: Sized,
+ {
+ loop {}
+ }
+
+ fn join(self) -> (MaybeDone<Self>, ())
+ where
+ Self: Sized,
+ {
+ loop {}
+ }
+}
+
+impl<S: ?Sized + Future> Future for Box<S> {
+ type Error = S::Error;
+}
+
+enum MaybeDone<A: Future> {
+ _Done(A::Error),
+}
+
+impl<U, A: Future, F> Future for (A, F)
+where
+ F: FnOnce(A::Error) -> U,
+{
+ type Error = U;
+}
--- /dev/null
+#![feature(unsize, dispatch_from_dyn)]
+
+use std::marker::Unsize;
+use std::ops::DispatchFromDyn;
+
+#[allow(unused)]
+struct Foo<'a, T: ?Sized> {
+ _inner: &'a &'a T,
+}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {}
+//~^ ERROR the trait bound `&'a T: Unsize<&'a U>` is not satisfied
+//~| NOTE the trait `Unsize<&'a U>` is not implemented for `&'a T`
+//~| NOTE all implementations of `Unsize` are provided automatically by the compiler
+//~| NOTE required because of the requirements on the impl
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `&'a T: Unsize<&'a U>` is not satisfied
+ --> $DIR/issue-71036.rs:11:1
+ |
+LL | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T`
+ |
+ = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
+ = note: required because of the requirements on the impl of `DispatchFromDyn<&'a &'a U>` for `&'a &'a T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
| |
| &T
|
-help: consider further restricting this bound
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
-LL | fn foo<T: MyMul<f64, f64> + std::ops::Mul<Output = f64>>(a: &T, b: f64) -> f64 {
- | +++++++++++++++++++++++++++++
+LL | fn foo<T: MyMul<f64, f64>>(a: &T, b: f64) -> f64 where &T: Mul<f64> {
+ | ++++++++++++++++++
error: aborting due to previous error
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/generic_type_does_not_live_long_enough.rs:18:5
|
+LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
LL | t
- | ^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
+ | ^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to 3 previous errors
trait Animal { }
fn main() {
- pub type ServeFut = /*impl Trait*/;
+ type ServeFut = /*impl Trait*/;
}
|
help: consider restricting type parameter `T`
|
-LL | fn foo<T: std::ops::Add<Output = T>>(x: T, y: T) {
- | +++++++++++++++++++++++++++
+LL | fn foo<T: std::ops::Add>(x: T, y: T) {
+ | +++++++++++++++
error[E0368]: binary assignment operation `+=` cannot be applied to type `T`
--> $DIR/missing_trait_impl.rs:9:5
|
help: consider restricting type parameter `T`
|
-LL | fn baz<T: std::ops::Neg<Output = T>>(x: T) {
- | +++++++++++++++++++++++++++
+LL | fn baz<T: std::ops::Neg>(x: T) {
+ | +++++++++++++++
error[E0600]: cannot apply unary operator `!` to type `T`
--> $DIR/missing_trait_impl.rs:14:13
|
help: consider restricting type parameter `T`
|
-LL | fn baz<T: std::ops::Not<Output = T>>(x: T) {
- | +++++++++++++++++++++++++++
+LL | fn baz<T: std::ops::Not>(x: T) {
+ | +++++++++++++++
error[E0614]: type `T` cannot be dereferenced
--> $DIR/missing_trait_impl.rs:15:13
--- /dev/null
+struct Bar<T> {
+ bar: T
+}
+
+struct Foo();
+impl Foo {
+ fn foo() { }
+}
+
+fn main() {
+ let thing = Bar { bar: Foo };
+ thing.bar.foo();
+ //~^ ERROR no method named `foo` found for fn item `fn() -> Foo {Foo}` in the current scope [E0599]
+}
--- /dev/null
+error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo}` in the current scope
+ --> $DIR/empty-tuple-method.rs:12:15
+ |
+LL | thing.bar.foo();
+ | --------- ^^^ method not found in `fn() -> Foo {Foo}`
+ | |
+ | this is the constructor of a struct
+ |
+help: call the constructor
+ |
+LL | (thing.bar)().foo();
+ | + +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
--- /dev/null
+struct Bar<T> {
+ bar: T
+}
+
+enum Foo{
+ Tup()
+}
+impl Foo {
+ fn foo() { }
+}
+
+fn main() {
+ let thing = Bar { bar: Foo::Tup };
+ thing.bar.foo();
+ //~^ ERROR no method named `foo` found for fn item `fn() -> Foo {Foo::Tup}` in the current scope [E0599]
+}
--- /dev/null
+error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo::Tup}` in the current scope
+ --> $DIR/enum-variant.rs:14:15
+ |
+LL | thing.bar.foo();
+ | --------- ^^^ method not found in `fn() -> Foo {Foo::Tup}`
+ | |
+ | this is the constructor of an enum variant
+ |
+help: call the constructor
+ |
+LL | (thing.bar)().foo();
+ | + +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
--- /dev/null
+struct Bar<T> {
+ bar: T
+}
+
+struct Foo(char, u16);
+impl Foo {
+ fn foo() { }
+}
+
+fn main() {
+ let thing = Bar { bar: Foo };
+ thing.bar.0;
+ //~^ ERROR no field `0` on type `fn(char, u16) -> Foo {Foo}` [E0609]
+}
--- /dev/null
+error[E0609]: no field `0` on type `fn(char, u16) -> Foo {Foo}`
+ --> $DIR/tuple-field.rs:12:15
+ |
+LL | thing.bar.0;
+ | --------- ^
+ | |
+ | this is the constructor of a struct
+ |
+help: call the constructor
+ |
+LL | (thing.bar)(_, _).0;
+ | + +++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0609`.
--- /dev/null
+struct Bar<T> {
+ bar: T
+}
+
+struct Foo(u8, i32);
+impl Foo {
+ fn foo() { }
+}
+
+fn main() {
+ let thing = Bar { bar: Foo };
+ thing.bar.foo();
+ //~^ ERROR no method named `foo` found for fn item `fn(u8, i32) -> Foo {Foo}` in the current scope [E0599]
+}
--- /dev/null
+error[E0599]: no method named `foo` found for fn item `fn(u8, i32) -> Foo {Foo}` in the current scope
+ --> $DIR/tuple-method.rs:12:15
+ |
+LL | thing.bar.foo();
+ | --------- ^^^ method not found in `fn(u8, i32) -> Foo {Foo}`
+ | |
+ | this is the constructor of a struct
+ |
+help: call the constructor
+ |
+LL | (thing.bar)(_, _).foo();
+ | + +++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
LL | impl DefaultedTrait for Box<C> { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait for type in another crate
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
--> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:22:1
|
LL | impl DefaultedTrait for lib::Something<C> { }
impl Clone for Test9 {
fn clone(&self) -> _ { Test9 }
- //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
fn clone_from(&mut self, other: _) { *self = Test9; }
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
impl Clone for FnTest9 {
fn clone(&self) -> _ { FnTest9 }
- //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
fn clone_from(&mut self, other: _) { *self = FnTest9; }
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
LL | fn test10<T>(&self, _x : T) { }
| +++ ~
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/typeck_type_placeholder_item.rs:59:24
|
LL | fn clone(&self) -> _ { Test9 }
- | ^
- | |
- | not allowed in type signatures
- | help: replace with the correct return type: `Test9`
+ | ^ not allowed in type signatures
+ |
+help: try replacing `_` with the type in the corresponding trait method signature
+ |
+LL | fn clone(&self) -> Test9 { Test9 }
+ | ~~~~~
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/typeck_type_placeholder_item.rs:62:37
LL | fn clone_from(&mut self, other: _) { *self = Test9; }
| ^ not allowed in type signatures
|
-help: use type parameters instead
+help: try replacing `_` with the type in the corresponding trait method signature
|
-LL | fn clone_from<T>(&mut self, other: T) { *self = Test9; }
- | +++ ~
+LL | fn clone_from(&mut self, other: &Test9) { *self = Test9; }
+ | ~~~~~~
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
--> $DIR/typeck_type_placeholder_item.rs:107:31
LL | fn fn_test10<T>(&self, _x : T) { }
| +++ ~
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/typeck_type_placeholder_item.rs:115:28
|
LL | fn clone(&self) -> _ { FnTest9 }
- | ^
- | |
- | not allowed in type signatures
- | help: replace with the correct return type: `FnTest9`
+ | ^ not allowed in type signatures
+ |
+help: try replacing `_` with the type in the corresponding trait method signature
+ |
+LL | fn clone(&self) -> FnTest9 { FnTest9 }
+ | ~~~~~~~
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/typeck_type_placeholder_item.rs:118:41
LL | fn clone_from(&mut self, other: _) { *self = FnTest9; }
| ^ not allowed in type signatures
|
-help: use type parameters instead
+help: try replacing `_` with the type in the corresponding trait method signature
|
-LL | fn clone_from<T>(&mut self, other: T) { *self = FnTest9; }
- | +++ ~
+LL | fn clone_from(&mut self, other: &FnTest9) { *self = FnTest9; }
+ | ~~~~~~~~
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
--> $DIR/typeck_type_placeholder_item.rs:201:14
--> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10
|
LL | mut_.call((0, ));
- | ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]`
- |
- = note: `mut_` is a function, perhaps you wish to call it
+ | ---- ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]`
+ | |
+ | this is a function, perhaps you wish to call it
error: aborting due to previous error
LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
LL | Box::new(items.iter())
| ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+ |
+help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T> + '_> {
+ | ++++
error: aborting due to previous error
--- /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`.
= note: consult the function's documentation for information on how to avoid undefined behavior
error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:15:5
|
LL | *PTR;
| ^^^^ 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: use of mutable static is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:17:5
|
LL | VOID = ();
| ^^^^^^^^^ use of mutable static
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:5
|
LL | unsafe {}
| ^^^^^^ unnecessary `unsafe` block
| ^^^^^^^^^^^^^
error: call to unsafe function is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5
|
LL | unsf();
| ^^^^^^ call to unsafe function
|
note: the lint level is defined here
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:8
|
LL | #[deny(warnings)]
| ^^^^^^^^
= note: consult the function's documentation for information on how to avoid undefined behavior
error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
|
LL | *PTR;
| ^^^^ 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: use of mutable static is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
|
LL | VOID = ();
| ^^^^^^^^^ use of mutable static
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:35:5
|
LL | unsafe {}
| ^^^^^^ unnecessary `unsafe` block
error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:49:5
|
LL | unsafe { unsafe { unsf() } }
| ^^^^^^ unnecessary `unsafe` block
error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:60:5
|
LL | unsafe fn allow_level() {
| ----------------------- because it's nested under this `unsafe` fn
|
= note: this `unsafe` block does contain unsafe operations, but those are already allowed in an `unsafe fn`
note: the lint level is defined here
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:51:9
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:53:9
|
LL | #[allow(unsafe_op_in_unsafe_fn)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:72:9
|
LL | unsafe fn nested_allow_level() {
| ------------------------------ because it's nested under this `unsafe` fn
|
= note: this `unsafe` block does contain unsafe operations, but those are already allowed in an `unsafe fn`
note: the lint level is defined here
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:63:13
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:65:13
|
LL | #[allow(unsafe_op_in_unsafe_fn)]
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0133]: call to unsafe function is unsafe and requires unsafe block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:78:5
|
LL | unsf();
| ^^^^^^ call to unsafe function
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:83:9
|
LL | unsf();
| ^^^^^^ call to unsafe function
unsafe fn deny_level() {
unsf();
- //~^ ERROR call to unsafe function is unsafe and requires unsafe block
+ //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe block
+ //[thir]~^^ ERROR call to unsafe function `unsf` is unsafe and requires unsafe block
*PTR;
//~^ ERROR dereference of raw pointer is unsafe and requires unsafe block
VOID = ();
#[deny(warnings)]
unsafe fn warning_level() {
unsf();
- //~^ ERROR call to unsafe function is unsafe and requires unsafe block
+ //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe block
+ //[thir]~^^ ERROR call to unsafe function `unsf` is unsafe and requires unsafe block
*PTR;
//~^ ERROR dereference of raw pointer is unsafe and requires unsafe block
VOID = ();
fn main() {
unsf();
- //~^ ERROR call to unsafe function is unsafe and requires unsafe block
+ //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe block
+ //[thir]~^^ ERROR call to unsafe function `unsf` is unsafe and requires unsafe block
#[allow(unsafe_op_in_unsafe_fn)]
{
unsf();
- //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+ //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+ //[thir]~^^ ERROR call to unsafe function `unsf` is unsafe and requires unsafe function or block
}
}
-error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+error: call to unsafe function `unsf` is unsafe and requires unsafe block (error E0133)
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
|
LL | unsf();
= note: consult the function's documentation for information on how to avoid undefined behavior
error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:15:5
|
LL | *PTR;
| ^^^^ 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: use of mutable static is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:17:5
|
LL | VOID = ();
| ^^^^ use of mutable static
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:5
|
LL | unsafe {}
| ^^^^^^ unnecessary `unsafe` block
LL | #![deny(unused_unsafe)]
| ^^^^^^^^^^^^^
-error: call to unsafe function is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
+error: call to unsafe function `unsf` is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5
|
LL | unsf();
| ^^^^^^ call to unsafe function
|
note: the lint level is defined here
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:8
|
LL | #[deny(warnings)]
| ^^^^^^^^
= note: consult the function's documentation for information on how to avoid undefined behavior
error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
|
LL | *PTR;
| ^^^^ 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: use of mutable static is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
|
LL | VOID = ();
| ^^^^ use of mutable static
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:35:5
|
LL | unsafe {}
| ^^^^^^ unnecessary `unsafe` block
error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:49:14
|
LL | unsafe { unsafe { unsf() } }
| ------ ^^^^^^ unnecessary `unsafe` block
| because it's nested under this `unsafe` block
error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:60:5
|
LL | unsafe fn allow_level() {
| ----------------------- because it's nested under this `unsafe` fn
| ^^^^^^ unnecessary `unsafe` block
error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:72:9
|
LL | unsafe fn nested_allow_level() {
| ------------------------------ because it's nested under this `unsafe` fn
LL | unsafe { unsf() }
| ^^^^^^ unnecessary `unsafe` block
-error[E0133]: call to unsafe function is unsafe and requires unsafe block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
+error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:78:5
|
LL | unsf();
| ^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9
+error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe function or block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:83:9
|
LL | unsf();
| ^^^^^^ call to unsafe function
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `dummy` is unsafe and requires unsafe function or block
--> $DIR/unsafe-const-fn.rs:10:18
|
LL | const VAL: u32 = dummy(0xFFFF);
unsafe fn f() { return; }
fn main() {
- f(); //~ ERROR call to unsafe function is unsafe
+ f();
+ //[mir]~^ ERROR call to unsafe function is unsafe
+ //[thir]~^^ ERROR call to unsafe function `f` is unsafe
}
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
--> $DIR/unsafe-fn-called-from-safe.rs:7:5
|
LL | f();
fn main() {
let x = f;
- x(); //~ ERROR call to unsafe function is unsafe
+ x();
+ //[mir]~^ ERROR call to unsafe function is unsafe
+ //[thir]~^^ ERROR call to unsafe function `f` is unsafe
}
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
--> $DIR/unsafe-fn-used-as-value.rs:8:5
|
LL | x();
+++ /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
-Subproject commit dba5baf4345858c591517b24801902a062c399f8
+Subproject commit edffc4ada3d77799e5a04eeafd9b2f843d29fc23
if rust_cc > self.limit.limit() {
let fn_span = match kind {
- FnKind::ItemFn(ident, _, _, _) | FnKind::Method(ident, _, _) => ident.span,
+ FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span,
FnKind::Closure => {
let header_span = body_span.with_hi(decl.output.span().lo());
let pos = snippet_opt(cx, header_span).and_then(|snip| {
}
// The `module_name_repetitions` lint should only trigger if the item has the module in its
// name. Having the same name is accepted.
- if item.vis.node.is_pub() && item_camel.len() > mod_camel.len() {
+ if cx.tcx.visibility(item.def_id).is_public() && item_camel.len() > mod_camel.len() {
let matching = count_match_start(mod_camel, &item_camel);
let rmatching = count_match_end(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();
if !attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
then {
let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
- if v.fields().iter().any(|f| !f.vis.node.is_pub()) {
+ if v.fields().iter().any(|f| {
+ let def_id = cx.tcx.hir().local_def_id(f.hir_id);
+ !cx.tcx.visibility(def_id).is_public()
+ }) {
// skip structs with private fields
return;
}
hir_id: hir::HirId,
) {
let unsafety = match kind {
- intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }, _) => unsafety,
- intravisit::FnKind::Method(_, sig, _) => sig.header.unsafety,
+ intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }) => unsafety,
+ intravisit::FnKind::Method(_, sig) => sig.header.unsafety,
intravisit::FnKind::Closure => return,
};
header: hir::FnHeader { abi: Abi::Rust, .. },
..
},
- _,
)
- | intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _) => check_arg_number(
+ | intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }) => check_arg_number(
cx,
decl,
span.with_hi(decl.output.span().hi()),
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;
}
}
}
match kind {
- FnKind::ItemFn(.., header, _) => {
+ FnKind::ItemFn(.., header) => {
let attrs = cx.tcx.hir().attrs(hir_id);
if header.abi != Abi::Rust || requires_exact_signature(attrs) {
return;
}
match kind {
- FnKind::ItemFn(.., header, _) => {
+ FnKind::ItemFn(.., header) => {
if header.abi != Abi::Rust {
return;
}
use clippy_utils::diagnostics::span_lint_and_then;
use rustc_errors::Applicability;
-use rustc_hir::{Item, ItemKind, VisibilityKind};
+use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::CRATE_DEF_ID;
declare_clippy_lint! {
/// ### What it does
impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
- if let VisibilityKind::Crate { .. } = item.vis.node {
+ if cx.tcx.visibility(item.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()) {
if !cx.access_levels.is_exported(item.def_id) && self.is_exported.last() == Some(&false) {
let span = item.span.with_hi(item.ident.span.hi());
let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id());
&format!("pub(crate) {} inside private module", descr),
|diag| {
diag.span_suggestion(
- item.vis.span,
+ item.vis_span,
"consider using",
"pub".to_string(),
Applicability::MachineApplicable,
) {
if_chain! {
// We are only interested in methods, not in functions or associated functions.
- if matches!(kind, FnKind::Method(_, _, _));
+ if matches!(kind, FnKind::Method(_, _));
if let Some(fn_def) = cx.tcx.hir().opt_local_def_id(hir_id);
if let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id());
// We don't want this method to be te implementation of a trait because the
span: Span,
hir_id: HirId,
) {
- if let FnKind::ItemFn(_, _, FnHeader { asyncness, .. }, _) = &fn_kind {
+ if let FnKind::ItemFn(_, _, FnHeader { asyncness, .. }) = &fn_kind {
if matches!(asyncness, IsAsync::Async) {
let mut visitor = AsyncFnVisitor { cx, found_await: false };
walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), span, hir_id);
use rustc_ast::ast::{Attribute, InlineAsmTemplatePiece};
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty;
use rustc_session::Session;
use rustc_session::{declare_lint_pass, declare_tool_lint};
return;
}
println!("impl item `{}`", item.ident.name);
- match item.vis.node {
- hir::VisibilityKind::Public => println!("public"),
- hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
- hir::VisibilityKind::Restricted { path, .. } => println!(
- "visible in module `{}`",
- rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false))
- ),
- hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
+ match cx.tcx.visibility(item.def_id) {
+ ty::Visibility::Public => println!("public"),
+ ty::Visibility::Restricted(def_id) => {
+ if def_id.is_top_level_module() {
+ println!("visible crate wide")
+ } else {
+ println!("visible in module `{}`", cx.tcx.def_path_str(def_id))
+ }
+ },
+ ty::Visibility::Invisible => println!("invisible"),
}
match item.kind {
hir::ImplItemKind::Const(_, body_id) => {
fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
let did = item.def_id;
println!("item `{}`", item.ident.name);
- match item.vis.node {
- hir::VisibilityKind::Public => println!("public"),
- hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
- hir::VisibilityKind::Restricted { path, .. } => println!(
- "visible in module `{}`",
- rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false))
- ),
- hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
+ match cx.tcx.visibility(item.def_id) {
+ ty::Visibility::Public => println!("public"),
+ ty::Visibility::Restricted(def_id) => {
+ if def_id.is_top_level_module() {
+ println!("visible crate wide")
+ } else {
+ println!("visible in module `{}`", cx.tcx.def_path_str(def_id))
+ }
+ },
+ ty::Visibility::Invisible => println!("invisible"),
}
match item.kind {
hir::ItemKind::ExternCrate(ref _renamed_from) => {
Item, ItemKind, PathSegment, UseKind,
};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::kw;
use rustc_span::{sym, BytePos};
if is_test_module_or_function(cx.tcx, item) {
self.test_modules_deep = self.test_modules_deep.saturating_add(1);
}
- if item.vis.node.is_pub() || item.vis.node.is_pub_restricted() {
+ let module = cx.tcx.parent_module_from_def_id(item.def_id);
+ if cx.tcx.visibility(item.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
return;
}
if_chain! {
/// Checks if the given function kind is an async function.
pub fn is_async_fn(kind: FnKind<'_>) -> bool {
- matches!(kind, FnKind::ItemFn(_, _, header, _) if header.asyncness == IsAsync::Async)
+ matches!(kind, FnKind::ItemFn(_, _, header) if header.asyncness == IsAsync::Async)
}
/// Peels away all the compiler generated code surrounding the body of an async function,
/// The rust-demangler executable.
pub rust_demangler_path: Option<PathBuf>,
- /// The Python executable to use for LLDB.
- pub lldb_python: String,
-
- /// The Python executable to use for htmldocck.
- pub docck_python: String,
+ /// The Python executable to use for LLDB and htmldocck.
+ pub python: String,
/// The jsondocck executable.
pub jsondocck_path: Option<String>,
pub should_ice: bool,
// If true, the stderr is expected to be different across bit-widths.
pub stderr_per_bitwidth: bool,
+ // The MIR opt to unit test, if any
+ pub mir_unit_test: Option<String>,
}
mod directives {
pub const STDERR_PER_BITWIDTH: &'static str = "stderr-per-bitwidth";
pub const INCREMENTAL: &'static str = "incremental";
pub const KNOWN_BUG: &'static str = "known-bug";
+ pub const MIR_UNIT_TEST: &'static str = "unit-test";
// This isn't a real directive, just one that is probably mistyped often
pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags";
}
assembly_output: None,
should_ice: false,
stderr_per_bitwidth: false,
+ mir_unit_test: None,
}
}
config.set_name_directive(ln, STDERR_PER_BITWIDTH, &mut self.stderr_per_bitwidth);
config.set_name_directive(ln, INCREMENTAL, &mut self.incremental);
config.set_name_directive(ln, KNOWN_BUG, &mut self.known_bug);
+ config.set_name_value_directive(ln, MIR_UNIT_TEST, &mut self.mir_unit_test, |s| {
+ s.trim().to_string()
+ });
});
}
"--compile-lib-path=",
"--run-lib-path=",
"--rustc-path=",
- "--lldb-python=",
- "--docck-python=",
+ "--python=",
"--jsondocck-path=",
"--src-base=",
"--build-base=",
.reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH")
.optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH")
.optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH")
- .reqopt("", "lldb-python", "path to python to use for doc tests", "PATH")
- .reqopt("", "docck-python", "path to python to use for doc tests", "PATH")
+ .reqopt("", "python", "path to python to use for doc tests", "PATH")
.optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH")
.optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM")
.optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind")
rustc_path: opt_path(matches, "rustc-path"),
rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from),
rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from),
- lldb_python: matches.opt_str("lldb-python").unwrap(),
- docck_python: matches.opt_str("docck-python").unwrap(),
+ python: matches.opt_str("python").unwrap(),
jsondocck_path: matches.opt_str("jsondocck-path"),
valgrind_path: matches.opt_str("valgrind-path"),
force_valgrind: matches.opt_present("force-valgrind"),
}
Some(Debugger::Lldb) => {
- config.lldb_python.hash(&mut hash);
+ config.python.hash(&mut hash);
config.lldb_python_dir.hash(&mut hash);
env::var_os("PATH").hash(&mut hash);
env::var_os("PYTHONPATH").hash(&mut hash);
// Prepare the lldb_batchmode which executes the debugger script
let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
self.cmd2procres(
- Command::new(&self.config.lldb_python)
+ Command::new(&self.config.python)
.arg(&lldb_script_path)
.arg(test_executable)
.arg(debugger_script)
rustc.args(&[
"-Copt-level=1",
"-Zdump-mir=all",
- "-Zmir-opt-level=4",
"-Zvalidate-mir",
"-Zdump-mir-exclude-pass-number",
]);
+ if let Some(pass) = &self.props.mir_unit_test {
+ rustc.args(&["-Zmir-opt-level=0", &format!("-Zmir-enable-passes=+{}", pass)]);
+ } else {
+ rustc.arg("-Zmir-opt-level=4");
+ }
let mir_dump_dir = self.get_mir_dump_dir();
let _ = fs::remove_dir_all(&mir_dump_dir);
self.check_rustdoc_test_option(proc_res);
} else {
let root = self.config.find_rust_src_root().unwrap();
- let mut cmd = Command::new(&self.config.docck_python);
+ let mut cmd = Command::new(&self.config.python);
cmd.arg(root.join("src/etc/htmldocck.py")).arg(&out_dir).arg(&self.testpaths.file);
if self.config.bless {
cmd.arg("--bless");
let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap());
json_out.set_extension("json");
let res = self.cmd2procres(
- Command::new(&self.config.docck_python)
+ Command::new(&self.config.python)
.arg(root.join("src/etc/check_missing_items.py"))
.arg(&json_out),
);
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.env("TARGET", &self.config.target)
- .env("PYTHON", &self.config.docck_python)
+ .env("PYTHON", &self.config.python)
.env("S", src_root)
.env("RUST_BUILD_STAGE", &self.config.stage_id)
.env("RUSTC", cwd.join(&self.config.rustc_path))
-Subproject commit 1ef91e122775060acb1fbda2c9a366891af3ea89
+Subproject commit a71a0083937671d79e16bfac4c7b8cab9c8ab9bb
} 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] === '\\') {
}
// Stupid function extractor for array.
-function extractArrayVariable(content, arrayName) {
- var splitter = "var " + arrayName;
+function extractArrayVariable(content, arrayName, kind) {
+ if (typeof kind === "undefined") {
+ kind = "let ";
+ }
+ var splitter = kind + arrayName;
while (true) {
var start = content.indexOf(splitter);
if (start === -1) {
}
content = content.slice(start + 1);
}
+ if (kind === "let ") {
+ return extractArrayVariable(content, arrayName, "const ");
+ }
return null;
}
// Stupid function extractor for variable.
-function extractVariable(content, varName) {
- var splitter = "var " + varName;
+function extractVariable(content, varName, kind) {
+ if (typeof kind === "undefined") {
+ kind = "let ";
+ }
+ var splitter = kind + varName;
while (true) {
var start = content.indexOf(splitter);
if (start === -1) {
}
content = content.slice(start + 1);
}
+ if (kind === "let ") {
+ return extractVariable(content, varName, "const ");
+ }
return null;
}
// 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) {
("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)] = &[
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
const ROOT_ENTRY_LIMIT: usize = 986;
-const ISSUES_ENTRY_LIMIT: usize = 2310;
+const ISSUES_ENTRY_LIMIT: usize = 2292;
fn check_entries(path: &Path, bad: &mut bool) {
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))