[[package]]
name = "cargo"
-version = "0.52.0"
+version = "0.53.0"
dependencies = [
"anyhow",
"atty",
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct Crate {
- pub module: Mod,
pub attrs: Vec<Attribute>,
+ pub items: Vec<P<Item>>,
pub span: Span,
/// The order of items in the HIR is unrelated to the order of
/// items in the AST. However, we generate proc macro harnesses
}
}
-/// Module declaration.
-///
-/// E.g., `mod foo;` or `mod foo { .. }`.
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
+pub enum Inline {
+ Yes,
+ No,
+}
+
+/// Module item kind.
#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct Mod {
- /// A span from the first token past `{` to the last token until `}`.
- /// For `mod foo;`, the inner span ranges from the first token
- /// to the last token in the external file.
- pub inner: Span,
- /// `unsafe` keyword accepted syntactically for macro DSLs, but not
- /// semantically by Rust.
- pub unsafety: Unsafe,
- pub items: Vec<P<Item>>,
- /// `true` for `mod foo { .. }`; `false` for `mod foo;`.
- pub inline: bool,
+pub enum ModKind {
+ /// Module with inlined definition `mod foo { ... }`,
+ /// or with definition outlined to a separate file `mod foo;` and already loaded from it.
+ /// The inner span is from the first token past `{` to the last token until `}`,
+ /// or from the first to the last token in the loaded file.
+ Loaded(Vec<P<Item>>, Inline, Span),
+ /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
+ Unloaded,
}
/// Foreign module declaration.
/// A module declaration (`mod`).
///
/// E.g., `mod foo;` or `mod foo { .. }`.
- Mod(Mod),
+ /// `unsafe` keyword on modules is accepted syntactically for macro DSLs, but not
+ /// semantically by Rust.
+ Mod(Unsafe, ModKind),
/// An external module (`extern`).
///
/// E.g., `extern {}` or `extern "C" {}`.
noop_visit_ty_constraint(t, self);
}
- fn visit_mod(&mut self, m: &mut Mod) {
- noop_visit_mod(m, self);
- }
-
fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
noop_visit_foreign_mod(nm, self);
}
vis.visit_generics(generics);
visit_opt(body, |body| vis.visit_block(body));
}
- ItemKind::Mod(m) => vis.visit_mod(m),
+ ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
+ ModKind::Loaded(items, _inline, inner_span) => {
+ vis.visit_span(inner_span);
+ items.flat_map_in_place(|item| vis.flat_map_item(item));
+ }
+ ModKind::Unloaded => {}
+ },
ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
ItemKind::GlobalAsm(_ga) => {}
ItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
vis.visit_asyncness(asyncness);
}
-pub fn noop_visit_mod<T: MutVisitor>(module: &mut Mod, vis: &mut T) {
- let Mod { inner, unsafety: _, items, inline: _ } = module;
- vis.visit_span(inner);
- items.flat_map_in_place(|item| vis.flat_map_item(item));
-}
-
+// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible,
+// or make crate visiting first class if necessary.
pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
- visit_clobber(krate, |Crate { module, attrs, span, proc_macros }| {
+ visit_clobber(krate, |Crate { attrs, items, span, proc_macros }| {
let item_vis =
Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None };
let item = P(Item {
id: DUMMY_NODE_ID,
vis: item_vis,
span,
- kind: ItemKind::Mod(module),
+ kind: ItemKind::Mod(Unsafe::No, ModKind::Loaded(items, Inline::Yes, span)),
tokens: None,
});
let items = vis.flat_map_item(item);
let len = items.len();
if len == 0 {
- let module = Mod { inner: span, unsafety: Unsafe::No, items: vec![], inline: true };
- Crate { module, attrs: vec![], span, proc_macros }
+ Crate { attrs: vec![], items: vec![], span, proc_macros }
} else if len == 1 {
let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
match kind {
- ItemKind::Mod(module) => Crate { module, attrs, span, proc_macros },
+ ItemKind::Mod(_, ModKind::Loaded(items, ..)) => {
+ Crate { attrs, items, span, proc_macros }
+ }
_ => panic!("visitor converted a module to not a module"),
}
} else {
/// Each method of the `Visitor` trait is a hook to be potentially
/// overridden. Each method's default implementation recursively visits
/// the substructure of the input via the corresponding `walk` method;
-/// e.g., the `visit_mod` method by default calls `visit::walk_mod`.
+/// e.g., the `visit_item` method by default calls `visit::walk_item`.
///
/// If you want to ensure that your code handles every variant
/// explicitly, you need to override each method. (And you also need
fn visit_ident(&mut self, ident: Ident) {
walk_ident(self, ident);
}
- fn visit_mod(&mut self, m: &'ast Mod, _s: Span, _attrs: &[Attribute], _n: NodeId) {
- walk_mod(self, m);
- }
fn visit_foreign_item(&mut self, i: &'ast ForeignItem) {
walk_foreign_item(self, i)
}
}
pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) {
- visitor.visit_mod(&krate.module, krate.span, &krate.attrs, CRATE_NODE_ID);
+ walk_list!(visitor, visit_item, &krate.items);
walk_list!(visitor, visit_attribute, &krate.attrs);
}
-pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, module: &'a Mod) {
- walk_list!(visitor, visit_item, &module.items);
-}
-
pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) {
for attr in local.attrs.iter() {
visitor.visit_attribute(attr);
let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
visitor.visit_fn(kind, item.span, item.id)
}
- ItemKind::Mod(ref module) => visitor.visit_mod(module, item.span, &item.attrs, item.id),
+ ItemKind::Mod(_unsafety, ref mod_kind) => match mod_kind {
+ ModKind::Loaded(items, _inline, _inner_span) => {
+ walk_list!(visitor, visit_item, items)
+ }
+ ModKind::Unloaded => {}
+ },
ItemKind::ForeignMod(ref foreign_module) => {
walk_list!(visitor, visit_foreign_item, &foreign_module.items);
}
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
use rustc_target::spec::abi;
-
use smallvec::{smallvec, SmallVec};
-use std::collections::BTreeSet;
use tracing::debug;
+use std::mem;
+
pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>,
}
}
impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
- fn visit_mod(&mut self, m: &'a Mod, _s: Span, _attrs: &[Attribute], n: NodeId) {
- let def_id = self.lctx.lower_node_id(n).expect_owner();
-
- self.lctx.modules.insert(
- def_id,
- hir::ModuleItems {
- items: BTreeSet::new(),
- trait_items: BTreeSet::new(),
- impl_items: BTreeSet::new(),
- foreign_items: BTreeSet::new(),
- },
- );
-
- let old = self.lctx.current_module;
- self.lctx.current_module = def_id;
- visit::walk_mod(self, m);
- self.lctx.current_module = old;
- }
-
fn visit_item(&mut self, item: &'a Item) {
let mut item_hir_id = None;
self.lctx.with_hir_id_owner(item.id, |lctx| {
if let Some(hir_id) = item_hir_id {
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
let this = &mut ItemLowerer { lctx: this };
- if let ItemKind::Impl(box ImplKind { ref of_trait, .. }) = item.kind {
- this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
- } else {
- visit::walk_item(this, item);
+ match item.kind {
+ ItemKind::Mod(..) => {
+ let def_id = this.lctx.lower_node_id(item.id).expect_owner();
+ let old_current_module =
+ mem::replace(&mut this.lctx.current_module, def_id);
+ visit::walk_item(this, item);
+ this.lctx.current_module = old_current_module;
+ }
+ ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
+ this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
+ }
+ _ => visit::walk_item(this, item),
}
});
}
let hir_item = lctx.lower_trait_item(item);
let id = hir_item.trait_item_id();
lctx.trait_items.insert(id, hir_item);
- lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id);
+ lctx.modules.entry(lctx.current_module).or_default().trait_items.insert(id);
}
AssocCtxt::Impl => {
let hir_item = lctx.lower_impl_item(item);
let id = hir_item.impl_item_id();
lctx.impl_items.insert(id, hir_item);
- lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id);
+ lctx.modules.entry(lctx.current_module).or_default().impl_items.insert(id);
}
});
let hir_item = lctx.lower_foreign_item(item);
let id = hir_item.foreign_item_id();
lctx.foreign_items.insert(id, hir_item);
- lctx.modules.get_mut(&lctx.current_module).unwrap().foreign_items.insert(id);
+ lctx.modules.entry(lctx.current_module).or_default().foreign_items.insert(id);
});
visit::walk_foreign_item(self, item);
&mut self,
f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T,
) -> T {
- let old_in_scope_lifetimes = std::mem::replace(&mut self.in_scope_lifetimes, vec![]);
+ let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
// this vector is only used when walking over impl headers,
// input types, and the like, and should not be non-empty in
res
}
- pub(super) fn lower_mod(&mut self, m: &Mod) -> hir::Mod<'hir> {
+ pub(super) fn lower_mod(&mut self, items: &[P<Item>], inner: Span) -> hir::Mod<'hir> {
hir::Mod {
- inner: m.inner,
- item_ids: self
- .arena
- .alloc_from_iter(m.items.iter().flat_map(|x| self.lower_item_id(x))),
+ inner,
+ item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_id(x))),
}
}
hir::ItemKind::Fn(sig, generics, body_id)
})
}
- ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)),
+ ItemKind::Mod(_, ref mod_kind) => match mod_kind {
+ ModKind::Loaded(items, _, inner_span) => {
+ hir::ItemKind::Mod(self.lower_mod(items, *inner_span))
+ }
+ ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
+ },
ItemKind::ForeignMod(ref fm) => {
if fm.abi.is_none() {
self.maybe_lint_missing_abi(span, id, abi::Abi::C);
visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
- let module = self.lower_mod(&c.module);
+ let module = self.lower_mod(&c.items, c.span);
let attrs = self.lower_attrs(&c.attrs);
let body_ids = body_ids(&self.bodies);
let proc_macros =
fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId {
let id = hir::ItemId { def_id: item.def_id };
self.items.insert(id, item);
- self.modules.get_mut(&self.current_module).unwrap().items.insert(id);
+ self.modules.entry(self.current_module).or_default().items.insert(id);
id
}
walk_list!(self, visit_attribute, &item.attrs);
return;
}
- ItemKind::Mod(Mod { inline, unsafety, .. }) => {
+ ItemKind::Mod(unsafety, ref mod_kind) => {
if let Unsafe::Yes(span) = unsafety {
self.err_handler().span_err(span, "module cannot be declared unsafe");
}
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
- if !inline && !self.session.contains_name(&item.attrs, sym::path) {
+ if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
+ && !self.session.contains_name(&item.attrs, sym::path)
+ {
self.check_mod_file_item_asciionly(item.ident);
}
}
self.count += 1;
walk_ident(self, ident);
}
- fn visit_mod(&mut self, m: &Mod, _s: Span, _a: &[Attribute], _n: NodeId) {
- self.count += 1;
- walk_mod(self, m)
- }
fn visit_foreign_item(&mut self, i: &ForeignItem) {
self.count += 1;
walk_foreign_item(self, i)
use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
use rustc_ast::util::parser::{self, AssocOp, Fixity};
use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
-use rustc_ast::{GenericArg, MacArgs};
+use rustc_ast::{GenericArg, MacArgs, ModKind};
use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
pub s: pp::Printer,
comments: Option<Comments<'a>>,
ann: &'a (dyn PpAnn + 'a),
- is_expanded: bool,
}
crate const INDENT_UNIT: usize = 4;
is_expanded: bool,
edition: Edition,
) -> String {
- let mut s = State {
- s: pp::mk_printer(),
- comments: Some(Comments::new(sm, filename, input)),
- ann,
- is_expanded,
- };
+ let mut s =
+ State { s: pp::mk_printer(), comments: Some(Comments::new(sm, filename, input)), ann };
if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
// We need to print `#![no_std]` (and its feature gate) so that
}
}
- s.print_mod(&krate.module, &krate.attrs);
+ s.print_inner_attributes(&krate.attrs);
+ for item in &krate.items {
+ s.print_item(item);
+ }
s.print_remaining_comments();
s.ann.post(&mut s, AnnNode::Crate(krate));
s.s.eof()
impl<'a> State<'a> {
pub fn new() -> State<'a> {
- State { s: pp::mk_printer(), comments: None, ann: &NoAnn, is_expanded: false }
+ State { s: pp::mk_printer(), comments: None, ann: &NoAnn }
}
// Synthesizes a comment that was not textually present in the original source
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
}
- pub fn print_mod(&mut self, _mod: &ast::Mod, attrs: &[ast::Attribute]) {
- self.print_inner_attributes(attrs);
- for item in &_mod.items {
- self.print_item(item);
- }
- }
-
crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
self.print_inner_attributes(attrs);
for item in &nmod.items {
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
self.print_ident(constraint.ident);
+ constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
self.s.space();
match &constraint.kind {
ast::AssocTyConstraintKind::Equality { ty } => {
let body = body.as_deref();
self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
}
- ast::ItemKind::Mod(ref _mod) => {
+ ast::ItemKind::Mod(unsafety, ref mod_kind) => {
self.head(self.to_string(|s| {
s.print_visibility(&item.vis);
- s.print_unsafety(_mod.unsafety);
+ s.print_unsafety(unsafety);
s.word("mod");
}));
self.print_ident(item.ident);
- if _mod.inline || self.is_expanded {
- self.nbsp();
- self.bopen();
- self.print_mod(_mod, &item.attrs);
- self.bclose(item.span);
- } else {
- self.s.word(";");
- self.end(); // end inner head-block
- self.end(); // end outer head-block
+ match mod_kind {
+ ModKind::Loaded(items, ..) => {
+ self.nbsp();
+ self.bopen();
+ self.print_inner_attributes(&item.attrs);
+ for item in items {
+ self.print_item(item);
+ }
+ self.bclose(item.span);
+ }
+ ModKind::Unloaded => {
+ self.s.word(";");
+ self.end(); // end inner head-block
+ self.end(); // end outer head-block
+ }
}
}
ast::ItemKind::ForeignMod(ref nmod) => {
}
let decls = mk_decls(&mut krate, &mut cx, ¯os);
- krate.module.items.push(decls);
+ krate.items.push(decls);
krate
}
// .rev() to preserve ordering above in combination with insert(0, ...)
for &name in names.iter().rev() {
let ident = if rust_2018 { Ident::new(name, span) } else { Ident::new(name, call_site) };
- krate.module.items.insert(
+ krate.items.insert(
0,
cx.item(
span,
})),
);
- krate.module.items.insert(0, use_item);
+ krate.items.insert(0, use_item);
krate
}
// Code that generates a test runner to run all the tests in a crate
use rustc_ast as ast;
-use rustc_ast::attr;
use rustc_ast::entry::EntryPointType;
use rustc_ast::mut_visit::{ExpectOne, *};
use rustc_ast::ptr::P;
+use rustc_ast::{attr, ModKind};
use rustc_expand::base::{ExtCtxt, ResolverExpand};
use rustc_expand::expand::{AstFragment, ExpansionConfig};
use rustc_feature::Features;
noop_visit_crate(c, self);
// Create a main function to run our tests
- c.module.items.push(mk_main(&mut self.cx));
+ c.items.push(mk_main(&mut self.cx));
}
fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
// We don't want to recurse into anything other than mods, since
// mods or tests inside of functions will break things
- if let ast::ItemKind::Mod(mut module) = item.kind {
+ if let ast::ItemKind::Mod(..) = item.kind {
let tests = mem::take(&mut self.tests);
- noop_visit_mod(&mut module, self);
+ noop_visit_item_kind(&mut item.kind, self);
let mut tests = mem::replace(&mut self.tests, tests);
if !tests.is_empty() {
if item.id == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { item.id };
// Create an identifier that will hygienically resolve the test
// case name, even in another module.
+ let inner_span = match item.kind {
+ ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) => span,
+ _ => unreachable!(),
+ };
let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
- module.inner,
+ inner_span,
AstPass::TestHarness,
&[],
Some(parent),
}
self.cx.test_cases.extend(tests);
}
- item.kind = ast::ItemKind::Mod(module);
}
smallvec![P(item)]
}
) -> Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>> {
let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full;
+ let target_is_msvc = self.cx.sess().target.is_like_msvc;
+
if !full_debug_info && self.cx.sess().fewer_names() {
return None;
}
&& var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE
{
let arg_index = place.local.index() - 1;
-
- // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
- // offset in closures to account for the hidden environment?
- // Also, is this `+ 1` needed at all?
- VariableKind::ArgumentVariable(arg_index + 1)
+ if target_is_msvc {
+ // Rust compiler decomposes every &str or slice argument into two components:
+ // a pointer to the memory address where the data is stored and a usize representing
+ // the length of the str (or slice). These components will later be used to reconstruct
+ // the original argument inside the body of the function that owns it (see the
+ // definition of debug_introduce_local for more details).
+ //
+ // Since the original argument is declared inside a function rather than being passed
+ // in as an argument, it must be marked as a LocalVariable for MSVC debuggers to visualize
+ // its data correctly. (See issue #81894 for an in-depth description of the problem).
+ match *var_ty.kind() {
+ ty::Ref(_, inner_type, _) => match *inner_type.kind() {
+ ty::Slice(_) | ty::Str => VariableKind::LocalVariable,
+ _ => VariableKind::ArgumentVariable(arg_index + 1),
+ },
+ _ => VariableKind::ArgumentVariable(arg_index + 1),
+ }
+ } else {
+ // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
+ // offset in closures to account for the hidden environment?
+ // Also, is this `+ 1` needed at all?
+ VariableKind::ArgumentVariable(arg_index + 1)
+ }
} else {
VariableKind::LocalVariable
};
(None, None) => String::new(),
};
- println!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what);
+ eprintln!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what);
}
// Hack up our own formatting for the duration to make it easier for scripts
use std::fs;
use std::io;
-pub fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
+fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
if let Some(path) = arg.strip_prefix('@') {
let file = match fs::read_to_string(path) {
Ok(file) => file,
}
}
+pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
+ let mut args = Vec::new();
+ for arg in at_args {
+ match arg_expand(arg.clone()) {
+ Ok(arg) => args.extend(arg),
+ Err(err) => rustc_session::early_error(
+ rustc_session::config::ErrorOutputType::default(),
+ &format!("Failed to load argument file: {}", err),
+ ),
+ }
+ }
+ args
+}
+
#[derive(Debug)]
pub enum Error {
Utf8Error(Option<String>),
use std::str;
use std::time::Instant;
-mod args;
+pub mod args;
pub mod pretty;
/// Exit status code used for successful compilation and help output.
Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
>,
) -> interface::Result<()> {
- let mut args = Vec::new();
- for arg in at_args {
- match args::arg_expand(arg.clone()) {
- Ok(arg) => args.extend(arg),
- Err(err) => early_error(
- ErrorOutputType::default(),
- &format!("Failed to load argument file: {}", err),
- ),
- }
- }
+ let args = args::arg_expand_all(at_args);
+
let diagnostic_output = emitter.map_or(DiagnosticOutput::Default, DiagnosticOutput::Raw);
let matches = match handle_options(&args) {
Some(matches) => matches,
E0545: include_str!("./error_codes/E0545.md"),
E0546: include_str!("./error_codes/E0546.md"),
E0547: include_str!("./error_codes/E0547.md"),
+E0549: include_str!("./error_codes/E0549.md"),
E0550: include_str!("./error_codes/E0550.md"),
E0551: include_str!("./error_codes/E0551.md"),
E0552: include_str!("./error_codes/E0552.md"),
// E0540, // multiple rustc_deprecated attributes
E0544, // multiple stability levels
// E0548, // replaced with a generic attribute input check
- // rustc_deprecated attribute must be paired with either stable or unstable
- // attribute
- E0549,
E0553, // multiple rustc_const_unstable attributes
// E0555, // replaced with a generic attribute input check
// E0558, // replaced with a generic attribute input check
#### Note: this error code is no longer emitted by the compiler.
-An if-let pattern attempts to match the pattern, and enters the body if the
+An `if let` pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding instead. For instance:
#### Note: this error code is no longer emitted by the compiler.
-A while-let pattern attempts to match the pattern, and enters the body if the
+A `while let` pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding inside a `loop` instead. For instance:
--- /dev/null
+A `rustc_deprecated` attribute wasn't paired with a `stable`/`unstable`
+attribute.
+
+Erroneous code example:
+
+```compile_fail,E0549
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[rustc_deprecated(
+ since = "1.0.1",
+ reason = "explanation for deprecation"
+)] // invalid
+fn _deprecated_fn() {}
+```
+
+To fix this issue, you need to add also an attribute `stable` or `unstable`.
+Example:
+
+```
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[stable(since = "1.0.0", feature = "test")]
+#[rustc_deprecated(
+ since = "1.0.1",
+ reason = "explanation for deprecation"
+)] // ok!
+fn _deprecated_fn() {}
+```
+
+See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
+of the Book and the [Stability attributes][stability-attributes] section of the
+Rustc Dev Guide for more details.
+
+[how-rust-made-nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+[stability-attributes]: https://rustc-dev-guide.rust-lang.org/stability.html
let max_line_num_len = if self.ui_testing {
ANONYMIZED_LINE_NUM.len()
} else {
- self.get_max_line_num(span, children).to_string().len()
+ // Instead of using .to_string().len(), we iteratively count the
+ // number of digits to avoid allocation. This strategy has sizable
+ // performance gains over the old string strategy.
+ let mut n = self.get_max_line_num(span, children);
+ let mut num_digits = 0;
+ loop {
+ num_digits += 1;
+ n /= 10;
+ if n == 0 {
+ break num_digits;
+ }
+ }
};
match self.emit_message_default(span, message, code, level, max_line_num_len, false) {
None => {
// The entire crate is unconfigured.
krate.attrs = Vec::new();
- krate.module.items = Vec::new();
+ krate.items = Vec::new();
Features::default()
}
Some(attrs) => {
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AttrItem, AttrStyle, Block, ItemKind, LitKind, MacArgs};
-use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, NestedMetaItem};
+use rustc_ast::{AttrItem, AttrStyle, Block, Inline, ItemKind, LitKind, MacArgs};
+use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, PResult};
use rustc_feature::Features;
-use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser};
+use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, GateOr, Parser, RecoverComma};
use rustc_parse::validate_attr;
use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
use rustc_session::lint::BuiltinLintDiagnostics;
MacroExpander { cx, monotonic }
}
+ // FIXME: Avoid visiting the crate as a `Mod` item,
+ // make crate a first class expansion target instead.
pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
let mut module = ModuleData {
mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)],
self.cx.root_path = module.directory.clone();
self.cx.current_expansion.module = Rc::new(module);
- let orig_mod_span = krate.module.inner;
-
let krate_item = AstFragment::Items(smallvec![P(ast::Item {
attrs: krate.attrs,
span: krate.span,
- kind: ast::ItemKind::Mod(krate.module),
+ kind: ast::ItemKind::Mod(
+ Unsafe::No,
+ ModKind::Loaded(krate.items, Inline::Yes, krate.span)
+ ),
ident: Ident::invalid(),
id: ast::DUMMY_NODE_ID,
vis: ast::Visibility {
})]);
match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) {
- Some(ast::Item { attrs, kind: ast::ItemKind::Mod(module), .. }) => {
+ Some(ast::Item {
+ attrs,
+ kind: ast::ItemKind::Mod(_, ModKind::Loaded(items, ..)),
+ ..
+ }) => {
krate.attrs = attrs;
- krate.module = module;
+ krate.items = items;
}
None => {
// Resolution failed so we return an empty expansion
krate.attrs = vec![];
- krate.module = ast::Mod {
- inner: orig_mod_span,
- unsafety: Unsafe::No,
- items: vec![],
- inline: true,
- };
+ krate.items = vec![];
}
Some(ast::Item { span, kind, .. }) => {
krate.attrs = vec![];
- krate.module = ast::Mod {
- inner: orig_mod_span,
- unsafety: Unsafe::No,
- items: vec![],
- inline: true,
- };
+ krate.items = vec![];
self.cx.span_err(
span,
&format!(
impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
fn visit_item(&mut self, item: &'ast ast::Item) {
match &item.kind {
- ast::ItemKind::Mod(module) if !module.inline => {
+ ast::ItemKind::Mod(_, mod_kind)
+ if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
+ {
feature_err(
self.parse_sess,
sym::proc_macro_hygiene,
}
}
AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?),
- AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat(None)?),
+ AstFragmentKind::Pat => {
+ AstFragment::Pat(this.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)?)
+ }
AstFragmentKind::Arms
| AstFragmentKind::Fields
| AstFragmentKind::FieldPats
_ => unreachable!(),
})
}
- ast::ItemKind::Mod(ref mut old_mod @ ast::Mod { .. }) if ident != Ident::invalid() => {
+ ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => {
let sess = &self.cx.sess.parse_sess;
let orig_ownership = self.cx.current_expansion.directory_ownership;
let mut module = (*self.cx.current_expansion.module).clone();
let pushed = &mut false; // Record `parse_external_mod` pushing so we can pop.
let dir = Directory { ownership: orig_ownership, path: module.directory };
- let Directory { ownership, path } = if old_mod.inline {
- // Inline `mod foo { ... }`, but we still need to push directories.
- item.attrs = attrs;
- push_directory(&self.cx.sess, ident, &item.attrs, dir)
- } else {
- // We have an outline `mod foo;` so we need to parse the file.
- let (new_mod, dir) = parse_external_mod(
- &self.cx.sess,
- ident,
- span,
- old_mod.unsafety,
- dir,
- &mut attrs,
- pushed,
- );
-
- let krate = ast::Crate {
- span: new_mod.inner,
- module: new_mod,
- attrs,
- proc_macros: vec![],
- };
- if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
- extern_mod_loaded(&krate, ident);
+ let Directory { ownership, path } = match mod_kind {
+ ModKind::Loaded(_, Inline::Yes, _) => {
+ // Inline `mod foo { ... }`, but we still need to push directories.
+ item.attrs = attrs;
+ push_directory(&self.cx.sess, ident, &item.attrs, dir)
+ }
+ ModKind::Loaded(_, Inline::No, _) => {
+ panic!("`mod` item is loaded from a file for the second time")
}
+ ModKind::Unloaded => {
+ // We have an outline `mod foo;` so we need to parse the file.
+ let (items, inner_span, dir) =
+ parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed);
+
+ let krate =
+ ast::Crate { attrs, items, span: inner_span, proc_macros: vec![] };
+ if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
+ extern_mod_loaded(&krate, ident);
+ }
- *old_mod = krate.module;
- item.attrs = krate.attrs;
- // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure.
- item = match self.configure(item) {
- Some(node) => node,
- None => {
- if *pushed {
- sess.included_mod_stack.borrow_mut().pop();
+ *mod_kind = ModKind::Loaded(krate.items, Inline::No, inner_span);
+ item.attrs = krate.attrs;
+ // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure.
+ item = match self.configure(item) {
+ Some(node) => node,
+ None => {
+ if *pushed {
+ sess.included_mod_stack.borrow_mut().pop();
+ }
+ return Default::default();
}
- return Default::default();
- }
- };
- dir
+ };
+ dir
+ }
};
// Set the module info before we flat map.
-use rustc_ast::{token, Attribute, Mod, Unsafe};
+use rustc_ast::ptr::P;
+use rustc_ast::{token, Attribute, Item};
use rustc_errors::{struct_span_err, PResult};
use rustc_parse::new_parser_from_file;
use rustc_session::parse::ParseSess;
sess: &Session,
id: Ident,
span: Span, // The span to blame on errors.
- unsafety: Unsafe,
Directory { mut ownership, path }: Directory,
attrs: &mut Vec<Attribute>,
pop_mod_stack: &mut bool,
-) -> (Mod, Directory) {
+) -> (Vec<P<Item>>, Span, Directory) {
// We bail on the first error, but that error does not cause a fatal error... (1)
let result: PResult<'_, _> = try {
// Extract the file path and the new ownership.
// Actually parse the external file as a module.
let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span));
- let mut module = parser.parse_mod(&token::Eof, unsafety)?;
- module.0.inline = false;
- module
+ let (mut inner_attrs, items, inner_span) = parser.parse_mod(&token::Eof)?;
+ attrs.append(&mut inner_attrs);
+ (items, inner_span)
};
// (1) ...instead, we return a dummy module.
- let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_else(|_| {
- let module = Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false };
- (module, Vec::new())
- });
- attrs.append(&mut new_attrs);
+ let (items, inner_span) = result.map_err(|mut err| err.emit()).unwrap_or_default();
- // Extract the directory path for submodules of `module`.
- let path = sess.source_map().span_to_unmapped_path(module.inner);
+ // Extract the directory path for submodules of the module.
+ let path = sess.source_map().span_to_unmapped_path(inner_span);
let mut path = match path {
FileName::Real(name) => name.into_local_path(),
other => PathBuf::from(other.to_string()),
};
path.pop();
- (module, Directory { ownership, path })
+ (items, inner_span, Directory { ownership, path })
}
fn error_on_circular_module<'a>(
use rustc_span::with_default_session_globals;
// This version doesn't care about getting comments or doc-strings in.
-fn fake_print_crate(s: &mut pprust::State<'_>, krate: &ast::Crate) {
- s.print_mod(&krate.module, &krate.attrs)
+fn print_crate_items(krate: &ast::Crate) -> String {
+ krate.items.iter().map(|i| pprust::item_to_string(i)).collect::<Vec<_>>().join(" ")
}
// Change every identifier to "zz".
assert_pred!(
matches_codepattern,
"matches_codepattern",
- pprust::to_string(|s| fake_print_crate(s, &krate)),
+ print_crate_items(&krate),
"#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string()
);
})
assert_pred!(
matches_codepattern,
"matches_codepattern",
- pprust::to_string(|s| fake_print_crate(s, &krate)),
+ print_crate_items(&krate),
"macro_rules! zz{(zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+))}".to_string()
);
})
.unwrap()
.unwrap();
- if let ast::ItemKind::Mod(ref m) = item.kind {
- assert!(m.items.len() == 2);
+ if let ast::ItemKind::Mod(_, ref mod_kind) = item.kind {
+ assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2));
} else {
panic!();
}
+// ignore-tidy-filelength
use crate::def::{DefKind, Namespace, Res};
use crate::def_id::DefId;
crate use crate::hir_id::HirId;
pub rhs_ty: &'hir Ty<'hir>,
}
-#[derive(Encodable, Debug, HashStable_Generic)]
+#[derive(Default, Encodable, Debug, HashStable_Generic)]
pub struct ModuleItems {
// Use BTreeSets here so items are in the same order as in the
// list of all items in Crate
}
/// The type of source expression that caused this generator to be created.
-#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
pub enum GeneratorKind {
/// An explicit `async` block or the body of an async function.
Async(AsyncGeneratorKind),
}
}
+impl GeneratorKind {
+ pub fn descr(&self) -> &'static str {
+ match self {
+ GeneratorKind::Async(ask) => ask.descr(),
+ GeneratorKind::Gen => "generator",
+ }
+ }
+}
+
/// In the case of a generator created as part of an async construct,
/// which kind of async construct caused it to be created?
///
/// This helps error messages but is also used to drive coercions in
/// type-checking (see #60424).
-#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
pub enum AsyncGeneratorKind {
/// An explicit `async` block written by the user.
Block,
}
}
+impl AsyncGeneratorKind {
+ pub fn descr(&self) -> &'static str {
+ match self {
+ AsyncGeneratorKind::Block => "`async` block",
+ AsyncGeneratorKind::Closure => "`async` closure body",
+ AsyncGeneratorKind::Fn => "`async fn` body",
+ }
+ }
+}
+
#[derive(Copy, Clone, Debug)]
pub enum BodyOwnerKind {
/// Functions and methods.
// The associated item of `trait DiscriminantKind`.
Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy;
+ PointeeTrait, sym::pointee_trait, pointee_trait, Target::Trait;
+ Metadata, sym::metadata_type, metadata_type, Target::AssocTy;
+ DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct;
+
Freeze, sym::freeze, freeze_trait, Target::Trait;
Drop, sym::drop, drop_trait, Target::Trait;
Deref, sym::deref, deref_trait, Target::Trait;
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait;
+ DerefTarget, sym::deref_target, deref_target, Target::AssocTy;
Receiver, sym::receiver, receiver_trait, Target::Trait;
Fn, kw::Fn, fn_trait, Target::Trait;
debug!("read_file: {}", message);
if report_incremental_info {
- println!(
+ eprintln!(
"[incremental] ignoring cache artifact `{}`: {}",
file.file_name().unwrap().to_string_lossy(),
message
}
if sess.opts.debugging_opts.incremental_info {
- println!(
+ eprintln!(
"[incremental] session directory: \
{} files hard-linked",
files_linked
);
- println!(
+ eprintln!(
"[incremental] session directory: \
{} files copied",
files_copied
if prev_commandline_args_hash != expected_hash {
if report_incremental_info {
- println!(
+ eprintln!(
"[incremental] completely ignoring cache because of \
differing commandline arguments"
);
pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
fn to_trace(
+ tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
where
T: ToTrace<'tcx>,
{
- let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
+ let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b);
Trace { at: self, trace, a_is_expected }
}
}
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
fn to_trace(
+ _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
fn to_trace(
+ _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
fn to_trace(
+ _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
fn to_trace(
+ _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
fn to_trace(
+ _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
}
}
}
+
+impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> {
+ fn to_trace(
+ tcx: TyCtxt<'tcx>,
+ cause: &ObligationCause<'tcx>,
+ a_is_expected: bool,
+ a: Self,
+ b: Self,
+ ) -> TypeTrace<'tcx> {
+ let a_ty = tcx.mk_projection(a.item_def_id, a.substs);
+ let b_ty = tcx.mk_projection(b.item_def_id, b.substs);
+ TypeTrace {
+ cause: cause.clone(),
+ values: Types(ExpectedFound::new(a_is_expected, a_ty, b_ty)),
+ }
+ }
+}
// Unify the original value for each variable with the value
// taken from `query_response` (after applying `result_subst`).
- Ok(self.unify_canonical_vars(
- cause,
- param_env,
- original_values,
- substituted_query_response,
- )?)
+ self.unify_canonical_vars(cause, param_env, original_values, substituted_query_response)
}
/// Converts the region constraints resulting from a query into an
impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let Some((kind, def_id)) = TyCategory::from_ty(t) {
+ if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) {
let span = self.tcx.def_span(def_id);
// Avoid cluttering the output when the "found" and error span overlap:
//
};
if let Some((expected, found)) = expected_found {
let expected_label = match exp_found {
- Mismatch::Variable(ef) => ef.expected.prefix_string(),
+ Mismatch::Variable(ef) => ef.expected.prefix_string(self.tcx),
Mismatch::Fixed(s) => s.into(),
};
let found_label = match exp_found {
- Mismatch::Variable(ef) => ef.found.prefix_string(),
+ Mismatch::Variable(ef) => ef.found.prefix_string(self.tcx),
Mismatch::Fixed(s) => s.into(),
};
let exp_found = match exp_found {
pub enum TyCategory {
Closure,
Opaque,
- Generator,
+ Generator(hir::GeneratorKind),
Foreign,
}
match self {
Self::Closure => "closure",
Self::Opaque => "opaque type",
- Self::Generator => "generator",
+ Self::Generator(gk) => gk.descr(),
Self::Foreign => "foreign type",
}
}
- pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> {
+ pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
match *ty.kind() {
ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)),
- ty::Generator(def_id, ..) => Some((Self::Generator, def_id)),
+ ty::Generator(def_id, ..) => {
+ Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id))
+ }
ty::Foreign(def_id) => Some((Self::Foreign, def_id)),
_ => None,
}
InferenceDiagnosticsData {
name: s,
span: None,
- kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string() },
+ kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
parent: None,
}
}
self.infcx.tcx
}
- pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'cx>> {
+ pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx>> {
// Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
// the nice region errors are required when running under the MIR borrow checker.
self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict())
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// When given a `ConcreteFailure` for a function with parameters containing a named region and
/// an anonymous region, emit an descriptive diagnostic error.
- pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'a>> {
+ pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'tcx>> {
let (span, sub, sup) = self.regions()?;
debug!(
impl NiceRegionError<'me, 'tcx> {
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
/// an anonymous region, emit a descriptive diagnostic error.
- pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder<'me>> {
+ pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder<'tcx>> {
match &self.error {
///////////////////////////////////////////////////////////////////////////
// NB. The ordering of cases in this match is very
Some(RegionResolutionError::SubSupConflict(
vid,
_,
- SubregionOrigin::Subtype(box TypeTrace {
- cause,
- values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
- }),
+ SubregionOrigin::Subtype(box TypeTrace { cause, values }),
sub_placeholder @ ty::RePlaceholder(_),
_,
sup_placeholder @ ty::RePlaceholder(_),
- )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+ )) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
Some(sub_placeholder),
Some(sup_placeholder),
- expected.def_id,
- expected.substs,
- found.substs,
- )),
+ values,
+ ),
Some(RegionResolutionError::SubSupConflict(
vid,
_,
- SubregionOrigin::Subtype(box TypeTrace {
- cause,
- values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
- }),
+ SubregionOrigin::Subtype(box TypeTrace { cause, values }),
sub_placeholder @ ty::RePlaceholder(_),
_,
_,
- )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+ )) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
Some(sub_placeholder),
None,
- expected.def_id,
- expected.substs,
- found.substs,
- )),
+ values,
+ ),
Some(RegionResolutionError::SubSupConflict(
vid,
_,
- SubregionOrigin::Subtype(box TypeTrace {
- cause,
- values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
- }),
+ SubregionOrigin::Subtype(box TypeTrace { cause, values }),
_,
_,
sup_placeholder @ ty::RePlaceholder(_),
- )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+ )) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
None,
Some(*sup_placeholder),
- expected.def_id,
- expected.substs,
- found.substs,
- )),
+ values,
+ ),
Some(RegionResolutionError::SubSupConflict(
vid,
_,
_,
_,
- SubregionOrigin::Subtype(box TypeTrace {
- cause,
- values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
- }),
+ SubregionOrigin::Subtype(box TypeTrace { cause, values }),
sup_placeholder @ ty::RePlaceholder(_),
- )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+ )) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
None,
Some(*sup_placeholder),
- expected.def_id,
- expected.substs,
- found.substs,
- )),
+ values,
+ ),
Some(RegionResolutionError::UpperBoundUniverseConflict(
vid,
_,
_,
- SubregionOrigin::Subtype(box TypeTrace {
- cause,
- values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
- }),
+ SubregionOrigin::Subtype(box TypeTrace { cause, values }),
sup_placeholder @ ty::RePlaceholder(_),
- )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+ )) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
None,
Some(*sup_placeholder),
- expected.def_id,
- expected.substs,
- found.substs,
- )),
+ values,
+ ),
Some(RegionResolutionError::ConcreteFailure(
- SubregionOrigin::Subtype(box TypeTrace {
- cause,
- values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
- }),
+ SubregionOrigin::Subtype(box TypeTrace { cause, values }),
sub_region @ ty::RePlaceholder(_),
sup_region @ ty::RePlaceholder(_),
- )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+ )) => self.try_report_trait_placeholder_mismatch(
None,
cause,
Some(*sub_region),
Some(*sup_region),
- expected.def_id,
- expected.substs,
- found.substs,
- )),
+ values,
+ ),
Some(RegionResolutionError::ConcreteFailure(
- SubregionOrigin::Subtype(box TypeTrace {
- cause,
- values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
- }),
+ SubregionOrigin::Subtype(box TypeTrace { cause, values }),
sub_region @ ty::RePlaceholder(_),
sup_region,
- )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
- Some(sup_region),
+ )) => self.try_report_trait_placeholder_mismatch(
+ (!sup_region.has_name()).then_some(sup_region),
cause,
- Some(*sub_region),
+ Some(sub_region),
None,
- expected.def_id,
- expected.substs,
- found.substs,
- )),
+ values,
+ ),
Some(RegionResolutionError::ConcreteFailure(
- SubregionOrigin::Subtype(box TypeTrace {
- cause,
- values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
- }),
+ SubregionOrigin::Subtype(box TypeTrace { cause, values }),
sub_region,
sup_region @ ty::RePlaceholder(_),
- )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
- Some(sub_region),
+ )) => self.try_report_trait_placeholder_mismatch(
+ (!sub_region.has_name()).then_some(sub_region),
cause,
None,
- Some(*sup_region),
- expected.def_id,
- expected.substs,
- found.substs,
- )),
+ Some(sup_region),
+ values,
+ ),
_ => None,
}
}
+ fn try_report_trait_placeholder_mismatch(
+ &self,
+ vid: Option<ty::Region<'tcx>>,
+ cause: &ObligationCause<'tcx>,
+ sub_placeholder: Option<ty::Region<'tcx>>,
+ sup_placeholder: Option<ty::Region<'tcx>>,
+ value_pairs: &ValuePairs<'tcx>,
+ ) -> Option<DiagnosticBuilder<'tcx>> {
+ let (expected_substs, found_substs, trait_def_id) = match value_pairs {
+ ValuePairs::TraitRefs(ExpectedFound { expected, found })
+ if expected.def_id == found.def_id =>
+ {
+ (expected.substs, found.substs, expected.def_id)
+ }
+ ValuePairs::PolyTraitRefs(ExpectedFound { expected, found })
+ if expected.def_id() == found.def_id() =>
+ {
+ // It's possible that the placeholders come from a binder
+ // outside of this value pair. Use `no_bound_vars` as a
+ // simple heuristic for that.
+ (expected.no_bound_vars()?.substs, found.no_bound_vars()?.substs, expected.def_id())
+ }
+ _ => return None,
+ };
+
+ Some(self.report_trait_placeholder_mismatch(
+ vid,
+ cause,
+ sub_placeholder,
+ sup_placeholder,
+ trait_def_id,
+ expected_substs,
+ found_substs,
+ ))
+ }
+
// error[E0308]: implementation of `Foo` does not apply to enough lifetimes
// --> /home/nmatsakis/tmp/foo.rs:12:5
// |
// = note: Due to a where-clause on the function `all`,
// = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
// = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
- fn try_report_placeholders_trait(
+ #[instrument(level = "debug", skip(self))]
+ fn report_trait_placeholder_mismatch(
&self,
vid: Option<ty::Region<'tcx>>,
cause: &ObligationCause<'tcx>,
trait_def_id: DefId,
expected_substs: SubstsRef<'tcx>,
actual_substs: SubstsRef<'tcx>,
- ) -> DiagnosticBuilder<'me> {
- debug!(
- "try_report_placeholders_trait(\
- vid={:?}, \
- sub_placeholder={:?}, \
- sup_placeholder={:?}, \
- trait_def_id={:?}, \
- expected_substs={:?}, \
- actual_substs={:?})",
- vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs
- );
-
+ ) -> DiagnosticBuilder<'tcx> {
let span = cause.span(self.tcx());
let msg = format!(
"implementation of `{}` is not general enough",
self.tcx().def_path_str(trait_def_id),
);
let mut err = self.tcx().sess.struct_span_err(span, &msg);
- err.span_label(
- self.tcx().def_span(trait_def_id),
- format!("trait `{}` defined here", self.tcx().def_path_str(trait_def_id)),
- );
let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = cause.code {
err.span_label(span, "doesn't satisfy where-clause");
let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;
- debug!("try_report_placeholders_trait: actual_has_vid={:?}", actual_has_vid);
- debug!("try_report_placeholders_trait: expected_has_vid={:?}", expected_has_vid);
- debug!("try_report_placeholders_trait: has_sub={:?}", has_sub);
- debug!("try_report_placeholders_trait: has_sup={:?}", has_sup);
debug!(
- "try_report_placeholders_trait: actual_self_ty_has_vid={:?}",
- actual_self_ty_has_vid
- );
- debug!(
- "try_report_placeholders_trait: expected_self_ty_has_vid={:?}",
- expected_self_ty_has_vid
+ ?actual_has_vid,
+ ?expected_has_vid,
+ ?has_sub,
+ ?has_sup,
+ ?actual_self_ty_has_vid,
+ ?expected_self_ty_has_vid,
);
self.explain_actual_impl_that_was_found(
value: trait_ref,
};
+ let same_self_type = actual_trait_ref.self_ty() == expected_trait_ref.self_ty();
+
let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
}
};
- let mut note = if passive_voice {
+ let mut note = if same_self_type {
+ let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
+ self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
+
+ if self_ty.value.is_closure()
+ && self
+ .tcx()
+ .fn_trait_kind_from_lang_item(expected_trait_ref.value.def_id)
+ .is_some()
+ {
+ let closure_sig = self_ty.map(|closure| {
+ if let ty::Closure(_, substs) = closure.kind() {
+ self.tcx().signature_unclosure(
+ substs.as_closure().sig(),
+ rustc_hir::Unsafety::Normal,
+ )
+ } else {
+ bug!("type is not longer closure");
+ }
+ });
+
+ format!(
+ "{}closure with signature `{}` must implement `{}`",
+ if leading_ellipsis { "..." } else { "" },
+ closure_sig,
+ expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+ )
+ } else {
+ format!(
+ "{}`{}` must implement `{}`",
+ if leading_ellipsis { "..." } else { "" },
+ self_ty,
+ expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+ )
+ }
+ } else if passive_voice {
format!(
"{}`{}` would have to be implemented for the type `{}`",
if leading_ellipsis { "..." } else { "" },
None => true,
};
- let mut note = if passive_voice {
+ let mut note = if same_self_type {
+ format!(
+ "...but it actually implements `{}`",
+ actual_trait_ref.map(|tr| tr.print_only_trait_path()),
+ )
+ } else if passive_voice {
format!(
"...but `{}` is actually implemented for the type `{}`",
actual_trait_ref.map(|tr| tr.print_only_trait_path()),
}
if sess.opts.debugging_opts.input_stats {
- println!("Lines of code: {}", sess.source_map().count_lines());
- println!("Pre-expansion node count: {}", count_nodes(&krate));
+ eprintln!("Lines of code: {}", sess.source_map().count_lines());
+ eprintln!("Pre-expansion node count: {}", count_nodes(&krate));
}
if let Some(ref s) = sess.opts.debugging_opts.show_span {
// Done with macro expansion!
if sess.opts.debugging_opts.input_stats {
- println!("Post-expansion node count: {}", count_nodes(&krate));
+ eprintln!("Post-expansion node count: {}", count_nodes(&krate));
}
if sess.opts.debugging_opts.hir_stats {
run_early_pass!(self, check_ident, ident);
}
- fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) {
- run_early_pass!(self, check_mod, m, s, n);
- self.check_id(n);
- ast_visit::walk_mod(self, m);
- run_early_pass!(self, check_mod_post, m, s, n);
- }
-
fn visit_local(&mut self, l: &'a ast::Local) {
self.with_lint_attrs(l.id, &l.attrs, |cx| {
run_early_pass!(cx, check_local, l);
fn check_ident(a: Ident);
fn check_crate(a: &ast::Crate);
fn check_crate_post(a: &ast::Crate);
- fn check_mod(a: &ast::Mod, b: Span, c: ast::NodeId);
- fn check_mod_post(a: &ast::Mod, b: Span, c: ast::NodeId);
fn check_foreign_item(a: &ast::ForeignItem);
fn check_foreign_item_post(a: &ast::ForeignItem);
fn check_item(a: &ast::Item);
}
declare_lint! {
- /// The `irrefutable_let_patterns` lint detects detects [irrefutable
- /// patterns] in [if-let] and [while-let] statements.
- ///
- ///
+ /// The `irrefutable_let_patterns` lint detects [irrefutable patterns]
+ /// in [`if let`]s, [`while let`]s, and `if let` guards.
///
/// ### Example
///
- /// ```rust
+ /// ```
/// if let _ = 123 {
/// println!("always runs!");
/// }
/// ### Explanation
///
/// There usually isn't a reason to have an irrefutable pattern in an
- /// if-let or while-let statement, because the pattern will always match
+ /// `if let` or `while let` statement, because the pattern will always match
/// successfully. A [`let`] or [`loop`] statement will suffice. However,
/// when generating code with a macro, forbidding irrefutable patterns
/// would require awkward workarounds in situations where the macro
/// See [RFC 2086] for more details.
///
/// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability
- /// [if-let]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
- /// [while-let]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
+ /// [`if let`]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
+ /// [`while let`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
/// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements
/// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops
/// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md
pub IRREFUTABLE_LET_PATTERNS,
Warn,
- "detects irrefutable patterns in if-let and while-let statements"
+ "detects irrefutable patterns in `if let` and `while let` statements"
}
declare_lint! {
}
}
- println!("metadata stats:");
- println!(" dep bytes: {}", dep_bytes);
- println!(" lib feature bytes: {}", lib_feature_bytes);
- println!(" lang item bytes: {}", lang_item_bytes);
- println!(" diagnostic item bytes: {}", diagnostic_item_bytes);
- println!(" native bytes: {}", native_lib_bytes);
- println!(" source_map bytes: {}", source_map_bytes);
- println!(" impl bytes: {}", impl_bytes);
- println!(" exp. symbols bytes: {}", exported_symbols_bytes);
- println!(" def-path table bytes: {}", def_path_table_bytes);
- println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
- println!(" mir bytes: {}", mir_bytes);
- println!(" item bytes: {}", item_bytes);
- println!(" table bytes: {}", tables_bytes);
- println!(" hygiene bytes: {}", hygiene_bytes);
- println!(" zero bytes: {}", zero_bytes);
- println!(" total bytes: {}", total_bytes);
+ eprintln!("metadata stats:");
+ eprintln!(" dep bytes: {}", dep_bytes);
+ eprintln!(" lib feature bytes: {}", lib_feature_bytes);
+ eprintln!(" lang item bytes: {}", lang_item_bytes);
+ eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes);
+ eprintln!(" native bytes: {}", native_lib_bytes);
+ eprintln!(" source_map bytes: {}", source_map_bytes);
+ eprintln!(" impl bytes: {}", impl_bytes);
+ eprintln!(" exp. symbols bytes: {}", exported_symbols_bytes);
+ eprintln!(" def-path table bytes: {}", def_path_table_bytes);
+ eprintln!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
+ eprintln!(" mir bytes: {}", mir_bytes);
+ eprintln!(" item bytes: {}", item_bytes);
+ eprintln!(" table bytes: {}", tables_bytes);
+ eprintln!(" hygiene bytes: {}", hygiene_bytes);
+ eprintln!(" zero bytes: {}", zero_bytes);
+ eprintln!(" total bytes: {}", total_bytes);
}
root
/// ImplSource for a builtin `DeterminantKind` trait implementation.
DiscriminantKind(ImplSourceDiscriminantKindData),
+ /// ImplSource for a builtin `Pointee` trait implementation.
+ Pointee(ImplSourcePointeeData),
+
/// ImplSource automatically generated for a generator.
Generator(ImplSourceGeneratorData<'tcx, N>),
ImplSource::Generator(c) => c.nested,
ImplSource::Object(d) => d.nested,
ImplSource::FnPointer(d) => d.nested,
- ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(),
+ ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
+ | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
ImplSource::TraitAlias(d) => d.nested,
}
}
ImplSource::Generator(c) => &c.nested[..],
ImplSource::Object(d) => &d.nested[..],
ImplSource::FnPointer(d) => &d.nested[..],
- ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => &[],
+ ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
+ | ImplSource::Pointee(ImplSourcePointeeData) => &[],
ImplSource::TraitAlias(d) => &d.nested[..],
}
}
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => {
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
}
+ ImplSource::Pointee(ImplSourcePointeeData) => {
+ ImplSource::Pointee(ImplSourcePointeeData)
+ }
ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
alias_def_id: d.alias_def_id,
substs: d.substs,
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
pub struct ImplSourceDiscriminantKindData;
+#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
+pub struct ImplSourcePointeeData;
+
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub struct ImplSourceTraitAliasData<'tcx, N> {
pub alias_def_id: DefId,
/// Builtin implementation of `DiscriminantKind`.
DiscriminantKindCandidate,
+ /// Builtin implementation of `Pointee`.
+ PointeeCandidate,
+
TraitAliasCandidate(DefId),
/// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
super::ImplSource::DiscriminantKind(ref d) => write!(f, "{:?}", d),
+ super::ImplSource::Pointee(ref d) => write!(f, "{:?}", d),
+
super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
super::ImplSource::Param(ref n, ct) => {
TrivialTypeFoldableAndLiftImpls! {
super::IfExpressionCause,
super::ImplSourceDiscriminantKindData,
+ super::ImplSourcePointeeData,
}
fn decode(decoder: &mut D) -> Result<Self, D::Error> {
let len = decoder.read_usize()?;
let tcx = decoder.tcx();
- Ok(tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))?)
+ tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))
}
}
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> {
fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
let len = decoder.read_usize()?;
- Ok(decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))?)
+ decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))
}
}
{
fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
let len = decoder.read_usize()?;
- Ok(decoder
- .tcx()
- .mk_poly_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?)
+ decoder.tcx().mk_poly_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))
}
}
}
}
+pub fn suggest_arbitrary_trait_bound(
+ generics: &hir::Generics<'_>,
+ err: &mut DiagnosticBuilder<'_>,
+ param_name: &str,
+ constraint: &str,
+) -> bool {
+ let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
+ match (param, param_name) {
+ (Some(_), "Self") => return false,
+ _ => {}
+ }
+ // Suggest a where clause bound for a non-type paremeter.
+ let (action, prefix) = if generics.where_clause.predicates.is_empty() {
+ ("introducing a", " where ")
+ } else {
+ ("extending the", ", ")
+ };
+ err.span_suggestion_verbose(
+ generics.where_clause.tail_span_for_suggestion(),
+ &format!(
+ "consider {} `where` bound, but there might be an alternative better way to express \
+ this requirement",
+ action,
+ ),
+ format!("{}{}: {}", prefix, param_name, constraint),
+ Applicability::MaybeIncorrect,
+ );
+ true
+}
+
/// Suggest restricting a type param with a new bound.
pub fn suggest_constraining_type_param(
tcx: TyCtxt<'_>,
use crate::traits::{ObligationCause, ObligationCauseCode};
use crate::ty::diagnostics::suggest_constraining_type_param;
+use crate::ty::print::{FmtPrinter, Printer};
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
use rustc_errors::{pluralize, DiagnosticBuilder};
}
}
ty::Closure(..) => "closure".into(),
- ty::Generator(..) => "generator".into(),
+ ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
ty::GeneratorWitness(..) => "generator witness".into(),
ty::Tuple(..) => "tuple".into(),
ty::Infer(ty::TyVar(_)) => "inferred type".into(),
}
}
- pub fn prefix_string(&self) -> Cow<'static, str> {
+ pub fn prefix_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
match *self.kind() {
ty::Infer(_)
| ty::Error(_)
ty::FnPtr(_) => "fn pointer".into(),
ty::Dynamic(..) => "trait object".into(),
ty::Closure(..) => "closure".into(),
- ty::Generator(..) => "generator".into(),
+ ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
ty::GeneratorWitness(..) => "generator witness".into(),
ty::Tuple(..) => "tuple".into(),
ty::Placeholder(..) => "higher-ranked type".into(),
{
// Synthesize the associated type restriction `Add<Output = Expected>`.
// FIXME: extract this logic for use in other diagnostics.
- let trait_ref = proj.trait_ref(self);
+ let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
let path =
self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
let item_name = self.item_name(proj.item_def_id);
+ let item_args = self.format_generic_args(assoc_substs);
+
let path = if path.ends_with('>') {
- format!("{}, {} = {}>", &path[..path.len() - 1], item_name, p)
+ format!(
+ "{}, {}{} = {}>",
+ &path[..path.len() - 1],
+ item_name,
+ item_args,
+ p
+ )
} else {
- format!("{}<{} = {}>", path, item_name, p)
+ format!("{}<{}{} = {}>", path, item_name, item_args, p)
};
note = !suggest_constraining_type_param(
self,
ty: Ty<'tcx>,
) -> bool {
let assoc = self.associated_item(proj_ty.item_def_id);
- let trait_ref = proj_ty.trait_ref(self);
+ let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
if let Some(hir_generics) = item.generics() {
// Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
&trait_ref,
pred.bounds,
&assoc,
+ assoc_substs,
ty,
msg,
) {
&trait_ref,
param.bounds,
&assoc,
+ assoc_substs,
ty,
msg,
);
db,
self.def_span(def_id),
&assoc,
+ proj_ty.trait_ref_and_own_substs(self).1,
values.found,
&msg,
) {
trait_ref: &ty::TraitRef<'tcx>,
bounds: hir::GenericBounds<'_>,
assoc: &ty::AssocItem,
+ assoc_substs: &[ty::GenericArg<'tcx>],
ty: Ty<'tcx>,
msg: &str,
) -> bool {
// Relate the type param against `T` in `<A as T>::Foo`.
ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
&& self.constrain_associated_type_structured_suggestion(
- db, ptr.span, assoc, ty, msg,
+ db,
+ ptr.span,
+ assoc,
+ assoc_substs,
+ ty,
+ msg,
)
}
_ => false,
db: &mut DiagnosticBuilder<'_>,
span: Span,
assoc: &ty::AssocItem,
+ assoc_substs: &[ty::GenericArg<'tcx>],
ty: Ty<'tcx>,
msg: &str,
) -> bool {
let span = Span::new(pos, pos, span.ctxt());
(span, format!(", {} = {}", assoc.ident, ty))
} else {
- (span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty))
+ let item_args = self.format_generic_args(assoc_substs);
+ (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty))
};
db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
return true;
}
false
}
+
+ fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
+ let mut item_args = String::new();
+ FmtPrinter::new(self, &mut item_args, hir::def::Namespace::TypeNS)
+ .path_generic_args(Ok, args)
+ .expect("could not write to `String`.");
+ item_args
+ }
}
self.skip_binder().projection_ty.item_def_id
}
+ /// Returns the `DefId` of the trait of the associated item being projected.
#[inline]
- pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
+ pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
+ self.skip_binder().projection_ty.trait_def_id(tcx)
+ }
+
+ #[inline]
+ pub fn projection_self_ty(&self) -> Binder<Ty<'tcx>> {
+ self.map_bound(|predicate| predicate.projection_ty.self_ty())
+ }
+
+ /// Get the [PolyTraitRef] required for this projection to be well formed.
+ /// Note that for generic associated types the predicates of the associated
+ /// type also need to be checked.
+ #[inline]
+ pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
// Note: unlike with `TraitRef::to_poly_trait_ref()`,
// `self.0.trait_ref` is permitted to have escaping regions.
// This is because here `self` has a `Binder` and so does our
return Ok(self);
}
- return Ok(with_no_queries(|| {
+ return with_no_queries(|| {
let def_key = self.tcx().def_key(def_id);
if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
p!(write("{}", name));
p!(" Sized");
}
Ok(self)
- })?);
+ });
}
ty::Str => p!("str"),
ty::Generator(did, substs, movability) => {
p!(write("{:?}", char::try_from(int).unwrap()))
}
// Raw pointers
- (Scalar::Int(int), ty::RawPtr(_)) => {
+ (Scalar::Int(int), ty::RawPtr(_) | ty::FnPtr(_)) => {
let data = int.assert_bits(self.tcx().data_layout.pointer_size);
self = self.typed_value(
|mut this| {
)?;
}
(Scalar::Ptr(ptr), ty::FnPtr(_)) => {
- // FIXME: this can ICE when the ptr is dangling or points to a non-function.
- // We should probably have a helper method to share code with the "Byte strings"
+ // FIXME: We should probably have a helper method to share code with the "Byte strings"
// printing above (which also has to handle pointers to all sorts of things).
- let instance = self.tcx().global_alloc(ptr.alloc_id).unwrap_fn();
- self = self.typed_value(
- |this| this.print_value_path(instance.def_id(), instance.substs),
- |this| this.print_type(ty),
- " as ",
- )?;
+ match self.tcx().get_global_alloc(ptr.alloc_id) {
+ Some(GlobalAlloc::Function(instance)) => {
+ self = self.typed_value(
+ |this| this.print_value_path(instance.def_id(), instance.substs),
+ |this| this.print_type(ty),
+ " as ",
+ )?;
+ }
+ _ => self = self.pretty_print_const_pointer(ptr, ty, print_ty)?,
+ }
}
// For function type zsts just printing the path is enough
(Scalar::Int(int), ty::FnDef(d, s)) if int == ScalarInt::ZST => {
if cfg!(debug_assertions) {
let hits: usize = queries.iter().map(|s| s.cache_hits).sum();
let results: usize = queries.iter().map(|s| s.entry_count).sum();
- println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
+ eprintln!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
}
let mut query_key_sizes = queries.clone();
query_key_sizes.sort_by_key(|q| q.key_size);
- println!("\nLarge query keys:");
+ eprintln!("\nLarge query keys:");
for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) {
- println!(" {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
+ eprintln!(" {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
}
let mut query_value_sizes = queries.clone();
query_value_sizes.sort_by_key(|q| q.value_size);
- println!("\nLarge query values:");
+ eprintln!("\nLarge query values:");
for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) {
- println!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
+ eprintln!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
}
if cfg!(debug_assertions) {
let mut query_cache_hits = queries.clone();
query_cache_hits.sort_by_key(|q| q.cache_hits);
- println!("\nQuery cache hits:");
+ eprintln!("\nQuery cache hits:");
for q in query_cache_hits.iter().rev() {
- println!(
+ eprintln!(
" {} - {} ({}%)",
q.name,
q.cache_hits,
let mut query_value_count = queries.clone();
query_value_count.sort_by_key(|q| q.entry_count);
- println!("\nQuery value count:");
+ eprintln!("\nQuery value count:");
for q in query_value_count.iter().rev() {
- println!(" {} - {}", q.name, q.entry_count);
+ eprintln!(" {} - {}", q.name, q.entry_count);
}
let mut def_id_density: Vec<_> =
queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect();
def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap());
- println!("\nLocal DefId density:");
+ eprintln!("\nLocal DefId density:");
let total = tcx.hir().definitions().def_index_count() as f64;
for q in def_id_density.iter().rev() {
let local = q.local_def_id_keys.unwrap();
- println!(" {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
+ eprintln!(" {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
}
}
relation.relate_with_variance(variance, a, b)
});
- Ok(tcx.mk_substs(params)?)
+ tcx.mk_substs(params)
}
impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
_ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))),
}
});
- Ok(tcx.mk_poly_existential_predicates(v)?)
+ tcx.mk_poly_existential_predicates(v)
}
}
use rustc_hir::def_id::DefId;
use rustc_index::vec::Idx;
use rustc_macros::HashStable;
-use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::symbol::{kw, Symbol};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi;
use std::borrow::Cow;
}
impl<'tcx> ProjectionTy<'tcx> {
- /// Construct a `ProjectionTy` by searching the trait from `trait_ref` for the
- /// associated item named `item_name`.
- pub fn from_ref_and_name(
- tcx: TyCtxt<'_>,
- trait_ref: ty::TraitRef<'tcx>,
- item_name: Ident,
- ) -> ProjectionTy<'tcx> {
- let item_def_id = tcx
- .associated_items(trait_ref.def_id)
- .find_by_name_and_kind(tcx, item_name, ty::AssocKind::Type, trait_ref.def_id)
- .unwrap()
- .def_id;
+ pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
+ tcx.associated_item(self.item_def_id).container.id()
+ }
- ProjectionTy { substs: trait_ref.substs, item_def_id }
+ /// Extracts the underlying trait reference and own substs from this projection.
+ /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
+ /// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
+ pub fn trait_ref_and_own_substs(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
+ let def_id = tcx.associated_item(self.item_def_id).container.id();
+ let trait_generics = tcx.generics_of(def_id);
+ (
+ ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
+ &self.substs[trait_generics.count()..],
+ )
}
/// Extracts the underlying trait reference from this projection.
/// For example, if this is a projection of `<T as Iterator>::Item`,
/// then this function would return a `T: Iterator` trait reference.
+ ///
+ /// WARNING: This will drop the substs for generic associated types
+ /// consider calling [Self::trait_ref_and_own_substs] to get those
+ /// as well.
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
- // FIXME: This method probably shouldn't exist at all, since it's not
- // clear what this method really intends to do. Be careful when
- // using this method since the resulting TraitRef additionally
- // contains the substs for the assoc_item, which strictly speaking
- // is not correct
- let def_id = tcx.associated_item(self.item_def_id).container.id();
- // Include substitutions for generic arguments of associated types
- let assoc_item = tcx.associated_item(self.item_def_id);
- let substs_assoc_item = self.substs.truncate_to(tcx, tcx.generics_of(assoc_item.def_id));
- ty::TraitRef { def_id, substs: substs_assoc_item }
+ let def_id = self.trait_def_id(tcx);
+ ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
}
pub fn self_ty(&self) -> Ty<'tcx> {
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
/// then this function would return a `exists T. T: Iterator` existential trait
/// reference.
- pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::ExistentialTraitRef<'tcx> {
- // FIXME(generic_associated_types): substs is the substs of the
- // associated type, which should be truncated to get the correct substs
- // for the trait.
+ pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
let def_id = tcx.associated_item(self.item_def_id).container.id();
- ty::ExistentialTraitRef { def_id, substs: self.substs }
+ let subst_count = tcx.generics_of(def_id).count() - 1;
+ let substs = tcx.intern_substs(&self.substs[..subst_count]);
+ ty::ExistentialTraitRef { def_id, substs }
}
pub fn with_self_ty(
ty: self.ty,
}
}
+
+ pub fn erase_self_ty(
+ tcx: TyCtxt<'tcx>,
+ projection_predicate: ty::ProjectionPredicate<'tcx>,
+ ) -> Self {
+ // Assert there is a Self.
+ projection_predicate.projection_ty.substs.type_at(0);
+
+ Self {
+ item_def_id: projection_predicate.projection_ty.item_def_id,
+ substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
+ ty: projection_predicate.ty,
+ }
+ }
}
impl<'tcx> PolyExistentialProjection<'tcx> {
}
}
+ /// Returns the type of metadata for (potentially fat) pointers to this type.
+ pub fn ptr_metadata_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+ // FIXME: should this normalize?
+ let tail = tcx.struct_tail_without_normalization(self);
+ match tail.kind() {
+ // Sized types
+ ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+ | ty::Uint(_)
+ | ty::Int(_)
+ | ty::Bool
+ | ty::Float(_)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::RawPtr(..)
+ | ty::Char
+ | ty::Ref(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::Array(..)
+ | ty::Closure(..)
+ | ty::Never
+ | ty::Error(_)
+ | ty::Foreign(..)
+ // If returned by `struct_tail_without_normalization` this is a unit struct
+ // without any fields, or not a struct, and therefore is Sized.
+ | ty::Adt(..)
+ // If returned by `struct_tail_without_normalization` this is the empty tuple,
+ // a.k.a. unit type, which is Sized
+ | ty::Tuple(..) => tcx.types.unit,
+
+ ty::Str | ty::Slice(_) => tcx.types.usize,
+ ty::Dynamic(..) => {
+ let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
+ tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()])
+ },
+
+ ty::Projection(_)
+ | ty::Param(_)
+ | ty::Opaque(..)
+ | ty::Infer(ty::TyVar(_))
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+ bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail)
+ }
+ }
+ }
+
/// When we create a closure, we record its kind (i.e., what trait
/// it implements) into its `ClosureSubsts` using a type
/// parameter. This is kind of a phantom type, except that the
ecx.push_stack_frame(
cid.instance,
body,
- Some(ret.into()),
+ Some(&ret.into()),
StackPopCleanup::None { cleanup: false },
)?;
None => InternKind::Constant,
}
};
- intern_const_alloc_recursive(ecx, intern_kind, ret)?;
+ intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
debug!("eval_body_using_ecx done: {:?}", *ret);
Ok(ret)
/// type system.
pub(super) fn op_to_const<'tcx>(
ecx: &CompileTimeEvalContext<'_, 'tcx>,
- op: OpTy<'tcx>,
+ op: &OpTy<'tcx>,
) -> ConstValue<'tcx> {
// We do not have value optimizations for everything.
// Only scalars and slices, since they are very common.
op.try_as_mplace(ecx)
};
- let to_const_value = |mplace: MPlaceTy<'_>| match mplace.ptr {
+ let to_const_value = |mplace: &MPlaceTy<'_>| match mplace.ptr {
Scalar::Ptr(ptr) => {
let alloc = ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory();
ConstValue::ByRef { alloc, offset: ptr.offset }
}
};
match immediate {
- Ok(mplace) => to_const_value(mplace),
+ Ok(ref mplace) => to_const_value(mplace),
// see comment on `let try_as_immediate` above
Err(imm) => match *imm {
Immediate::Scalar(x) => match x {
ScalarMaybeUninit::Scalar(s) => ConstValue::Scalar(s),
- ScalarMaybeUninit::Uninit => to_const_value(op.assert_mem_place(ecx)),
+ ScalarMaybeUninit::Uninit => to_const_value(&op.assert_mem_place(ecx)),
},
Immediate::ScalarPair(a, b) => {
let (data, start) = match a.check_init().unwrap() {
"the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead"
);
// Turn this into a proper constant.
- op_to_const(&ecx, mplace.into())
+ op_to_const(&ecx, &mplace.into())
}
pub fn eval_to_const_value_raw_provider<'tcx>(
Some(_) => CtfeValidationMode::Regular, // a `static`
None => CtfeValidationMode::Const { inner, allow_static_ptrs: false },
};
- ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?;
+ ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
inner = true;
}
};
// &str
assert!(args.len() == 1);
- let msg_place = self.deref_operand(args[0])?;
- let msg = Symbol::intern(self.read_str(msg_place)?);
+ let msg_place = self.deref_operand(&args[0])?;
+ let msg = Symbol::intern(self.read_str(&msg_place)?);
let span = self.find_closest_untracked_caller_location();
let (file, line, col) = self.location_triple_for_span(span);
Err(ConstEvalErrKind::Panic { msg, file, line, col }.into())
instance: ty::Instance<'tcx>,
_abi: Abi,
args: &[OpTy<'tcx>],
- _ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
+ _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
_unwind: Option<mir::BasicBlock>, // unwinding is not supported in consts
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
debug!("find_mir_or_eval_fn: {:?}", instance);
ecx: &mut InterpCx<'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
- ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
+ ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
_unwind: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
// Shared intrinsics.
};
match intrinsic_name {
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
- let a = ecx.read_immediate(args[0])?.to_scalar()?;
- let b = ecx.read_immediate(args[1])?.to_scalar()?;
+ let a = ecx.read_immediate(&args[0])?.to_scalar()?;
+ let b = ecx.read_immediate(&args[1])?.to_scalar()?;
let cmp = if intrinsic_name == sym::ptr_guaranteed_eq {
ecx.guaranteed_eq(a, b)
} else {
ecx.write_scalar(Scalar::from_bool(cmp), dest)?;
}
sym::const_allocate => {
- let size = ecx.read_scalar(args[0])?.to_machine_usize(ecx)?;
- let align = ecx.read_scalar(args[1])?.to_machine_usize(ecx)?;
+ let size = ecx.read_scalar(&args[0])?.to_machine_usize(ecx)?;
+ let align = ecx.read_scalar(&args[1])?.to_machine_usize(ecx)?;
let align = match Align::from_bytes(align) {
Ok(a) => a,
use rustc_middle::mir::AssertKind::*;
// Convert `AssertKind<Operand>` to `AssertKind<Scalar>`.
let eval_to_int =
- |op| ecx.read_immediate(ecx.eval_operand(op, None)?).map(|x| x.to_const_int());
+ |op| ecx.read_immediate(&ecx.eval_operand(op, None)?).map(|x| x.to_const_int());
let err = match msg {
BoundsCheck { ref len, ref index } => {
let len = eval_to_int(len)?;
fn binary_ptr_op(
_ecx: &InterpCx<'mir, 'tcx, Self>,
_bin_op: mir::BinOp,
- _left: ImmTy<'tcx>,
- _right: ImmTy<'tcx>,
+ _left: &ImmTy<'tcx>,
+ _right: &ImmTy<'tcx>,
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into())
}
fn box_alloc(
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
- _dest: PlaceTy<'tcx>,
+ _dest: &PlaceTy<'tcx>,
) -> InterpResult<'tcx> {
Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into())
}
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false);
let loc_place = ecx.alloc_caller_location(file, line, col);
- if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place).is_err() {
+ 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(loc_place.ptr)
return mir::DestructuredConst { variant: None, fields: &[] };
}
ty::Adt(def, _) => {
- let variant = ecx.read_discriminant(op).unwrap().1;
- let down = ecx.operand_downcast(op, variant).unwrap();
+ let variant = ecx.read_discriminant(&op).unwrap().1;
+ let down = ecx.operand_downcast(&op, variant).unwrap();
(def.variants[variant].fields.len(), Some(variant), down)
}
ty::Tuple(substs) => (substs.len(), None, op),
};
let fields_iter = (0..field_count).map(|i| {
- let field_op = ecx.operand_field(down, i).unwrap();
- let val = op_to_const(&ecx, field_op);
+ let field_op = ecx.operand_field(&down, i).unwrap();
+ let val = op_to_const(&ecx, &field_op);
ty::Const::from_value(tcx, val, field_op.layout.ty)
});
let fields = tcx.arena.alloc_from_iter(fields_iter);
trace!("deref_const: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
let op = ecx.const_to_op(val, None).unwrap();
- let mplace = ecx.deref_operand(op).unwrap();
+ let mplace = ecx.deref_operand(&op).unwrap();
if let Scalar::Ptr(ptr) = mplace.ptr {
assert_eq!(
ecx.memory.get_raw(ptr.alloc_id).unwrap().mutability,
},
};
- tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, mplace.into())), ty })
+ tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
}
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
pub fn cast(
&mut self,
- src: OpTy<'tcx, M::PointerTag>,
+ src: &OpTy<'tcx, M::PointerTag>,
cast_kind: CastKind,
cast_ty: Ty<'tcx>,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
use rustc_middle::mir::CastKind::*;
// FIXME: In which cases should we trigger UB when the source is uninit?
Misc => {
let src = self.read_immediate(src)?;
- let res = self.misc_cast(src, cast_ty)?;
+ let res = self.misc_cast(&src, cast_ty)?;
self.write_immediate(res, dest)?;
}
fn misc_cast(
&self,
- src: ImmTy<'tcx, M::PointerTag>,
+ src: &ImmTy<'tcx, M::PointerTag>,
cast_ty: Ty<'tcx>,
) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
use rustc_middle::ty::TyKind::*;
let dest_layout = self.layout_of(cast_ty)?;
if dest_layout.size == src.layout.size {
// Thin or fat pointer that just hast the ptr kind of target type changed.
- return Ok(*src);
+ return Ok(**src);
} else {
// Casting the metadata away from a fat ptr.
assert_eq!(src.layout.size, 2 * self.memory.pointer_size());
assert_eq!(dest_layout.size, self.memory.pointer_size());
assert!(src.layout.ty.is_unsafe_ptr());
- return match *src {
+ return match **src {
Immediate::ScalarPair(data, _) => Ok(data.into()),
Immediate::Scalar(..) => span_bug!(
self.cur_span(),
fn unsize_into_ptr(
&mut self,
- src: OpTy<'tcx, M::PointerTag>,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ src: &OpTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
// The pointee types
source_ty: Ty<'tcx>,
cast_ty: Ty<'tcx>,
fn unsize_into(
&mut self,
- src: OpTy<'tcx, M::PointerTag>,
+ src: &OpTy<'tcx, M::PointerTag>,
cast_ty: TyAndLayout<'tcx>,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty);
match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
let src_field = self.operand_field(src, i)?;
let dst_field = self.place_field(dest, i)?;
if src_field.layout.ty == cast_ty_field.ty {
- self.copy_op(src_field, dst_field)?;
+ self.copy_op(&src_field, &dst_field)?;
} else {
- self.unsize_into(src_field, cast_ty_field, dst_field)?;
+ self.unsize_into(&src_field, cast_ty_field, &dst_field)?;
}
}
Ok(())
/// This can fail to provide an answer for extern types.
pub(super) fn size_and_align_of(
&self,
- metadata: MemPlaceMeta<M::PointerTag>,
- layout: TyAndLayout<'tcx>,
+ metadata: &MemPlaceMeta<M::PointerTag>,
+ layout: &TyAndLayout<'tcx>,
) -> InterpResult<'tcx, Option<(Size, Align)>> {
if !layout.is_unsized() {
return Ok(Some((layout.size, layout.align.abi)));
// the last field). Can't have foreign types here, how would we
// adjust alignment and size for them?
let field = layout.field(self, layout.fields.count() - 1)?;
- let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? {
- Some(size_and_align) => size_and_align,
- None => {
- // A field with extern type. If this field is at offset 0, we behave
- // like the underlying extern type.
- // FIXME: Once we have made decisions for how to handle size and alignment
- // of `extern type`, this should be adapted. It is just a temporary hack
- // to get some code to work that probably ought to work.
- if sized_size == Size::ZERO {
- return Ok(None);
- } else {
- span_bug!(
- self.cur_span(),
- "Fields cannot be extern types, unless they are at offset 0"
- )
+ let (unsized_size, unsized_align) =
+ match self.size_and_align_of(metadata, &field)? {
+ Some(size_and_align) => size_and_align,
+ None => {
+ // A field with extern type. If this field is at offset 0, we behave
+ // like the underlying extern type.
+ // FIXME: Once we have made decisions for how to handle size and alignment
+ // of `extern type`, this should be adapted. It is just a temporary hack
+ // to get some code to work that probably ought to work.
+ if sized_size == Size::ZERO {
+ return Ok(None);
+ } else {
+ span_bug!(
+ self.cur_span(),
+ "Fields cannot be extern types, unless they are at offset 0"
+ )
+ }
}
- }
- };
+ };
// FIXME (#26403, #27023): We should be adding padding
// to `sized_size` (to accommodate the `unsized_align`
#[inline]
pub fn size_and_align_of_mplace(
&self,
- mplace: MPlaceTy<'tcx, M::PointerTag>,
+ mplace: &MPlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, Option<(Size, Align)>> {
- self.size_and_align_of(mplace.meta, mplace.layout)
+ self.size_and_align_of(&mplace.meta, &mplace.layout)
}
pub fn push_stack_frame(
&mut self,
instance: ty::Instance<'tcx>,
body: &'mir mir::Body<'tcx>,
- return_place: Option<PlaceTy<'tcx, M::PointerTag>>,
+ return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
return_to_block: StackPopCleanup,
) -> InterpResult<'tcx> {
// first push a stack frame so we have access to the local substs
body,
loc: Err(body.span), // Span used for errors caused during preamble.
return_to_block,
- return_place,
+ return_place: return_place.copied(),
// empty local array, we fill it in below, after we are inside the stack frame and
// all methods actually know about the frame
locals: IndexVec::new(),
if !unwinding {
// Copy the return value to the caller's stack frame.
- if let Some(return_place) = frame.return_place {
+ if let Some(ref return_place) = frame.return_place {
let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
- self.copy_op_transmute(op, return_place)?;
- trace!("{:?}", self.dump_place(*return_place));
+ self.copy_op_transmute(&op, return_place)?;
+ trace!("{:?}", self.dump_place(**return_place));
} else {
throw_ub!(Unreachable);
}
fn visit_aggregate(
&mut self,
- mplace: MPlaceTy<'tcx>,
+ mplace: &MPlaceTy<'tcx>,
fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>,
) -> InterpResult<'tcx> {
// ZSTs cannot contain pointers, so we can skip them.
self.walk_aggregate(mplace, fields)
}
- fn visit_value(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
+ fn visit_value(&mut self, mplace: &MPlaceTy<'tcx>) -> InterpResult<'tcx> {
// Handle Reference types, as these are the only relocations supported by const eval.
// Raw pointers (and boxes) are handled by the `leftover_relocations` logic.
let tcx = self.ecx.tcx;
let ty = mplace.layout.ty;
if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() {
- let value = self.ecx.read_immediate(mplace.into())?;
- let mplace = self.ecx.ref_to_mplace(value)?;
+ let value = self.ecx.read_immediate(&(*mplace).into())?;
+ let mplace = self.ecx.ref_to_mplace(&value)?;
assert_eq!(mplace.layout.ty, referenced_ty);
// Handle trait object vtables.
if let ty::Dynamic(..) =
pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>(
ecx: &mut InterpCx<'mir, 'tcx, M>,
intern_kind: InternKind,
- ret: MPlaceTy<'tcx>,
+ ret: &MPlaceTy<'tcx>,
) -> Result<(), ErrorReported>
where
'tcx: 'mir,
Some(ret.layout.ty),
);
- ref_tracking.track((ret, base_intern_mode), || ());
+ ref_tracking.track((*ret, base_intern_mode), || ());
while let Some(((mplace, mode), _)) = ref_tracking.todo.pop() {
let res = InternVisitor {
leftover_allocations,
inside_unsafe_cell: false,
}
- .visit_value(mplace);
+ .visit_value(&mplace);
// We deliberately *ignore* interpreter errors here. When there is a problem, the remaining
// references are "leftover"-interned, and later validation will show a proper error
// and point at the right part of the value causing the problem.
layout: TyAndLayout<'tcx>,
f: impl FnOnce(
&mut InterpCx<'mir, 'tcx, M>,
- MPlaceTy<'tcx, M::PointerTag>,
+ &MPlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, ()>,
) -> InterpResult<'tcx, &'tcx Allocation> {
let dest = self.allocate(layout, MemoryKind::Stack);
- f(self, dest)?;
+ f(self, &dest)?;
let ptr = dest.ptr.assert_ptr();
assert_eq!(ptr.offset, Size::ZERO);
let mut alloc = self.memory.alloc_map.remove(&ptr.alloc_id).unwrap().1;
&mut self,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx, M::PointerTag>],
- ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
+ ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
) -> InterpResult<'tcx, bool> {
let substs = instance.substs;
let intrinsic_name = self.tcx.item_name(instance.def_id());
sym::min_align_of_val | sym::size_of_val => {
// Avoid `deref_operand` -- this is not a deref, the ptr does not have to be
// dereferencable!
- let place = self.ref_to_mplace(self.read_immediate(args[0])?)?;
+ let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
let (size, align) = self
- .size_and_align_of_mplace(place)?
+ .size_and_align_of_mplace(&place)?
.ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?;
let result = match intrinsic_name {
self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?;
let const_ = ty::Const { val: ty::ConstKind::Value(val), ty };
let val = self.const_to_op(&const_, None)?;
- self.copy_op(val, dest)?;
+ self.copy_op(&val, dest)?;
}
sym::ctpop
| sym::bitreverse => {
let ty = substs.type_at(0);
let layout_of = self.layout_of(ty)?;
- let val = self.read_scalar(args[0])?.check_init()?;
+ let val = self.read_scalar(&args[0])?.check_init()?;
let bits = self.force_bits(val, layout_of.size)?;
let kind = match layout_of.abi {
Abi::Scalar(ref scalar) => scalar.value,
self.write_scalar(out_val, dest)?;
}
sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
- let lhs = self.read_immediate(args[0])?;
- let rhs = self.read_immediate(args[1])?;
+ let lhs = self.read_immediate(&args[0])?;
+ let rhs = self.read_immediate(&args[1])?;
let bin_op = match intrinsic_name {
sym::add_with_overflow => BinOp::Add,
sym::sub_with_overflow => BinOp::Sub,
sym::mul_with_overflow => BinOp::Mul,
_ => bug!("Already checked for int ops"),
};
- self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
+ self.binop_with_overflow(bin_op, &lhs, &rhs, dest)?;
}
sym::saturating_add | sym::saturating_sub => {
- let l = self.read_immediate(args[0])?;
- let r = self.read_immediate(args[1])?;
+ let l = self.read_immediate(&args[0])?;
+ let r = self.read_immediate(&args[1])?;
let is_add = intrinsic_name == sym::saturating_add;
- let (val, overflowed, _ty) =
- self.overflowing_binary_op(if is_add { BinOp::Add } else { BinOp::Sub }, l, r)?;
+ let (val, overflowed, _ty) = self.overflowing_binary_op(
+ if is_add { BinOp::Add } else { BinOp::Sub },
+ &l,
+ &r,
+ )?;
let val = if overflowed {
let num_bits = l.layout.size.bits();
if l.layout.abi.is_signed() {
self.write_scalar(val, dest)?;
}
sym::discriminant_value => {
- let place = self.deref_operand(args[0])?;
- let discr_val = self.read_discriminant(place.into())?.0;
+ let place = self.deref_operand(&args[0])?;
+ let discr_val = self.read_discriminant(&place.into())?.0;
self.write_scalar(discr_val, dest)?;
}
sym::unchecked_shl
| sym::unchecked_mul
| sym::unchecked_div
| sym::unchecked_rem => {
- let l = self.read_immediate(args[0])?;
- let r = self.read_immediate(args[1])?;
+ let l = self.read_immediate(&args[0])?;
+ let r = self.read_immediate(&args[1])?;
let bin_op = match intrinsic_name {
sym::unchecked_shl => BinOp::Shl,
sym::unchecked_shr => BinOp::Shr,
sym::unchecked_rem => BinOp::Rem,
_ => bug!("Already checked for int ops"),
};
- let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?;
+ let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?;
if overflowed {
let layout = self.layout_of(substs.type_at(0))?;
let r_val = self.force_bits(r.to_scalar()?, layout.size)?;
// rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
// rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
let layout = self.layout_of(substs.type_at(0))?;
- let val = self.read_scalar(args[0])?.check_init()?;
+ let val = self.read_scalar(&args[0])?.check_init()?;
let val_bits = self.force_bits(val, layout.size)?;
- let raw_shift = self.read_scalar(args[1])?.check_init()?;
+ let raw_shift = self.read_scalar(&args[1])?.check_init()?;
let raw_shift_bits = self.force_bits(raw_shift, layout.size)?;
let width_bits = u128::from(layout.size.bits());
let shift_bits = raw_shift_bits % width_bits;
sym::copy | sym::copy_nonoverlapping => {
let elem_ty = instance.substs.type_at(0);
let elem_layout = self.layout_of(elem_ty)?;
- let count = self.read_scalar(args[2])?.to_machine_usize(self)?;
+ let count = self.read_scalar(&args[2])?.to_machine_usize(self)?;
let elem_align = elem_layout.align.abi;
let size = elem_layout.size.checked_mul(count, self).ok_or_else(|| {
err_ub_format!("overflow computing total size of `{}`", intrinsic_name)
})?;
- let src = self.read_scalar(args[0])?.check_init()?;
+ let src = self.read_scalar(&args[0])?.check_init()?;
let src = self.memory.check_ptr_access(src, size, elem_align)?;
- let dest = self.read_scalar(args[1])?.check_init()?;
+ let dest = self.read_scalar(&args[1])?.check_init()?;
let dest = self.memory.check_ptr_access(dest, size, elem_align)?;
if let (Some(src), Some(dest)) = (src, dest) {
}
}
sym::offset => {
- let ptr = self.read_scalar(args[0])?.check_init()?;
- let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
+ let ptr = self.read_scalar(&args[0])?.check_init()?;
+ let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?;
let pointee_ty = substs.type_at(0);
let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?;
self.write_scalar(offset_ptr, dest)?;
}
sym::arith_offset => {
- let ptr = self.read_scalar(args[0])?.check_init()?;
- let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
+ let ptr = self.read_scalar(&args[0])?.check_init()?;
+ let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?;
let pointee_ty = substs.type_at(0);
let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
self.write_scalar(offset_ptr, dest)?;
}
sym::ptr_offset_from => {
- let a = self.read_immediate(args[0])?.to_scalar()?;
- let b = self.read_immediate(args[1])?.to_scalar()?;
+ let a = self.read_immediate(&args[0])?.to_scalar()?;
+ let b = self.read_immediate(&args[1])?.to_scalar()?;
// Special case: if both scalars are *equal integers*
// and not NULL, we pretend there is an allocation of size 0 right there,
let a_offset = ImmTy::from_uint(a.offset.bytes(), usize_layout);
let b_offset = ImmTy::from_uint(b.offset.bytes(), usize_layout);
let (val, _overflowed, _ty) =
- self.overflowing_binary_op(BinOp::Sub, a_offset, b_offset)?;
+ self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
let pointee_layout = self.layout_of(substs.type_at(0))?;
let val = ImmTy::from_scalar(val, isize_layout);
let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
- self.exact_div(val, size, dest)?;
+ self.exact_div(&val, &size, dest)?;
}
}
sym::transmute => {
- self.copy_op_transmute(args[0], dest)?;
+ self.copy_op_transmute(&args[0], dest)?;
}
sym::assert_inhabited => {
let ty = instance.substs.type_at(0);
}
}
sym::simd_insert => {
- let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
- let elem = args[2];
- let input = args[0];
+ let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
+ let elem = &args[2];
+ let input = &args[0];
let (len, e_ty) = input.layout.ty.simd_size_and_type(*self.tcx);
assert!(
index < len,
for i in 0..len {
let place = self.place_index(dest, i)?;
- let value = if i == index { elem } else { self.operand_index(input, i)? };
- self.copy_op(value, place)?;
+ let value = if i == index { *elem } else { self.operand_index(input, i)? };
+ self.copy_op(&value, &place)?;
}
}
sym::simd_extract => {
- let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
+ let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
let (len, e_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx);
assert!(
index < len,
"Return type `{}` must match vector element type `{}`",
dest.layout.ty, e_ty
);
- self.copy_op(self.operand_index(args[0], index)?, dest)?;
+ self.copy_op(&self.operand_index(&args[0], index)?, dest)?;
}
sym::likely | sym::unlikely => {
// These just return their argument
- self.copy_op(args[0], dest)?;
+ self.copy_op(&args[0], dest)?;
}
sym::assume => {
- let cond = self.read_scalar(args[0])?.check_init()?.to_bool()?;
+ let cond = self.read_scalar(&args[0])?.check_init()?.to_bool()?;
if !cond {
throw_ub_format!("`assume` intrinsic called with `false`");
}
_ => return Ok(false),
}
- trace!("{:?}", self.dump_place(*dest));
+ trace!("{:?}", self.dump_place(**dest));
self.go_to_block(ret);
Ok(true)
}
pub fn exact_div(
&mut self,
- a: ImmTy<'tcx, M::PointerTag>,
- b: ImmTy<'tcx, M::PointerTag>,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ a: &ImmTy<'tcx, M::PointerTag>,
+ b: &ImmTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
// Performs an exact division, resulting in undefined behavior where
// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`.
// First, check x % y != 0 (or if that computation overflows).
- let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, a, b)?;
+ let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?;
if overflow || res.assert_bits(a.layout.size) != 0 {
// Then, check if `b` is -1, which is the "MIN / -1" case.
let minus1 = Scalar::from_int(-1, dest.layout.size);
}
}
// `Rem` says this is all right, so we can let `Div` do its job.
- self.binop_ignore_overflow(BinOp::Div, a, b, dest)
+ self.binop_ignore_overflow(BinOp::Div, &a, &b, dest)
}
/// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
let location = self.allocate(loc_layout, MemoryKind::CallerLocation);
// Initialize fields.
- self.write_immediate(file.to_ref(), self.mplace_field(location, 0).unwrap().into())
+ self.write_immediate(file.to_ref(), &self.mplace_field(&location, 0).unwrap().into())
.expect("writing to memory we just allocated cannot fail");
- self.write_scalar(line, self.mplace_field(location, 1).unwrap().into())
+ self.write_scalar(line, &self.mplace_field(&location, 1).unwrap().into())
.expect("writing to memory we just allocated cannot fail");
- self.write_scalar(col, self.mplace_field(location, 2).unwrap().into())
+ self.write_scalar(col, &self.mplace_field(&location, 2).unwrap().into())
.expect("writing to memory we just allocated cannot fail");
location
instance: ty::Instance<'tcx>,
abi: Abi,
args: &[OpTy<'tcx, Self::PointerTag>],
- ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
+ ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
unwind: Option<mir::BasicBlock>,
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;
fn_val: Self::ExtraFnVal,
abi: Abi,
args: &[OpTy<'tcx, Self::PointerTag>],
- ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
+ ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
unwind: Option<mir::BasicBlock>,
) -> InterpResult<'tcx>;
ecx: &mut InterpCx<'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx, Self::PointerTag>],
- ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
+ ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
unwind: Option<mir::BasicBlock>,
) -> InterpResult<'tcx>;
fn binary_ptr_op(
ecx: &InterpCx<'mir, 'tcx, Self>,
bin_op: mir::BinOp,
- left: ImmTy<'tcx, Self::PointerTag>,
- right: ImmTy<'tcx, Self::PointerTag>,
+ left: &ImmTy<'tcx, Self::PointerTag>,
+ right: &ImmTy<'tcx, Self::PointerTag>,
) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>;
/// Heap allocations via the `box` keyword.
fn box_alloc(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
- dest: PlaceTy<'tcx, Self::PointerTag>,
+ dest: &PlaceTy<'tcx, Self::PointerTag>,
) -> InterpResult<'tcx>;
/// Called to read the specified `local` from the `frame`.
fn retag(
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_kind: mir::RetagKind,
- _place: PlaceTy<'tcx, Self::PointerTag>,
+ _place: &PlaceTy<'tcx, Self::PointerTag>,
) -> InterpResult<'tcx> {
Ok(())
}
fn_val: !,
_abi: Abi,
_args: &[OpTy<$tcx>],
- _ret: Option<(PlaceTy<$tcx>, mir::BasicBlock)>,
+ _ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>,
_unwind: Option<mir::BasicBlock>,
) -> InterpResult<$tcx> {
match fn_val {}
ScalarPair(ScalarMaybeUninit<Tag>, ScalarMaybeUninit<Tag>),
}
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(Immediate, 56);
+
impl<Tag> From<ScalarMaybeUninit<Tag>> for Immediate<Tag> {
#[inline(always)]
fn from(val: ScalarMaybeUninit<Tag>) -> Self {
pub layout: TyAndLayout<'tcx>,
}
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(ImmTy<'_>, 72);
+
impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
/// Helper function for printing a scalar to a FmtPrinter
}
ScalarMaybeUninit::Uninit => cx.typed_value(
|mut this| {
- this.write_str("{uninit ")?;
+ this.write_str("uninit ")?;
Ok(this)
},
|this| this.print_type(ty),
pub layout: TyAndLayout<'tcx>,
}
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(OpTy<'_, ()>, 80);
+
impl<'tcx, Tag> std::ops::Deref for OpTy<'tcx, Tag> {
type Target = Operand<Tag>;
#[inline(always)]
}
}
+impl<'tcx, Tag: Copy> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
+ #[inline(always)]
+ fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self {
+ OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout }
+ }
+}
+
impl<'tcx, Tag> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
#[inline(always)]
fn from(val: ImmTy<'tcx, Tag>) -> Self {
#[inline]
pub fn force_op_ptr(
&self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
match op.try_as_mplace(self) {
Ok(mplace) => Ok(self.force_mplace_ptr(mplace)?.into()),
/// Returns `None` if the layout does not permit loading this as a value.
fn try_read_immediate_from_mplace(
&self,
- mplace: MPlaceTy<'tcx, M::PointerTag>,
+ mplace: &MPlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::PointerTag>>> {
if mplace.layout.is_unsized() {
// Don't touch unsized
/// in a `Immediate`, not on which data is stored there currently.
pub(crate) fn try_read_immediate(
&self,
- src: OpTy<'tcx, M::PointerTag>,
+ src: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::PointerTag>, MPlaceTy<'tcx, M::PointerTag>>> {
Ok(match src.try_as_mplace(self) {
- Ok(mplace) => {
+ Ok(ref mplace) => {
if let Some(val) = self.try_read_immediate_from_mplace(mplace)? {
Ok(val)
} else {
- Err(mplace)
+ Err(*mplace)
}
}
Err(val) => Ok(val),
#[inline(always)]
pub fn read_immediate(
&self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
if let Ok(imm) = self.try_read_immediate(op)? {
Ok(imm)
/// Read a scalar from a place
pub fn read_scalar(
&self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, ScalarMaybeUninit<M::PointerTag>> {
Ok(self.read_immediate(op)?.to_scalar_or_uninit())
}
// Turn the wide MPlace into a string (must already be dereferenced!)
- pub fn read_str(&self, mplace: MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> {
+ pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> {
let len = mplace.len(self)?;
let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len))?;
let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?;
/// Projection functions
pub fn operand_field(
&self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
field: usize,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let base = match op.try_as_mplace(self) {
- Ok(mplace) => {
+ Ok(ref mplace) => {
// We can reuse the mplace field computation logic for indirect operands.
let field = self.mplace_field(mplace, field)?;
return Ok(field.into());
pub fn operand_index(
&self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
index: u64,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
if let Ok(index) = usize::try_from(index) {
} else {
// Indexing into a big array. This must be an mplace.
let mplace = op.assert_mem_place(self);
- Ok(self.mplace_index(mplace, index)?.into())
+ Ok(self.mplace_index(&mplace, index)?.into())
}
}
pub fn operand_downcast(
&self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
variant: VariantIdx,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
// Downcasts only change the layout
Ok(match op.try_as_mplace(self) {
- Ok(mplace) => self.mplace_downcast(mplace, variant)?.into(),
+ Ok(ref mplace) => self.mplace_downcast(mplace, variant)?.into(),
Err(..) => {
let layout = op.layout.for_variant(self, variant);
- OpTy { layout, ..op }
+ OpTy { layout, ..*op }
}
})
}
pub fn operand_projection(
&self,
- base: OpTy<'tcx, M::PointerTag>,
+ base: &OpTy<'tcx, M::PointerTag>,
proj_elem: mir::PlaceElem<'tcx>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
use rustc_middle::mir::ProjectionElem::*;
// The rest should only occur as mplace, we do not use Immediates for types
// allowing such operations. This matches place_projection forcing an allocation.
let mplace = base.assert_mem_place(self);
- self.mplace_projection(mplace, proj_elem)?.into()
+ self.mplace_projection(&mplace, proj_elem)?.into()
}
})
}
#[inline(always)]
pub fn place_to_op(
&self,
- place: PlaceTy<'tcx, M::PointerTag>,
+ place: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
- let op = match *place {
+ let op = match **place {
Place::Ptr(mplace) => Operand::Indirect(mplace),
Place::Local { frame, local } => {
*self.access_local(&self.stack()[frame], local, None)?
let op = place
.projection
.iter()
- .try_fold(base_op, |op, elem| self.operand_projection(op, elem))?;
+ .try_fold(base_op, |op, elem| self.operand_projection(&op, elem))?;
trace!("eval_place_to_op: got {:?}", *op);
// Sanity-check the type we ended up with.
/// Read discriminant, return the runtime value as well as the variant index.
pub fn read_discriminant(
&self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> {
trace!("read_discriminant_value {:#?}", op.layout);
// Get type and layout of the discriminant.
let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
// Read tag and sanity-check `tag_layout`.
- let tag_val = self.read_immediate(self.operand_field(op, tag_field)?)?;
+ let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?;
assert_eq!(tag_layout.size, tag_val.layout.size);
assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
let tag_val = tag_val.to_scalar()?;
let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
let variant_index_relative_val =
- self.binary_op(mir::BinOp::Sub, tag_val, niche_start_val)?;
+ self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
let variant_index_relative = variant_index_relative_val
.to_scalar()?
.assert_bits(tag_val.layout.size);
pub fn binop_with_overflow(
&mut self,
op: mir::BinOp,
- left: ImmTy<'tcx, M::PointerTag>,
- right: ImmTy<'tcx, M::PointerTag>,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ left: &ImmTy<'tcx, M::PointerTag>,
+ right: &ImmTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
- let (val, overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
+ let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?;
debug_assert_eq!(
self.tcx.intern_tup(&[ty, self.tcx.types.bool]),
dest.layout.ty,
pub fn binop_ignore_overflow(
&mut self,
op: mir::BinOp,
- left: ImmTy<'tcx, M::PointerTag>,
- right: ImmTy<'tcx, M::PointerTag>,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ left: &ImmTy<'tcx, M::PointerTag>,
+ right: &ImmTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op);
pub fn overflowing_binary_op(
&self,
bin_op: mir::BinOp,
- left: ImmTy<'tcx, M::PointerTag>,
- right: ImmTy<'tcx, M::PointerTag>,
+ left: &ImmTy<'tcx, M::PointerTag>,
+ right: &ImmTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
trace!(
"Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
pub fn binary_op(
&self,
bin_op: mir::BinOp,
- left: ImmTy<'tcx, M::PointerTag>,
- right: ImmTy<'tcx, M::PointerTag>,
+ left: &ImmTy<'tcx, M::PointerTag>,
+ right: &ImmTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?;
Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
pub fn overflowing_unary_op(
&self,
un_op: mir::UnOp,
- val: ImmTy<'tcx, M::PointerTag>,
+ val: &ImmTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
use rustc_middle::mir::UnOp::*;
pub fn unary_op(
&self,
un_op: mir::UnOp,
- val: ImmTy<'tcx, M::PointerTag>,
+ val: &ImmTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?;
Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
Poison,
}
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(MemPlaceMeta, 24);
+
impl<Tag> MemPlaceMeta<Tag> {
pub fn unwrap_meta(self) -> Scalar<Tag> {
match self {
pub meta: MemPlaceMeta<Tag>,
}
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(MemPlace, 56);
+
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
pub enum Place<Tag = ()> {
/// A place referring to a value allocated in the `Memory` system.
Local { frame: usize, local: mir::Local },
}
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(Place, 64);
+
#[derive(Copy, Clone, Debug)]
pub struct PlaceTy<'tcx, Tag = ()> {
place: Place<Tag>, // Keep this private; it helps enforce invariants.
pub layout: TyAndLayout<'tcx>,
}
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(PlaceTy<'_>, 80);
+
impl<'tcx, Tag> std::ops::Deref for PlaceTy<'tcx, Tag> {
type Target = Place<Tag>;
#[inline(always)]
pub layout: TyAndLayout<'tcx>,
}
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 72);
+
impl<'tcx, Tag> std::ops::Deref for MPlaceTy<'tcx, Tag> {
type Target = MemPlace<Tag>;
#[inline(always)]
}
}
-impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
+impl<'tcx, Tag: Copy> MPlaceTy<'tcx, Tag> {
/// Produces a MemPlace that works for ZST but nothing else
#[inline]
pub fn dangling(layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
/// Replace ptr tag, maintain vtable tag (if any)
#[inline]
- pub fn replace_tag(self, new_tag: Tag) -> Self {
+ pub fn replace_tag(&self, new_tag: Tag) -> Self {
MPlaceTy { mplace: self.mplace.replace_tag(new_tag), layout: self.layout }
}
#[inline]
pub fn offset(
- self,
+ &self,
offset: Size,
meta: MemPlaceMeta<Tag>,
layout: TyAndLayout<'tcx>,
}
#[inline]
- pub(super) fn len(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
+ pub(super) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
if self.layout.is_unsized() {
// We need to consult `meta` metadata
match self.layout.ty.kind() {
}
#[inline]
- pub(super) fn vtable(self) -> Scalar<Tag> {
+ pub(super) fn vtable(&self) -> Scalar<Tag> {
match self.layout.ty.kind() {
ty::Dynamic(..) => self.mplace.meta.unwrap_meta(),
_ => bug!("vtable not supported on type {:?}", self.layout.ty),
/// Note: do not call `as_ref` on the resulting place. This function should only be used to
/// read from the resulting mplace, not to get its address back.
pub fn try_as_mplace(
- self,
+ &self,
cx: &impl HasDataLayout,
) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
- match *self {
+ match **self {
Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
Operand::Immediate(_) if self.layout.is_zst() => {
Ok(MPlaceTy::dangling(self.layout, cx))
#[inline(always)]
/// Note: do not call `as_ref` on the resulting place. This function should only be used to
/// read from the resulting mplace, not to get its address back.
- pub fn assert_mem_place(self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> {
+ pub fn assert_mem_place(&self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> {
self.try_as_mplace(cx).unwrap()
}
}
/// Generally prefer `deref_operand`.
pub fn ref_to_mplace(
&self,
- val: ImmTy<'tcx, M::PointerTag>,
+ val: &ImmTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let pointee_type =
val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty;
let layout = self.layout_of(pointee_type)?;
- let (ptr, meta) = match *val {
+ let (ptr, meta) = match **val {
Immediate::Scalar(ptr) => (ptr.check_init()?, MemPlaceMeta::None),
Immediate::ScalarPair(ptr, meta) => {
(ptr.check_init()?, MemPlaceMeta::Meta(meta.check_init()?))
/// will always be a MemPlace. Lives in `place.rs` because it creates a place.
pub fn deref_operand(
&self,
- src: OpTy<'tcx, M::PointerTag>,
+ src: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let val = self.read_immediate(src)?;
trace!("deref to {} on {:?}", val.layout.ty, *val);
- let place = self.ref_to_mplace(val)?;
+ let place = self.ref_to_mplace(&val)?;
self.mplace_access_checked(place, None)
}
#[inline]
pub(super) fn check_mplace_access(
&self,
- place: MPlaceTy<'tcx, M::PointerTag>,
+ place: &MPlaceTy<'tcx, M::PointerTag>,
size: Option<Size>,
) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
let size = size.unwrap_or_else(|| {
force_align: Option<Align>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let (size, align) = self
- .size_and_align_of_mplace(place)?
+ .size_and_align_of_mplace(&place)?
.unwrap_or((place.layout.size, place.layout.align.abi));
assert!(place.mplace.align <= align, "dynamic alignment less strict than static one?");
// Check (stricter) dynamic alignment, unless forced otherwise.
place.mplace.align = force_align.unwrap_or(align);
// When dereferencing a pointer, it must be non-NULL, aligned, and live.
- if let Some(ptr) = self.check_mplace_access(place, Some(size))? {
+ if let Some(ptr) = self.check_mplace_access(&place, Some(size))? {
place.mplace.ptr = ptr.into();
}
Ok(place)
#[inline(always)]
pub fn mplace_field(
&self,
- base: MPlaceTy<'tcx, M::PointerTag>,
+ base: &MPlaceTy<'tcx, M::PointerTag>,
field: usize,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let offset = base.layout.fields.offset(field);
// Re-use parent metadata to determine dynamic field layout.
// With custom DSTS, this *will* execute user-defined code, but the same
// happens at run-time so that's okay.
- let align = match self.size_and_align_of(base.meta, field_layout)? {
+ let align = match self.size_and_align_of(&base.meta, &field_layout)? {
Some((_, align)) => align,
None if offset == Size::ZERO => {
// An extern type at offset 0, we fall back to its static alignment.
#[inline(always)]
pub fn mplace_index(
&self,
- base: MPlaceTy<'tcx, M::PointerTag>,
+ base: &MPlaceTy<'tcx, M::PointerTag>,
index: u64,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
// Not using the layout method because we want to compute on u64
// same by repeatedly calling `mplace_array`.
pub(super) fn mplace_array_fields(
&self,
- base: MPlaceTy<'tcx, Tag>,
- ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'tcx>
+ base: &'a MPlaceTy<'tcx, Tag>,
+ ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
{
let len = base.len(self)?; // also asserts that we have a type where this makes sense
let stride = match base.layout.fields {
fn mplace_subslice(
&self,
- base: MPlaceTy<'tcx, M::PointerTag>,
+ base: &MPlaceTy<'tcx, M::PointerTag>,
from: u64,
to: u64,
from_end: bool,
pub(super) fn mplace_downcast(
&self,
- base: MPlaceTy<'tcx, M::PointerTag>,
+ base: &MPlaceTy<'tcx, M::PointerTag>,
variant: VariantIdx,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
// Downcasts only change the layout
assert!(!base.meta.has_meta());
- Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
+ Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..*base })
}
/// Project into an mplace
pub(super) fn mplace_projection(
&self,
- base: MPlaceTy<'tcx, M::PointerTag>,
+ base: &MPlaceTy<'tcx, M::PointerTag>,
proj_elem: mir::PlaceElem<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
use rustc_middle::mir::ProjectionElem::*;
Ok(match proj_elem {
Field(field, _) => self.mplace_field(base, field.index())?,
Downcast(_, variant) => self.mplace_downcast(base, variant)?,
- Deref => self.deref_operand(base.into())?,
+ Deref => self.deref_operand(&base.into())?,
Index(local) => {
let layout = self.layout_of(self.tcx.types.usize)?;
let n = self.access_local(self.frame(), local, Some(layout))?;
- let n = self.read_scalar(n)?;
+ let n = self.read_scalar(&n)?;
let n = u64::try_from(
self.force_bits(n.check_init()?, self.tcx.data_layout.pointer_size)?,
)
/// into the field of a local `ScalarPair`, we have to first allocate it.
pub fn place_field(
&mut self,
- base: PlaceTy<'tcx, M::PointerTag>,
+ base: &PlaceTy<'tcx, M::PointerTag>,
field: usize,
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
// FIXME: We could try to be smarter and avoid allocation for fields that span the
// entire place.
let mplace = self.force_allocation(base)?;
- Ok(self.mplace_field(mplace, field)?.into())
+ Ok(self.mplace_field(&mplace, field)?.into())
}
pub fn place_index(
&mut self,
- base: PlaceTy<'tcx, M::PointerTag>,
+ base: &PlaceTy<'tcx, M::PointerTag>,
index: u64,
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
let mplace = self.force_allocation(base)?;
- Ok(self.mplace_index(mplace, index)?.into())
+ Ok(self.mplace_index(&mplace, index)?.into())
}
pub fn place_downcast(
&self,
- base: PlaceTy<'tcx, M::PointerTag>,
+ base: &PlaceTy<'tcx, M::PointerTag>,
variant: VariantIdx,
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
// Downcast just changes the layout
Ok(match base.place {
Place::Ptr(mplace) => {
- self.mplace_downcast(MPlaceTy { mplace, layout: base.layout }, variant)?.into()
+ self.mplace_downcast(&MPlaceTy { mplace, layout: base.layout }, variant)?.into()
}
Place::Local { .. } => {
let layout = base.layout.for_variant(self, variant);
- PlaceTy { layout, ..base }
+ PlaceTy { layout, ..*base }
}
})
}
/// Projects into a place.
pub fn place_projection(
&mut self,
- base: PlaceTy<'tcx, M::PointerTag>,
+ base: &PlaceTy<'tcx, M::PointerTag>,
&proj_elem: &mir::ProjectionElem<mir::Local, Ty<'tcx>>,
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
use rustc_middle::mir::ProjectionElem::*;
Ok(match proj_elem {
Field(field, _) => self.place_field(base, field.index())?,
Downcast(_, variant) => self.place_downcast(base, variant)?,
- Deref => self.deref_operand(self.place_to_op(base)?)?.into(),
+ Deref => self.deref_operand(&self.place_to_op(base)?)?.into(),
// For the other variants, we have to force an allocation.
// This matches `operand_projection`.
Subslice { .. } | ConstantIndex { .. } | Index(_) => {
let mplace = self.force_allocation(base)?;
- self.mplace_projection(mplace, proj_elem)?.into()
+ self.mplace_projection(&mplace, proj_elem)?.into()
}
})
}
};
for elem in place.projection.iter() {
- place_ty = self.place_projection(place_ty, &elem)?
+ place_ty = self.place_projection(&place_ty, &elem)?
}
trace!("{:?}", self.dump_place(place_ty.place));
pub fn write_scalar(
&mut self,
val: impl Into<ScalarMaybeUninit<M::PointerTag>>,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
self.write_immediate(Immediate::Scalar(val.into()), dest)
}
pub fn write_immediate(
&mut self,
src: Immediate<M::PointerTag>,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
self.write_immediate_no_validate(src, dest)?;
if M::enforce_validity(self) {
// Data got changed, better make sure it matches the type!
- self.validate_operand(self.place_to_op(dest)?)?;
+ self.validate_operand(&self.place_to_op(dest)?)?;
}
Ok(())
pub fn write_immediate_to_mplace(
&mut self,
src: Immediate<M::PointerTag>,
- dest: MPlaceTy<'tcx, M::PointerTag>,
+ dest: &MPlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
self.write_immediate_to_mplace_no_validate(src, dest)?;
if M::enforce_validity(self) {
// Data got changed, better make sure it matches the type!
- self.validate_operand(dest.into())?;
+ self.validate_operand(&dest.into())?;
}
Ok(())
fn write_immediate_no_validate(
&mut self,
src: Immediate<M::PointerTag>,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
if cfg!(debug_assertions) {
// This is a very common path, avoid some checks in release mode
let dest = MPlaceTy { mplace, layout: dest.layout };
// This is already in memory, write there.
- self.write_immediate_to_mplace_no_validate(src, dest)
+ self.write_immediate_to_mplace_no_validate(src, &dest)
}
/// Write an immediate to memory.
fn write_immediate_to_mplace_no_validate(
&mut self,
value: Immediate<M::PointerTag>,
- dest: MPlaceTy<'tcx, M::PointerTag>,
+ dest: &MPlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
// Note that it is really important that the type here is the right one, and matches the
// type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here
#[inline(always)]
pub fn copy_op(
&mut self,
- src: OpTy<'tcx, M::PointerTag>,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ src: &OpTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
self.copy_op_no_validate(src, dest)?;
if M::enforce_validity(self) {
// Data got changed, better make sure it matches the type!
- self.validate_operand(self.place_to_op(dest)?)?;
+ self.validate_operand(&self.place_to_op(dest)?)?;
}
Ok(())
/// right type.
fn copy_op_no_validate(
&mut self,
- src: OpTy<'tcx, M::PointerTag>,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ src: &OpTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
// We do NOT compare the types for equality, because well-typed code can
// actually "transmute" `&mut T` to `&T` in an assignment without a cast.
assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances");
let src = self
- .check_mplace_access(src, Some(size))
+ .check_mplace_access(&src, Some(size))
.expect("places should be checked on creation");
let dest = self
- .check_mplace_access(dest, Some(size))
+ .check_mplace_access(&dest, Some(size))
.expect("places should be checked on creation");
let (src_ptr, dest_ptr) = match (src, dest) {
(Some(src_ptr), Some(dest_ptr)) => (src_ptr, dest_ptr),
/// have the same size.
pub fn copy_op_transmute(
&mut self,
- src: OpTy<'tcx, M::PointerTag>,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ src: &OpTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
if mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) {
// Fast path: Just use normal `copy_op`
let dest = self.force_allocation(dest)?;
self.copy_op_no_validate(
src,
- PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }),
+ &PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }),
)?;
if M::enforce_validity(self) {
// Data got changed, better make sure it matches the type!
- self.validate_operand(dest.into())?;
+ self.validate_operand(&dest.into())?;
}
Ok(())
/// version.
pub fn force_allocation_maybe_sized(
&mut self,
- place: PlaceTy<'tcx, M::PointerTag>,
+ place: &PlaceTy<'tcx, M::PointerTag>,
meta: MemPlaceMeta<M::PointerTag>,
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> {
let (mplace, size) = match place.place {
self.layout_of_local(&self.stack()[frame], local, None)?;
// We also need to support unsized types, and hence cannot use `allocate`.
let (size, align) = self
- .size_and_align_of(meta, local_layout)?
+ .size_and_align_of(&meta, &local_layout)?
.expect("Cannot allocate for non-dyn-sized type");
let ptr = self.memory.allocate(size, align, MemoryKind::Stack);
let mplace = MemPlace { ptr: ptr.into(), align, meta };
// We don't have to validate as we can assume the local
// was already valid for its type.
let mplace = MPlaceTy { mplace, layout: local_layout };
- self.write_immediate_to_mplace_no_validate(value, mplace)?;
+ self.write_immediate_to_mplace_no_validate(value, &mplace)?;
}
// Now we can call `access_mut` again, asserting it goes well,
// and actually overwrite things.
#[inline(always)]
pub fn force_allocation(
&mut self,
- place: PlaceTy<'tcx, M::PointerTag>,
+ place: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
Ok(self.force_allocation_maybe_sized(place, MemPlaceMeta::None)?.0)
}
pub fn write_discriminant(
&mut self,
variant_index: VariantIdx,
- dest: PlaceTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
// Layout computation excludes uninhabited variants from consideration
// therefore there's no way to represent those variants in the given layout.
let tag_val = size.truncate(discr_val);
let tag_dest = self.place_field(dest, tag_field)?;
- self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?;
+ self.write_scalar(Scalar::from_uint(tag_val, size), &tag_dest)?;
}
Variants::Multiple {
tag_encoding:
ImmTy::from_uint(variant_index_relative, tag_layout);
let tag_val = self.binary_op(
mir::BinOp::Add,
- variant_index_relative_val,
- niche_start_val,
+ &variant_index_relative_val,
+ &niche_start_val,
)?;
// Write result.
let niche_dest = self.place_field(dest, tag_field)?;
- self.write_immediate(*tag_val, niche_dest)?;
+ self.write_immediate(*tag_val, &niche_dest)?;
}
}
}
/// Also return some more information so drop doesn't have to run the same code twice.
pub(super) fn unpack_dyn_trait(
&self,
- mplace: MPlaceTy<'tcx, M::PointerTag>,
+ mplace: &MPlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
let vtable = mplace.vtable(); // also sanity checks the type
let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
assert_eq!(align, layout.align.abi);
}
- let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..*mplace }, layout };
+ let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, layout };
Ok((instance, mplace))
}
}
SetDiscriminant { place, variant_index } => {
let dest = self.eval_place(**place)?;
- self.write_discriminant(*variant_index, dest)?;
+ self.write_discriminant(*variant_index, &dest)?;
}
// Mark locals as alive
// Stacked Borrows.
Retag(kind, place) => {
let dest = self.eval_place(**place)?;
- M::retag(self, *kind, dest)?;
+ M::retag(self, *kind, &dest)?;
}
// Statements we do not track.
ThreadLocalRef(did) => {
let id = M::thread_local_static_alloc_id(self, did)?;
let val = self.global_base_pointer(id.into())?;
- self.write_scalar(val, dest)?;
+ self.write_scalar(val, &dest)?;
}
Use(ref operand) => {
// Avoid recomputing the layout
let op = self.eval_operand(operand, Some(dest.layout))?;
- self.copy_op(op, dest)?;
+ self.copy_op(&op, &dest)?;
}
BinaryOp(bin_op, ref left, ref right) => {
let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
- let left = self.read_immediate(self.eval_operand(left, layout)?)?;
+ let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
- let right = self.read_immediate(self.eval_operand(right, layout)?)?;
- self.binop_ignore_overflow(bin_op, left, right, dest)?;
+ let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
+ self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
}
CheckedBinaryOp(bin_op, ref left, ref right) => {
// Due to the extra boolean in the result, we can never reuse the `dest.layout`.
- let left = self.read_immediate(self.eval_operand(left, None)?)?;
+ let left = self.read_immediate(&self.eval_operand(left, None)?)?;
let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
- let right = self.read_immediate(self.eval_operand(right, layout)?)?;
- self.binop_with_overflow(bin_op, left, right, dest)?;
+ let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
+ self.binop_with_overflow(bin_op, &left, &right, &dest)?;
}
UnaryOp(un_op, ref operand) => {
// The operand always has the same type as the result.
- let val = self.read_immediate(self.eval_operand(operand, Some(dest.layout))?)?;
- let val = self.unary_op(un_op, val)?;
+ let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?;
+ let val = self.unary_op(un_op, &val)?;
assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op);
- self.write_immediate(*val, dest)?;
+ self.write_immediate(*val, &dest)?;
}
Aggregate(ref kind, ref operands) => {
let (dest, active_field_index) = match **kind {
mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
- self.write_discriminant(variant_index, dest)?;
+ self.write_discriminant(variant_index, &dest)?;
if adt_def.is_enum() {
- (self.place_downcast(dest, variant_index)?, active_field_index)
+ (self.place_downcast(&dest, variant_index)?, active_field_index)
} else {
(dest, active_field_index)
}
// Ignore zero-sized fields.
if !op.layout.is_zst() {
let field_index = active_field_index.unwrap_or(i);
- let field_dest = self.place_field(dest, field_index)?;
- self.copy_op(op, field_dest)?;
+ let field_dest = self.place_field(&dest, field_index)?;
+ self.copy_op(&op, &field_dest)?;
}
}
}
Repeat(ref operand, _) => {
let op = self.eval_operand(operand, None)?;
- let dest = self.force_allocation(dest)?;
+ let dest = self.force_allocation(&dest)?;
let length = dest.len(self)?;
- if let Some(first_ptr) = self.check_mplace_access(dest, None)? {
+ if let Some(first_ptr) = self.check_mplace_access(&dest, None)? {
// Write the first.
- let first = self.mplace_field(dest, 0)?;
- self.copy_op(op, first.into())?;
+ let first = self.mplace_field(&dest, 0)?;
+ self.copy_op(&op, &first.into())?;
if length > 1 {
let elem_size = first.layout.size;
Len(place) => {
// FIXME(CTFE): don't allow computing the length of arrays in const eval
let src = self.eval_place(place)?;
- let mplace = self.force_allocation(src)?;
+ let mplace = self.force_allocation(&src)?;
let len = mplace.len(self)?;
- self.write_scalar(Scalar::from_machine_usize(len, self), dest)?;
+ self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?;
}
AddressOf(_, place) | Ref(_, _, place) => {
let src = self.eval_place(place)?;
- let place = self.force_allocation(src)?;
+ let place = self.force_allocation(&src)?;
if place.layout.size.bytes() > 0 {
// definitely not a ZST
assert!(place.ptr.is_ptr(), "non-ZST places should be normalized to `Pointer`");
}
- self.write_immediate(place.to_ref(), dest)?;
+ self.write_immediate(place.to_ref(), &dest)?;
}
NullaryOp(mir::NullOp::Box, _) => {
- M::box_alloc(self, dest)?;
+ M::box_alloc(self, &dest)?;
}
NullaryOp(mir::NullOp::SizeOf, ty) => {
);
throw_inval!(SizeOfUnsizedType(ty));
}
- self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), dest)?;
+ self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), &dest)?;
}
Cast(cast_kind, ref operand, cast_ty) => {
let src = self.eval_operand(operand, None)?;
let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty);
- self.cast(src, cast_kind, cast_ty, dest)?;
+ self.cast(&src, cast_kind, cast_ty, &dest)?;
}
Discriminant(place) => {
let op = self.eval_place_to_op(place, None)?;
- let discr_val = self.read_discriminant(op)?.0;
- self.write_scalar(discr_val, dest)?;
+ let discr_val = self.read_discriminant(&op)?.0;
+ self.write_scalar(discr_val, &dest)?;
}
}
Goto { target } => self.go_to_block(target),
SwitchInt { ref discr, ref targets, switch_ty } => {
- let discr = self.read_immediate(self.eval_operand(discr, None)?)?;
+ let discr = self.read_immediate(&self.eval_operand(discr, None)?)?;
trace!("SwitchInt({:?})", *discr);
assert_eq!(discr.layout.ty, switch_ty);
let res = self
.overflowing_binary_op(
mir::BinOp::Eq,
- discr,
- ImmTy::from_uint(const_int, discr.layout),
+ &discr,
+ &ImmTy::from_uint(const_int, discr.layout),
)?
.0;
if res.to_bool()? {
let (fn_val, abi) = match *func.layout.ty.kind() {
ty::FnPtr(sig) => {
let caller_abi = sig.abi();
- let fn_ptr = self.read_scalar(func)?.check_init()?;
+ let fn_ptr = self.read_scalar(&func)?.check_init()?;
let fn_val = self.memory.get_fn(fn_ptr)?;
(fn_val, caller_abi)
}
),
};
let args = self.eval_operands(args)?;
+ let dest_place;
let ret = match destination {
- Some((dest, ret)) => Some((self.eval_place(dest)?, ret)),
+ Some((dest, ret)) => {
+ dest_place = self.eval_place(dest)?;
+ Some((&dest_place, ret))
+ }
None => None,
};
self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?;
trace!("TerminatorKind::drop: {:?}, type {}", place, ty);
let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
- self.drop_in_place(place, instance, target, unwind)?;
+ self.drop_in_place(&place, instance, target, unwind)?;
}
Assert { ref cond, expected, ref msg, target, cleanup } => {
let cond_val =
- self.read_immediate(self.eval_operand(cond, None)?)?.to_scalar()?.to_bool()?;
+ self.read_immediate(&self.eval_operand(cond, None)?)?.to_scalar()?.to_bool()?;
if expected == cond_val {
self.go_to_block(target);
} else {
&mut self,
rust_abi: bool,
caller_arg: &mut impl Iterator<Item = OpTy<'tcx, M::PointerTag>>,
- callee_arg: PlaceTy<'tcx, M::PointerTag>,
+ callee_arg: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
if rust_abi && callee_arg.layout.is_zst() {
// Nothing to do.
)
}
// We allow some transmutes here
- self.copy_op_transmute(caller_arg, callee_arg)
+ self.copy_op_transmute(&caller_arg, callee_arg)
}
/// Call this function -- pushing the stack frame and initializing the arguments.
fn_val: FnVal<'tcx, M::ExtraFnVal>,
caller_abi: Abi,
args: &[OpTy<'tcx, M::PointerTag>],
- ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
+ ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
unwind: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
trace!("eval_fn_call: {:#?}", fn_val);
let caller_args: Cow<'_, [OpTy<'tcx, M::PointerTag>]> =
if caller_abi == Abi::RustCall && !args.is_empty() {
// Untuple
- let (&untuple_arg, args) = args.split_last().unwrap();
+ let (untuple_arg, args) = args.split_last().unwrap();
trace!("eval_fn_call: Will pass last argument by untupling");
Cow::from(
args.iter()
if Some(local) == body.spread_arg {
// Must be a tuple
for i in 0..dest.layout.fields.count() {
- let dest = self.place_field(dest, i)?;
- self.pass_argument(rust_abi, &mut caller_iter, dest)?;
+ let dest = self.place_field(&dest, i)?;
+ self.pass_argument(rust_abi, &mut caller_iter, &dest)?;
}
} else {
// Normal argument
- self.pass_argument(rust_abi, &mut caller_iter, dest)?;
+ self.pass_argument(rust_abi, &mut caller_iter, &dest)?;
}
}
// Now we should have no more caller args
let receiver_place = match args[0].layout.ty.builtin_deref(true) {
Some(_) => {
// Built-in pointer.
- self.deref_operand(args[0])?
+ self.deref_operand(&args[0])?
}
None => {
// Unsized self.
fn drop_in_place(
&mut self,
- place: PlaceTy<'tcx, M::PointerTag>,
+ place: &PlaceTy<'tcx, M::PointerTag>,
instance: ty::Instance<'tcx>,
target: mir::BasicBlock,
unwind: Option<mir::BasicBlock>,
let (instance, place) = match place.layout.ty.kind() {
ty::Dynamic(..) => {
// Dropping a trait object.
- self.unpack_dyn_trait(place)?
+ self.unpack_dyn_trait(&place)?
}
_ => (instance, place),
};
FnVal::Instance(instance),
Abi::Rust,
&[arg.into()],
- Some((dest.into(), target)),
+ Some((&dest.into(), target)),
unwind,
)
}
.get_raw(vtable_slot.alloc_id)?
.read_ptr_sized(self, vtable_slot)?
.check_init()?;
- Ok(self.memory.get_fn(fn_ptr)?)
+ self.memory.get_fn(fn_ptr)
}
/// Returns the drop fn instance as well as the actual dynamic type.
/// Check a reference or `Box`.
fn check_safe_pointer(
&mut self,
- value: OpTy<'tcx, M::PointerTag>,
+ value: &OpTy<'tcx, M::PointerTag>,
kind: &str,
) -> InterpResult<'tcx> {
let value = try_validation!(
// Handle wide pointers.
// Check metadata early, for better diagnostics
let place = try_validation!(
- self.ecx.ref_to_mplace(value),
+ self.ecx.ref_to_mplace(&value),
self.path,
err_ub!(InvalidUninitBytes(None)) => { "uninitialized {}", kind },
);
}
// Make sure this is dereferenceable and all.
let size_and_align = try_validation!(
- self.ecx.size_and_align_of_mplace(place),
+ self.ecx.size_and_align_of_mplace(&place),
self.path,
err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg },
);
fn read_scalar(
&self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, ScalarMaybeUninit<M::PointerTag>> {
Ok(try_validation!(
self.ecx.read_scalar(op),
/// at that type. Return `true` if the type is indeed primitive.
fn try_visit_primitive(
&mut self,
- value: OpTy<'tcx, M::PointerTag>,
+ value: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, bool> {
// Go over all the primitive types
let ty = value.layout.ty;
// actually enforce the strict rules for raw pointers (mostly because
// that lets us re-use `ref_to_mplace`).
let place = try_validation!(
- self.ecx.read_immediate(value).and_then(|i| self.ecx.ref_to_mplace(i)),
+ self.ecx.read_immediate(value).and_then(|ref i| self.ecx.ref_to_mplace(i)),
self.path,
err_ub!(InvalidUninitBytes(None)) => { "uninitialized raw pointer" },
err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
fn visit_scalar(
&mut self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
scalar_layout: &Scalar,
) -> InterpResult<'tcx> {
let value = self.read_scalar(op)?;
fn read_discriminant(
&mut self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, VariantIdx> {
self.with_elem(PathElem::EnumTag, move |this| {
Ok(try_validation!(
#[inline]
fn visit_field(
&mut self,
- old_op: OpTy<'tcx, M::PointerTag>,
+ old_op: &OpTy<'tcx, M::PointerTag>,
field: usize,
- new_op: OpTy<'tcx, M::PointerTag>,
+ new_op: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
let elem = self.aggregate_field_path_elem(old_op.layout, field);
self.with_elem(elem, move |this| this.visit_value(new_op))
#[inline]
fn visit_variant(
&mut self,
- old_op: OpTy<'tcx, M::PointerTag>,
+ old_op: &OpTy<'tcx, M::PointerTag>,
variant_id: VariantIdx,
- new_op: OpTy<'tcx, M::PointerTag>,
+ new_op: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
let name = match old_op.layout.ty.kind() {
ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name),
#[inline(always)]
fn visit_union(
&mut self,
- _op: OpTy<'tcx, M::PointerTag>,
+ _op: &OpTy<'tcx, M::PointerTag>,
_fields: NonZeroUsize,
) -> InterpResult<'tcx> {
Ok(())
}
#[inline]
- fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
+ fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
trace!("visit_value: {:?}, {:?}", *op, op.layout);
// Check primitive types -- the leafs of our recursive descend.
fn visit_aggregate(
&mut self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>,
) -> InterpResult<'tcx> {
match op.layout.ty.kind() {
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
fn validate_operand_internal(
&self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
path: Vec<PathElem>,
ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>>,
ctfe_mode: Option<CtfeValidationMode>,
let mut visitor = ValidityVisitor { path, ref_tracking, ctfe_mode, ecx: self };
// Try to cast to ptr *once* instead of all the time.
- let op = self.force_op_ptr(op).unwrap_or(op);
+ let op = self.force_op_ptr(&op).unwrap_or(*op);
// Run it.
- match visitor.visit_value(op) {
+ match visitor.visit_value(&op) {
Ok(()) => Ok(()),
// Pass through validation failures.
Err(err) if matches!(err.kind(), err_ub!(ValidationFailure { .. })) => Err(err),
#[inline(always)]
pub fn const_validate_operand(
&self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
path: Vec<PathElem>,
ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>,
ctfe_mode: CtfeValidationMode,
/// `op` is assumed to cover valid memory if it is an indirect operand.
/// It will error if the bits at the destination do not match the ones described by the layout.
#[inline(always)]
- pub fn validate_operand(&self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
+ pub fn validate_operand(&self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
self.validate_operand_internal(op, vec![], None, None)
}
}
fn layout(&self) -> TyAndLayout<'tcx>;
/// Makes this into an `OpTy`.
- fn to_op(self, ecx: &InterpCx<'mir, 'tcx, M>) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>;
+ fn to_op(&self, ecx: &InterpCx<'mir, 'tcx, M>)
+ -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>;
/// Creates this from an `MPlaceTy`.
fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self;
/// Projects to the given enum variant.
fn project_downcast(
- self,
+ &self,
ecx: &InterpCx<'mir, 'tcx, M>,
variant: VariantIdx,
) -> InterpResult<'tcx, Self>;
/// Projects to the n-th field.
- fn project_field(self, ecx: &InterpCx<'mir, 'tcx, M>, field: usize)
- -> InterpResult<'tcx, Self>;
+ fn project_field(
+ &self,
+ ecx: &InterpCx<'mir, 'tcx, M>,
+ field: usize,
+ ) -> InterpResult<'tcx, Self>;
}
// Operands and memory-places are both values.
#[inline(always)]
fn to_op(
- self,
+ &self,
_ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
- Ok(self)
+ Ok(*self)
}
#[inline(always)]
#[inline(always)]
fn project_downcast(
- self,
+ &self,
ecx: &InterpCx<'mir, 'tcx, M>,
variant: VariantIdx,
) -> InterpResult<'tcx, Self> {
#[inline(always)]
fn project_field(
- self,
+ &self,
ecx: &InterpCx<'mir, 'tcx, M>,
field: usize,
) -> InterpResult<'tcx, Self> {
#[inline(always)]
fn to_op(
- self,
+ &self,
_ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
- Ok(self.into())
+ Ok((*self).into())
}
#[inline(always)]
#[inline(always)]
fn project_downcast(
- self,
+ &self,
ecx: &InterpCx<'mir, 'tcx, M>,
variant: VariantIdx,
) -> InterpResult<'tcx, Self> {
#[inline(always)]
fn project_field(
- self,
+ &self,
ecx: &InterpCx<'mir, 'tcx, M>,
field: usize,
) -> InterpResult<'tcx, Self> {
#[inline(always)]
fn read_discriminant(
&mut self,
- op: OpTy<'tcx, M::PointerTag>,
+ op: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, VariantIdx> {
Ok(self.ecx().read_discriminant(op)?.1)
}
// Recursive actions, ready to be overloaded.
/// Visits the given value, dispatching as appropriate to more specialized visitors.
#[inline(always)]
- fn visit_value(&mut self, v: Self::V) -> InterpResult<'tcx>
+ fn visit_value(&mut self, v: &Self::V) -> InterpResult<'tcx>
{
self.walk_value(v)
}
/// Visits the given value as a union. No automatic recursion can happen here.
#[inline(always)]
- fn visit_union(&mut self, _v: Self::V, _fields: NonZeroUsize) -> InterpResult<'tcx>
+ fn visit_union(&mut self, _v: &Self::V, _fields: NonZeroUsize) -> InterpResult<'tcx>
{
Ok(())
}
#[inline(always)]
fn visit_aggregate(
&mut self,
- v: Self::V,
+ v: &Self::V,
fields: impl Iterator<Item=InterpResult<'tcx, Self::V>>,
) -> InterpResult<'tcx> {
self.walk_aggregate(v, fields)
#[inline(always)]
fn visit_field(
&mut self,
- _old_val: Self::V,
+ _old_val: &Self::V,
_field: usize,
- new_val: Self::V,
+ new_val: &Self::V,
) -> InterpResult<'tcx> {
self.visit_value(new_val)
}
#[inline(always)]
fn visit_variant(
&mut self,
- _old_val: Self::V,
+ _old_val: &Self::V,
_variant: VariantIdx,
- new_val: Self::V,
+ new_val: &Self::V,
) -> InterpResult<'tcx> {
self.visit_value(new_val)
}
// Default recursors. Not meant to be overloaded.
fn walk_aggregate(
&mut self,
- v: Self::V,
+ v: &Self::V,
fields: impl Iterator<Item=InterpResult<'tcx, Self::V>>,
) -> InterpResult<'tcx> {
// Now iterate over it.
for (idx, field_val) in fields.enumerate() {
- self.visit_field(v, idx, field_val?)?;
+ self.visit_field(v, idx, &field_val?)?;
}
Ok(())
}
- fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx>
+ fn walk_value(&mut self, v: &Self::V) -> InterpResult<'tcx>
{
trace!("walk_value: type: {}", v.layout().ty);
ty::Dynamic(..) => {
// immediate trait objects are not a thing
let dest = v.to_op(self.ecx())?.assert_mem_place(self.ecx());
- let inner = self.ecx().unpack_dyn_trait(dest)?.1;
+ let inner = self.ecx().unpack_dyn_trait(&dest)?.1;
trace!("walk_value: dyn object layout: {:#?}", inner.layout);
// recurse with the inner type
- return self.visit_field(v, 0, Value::from_mem_place(inner));
+ return self.visit_field(&v, 0, &Value::from_mem_place(inner));
},
// Slices do not need special handling here: they have `Array` field
// placement with length 0, so we enter the `Array` case below which
// Now we can go over all the fields.
// This uses the *run-time length*, i.e., if we are a slice,
// the dynamic info from the metadata is used.
- let iter = self.ecx().mplace_array_fields(mplace)?
+ let iter = self.ecx().mplace_array_fields(&mplace)?
.map(|f| f.and_then(|f| {
Ok(Value::from_mem_place(f))
}));
// with *its* fields.
Variants::Multiple { .. } => {
let op = v.to_op(self.ecx())?;
- let idx = self.read_discriminant(op)?;
+ let idx = self.read_discriminant(&op)?;
let inner = v.project_downcast(self.ecx(), idx)?;
trace!("walk_value: variant layout: {:#?}", inner.layout());
// recurse with the inner type
- self.visit_variant(v, idx, inner)
+ self.visit_variant(v, idx, &inner)
}
// For single-variant layouts, we already did anything there is to do.
Variants::Single { .. } => Ok(())
_instance: ty::Instance<'tcx>,
_abi: Abi,
_args: &[OpTy<'tcx>],
- _ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
+ _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
_unwind: Option<BasicBlock>,
) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> {
Ok(None)
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_instance: ty::Instance<'tcx>,
_args: &[OpTy<'tcx>],
- _ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
+ _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
_unwind: Option<BasicBlock>,
) -> InterpResult<'tcx> {
throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
fn binary_ptr_op(
_ecx: &InterpCx<'mir, 'tcx, Self>,
_bin_op: BinOp,
- _left: ImmTy<'tcx>,
- _right: ImmTy<'tcx>,
+ _left: &ImmTy<'tcx>,
+ _right: &ImmTy<'tcx>,
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
// We can't do this because aliasing of memory can differ between const eval and llvm
throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
fn box_alloc(
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
- _dest: PlaceTy<'tcx>,
+ _dest: &PlaceTy<'tcx>,
) -> InterpResult<'tcx> {
throw_machine_stop_str!("can't const prop heap allocations")
}
.filter(|ret_layout| {
!ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
})
- .map(|ret_layout| ecx.allocate(ret_layout, MemoryKind::Stack));
+ .map(|ret_layout| ecx.allocate(ret_layout, MemoryKind::Stack).into());
ecx.push_stack_frame(
Instance::new(def_id, substs),
dummy_body,
- ret.map(Into::into),
+ ret.as_ref(),
StackPopCleanup::None { cleanup: false },
)
.expect("failed to push initial stack frame");
// Try to read the local as an immediate so that if it is representable as a scalar, we can
// handle it as such, but otherwise, just return the value as is.
- Some(match self.ecx.try_read_immediate(op) {
+ Some(match self.ecx.try_read_immediate(&op) {
Ok(Ok(imm)) => imm.into(),
_ => op,
})
source_info: SourceInfo,
) -> Option<()> {
if let (val, true) = self.use_ecx(|this| {
- let val = this.ecx.read_immediate(this.ecx.eval_operand(arg, None)?)?;
- let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, val)?;
+ let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?;
+ let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, &val)?;
Ok((val, overflow))
})? {
// `AssertKind` only has an `OverflowNeg` variant, so make sure that is
right: &Operand<'tcx>,
source_info: SourceInfo,
) -> Option<()> {
- let r = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?));
- let l = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(left, None)?));
+ let r = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?));
+ let l = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?));
// Check for exceeding shifts *even if* we cannot evaluate the LHS.
if op == BinOp::Shr || op == BinOp::Shl {
let r = r?;
}
}
- if let (Some(l), Some(r)) = (l, r) {
+ if let (Some(l), Some(r)) = (&l, &r) {
// The remaining operators are handled through `overflowing_binary_op`.
if self.use_ecx(|this| {
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
match *operand {
Operand::Copy(l) | Operand::Move(l) => {
if let Some(value) = self.get_const(l) {
- if self.should_const_prop(value) {
+ if self.should_const_prop(&value) {
// FIXME(felix91gr): this code only handles `Scalar` cases.
// For now, we're not handling `ScalarPair` cases because
// doing so here would require a lot of code duplication.
let r = this.ecx.eval_operand(right, None);
let const_arg = match (l, r) {
- (Ok(x), Err(_)) | (Err(_), Ok(x)) => this.ecx.read_immediate(x)?,
+ (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
(Err(e), Err(_)) => return Err(e),
(Ok(_), Ok(_)) => {
this.ecx.eval_rvalue_into_place(rvalue, place)?;
match op {
BinOp::BitAnd => {
if arg_value == 0 {
- this.ecx.write_immediate(*const_arg, dest)?;
+ this.ecx.write_immediate(*const_arg, &dest)?;
}
}
BinOp::BitOr => {
if arg_value == const_arg.layout.size.truncate(u128::MAX)
|| (const_arg.layout.ty.is_bool() && arg_value == 1)
{
- this.ecx.write_immediate(*const_arg, dest)?;
+ this.ecx.write_immediate(*const_arg, &dest)?;
}
}
BinOp::Mul => {
const_arg.to_scalar()?.into(),
Scalar::from_bool(false).into(),
);
- this.ecx.write_immediate(val, dest)?;
+ this.ecx.write_immediate(val, &dest)?;
} else {
- this.ecx.write_immediate(*const_arg, dest)?;
+ this.ecx.write_immediate(*const_arg, &dest)?;
}
}
}
fn replace_with_const(
&mut self,
rval: &mut Rvalue<'tcx>,
- value: OpTy<'tcx>,
+ value: &OpTy<'tcx>,
source_info: SourceInfo,
) {
if let Rvalue::Use(Operand::Constant(c)) = rval {
}
/// Returns `true` if and only if this `op` should be const-propagated into.
- fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool {
+ fn should_const_prop(&mut self, op: &OpTy<'tcx>) -> bool {
let mir_opt_level = self.tcx.sess.opts.debugging_opts.mir_opt_level;
if mir_opt_level == 0 {
return false;
}
- match *op {
+ match **op {
interpret::Operand::Immediate(Immediate::Scalar(ScalarMaybeUninit::Scalar(s))) => {
s.is_bits()
}
// This will return None if the above `const_prop` invocation only "wrote" a
// type whose creation requires no write. E.g. a generator whose initial state
// consists solely of uninitialized memory (so it doesn't capture any locals).
- if let Some(value) = self.get_const(place) {
+ if let Some(ref value) = self.get_const(place) {
if self.should_const_prop(value) {
trace!("replacing {:?} with {:?}", rval, value);
self.replace_with_const(rval, value, source_info);
self.super_terminator(terminator, location);
match &mut terminator.kind {
TerminatorKind::Assert { expected, ref msg, ref mut cond, .. } => {
- if let Some(value) = self.eval_operand(&cond, source_info) {
+ if let Some(ref value) = self.eval_operand(&cond, source_info) {
trace!("assertion on {:?} should be {:?}", value, expected);
let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected));
- let value_const = self.ecx.read_scalar(value).unwrap();
+ let value_const = self.ecx.read_scalar(&value).unwrap();
if expected != value_const {
enum DbgVal<T> {
Val(T),
// This can be `None` if the lhs wasn't const propagated and we just
// triggered the assert on the value of the rhs.
match self.eval_operand(op, source_info) {
- Some(op) => {
- DbgVal::Val(self.ecx.read_immediate(op).unwrap().to_const_int())
- }
+ Some(op) => DbgVal::Val(
+ self.ecx.read_immediate(&op).unwrap().to_const_int(),
+ ),
None => DbgVal::Underscore,
}
};
fn test_covgraph_goto_switchint() {
let mir_body = goto_switchint();
if false {
- println!("basic_blocks = {}", debug_basic_blocks(&mir_body));
+ eprintln!("basic_blocks = {}", debug_basic_blocks(&mir_body));
}
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &basic_coverage_blocks);
let mir_body = goto_switchint();
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
if false {
- println!(
+ eprintln!(
"basic_coverage_blocks = {:?}",
basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
);
- println!("successors = {:?}", basic_coverage_blocks.successors);
+ eprintln!("successors = {:?}", basic_coverage_blocks.successors);
}
let backedges = graph::find_loop_backedges(&basic_coverage_blocks);
assert_eq!(
pub struct GraphvizWriter<
'a,
G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes,
- NodeContentFn: Fn(<G as rustc_data_structures::graph::DirectedGraph>::Node) -> Vec<String>,
- EdgeLabelsFn: Fn(<G as rustc_data_structures::graph::DirectedGraph>::Node) -> Vec<String>,
+ NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
+ EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
> {
graph: &'a G,
is_subgraph: bool,
impl<
'a,
G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes,
- NodeContentFn: Fn(<G as rustc_data_structures::graph::DirectedGraph>::Node) -> Vec<String>,
- EdgeLabelsFn: Fn(<G as rustc_data_structures::graph::DirectedGraph>::Node) -> Vec<String>,
+ NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
+ EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
> GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn>
{
pub fn new(
}
fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
- tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| {
- let msg = match source {
- hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern",
- hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern",
- hir::MatchSource::IfLetGuardDesugar => "irrefutable if-let guard",
- _ => bug!(),
- };
- lint.build(msg).emit()
+ tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source {
+ hir::MatchSource::IfLetDesugar { .. } => {
+ let mut diag = lint.build("irrefutable `if let` pattern");
+ diag.note("this pattern will always match, so the `if let` is useless");
+ diag.help("consider replacing the `if let` with a `let`");
+ diag.emit()
+ }
+ hir::MatchSource::WhileLetDesugar => {
+ let mut diag = lint.build("irrefutable `while let` pattern");
+ diag.note("this pattern will always match, so the loop will never exit");
+ diag.help("consider instead using a `loop { ... }` with a `let` inside it");
+ diag.emit()
+ }
+ hir::MatchSource::IfLetGuardDesugar => {
+ let mut diag = lint.build("irrefutable `if let` guard pattern");
+ diag.note("this pattern will always match, so the guard is useless");
+ diag.help("consider removing the guard and adding a `let` inside the match arm");
+ diag.emit()
+ }
+ _ => {
+ bug!(
+ "expected `if let`, `while let`, or `if let` guard HIR match source, found {:?}",
+ source,
+ )
+ }
});
}
report_arm_reachability(&cx, &report, hir::MatchSource::IfLetGuardDesugar);
if report.non_exhaustiveness_witnesses.is_empty() {
- // The match is exhaustive, i.e. the if let pattern is irrefutable.
+ // The match is exhaustive, i.e. the `if let` pattern is irrefutable.
irrefutable_let_pattern(cx.tcx, pat.span, pat_id, hir::MatchSource::IfLetGuardDesugar)
}
}
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::OnceCell;
use rustc_arena::TypedArena;
use rustc_hir::def_id::DefId;
use smallvec::{smallvec, SmallVec};
use std::fmt;
use std::iter::{FromIterator, IntoIterator};
+use std::lazy::OnceCell;
crate struct MatchCheckCtxt<'a, 'tcx> {
crate tcx: TyCtxt<'tcx>,
}
pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
- let pat = self.parse_pat(Some("argument name"))?;
+ let pat = self.parse_pat_no_top_alt(Some("argument name"))?;
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;
token::Ident(..) if this.is_mistaken_not_ident_negation() => {
make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
}
- _ => return this.parse_dot_or_call_expr(Some(attrs.into())),
+ _ => return this.parse_dot_or_call_expr(Some(attrs)),
}
}
let lo = self.token.span;
let attrs = self.parse_outer_attributes()?;
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
- let pat = this.parse_pat(PARAM_EXPECTED)?;
+ let pat = this.parse_pat_no_top_alt(PARAM_EXPECTED)?;
let ty = if this.eat(&token::Colon) {
this.parse_ty()?
} else {
/// The `let` token has already been eaten.
fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
let lo = self.prev_token.span;
- let pat = self.parse_top_pat(GateOr::No, RecoverComma::Yes)?;
+ let pat = self.parse_pat_allow_top_alt(None, GateOr::No, RecoverComma::Yes)?;
self.expect(&token::Eq)?;
let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| {
this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
_ => None,
};
- let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?;
+ let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::Yes)?;
if !self.eat_keyword(kw::In) {
self.error_missing_in_for_loop();
}
let attrs = self.parse_outer_attributes()?;
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let lo = this.token.span;
- let pat = this.parse_top_pat(GateOr::No, RecoverComma::Yes)?;
+ let pat = this.parse_pat_allow_top_alt(None, GateOr::No, RecoverComma::Yes)?;
let guard = if this.eat_keyword(kw::If) {
let if_span = this.prev_token.span;
let cond = this.parse_expr()?;
impl<'a> Parser<'a> {
/// Parses a source module as a crate. This is the main entry point for the parser.
pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
- let lo = self.token.span;
- let (module, attrs) = self.parse_mod(&token::Eof, Unsafe::No)?;
- let span = lo.to(self.token.span);
+ let (attrs, items, span) = self.parse_mod(&token::Eof)?;
let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
- Ok(ast::Crate { attrs, module, span, proc_macros })
+ Ok(ast::Crate { attrs, items, span, proc_macros })
}
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
let unsafety = self.parse_unsafety();
self.expect_keyword(kw::Mod)?;
let id = self.parse_ident()?;
- let (module, mut inner_attrs) = if self.eat(&token::Semi) {
- (Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }, Vec::new())
+ let mod_kind = if self.eat(&token::Semi) {
+ ModKind::Unloaded
} else {
self.expect(&token::OpenDelim(token::Brace))?;
- self.parse_mod(&token::CloseDelim(token::Brace), unsafety)?
+ let (mut inner_attrs, items, inner_span) =
+ self.parse_mod(&token::CloseDelim(token::Brace))?;
+ attrs.append(&mut inner_attrs);
+ ModKind::Loaded(items, Inline::Yes, inner_span)
};
- attrs.append(&mut inner_attrs);
- Ok((id, ItemKind::Mod(module)))
+ Ok((id, ItemKind::Mod(unsafety, mod_kind)))
}
/// Parses the contents of a module (inner attributes followed by module items).
pub fn parse_mod(
&mut self,
term: &TokenKind,
- unsafety: Unsafe,
- ) -> PResult<'a, (Mod, Vec<Attribute>)> {
+ ) -> PResult<'a, (Vec<Attribute>, Vec<P<Item>>, Span)> {
let lo = self.token.span;
let attrs = self.parse_inner_attributes()?;
- let module = self.parse_mod_items(term, lo, unsafety)?;
- Ok((module, attrs))
- }
- /// Given a termination token, parses all of the items in a module.
- fn parse_mod_items(
- &mut self,
- term: &TokenKind,
- inner_lo: Span,
- unsafety: Unsafe,
- ) -> PResult<'a, Mod> {
let mut items = vec![];
while let Some(item) = self.parse_item(ForceCollect::No)? {
items.push(item);
}
}
- let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };
-
- Ok(Mod { inner: inner_lo.to(hi), unsafety, items, inline: true })
+ Ok((attrs, items, lo.to(self.prev_token.span)))
}
}
pub use attr_wrapper::AttrWrapper;
pub use diagnostics::AttemptLocalParseRecovery;
use diagnostics::Error;
+pub use pat::{GateOr, RecoverComma};
pub use path::PathStyle;
use rustc_ast::ptr::P;
},
NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => {
token::NtPat(self.collect_tokens_no_attrs(|this| match kind {
- NonterminalKind::Pat2018 { .. } => this.parse_pat(None),
+ NonterminalKind::Pat2018 { .. } => this.parse_pat_no_top_alt(None),
NonterminalKind::Pat2021 { .. } => {
- this.parse_top_pat(GateOr::Yes, RecoverComma::No)
+ this.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)
}
_ => unreachable!(),
})?)
/// Whether or not an or-pattern should be gated when occurring in the current context.
#[derive(PartialEq, Clone, Copy)]
-pub(super) enum GateOr {
+pub enum GateOr {
Yes,
No,
}
/// Whether or not to recover a `,` when parsing or-patterns.
#[derive(PartialEq, Copy, Clone)]
-pub(super) enum RecoverComma {
+pub enum RecoverComma {
Yes,
No,
}
/// Corresponds to `pat<no_top_alt>` in RFC 2535 and does not admit or-patterns
/// at the top level. Used when parsing the parameters of lambda expressions,
/// functions, function pointers, and `pat` macro fragments.
- pub fn parse_pat(&mut self, expected: Expected) -> PResult<'a, P<Pat>> {
+ pub fn parse_pat_no_top_alt(&mut self, expected: Expected) -> PResult<'a, P<Pat>> {
self.parse_pat_with_range_pat(true, expected)
}
- /// Entry point to the main pattern parser.
+ /// Parses a pattern.
+ ///
/// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level.
- pub(super) fn parse_top_pat(
+ /// Used for parsing patterns in all cases when `pat<no_top_alt>` is not used.
+ ///
+ /// Note that after the FCP in <https://github.com/rust-lang/rust/issues/81415>,
+ /// a leading vert is allowed in nested or-patterns, too. This allows us to
+ /// simplify the grammar somewhat.
+ pub fn parse_pat_allow_top_alt(
&mut self,
+ expected: Expected,
gate_or: GateOr,
rc: RecoverComma,
) -> PResult<'a, P<Pat>> {
// Allow a '|' before the pats (RFCs 1925, 2530, and 2535).
- let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes;
- let leading_vert_span = self.prev_token.span;
-
- // Parse the possibly-or-pattern.
- let pat = self.parse_pat_with_or(None, gate_or, rc)?;
-
- // If we parsed a leading `|` which should be gated,
- // and no other gated or-pattern has been parsed thus far,
- // then we should really gate the leading `|`.
- // This complicated procedure is done purely for diagnostics UX.
- if gated_leading_vert && self.sess.gated_spans.is_ungated(sym::or_patterns) {
- self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span);
- }
-
- Ok(pat)
- }
-
- /// Parse the pattern for a function or function pointer parameter.
- /// Special recovery is provided for or-patterns and leading `|`.
- pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P<Pat>> {
- self.recover_leading_vert(None, "not allowed in a parameter pattern");
- let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?;
-
- if let PatKind::Or(..) = &pat.kind {
- self.ban_illegal_fn_param_or_pat(&pat);
- }
-
- Ok(pat)
- }
+ let leading_vert_span =
+ if self.eat_or_separator(None) { Some(self.prev_token.span) } else { None };
- /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens.
- fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) {
- let msg = "wrap the pattern in parenthesis";
- let fix = format!("({})", pprust::pat_to_string(pat));
- self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parenthesis")
- .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable)
- .emit();
- }
-
- /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`).
- /// Corresponds to `pat<allow_top_alt>` in RFC 2535.
- fn parse_pat_with_or(
- &mut self,
- expected: Expected,
- gate_or: GateOr,
- rc: RecoverComma,
- ) -> PResult<'a, P<Pat>> {
// Parse the first pattern (`p_0`).
- let first_pat = self.parse_pat(expected)?;
+ let first_pat = self.parse_pat_no_top_alt(expected)?;
self.maybe_recover_unexpected_comma(first_pat.span, rc, gate_or)?;
// If the next token is not a `|`,
// this is not an or-pattern and we should exit here.
if !self.check(&token::BinOp(token::Or)) && self.token != token::OrOr {
+ // If we parsed a leading `|` which should be gated,
+ // then we should really gate the leading `|`.
+ // This complicated procedure is done purely for diagnostics UX.
+ if let Some(leading_vert_span) = leading_vert_span {
+ if gate_or == GateOr::Yes && self.sess.gated_spans.is_ungated(sym::or_patterns) {
+ self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span);
+ }
+
+ // If there was a leading vert, treat this as an or-pattern. This improves
+ // diagnostics.
+ let span = leading_vert_span.to(self.prev_token.span);
+ return Ok(self.mk_pat(span, PatKind::Or(vec![first_pat])));
+ }
+
return Ok(first_pat);
}
// Parse the patterns `p_1 | ... | p_n` where `n > 0`.
- let lo = first_pat.span;
+ let lo = leading_vert_span.unwrap_or(first_pat.span);
let mut pats = vec![first_pat];
while self.eat_or_separator(Some(lo)) {
- let pat = self.parse_pat(expected).map_err(|mut err| {
+ let pat = self.parse_pat_no_top_alt(expected).map_err(|mut err| {
err.span_label(lo, WHILE_PARSING_OR_MSG);
err
})?;
Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats)))
}
+ /// Parse the pattern for a function or function pointer parameter.
+ pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P<Pat>> {
+ // We actually do _not_ allow top-level or-patterns in function params, but we use
+ // `parse_pat_allow_top_alt` anyway so that we can detect when a user tries to use it. This
+ // allows us to print a better error message.
+ //
+ // In order to get good UX, we first recover in the case of a leading vert for an illegal
+ // top-level or-pat. Normally, this means recovering both `|` and `||`, but in this case,
+ // a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that
+ // separately.
+ if let token::OrOr = self.token.kind {
+ let span = self.token.span;
+ let mut err = self.struct_span_err(span, "unexpected `||` before function parameter");
+ err.span_suggestion(
+ span,
+ "remove the `||`",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ err.note("alternatives in or-patterns are separated with `|`, not `||`");
+ err.emit();
+ self.bump();
+ }
+
+ let pat = self.parse_pat_allow_top_alt(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?;
+
+ if let PatKind::Or(..) = &pat.kind {
+ self.ban_illegal_fn_param_or_pat(&pat);
+ }
+
+ Ok(pat)
+ }
+
+ /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens.
+ fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) {
+ // If all we have a leading vert, then print a special message. This is the case if
+ // `parse_pat_allow_top_alt` returns an or-pattern with one variant.
+ let (msg, fix) = match &pat.kind {
+ PatKind::Or(pats) if pats.len() == 1 => {
+ let msg = "remove the leading `|`";
+ let fix = pprust::pat_to_string(pat);
+ (msg, fix)
+ }
+
+ _ => {
+ let msg = "wrap the pattern in parentheses";
+ let fix = format!("({})", pprust::pat_to_string(pat));
+ (msg, fix)
+ }
+ };
+
+ self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parentheses")
+ .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable)
+ .emit();
+ }
+
/// Eat the or-pattern `|` separator.
/// If instead a `||` token is encountered, recover and pretend we parsed `|`.
fn eat_or_separator(&mut self, lo: Option<Span>) -> bool {
/// We have parsed `||` instead of `|`. Error and suggest `|` instead.
fn ban_unexpected_or_or(&mut self, lo: Option<Span>) {
- let mut err = self.struct_span_err(self.token.span, "unexpected token `||` after pattern");
+ let mut err = self.struct_span_err(self.token.span, "unexpected token `||` in pattern");
err.span_suggestion(
self.token.span,
"use a single `|` to separate multiple alternative patterns",
/// sequence of patterns until `)` is reached.
fn skip_pat_list(&mut self) -> PResult<'a, ()> {
while !self.check(&token::CloseDelim(token::Paren)) {
- self.parse_pat(None)?;
+ self.parse_pat_no_top_alt(None)?;
if !self.eat(&token::Comma) {
return Ok(());
}
Ok(())
}
- /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`.
- /// See `parse_pat_with_or` for details on parsing or-patterns.
- fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P<Pat>> {
- self.recover_leading_vert(None, "only allowed in a top-level pattern");
- self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No)
- }
-
- /// Recover if `|` or `||` is here.
- /// The user is thinking that a leading `|` is allowed in this position.
- fn recover_leading_vert(&mut self, lo: Option<Span>, ctx: &str) {
- if let token::BinOp(token::Or) | token::OrOr = self.token.kind {
- self.ban_illegal_vert(lo, "leading", ctx);
- self.bump();
- }
- }
-
/// A `|` or possibly `||` token shouldn't be here. Ban it.
fn ban_illegal_vert(&mut self, lo: Option<Span>, pos: &str, ctx: &str) {
let span = self.token.span;
self.parse_pat_tuple_or_parens()?
} else if self.check(&token::OpenDelim(token::Bracket)) {
// Parse `[pat, pat,...]` as a slice pattern.
- let (pats, _) =
- self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat_with_or_inner())?;
+ let (pats, _) = self.parse_delim_comma_seq(token::Bracket, |p| {
+ p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)
+ })?;
PatKind::Slice(pats)
} else if self.check(&token::DotDot) && !self.is_pat_range_end_start(1) {
// A rest pattern `..`.
// At this point we attempt to parse `@ $pat_rhs` and emit an error.
self.bump(); // `@`
- let mut rhs = self.parse_pat(None)?;
+ let mut rhs = self.parse_pat_no_top_alt(None)?;
let sp = lhs.span.to(rhs.span);
if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind {
/// Parse a tuple or parenthesis pattern.
fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
- let (fields, trailing_comma) =
- self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?;
+ let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
+ p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)
+ })?;
// Here, `(pat,)` is a tuple pattern.
// For backward compatibility, `(..)` is a tuple pattern as well.
}
// Parse the pattern we hope to be an identifier.
- let mut pat = self.parse_pat(Some("identifier"))?;
+ let mut pat = self.parse_pat_no_top_alt(Some("identifier"))?;
// If we don't have `mut $ident (@ pat)?`, error.
if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind {
fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind> {
let ident = self.parse_ident()?;
let sub = if self.eat(&token::At) {
- Some(self.parse_pat(Some("binding pattern"))?)
+ Some(self.parse_pat_no_top_alt(Some("binding pattern"))?)
} else {
None
};
if qself.is_some() {
return self.error_qpath_before_pat(&path, "(");
}
- let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?;
+ let (fields, _) = self.parse_paren_comma_seq(|p| {
+ p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)
+ })?;
Ok(PatKind::TupleStruct(path, fields))
}
// Parsing a pattern of the form `fieldname: pat`.
let fieldname = self.parse_field_name()?;
self.bump();
- let pat = self.parse_pat_with_or_inner()?;
+ let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)?;
hi = pat.span;
(pat, fieldname, false)
} else {
self.mk_stmt(lo, StmtKind::Empty)
} else if self.token != token::CloseDelim(token::Brace) {
// Remainder are line-expr stmts.
- let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
+ let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))?;
self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
} else {
self.error_outer_attrs(&attrs.take_for_recovery());
};
let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
- let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
+ let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs)?;
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
})?;
Ok((
}
fn recover_local_after_let(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
- let local = self.parse_local(attrs.into())?;
+ let local = self.parse_local(attrs)?;
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local)))
}
/// Parses a local variable declaration.
fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
let lo = self.prev_token.span;
- let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?;
+ let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::Yes)?;
let (err, ty) = if self.eat(&token::Colon) {
// Save the state of the parser before parsing type normally, in case there is a `:`
return None;
}
- Self::Match(IfLetGuardDesugar) => bug!("if-let guard outside a `match` expression"),
+ Self::Match(IfLetGuardDesugar) => bug!("`if let` guard outside a `match` expression"),
// All other expressions are allowed.
Self::Loop(Loop | While | WhileLet)
let mut total_size = 0;
- println!("\n{}\n", title);
+ eprintln!("\n{}\n", title);
- println!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
- println!("----------------------------------------------------------------");
+ eprintln!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
+ eprintln!("----------------------------------------------------------------");
for (label, data) in stats {
- println!(
+ eprintln!(
"{:<18}{:>18}{:>14}{:>14}",
label,
to_readable_str(data.count * data.size),
total_size += data.count * data.size;
}
- println!("----------------------------------------------------------------");
- println!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
+ eprintln!("----------------------------------------------------------------");
+ eprintln!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
}
}
hir_visit::walk_item(self, i)
}
- fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: hir::HirId) {
- self.record("Mod", Id::None, m);
- hir_visit::walk_mod(self, m, n)
- }
-
fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) {
self.record("ForeignItem", Id::Node(i.hir_id()), i);
hir_visit::walk_foreign_item(self, i)
}
impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
- fn visit_mod(&mut self, m: &'v ast::Mod, _s: Span, _a: &[ast::Attribute], _n: NodeId) {
- self.record("Mod", Id::None, m);
- ast_visit::walk_mod(self, m)
- }
-
fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
self.record("ForeignItem", Id::None, i);
ast_visit::walk_foreign_item(self, i)
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> {
self.skeleton().visit_trait(trait_ref)
}
+ fn visit_projection_ty(
+ &mut self,
+ projection: ty::ProjectionTy<'tcx>,
+ ) -> ControlFlow<Self::BreakTy> {
+ self.skeleton().visit_projection_ty(projection)
+ }
fn visit_predicates(
&mut self,
predicates: ty::GenericPredicates<'tcx>,
if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
}
+ fn visit_projection_ty(
+ &mut self,
+ projection: ty::ProjectionTy<'tcx>,
+ ) -> ControlFlow<V::BreakTy> {
+ let (trait_ref, assoc_substs) =
+ projection.trait_ref_and_own_substs(self.def_id_visitor.tcx());
+ self.visit_trait(trait_ref)?;
+ if self.def_id_visitor.shallow() {
+ ControlFlow::CONTINUE
+ } else {
+ assoc_substs.iter().try_for_each(|subst| subst.visit_with(self))
+ }
+ }
+
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
match predicate.kind().skip_binder() {
ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref }, _) => {
}
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
ty.visit_with(self)?;
- self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
+ self.visit_projection_ty(projection_ty)
}
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
ty.visit_with(self)
return ControlFlow::CONTINUE;
}
// This will also visit substs if necessary, so we don't need to recurse.
- return self.visit_trait(proj.trait_ref(tcx));
+ return self.visit_projection_ty(proj);
}
ty::Dynamic(predicates, ..) => {
// All traits in the list are considered the "primary" part of the type
}
for (poly_predicate, _) in bounds.projection_bounds {
- let tcx = self.tcx;
if self.visit(poly_predicate.skip_binder().ty).is_break()
|| self
- .visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx))
+ .visit_projection_ty(poly_predicate.skip_binder().projection_ty)
.is_break()
{
return;
}
}
-struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
+struct PrivateItemsInPublicInterfacesVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
has_pub_restricted: bool,
- old_error_set: &'a HirIdSet,
+ old_error_set_ancestry: HirIdSet,
}
-impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
+impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> {
fn check(
&self,
item_id: hir::HirId,
required_visibility: ty::Visibility,
) -> SearchInterfaceForPrivateItemsVisitor<'tcx> {
- let mut has_old_errors = false;
-
- // Slow path taken only if there any errors in the crate.
- for &id in self.old_error_set {
- // Walk up the nodes until we find `item_id` (or we hit a root).
- let mut id = id;
- loop {
- if id == item_id {
- has_old_errors = true;
- break;
- }
- let parent = self.tcx.hir().get_parent_node(id);
- if parent == id {
- break;
- }
- id = parent;
- }
-
- if has_old_errors {
- break;
- }
- }
-
SearchInterfaceForPrivateItemsVisitor {
tcx: self.tcx,
item_id,
span: self.tcx.hir().span(item_id),
required_visibility,
has_pub_restricted: self.has_pub_restricted,
- has_old_errors,
+ has_old_errors: self.old_error_set_ancestry.contains(&item_id),
in_assoc_ty: false,
}
}
}
}
-impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
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 {
+ if !old_error_set_ancestry.insert(id) {
+ break;
+ }
+ let parent = tcx.hir().get_parent_node(id);
+ if parent == id {
+ break;
+ }
+ id = parent;
+ }
+ }
+
// Check for private types and traits in public interfaces.
- let mut visitor = PrivateItemsInPublicInterfacesVisitor {
- tcx,
- has_pub_restricted,
- old_error_set: &visitor.old_error_set,
- };
+ let mut visitor =
+ PrivateItemsInPublicInterfacesVisitor { tcx, has_pub_restricted, old_error_set_ancestry };
krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
}
----------------------------------------------\
------------";
- println!("[incremental]");
- println!("[incremental] DepGraph Statistics");
- println!("{}", SEPARATOR);
- println!("[incremental]");
- println!("[incremental] Total Node Count: {}", total_node_count);
- println!("[incremental] Total Edge Count: {}", total_edge_count);
+ eprintln!("[incremental]");
+ eprintln!("[incremental] DepGraph Statistics");
+ eprintln!("{}", SEPARATOR);
+ eprintln!("[incremental]");
+ eprintln!("[incremental] Total Node Count: {}", total_node_count);
+ eprintln!("[incremental] Total Edge Count: {}", total_edge_count);
if cfg!(debug_assertions) {
let total_edge_reads = current.total_read_count.load(Relaxed);
let total_duplicate_edge_reads = current.total_duplicate_read_count.load(Relaxed);
- println!("[incremental] Total Edge Reads: {}", total_edge_reads);
- println!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
+ eprintln!("[incremental] Total Edge Reads: {}", total_edge_reads);
+ eprintln!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
}
- println!("[incremental]");
+ eprintln!("[incremental]");
- println!(
+ eprintln!(
"[incremental] {:<36}| {:<17}| {:<12}| {:<17}|",
"Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count"
);
- println!(
+ eprintln!(
"[incremental] -------------------------------------\
|------------------\
|-------------\
let node_kind_ratio = (100.0 * (stat.node_counter as f64)) / (total_node_count as f64);
let node_kind_avg_edges = (stat.edge_counter as f64) / (stat.node_counter as f64);
- println!(
+ eprintln!(
"[incremental] {:<36}|{:>16.1}% |{:>12} |{:>17.1} |",
format!("{:?}", stat.kind),
node_kind_ratio,
);
}
- println!("{}", SEPARATOR);
- println!("[incremental]");
+ eprintln!("{}", SEPARATOR);
+ eprintln!("[incremental]");
}
fn next_virtual_depnode_index(&self) -> DepNodeIndex {
});
}
- ItemKind::Mod(_) | ItemKind::ForeignMod(_) => {
+ ItemKind::Mod(..) | ItemKind::ForeignMod(_) => {
self.with_scope(item.id, |this| {
visit::walk_item(this, item);
});
crate_lint: CrateLint,
) -> PartialRes {
tracing::debug!(
- "smart_resolve_path_fragment(id={:?},qself={:?},path={:?}",
+ "smart_resolve_path_fragment(id={:?}, qself={:?}, path={:?})",
id,
qself,
path
// Before we start looking for candidates, we have to get our hands
// on the type user is trying to perform invocation on; basically:
- // we're transforming `HashMap::new` into just `HashMap`
- let path = if let Some((_, path)) = path.split_last() {
- path
- } else {
- return Some(parent_err);
+ // we're transforming `HashMap::new` into just `HashMap`.
+ let path = match path.split_last() {
+ Some((_, path)) if !path.is_empty() => path,
+ _ => return Some(parent_err),
};
let (mut err, candidates) =
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(box_patterns)]
#![feature(bool_to_option)]
+#![feature(control_flow_enum)]
#![feature(crate_visibility_modifier)]
#![feature(format_args_capture)]
#![feature(nll)]
use rustc_arena::{DroplessArena, TypedArena};
use rustc_ast::node_id::NodeMap;
+use rustc_ast::ptr::P;
use rustc_ast::unwrap_or;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{self as ast, NodeId};
use rustc_ast::{Crate, CRATE_NODE_ID};
-use rustc_ast::{ItemKind, Path};
+use rustc_ast::{ItemKind, ModKind, Path};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use smallvec::{smallvec, SmallVec};
use std::cell::{Cell, RefCell};
use std::collections::BTreeSet;
+use std::ops::ControlFlow;
use std::{cmp, fmt, iter, ptr};
use tracing::debug;
impl UsePlacementFinder {
fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, bool) {
let mut finder = UsePlacementFinder { target_module, span: None, found_use: false };
- visit::walk_crate(&mut finder, krate);
+ if let ControlFlow::Continue(..) = finder.check_mod(&krate.items, CRATE_NODE_ID) {
+ visit::walk_crate(&mut finder, krate);
+ }
(finder.span, finder.found_use)
}
-}
-impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
- fn visit_mod(
- &mut self,
- module: &'tcx ast::Mod,
- _: Span,
- _: &[ast::Attribute],
- node_id: NodeId,
- ) {
+ fn check_mod(&mut self, items: &[P<ast::Item>], node_id: NodeId) -> ControlFlow<()> {
if self.span.is_some() {
- return;
+ return ControlFlow::Break(());
}
if node_id != self.target_module {
- visit::walk_mod(self, module);
- return;
+ return ControlFlow::Continue(());
}
// find a use statement
- for item in &module.items {
+ for item in items {
match item.kind {
ItemKind::Use(..) => {
// don't suggest placing a use before the prelude
if !item.span.from_expansion() {
self.span = Some(item.span.shrink_to_lo());
self.found_use = true;
- return;
+ return ControlFlow::Break(());
}
}
// don't place use before extern crate
}
}
}
+ ControlFlow::Continue(())
+ }
+}
+
+impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
+ fn visit_item(&mut self, item: &'tcx ast::Item) {
+ if let ItemKind::Mod(_, ModKind::Loaded(items, ..)) = &item.kind {
+ if let ControlFlow::Break(..) = self.check_mod(items, item.id) {
+ return;
+ }
+ }
+ visit::walk_item(self, item);
}
}
}
pub fn print_perf_stats(&self) {
- println!(
+ eprintln!(
"Total time spent computing symbol hashes: {}",
duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock())
);
- println!(
+ eprintln!(
"Total queries canonicalized: {}",
self.perf_stats.queries_canonicalized.load(Ordering::Relaxed)
);
- println!(
+ eprintln!(
"normalize_generic_arg_after_erasing_regions: {}",
self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed)
);
- println!(
+ eprintln!(
"normalize_projection_ty: {}",
self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed)
);
self.span_until_char(sp, '{')
}
- /// Returns a new span representing just the start point of this span.
+ /// Returns a new span representing just the first character of the given span.
pub fn start_point(&self, sp: Span) -> Span {
- let pos = sp.lo().0;
- let width = self.find_width_of_character_at_span(sp, false);
- let corrected_start_position = pos.checked_add(width).unwrap_or(pos);
- let end_point = BytePos(cmp::max(corrected_start_position, sp.lo().0));
- sp.with_hi(end_point)
+ let width = {
+ let sp = sp.data();
+ let local_begin = self.lookup_byte_offset(sp.lo);
+ let start_index = local_begin.pos.to_usize();
+ let src = local_begin.sf.external_src.borrow();
+
+ let snippet = if let Some(ref src) = local_begin.sf.src {
+ Some(&src[start_index..])
+ } else if let Some(src) = src.get_source() {
+ Some(&src[start_index..])
+ } else {
+ None
+ };
+
+ match snippet {
+ None => 1,
+ Some(snippet) => match snippet.chars().next() {
+ None => 1,
+ Some(c) => c.len_utf8(),
+ },
+ }
+ };
+
+ sp.with_hi(BytePos(sp.lo().0 + width as u32))
}
- /// Returns a new span representing just the end point of this span.
+ /// Returns a new span representing just the last character of this span.
pub fn end_point(&self, sp: Span) -> Span {
let pos = sp.hi().0;
Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt())
}
- /// Finds the width of a character, either before or after the provided span.
+ /// Finds the width of the character, either before or after the end of provided span,
+ /// depending on the `forwards` parameter.
fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
let sp = sp.data();
if sp.lo == sp.hi {
// We need to extend the snippet to the end of the src rather than to end_index so when
// searching forwards for boundaries we've got somewhere to search.
let snippet = if let Some(ref src) = local_begin.sf.src {
- let len = src.len();
- &src[start_index..len]
+ &src[start_index..]
} else if let Some(src) = src.get_source() {
- let len = src.len();
- &src[start_index..len]
+ &src[start_index..]
} else {
return 1;
};
substring: &str,
n: usize,
) -> Span {
- println!(
+ eprintln!(
"span_substr(file={:?}/{:?}, substring={:?}, n={})",
file.name, file.start_pos, substring, n
);
dropck_eyepatch,
dropck_parametricity,
dylib,
+ dyn_metadata,
dyn_trait,
edition_macro_pats,
eh_catch_typeinfo,
memory,
message,
meta,
+ metadata_type,
min_align_of,
min_align_of_val,
min_const_fn,
plugin,
plugin_registrar,
plugins,
+ pointee_trait,
pointer,
pointer_trait,
pointer_trait_fmt,
("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu),
+ ("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl),
("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf),
("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf),
("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu),
+ ("riscv64gc-unknown-linux-musl", riscv64gc_unknown_linux_musl),
("aarch64-unknown-none", aarch64_unknown_none),
("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat),
--- /dev/null
+use crate::spec::{CodeModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "riscv32-unknown-linux-musl".to_string(),
+ pointer_width: 32,
+ data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
+ arch: "riscv32".to_string(),
+ options: TargetOptions {
+ unsupported_abis: super::riscv_base::unsupported_abis(),
+ code_model: Some(CodeModel::Medium),
+ cpu: "generic-rv32".to_string(),
+ features: "+m,+a,+f,+d,+c".to_string(),
+ llvm_abiname: "ilp32d".to_string(),
+ max_atomic_width: Some(32),
+ ..super::linux_musl_base::opts()
+ },
+ }
+}
--- /dev/null
+use crate::spec::{CodeModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "riscv64-unknown-linux-musl".to_string(),
+ pointer_width: 64,
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
+ arch: "riscv64".to_string(),
+ options: TargetOptions {
+ unsupported_abis: super::riscv_base::unsupported_abis(),
+ code_model: Some(CodeModel::Medium),
+ cpu: "generic-rv64".to_string(),
+ features: "+m,+a,+f,+d,+c".to_string(),
+ llvm_abiname: "lp64d".to_string(),
+ max_atomic_width: Some(64),
+ ..super::linux_musl_base::opts()
+ },
+ }
+}
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
use rustc_middle::ty::{ToPredicate, TypeFoldable};
use rustc_session::DiagnosticMessageId;
-use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
#[derive(Copy, Clone, Debug)]
let normalized_ty = fulfillcx.normalize_projection_type(
&self.infcx,
self.param_env,
- ty::ProjectionTy::from_ref_and_name(
- tcx,
- trait_ref,
- Ident::with_dummy_span(sym::Target),
- ),
+ ty::ProjectionTy {
+ item_def_id: tcx.lang_items().deref_target()?,
+ substs: trait_ref.substs,
+ },
cause,
);
if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
ty: Ty<'tcx>,
orig_env: ty::ParamEnv<'tcx>,
trait_did: DefId,
- auto_trait_callback: impl Fn(&InferCtxt<'_, 'tcx>, AutoTraitInfo<'tcx>) -> A,
+ mut auto_trait_callback: impl FnMut(&InferCtxt<'_, 'tcx>, AutoTraitInfo<'tcx>) -> A,
) -> AutoTraitResult<A> {
let tcx = self.tcx;
// We were unable to unify the abstract constant with
// a constant found in the caller bounds, there are
// now three possible cases here.
- //
- // - The substs are concrete enough that we can simply
- // try and evaluate the given constant.
- // - The abstract const still references an inference
- // variable, in this case we return `TooGeneric`.
- // - The abstract const references a generic parameter,
- // this means that we emit an error here.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum FailureKind {
+ /// The abstract const still references an inference
+ /// variable, in this case we return `TooGeneric`.
MentionsInfer,
+ /// The abstract const references a generic parameter,
+ /// this means that we emit an error here.
MentionsParam,
+ /// The substs are concrete enough that we can simply
+ /// try and evaluate the given constant.
Concrete,
}
let mut failure_kind = FailureKind::Concrete;
Some(t) => Some(t),
None => {
let ty = parent_trait_ref.skip_binder().self_ty();
- let span =
- TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id));
+ let span = TyCategory::from_ty(self.tcx, ty)
+ .map(|(_, def_id)| self.tcx.def_span(def_id));
Some((ty.to_string(), span))
}
}
self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
}
ty::PredicateKind::Projection(data) => {
- let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx);
- let self_ty = trait_ref.skip_binder().self_ty();
+ let self_ty = data.projection_ty.self_ty();
let ty = data.ty;
if predicate.references_error() {
return;
if let Some(def) = aty.ty_adt_def() {
// We also want to be able to select the array's type's original
// signature with no type arguments resolved
- flags.push((
- sym::_Self,
- Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
- ));
- let tcx = self.tcx;
- if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
- flags.push((
- sym::_Self,
- Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
- ));
- } else {
- flags.push((
- sym::_Self,
- Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
- ));
- }
+ let type_string = self.tcx.type_of(def.did).to_string();
+ flags.push((sym::_Self, Some(format!("[{}]", type_string))));
+
+ let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
+ let string = match len {
+ Some(n) => format!("[{}; {}]", type_string, n),
+ None => format!("[{}; _]", type_string),
+ };
+ flags.push((sym::_Self, Some(string)));
}
}
if let ty::Dynamic(traits, _) = self_ty.kind() {
use rustc_hir::lang_items::LangItem;
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
use rustc_middle::ty::{
- self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
- TyCtxt, TypeFoldable, WithConstness,
+ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
+ Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
};
use rustc_middle::ty::{TypeAndMut, TypeckResults};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
let (param_ty, projection) = match self_ty.kind() {
ty::Param(_) => (true, None),
ty::Projection(projection) => (false, Some(projection)),
- _ => return,
+ _ => (false, None),
};
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
}
}
+ hir::Node::Item(hir::Item {
+ kind:
+ hir::ItemKind::Struct(_, generics)
+ | hir::ItemKind::Enum(_, generics)
+ | hir::ItemKind::Union(_, generics)
+ | hir::ItemKind::Trait(_, _, generics, ..)
+ | hir::ItemKind::Impl(hir::Impl { generics, .. })
+ | hir::ItemKind::Fn(_, generics, _)
+ | hir::ItemKind::TyAlias(_, generics)
+ | hir::ItemKind::TraitAlias(generics, _)
+ | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
+ ..
+ }) if !param_ty => {
+ // Missing generic type parameter bound.
+ let param_name = self_ty.to_string();
+ let constraint = trait_ref.print_only_trait_path().to_string();
+ if suggest_arbitrary_trait_bound(generics, &mut err, ¶m_name, &constraint) {
+ return;
+ }
+ }
hir::Node::Crate(..) => return,
_ => {}
use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
use std::marker::PhantomData;
// only reason we can fail to make progress on
// trait selection is because we don't have enough
// information about the types in the trait.
- *stalled_on = trait_ref_infer_vars(
+ *stalled_on = substs_infer_vars(
self.selcx,
- trait_obligation.predicate.map_bound(|pred| pred.trait_ref),
+ trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs),
);
debug!(
match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)),
Ok(Ok(None)) => {
- *stalled_on = trait_ref_infer_vars(
+ *stalled_on = substs_infer_vars(
self.selcx,
- project_obligation.predicate.to_poly_trait_ref(tcx),
+ project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs),
);
ProcessResult::Unchanged
}
}
}
-/// Returns the set of inference variables contained in a trait ref.
-fn trait_ref_infer_vars<'a, 'tcx>(
+/// Returns the set of inference variables contained in `substs`.
+fn substs_infer_vars<'a, 'tcx>(
selcx: &mut SelectionContext<'a, 'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ substs: ty::Binder<SubstsRef<'tcx>>,
) -> Vec<TyOrConstInferVar<'tcx>> {
selcx
.infcx()
- .resolve_vars_if_possible(trait_ref)
- .skip_binder()
- .substs
+ .resolve_vars_if_possible(substs)
+ .skip_binder() // ok because this check doesn't care about regions
.iter()
// FIXME(eddyb) try using `skip_current_subtree` to skip everything that
// doesn't contain inference variables, not just the outermost level.
//
// This is ALT2 in issue #56288, see that for discussion of the
// possible alternatives.
- if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
- Some(sp)
- } else {
- None
- }
+ if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
}
ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
use super::SelectionError;
use super::{
ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
- ImplSourceGeneratorData, ImplSourceUserDefinedData,
+ ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
};
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
}
- let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx());
-
- debug!(?obligation_trait_ref);
-
- if obligation_trait_ref.references_error() {
+ if obligation.predicate.references_error() {
return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
}
// Make sure that the following procedures are kept in order. ParamEnv
// needs to be first because it has highest priority, and Select checks
// the return value of push_candidate which assumes it's ran at last.
- assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, &mut candidates);
+ assemble_candidates_from_param_env(selcx, obligation, &mut candidates);
- assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates);
+ assemble_candidates_from_trait_def(selcx, obligation, &mut candidates);
- assemble_candidates_from_object_ty(selcx, obligation, &obligation_trait_ref, &mut candidates);
+ assemble_candidates_from_object_ty(selcx, obligation, &mut candidates);
if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates {
// Avoid normalization cycle from selection (see
// `assemble_candidates_from_object_ty`).
// FIXME(lazy_normalization): Lazy normalization should save us from
- // having to do special case this.
+ // having to special case this.
} else {
- assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates);
+ assemble_candidates_from_impls(selcx, obligation, &mut candidates);
};
match candidates {
fn assemble_candidates_from_param_env<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- obligation_trait_ref: &ty::TraitRef<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
) {
debug!("assemble_candidates_from_param_env(..)");
assemble_candidates_from_predicates(
selcx,
obligation,
- obligation_trait_ref,
candidate_set,
ProjectionTyCandidate::ParamEnv,
obligation.param_env.caller_bounds().iter(),
fn assemble_candidates_from_trait_def<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- obligation_trait_ref: &ty::TraitRef<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
) {
debug!("assemble_candidates_from_trait_def(..)");
let tcx = selcx.tcx();
// Check whether the self-type is itself a projection.
// If so, extract what we know from the trait and try to come up with a good answer.
- let bounds = match *obligation_trait_ref.self_ty().kind() {
+ let bounds = match *obligation.predicate.self_ty().kind() {
ty::Projection(ref data) => tcx.item_bounds(data.item_def_id).subst(tcx, data.substs),
ty::Opaque(def_id, substs) => tcx.item_bounds(def_id).subst(tcx, substs),
ty::Infer(ty::TyVar(_)) => {
assemble_candidates_from_predicates(
selcx,
obligation,
- obligation_trait_ref,
candidate_set,
ProjectionTyCandidate::TraitDef,
bounds.iter(),
fn assemble_candidates_from_object_ty<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- obligation_trait_ref: &ty::TraitRef<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
) {
debug!("assemble_candidates_from_object_ty(..)");
let tcx = selcx.tcx();
- let self_ty = obligation_trait_ref.self_ty();
+ let self_ty = obligation.predicate.self_ty();
let object_ty = selcx.infcx().shallow_resolve(self_ty);
let data = match object_ty.kind() {
ty::Dynamic(data, ..) => data,
assemble_candidates_from_predicates(
selcx,
obligation,
- obligation_trait_ref,
candidate_set,
ProjectionTyCandidate::Object,
env_predicates,
fn assemble_candidates_from_predicates<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- obligation_trait_ref: &ty::TraitRef<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
&& infcx.probe(|_| {
selcx.match_projection_projections(
obligation,
- obligation_trait_ref,
- &data,
+ data,
potentially_unnormalized_candidates,
)
});
fn assemble_candidates_from_impls<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- obligation_trait_ref: &ty::TraitRef<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
) {
debug!("assemble_candidates_from_impls");
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
// start out by selecting the predicate `T as TraitRef<...>`:
- let poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref);
+ let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref();
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
let _ = selcx.infcx().commit_if_ok(|_| {
let impl_source = match selcx.select(&trait_obligation) {
| ty::Error(_) => false,
}
}
+ super::ImplSource::Pointee(..) => {
+ // While `Pointee` is automatically implemented for every type,
+ // the concrete metadata type may not be known yet.
+ //
+ // Any type with multiple potential metadata types is therefore not eligible.
+ let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+
+ // FIXME: should this normalize?
+ let tail = selcx.tcx().struct_tail_without_normalization(self_ty);
+ match tail.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Foreign(_)
+ | ty::Str
+ | ty::Array(..)
+ | ty::Slice(_)
+ | ty::RawPtr(..)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(..)
+ | ty::Dynamic(..)
+ | ty::Closure(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::Never
+ // If returned by `struct_tail_without_normalization` this is a unit struct
+ // without any fields, or not a struct, and therefore is Sized.
+ | ty::Adt(..)
+ // If returned by `struct_tail_without_normalization` this is the empty tuple.
+ | ty::Tuple(..)
+ // Integers and floats are always Sized, and so have unit type metadata.
+ | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
+
+ ty::Projection(..)
+ | ty::Opaque(..)
+ | ty::Param(..)
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Infer(..)
+ | ty::Error(_) => false,
+ }
+ }
super::ImplSource::Param(..) => {
// This case tell us nothing about the value of an
// associated type. Consider:
super::ImplSource::DiscriminantKind(data) => {
confirm_discriminant_kind_candidate(selcx, obligation, data)
}
+ super::ImplSource::Pointee(data) => confirm_pointee_candidate(selcx, obligation, data),
super::ImplSource::Object(_)
| super::ImplSource::AutoImpl(..)
| super::ImplSource::Param(..)
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
}
+fn confirm_pointee_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ _: ImplSourcePointeeData,
+) -> Progress<'tcx> {
+ let tcx = selcx.tcx();
+
+ let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+ let substs = tcx.mk_substs([self_ty.into()].iter());
+
+ let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
+
+ let predicate = ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
+ ty: self_ty.ptr_metadata_ty(tcx),
+ };
+
+ confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false)
+}
+
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
poly_cache_entry,
);
- let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
- let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx);
+ let cache_projection = cache_entry.projection_ty;
+ let obligation_projection = obligation.predicate;
let mut nested_obligations = Vec::new();
- let cache_trait_ref = if potentially_unnormalized_candidate {
+ let cache_projection = if potentially_unnormalized_candidate {
ensure_sufficient_stack(|| {
normalize_with_depth_to(
selcx,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
- cache_trait_ref,
+ cache_projection,
&mut nested_obligations,
)
})
} else {
- cache_trait_ref
+ cache_projection
};
- match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
+ match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
Ok(InferOk { value: _, obligations }) => {
nested_obligations.extend(obligations);
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
info!("fully_perform({:?})", self);
}
- scrape_region_constraints(infcx, || Ok((self.closure)(infcx)?))
+ scrape_region_constraints(infcx, || (self.closure)(infcx))
}
}
} else if lang_items.discriminant_kind_trait() == Some(def_id) {
// `DiscriminantKind` is automatically implemented for every type.
candidates.vec.push(DiscriminantKindCandidate);
+ } else if lang_items.pointee_trait() == Some(def_id) {
+ // `Pointee` is automatically implemented for every type.
+ candidates.vec.push(PointeeCandidate);
} else if lang_items.sized_trait() == Some(def_id) {
// Sized is never implementable by end-users, it is
// always automatically computed.
use crate::traits::{
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
- ImplSourceObjectData, ImplSourceTraitAliasData, ImplSourceUserDefinedData,
+ ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
+ ImplSourceUserDefinedData,
};
use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
use crate::traits::{Obligation, ObligationCause};
Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData))
}
+ PointeeCandidate => Ok(ImplSource::Pointee(ImplSourcePointeeData)),
+
TraitAliasCandidate(alias_def_id) => {
let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
Ok(ImplSource::TraitAlias(data))
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::Constness;
+use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::fast_reject;
pub(super) fn match_projection_projections(
&mut self,
obligation: &ProjectionTyObligation<'tcx>,
- obligation_trait_ref: &ty::TraitRef<'tcx>,
- data: &PolyProjectionPredicate<'tcx>,
+ env_predicate: PolyProjectionPredicate<'tcx>,
potentially_unnormalized_candidates: bool,
) -> bool {
let mut nested_obligations = Vec::new();
- let projection_ty = if potentially_unnormalized_candidates {
+ let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
+ obligation.cause.span,
+ LateBoundRegionConversionTime::HigherRankedType,
+ env_predicate,
+ );
+ let infer_projection = if potentially_unnormalized_candidates {
ensure_sufficient_stack(|| {
project::normalize_with_depth_to(
self,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
- data.map_bound(|data| data.projection_ty),
+ infer_predicate.projection_ty,
&mut nested_obligations,
)
})
} else {
- data.map_bound(|data| data.projection_ty)
+ infer_predicate.projection_ty
};
- // FIXME(generic_associated_types): Compare the whole projections
- let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx()));
- let obligation_poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref);
self.infcx
.at(&obligation.cause, obligation.param_env)
- .sup(obligation_poly_trait_ref, data_poly_trait_ref)
+ .sup(obligation.predicate, infer_projection)
.map_or(false, |InferOk { obligations, value: () }| {
self.evaluate_predicates_recursively(
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
let is_global =
|cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
- // (*) Prefer `BuiltinCandidate { has_nested: false }` and `DiscriminantKindCandidate`
- // to anything else.
+ // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
+ // and `DiscriminantKindCandidate` to anything else.
//
// This is a fix for #53123 and prevents winnowing from accidentally extending the
// lifetime of a variable.
}
// (*)
- (BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true,
- (_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false,
+ (
+ BuiltinCandidate { has_nested: false }
+ | DiscriminantKindCandidate
+ | PointeeCandidate,
+ _,
+ ) => true,
+ (
+ _,
+ BuiltinCandidate { has_nested: false }
+ | DiscriminantKindCandidate
+ | PointeeCandidate,
+ ) => false,
(ParamCandidate(other), ParamCandidate(victim)) => {
if other.value == victim.value && victim.constness == Constness::NotConst {
self,
interner: &RustInterner<'tcx>,
) -> chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>> {
- let trait_ref = self.projection_ty.trait_ref(interner.tcx);
+ let (trait_ref, own_substs) = self.projection_ty.trait_ref_and_own_substs(interner.tcx);
chalk_solve::rust_ir::AliasEqBound {
trait_bound: trait_ref.lower_into(interner),
associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
- parameters: self.projection_ty.substs[trait_ref.substs.len()..]
- .iter()
- .map(|arg| arg.lower_into(interner))
- .collect(),
+ parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
value: self.ty.lower_into(interner),
}
}
traits::ImplSource::AutoImpl(..)
| traits::ImplSource::Param(..)
| traits::ImplSource::TraitAlias(..)
- | traits::ImplSource::DiscriminantKind(..) => None,
+ | traits::ImplSource::DiscriminantKind(..)
+ | traits::ImplSource::Pointee(..) => None,
})
}
use crate::errors::AssocTypeBindingNotAllowed;
use crate::structured_errors::{StructuredDiagnostic, WrongNumberOfGenericArgs};
use rustc_ast::ast::ParamKindOrd;
-use rustc_errors::{struct_span_err, Applicability, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg;
use rustc_middle::ty::{
}
}
+ let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut DiagnosticBuilder<'_>| {
+ let suggestions = vec![
+ (arg.span().shrink_to_lo(), String::from("{ ")),
+ (arg.span().shrink_to_hi(), String::from(" }")),
+ ];
+ err.multipart_suggestion(
+ "if this generic argument was intended as a const parameter, \
+ surround it with braces",
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ };
+
// Specific suggestion set for diagnostics
match (arg, ¶m.kind) {
(
- GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }),
- GenericParamDefKind::Const { .. },
- ) => {
- let suggestions = vec![
- (arg.span().shrink_to_lo(), String::from("{ ")),
- (arg.span().shrink_to_hi(), String::from(" }")),
- ];
- err.multipart_suggestion(
- "if this generic argument was intended as a const parameter, \
- try surrounding it with braces:",
- suggestions,
- Applicability::MaybeIncorrect,
- );
- }
+ GenericArg::Type(hir::Ty {
+ kind: hir::TyKind::Path(rustc_hir::QPath::Resolved(_, path)),
+ ..
+ }),
+ GenericParamDefKind::Const,
+ ) => match path.res {
+ Res::Err => {
+ add_braces_suggestion(arg, &mut err);
+ err.set_primary_message(
+ "unresolved item provided when a constant was expected",
+ )
+ .emit();
+ return;
+ }
+ Res::Def(DefKind::TyParam, src_def_id) => {
+ if let Some(param_local_id) = param.def_id.as_local() {
+ let param_hir_id = tcx.hir().local_def_id_to_hir_id(param_local_id);
+ let param_name = tcx.hir().ty_param_name(param_hir_id);
+ let param_type = tcx.type_of(param.def_id);
+ if param_type.is_suggestable() {
+ err.span_suggestion(
+ tcx.def_span(src_def_id),
+ "consider changing this type paramater to a `const`-generic",
+ format!("const {}: {}", param_name, param_type),
+ Applicability::MaybeIncorrect,
+ );
+ };
+ }
+ }
+ _ => add_braces_suggestion(arg, &mut err),
+ },
+ (
+ GenericArg::Type(hir::Ty { kind: hir::TyKind::Path(_), .. }),
+ GenericParamDefKind::Const,
+ ) => add_braces_suggestion(arg, &mut err),
(
GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
GenericParamDefKind::Const { .. },
//
// We want to produce `<B as SuperTrait<i32>>::T == foo`.
- debug!(
- "add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}",
- hir_ref_id, trait_ref, binding, bounds
- );
+ debug!(?hir_ref_id, ?trait_ref, ?binding, ?bounds, "add_predicates_for_ast_type_binding",);
let tcx = self.tcx();
let candidate =
debug!("regular_traits: {:?}", regular_traits);
debug!("auto_traits: {:?}", auto_traits);
- // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
- // removing the dummy `Self` type (`trait_object_dummy_self`).
- let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| {
- if trait_ref.self_ty() != dummy_self {
- // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
- // which picks up non-supertraits where clauses - but also, the object safety
- // completely ignores trait aliases, which could be object safety hazards. We
- // `delay_span_bug` here to avoid an ICE in stable even when the feature is
- // disabled. (#66420)
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- &format!(
- "trait_ref_to_existential called on {:?} with non-dummy Self",
- trait_ref,
- ),
- );
- }
- ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
- };
-
// Erase the `dummy_self` (`trait_object_dummy_self`) used above.
- let existential_trait_refs =
- regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential));
+ let existential_trait_refs = regular_traits.iter().map(|i| {
+ i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
+ if trait_ref.self_ty() != dummy_self {
+ // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
+ // which picks up non-supertraits where clauses - but also, the object safety
+ // completely ignores trait aliases, which could be object safety hazards. We
+ // `delay_span_bug` here to avoid an ICE in stable even when the feature is
+ // disabled. (#66420)
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ &format!(
+ "trait_ref_to_existential called on {:?} with non-dummy Self",
+ trait_ref,
+ ),
+ );
+ }
+ ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
+ })
+ });
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
bound.map_bound(|b| {
- let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
- ty::ExistentialProjection {
- ty: b.ty,
- item_def_id: b.projection_ty.item_def_id,
- substs: trait_ref.substs,
+ if b.projection_ty.self_ty() != dummy_self {
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ &format!("trait_ref_to_existential called on {:?} with non-dummy Self", b),
+ );
}
+ ty::ExistentialProjection::erase_self_ty(tcx, b)
})
});
}),
assoc_name,
)
- .into_iter()
},
|| param_name.to_string(),
assoc_name,
use rustc_errors::{Applicability, ErrorReported};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ItemKind, Node};
+use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_middle::ty::fold::TypeFoldable;
}
}
- #[derive(Debug)]
struct ProhibitOpaqueVisitor<'tcx> {
opaque_identity_ty: Ty<'tcx>,
generics: &'tcx ty::Generics,
+ tcx: TyCtxt<'tcx>,
+ selftys: Vec<(Span, Option<String>)>,
}
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
}
}
+ impl Visitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
+ type Map = rustc_middle::hir::map::Map<'tcx>;
+
+ fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
+ hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ }
+
+ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
+ match arg.kind {
+ hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
+ [PathSegment { res: Some(Res::SelfTy(_, impl_ref)), .. }] => {
+ let impl_ty_name =
+ impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id));
+ self.selftys.push((path.span, impl_ty_name));
+ }
+ _ => {}
+ },
+ _ => {}
+ }
+ hir::intravisit::walk_ty(self, arg);
+ }
+ }
+
if let ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
..
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
),
generics: tcx.generics_of(def_id),
+ tcx,
+ selftys: vec![],
};
let prohibit_opaque = tcx
.explicit_item_bounds(def_id)
.iter()
.try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
debug!(
- "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
- prohibit_opaque, visitor
+ "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor.opaque_identity_ty={:?}, visitor.generics={:?}",
+ prohibit_opaque, visitor.opaque_identity_ty, visitor.generics
);
if let Some(ty) = prohibit_opaque.break_value() {
+ visitor.visit_item(&item);
let is_async = match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
matches!(origin, hir::OpaqueTyOrigin::AsyncFn)
if is_async { "async fn" } else { "impl Trait" },
);
- if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
- if snippet == "Self" {
- err.span_suggestion(
- span,
- "consider spelling out the type instead",
- format!("{:?}", ty),
- Applicability::MaybeIncorrect,
- );
- }
+ for (span, name) in visitor.selftys {
+ err.span_suggestion(
+ span,
+ "consider spelling out the type instead",
+ name.unwrap_or_else(|| format!("{:?}", ty)),
+ Applicability::MaybeIncorrect,
+ );
}
err.emit();
}
});
// Even if we can't infer the full signature, we may be able to
- // infer the kind. This can occur if there is a trait-reference
+ // infer the kind. This can occur when we elaborate a predicate
// like `F : Fn<A>`. Note that due to subtyping we could encounter
// many viable options, so pick the most restrictive.
let expected_kind = self
debug!("deduce_sig_from_projection({:?})", projection);
- let trait_ref = projection.to_poly_trait_ref(tcx);
+ let trait_def_id = projection.trait_def_id(tcx);
- let is_fn = tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some();
+ let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
- let is_gen = gen_trait == trait_ref.def_id();
+ let is_gen = gen_trait == trait_def_id;
if !is_fn && !is_gen {
debug!("deduce_sig_from_projection: not fn or generator");
return None;
}
let input_tys = if is_fn {
- let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
+ let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
};
// Check that this is a projection from the `Future` trait.
- let trait_ref = predicate.projection_ty.trait_ref(self.tcx);
+ let trait_def_id = predicate.projection_ty.trait_def_id(self.tcx);
let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span));
- if trait_ref.def_id != future_trait {
+ if trait_def_id != future_trait {
debug!("deduce_future_output_from_projection: not a future");
return None;
}
}
_ => {
self.tcx.sess.emit_err(YieldExprOutsideOfGenerator { span: expr.span });
+ // Avoid expressions without types during writeback (#78653).
+ self.check_expr(value);
self.tcx.mk_unit()
}
}
.filter_map(move |obligation| {
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Projection(data) => {
- Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation))
- }
+ ty::PredicateKind::Projection(data) => Some((
+ bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
+ obligation,
+ )),
ty::PredicateKind::Trait(data, _) => {
Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
}
};
let last_expr_ty = self.node_ty(last_expr.hir_id);
let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
+ (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _))
+ if last_def_id == exp_def_id =>
+ {
+ StatementAsExpression::CorrectType
+ }
(ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
debug!(
"both opaque, likely future {:?} {:?} {:?} {:?}",
last_def_id, last_bounds, exp_def_id, exp_bounds
);
- let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_def_id.expect_local());
- let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_def_id.expect_local());
+
+ let (last_local_id, exp_local_id) =
+ match (last_def_id.as_local(), exp_def_id.as_local()) {
+ (Some(last_hir_id), Some(exp_hir_id)) => (last_hir_id, exp_hir_id),
+ (_, _) => return None,
+ };
+
+ let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_local_id);
+ let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_local_id);
+
match (
&self.tcx.hir().expect_item(last_hir_id).kind,
&self.tcx.hir().expect_item(exp_hir_id).kind,
use rustc_trait_selection::traits::Obligation;
use std::cmp::Ordering;
+use std::iter;
use super::probe::Mode;
use super::{CandidateSource, MethodError, NoMatchData};
"no {} named `{}` found for {} `{}` in the current scope",
item_kind,
item_name,
- actual.prefix_string(),
+ actual.prefix_string(self.tcx),
ty_str,
);
if let Mode::MethodCall = mode {
ty::PredicateKind::Projection(pred) => {
let pred = bound_predicate.rebind(pred);
// `<Foo as Iterator>::Item = String`.
- let trait_ref =
- pred.skip_binder().projection_ty.trait_ref(self.tcx);
- let assoc = self
- .tcx
- .associated_item(pred.skip_binder().projection_ty.item_def_id);
- let ty = pred.skip_binder().ty;
- let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
- let quiet = format!(
- "<_ as {}>::{} = {}",
- trait_ref.print_only_trait_path(),
- assoc.ident,
- ty
+ let projection_ty = pred.skip_binder().projection_ty;
+
+ let substs_with_infer_self = tcx.mk_substs(
+ iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into())
+ .chain(projection_ty.substs.iter().skip(1)),
);
- bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
- Some((obligation, trait_ref.self_ty()))
+
+ let quiet_projection_ty = ty::ProjectionTy {
+ substs: substs_with_infer_self,
+ item_def_id: projection_ty.item_def_id,
+ };
+
+ let ty = pred.skip_binder().ty;
+
+ let obligation = format!("{} = {}", projection_ty, ty);
+ let quiet = format!("{} = {}", quiet_projection_ty, ty);
+
+ bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
+ Some((obligation, projection_ty.self_ty()))
}
ty::PredicateKind::Trait(poly_trait_ref, _) => {
let p = poly_trait_ref.trait_ref;
.map(|(_, path)| path)
.collect::<Vec<_>>()
.join("\n");
- let actual_prefix = actual.prefix_string();
+ let actual_prefix = actual.prefix_string(self.tcx);
err.set_primary_message(&format!(
"the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
));
let trait_def_ids: FxHashSet<DefId> = param
.bounds
.iter()
- .filter_map(|bound| Some(bound.trait_ref()?.trait_def_id()?))
+ .filter_map(|bound| bound.trait_ref()?.trait_def_id())
.collect();
if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
err.span_suggestions(
debug!("seed place {:?}", place);
let upvar_id = ty::UpvarId::new(*var_hir_id, local_def_id);
- let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span);
+ let capture_kind =
+ self.init_capture_kind_for_place(&place, capture_clause, upvar_id, span);
let fake_info = ty::CaptureInfo {
capture_kind_expr_id: None,
path_expr_id: None,
// If we have an origin, store it.
if let Some(origin) = delegate.current_origin.clone() {
let origin = if self.tcx.features().capture_disjoint_fields {
- origin
+ (origin.0, restrict_capture_precision(origin.1))
} else {
- // FIXME(project-rfc-2229#31): Once the changes to support reborrowing are
- // made, make sure we are selecting and restricting
- // the origin correctly.
(origin.0, Place { projections: vec![], ..origin.1 })
};
base => bug!("Expected upvar, found={:?}", base),
};
- let place = restrict_capture_precision(place, capture_info.capture_kind);
+ let place = restrict_capture_precision(place);
let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
None => {
}
}
- fn init_capture_kind(
+ fn init_capture_kind_for_place(
&self,
+ place: &Place<'tcx>,
capture_clause: hir::CaptureBy,
upvar_id: ty::UpvarId,
closure_span: Span,
) -> ty::UpvarCapture<'tcx> {
match capture_clause {
- hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None),
- hir::CaptureBy::Ref => {
+ // In case of a move closure if the data is accessed through a reference we
+ // want to capture by ref to allow precise capture using reborrows.
+ //
+ // If the data will be moved out of this place, then the place will be truncated
+ // at the first Deref in `adjust_upvar_borrow_kind_for_consume` and then moved into
+ // the closure.
+ hir::CaptureBy::Value if !place.deref_tys().any(ty::TyS::is_ref) => {
+ ty::UpvarCapture::ByValue(None)
+ }
+ hir::CaptureBy::Value | hir::CaptureBy::Ref => {
let origin = UpvarRegion(upvar_id, closure_span);
let upvar_region = self.next_region_var(origin);
let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
place_with_id, diag_expr_id, mode
);
- // we only care about moves
- match mode {
- euv::Copy => {
+ match (self.capture_clause, mode) {
+ // In non-move closures, we only care about moves
+ (hir::CaptureBy::Ref, euv::Copy) => return,
+
+ // We want to capture Copy types that read through a ref via a reborrow
+ (hir::CaptureBy::Value, euv::Copy)
+ if place_with_id.place.deref_tys().any(ty::TyS::is_ref) =>
+ {
return;
}
- euv::Move => {}
+
+ (hir::CaptureBy::Ref, euv::Move) | (hir::CaptureBy::Value, euv::Move | euv::Copy) => {}
+ };
+
+ let place = truncate_capture_for_move(place_with_id.place.clone());
+ let place_with_id = PlaceWithHirId { place: place.clone(), hir_id: place_with_id.hir_id };
+
+ if !self.capture_information.contains_key(&place) {
+ self.init_capture_info_for_place(&place_with_id, diag_expr_id);
}
let tcx = self.fcx.tcx;
let usage_span = tcx.hir().span(diag_expr_id);
- // To move out of an upvar, this must be a FnOnce closure
- self.adjust_closure_kind(
- upvar_id.closure_expr_id,
- ty::ClosureKind::FnOnce,
- usage_span,
- place_with_id.place.clone(),
- );
+ if matches!(mode, euv::Move) {
+ // To move out of an upvar, this must be a FnOnce closure
+ self.adjust_closure_kind(
+ upvar_id.closure_expr_id,
+ ty::ClosureKind::FnOnce,
+ usage_span,
+ place.clone(),
+ );
+ }
let capture_info = ty::CaptureInfo {
capture_kind_expr_id: Some(diag_expr_id),
if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id);
- let capture_kind =
- self.fcx.init_capture_kind(self.capture_clause, upvar_id, self.closure_span);
+ let capture_kind = self.fcx.init_capture_kind_for_place(
+ &place_with_id.place,
+ self.capture_clause,
+ upvar_id,
+ self.closure_span,
+ );
let expr_id = Some(diag_expr_id);
let capture_info = ty::CaptureInfo {
}
/// Truncate projections so that following rules are obeyed by the captured `place`:
-///
-/// - No Derefs in move closure, this will result in value behind a reference getting moved.
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
/// them completely.
/// - No Index projections are captured, since arrays are captured completely.
-fn restrict_capture_precision<'tcx>(
- mut place: Place<'tcx>,
- capture_kind: ty::UpvarCapture<'tcx>,
-) -> Place<'tcx> {
+fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
if place.projections.is_empty() {
// Nothing to do here
return place;
}
let mut truncated_length = usize::MAX;
- let mut first_deref_projection = usize::MAX;
for (i, proj) in place.projections.iter().enumerate() {
if proj.ty.is_unsafe_ptr() {
truncated_length = truncated_length.min(i);
break;
}
- ProjectionKind::Deref => {
- // We only drop Derefs in case of move closures
- // There might be an index projection or raw ptr ahead, so we don't stop here.
- first_deref_projection = first_deref_projection.min(i);
- }
+ ProjectionKind::Deref => {}
ProjectionKind::Field(..) => {} // ignore
ProjectionKind::Subslice => {} // We never capture this
}
}
- let length = place
- .projections
- .len()
- .min(truncated_length)
- // In case of capture `ByValue` we want to not capture derefs
- .min(match capture_kind {
- ty::UpvarCapture::ByValue(..) => first_deref_projection,
- ty::UpvarCapture::ByRef(..) => usize::MAX,
- });
+ let length = place.projections.len().min(truncated_length);
place.projections.truncate(length);
place
}
+/// Truncates a place so that the resultant capture doesn't move data out of a reference
+fn truncate_capture_for_move(mut place: Place<'tcx>) -> Place<'tcx> {
+ if let Some(i) = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref) {
+ // We only drop Derefs in case of move closures
+ // There might be an index projection or raw ptr ahead, so we don't stop here.
+ place.projections.truncate(i);
+ }
+
+ place
+}
+
fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
let variable_name = match place.base {
PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(),
let did = Some(trait_def_id);
let li = tcx.lang_items();
- // Disallow *all* explicit impls of `DiscriminantKind`, `Sized` and `Unsize` for now.
+ // Disallow *all* explicit impls of `Pointee`, `DiscriminantKind`, `Sized` and `Unsize` for now.
+ if did == li.pointee_trait() {
+ let span = impl_header_span(tcx, impl_def_id);
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0322,
+ "explicit impls for the `Pointee` trait are not permitted"
+ )
+ .span_label(span, "impl of 'Pointee' not allowed")
+ .emit();
+ return;
+ }
+
if did == li.discriminant_kind_trait() {
let span = impl_header_span(tcx, impl_def_id);
struct_span_err!(
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
// Then the projection only applies if `T` is known, but it still
// does not determine `U`.
- let inputs = parameters_for(&projection.projection_ty.trait_ref(tcx), true);
+ let inputs = parameters_for(&projection.projection_ty, true);
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
if !relies_only_on_inputs {
continue;
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Hash for *const T {
fn hash<H: Hasher>(&self, state: &mut H) {
- if mem::size_of::<Self>() == mem::size_of::<usize>() {
- // Thin pointer
- state.write_usize(*self as *const () as usize);
- } else {
- // Fat pointer
- // SAFETY: we are accessing the memory occupied by `self`
- // which is guaranteed to be valid.
- // This assumes a fat pointer can be represented by a `(usize, usize)`,
- // which is safe to do in `std` because it is shipped and kept in sync
- // with the implementation of fat pointers in `rustc`.
- let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
- state.write_usize(a);
- state.write_usize(b);
+ #[cfg(not(bootstrap))]
+ {
+ let (address, metadata) = self.to_raw_parts();
+ state.write_usize(address as usize);
+ metadata.hash(state);
+ }
+ #[cfg(bootstrap)]
+ {
+ if mem::size_of::<Self>() == mem::size_of::<usize>() {
+ // Thin pointer
+ state.write_usize(*self as *const () as usize);
+ } else {
+ // Fat pointer
+ // SAFETY: we are accessing the memory occupied by `self`
+ // which is guaranteed to be valid.
+ // This assumes a fat pointer can be represented by a `(usize, usize)`,
+ // which is safe to do in `std` because it is shipped and kept in sync
+ // with the implementation of fat pointers in `rustc`.
+ let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
+ state.write_usize(a);
+ state.write_usize(b);
+ }
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Hash for *mut T {
fn hash<H: Hasher>(&self, state: &mut H) {
- if mem::size_of::<Self>() == mem::size_of::<usize>() {
- // Thin pointer
- state.write_usize(*self as *const () as usize);
- } else {
- // Fat pointer
- // SAFETY: we are accessing the memory occupied by `self`
- // which is guaranteed to be valid.
- // This assumes a fat pointer can be represented by a `(usize, usize)`,
- // which is safe to do in `std` because it is shipped and kept in sync
- // with the implementation of fat pointers in `rustc`.
- let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
- state.write_usize(a);
- state.write_usize(b);
+ #[cfg(not(bootstrap))]
+ {
+ let (address, metadata) = self.to_raw_parts();
+ state.write_usize(address as usize);
+ metadata.hash(state);
+ }
+ #[cfg(bootstrap)]
+ {
+ if mem::size_of::<Self>() == mem::size_of::<usize>() {
+ // Thin pointer
+ state.write_usize(*self as *const () as usize);
+ } else {
+ // Fat pointer
+ // SAFETY: we are accessing the memory occupied by `self`
+ // which is guaranteed to be valid.
+ // This assumes a fat pointer can be represented by a `(usize, usize)`,
+ // which is safe to do in `std` because it is shipped and kept in sync
+ // with the implementation of fat pointers in `rustc`.
+ let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
+ state.write_usize(a);
+ state.write_usize(b);
+ }
}
}
}
#![feature(extended_key_value_attributes)]
#![feature(extern_types)]
#![feature(fundamental)]
+#![cfg_attr(not(bootstrap), feature(intra_doc_pointers))]
#![feature(intrinsics)]
#![feature(lang_items)]
#![feature(link_llvm_intrinsics)]
#![feature(auto_traits)]
#![feature(or_patterns)]
#![feature(prelude_import)]
+#![cfg_attr(not(bootstrap), feature(ptr_metadata))]
#![feature(repr_simd, platform_intrinsics)]
#![feature(rustc_attrs)]
#![feature(simd_ffi)]
#![feature(stmt_expr_attributes)]
#![feature(str_split_as_str)]
#![feature(str_split_inclusive_as_str)]
+#![feature(trait_alias)]
#![feature(transparent_unions)]
#![feature(try_blocks)]
#![feature(unboxed_closures)]
/// Carves off decimal digits up to the first non-digit character.
fn eat_digits(s: &[u8]) -> (&[u8], &[u8]) {
- let mut i = 0;
- while i < s.len() && b'0' <= s[i] && s[i] <= b'9' {
- i += 1;
- }
- (&s[..i], &s[i..])
+ let pos = s.iter().position(|c| !c.is_ascii_digit()).unwrap_or(s.len());
+ s.split_at(pos)
}
/// Exponent extraction and error checking.
/// The resulting type after dereferencing.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "deref_target"]
+ #[cfg_attr(not(bootstrap), lang = "deref_target")]
type Target: ?Sized;
/// Dereferences the value.
self as _
}
+ /// Decompose a (possibly wide) pointer into is address and metadata components.
+ ///
+ /// The pointer can be later reconstructed with [`from_raw_parts`].
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "ptr_metadata", issue = "81513")]
+ #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+ #[inline]
+ pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata) {
+ (self.cast(), metadata(self))
+ }
+
/// Returns `None` if the pointer is null, or else returns a shared reference to
/// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
/// must be used instead.
#[unstable(feature = "slice_ptr_len", issue = "71146")]
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
pub const fn len(self) -> usize {
- // SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
- // Only `std` can make this guarantee.
- unsafe { Repr { rust: self }.raw }.len
+ #[cfg(bootstrap)]
+ {
+ // SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
+ // Only `std` can make this guarantee.
+ unsafe { Repr { rust: self }.raw }.len
+ }
+ #[cfg(not(bootstrap))]
+ metadata(self)
}
/// Returns a raw pointer to the slice's buffer.
--- /dev/null
+#![unstable(feature = "ptr_metadata", issue = "81513")]
+
+use crate::fmt;
+use crate::hash::{Hash, Hasher};
+
+/// Provides the pointer metadata type of any pointed-to type.
+///
+/// # Pointer metadata
+///
+/// Raw pointer types and reference types in Rust can be thought of as made of two parts:
+/// a data pointer that contains the memory address of the value, and some metadata.
+///
+/// For statically-sized types (that implement the `Sized` traits)
+/// as well as for `extern` types,
+/// pointers are said to be “thin”: metadata is zero-sized and its type is `()`.
+///
+/// Pointers to [dynamically-sized types][dst] are said to be “wide” or “fat”,
+/// they have non-zero-sized metadata:
+///
+/// * For structs whose last field is a DST, metadata is the metadata for the last field
+/// * For the `str` type, metadata is the length in bytes as `usize`
+/// * For slice types like `[T]`, metadata is the length in items as `usize`
+/// * For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata<Self>`][DynMetadata]
+/// (e.g. `DynMetadata<dyn SomeTrait>`)
+///
+/// In the future, the Rust language may gain new kinds of types
+/// that have different pointer metadata.
+///
+/// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts
+///
+///
+/// # The `Pointee` trait
+///
+/// The point of this trait is its `Metadata` associated type,
+/// which is `()` or `usize` or `DynMetadata<_>` as described above.
+/// It is automatically implemented for every type.
+/// It can be assumed to be implemented in a generic context, even without a corresponding bound.
+///
+///
+/// # Usage
+///
+/// Raw pointers can be decomposed into the data address and metadata components
+/// with their [`to_raw_parts`] method.
+///
+/// Alternatively, metadata alone can be extracted with the [`metadata`] function.
+/// A reference can be passed to [`metadata`] and implicitly coerced.
+///
+/// A (possibly-wide) pointer can be put back together from its address and metadata
+/// with [`from_raw_parts`] or [`from_raw_parts_mut`].
+///
+/// [`to_raw_parts`]: *const::to_raw_parts
+#[lang = "pointee_trait"]
+pub trait Pointee {
+ /// The type for metadata in pointers and references to `Self`.
+ #[lang = "metadata_type"]
+ // NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
+ // in `library/core/src/ptr/metadata.rs`
+ // in sync with those here:
+ type Metadata: Copy + Send + Sync + Ord + Hash + Unpin;
+}
+
+/// Pointers to types implementing this trait alias are “thin”.
+///
+/// This includes statically-`Sized` types and `extern` types.
+///
+/// # Example
+///
+/// ```rust
+/// #![feature(ptr_metadata)]
+///
+/// fn this_never_panics<T: std::ptr::Thin>() {
+/// assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>())
+/// }
+/// ```
+#[unstable(feature = "ptr_metadata", issue = "81513")]
+// NOTE: don’t stabilize this before trait aliases are stable in the language?
+pub trait Thin = Pointee<Metadata = ()>;
+
+/// Extract the metadata component of a pointer.
+///
+/// Values of type `*mut T`, `&T`, or `&mut T` can be passed directly to this function
+/// as they implicitly coerce to `*const T`.
+///
+/// # Example
+///
+/// ```
+/// #![feature(ptr_metadata)]
+///
+/// assert_eq!(std::ptr::metadata("foo"), 3_usize);
+/// ```
+#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[inline]
+pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
+ // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
+ // and PtrComponents<T> have the same memory layouts. Only std can make this
+ // guarantee.
+ unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
+}
+
+/// Forms a (possibly-wide) raw pointer from a data address and metadata.
+///
+/// This function is safe but the returned pointer is not necessarily safe to dereference.
+/// For slices, see the documentation of [`slice::from_raw_parts`] for safety requirements.
+/// For trait objects, the metadata must come from a pointer to the same underlying ereased type.
+///
+/// [`slice::from_raw_parts`]: crate::slice::from_raw_parts
+#[unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[inline]
+pub const fn from_raw_parts<T: ?Sized>(
+ data_address: *const (),
+ metadata: <T as Pointee>::Metadata,
+) -> *const T {
+ // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
+ // and PtrComponents<T> have the same memory layouts. Only std can make this
+ // guarantee.
+ unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr }
+}
+
+/// Performs the same functionality as [`from_raw_parts`], except that a
+/// raw `*mut` pointer is returned, as opposed to a raw `*const` pointer.
+///
+/// See the documentation of [`from_raw_parts`] for more details.
+#[unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[inline]
+pub const fn from_raw_parts_mut<T: ?Sized>(
+ data_address: *mut (),
+ metadata: <T as Pointee>::Metadata,
+) -> *mut T {
+ // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
+ // and PtrComponents<T> have the same memory layouts. Only std can make this
+ // guarantee.
+ unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.mut_ptr }
+}
+
+#[repr(C)]
+pub(crate) union PtrRepr<T: ?Sized> {
+ pub(crate) const_ptr: *const T,
+ pub(crate) mut_ptr: *mut T,
+ pub(crate) components: PtrComponents<T>,
+}
+
+#[repr(C)]
+pub(crate) struct PtrComponents<T: ?Sized> {
+ pub(crate) data_address: *const (),
+ pub(crate) metadata: <T as Pointee>::Metadata,
+}
+
+// Manual impl needed to avoid `T: Copy` bound.
+impl<T: ?Sized> Copy for PtrComponents<T> {}
+
+// Manual impl needed to avoid `T: Clone` bound.
+impl<T: ?Sized> Clone for PtrComponents<T> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+/// The metadata for a `Dyn = dyn SomeTrait` trait object type.
+///
+/// It is a pointer to a vtable (virtual call table)
+/// that represents all the necessary information
+/// to manipulate the concrete type stored inside a trait object.
+/// The vtable notably it contains:
+///
+/// * type size
+/// * type alignment
+/// * a pointer to the type’s `drop_in_place` impl (may be a no-op for plain-old-data)
+/// * pointers to all the methods for the type’s implementation of the trait
+///
+/// Note that the first three are special because they’re necessary to allocate, drop,
+/// and deallocate any trait object.
+///
+/// It is possible to name this struct with a type parameter that is not a `dyn` trait object
+/// (for example `DynMetadata<u64>`) but not to obtain a meaningful value of that struct.
+#[lang = "dyn_metadata"]
+pub struct DynMetadata<Dyn: ?Sized> {
+ vtable_ptr: &'static VTable,
+ phantom: crate::marker::PhantomData<Dyn>,
+}
+
+/// The common prefix of all vtables. It is followed by function pointers for trait methods.
+///
+/// Private implementation detail of `DynMetadata::size_of` etc.
+#[repr(C)]
+struct VTable {
+ drop_in_place: fn(*mut ()),
+ size_of: usize,
+ align_of: usize,
+}
+
+impl<Dyn: ?Sized> DynMetadata<Dyn> {
+ /// Returns the size of the type associated with this vtable.
+ #[inline]
+ pub fn size_of(self) -> usize {
+ self.vtable_ptr.size_of
+ }
+
+ /// Returns the alignment of the type associated with this vtable.
+ #[inline]
+ pub fn align_of(self) -> usize {
+ self.vtable_ptr.align_of
+ }
+
+ /// Returns the size and alignment together as a `Layout`
+ #[inline]
+ pub fn layout(self) -> crate::alloc::Layout {
+ // SAFETY: the compiler emitted this vtable for a concrete Rust type which
+ // is known to have a valid layout. Same rationale as in `Layout::for_value`.
+ unsafe { crate::alloc::Layout::from_size_align_unchecked(self.size_of(), self.align_of()) }
+ }
+}
+
+unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
+unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
+
+impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish()
+ }
+}
+
+// Manual impls needed to avoid `Dyn: $Trait` bounds.
+
+impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
+
+impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
+
+impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
+ #[inline]
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
+
+impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ crate::ptr::eq::<VTable>(self.vtable_ptr, other.vtable_ptr)
+ }
+}
+
+impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
+ #[inline]
+ fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
+ (self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable))
+ }
+}
+
+impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
+ #[inline]
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ crate::ptr::hash::<VTable, _>(self.vtable_ptr, hasher)
+ }
+}
#[doc(inline)]
pub use crate::intrinsics::write_bytes;
+#[cfg(not(bootstrap))]
+mod metadata;
+#[cfg(not(bootstrap))]
+pub(crate) use metadata::PtrRepr;
+#[cfg(not(bootstrap))]
+#[unstable(feature = "ptr_metadata", issue = "81513")]
+pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin};
+
mod non_null;
#[stable(feature = "nonnull", since = "1.25.0")]
pub use non_null::NonNull;
0 as *mut T
}
+#[cfg(bootstrap)]
#[repr(C)]
pub(crate) union Repr<T> {
pub(crate) rust: *const [T],
pub(crate) raw: FatPtr<T>,
}
+#[cfg(bootstrap)]
#[repr(C)]
pub(crate) struct FatPtr<T> {
data: *const T,
pub(crate) len: usize,
}
+#[cfg(bootstrap)]
// Manual impl needed to avoid `T: Clone` bound.
impl<T> Clone for FatPtr<T> {
fn clone(&self) -> Self {
}
}
+#[cfg(bootstrap)]
// Manual impl needed to avoid `T: Copy` bound.
impl<T> Copy for FatPtr<T> {}
#[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
- // SAFETY: Accessing the value from the `Repr` union is safe since *const [T]
- // and FatPtr have the same memory layouts. Only std can make this
- // guarantee.
- unsafe { Repr { raw: FatPtr { data, len } }.rust }
+ #[cfg(bootstrap)]
+ {
+ // SAFETY: Accessing the value from the `Repr` union is safe since *const [T]
+ // and FatPtr have the same memory layouts. Only std can make this
+ // guarantee.
+ unsafe { Repr { raw: FatPtr { data, len } }.rust }
+ }
+ #[cfg(not(bootstrap))]
+ from_raw_parts(data.cast(), len)
}
/// Performs the same functionality as [`slice_from_raw_parts`], except that a
#[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
- // SAFETY: Accessing the value from the `Repr` union is safe since *mut [T]
- // and FatPtr have the same memory layouts
- unsafe { Repr { raw: FatPtr { data, len } }.rust_mut }
+ #[cfg(bootstrap)]
+ {
+ // SAFETY: Accessing the value from the `Repr` union is safe since *mut [T]
+ // and FatPtr have the same memory layouts
+ unsafe { Repr { raw: FatPtr { data, len } }.rust_mut }
+ }
+ #[cfg(not(bootstrap))]
+ from_raw_parts_mut(data.cast(), len)
}
/// Swaps the values at two mutable locations of the same type, without
self as _
}
+ /// Decompose a (possibly wide) pointer into is address and metadata components.
+ ///
+ /// The pointer can be later reconstructed with [`from_raw_parts_mut`].
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "ptr_metadata", issue = "81513")]
+ #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+ #[inline]
+ pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
+ (self.cast(), super::metadata(self))
+ }
+
/// Returns `None` if the pointer is null, or else returns a shared reference to
/// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
/// must be used instead.
#[unstable(feature = "slice_ptr_len", issue = "71146")]
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
pub const fn len(self) -> usize {
- // SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
- // Only `std` can make this guarantee.
- unsafe { Repr { rust_mut: self }.raw }.len
+ #[cfg(bootstrap)]
+ {
+ // SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
+ // Only `std` can make this guarantee.
+ unsafe { Repr { rust_mut: self }.raw }.len
+ }
+ #[cfg(not(bootstrap))]
+ metadata(self)
}
/// Returns a raw pointer to the slice's buffer.
}
}
+ /// Performs the same functionality as [`std::ptr::from_raw_parts`], except that a
+ /// `NonNull` pointer is returned, as opposed to a raw `*const` pointer.
+ ///
+ /// See the documentation of [`std::ptr::from_raw_parts`] for more details.
+ ///
+ /// [`std::ptr::from_raw_parts`]: crate::ptr::from_raw_parts
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "ptr_metadata", issue = "81513")]
+ #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+ #[inline]
+ pub const fn from_raw_parts(
+ data_address: NonNull<()>,
+ metadata: <T as super::Pointee>::Metadata,
+ ) -> NonNull<T> {
+ // SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_address` is.
+ unsafe {
+ NonNull::new_unchecked(super::from_raw_parts_mut(data_address.as_ptr(), metadata))
+ }
+ }
+
+ /// Decompose a (possibly wide) pointer into is address and metadata components.
+ ///
+ /// The pointer can be later reconstructed with [`NonNull::from_raw_parts`].
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "ptr_metadata", issue = "81513")]
+ #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+ #[inline]
+ pub const fn to_raw_parts(self) -> (NonNull<()>, <T as super::Pointee>::Metadata) {
+ (self.cast(), super::metadata(self.as_ptr()))
+ }
+
/// Acquires the underlying `*mut` pointer.
#[stable(feature = "nonnull", since = "1.25.0")]
#[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")]
}
}
+impl<T> Result<T, T> {
+ /// Returns the [`Ok`] value if `self` is `Ok`, and the [`Err`] value if
+ /// `self` is `Err`.
+ ///
+ /// In other words, this function returns the value (the `T`) of a
+ /// `Result<T, T>`, regardless of whether or not that result is `Ok` or
+ /// `Err`.
+ ///
+ /// This can be useful in conjunction with APIs such as
+ /// [`Atomic*::compare_exchange`], or [`slice::binary_search`][binary_search], but only in
+ /// cases where you don't care if the result was `Ok` or not.
+ ///
+ /// [`Atomic*::compare_exchange`]: crate::sync::atomic::AtomicBool::compare_exchange
+ /// [binary_search]: ../../std/primitive.slice.html#method.binary_search
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(result_into_ok_or_err)]
+ /// let ok: Result<u32, u32> = Ok(3);
+ /// let err: Result<u32, u32> = Err(4);
+ ///
+ /// assert_eq!(ok.into_ok_or_err(), 3);
+ /// assert_eq!(err.into_ok_or_err(), 4);
+ /// ```
+ #[inline]
+ #[unstable(feature = "result_into_ok_or_err", reason = "newly added", issue = "82223")]
+ pub const fn into_ok_or_err(self) -> T {
+ match self {
+ Ok(v) => v,
+ Err(v) => v,
+ }
+ }
+}
+
// This is a separate function to reduce the code size of the methods
#[inline(never)]
#[cold]
// SAFETY: const sound because we transmute out the length field as a usize (which it must be)
#[rustc_allow_const_fn_unstable(const_fn_union)]
pub const fn len(&self) -> usize {
- // SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
- // Only `std` can make this guarantee.
- unsafe { crate::ptr::Repr { rust: self }.raw.len }
+ #[cfg(bootstrap)]
+ {
+ // SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
+ // Only `std` can make this guarantee.
+ unsafe { crate::ptr::Repr { rust: self }.raw.len }
+ }
+ #[cfg(not(bootstrap))]
+ {
+ // FIXME: Replace with `crate::ptr::metadata(self)` when that is const-stable.
+ // As of this writing this causes a "Const-stable functions can only call other
+ // const-stable functions" error.
+
+ // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
+ // and PtrComponents<T> have the same memory layouts. Only std can make this
+ // guarantee.
+ unsafe { crate::ptr::PtrRepr { const_ptr: self }.components.metadata }
+ }
}
/// Returns `true` if the slice has a length of 0.
assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f);
}
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn uint_min() {
+ let x = AtomicUsize::new(0xf731);
+ assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0x137f);
+ assert_eq!(x.fetch_min(0xf731, SeqCst), 0x137f);
+ assert_eq!(x.load(SeqCst), 0x137f);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn uint_max() {
+ let x = AtomicUsize::new(0x137f);
+ assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f);
+ assert_eq!(x.load(SeqCst), 0xf731);
+ assert_eq!(x.fetch_max(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0xf731);
+}
+
#[test]
fn int_and() {
let x = AtomicIsize::new(0xf731);
assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f);
}
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn int_min() {
+ let x = AtomicIsize::new(0xf731);
+ assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0x137f);
+ assert_eq!(x.fetch_min(0xf731, SeqCst), 0x137f);
+ assert_eq!(x.load(SeqCst), 0x137f);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn int_max() {
+ let x = AtomicIsize::new(0x137f);
+ assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f);
+ assert_eq!(x.load(SeqCst), 0xf731);
+ assert_eq!(x.fetch_max(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0xf731);
+}
+
static S_FALSE: AtomicBool = AtomicBool::new(false);
static S_TRUE: AtomicBool = AtomicBool::new(true);
static S_INT: AtomicIsize = AtomicIsize::new(0);
#![feature(duration_saturating_ops)]
#![feature(duration_zero)]
#![feature(exact_size_is_empty)]
+#![feature(extern_types)]
#![feature(fixed_size_array)]
#![feature(flt2dec)]
#![feature(fmt_internals)]
#![feature(never_type)]
#![feature(unwrap_infallible)]
#![feature(option_result_unwrap_unchecked)]
+#![feature(result_into_ok_or_err)]
#![feature(option_unwrap_none)]
#![feature(peekable_peek_mut)]
+#![cfg_attr(not(bootstrap), feature(ptr_metadata))]
#![feature(once_cell)]
#![feature(unsafe_block_in_unsafe_fn)]
+#![feature(unsized_tuple_coercion)]
#![feature(int_bits_const)]
#![feature(nonzero_leading_trailing_zeros)]
#![feature(const_option)]
#![feature(slice_group_by)]
#![feature(trusted_random_access)]
#![deny(unsafe_op_in_unsafe_fn)]
+#![cfg_attr(not(bootstrap), feature(unsize))]
extern crate test;
use core::cell::RefCell;
+#[cfg(not(bootstrap))]
+use core::ptr;
use core::ptr::*;
+#[cfg(not(bootstrap))]
+use std::fmt::{Debug, Display};
#[test]
fn test_const_from_raw_parts() {
assert_eq!(ptr2.offset(-2), ptr1);
}
}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn ptr_metadata() {
+ struct Unit;
+ struct Pair<A, B: ?Sized>(A, B);
+ extern "C" {
+ type Extern;
+ }
+ let () = metadata(&());
+ let () = metadata(&Unit);
+ let () = metadata(&4_u32);
+ let () = metadata(&String::new());
+ let () = metadata(&Some(4_u32));
+ let () = metadata(&ptr_metadata);
+ let () = metadata(&|| {});
+ let () = metadata(&[4, 7]);
+ let () = metadata(&(4, String::new()));
+ let () = metadata(&Pair(4, String::new()));
+ let () = metadata(0 as *const Extern);
+ let () = metadata(0 as *const <&u32 as std::ops::Deref>::Target);
+
+ assert_eq!(metadata("foo"), 3_usize);
+ assert_eq!(metadata(&[4, 7][..]), 2_usize);
+
+ let dst_tuple: &(bool, [u8]) = &(true, [0x66, 0x6F, 0x6F]);
+ let dst_struct: &Pair<bool, [u8]> = &Pair(true, [0x66, 0x6F, 0x6F]);
+ assert_eq!(metadata(dst_tuple), 3_usize);
+ assert_eq!(metadata(dst_struct), 3_usize);
+ unsafe {
+ let dst_tuple: &(bool, str) = std::mem::transmute(dst_tuple);
+ let dst_struct: &Pair<bool, str> = std::mem::transmute(dst_struct);
+ assert_eq!(&dst_tuple.1, "foo");
+ assert_eq!(&dst_struct.1, "foo");
+ assert_eq!(metadata(dst_tuple), 3_usize);
+ assert_eq!(metadata(dst_struct), 3_usize);
+ }
+
+ let vtable_1: DynMetadata<dyn Debug> = metadata(&4_u16 as &dyn Debug);
+ let vtable_2: DynMetadata<dyn Display> = metadata(&4_u16 as &dyn Display);
+ let vtable_3: DynMetadata<dyn Display> = metadata(&4_u32 as &dyn Display);
+ let vtable_4: DynMetadata<dyn Display> = metadata(&(true, 7_u32) as &(bool, dyn Display));
+ let vtable_5: DynMetadata<dyn Display> =
+ metadata(&Pair(true, 7_u32) as &Pair<bool, dyn Display>);
+ unsafe {
+ let address_1: usize = std::mem::transmute(vtable_1);
+ let address_2: usize = std::mem::transmute(vtable_2);
+ let address_3: usize = std::mem::transmute(vtable_3);
+ let address_4: usize = std::mem::transmute(vtable_4);
+ let address_5: usize = std::mem::transmute(vtable_5);
+ // Different trait => different vtable pointer
+ assert_ne!(address_1, address_2);
+ // Different erased type => different vtable pointer
+ assert_ne!(address_2, address_3);
+ // Same erased type and same trait => same vtable pointer
+ assert_eq!(address_3, address_4);
+ assert_eq!(address_3, address_5);
+ }
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn ptr_metadata_bounds() {
+ fn metadata_eq_method_address<T: ?Sized>() -> usize {
+ // The `Metadata` associated type has an `Ord` bound, so this is valid:
+ <<T as Pointee>::Metadata as PartialEq>::eq as usize
+ }
+ // "Synthetic" trait impls generated by the compiler like those of `Pointee`
+ // are not checked for bounds of associated type.
+ // So with a buggy libcore we could have both:
+ // * `<dyn Display as Pointee>::Metadata == DynMetadata`
+ // * `DynMetadata: !PartialEq`
+ // … and cause an ICE here:
+ metadata_eq_method_address::<dyn Display>();
+
+ // For this reason, let’s check here that bounds are satisfied:
+
+ let _ = static_assert_expected_bounds_for_metadata::<()>;
+ let _ = static_assert_expected_bounds_for_metadata::<usize>;
+ let _ = static_assert_expected_bounds_for_metadata::<DynMetadata<dyn Display>>;
+ fn _static_assert_associated_type<T: ?Sized>() {
+ let _ = static_assert_expected_bounds_for_metadata::<<T as Pointee>::Metadata>;
+ }
+
+ fn static_assert_expected_bounds_for_metadata<Meta>()
+ where
+ // Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs`
+ Meta: Copy + Send + Sync + Ord + std::hash::Hash + Unpin,
+ {
+ }
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn dyn_metadata() {
+ #[derive(Debug)]
+ #[repr(align(32))]
+ struct Something([u8; 47]);
+
+ let value = Something([0; 47]);
+ let trait_object: &dyn Debug = &value;
+ let meta = metadata(trait_object);
+
+ assert_eq!(meta.size_of(), 64);
+ assert_eq!(meta.size_of(), std::mem::size_of::<Something>());
+ assert_eq!(meta.align_of(), 32);
+ assert_eq!(meta.align_of(), std::mem::align_of::<Something>());
+ assert_eq!(meta.layout(), std::alloc::Layout::new::<Something>());
+
+ assert!(format!("{:?}", meta).starts_with("DynMetadata(0x"));
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn from_raw_parts() {
+ let mut value = 5_u32;
+ let address = &mut value as *mut _ as *mut ();
+ let trait_object: &dyn Display = &mut value;
+ let vtable = metadata(trait_object);
+ let trait_object = NonNull::from(trait_object);
+
+ assert_eq!(ptr::from_raw_parts(address, vtable), trait_object.as_ptr());
+ assert_eq!(ptr::from_raw_parts_mut(address, vtable), trait_object.as_ptr());
+ assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), vtable), trait_object);
+
+ let mut array = [5_u32, 5, 5, 5, 5];
+ let address = &mut array as *mut _ as *mut ();
+ let array_ptr = NonNull::from(&mut array);
+ let slice_ptr = NonNull::from(&mut array[..]);
+
+ assert_eq!(ptr::from_raw_parts(address, ()), array_ptr.as_ptr());
+ assert_eq!(ptr::from_raw_parts_mut(address, ()), array_ptr.as_ptr());
+ assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), ()), array_ptr);
+
+ assert_eq!(ptr::from_raw_parts(address, 5), slice_ptr.as_ptr());
+ assert_eq!(ptr::from_raw_parts_mut(address, 5), slice_ptr.as_ptr());
+ assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), 5), slice_ptr);
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn thin_box() {
+ let foo = ThinBox::<dyn Display>::new(4);
+ assert_eq!(foo.to_string(), "4");
+ drop(foo);
+ let bar = ThinBox::<dyn Display>::new(7);
+ assert_eq!(bar.to_string(), "7");
+
+ // A slightly more interesting library that could be built on top of metadata APIs.
+ //
+ // * It could be generalized to any `T: ?Sized` (not just trait object)
+ // if `{size,align}_of_for_meta<T: ?Sized>(T::Metadata)` are added.
+ // * Constructing a `ThinBox` without consuming and deallocating a `Box`
+ // requires either the unstable `Unsize` marker trait,
+ // or the unstable `unsized_locals` language feature,
+ // or taking `&dyn T` and restricting to `T: Copy`.
+
+ use std::alloc::*;
+ use std::marker::PhantomData;
+
+ struct ThinBox<T>
+ where
+ T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+ {
+ ptr: NonNull<DynMetadata<T>>,
+ phantom: PhantomData<T>,
+ }
+
+ impl<T> ThinBox<T>
+ where
+ T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+ {
+ pub fn new<Value: std::marker::Unsize<T>>(value: Value) -> Self {
+ let unsized_: &T = &value;
+ let meta = metadata(unsized_);
+ let meta_layout = Layout::for_value(&meta);
+ let value_layout = Layout::for_value(&value);
+ let (layout, offset) = meta_layout.extend(value_layout).unwrap();
+ // `DynMetadata` is pointer-sized:
+ assert!(layout.size() > 0);
+ // If `ThinBox<T>` is generalized to any `T: ?Sized`,
+ // handle ZSTs with a dangling pointer without going through `alloc()`,
+ // like `Box<T>` does.
+ unsafe {
+ let ptr = NonNull::new(alloc(layout))
+ .unwrap_or_else(|| handle_alloc_error(layout))
+ .cast::<DynMetadata<T>>();
+ ptr.as_ptr().write(meta);
+ ptr.cast::<u8>().as_ptr().add(offset).cast::<Value>().write(value);
+ Self { ptr, phantom: PhantomData }
+ }
+ }
+
+ fn meta(&self) -> DynMetadata<T> {
+ unsafe { *self.ptr.as_ref() }
+ }
+
+ fn layout(&self) -> (Layout, usize) {
+ let meta = self.meta();
+ Layout::for_value(&meta).extend(meta.layout()).unwrap()
+ }
+
+ fn value_ptr(&self) -> *const T {
+ let (_, offset) = self.layout();
+ let data_ptr = unsafe { self.ptr.cast::<u8>().as_ptr().add(offset) };
+ ptr::from_raw_parts(data_ptr.cast(), self.meta())
+ }
+
+ fn value_mut_ptr(&mut self) -> *mut T {
+ let (_, offset) = self.layout();
+ // FIXME: can this line be shared with the same in `value_ptr()`
+ // without upsetting Stacked Borrows?
+ let data_ptr = unsafe { self.ptr.cast::<u8>().as_ptr().add(offset) };
+ from_raw_parts_mut(data_ptr.cast(), self.meta())
+ }
+ }
+
+ impl<T> std::ops::Deref for ThinBox<T>
+ where
+ T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+ {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ unsafe { &*self.value_ptr() }
+ }
+ }
+
+ impl<T> std::ops::DerefMut for ThinBox<T>
+ where
+ T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+ {
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe { &mut *self.value_mut_ptr() }
+ }
+ }
+
+ impl<T> std::ops::Drop for ThinBox<T>
+ where
+ T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+ {
+ fn drop(&mut self) {
+ let (layout, _) = self.layout();
+ unsafe {
+ drop_in_place::<T>(&mut **self);
+ dealloc(self.ptr.cast().as_ptr(), layout);
+ }
+ }
+ }
+}
assert_eq!(ok_err.unwrap_or(50), 50);
}
+#[test]
+fn test_ok_or_err() {
+ let ok: Result<isize, isize> = Ok(100);
+ let err: Result<isize, isize> = Err(200);
+
+ assert_eq!(ok.into_ok_or_err(), 100);
+ assert_eq!(err.into_ok_or_err(), 200);
+}
+
#[test]
fn test_unwrap_or_else() {
fn handler(msg: &'static str) -> isize {
}
}
-#[stable(feature = "proc_macro_punct_eq", since = "1.49.0")]
+#[stable(feature = "proc_macro_punct_eq", since = "1.50.0")]
impl PartialEq<char> for Punct {
fn eq(&self, rhs: &char) -> bool {
self.as_char() == *rhs
}
}
+#[stable(feature = "proc_macro_punct_eq_flipped", since = "1.52.0")]
+impl PartialEq<Punct> for char {
+ fn eq(&self, rhs: &Punct) -> bool {
+ *self == rhs.as_char()
+ }
+}
+
/// An identifier (`ident`).
#[derive(Clone)]
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
inner: &'static Mutex<BufReader<StdinRaw>>,
}
-/// A locked reference to the `Stdin` handle.
+/// A locked reference to the [`Stdin`] handle.
///
/// This handle implements both the [`Read`] and [`BufRead`] traits, and
/// is constructed via the [`Stdin::lock`] method.
inner: Pin<&'static ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>>,
}
-/// A locked reference to the `Stdout` handle.
+/// A locked reference to the [`Stdout`] handle.
///
/// This handle implements the [`Write`] trait, and is constructed via
/// the [`Stdout::lock`] method.
inner: Pin<&'static ReentrantMutex<RefCell<StderrRaw>>>,
}
-/// A locked reference to the `Stderr` handle.
+/// A locked reference to the [`Stderr`] handle.
///
-/// This handle implements the `Write` trait and is constructed via
+/// This handle implements the [`Write`] trait and is constructed via
/// the [`Stderr::lock`] method.
///
/// ### Note: Windows Portability Consideration
#![feature(int_error_matching)]
#![feature(integer_atomics)]
#![feature(into_future)]
+#![cfg_attr(not(bootstrap), feature(intra_doc_pointers))]
#![feature(lang_items)]
#![feature(link_args)]
#![feature(linkage)]
data: UnsafeCell::new(t),
}
}
+
+ /// Immediately drops the guard, and consequently unlocks the mutex.
+ ///
+ /// This function is equivalent to calling [`drop`] on the guard but is more self-documenting.
+ /// Alternately, the guard will be automatically dropped when it goes out of scope.
+ ///
+ /// ```
+ /// #![feature(mutex_unlock)]
+ ///
+ /// use std::sync::Mutex;
+ /// let mutex = Mutex::new(0);
+ ///
+ /// let mut guard = mutex.lock().unwrap();
+ /// *guard += 20;
+ /// Mutex::unlock(guard);
+ /// ```
+ #[unstable(feature = "mutex_unlock", issue = "81872")]
+ pub fn unlock(guard: MutexGuard<'_, T>) {
+ drop(guard);
+ }
}
impl<T: ?Sized> Mutex<T> {
/// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
+
+ /// Forces all arguments to be wrapped in quote (`"`) characters.
+ ///
+ /// This is useful for passing arguments to [MSYS2/Cygwin][1] based
+ /// executables: these programs will expand unquoted arguments containing
+ /// wildcard characters (`?` and `*`) by searching for any file paths
+ /// matching the wildcard pattern.
+ ///
+ /// Adding quotes has no effect when passing arguments to programs
+ /// that use [msvcrt][2]. This includes programs built with both
+ /// MinGW and MSVC.
+ ///
+ /// [1]: <https://github.com/msys2/MSYS2-packages/issues/2176>
+ /// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx>
+ #[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")]
+ fn force_quotes(&mut self, enabled: bool) -> &mut process::Command;
}
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
self.as_inner_mut().creation_flags(flags);
self
}
+
+ fn force_quotes(&mut self, enabled: bool) -> &mut process::Command {
+ self.as_inner_mut().force_quotes(enabled);
+ self
+ }
}
stdin: Option<Stdio>,
stdout: Option<Stdio>,
stderr: Option<Stdio>,
+ force_quotes_enabled: bool,
}
pub enum Stdio {
stdin: None,
stdout: None,
stderr: None,
+ force_quotes_enabled: false,
}
}
self.flags = flags;
}
+ pub fn force_quotes(&mut self, enabled: bool) {
+ self.force_quotes_enabled = enabled;
+ }
+
pub fn get_program(&self) -> &OsStr {
&self.program
}
si.dwFlags = c::STARTF_USESTDHANDLES;
let program = program.as_ref().unwrap_or(&self.program);
- let mut cmd_str = make_command_line(program, &self.args)?;
+ let mut cmd_str = make_command_line(program, &self.args, self.force_quotes_enabled)?;
cmd_str.push(0); // add null terminator
// stolen from the libuv code.
// 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: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
+fn make_command_line(prog: &OsStr, args: &[OsString], 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();
append_arg(&mut cmd, prog, true)?;
for arg in args {
cmd.push(' ' as u16);
- append_arg(&mut cmd, arg, false)?;
+ append_arg(&mut cmd, arg, force_quotes)?;
}
return Ok(cmd);
#[test]
fn test_make_command_line() {
- fn test_wrapper(prog: &str, args: &[&str]) -> String {
+ fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
let command_line = &make_command_line(
OsStr::new(prog),
&args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(),
+ force_quotes,
)
.unwrap();
String::from_utf16(command_line).unwrap()
}
- assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc");
+ assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc");
assert_eq!(
- test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]),
+ test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false),
"\"C:\\Program Files\\blah\\blah.exe\" aaa"
);
assert_eq!(
- test_wrapper("C:\\Program Files\\test", &["aa\"bb"]),
+ test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], false),
+ "\"C:\\Program Files\\blah\\blah.exe\" aaa v*"
+ );
+ assert_eq!(
+ test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], true),
+ "\"C:\\Program Files\\blah\\blah.exe\" \"aaa\" \"v*\""
+ );
+ assert_eq!(
+ test_wrapper("C:\\Program Files\\test", &["aa\"bb"], false),
"\"C:\\Program Files\\test\" aa\\\"bb"
);
- assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\"");
- assert_eq!(test_wrapper("echo", &["\" \\\" \\", "\\"]), "\"echo\" \"\\\" \\\\\\\" \\\\\" \\");
+ assert_eq!(test_wrapper("echo", &["a b c"], false), "\"echo\" \"a b c\"");
+ assert_eq!(
+ test_wrapper("echo", &["\" \\\" \\", "\\"], false),
+ "\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
+ );
assert_eq!(
- test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
+ test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[], false),
"\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
);
}
}
let mut completed_test = res.unwrap();
- let running_test = running_tests.remove(&completed_test.desc).unwrap();
- if let Some(join_handle) = running_test.join_handle {
- if let Err(_) = join_handle.join() {
- if let TrOk = completed_test.result {
- completed_test.result =
- TrFailedMsg("panicked after reporting success".to_string());
+ if let Some(running_test) = running_tests.remove(&completed_test.desc) {
+ if let Some(join_handle) = running_test.join_handle {
+ if let Err(_) = join_handle.join() {
+ if let TrOk = completed_test.result {
+ completed_test.result =
+ TrFailedMsg("panicked after reporting success".to_string());
+ }
}
}
}
let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32");
if concurrency == Concurrent::Yes && supports_threads {
let cfg = thread::Builder::new().name(name.as_slice().to_owned());
- Some(cfg.spawn(runtest).unwrap())
+ let mut runtest = Arc::new(Mutex::new(Some(runtest)));
+ let runtest2 = runtest.clone();
+ match cfg.spawn(move || runtest2.lock().unwrap().take().unwrap()()) {
+ Ok(handle) => Some(handle),
+ Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
+ // `ErrorKind::WouldBlock` means hitting the thread limit on some
+ // platforms, so run the test synchronously here instead.
+ Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()();
+ None
+ }
+ Err(e) => panic!("failed to spawn thread to run test: {}", e),
+ }
} else {
runtest();
None
let suggest_setup = !config.config.exists() && !matches!(config.cmd, Subcommand::Setup { .. });
if suggest_setup {
println!("warning: you have not made a `config.toml`");
- println!("help: consider running `x.py setup` or copying `config.toml.example`");
+ println!(
+ "help: consider running `./x.py setup` or copying `config.toml.example` by running \
+ `cp config.toml.example config.toml`"
+ );
} else if let Some(suggestion) = &changelog_suggestion {
println!("{}", suggestion);
}
if suggest_setup {
println!("warning: you have not made a `config.toml`");
- println!("help: consider running `x.py setup` or copying `config.toml.example`");
+ println!(
+ "help: consider running `./x.py setup` or copying `config.toml.example` by running \
+ `cp config.toml.example config.toml`"
+ );
} else if let Some(suggestion) = &changelog_suggestion {
println!("{}", suggestion);
}
use crate::dist;
use crate::native;
use crate::tool::SourceType;
-use crate::util::{exe, is_dylib, symlink_dir};
+use crate::util::{exe, is_debug_info, is_dylib, symlink_dir};
use crate::{Compiler, DependencyType, GitRepo, Mode};
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
let src_libdir = builder.sysroot_libdir(build_compiler, host);
for f in builder.read_dir(&src_libdir) {
let filename = f.file_name().into_string().unwrap();
- if is_dylib(&filename) && !proc_macros.contains(&filename) {
+ if (is_dylib(&filename) || is_debug_info(&filename)) && !proc_macros.contains(&filename)
+ {
builder.copy(&f.path(), &rustc_libdir.join(&filename));
}
}
if !(filename.ends_with(".rlib")
|| filename.ends_with(".lib")
|| filename.ends_with(".a")
+ || is_debug_info(&filename)
|| is_dylib(&filename)
|| (is_check && filename.ends_with(".rmeta")))
{
}
fn default_path(config: &Option<PathBuf>, default: &str) -> PathBuf {
- PathBuf::from(config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default)))
+ config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default))
}
fn prepare_dir(mut path: PathBuf) -> String {
name.ends_with(".dylib") || name.ends_with(".so") || name.ends_with(".dll")
}
+/// Returns `true` if the file name given looks like a debug info file
+pub fn is_debug_info(name: &str) -> bool {
+ // FIXME: consider split debug info on other platforms (e.g., Linux, macOS)
+ name.ends_with(".pdb")
+}
+
/// Returns the corresponding relative library directory that the compiler's
/// dylibs will be found in.
pub fn libdir(target: TargetSelection) -> &'static str {
`powerpc64-unknown-linux-musl` | ? | |
`powerpc64-wrs-vxworks` | ? | |
`powerpc64le-unknown-linux-musl` | ? | |
+`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0)
`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33)
+`riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
`sparc64-unknown-openbsd` | ? | |
When `rustdoc` receives this flag, it will print an extra "Version (version)" into the sidebar of
the crate root's docs. You can use this flag to differentiate between different versions of your
library's documentation.
+
+## `@path`: load command-line flags from a path
+
+If you specify `@path` on the command-line, then it will open `path` and read
+command line options from it. These options are one per line; a blank line indicates
+an empty option. The file can use Unix or Windows style line endings, and must be
+encoded as UTF-8.
}
crate struct AutoTraitFinder<'a, 'tcx> {
- crate cx: &'a core::DocContext<'tcx>,
- crate f: auto_trait::AutoTraitFinder<'tcx>,
+ crate cx: &'a mut core::DocContext<'tcx>,
}
impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
- crate fn new(cx: &'a core::DocContext<'tcx>) -> Self {
- let f = auto_trait::AutoTraitFinder::new(cx.tcx);
+ crate fn new(cx: &'a mut core::DocContext<'tcx>) -> Self {
+ AutoTraitFinder { cx }
+ }
+
+ fn generate_for_trait(
+ &mut self,
+ ty: Ty<'tcx>,
+ trait_def_id: DefId,
+ param_env: ty::ParamEnv<'tcx>,
+ param_env_def_id: DefId,
+ f: &auto_trait::AutoTraitFinder<'tcx>,
+ // If this is set, show only negative trait implementations, not positive ones.
+ discard_positive_impl: bool,
+ ) -> Option<Item> {
+ let tcx = self.cx.tcx;
+ let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) };
+ if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) {
+ debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
+ return None;
+ }
+
+ let result = f.find_auto_trait_generics(ty, param_env, trait_def_id, |infcx, info| {
+ let region_data = info.region_data;
+
+ let names_map = tcx
+ .generics_of(param_env_def_id)
+ .params
+ .iter()
+ .filter_map(|param| match param.kind {
+ ty::GenericParamDefKind::Lifetime => Some(param.name),
+ _ => None,
+ })
+ .map(|name| (name, Lifetime(name)))
+ .collect();
+ let lifetime_predicates = Self::handle_lifetimes(®ion_data, &names_map);
+ let new_generics = self.param_env_to_generics(
+ infcx.tcx,
+ param_env_def_id,
+ info.full_user_env,
+ lifetime_predicates,
+ info.vid_to_region,
+ );
+
+ debug!(
+ "find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \
+ finished with {:?}",
+ param_env_def_id, trait_def_id, new_generics
+ );
+
+ new_generics
+ });
+
+ let negative_polarity;
+ let new_generics = match result {
+ AutoTraitResult::PositiveImpl(new_generics) => {
+ negative_polarity = false;
+ if discard_positive_impl {
+ return None;
+ }
+ new_generics
+ }
+ AutoTraitResult::NegativeImpl => {
+ negative_polarity = true;
+
+ // For negative impls, we use the generic params, but *not* the predicates,
+ // from the original type. Otherwise, the displayed impl appears to be a
+ // conditional negative impl, when it's really unconditional.
+ //
+ // For example, consider the struct Foo<T: Copy>(*mut T). Using
+ // the original predicates in our impl would cause us to generate
+ // `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
+ // implements Send where T is not copy.
+ //
+ // Instead, we generate `impl !Send for Foo<T>`, which better
+ // expresses the fact that `Foo<T>` never implements `Send`,
+ // regardless of the choice of `T`.
+ let params = (tcx.generics_of(param_env_def_id), ty::GenericPredicates::default())
+ .clean(self.cx)
+ .params;
+
+ Generics { params, where_predicates: Vec::new() }
+ }
+ AutoTraitResult::ExplicitImpl => return None,
+ };
- AutoTraitFinder { cx, f }
+ Some(Item {
+ source: Span::dummy(),
+ name: None,
+ attrs: Default::default(),
+ visibility: Inherited,
+ def_id: self.cx.next_def_id(param_env_def_id.krate),
+ kind: box ImplItem(Impl {
+ unsafety: hir::Unsafety::Normal,
+ generics: new_generics,
+ provided_trait_methods: Default::default(),
+ trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
+ for_: ty.clean(self.cx),
+ items: Vec::new(),
+ negative_polarity,
+ synthetic: true,
+ blanket_impl: None,
+ }),
+ })
}
// FIXME(eddyb) figure out a better way to pass information about
// parametrization of `ty` than `param_env_def_id`.
- crate fn get_auto_trait_impls(&self, ty: Ty<'tcx>, param_env_def_id: DefId) -> Vec<Item> {
- let param_env = self.cx.tcx.param_env(param_env_def_id);
+ crate fn get_auto_trait_impls(&mut self, ty: Ty<'tcx>, param_env_def_id: DefId) -> Vec<Item> {
+ let tcx = self.cx.tcx;
+ let param_env = tcx.param_env(param_env_def_id);
+ let f = auto_trait::AutoTraitFinder::new(self.cx.tcx);
debug!("get_auto_trait_impls({:?})", ty);
- let auto_traits = self.cx.auto_traits.iter().cloned();
- auto_traits
+ let auto_traits: Vec<_> = self.cx.auto_traits.iter().cloned().collect();
+ let mut auto_traits: Vec<Item> = auto_traits
+ .into_iter()
.filter_map(|trait_def_id| {
- let trait_ref = ty::TraitRef {
- def_id: trait_def_id,
- substs: self.cx.tcx.mk_substs_trait(ty, &[]),
- };
- if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) {
- debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
- return None;
- }
-
- let result =
- self.f.find_auto_trait_generics(ty, param_env, trait_def_id, |infcx, info| {
- let region_data = info.region_data;
-
- let names_map = self
- .cx
- .tcx
- .generics_of(param_env_def_id)
- .params
- .iter()
- .filter_map(|param| match param.kind {
- ty::GenericParamDefKind::Lifetime => Some(param.name),
- _ => None,
- })
- .map(|name| (name, Lifetime(name)))
- .collect();
- let lifetime_predicates = self.handle_lifetimes(®ion_data, &names_map);
- let new_generics = self.param_env_to_generics(
- infcx.tcx,
- param_env_def_id,
- info.full_user_env,
- lifetime_predicates,
- info.vid_to_region,
- );
-
- debug!(
- "find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \
- finished with {:?}",
- param_env_def_id, trait_def_id, new_generics
- );
-
- new_generics
- });
-
- let negative_polarity;
- let new_generics = match result {
- AutoTraitResult::PositiveImpl(new_generics) => {
- negative_polarity = false;
- new_generics
- }
- AutoTraitResult::NegativeImpl => {
- negative_polarity = true;
-
- // For negative impls, we use the generic params, but *not* the predicates,
- // from the original type. Otherwise, the displayed impl appears to be a
- // conditional negative impl, when it's really unconditional.
- //
- // For example, consider the struct Foo<T: Copy>(*mut T). Using
- // the original predicates in our impl would cause us to generate
- // `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
- // implements Send where T is not copy.
- //
- // Instead, we generate `impl !Send for Foo<T>`, which better
- // expresses the fact that `Foo<T>` never implements `Send`,
- // regardless of the choice of `T`.
- let params = (
- self.cx.tcx.generics_of(param_env_def_id),
- ty::GenericPredicates::default(),
- )
- .clean(self.cx)
- .params;
-
- Generics { params, where_predicates: Vec::new() }
- }
- AutoTraitResult::ExplicitImpl => return None,
- };
-
- Some(Item {
- source: Span::dummy(),
- name: None,
- attrs: Default::default(),
- visibility: Inherited,
- def_id: self.cx.next_def_id(param_env_def_id.krate),
- kind: box ImplItem(Impl {
- unsafety: hir::Unsafety::Normal,
- generics: new_generics,
- provided_trait_methods: Default::default(),
- trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
- for_: ty.clean(self.cx),
- items: Vec::new(),
- negative_polarity,
- synthetic: true,
- blanket_impl: None,
- }),
- })
+ self.generate_for_trait(ty, trait_def_id, param_env, param_env_def_id, &f, false)
})
- .collect()
+ .collect();
+ // We are only interested in case the type *doesn't* implement the Sized trait.
+ if !ty.is_sized(self.cx.tcx.at(rustc_span::DUMMY_SP), param_env) {
+ // In case `#![no_core]` is used, `sized_trait` returns nothing.
+ if let Some(item) = self.cx.tcx.lang_items().sized_trait().and_then(|sized_trait_did| {
+ self.generate_for_trait(ty, sized_trait_did, param_env, param_env_def_id, &f, true)
+ }) {
+ auto_traits.push(item);
+ }
+ }
+ auto_traits
}
- fn get_lifetime(
- &self,
- region: Region<'_>,
- names_map: &FxHashMap<Symbol, Lifetime>,
- ) -> Lifetime {
- self.region_name(region)
+ fn get_lifetime(region: Region<'_>, names_map: &FxHashMap<Symbol, Lifetime>) -> Lifetime {
+ region_name(region)
.map(|name| {
names_map.get(&name).unwrap_or_else(|| {
panic!("Missing lifetime with name {:?} for {:?}", name.as_str(), region)
.clone()
}
- fn region_name(&self, region: Region<'_>) -> Option<Symbol> {
- match region {
- &ty::ReEarlyBound(r) => Some(r.name),
- _ => None,
- }
- }
-
// This method calculates two things: Lifetime constraints of the form 'a: 'b,
// and region constraints of the form ReVar: 'a
//
// to perform the calculations we need on our own, rather than trying to make
// existing inference/solver code do what we want.
fn handle_lifetimes<'cx>(
- &self,
regions: &RegionConstraintData<'cx>,
names_map: &FxHashMap<Symbol, Lifetime>,
) -> Vec<WherePredicate> {
&Constraint::RegSubReg(r1, r2) => {
// The constraint is already in the form that we want, so we're done with it
// Desired order is 'larger, smaller', so flip then
- if self.region_name(r1) != self.region_name(r2) {
+ if region_name(r1) != region_name(r2) {
finished
- .entry(self.region_name(r2).expect("no region_name found"))
+ .entry(region_name(r2).expect("no region_name found"))
.or_default()
.push(r1);
}
for larger in deps.larger.iter() {
match (smaller, larger) {
(&RegionTarget::Region(r1), &RegionTarget::Region(r2)) => {
- if self.region_name(r1) != self.region_name(r2) {
+ if region_name(r1) != region_name(r2) {
finished
- .entry(self.region_name(r2).expect("no region name found"))
+ .entry(region_name(r2).expect("no region name found"))
.or_default()
.push(r1) // Larger, smaller
}
.get(name)
.unwrap_or(&empty)
.iter()
- .map(|region| GenericBound::Outlives(self.get_lifetime(region, names_map)))
+ .map(|region| GenericBound::Outlives(Self::get_lifetime(region, names_map)))
.collect();
if bounds.is_empty() {
// K', we use the dedicated syntax 'T: Fn() -> K'
// * We explicitly add a '?Sized' bound if we didn't find any 'Sized' predicates for a type
fn param_env_to_generics(
- &self,
+ &mut self,
tcx: TyCtxt<'tcx>,
param_env_def_id: DefId,
param_env: ty::ParamEnv<'tcx>,
_ => false,
}
})
- .map(|p| {
- let replaced = p.fold_with(&mut replacer);
- (replaced, replaced.clean(self.cx))
- });
+ .map(|p| p.fold_with(&mut replacer));
let mut generic_params =
(tcx.generics_of(param_env_def_id), tcx.explicit_predicates_of(param_env_def_id))
let mut ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)> = Default::default();
- for (orig_p, p) in clean_where_predicates {
+ for p in clean_where_predicates {
+ let (orig_p, p) = (p, p.clean(self.cx));
if p.is_none() {
continue;
}
}
}
+fn region_name(region: Region<'_>) -> Option<Symbol> {
+ match region {
+ &ty::ReEarlyBound(r) => Some(r.name),
+ _ => None,
+ }
+}
+
// Replaces all ReVars in a type with ty::Region's, using the provided map
struct RegionReplacer<'a, 'tcx> {
vid_to_region: &'a FxHashMap<ty::RegionVid, ty::Region<'tcx>>,
use super::*;
crate struct BlanketImplFinder<'a, 'tcx> {
- crate cx: &'a core::DocContext<'tcx>,
+ crate cx: &'a mut core::DocContext<'tcx>,
}
impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
- crate fn new(cx: &'a core::DocContext<'tcx>) -> Self {
- BlanketImplFinder { cx }
- }
-
// FIXME(eddyb) figure out a better way to pass information about
// parametrization of `ty` than `param_env_def_id`.
- crate fn get_blanket_impls(&self, ty: Ty<'tcx>, param_env_def_id: DefId) -> Vec<Item> {
+ crate fn get_blanket_impls(&mut self, ty: Ty<'tcx>, param_env_def_id: DefId) -> Vec<Item> {
let param_env = self.cx.tcx.param_env(param_env_def_id);
debug!("get_blanket_impls({:?})", ty);
///
/// `parent_module` refers to the parent of the *re-export*, not the original item.
crate fn try_inline(
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
parent_module: DefId,
res: Res,
name: Symbol,
}
crate fn try_inline_glob(
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
res: Res,
visited: &mut FxHashSet<DefId>,
) -> Option<Vec<clean::Item>> {
}
}
-crate fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
+crate fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
let trait_items =
cx.tcx.associated_items(did).in_definition_order().map(|item| item.clean(cx)).collect();
}
}
-fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
+fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Function {
let sig = cx.tcx.fn_sig(did);
let constness =
if is_min_const_fn(cx.tcx, did) { hir::Constness::Const } else { hir::Constness::NotConst };
let asyncness = cx.tcx.asyncness(did);
let predicates = cx.tcx.predicates_of(did);
- let (generics, decl) = clean::enter_impl_trait(cx, || {
+ let (generics, decl) = clean::enter_impl_trait(cx, |cx| {
((cx.tcx.generics_of(did), predicates).clean(cx), (did, sig).clean(cx))
});
clean::Function {
}
}
-fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum {
+fn build_enum(cx: &mut DocContext<'_>, did: DefId) -> clean::Enum {
let predicates = cx.tcx.explicit_predicates_of(did);
clean::Enum {
}
}
-fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct {
+fn build_struct(cx: &mut DocContext<'_>, did: DefId) -> clean::Struct {
let predicates = cx.tcx.explicit_predicates_of(did);
let variant = cx.tcx.adt_def(did).non_enum_variant();
}
}
-fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union {
+fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union {
let predicates = cx.tcx.explicit_predicates_of(did);
let variant = cx.tcx.adt_def(did).non_enum_variant();
}
}
-fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef {
+fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::Typedef {
let predicates = cx.tcx.explicit_predicates_of(did);
let type_ = cx.tcx.type_of(did).clean(cx);
/// Builds all inherent implementations of an ADT (struct/union/enum) or Trait item/path/reexport.
crate fn build_impls(
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
parent_module: Option<DefId>,
did: DefId,
attrs: Option<Attrs<'_>>,
/// `parent_module` refers to the parent of the re-export, not the original item
fn merge_attrs(
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
parent_module: Option<DefId>,
old_attrs: Attrs<'_>,
new_attrs: Option<Attrs<'_>>,
/// Builds a specific implementation of a type. The `did` could be a type method or trait method.
crate fn build_impl(
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
parent_module: impl Into<Option<DefId>>,
did: DefId,
attrs: Option<Attrs<'_>>,
}
})
.collect::<Vec<_>>(),
- clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)),
+ clean::enter_impl_trait(cx, |cx| (tcx.generics_of(did), predicates).clean(cx)),
),
};
let polarity = tcx.impl_polarity(did);
ret.push(item);
}
-fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet<DefId>) -> clean::Module {
+fn build_module(
+ cx: &mut DocContext<'_>,
+ did: DefId,
+ visited: &mut FxHashSet<DefId>,
+) -> clean::Module {
let mut items = Vec::new();
// If we're re-exporting a re-export it may actually re-export something in
}
}
-fn build_const(cx: &DocContext<'_>, did: DefId) -> clean::Constant {
+fn build_const(cx: &mut DocContext<'_>, did: DefId) -> clean::Constant {
clean::Constant {
type_: cx.tcx.type_of(did).clean(cx),
expr: print_inlined_const(cx, did),
}
}
-fn build_static(cx: &DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
+fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
clean::Static {
type_: cx.tcx.type_of(did).clean(cx),
mutability: if mutable { Mutability::Mut } else { Mutability::Not },
}
}
-fn build_macro(cx: &DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemKind {
+fn build_macro(cx: &mut DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemKind {
let imported_from = cx.tcx.original_crate_name(did.krate);
match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) {
LoadedMacro::MacroDef(def, _) => {
(g, ty_bounds)
}
-crate fn record_extern_trait(cx: &DocContext<'_>, did: DefId) {
+crate fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
if did.is_local() {
return;
}
crate use self::types::*;
crate trait Clean<T> {
- fn clean(&self, cx: &DocContext<'_>) -> T;
+ fn clean(&self, cx: &mut DocContext<'_>) -> T;
}
impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
- fn clean(&self, cx: &DocContext<'_>) -> Vec<U> {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Vec<U> {
self.iter().map(|x| x.clean(cx)).collect()
}
}
impl<T: Clean<U>, U, V: Idx> Clean<IndexVec<V, U>> for IndexVec<V, T> {
- fn clean(&self, cx: &DocContext<'_>) -> IndexVec<V, U> {
+ fn clean(&self, cx: &mut DocContext<'_>) -> IndexVec<V, U> {
self.iter().map(|x| x.clean(cx)).collect()
}
}
impl<T: Clean<U>, U> Clean<U> for &T {
- fn clean(&self, cx: &DocContext<'_>) -> U {
+ fn clean(&self, cx: &mut DocContext<'_>) -> U {
(**self).clean(cx)
}
}
impl<T: Clean<U>, U> Clean<U> for Rc<T> {
- fn clean(&self, cx: &DocContext<'_>) -> U {
+ fn clean(&self, cx: &mut DocContext<'_>) -> U {
(**self).clean(cx)
}
}
impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
- fn clean(&self, cx: &DocContext<'_>) -> Option<U> {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Option<U> {
self.as_ref().map(|v| v.clean(cx))
}
}
impl Clean<ExternalCrate> for CrateNum {
- fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
+ fn clean(&self, cx: &mut DocContext<'_>) -> ExternalCrate {
+ let tcx = cx.tcx;
let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
- let krate_span = cx.tcx.def_span(root);
+ let krate_span = tcx.def_span(root);
let krate_src = cx.sess().source_map().span_to_filename(krate_span);
// Collect all inner modules which are tagged as implementations of
// Also note that this does not attempt to deal with modules tagged
// duplicately for the same primitive. This is handled later on when
// rendering by delegating everything to a hash map.
- let as_primitive = |res: Res| {
+ let mut as_primitive = |res: Res| {
if let Res::Def(DefKind::Mod, def_id) = res {
let attrs = cx.tcx.get_attrs(def_id).clean(cx);
let mut prim = None;
None
};
let primitives = if root.is_local() {
- cx.tcx
- .hir()
+ tcx.hir()
.krate()
.item
.module
.item_ids
.iter()
.filter_map(|&id| {
- let item = cx.tcx.hir().item(id);
+ let item = tcx.hir().item(id);
match item.kind {
hir::ItemKind::Mod(_) => {
as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
})
.collect()
} else {
- cx.tcx
- .item_children(root)
- .iter()
- .map(|item| item.res)
- .filter_map(as_primitive)
- .collect()
+ tcx.item_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
};
- let as_keyword = |res: Res| {
+ let mut as_keyword = |res: Res| {
if let Res::Def(DefKind::Mod, def_id) = res {
- let attrs = cx.tcx.get_attrs(def_id).clean(cx);
+ let attrs = tcx.get_attrs(def_id).clean(cx);
let mut keyword = None;
for attr in attrs.lists(sym::doc) {
if attr.has_name(sym::keyword) {
None
};
let keywords = if root.is_local() {
- cx.tcx
- .hir()
+ tcx.hir()
.krate()
.item
.module
.item_ids
.iter()
.filter_map(|&id| {
- let item = cx.tcx.hir().item(id);
+ let item = tcx.hir().item(id);
match item.kind {
hir::ItemKind::Mod(_) => {
as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
})
.collect()
} else {
- cx.tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
+ tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
};
ExternalCrate {
- name: cx.tcx.crate_name(*self),
+ name: tcx.crate_name(*self),
src: krate_src,
- attrs: cx.tcx.get_attrs(root).clean(cx),
+ attrs: tcx.get_attrs(root).clean(cx),
primitives,
keywords,
}
}
impl Clean<Item> for doctree::Module<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let mut items: Vec<Item> = vec![];
items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
items.extend(self.mods.iter().map(|x| x.clean(cx)));
}
impl Clean<Attributes> for [ast::Attribute] {
- fn clean(&self, cx: &DocContext<'_>) -> Attributes {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Attributes {
Attributes::from_ast(cx.sess().diagnostic(), self, None)
}
}
impl Clean<GenericBound> for hir::GenericBound<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
+ fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
match *self {
hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
}
impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
- fn clean(&self, cx: &DocContext<'_>) -> Type {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
let (trait_ref, bounds) = *self;
inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait);
let path = external_path(
}
impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> {
- fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
+ fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
GenericBound::TraitBound(
PolyTrait { trait_: (*self, &[][..]).clean(cx), generic_params: vec![] },
hir::TraitBoundModifier::None,
}
impl Clean<GenericBound> for (ty::PolyTraitRef<'_>, &[TypeBinding]) {
- fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
+ fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
let (poly_trait_ref, bounds) = *self;
let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
}
impl<'tcx> Clean<GenericBound> for ty::PolyTraitRef<'tcx> {
- fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
+ fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
(*self, &[][..]).clean(cx)
}
}
impl<'tcx> Clean<Option<Vec<GenericBound>>> for InternalSubsts<'tcx> {
- fn clean(&self, cx: &DocContext<'_>) -> Option<Vec<GenericBound>> {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Option<Vec<GenericBound>> {
let mut v = Vec::new();
v.extend(self.regions().filter_map(|r| r.clean(cx)).map(GenericBound::Outlives));
v.extend(self.types().map(|t| {
}
impl Clean<Lifetime> for hir::Lifetime {
- fn clean(&self, cx: &DocContext<'_>) -> Lifetime {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Lifetime {
let def = cx.tcx.named_region(self.hir_id);
match def {
Some(
}
impl Clean<Lifetime> for hir::GenericParam<'_> {
- fn clean(&self, _: &DocContext<'_>) -> Lifetime {
+ fn clean(&self, _: &mut DocContext<'_>) -> Lifetime {
match self.kind {
hir::GenericParamKind::Lifetime { .. } => {
if !self.bounds.is_empty() {
}
impl Clean<Constant> for hir::ConstArg {
- fn clean(&self, cx: &DocContext<'_>) -> Constant {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Constant {
Constant {
type_: cx
.tcx
}
impl Clean<Lifetime> for ty::GenericParamDef {
- fn clean(&self, _cx: &DocContext<'_>) -> Lifetime {
+ fn clean(&self, _cx: &mut DocContext<'_>) -> Lifetime {
Lifetime(self.name)
}
}
impl Clean<Option<Lifetime>> for ty::RegionKind {
- fn clean(&self, _cx: &DocContext<'_>) -> Option<Lifetime> {
+ fn clean(&self, _cx: &mut DocContext<'_>) -> Option<Lifetime> {
match *self {
ty::ReStatic => Some(Lifetime::statik()),
ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name) }) => {
}
impl Clean<WherePredicate> for hir::WherePredicate<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
+ fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
match *self {
hir::WherePredicate::BoundPredicate(ref wbp) => WherePredicate::BoundPredicate {
ty: wbp.bounded_ty.clean(cx),
}
impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
- fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
let bound_predicate = self.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(pred, _) => Some(bound_predicate.rebind(pred).clean(cx)),
}
impl<'a> Clean<WherePredicate> for ty::PolyTraitPredicate<'a> {
- fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
+ fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
let poly_trait_ref = self.map_bound(|pred| pred.trait_ref);
WherePredicate::BoundPredicate {
ty: poly_trait_ref.skip_binder().self_ty().clean(cx),
impl<'tcx> Clean<Option<WherePredicate>>
for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
{
- fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
let ty::OutlivesPredicate(a, b) = self;
if let (ty::ReEmpty(_), ty::ReEmpty(_)) = (a, b) {
}
impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
- fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
let ty::OutlivesPredicate(ty, lt) = self;
if let ty::ReEmpty(_) = lt {
}
impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
- fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
+ fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
let ty::ProjectionPredicate { projection_ty, ty } = self;
WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) }
}
}
impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
- fn clean(&self, cx: &DocContext<'_>) -> Type {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
let lifted = self.lift_to_tcx(cx.tcx).unwrap();
let trait_ = match lifted.trait_ref(cx.tcx).clean(cx) {
GenericBound::TraitBound(t, _) => t.trait_,
}
impl Clean<GenericParamDef> for ty::GenericParamDef {
- fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
+ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
let (name, kind) = match self.kind {
ty::GenericParamDefKind::Lifetime => (self.name, GenericParamDefKind::Lifetime),
ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
}
impl Clean<GenericParamDef> for hir::GenericParam<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
+ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
let (name, kind) = match self.kind {
hir::GenericParamKind::Lifetime { .. } => {
let name = if !self.bounds.is_empty() {
}
impl Clean<Generics> for hir::Generics<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Generics {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
// Synthetic type-parameters are inserted after normal ones.
// In order for normal parameters to be able to refer to synthetic ones,
// scans them first.
}
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx>) {
- fn clean(&self, cx: &DocContext<'_>) -> Generics {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
use self::WherePredicate as WP;
use std::collections::BTreeMap;
if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
if let Some(proj) = impl_trait_proj.remove(&idx) {
for (trait_did, name, rhs) in proj {
- simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs.clean(cx));
+ let rhs = rhs.clean(cx);
+ simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
}
}
} else {
generics: &'a hir::Generics<'a>,
body_id: hir::BodyId,
name: &mut Symbol,
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
) -> ItemKind {
let macro_kind = item.attrs.iter().find_map(|a| {
if a.has_name(sym::proc_macro) {
}
impl<'a> Clean<Function> for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId) {
- fn clean(&self, cx: &DocContext<'_>) -> Function {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Function {
let (generics, decl) =
- enter_impl_trait(cx, || (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx)));
+ enter_impl_trait(cx, |cx| (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx)));
Function { decl, generics, header: self.0.header }
}
}
impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], &'a [Ident]) {
- fn clean(&self, cx: &DocContext<'_>) -> Arguments {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Arguments {
Arguments {
values: self
.0
}
impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], hir::BodyId) {
- fn clean(&self, cx: &DocContext<'_>) -> Arguments {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Arguments {
let body = cx.tcx.hir().body(self.1);
Arguments {
where
(&'a [hir::Ty<'a>], A): Clean<Arguments>,
{
- fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
+ fn clean(&self, cx: &mut DocContext<'_>) -> FnDecl {
FnDecl {
inputs: (self.0.inputs, self.1).clean(cx),
output: self.0.output.clean(cx),
}
impl<'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
- fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
+ fn clean(&self, cx: &mut DocContext<'_>) -> FnDecl {
let (did, sig) = *self;
let mut names = if did.is_local() { &[] } else { cx.tcx.fn_arg_names(did) }.iter();
}
impl Clean<FnRetTy> for hir::FnRetTy<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> FnRetTy {
+ fn clean(&self, cx: &mut DocContext<'_>) -> FnRetTy {
match *self {
Self::Return(ref typ) => Return(typ.clean(cx)),
Self::DefaultReturn(..) => DefaultReturn,
}
impl Clean<bool> for hir::IsAuto {
- fn clean(&self, _: &DocContext<'_>) -> bool {
+ fn clean(&self, _: &mut DocContext<'_>) -> bool {
match *self {
hir::IsAuto::Yes => true,
hir::IsAuto::No => false,
}
impl Clean<Type> for hir::TraitRef<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Type {
- resolve_type(cx, self.path.clean(cx), self.hir_ref_id)
+ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
+ let path = self.path.clean(cx);
+ resolve_type(cx, path, self.hir_ref_id)
}
}
impl Clean<PolyTrait> for hir::PolyTraitRef<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> PolyTrait {
+ fn clean(&self, cx: &mut DocContext<'_>) -> PolyTrait {
PolyTrait {
trait_: self.trait_ref.clean(cx),
generic_params: self.bound_generic_params.clean(cx),
}
impl Clean<TypeKind> for hir::def::DefKind {
- fn clean(&self, _: &DocContext<'_>) -> TypeKind {
+ fn clean(&self, _: &mut DocContext<'_>) -> TypeKind {
(*self).into()
}
}
impl Clean<Item> for hir::TraitItem<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let local_did = self.def_id.to_def_id();
- cx.with_param_env(local_did, || {
+ cx.with_param_env(local_did, |cx| {
let inner = match self.kind {
hir::TraitItemKind::Const(ref ty, default) => {
AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx.tcx, e)))
MethodItem(m, None)
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref names)) => {
- let (generics, decl) = enter_impl_trait(cx, || {
+ let (generics, decl) = enter_impl_trait(cx, |cx| {
(self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
});
let mut t = Function { header: sig.header, decl, generics };
}
impl Clean<Item> for hir::ImplItem<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let local_did = self.def_id.to_def_id();
- cx.with_param_env(local_did, || {
+ cx.with_param_env(local_did, |cx| {
let inner = match self.kind {
hir::ImplItemKind::Const(ref ty, expr) => {
AssocConstItem(ty.clean(cx), Some(print_const_expr(cx.tcx, expr)))
}
impl Clean<Item> for ty::AssocItem {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
+ let tcx = cx.tcx;
let kind = match self.kind {
ty::AssocKind::Const => {
- let ty = cx.tcx.type_of(self.def_id);
+ let ty = tcx.type_of(self.def_id);
let default = if self.defaultness.has_value() {
Some(inline::print_inlined_const(cx, self.def_id))
} else {
}
ty::AssocKind::Fn => {
let generics =
- (cx.tcx.generics_of(self.def_id), cx.tcx.explicit_predicates_of(self.def_id))
+ (tcx.generics_of(self.def_id), tcx.explicit_predicates_of(self.def_id))
.clean(cx);
- let sig = cx.tcx.fn_sig(self.def_id);
+ let sig = tcx.fn_sig(self.def_id);
let mut decl = (self.def_id, sig).clean(cx);
if self.fn_has_self_parameter {
let self_ty = match self.container {
- ty::ImplContainer(def_id) => cx.tcx.type_of(def_id),
- ty::TraitContainer(_) => cx.tcx.types.self_param,
+ ty::ImplContainer(def_id) => tcx.type_of(def_id),
+ ty::TraitContainer(_) => tcx.types.self_param,
};
let self_arg_ty = sig.input(0).skip_binder();
if self_arg_ty == self_ty {
ty::TraitContainer(_) => self.defaultness.has_value(),
};
if provided {
- let constness = if is_min_const_fn(cx.tcx, self.def_id) {
+ let constness = if is_min_const_fn(tcx, self.def_id) {
hir::Constness::Const
} else {
hir::Constness::NotConst
};
- let asyncness = cx.tcx.asyncness(self.def_id);
+ let asyncness = tcx.asyncness(self.def_id);
let defaultness = match self.container {
ty::ImplContainer(_) => Some(self.defaultness),
ty::TraitContainer(_) => None,
let my_name = self.ident.name;
if let ty::TraitContainer(_) = self.container {
- let bounds = cx.tcx.explicit_item_bounds(self.def_id);
+ let bounds = tcx.explicit_item_bounds(self.def_id);
let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
- let generics = (cx.tcx.generics_of(self.def_id), predicates).clean(cx);
+ let generics = (tcx.generics_of(self.def_id), predicates).clean(cx);
let mut bounds = generics
.where_predicates
.iter()
}
let ty = if self.defaultness.has_value() {
- Some(cx.tcx.type_of(self.def_id))
+ Some(tcx.type_of(self.def_id))
} else {
None
};
AssocTypeItem(bounds, ty.clean(cx))
} else {
// FIXME: when could this happen? Associated items in inherent impls?
- let type_ = cx.tcx.type_of(self.def_id).clean(cx);
+ let type_ = tcx.type_of(self.def_id).clean(cx);
TypedefItem(
Typedef {
type_,
}
}
-fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &DocContext<'_>) -> Type {
+fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
use rustc_hir::GenericParamCount;
let hir::Ty { hir_id, span, ref kind } = *hir_ty;
let qpath = match kind {
}
}
}
- return cx.enter_alias(ty_substs, lt_substs, ct_substs, || ty.clean(cx));
+ return cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx));
}
- resolve_type(cx, path.clean(cx), hir_id)
+ let path = path.clean(cx);
+ resolve_type(cx, path, hir_id)
}
hir::QPath::Resolved(Some(ref qself), ref p) => {
// Try to normalize `<X as Y>::T` to a type
} else {
Res::Err
};
- let trait_path = hir::Path { span, res, segments: &[] };
+ let trait_path = hir::Path { span, res, segments: &[] }.clean(cx);
Type::QPath {
name: segment.ident.name,
self_type: box qself.clean(cx),
- trait_: box resolve_type(cx, trait_path.clean(cx), hir_id),
+ trait_: box resolve_type(cx, trait_path, hir_id),
}
}
hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
}
impl Clean<Type> for hir::Ty<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Type {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
use rustc_hir::*;
match self.kind {
}
/// Returns `None` if the type could not be normalized
-fn normalize(cx: &DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
+fn normalize(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
// HACK: low-churn fix for #79459 while we wait for a trait normalization fix
if !cx.tcx.sess.opts.debugging_opts.normalize_docs {
return None;
}
impl<'tcx> Clean<Type> for Ty<'tcx> {
- fn clean(&self, cx: &DocContext<'_>) -> Type {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
debug!("cleaning type: {:?}", self);
let ty = normalize(cx, self).unwrap_or(self);
match *ty.kind() {
}
impl<'tcx> Clean<Constant> for ty::Const<'tcx> {
- fn clean(&self, cx: &DocContext<'_>) -> Constant {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Constant {
Constant {
type_: self.ty.clean(cx),
expr: format!("{}", self),
}
impl Clean<Item> for hir::StructField<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let what_rustc_thinks = Item::from_hir_id_and_parts(
self.hir_id,
Some(self.ident.name),
}
impl Clean<Item> for ty::FieldDef {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let what_rustc_thinks = Item::from_def_id_and_parts(
self.did,
Some(self.ident.name),
}
impl Clean<Visibility> for hir::Visibility<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Visibility {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Visibility {
match self.node {
hir::VisibilityKind::Public => Visibility::Public,
hir::VisibilityKind::Inherited => Visibility::Inherited,
}
impl Clean<Visibility> for ty::Visibility {
- fn clean(&self, _cx: &DocContext<'_>) -> Visibility {
+ fn clean(&self, _cx: &mut DocContext<'_>) -> Visibility {
match *self {
ty::Visibility::Public => Visibility::Public,
// NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private',
}
impl Clean<VariantStruct> for rustc_hir::VariantData<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
+ fn clean(&self, cx: &mut DocContext<'_>) -> VariantStruct {
VariantStruct {
struct_type: CtorKind::from_hir(self),
fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
}
impl Clean<Item> for ty::VariantDef {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let kind = match self.ctor_kind {
CtorKind::Const => Variant::CLike,
CtorKind::Fn => Variant::Tuple(
}
impl Clean<Variant> for hir::VariantData<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Variant {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Variant {
match self {
hir::VariantData::Struct(..) => Variant::Struct(self.clean(cx)),
hir::VariantData::Tuple(..) => {
}
impl Clean<Span> for rustc_span::Span {
- fn clean(&self, _cx: &DocContext<'_>) -> Span {
+ fn clean(&self, _cx: &mut DocContext<'_>) -> Span {
Span::from_rustc_span(*self)
}
}
impl Clean<Path> for hir::Path<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Path {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Path {
Path {
global: self.is_global(),
res: self.res,
}
impl Clean<GenericArgs> for hir::GenericArgs<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> GenericArgs {
+ fn clean(&self, cx: &mut DocContext<'_>) -> GenericArgs {
if self.parenthesized {
let output = self.bindings[0].ty().clean(cx);
GenericArgs::Parenthesized {
}
impl Clean<PathSegment> for hir::PathSegment<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> PathSegment {
+ fn clean(&self, cx: &mut DocContext<'_>) -> PathSegment {
PathSegment { name: self.ident.name, args: self.args().clean(cx) }
}
}
impl Clean<String> for Ident {
#[inline]
- fn clean(&self, cx: &DocContext<'_>) -> String {
+ fn clean(&self, cx: &mut DocContext<'_>) -> String {
self.name.clean(cx)
}
}
impl Clean<String> for Symbol {
#[inline]
- fn clean(&self, _: &DocContext<'_>) -> String {
+ fn clean(&self, _: &mut DocContext<'_>) -> String {
self.to_string()
}
}
impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl {
- let (generic_params, decl) = enter_impl_trait(cx, || {
+ fn clean(&self, cx: &mut DocContext<'_>) -> BareFunctionDecl {
+ let (generic_params, decl) = enter_impl_trait(cx, |cx| {
(self.generic_params.clean(cx), (&*self.decl, self.param_names).clean(cx))
});
BareFunctionDecl { unsafety: self.unsafety, abi: self.abi, decl, generic_params }
}
impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
- fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Vec<Item> {
use hir::ItemKind;
let (item, renamed) = self;
let def_id = item.def_id.to_def_id();
let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
- cx.with_param_env(def_id, || {
+ cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
ItemKind::Static(ty, mutability, body_id) => {
StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) })
}
impl Clean<Item> for hir::Variant<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let kind = VariantItem(self.data.clean(cx));
let what_rustc_thinks =
Item::from_hir_id_and_parts(self.id, Some(self.ident.name), kind, cx);
impl Clean<bool> for ty::ImplPolarity {
/// Returns whether the impl has negative polarity.
- fn clean(&self, _: &DocContext<'_>) -> bool {
+ fn clean(&self, _: &mut DocContext<'_>) -> bool {
match self {
&ty::ImplPolarity::Positive |
// FIXME: do we want to do something else here?
}
}
-fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &DocContext<'_>) -> Vec<Item> {
+fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>) -> Vec<Item> {
+ let tcx = cx.tcx;
let mut ret = Vec::new();
let trait_ = impl_.of_trait.clean(cx);
let items =
- impl_.items.iter().map(|ii| cx.tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
- let def_id = cx.tcx.hir().local_def_id(hir_id);
+ impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
+ let def_id = tcx.hir().local_def_id(hir_id);
// If this impl block is an implementation of the Deref trait, then we
// need to try inlining the target's inherent impl blocks as well.
- if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
+ if trait_.def_id() == tcx.lang_items().deref_trait() {
build_deref_target_impls(cx, &items, &mut ret);
}
let provided: FxHashSet<Symbol> = trait_
.def_id()
- .map(|did| cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
+ .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
.unwrap_or_default();
let for_ = impl_.self_ty.clean(cx);
- let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) {
- DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)),
+ let type_alias = for_.def_id().and_then(|did| match tcx.def_kind(did) {
+ DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)),
_ => None,
});
- let make_item = |trait_: Option<Type>, for_: Type, items: Vec<Item>| {
+ let mut make_item = |trait_: Option<Type>, for_: Type, items: Vec<Item>| {
let kind = ImplItem(Impl {
unsafety: impl_.unsafety,
generics: impl_.generics.clean(cx),
trait_,
for_,
items,
- negative_polarity: cx.tcx.impl_polarity(def_id).clean(cx),
+ negative_polarity: tcx.impl_polarity(def_id).clean(cx),
synthetic: false,
blanket_impl: None,
});
krate: &hir::Item<'_>,
name: Symbol,
orig_name: Option<Symbol>,
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
) -> Vec<Item> {
// this is the ID of the `extern crate` statement
let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id).unwrap_or(LOCAL_CRATE);
name: Symbol,
path: &hir::Path<'_>,
kind: hir::UseKind,
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
) -> Vec<Item> {
// We need this comparison because some imports (for std types for example)
// are "inserted" as well but directly by the compiler and they should not be
}
impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let (item, renamed) = self;
- cx.with_param_env(item.def_id.to_def_id(), || {
+ cx.with_param_env(item.def_id.to_def_id(), |cx| {
let kind = match item.kind {
hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
- let (generics, decl) = enter_impl_trait(cx, || {
+ let (generics, decl) = enter_impl_trait(cx, |cx| {
(generics.clean(cx), (&**decl, &names[..]).clean(cx))
});
ForeignFunctionItem(Function {
}
impl Clean<Item> for (&hir::MacroDef<'_>, Option<Symbol>) {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
+ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let (item, renamed) = self;
let name = renamed.unwrap_or(item.ident.name);
let tts = item.ast.body.inner_tokens().trees().collect::<Vec<_>>();
}
impl Clean<TypeBinding> for hir::TypeBinding<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> TypeBinding {
+ fn clean(&self, cx: &mut DocContext<'_>) -> TypeBinding {
TypeBinding { name: self.ident.name, kind: self.kind.clean(cx) }
}
}
impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> TypeBindingKind {
+ fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind {
match *self {
hir::TypeBindingKind::Equality { ref ty } => {
TypeBindingKind::Equality { ty: ty.clean(cx) }
hir_id: hir::HirId,
name: Option<Symbol>,
kind: ItemKind,
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
) -> Item {
Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx)
}
def_id: DefId,
name: Option<Symbol>,
kind: ItemKind,
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
) -> Item {
debug!("name={:?}, def_id={:?}", name, def_id);
}
impl GenericBound {
- crate fn maybe_sized(cx: &DocContext<'_>) -> GenericBound {
+ crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
let did = cx.tcx.require_lang_item(LangItem::Sized, None);
let empty = cx.tcx.intern_substs(&[]);
let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty);
}
fn external_generic_args(
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
trait_did: Option<DefId>,
has_self: bool,
bindings: Vec<TypeBinding>,
// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
// from Fn<(A, B,), C> to Fn(A, B) -> C
pub(super) fn external_path(
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
name: Symbol,
trait_did: Option<DefId>,
has_self: bool,
s
}
-crate fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut Vec<Item>) {
+crate fn build_deref_target_impls(cx: &mut DocContext<'_>, items: &[Item], ret: &mut Vec<Item>) {
let tcx = cx.tcx;
for item in items {
impl ToSource for rustc_span::Span {
fn to_src(&self, cx: &DocContext<'_>) -> String {
- debug!("converting span {:?} to snippet", self.clean(cx));
+ debug!("converting span {:?} to snippet", self);
let sn = match cx.sess().source_map().span_to_snippet(*self) {
Ok(x) => x,
Err(_) => String::new(),
}
/// Given a type Path, resolve it to a Type using the TyCtxt
-crate fn resolve_type(cx: &DocContext<'_>, path: Path, id: hir::HirId) -> Type {
+crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Type {
debug!("resolve_type({:?},{:?})", path, id);
let is_generic = match path.res {
Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true,
_ => false,
};
- let did = register_res(&*cx, path.res);
+ let did = register_res(cx, path.res);
ResolvedPath { path, param_names: None, did, is_generic }
}
crate fn get_auto_trait_and_blanket_impls(
- cx: &DocContext<'tcx>,
+ cx: &mut DocContext<'tcx>,
ty: Ty<'tcx>,
param_env_def_id: DefId,
) -> impl Iterator<Item = Item> {
.sess()
.prof
.generic_activity("get_blanket_impls")
- .run(|| BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id));
+ .run(|| BlanketImplFinder { cx }.get_blanket_impls(ty, param_env_def_id));
auto_impls.into_iter().chain(blanket_impls)
}
-crate fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
+crate fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
debug!("register_res({:?})", res);
let (did, kind) = match res {
did
}
-crate fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource {
+crate fn resolve_use_source(cx: &mut DocContext<'_>, path: Path) -> ImportSource {
ImportSource {
did: if path.res.opt_def_id().is_none() { None } else { Some(register_res(cx, path.res)) },
path,
}
}
-crate fn enter_impl_trait<F, R>(cx: &DocContext<'_>, f: F) -> R
+crate fn enter_impl_trait<F, R>(cx: &mut DocContext<'_>, f: F) -> R
where
- F: FnOnce() -> R,
+ F: FnOnce(&mut DocContext<'_>) -> R,
{
- let old_bounds = mem::take(&mut *cx.impl_trait_bounds.borrow_mut());
- let r = f();
+ let old_bounds = mem::take(&mut *cx.impl_trait_bounds.get_mut());
+ let r = f(cx);
assert!(cx.impl_trait_bounds.borrow().is_empty());
- *cx.impl_trait_bounds.borrow_mut() = old_bounds;
+ *cx.impl_trait_bounds.get_mut() = old_bounds;
r
}
};
use crate::clean;
+use crate::clean::inline::build_external_trait;
use crate::clean::{AttributesExt, MAX_DEF_IDX};
use crate::config::{Options as RustdocOptions, RenderOptions};
use crate::config::{OutputFormat, RenderInfo};
}
impl<'tcx> DocContext<'tcx> {
- crate fn sess(&self) -> &Session {
+ crate fn sess(&self) -> &'tcx Session {
&self.tcx.sess
}
- crate fn with_param_env<T, F: FnOnce() -> T>(&self, def_id: DefId, f: F) -> T {
+ crate fn with_param_env<T, F: FnOnce(&mut Self) -> T>(&mut self, def_id: DefId, f: F) -> T {
let old_param_env = self.param_env.replace(self.tcx.param_env(def_id));
- let ret = f();
+ let ret = f(self);
self.param_env.set(old_param_env);
ret
}
/// Call the closure with the given parameters set as
/// the substitutions for a type alias' RHS.
crate fn enter_alias<F, R>(
- &self,
+ &mut self,
ty_substs: FxHashMap<DefId, clean::Type>,
lt_substs: FxHashMap<DefId, clean::Lifetime>,
ct_substs: FxHashMap<DefId, clean::Constant>,
f: F,
) -> R
where
- F: FnOnce() -> R,
+ F: FnOnce(&mut Self) -> R,
{
let (old_tys, old_lts, old_cts) = (
- mem::replace(&mut *self.ty_substs.borrow_mut(), ty_substs),
- mem::replace(&mut *self.lt_substs.borrow_mut(), lt_substs),
- mem::replace(&mut *self.ct_substs.borrow_mut(), ct_substs),
+ mem::replace(&mut *self.ty_substs.get_mut(), ty_substs),
+ mem::replace(&mut *self.lt_substs.get_mut(), lt_substs),
+ mem::replace(&mut *self.ct_substs.get_mut(), ct_substs),
);
- let r = f();
- *self.ty_substs.borrow_mut() = old_tys;
- *self.lt_substs.borrow_mut() = old_lts;
- *self.ct_substs.borrow_mut() = old_cts;
+ let r = f(self);
+ *self.ty_substs.get_mut() = old_tys;
+ *self.lt_substs.get_mut() = old_lts;
+ *self.ct_substs.get_mut() = old_cts;
r
}
}
Entry::Occupied(e) => e.into_mut(),
};
- *def_index = DefIndex::from(*def_index + 1);
+ *def_index = *def_index + 1;
DefId { krate: crate_num, index: *def_index }
}
module_trait_cache: RefCell::new(FxHashMap::default()),
cache: Cache::default(),
};
+
+ // Small hack to force the Sized trait to be present.
+ //
+ // Note that in case of `#![no_core]`, the trait is not available.
+ if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
+ let mut sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
+ sized_trait.is_auto = true;
+ ctxt.external_traits.borrow_mut().insert(sized_trait_did, sized_trait);
+ }
+
debug!("crate: {:?}", tcx.hir().krate());
let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
};
if run {
debug!("running pass {}", p.pass.name);
- krate = ctxt.tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &ctxt));
+ krate = ctxt.tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &mut ctxt));
}
}
self.shared.tcx
}
- fn sess(&self) -> &Session {
+ fn sess(&self) -> &'tcx Session {
&self.shared.tcx.sess
}
}
}
}
-impl SourceCollector<'_, '_> {
- fn sess(&self) -> &Session {
+impl SourceCollector<'_, 'tcx> {
+ fn sess(&self) -> &'tcx Session {
&self.scx.tcx.sess
}
bounds: g.into_iter().map(Into::into).collect(),
default: t.map(Into::into),
},
- StrippedItem(inner) => from_clean_item_kind(*inner, tcx).into(),
+ StrippedItem(inner) => from_clean_item_kind(*inner, tcx),
PrimitiveItem(_) | KeywordItem(_) => {
panic!("{:?} is not supported for JSON output", item)
}
cache: Rc<Cache>,
}
-impl JsonRenderer<'_> {
- fn sess(&self) -> &Session {
+impl JsonRenderer<'tcx> {
+ fn sess(&self) -> &'tcx Session {
self.tcx.sess
}
(option.apply)(&mut options);
}
println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
+ println!(" @path Read newline separated options from `path`\n");
println!("More information available at https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html")
}
/// A result type used by several functions under `main()`.
type MainResult = Result<(), ErrorReported>;
-fn main_args(args: &[String]) -> MainResult {
+fn main_args(at_args: &[String]) -> MainResult {
+ let args = rustc_driver::args::arg_expand_all(at_args);
+
let mut options = getopts::Options::new();
for option in opts() {
(option.apply)(&mut options);
description: "counts the number of items with and without documentation",
};
-fn calculate_doc_coverage(krate: clean::Crate, ctx: &DocContext<'_>) -> clean::Crate {
- let mut calc = CoverageCalculator::new(ctx);
+fn calculate_doc_coverage(krate: clean::Crate, ctx: &mut DocContext<'_>) -> clean::Crate {
+ let mut calc = CoverageCalculator { items: Default::default(), ctx };
let krate = calc.fold_crate(krate);
calc.print_results();
struct CoverageCalculator<'a, 'b> {
items: BTreeMap<FileName, ItemCount>,
- ctx: &'a DocContext<'b>,
+ ctx: &'a mut DocContext<'b>,
}
fn limit_filename_len(filename: String) -> String {
}
impl<'a, 'b> CoverageCalculator<'a, 'b> {
- fn new(ctx: &'a DocContext<'b>) -> CoverageCalculator<'a, 'b> {
- CoverageCalculator { items: Default::default(), ctx }
- }
-
fn to_json(&self) -> String {
serde_json::to_string(
&self
description: "validates syntax inside Rust code blocks",
};
-crate fn check_code_block_syntax(krate: clean::Crate, cx: &DocContext<'_>) -> clean::Crate {
+crate fn check_code_block_syntax(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
SyntaxChecker { cx }.fold_crate(krate)
}
description: "resolves intra-doc links",
};
-crate fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
- LinkCollector::new(cx).fold_crate(krate)
+crate fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+ LinkCollector {
+ cx,
+ mod_ids: Vec::new(),
+ kind_side_channel: Cell::new(None),
+ visited_links: FxHashMap::default(),
+ }
+ .fold_crate(krate)
}
/// Top-level errors emitted by this pass.
}
struct LinkCollector<'a, 'tcx> {
- cx: &'a DocContext<'tcx>,
+ cx: &'a mut DocContext<'tcx>,
/// A stack of modules used to decide what scope to resolve in.
///
/// The last module will be used if the parent scope of the current item is
}
impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
- fn new(cx: &'a DocContext<'tcx>) -> Self {
- LinkCollector {
- cx,
- mod_ids: Vec::new(),
- kind_side_channel: Cell::new(None),
- visited_links: FxHashMap::default(),
- }
- }
-
/// Given a full link, parse it as an [enum struct variant].
///
/// In particular, this will return an error whenever there aren't three
path_str: &'path str,
module_id: DefId,
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
- let cx = self.cx;
+ let tcx = self.cx.tcx;
let no_res = || ResolutionFailure::NotResolved {
module_id,
partial_res: None,
// If there's no third component, we saw `[a::b]` before and it failed to resolve.
// So there's no partial res.
.ok_or_else(no_res)?;
- let ty_res = cx
+ let ty_res = self
+ .cx
.enter_resolver(|resolver| {
resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
})
match ty_res {
Res::Def(DefKind::Enum, did) => {
- if cx
- .tcx
+ if tcx
.inherent_impls(did)
.iter()
- .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order())
+ .flat_map(|imp| tcx.associated_items(*imp).in_definition_order())
.any(|item| item.ident.name == variant_name)
{
// This is just to let `fold_item` know that this shouldn't be considered;
// it's a bug for the error to make it to the user
return Err(ResolutionFailure::Dummy.into());
}
- match cx.tcx.type_of(did).kind() {
+ match tcx.type_of(did).kind() {
ty::Adt(def, _) if def.is_enum() => {
if def.all_fields().any(|item| item.ident.name == variant_field_name) {
Ok((
item_name: Symbol,
item_str: &'path str,
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
- let cx = self.cx;
+ let tcx = self.cx.tcx;
prim_ty
- .impls(cx.tcx)
+ .impls(tcx)
.into_iter()
.find_map(|&impl_| {
- cx.tcx
- .associated_items(impl_)
- .find_by_name_and_namespace(
- cx.tcx,
- Ident::with_dummy_span(item_name),
- ns,
- impl_,
- )
+ tcx.associated_items(impl_)
+ .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
.map(|item| {
let kind = item.kind;
self.kind_side_channel.set(Some((kind.as_def_kind(), item.def_id)));
path_str: &'a str,
module_id: DefId,
) -> Result<Res, ResolutionFailure<'a>> {
- let cx = self.cx;
let path = ast::Path::from_ident(Ident::from_str(path_str));
- cx.enter_resolver(|resolver| {
+ self.cx.enter_resolver(|resolver| {
// FIXME(jynelson): does this really need 3 separate lookups?
if let Ok((Some(ext), res)) = resolver.resolve_macro_path(
&path,
module_id: DefId,
extra_fragment: &Option<String>,
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
- let cx = self.cx;
+ let cx = &self.cx;
if let Some(res) = self.resolve_path(path_str, ns, module_id) {
match res {
return None;
}
- let cx = self.cx;
let link = ori_link.link.replace("`", "");
let parts = link.split('#').collect::<Vec<_>>();
let (link, extra_fragment) = if parts.len() > 2 {
// A valid link can't have multiple #'s
- anchor_failure(cx, &item, &link, dox, ori_link.range, AnchorFailure::MultipleAnchors);
+ anchor_failure(
+ self.cx,
+ &item,
+ &link,
+ dox,
+ ori_link.range,
+ AnchorFailure::MultipleAnchors,
+ );
return None;
} else if parts.len() == 2 {
if parts[0].trim().is_empty() {
if matches!(disambiguator, Some(Disambiguator::Primitive)) {
if fragment.is_some() {
anchor_failure(
- cx,
+ self.cx,
&item,
path_str,
dox,
} else {
// `[char]` when a `char` module is in scope
let candidates = vec![res, prim];
- ambiguity_error(cx, &item, path_str, dox, ori_link.range, candidates);
+ ambiguity_error(self.cx, &item, path_str, dox, ori_link.range, candidates);
return None;
}
}
suggest_disambiguator(resolved, diag, path_str, dox, sp, &ori_link.range);
};
report_diagnostic(
- cx,
+ self.cx,
BROKEN_INTRA_DOC_LINKS,
&msg,
&item,
if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src)
&& !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst)
{
- privacy_error(cx, &item, &path_str, dox, &ori_link);
+ privacy_error(self.cx, &item, &path_str, dox, &ori_link);
}
}
&& !self.cx.tcx.features().intra_doc_pointers
{
let span = super::source_span_for_markdown_range(
- cx,
+ self.cx,
dox,
&ori_link.range,
&item.attrs,
}
Res::Def(kind, id) => {
verify(kind, id)?;
- let id = clean::register_res(cx, rustc_hir::def::Res::Def(kind, id));
+ let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
Some(ItemLink { link: ori_link.link, link_text, did: Some(id), fragment })
}
}
description: "retrieves trait impls for items in the crate",
};
-crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
- let mut synth = SyntheticImplCollector::new(cx);
- let mut krate = cx.sess().time("collect_synthetic_impls", || synth.fold_crate(krate));
+crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+ let (mut krate, synth_impls) = cx.sess().time("collect_synthetic_impls", || {
+ let mut synth = SyntheticImplCollector { cx, impls: Vec::new() };
+ (synth.fold_crate(krate), synth.impls)
+ });
let prims: FxHashSet<PrimitiveType> = krate.primitives.iter().map(|p| p.1).collect();
panic!("collect-trait-impls can't run");
};
- items.extend(synth.impls);
+ items.extend(synth_impls);
for it in new_items.drain(..) {
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
if !(cleaner.keep_impl(for_)
}
struct SyntheticImplCollector<'a, 'tcx> {
- cx: &'a DocContext<'tcx>,
+ cx: &'a mut DocContext<'tcx>,
impls: Vec<Item>,
}
-impl<'a, 'tcx> SyntheticImplCollector<'a, 'tcx> {
- fn new(cx: &'a DocContext<'tcx>) -> Self {
- SyntheticImplCollector { cx, impls: Vec::new() }
- }
-}
-
impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
if i.is_struct() || i.is_enum() || i.is_union() {
};
struct PrivateItemDocTestLinter<'a, 'tcx> {
- cx: &'a DocContext<'tcx>,
+ cx: &'a mut DocContext<'tcx>,
}
-impl<'a, 'tcx> PrivateItemDocTestLinter<'a, 'tcx> {
- fn new(cx: &'a DocContext<'tcx>) -> Self {
- PrivateItemDocTestLinter { cx }
- }
-}
-
-crate fn check_private_items_doc_tests(krate: Crate, cx: &DocContext<'_>) -> Crate {
- let mut coll = PrivateItemDocTestLinter::new(cx);
+crate fn check_private_items_doc_tests(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+ let mut coll = PrivateItemDocTestLinter { cx };
coll.fold_crate(krate)
}
impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> {
fn fold_item(&mut self, item: Item) -> Option<Item> {
- let cx = self.cx;
let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
- look_for_tests(&cx, &dox, &item);
+ look_for_tests(self.cx, &dox, &item);
Some(self.fold_item_recur(item))
}
};
struct InvalidHtmlTagsLinter<'a, 'tcx> {
- cx: &'a DocContext<'tcx>,
+ cx: &'a mut DocContext<'tcx>,
}
-impl<'a, 'tcx> InvalidHtmlTagsLinter<'a, 'tcx> {
- fn new(cx: &'a DocContext<'tcx>) -> Self {
- InvalidHtmlTagsLinter { cx }
- }
-}
-
-crate fn check_invalid_html_tags(krate: Crate, cx: &DocContext<'_>) -> Crate {
+crate fn check_invalid_html_tags(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
if !cx.tcx.sess.is_nightly_build() {
krate
} else {
- let mut coll = InvalidHtmlTagsLinter::new(cx);
+ let mut coll = InvalidHtmlTagsLinter { cx };
coll.fold_crate(krate)
}
#[derive(Copy, Clone)]
crate struct Pass {
crate name: &'static str,
- crate run: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
+ crate run: fn(clean::Crate, &mut DocContext<'_>) -> clean::Crate,
crate description: &'static str,
}
);
struct NonAutolinksLinter<'a, 'tcx> {
- cx: &'a DocContext<'tcx>,
+ cx: &'a mut DocContext<'tcx>,
regex: Regex,
}
impl<'a, 'tcx> NonAutolinksLinter<'a, 'tcx> {
- fn new(cx: &'a DocContext<'tcx>) -> Self {
- Self { cx, regex: Regex::new(URL_REGEX).expect("failed to build regex") }
- }
-
fn find_raw_urls(
&self,
text: &str,
}
}
-crate fn check_non_autolinks(krate: Crate, cx: &DocContext<'_>) -> Crate {
+crate fn check_non_autolinks(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
if !cx.tcx.sess.is_nightly_build() {
krate
} else {
- let mut coll = NonAutolinksLinter::new(cx);
+ let mut coll =
+ NonAutolinksLinter { cx, regex: Regex::new(URL_REGEX).expect("failed to build regex") };
coll.fold_crate(krate)
}
description: "propagates `#[doc(cfg(...))]` to child items",
};
-crate fn propagate_doc_cfg(cr: Crate, _: &DocContext<'_>) -> Crate {
+crate fn propagate_doc_cfg(cr: Crate, _: &mut DocContext<'_>) -> Crate {
CfgPropagator { parent_cfg: None }.fold_crate(cr)
}
};
/// Strip items marked `#[doc(hidden)]`
-crate fn strip_hidden(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
+crate fn strip_hidden(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
let mut retained = DefIdSet::default();
// strip all #[doc(hidden)] items
description: "strips all private import statements (`use`, `extern crate`) from a crate",
};
-crate fn strip_priv_imports(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
+crate fn strip_priv_imports(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
ImportStripper.fold_crate(krate)
}
/// Strip private items from the point of view of a crate or externally from a
/// crate, specified by the `xcrate` flag.
-crate fn strip_private(mut krate: clean::Crate, cx: &DocContext<'_>) -> clean::Crate {
+crate fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
// This stripper collects all *retained* nodes.
let mut retained = DefIdSet::default();
let access_levels = cx.renderinfo.borrow().access_levels.clone();
description: "removes excess indentation on comments in order for markdown to like it",
};
-crate fn unindent_comments(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
+crate fn unindent_comments(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
CommentCleaner.fold_crate(krate)
}
type Y<T> where Self: Sized = u32;
}
+fn f<T: X<Y<()> = i32>>() {}
+
fn main() { }
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+# only-linux
+
+all:
+ $(RUSTC) test.rs --test --target $(TARGET)
+ $(shell ulimit -p 0 && $(call RUN,test))
--- /dev/null
+#![feature(once_cell)]
+
+use std::{io::ErrorKind, lazy::SyncOnceCell, thread::{self, Builder, ThreadId}};
+
+static THREAD_ID: SyncOnceCell<ThreadId> = SyncOnceCell::new();
+
+#[test]
+fn spawn_thread_would_block() {
+ assert_eq!(Builder::new().spawn(|| unreachable!()).unwrap_err().kind(), ErrorKind::WouldBlock);
+ THREAD_ID.set(thread::current().id()).unwrap();
+}
+
+#[test]
+fn run_in_same_thread() {
+ assert_eq!(*THREAD_ID.get().unwrap(), thread::current().id());
+}
--- /dev/null
+--cfg
+unbroken\80
\ No newline at end of file
--- /dev/null
+// Check to see if we can get parameters from an @argsfile file
+//
+// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args
+
+#[cfg(not(cmdline_set))]
+compile_error!("cmdline_set not set");
+
+#[cfg(not(unbroken))]
+compile_error!("unbroken not set");
+
+fn main() {
+}
--- /dev/null
+error: Failed to load argument file: Utf8 error in $DIR/commandline-argfile-badutf8.args
+
--- /dev/null
+// Check to see if we can get parameters from an @argsfile file
+//
+// ignore-tidy-linelength
+// normalize-stderr-test: "os error \d+" -> "os error $$ERR"
+// normalize-stderr-test: "commandline-argfile-missing.args:[^(]*" -> "commandline-argfile-missing.args: $$FILE_MISSING "
+// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-missing.args
+
+#[cfg(not(cmdline_set))]
+compile_error!("cmdline_set not set");
+
+#[cfg(not(unbroken))]
+compile_error!("unbroken not set");
+
+fn main() {
+}
--- /dev/null
+error: Failed to load argument file: IO Error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR)
+
--- /dev/null
+--cfg
+unbroken
\ No newline at end of file
--- /dev/null
+// Check to see if we can get parameters from an @argsfile file
+//
+// check-pass
+// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile.args
+
+#[cfg(not(cmdline_set))]
+compile_error!("cmdline_set not set");
+
+#[cfg(not(unbroken))]
+compile_error!("unbroken not set");
+
+fn main() {
+}
#![deny(broken_intra_doc_links)]
+#![feature(intra_doc_pointers)]
pub use std::*;
--- /dev/null
+#![crate_name = "foo"]
+
+// @has foo/struct.Bar.html
+// @!has - '//h3[@id="impl-Sized"]'
+pub struct Bar {
+ a: u16,
+}
+
+// @has foo/struct.Foo.html
+// @!has - '//h3[@id="impl-Sized"]'
+pub struct Foo<T: ?Sized>(T);
+
+// @has foo/struct.Unsized.html
+// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
+pub struct Unsized {
+ data: [u8],
+}
error: implementation of `TheTrait` is not general enough
--> $DIR/associated-types-eq-hr.rs:96:5
|
-LL | / pub trait TheTrait<T> {
-LL | | type A;
-LL | |
-LL | | fn get(&self, t: T) -> Self::A;
-LL | | }
- | |_- trait `TheTrait` defined here
-...
-LL | tuple_one::<Tuple>();
- | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+LL | tuple_one::<Tuple>();
+ | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
- = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+ = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: implementation of `TheTrait` is not general enough
--> $DIR/associated-types-eq-hr.rs:96:5
|
-LL | / pub trait TheTrait<T> {
-LL | | type A;
-LL | |
-LL | | fn get(&self, t: T) -> Self::A;
-LL | | }
- | |_- trait `TheTrait` defined here
-...
-LL | tuple_one::<Tuple>();
- | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+LL | tuple_one::<Tuple>();
+ | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
- = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+ = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: implementation of `TheTrait` is not general enough
--> $DIR/associated-types-eq-hr.rs:102:5
|
-LL | / pub trait TheTrait<T> {
-LL | | type A;
-LL | |
-LL | | fn get(&self, t: T) -> Self::A;
-LL | | }
- | |_- trait `TheTrait` defined here
-...
-LL | tuple_two::<Tuple>();
- | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+LL | tuple_two::<Tuple>();
+ | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
- = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+ = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: implementation of `TheTrait` is not general enough
--> $DIR/associated-types-eq-hr.rs:102:5
|
-LL | / pub trait TheTrait<T> {
-LL | | type A;
-LL | |
-LL | | fn get(&self, t: T) -> Self::A;
-LL | | }
- | |_- trait `TheTrait` defined here
-...
-LL | tuple_two::<Tuple>();
- | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+LL | tuple_two::<Tuple>();
+ | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
- = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+ = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: implementation of `TheTrait` is not general enough
--> $DIR/associated-types-eq-hr.rs:112:5
|
-LL | / pub trait TheTrait<T> {
-LL | | type A;
-LL | |
-LL | | fn get(&self, t: T) -> Self::A;
-LL | | }
- | |_- trait `TheTrait` defined here
-...
-LL | tuple_four::<Tuple>();
- | ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+LL | tuple_four::<Tuple>();
+ | ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
- = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+ = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: aborting due to 7 previous errors
--- /dev/null
+// check-pass
+#![allow(dead_code)]
+// Regression test for #21726: an issue arose around the rules for
+// subtyping of projection types that resulted in an unconstrained
+// region, yielding region inference failures.
+
+// pretty-expanded FIXME #23616
+
+fn main() { }
+
+fn foo<'a>(s: &'a str) {
+ let b: B<()> = B::new(s, ());
+ b.get_short();
+}
+
+trait IntoRef<'a> {
+ type T: Clone;
+ fn into_ref(self, _: &'a str) -> Self::T;
+}
+
+impl<'a> IntoRef<'a> for () {
+ type T = &'a str;
+ fn into_ref(self, s: &'a str) -> &'a str {
+ s
+ }
+}
+
+struct B<'a, P: IntoRef<'a>>(P::T);
+
+impl<'a, P: IntoRef<'a>> B<'a, P> {
+ fn new(s: &'a str, i: P) -> B<'a, P> {
+ B(i.into_ref(s))
+ }
+
+ fn get_short(&self) -> P::T {
+ self.0.clone()
+ }
+}
--- /dev/null
+trait Add<Rhs=Self> {
+ type Output;
+}
+
+trait Sub<Rhs=Self> {
+ type Output;
+}
+
+type Test = dyn Add + Sub;
+//~^ ERROR E0393
+//~| ERROR E0191
+//~| ERROR E0393
+//~| ERROR E0225
+
+fn main() { }
--- /dev/null
+error[E0393]: the type parameter `Rhs` must be explicitly specified
+ --> $DIR/issue-22560.rs:9:23
+ |
+LL | / trait Sub<Rhs=Self> {
+LL | | type Output;
+LL | | }
+ | |_- type parameter `Rhs` must be specified for this
+LL |
+LL | type Test = dyn Add + Sub;
+ | ^^^ help: set the type parameter to the desired type: `Sub<Rhs>`
+ |
+ = note: because of the default `Self` reference, type parameters must be specified on object types
+
+error[E0393]: the type parameter `Rhs` must be explicitly specified
+ --> $DIR/issue-22560.rs:9:17
+ |
+LL | / trait Add<Rhs=Self> {
+LL | | type Output;
+LL | | }
+ | |_- type parameter `Rhs` must be specified for this
+...
+LL | type Test = dyn Add + Sub;
+ | ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
+ |
+ = note: because of the default `Self` reference, type parameters must be specified on object types
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+ --> $DIR/issue-22560.rs:9:23
+ |
+LL | type Test = dyn Add + Sub;
+ | --- ^^^ additional non-auto trait
+ | |
+ | first non-auto trait
+ |
+ = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}`
+ = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+
+error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified
+ --> $DIR/issue-22560.rs:9:17
+ |
+LL | type Output;
+ | ------------ `Output` defined here
+...
+LL | type Output;
+ | ------------ `Output` defined here
+...
+LL | type Test = dyn Add + Sub;
+ | ^^^ ^^^ associated type `Output` must be specified
+ | |
+ | associated type `Output` must be specified
+ |
+help: specify the associated types
+ |
+LL | type Test = dyn Add<Output = Type> + Sub<Output = Type>;
+ | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0191, E0225, E0393.
+For more information about an error, try `rustc --explain E0191`.
--- /dev/null
+#![feature(associated_type_defaults)]
+
+pub struct C<AType: A> {a:AType}
+
+pub trait A {
+ type B = C<Self::anything_here_kills_it>;
+ //~^ ERROR: associated type `anything_here_kills_it` not found for `Self`
+}
+
+fn main() {}
--- /dev/null
+error[E0220]: associated type `anything_here_kills_it` not found for `Self`
+ --> $DIR/issue-23595-2.rs:6:22
+ |
+LL | type B = C<Self::anything_here_kills_it>;
+ | ^^^^^^^^^^^^^^^^^^^^^^ associated type `anything_here_kills_it` not found
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0220`.
--- /dev/null
+// check-pass
+
+#![allow(dead_code)]
+
+trait MultiDispatch<T> {
+ type O;
+}
+
+trait Trait: Sized {
+ type A: MultiDispatch<Self::B, O = Self>;
+ type B;
+
+ fn new<U>(u: U) -> <Self::A as MultiDispatch<U>>::O
+ where
+ Self::A: MultiDispatch<U>;
+}
+
+fn test<T: Trait<B = i32>>(b: i32) -> T
+where
+ T::A: MultiDispatch<i32>,
+{
+ T::new(b)
+}
+
+fn main() {}
--- /dev/null
+pub trait Partial<X: ?Sized>: Copy {
+}
+
+pub trait Complete {
+ type Assoc: Partial<Self>;
+}
+
+impl<T> Partial<T> for T::Assoc where
+ T: Complete
+{
+}
+
+impl<T> Complete for T {
+ type Assoc = T; //~ ERROR the trait bound `T: Copy` is not satisfied
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `T: Copy` is not satisfied
+ --> $DIR/issue-43784-associated-type.rs:14:5
+ |
+LL | type Assoc: Partial<Self>;
+ | ------------- required by this bound in `Complete::Assoc`
+...
+LL | type Assoc = T;
+ | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+ |
+help: consider restricting type parameter `T`
+ |
+LL | impl<T: Copy> Complete for T {
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// run-pass
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unreachable_code)]
+// A regression test extracted from image-0.3.11. The point of
+// failure was in `index_colors` below.
+
+use std::ops::{Deref, DerefMut};
+
+#[derive(Copy, Clone)]
+pub struct Luma<T: Primitive> { pub data: [T; 1] }
+
+impl<T: Primitive + 'static> Pixel for Luma<T> {
+ type Subpixel = T;
+}
+
+pub struct ImageBuffer<P: Pixel, Container> {
+ pixels: P,
+ c: Container,
+}
+
+pub trait GenericImage: Sized {
+ type Pixel: Pixel;
+}
+
+pub trait Pixel: Copy + Clone {
+ type Subpixel: Primitive;
+}
+
+pub trait Primitive: Copy + PartialOrd<Self> + Clone {
+}
+
+impl<P, Container> GenericImage for ImageBuffer<P, Container>
+where P: Pixel + 'static,
+ Container: Deref<Target=[P::Subpixel]> + DerefMut,
+ P::Subpixel: 'static {
+
+ type Pixel = P;
+}
+
+impl Primitive for u8 { }
+
+impl<P, Container> ImageBuffer<P, Container>
+where P: Pixel + 'static,
+ P::Subpixel: 'static,
+ Container: Deref<Target=[P::Subpixel]>
+{
+ pub fn pixels<'a>(&'a self) -> Pixels<'a, Self> {
+ loop { }
+ }
+
+ pub fn pixels_mut(&mut self) -> PixelsMut<P> {
+ loop { }
+ }
+}
+
+pub struct Pixels<'a, I: 'a> {
+ image: &'a I,
+ x: u32,
+ y: u32,
+ width: u32,
+ height: u32
+}
+
+impl<'a, I: GenericImage> Iterator for Pixels<'a, I> {
+ type Item = (u32, u32, I::Pixel);
+
+ fn next(&mut self) -> Option<(u32, u32, I::Pixel)> {
+ loop { }
+ }
+}
+
+pub struct PixelsMut<'a, P: Pixel + 'a> where P::Subpixel: 'a {
+ chunks: &'a mut P::Subpixel
+}
+
+impl<'a, P: Pixel + 'a> Iterator for PixelsMut<'a, P> where P::Subpixel: 'a {
+ type Item = &'a mut P;
+
+ fn next(&mut self) -> Option<&'a mut P> {
+ loop { }
+ }
+}
+
+pub fn index_colors<Pix>(image: &ImageBuffer<Pix, Vec<u8>>)
+ -> ImageBuffer<Luma<u8>, Vec<u8>>
+where Pix: Pixel<Subpixel=u8> + 'static,
+{
+ // When NLL-enabled, `let mut` below is deemed unnecessary (due to
+ // the remaining code being unreachable); so ignore that lint.
+ #![allow(unused_mut)]
+
+ let mut indices: ImageBuffer<_,Vec<_>> = loop { };
+ for (pixel, idx) in image.pixels().zip(indices.pixels_mut()) {
+ // failured occurred here ^^ because we were requiring that we
+ // could project Pixel or Subpixel from `T_indices` (type of
+ // `indices`), but the type is insufficiently constrained
+ // until we reach the return below.
+ }
+ indices
+}
+
+fn main() { }
-{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"proc_macros":[]}
-{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"proc_macros":[]}
--- /dev/null
+// edition:2018
+#![feature(async_closure)]
+use std::future::Future;
+
+async fn one() {}
+async fn two() {}
+
+fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
+fn main() {
+ fun(async {}, async {});
+ //~^ ERROR mismatched types
+ fun(one(), two());
+ //~^ ERROR mismatched types
+ fun((async || {})(), (async || {})());
+ //~^ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/generator-desc.rs:10:25
+ |
+LL | fun(async {}, async {});
+ | -- ^^ expected `async` block, found a different `async` block
+ | |
+ | the expected `async` block
+ |
+ = note: expected `async` block `[static generator@$DIR/generator-desc.rs:10:15: 10:17]`
+ found `async` block `[static generator@$DIR/generator-desc.rs:10:25: 10:27]`
+
+error[E0308]: mismatched types
+ --> $DIR/generator-desc.rs:12:16
+ |
+LL | async fn one() {}
+ | - the `Output` of this `async fn`'s expected opaque type
+LL | async fn two() {}
+ | - the `Output` of this `async fn`'s found opaque type
+...
+LL | fun(one(), two());
+ | ^^^^^ expected opaque type, found a different opaque type
+ |
+ = note: expected opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:5:16>)
+ found opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:6:16>)
+ = help: consider `await`ing on both `Future`s
+ = note: distinct uses of `impl Trait` result in different opaque types
+
+error[E0308]: mismatched types
+ --> $DIR/generator-desc.rs:14:26
+ |
+LL | fun((async || {})(), (async || {})());
+ | -- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
+ | |
+ | the expected `async` closure body
+ |
+ ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
+ |
+LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
+ | -------------------------------
+ | |
+ | the expected opaque type
+ | the found opaque type
+ |
+ = note: expected opaque type `impl Future` (`async` closure body)
+ found opaque type `impl Future` (`async` closure body)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// edition:2018
+
+async fn test() -> Result<(), Box<dyn std::error::Error>> {
+ macro!();
+ //~^ ERROR expected identifier, found `!`
+ Ok(())
+}
+
+fn main() {}
--- /dev/null
+error: expected identifier, found `!`
+ --> $DIR/issue-77993-2.rs:4:10
+ |
+LL | macro!();
+ | ^ expected identifier
+
+error: aborting due to previous error
+
--- /dev/null
+// edition:2018
+
+struct S<'a>(&'a i32);
+
+impl<'a> S<'a> {
+ async fn new(i: &'a i32) -> Result<Self, ()> {
+ //~^ ERROR: `async fn`
+ Ok(S(&22))
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+ --> $DIR/issue-78600.rs:6:33
+ |
+LL | async fn new(i: &'a i32) -> Result<Self, ()> {
+ | ^^^^^^^----^^^^^
+ | |
+ | help: consider spelling out the type instead: `S<'a>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0760`.
--- /dev/null
+// check-pass
+// edition:2018
+// compile-flags: --crate-type=lib
+
+pub async fn test() {
+ const C: usize = 4;
+ foo(&mut [0u8; C]).await;
+}
+
+async fn foo(_: &mut [u8]) {}
if let Some(y) = x {
assert_eq!(y, 3);
} else {
- panic!("if-let panicked");
+ panic!("`if let` panicked");
}
let mut worked = false;
if let Some(_) = x {
if let Foo::Two(b) = a {
assert_eq!(b, 42_usize);
} else {
- panic!("panic in nested if-let");
+ panic!("panic in nested `if let`");
}
}
}
+++ /dev/null
-// run-pass
-// This test verifies that temporaries created for `while`'s and `if`
-// conditions are dropped after the condition is evaluated.
-
-#![feature(box_syntax)]
-
-struct Temporary;
-
-static mut DROPPED: isize = 0;
-
-impl Drop for Temporary {
- fn drop(&mut self) {
- unsafe { DROPPED += 1; }
- }
-}
-
-impl Temporary {
- fn do_stuff(&self) -> bool {true}
-}
-
-fn borrow() -> Box<Temporary> { box Temporary }
-
-
-pub fn main() {
- let mut i = 0;
-
- // This loop's condition
- // should call `Temporary`'s
- // `drop` 6 times.
- while borrow().do_stuff() {
- i += 1;
- unsafe { assert_eq!(DROPPED, i) }
- if i > 5 {
- break;
- }
- }
-
- // This if condition should
- // call it 1 time
- if borrow().do_stuff() {
- unsafe { assert_eq!(DROPPED, i + 1) }
- }
-}
//~^ First Pass analysis includes:
//~| Min Capture analysis includes:
let p = t.0.0;
- //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
+ //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+ //~| NOTE: Capturing t[(0, 0)] -> ByValue
//~| NOTE: Min Capture t[(0, 0)] -> ByValue
println!("{} {:?}", t.1, p);
//~^ NOTE: Capturing t[(1, 0)] -> ImmBorrow
LL | | };
| |_____^
|
-note: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
+note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+ --> $DIR/by_value.rs:28:17
+ |
+LL | let p = t.0.0;
+ | ^^^^^
+note: Capturing t[(0, 0)] -> ByValue
--> $DIR/by_value.rs:28:17
|
LL | let p = t.0.0;
| ^^^^^
note: Capturing t[(1, 0)] -> ImmBorrow
- --> $DIR/by_value.rs:31:29
+ --> $DIR/by_value.rs:32:29
|
LL | println!("{} {:?}", t.1, p);
| ^^^
LL | let p = t.0.0;
| ^^^^^
note: Min Capture t[(1, 0)] -> ImmBorrow
- --> $DIR/by_value.rs:31:29
+ --> $DIR/by_value.rs:32:29
|
LL | println!("{} {:?}", t.1, p);
| ^^^
--- /dev/null
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| `#[warn(incomplete_features)]` on by default
+//~| see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+// Test that array access is not stored as part of closure kind origin
+
+fn expect_fn<F: Fn()>(_f: F) {}
+
+fn main() {
+ let s = [format!("s"), format!("s")];
+ let c = || { //~ ERROR expected a closure that implements the `Fn`
+ let [_, _s] = s;
+ };
+ expect_fn(c);
+}
--- /dev/null
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/closure-origin-array-diagnostics.rs:1:12
+ |
+LL | #![feature(capture_disjoint_fields)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+ --> $DIR/closure-origin-array-diagnostics.rs:12:13
+ |
+LL | let c = || {
+ | ^^ this closure implements `FnOnce`, not `Fn`
+LL | let [_, _s] = s;
+ | - closure is `FnOnce` because it moves the variable `s` out of its environment
+LL | };
+LL | expect_fn(c);
+ | --------- the requirement to implement `Fn` derives from here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0525`.
// FIXME(project-rfc-2229#24): Change this to be a destructure pattern
// once this is fixed, to remove the warning.
if let SingleVariant::Point(ref mut x, _) = point {
- //~^ WARNING: irrefutable if-let pattern
+ //~^ WARNING: irrefutable `if let` pattern
*x += 1;
}
};
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
--> $DIR/closure-origin-single-variant-diagnostics.rs:18:9
|
LL | / if let SingleVariant::Point(ref mut x, _) = point {
| |_________^
|
= note: `#[warn(irrefutable_let_patterns)]` on by default
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
error[E0382]: use of moved value: `c`
--> $DIR/closure-origin-single-variant-diagnostics.rs:25:13
//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
#![feature(rustc_attrs)]
-// Test we truncate derefs properly
+fn simple_move_closure() {
+ struct S(String);
+ struct T(S);
+
+ let t = T(S("s".into()));
+ let mut c = #[rustc_capture_analysis]
+ //~^ ERROR: attributes on expressions are experimental
+ //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+ move || {
+ //~^ ERROR: First Pass analysis includes:
+ //~| ERROR: Min Capture analysis includes:
+ t.0.0 = "new S".into();
+ //~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue
+ //~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue
+ };
+ c();
+}
+
+// Test move closure use reborrows when using references
fn simple_ref() {
let mut s = 10;
let ref_s = &mut s;
//~^ ERROR: First Pass analysis includes:
//~| ERROR: Min Capture analysis includes:
*ref_s += 10;
- //~^ NOTE: Capturing ref_s[Deref] -> ByValue
- //~| NOTE: Min Capture ref_s[] -> ByValue
+ //~^ NOTE: Capturing ref_s[Deref] -> UniqueImmBorrow
+ //~| NOTE: Min Capture ref_s[Deref] -> UniqueImmBorrow
};
c();
}
-// Test we truncate derefs properly
-fn struct_contains_ref_to_another_struct() {
+// Test move closure use reborrows when using references
+fn struct_contains_ref_to_another_struct_1() {
struct S(String);
struct T<'a>(&'a mut S);
//~^ ERROR: First Pass analysis includes:
//~| ERROR: Min Capture analysis includes:
t.0.0 = "new s".into();
- //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
- //~| NOTE: Min Capture t[(0, 0)] -> ByValue
+ //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow
+ //~| NOTE: Min Capture t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow
};
c();
}
-// Test that we don't reduce precision when there is nothing deref.
-fn no_ref() {
+// Test that we can use reborrows to read data of Copy types
+// i.e. without truncating derefs
+fn struct_contains_ref_to_another_struct_2() {
+ struct S(i32);
+ struct T<'a>(&'a S);
+
+ let s = S(0);
+ let t = T(&s);
+
+ let mut c = #[rustc_capture_analysis]
+ //~^ ERROR: attributes on expressions are experimental
+ //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+ move || {
+ //~^ ERROR: First Pass analysis includes:
+ //~| ERROR: Min Capture analysis includes:
+ let _t = t.0.0;
+ //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+ //~| NOTE: Min Capture t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+ };
+
+ c();
+}
+
+// Test that we can use truncate to move out of !Copy types
+fn struct_contains_ref_to_another_struct_3() {
struct S(String);
- struct T(S);
+ struct T<'a>(&'a S);
+
+ let s = S("s".into());
+ let t = T(&s);
- let t = T(S("s".into()));
let mut c = #[rustc_capture_analysis]
//~^ ERROR: attributes on expressions are experimental
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
move || {
//~^ ERROR: First Pass analysis includes:
//~| ERROR: Min Capture analysis includes:
- t.0.0 = "new S".into();
- //~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue
- //~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue
+ let _t = t.0.0;
+ //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+ //~| NOTE: Capturing t[(0, 0)] -> ByValue
+ //~| NOTE: Min Capture t[(0, 0)] -> ByValue
};
+
+ c();
+}
+
+// Test that derefs of box are truncated in move closures
+fn truncate_box_derefs() {
+ struct S(i32);
+
+ let b = Box::new(S(10));
+
+ let c = #[rustc_capture_analysis]
+ //~^ ERROR: attributes on expressions are experimental
+ //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+ move || {
+ //~^ ERROR: First Pass analysis includes:
+ //~| ERROR: Min Capture analysis includes:
+ let _t = b.0;
+ //~^ NOTE: Capturing b[Deref,(0, 0)] -> ByValue
+ //~| NOTE: Capturing b[] -> ByValue
+ //~| NOTE: Min Capture b[] -> ByValue
+ };
+
c();
}
fn main() {
+ simple_move_closure();
simple_ref();
- struct_contains_ref_to_another_struct();
- no_ref();
+ struct_contains_ref_to_another_struct_1();
+ struct_contains_ref_to_another_struct_2();
+ struct_contains_ref_to_another_struct_3();
+ truncate_box_derefs();
}
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
error[E0658]: attributes on expressions are experimental
- --> $DIR/move_closure.rs:35:17
+ --> $DIR/move_closure.rs:32:17
|
LL | let mut c = #[rustc_capture_analysis]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
error[E0658]: attributes on expressions are experimental
- --> $DIR/move_closure.rs:55:17
+ --> $DIR/move_closure.rs:53:17
|
LL | let mut c = #[rustc_capture_analysis]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+error[E0658]: attributes on expressions are experimental
+ --> $DIR/move_closure.rs:76:17
+ |
+LL | let mut c = #[rustc_capture_analysis]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+ = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+ --> $DIR/move_closure.rs:98:17
+ |
+LL | let mut c = #[rustc_capture_analysis]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+ = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+ --> $DIR/move_closure.rs:119:13
+ |
+LL | let c = #[rustc_capture_analysis]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+ = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/move_closure.rs:3:12
|
LL | / move || {
LL | |
LL | |
-LL | | *ref_s += 10;
+LL | | t.0.0 = "new S".into();
+LL | |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Capturing t[(0, 0),(0, 0)] -> ByValue
+ --> $DIR/move_closure.rs:20:9
+ |
+LL | t.0.0 = "new S".into();
+ | ^^^^^
+
+error: Min Capture analysis includes:
+ --> $DIR/move_closure.rs:17:5
+ |
+LL | / move || {
+LL | |
+LL | |
+LL | | t.0.0 = "new S".into();
LL | |
LL | |
LL | | };
| |_____^
|
-note: Capturing ref_s[Deref] -> ByValue
+note: Min Capture t[(0, 0),(0, 0)] -> ByValue
--> $DIR/move_closure.rs:20:9
|
+LL | t.0.0 = "new S".into();
+ | ^^^^^
+
+error: First Pass analysis includes:
+ --> $DIR/move_closure.rs:35:5
+ |
+LL | / move || {
+LL | |
+LL | |
+LL | | *ref_s += 10;
+LL | |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Capturing ref_s[Deref] -> UniqueImmBorrow
+ --> $DIR/move_closure.rs:38:9
+ |
LL | *ref_s += 10;
| ^^^^^^
error: Min Capture analysis includes:
- --> $DIR/move_closure.rs:17:5
+ --> $DIR/move_closure.rs:35:5
|
LL | / move || {
LL | |
LL | | };
| |_____^
|
-note: Min Capture ref_s[] -> ByValue
- --> $DIR/move_closure.rs:20:9
+note: Min Capture ref_s[Deref] -> UniqueImmBorrow
+ --> $DIR/move_closure.rs:38:9
|
LL | *ref_s += 10;
| ^^^^^^
error: First Pass analysis includes:
- --> $DIR/move_closure.rs:38:5
+ --> $DIR/move_closure.rs:56:5
|
LL | / move || {
LL | |
LL | | };
| |_____^
|
-note: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
- --> $DIR/move_closure.rs:41:9
+note: Capturing t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow
+ --> $DIR/move_closure.rs:59:9
|
LL | t.0.0 = "new s".into();
| ^^^^^
error: Min Capture analysis includes:
- --> $DIR/move_closure.rs:38:5
+ --> $DIR/move_closure.rs:56:5
|
LL | / move || {
LL | |
LL | | };
| |_____^
|
-note: Min Capture t[(0, 0)] -> ByValue
- --> $DIR/move_closure.rs:41:9
+note: Min Capture t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow
+ --> $DIR/move_closure.rs:59:9
|
LL | t.0.0 = "new s".into();
| ^^^^^
error: First Pass analysis includes:
- --> $DIR/move_closure.rs:58:5
+ --> $DIR/move_closure.rs:79:5
|
LL | / move || {
LL | |
LL | |
-LL | | t.0.0 = "new S".into();
+LL | | let _t = t.0.0;
LL | |
LL | |
LL | | };
| |_____^
|
-note: Capturing t[(0, 0),(0, 0)] -> ByValue
- --> $DIR/move_closure.rs:61:9
+note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+ --> $DIR/move_closure.rs:82:18
|
-LL | t.0.0 = "new S".into();
- | ^^^^^
+LL | let _t = t.0.0;
+ | ^^^^^
error: Min Capture analysis includes:
- --> $DIR/move_closure.rs:58:5
+ --> $DIR/move_closure.rs:79:5
|
LL | / move || {
LL | |
LL | |
-LL | | t.0.0 = "new S".into();
+LL | | let _t = t.0.0;
LL | |
LL | |
LL | | };
| |_____^
|
-note: Min Capture t[(0, 0),(0, 0)] -> ByValue
- --> $DIR/move_closure.rs:61:9
+note: Min Capture t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+ --> $DIR/move_closure.rs:82:18
|
-LL | t.0.0 = "new S".into();
- | ^^^^^
+LL | let _t = t.0.0;
+ | ^^^^^
+
+error: First Pass analysis includes:
+ --> $DIR/move_closure.rs:101:5
+ |
+LL | / move || {
+LL | |
+LL | |
+LL | | let _t = t.0.0;
+... |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+ --> $DIR/move_closure.rs:104:18
+ |
+LL | let _t = t.0.0;
+ | ^^^^^
+note: Capturing t[(0, 0)] -> ByValue
+ --> $DIR/move_closure.rs:104:18
+ |
+LL | let _t = t.0.0;
+ | ^^^^^
+
+error: Min Capture analysis includes:
+ --> $DIR/move_closure.rs:101:5
+ |
+LL | / move || {
+LL | |
+LL | |
+LL | | let _t = t.0.0;
+... |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Min Capture t[(0, 0)] -> ByValue
+ --> $DIR/move_closure.rs:104:18
+ |
+LL | let _t = t.0.0;
+ | ^^^^^
+
+error: First Pass analysis includes:
+ --> $DIR/move_closure.rs:122:5
+ |
+LL | / move || {
+LL | |
+LL | |
+LL | | let _t = b.0;
+... |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Capturing b[Deref,(0, 0)] -> ByValue
+ --> $DIR/move_closure.rs:125:18
+ |
+LL | let _t = b.0;
+ | ^^^
+note: Capturing b[] -> ByValue
+ --> $DIR/move_closure.rs:125:18
+ |
+LL | let _t = b.0;
+ | ^^^
+
+error: Min Capture analysis includes:
+ --> $DIR/move_closure.rs:122:5
+ |
+LL | / move || {
+LL | |
+LL | |
+LL | | let _t = b.0;
+... |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Min Capture b[] -> ByValue
+ --> $DIR/move_closure.rs:125:18
+ |
+LL | let _t = b.0;
+ | ^^^
-error: aborting due to 9 previous errors; 1 warning emitted
+error: aborting due to 18 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0658`.
c();
}
+struct A<'a>(&'a mut String, &'a mut String);
+// Test that reborrowing works as expected for move closures
+// by attempting a disjoint capture through a reference.
+fn disjoint_via_ref() {
+ let mut x = String::new();
+ let mut y = String::new();
+
+ let mut a = A(&mut x, &mut y);
+ let a = &mut a;
+
+ let mut c1 = move || {
+ a.0.truncate(0);
+ };
+
+ let mut c2 = move || {
+ a.1.truncate(0);
+ };
+
+ c1();
+ c2();
+}
+
+// Test that even if a path is moved into the closure, the closure is not FnOnce
+// if the path is not moved by the closure call.
+fn data_moved_but_not_fn_once() {
+ let x = Box::new(10i32);
+
+ let c = move || {
+ // *x has type i32 which is Copy. So even though the box `x` will be moved
+ // into the closure, `x` is never moved when the closure is called, i.e. the
+ // ownership stays with the closure and therefore we can call the function multiple times.
+ let _x = *x;
+ };
+
+ c();
+ c();
+}
+
fn main() {
simple_ref();
struct_contains_ref_to_another_struct();
no_ref();
no_ref_nested();
+
+ disjoint_via_ref();
+ data_moved_but_not_fn_once();
}
LL | fn test<const N: usize>() -> Foo<N> {
| ^
|
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
|
LL | fn test<const N: usize>() -> Foo<{ N }> {
| ^ ^
--- /dev/null
+#![crate_type="lib"]
+#![feature(min_const_generics)]
+#![allow(incomplete_features)]
+
+struct A<const N: u8>;
+trait Foo {}
+impl Foo for A<N> {}
+//~^ ERROR cannot find type
+//~| unresolved item provided when a constant
+
+struct B<const N: u8>;
+impl<N> Foo for B<N> {}
+//~^ ERROR type provided when a constant
+
+struct C<const C: u8, const N: u8>;
+impl<const N: u8> Foo for C<N, T> {}
+//~^ ERROR cannot find type
+//~| unresolved item provided when a constant
--- /dev/null
+error[E0412]: cannot find type `N` in this scope
+ --> $DIR/diagnostics.rs:7:16
+ |
+LL | struct A<const N: u8>;
+ | ---------------------- similarly named struct `A` defined here
+LL | trait Foo {}
+LL | impl Foo for A<N> {}
+ | ^ help: a struct with a similar name exists: `A`
+
+error[E0412]: cannot find type `T` in this scope
+ --> $DIR/diagnostics.rs:16:32
+ |
+LL | struct A<const N: u8>;
+ | ---------------------- similarly named struct `A` defined here
+...
+LL | impl<const N: u8> Foo for C<N, T> {}
+ | ^ help: a struct with a similar name exists: `A`
+
+error[E0747]: unresolved item provided when a constant was expected
+ --> $DIR/diagnostics.rs:7:16
+ |
+LL | impl Foo for A<N> {}
+ | ^
+ |
+help: if this generic argument was intended as a const parameter, surround it with braces
+ |
+LL | impl Foo for A<{ N }> {}
+ | ^ ^
+
+error[E0747]: type provided when a constant was expected
+ --> $DIR/diagnostics.rs:12:19
+ |
+LL | impl<N> Foo for B<N> {}
+ | - ^
+ | |
+ | help: consider changing this type paramater to a `const`-generic: `const N: u8`
+
+error[E0747]: unresolved item provided when a constant was expected
+ --> $DIR/diagnostics.rs:16:32
+ |
+LL | impl<const N: u8> Foo for C<N, T> {}
+ | ^
+ |
+help: if this generic argument was intended as a const parameter, surround it with braces
+ |
+LL | impl<const N: u8> Foo for C<N, { T }> {}
+ | ^ ^
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0412, E0747.
+For more information about an error, try `rustc --explain E0412`.
--- /dev/null
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+// This tests that during error handling for the "trait not implemented" error
+// we dont try to evaluate std::mem::size_of::<Self::Assoc> causing an ICE
+
+struct Adt;
+
+trait Foo {
+ type Assoc;
+ fn foo()
+ where
+ [Adt; std::mem::size_of::<Self::Assoc>()]: ,
+ {
+ <[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
+ //~^ Error: the trait bound
+ }
+
+ fn bar() {}
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `[Adt; _]: Foo` is not satisfied
+ --> $DIR/dont-evaluate-array-len-on-err-1.rs:15:9
+ |
+LL | <[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[Adt; _]`
+...
+LL | fn bar() {}
+ | -------- required by `Foo::bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
#[derive(PartialEq, Eq)]
enum CompileFlag {
- A,
- B,
+ A,
+ B,
}
pub fn test_1<const CF: CompileFlag>() {}
pub fn test_2<T, const CF: CompileFlag>(x: T) {}
pub struct Example<const CF: CompileFlag, T=u32>{
- x: T,
+ x: T,
}
impl<const CF: CompileFlag, T> Example<CF, T> {
pub fn main() {
test_1::<CompileFlag::A>();
//~^ ERROR: expected type, found variant
- //~| ERROR: type provided when a constant was expected
+ //~| ERROR: unresolved item provided when a constant was expected
test_2::<_, CompileFlag::A>(0);
//~^ ERROR: expected type, found variant
- //~| ERROR: type provided when a constant was expected
+ //~| ERROR: unresolved item provided when a constant was expected
let _: Example<CompileFlag::A, _> = Example { x: 0 };
//~^ ERROR: expected type, found variant
- //~| ERROR: type provided when a constant was expected
+ //~| ERROR: unresolved item provided when a constant was expected
let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
//~^ ERROR: type provided when a constant was expected
| not a type
| help: try using the variant's enum: `CompileFlag`
-error[E0747]: type provided when a constant was expected
+error[E0747]: unresolved item provided when a constant was expected
--> $DIR/invalid-enum.rs:29:18
|
LL | let _: Example<CompileFlag::A, _> = Example { x: 0 };
| ^^^^^^^^^^^^^^
|
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
|
LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 };
| ^ ^
LL | let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
| ^^^^^^^^^^^^^^^^^^^
|
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
|
LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 };
| ^ ^
-error[E0747]: type provided when a constant was expected
+error[E0747]: unresolved item provided when a constant was expected
--> $DIR/invalid-enum.rs:21:12
|
LL | test_1::<CompileFlag::A>();
| ^^^^^^^^^^^^^^
|
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
|
LL | test_1::<{ CompileFlag::A }>();
| ^ ^
-error[E0747]: type provided when a constant was expected
+error[E0747]: unresolved item provided when a constant was expected
--> $DIR/invalid-enum.rs:25:15
|
LL | test_2::<_, CompileFlag::A>(0);
| ^^^^^^^^^^^^^^
|
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
|
LL | test_2::<_, { CompileFlag::A }>(0);
| ^ ^
--- /dev/null
+// check-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+struct TestStruct {
+ x: *const [isize; 2]
+}
+
+unsafe impl Sync for TestStruct {}
+
+static TEST_VALUE : TestStruct = TestStruct{x: 0x1234 as *const [isize; 2]};
+
+fn main() {}
--- /dev/null
+#![allow(warnings)]
+
+struct Struct { a: usize }
+
+const C: usize = 1;
+static S: usize = 1;
+
+const T1: &'static usize = &C;
+const T2: &'static usize = &S; //~ ERROR: constants cannot refer to statics
+static T3: &'static usize = &C;
+static T4: &'static usize = &S;
+
+const T5: usize = C;
+const T6: usize = S; //~ ERROR: constants cannot refer to statics
+static T7: usize = C;
+static T8: usize = S;
+
+const T9: Struct = Struct { a: C };
+const T10: Struct = Struct { a: S };
+//~^ ERROR: constants cannot refer to statics
+static T11: Struct = Struct { a: C };
+static T12: Struct = Struct { a: S };
+
+fn main() {}
--- /dev/null
+error[E0013]: constants cannot refer to statics
+ --> $DIR/issue-17718-references.rs:9:29
+ |
+LL | const T2: &'static usize = &S;
+ | ^
+ |
+ = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+ --> $DIR/issue-17718-references.rs:14:19
+ |
+LL | const T6: usize = S;
+ | ^
+ |
+ = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+ --> $DIR/issue-17718-references.rs:19:33
+ |
+LL | const T10: Struct = Struct { a: S };
+ | ^
+ |
+ = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0013`.
--- /dev/null
+static S : u64 = { { panic!("foo"); 0 } };
+//~^ ERROR panicking in statics is unstable
+
+fn main() {
+ println!("{:?}", S);
+}
--- /dev/null
+error[E0658]: panicking in statics is unstable
+ --> $DIR/issue-32829.rs:1:22
+ |
+LL | static S : u64 = { { panic!("foo"); 0 } };
+ | ^^^^^^^^^^^^^^
+ |
+ = note: see issue #51999 <https://github.com/rust-lang/rust/issues/51999> for more information
+ = help: add `#![feature(const_panic)]` to the crate attributes to enable
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// run-pass
+
+const fn foo() -> *const i8 {
+ b"foo" as *const _ as *const i8
+}
+
+const fn bar() -> i32 {
+ *&{(1, 2, 3).1}
+}
+
+fn main() {
+ assert_eq!(foo(), b"foo" as *const _ as *const i8);
+ assert_eq!(bar(), 2);
+}
--- /dev/null
+// run-pass
+
+use std::cell::Cell;
+
+const NONE_CELL_STRING: Option<Cell<String>> = None;
+
+struct Foo<T>(T);
+impl<T> Foo<T> {
+ const FOO: Option<Box<T>> = None;
+}
+
+fn main() {
+ let _: &'static u32 = &42;
+ let _: &'static Option<u32> = &None;
+
+ // We should be able to peek at consts and see they're None.
+ let _: &'static Option<Cell<String>> = &NONE_CELL_STRING;
+ let _: &'static Option<Box<()>> = &Foo::FOO;
+}
--- /dev/null
+pub static mut A: u32 = 0;
+pub static mut B: () = unsafe { A = 1; };
+//~^ ERROR could not evaluate static initializer
+
+pub static mut C: u32 = unsafe { C = 1; 0 };
+//~^ ERROR cycle detected
+
+pub static D: u32 = D;
+
+fn main() {}
--- /dev/null
+error[E0080]: could not evaluate static initializer
+ --> $DIR/write-to-static-mut-in-static.rs:2:33
+ |
+LL | pub static mut B: () = unsafe { A = 1; };
+ | ^^^^^ modifying a static's initial value from another static's initializer
+
+error[E0391]: cycle detected when const-evaluating + checking `C`
+ --> $DIR/write-to-static-mut-in-static.rs:5:1
+ |
+LL | pub static mut C: u32 = unsafe { C = 1; 0 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: ...which requires const-evaluating + checking `C`...
+ --> $DIR/write-to-static-mut-in-static.rs:5:1
+ |
+LL | pub static mut C: u32 = unsafe { C = 1; 0 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which again requires const-evaluating + checking `C`, completing the cycle
+ = note: cycle used when running analysis passes on this crate
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0080, E0391.
+For more information about an error, try `rustc --explain E0080`.
+++ /dev/null
-fn main() {
- let _redemptive = 1...21;
- //~^ ERROR unexpected token
-}
+++ /dev/null
-error: unexpected token: `...`
- --> $DIR/dotdotdot-expr.rs:2:24
- |
-LL | let _redemptive = 1...21;
- | ^^^
- |
-help: use `..` for an exclusive range
- |
-LL | let _redemptive = 1..21;
- | ^^
-help: or `..=` for an inclusive range
- |
-LL | let _redemptive = 1..=21;
- | ^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications.nll/libemit_artifact_notifications.rmeta","emit":"metadata"}
+++ /dev/null
-{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications.polonius/libemit_artifact_notifications.rmeta","emit":"metadata"}
+++ /dev/null
-// compile-flags:--emit=metadata --error-format=json --json artifacts
-// build-pass
-// ignore-pass
-// ^-- needed because `--pass check` does not emit the output needed.
-
-// A very basic test for the emission of artifact notifications in JSON output.
-
-fn main() {}
+++ /dev/null
-{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications/libemit_artifact_notifications.rmeta","emit":"metadata"}
+++ /dev/null
-// compile-flags:--emit=metadata,obj
-// build-pass
-
-// A test for the emission of metadata + obj and other metadata + non-link
-// combinations. See issue #81117.
-
-fn main() {}
+++ /dev/null
-// run-pass
-
-fn test_if_panic() {
- let x = if false { panic!() } else { 10 };
- assert_eq!(x, 10);
-}
-
-fn test_else_panic() {
- let x = if true { 10 } else { panic!() };
- assert_eq!(x, 10);
-}
-
-fn test_elseif_panic() {
- let x = if false { 0 } else if false { panic!() } else { 10 };
- assert_eq!(x, 10);
-}
-
-pub fn main() { test_if_panic(); test_else_panic(); test_elseif_panic(); }
--- /dev/null
+// run-pass
+
+fn test_if_panic() {
+ let x = if false { panic!() } else { 10 };
+ assert_eq!(x, 10);
+}
+
+fn test_else_panic() {
+ let x = if true { 10 } else { panic!() };
+ assert_eq!(x, 10);
+}
+
+fn test_elseif_panic() {
+ let x = if false { 0 } else if false { panic!() } else { 10 };
+ assert_eq!(x, 10);
+}
+
+pub fn main() { test_if_panic(); test_else_panic(); test_elseif_panic(); }
macro_rules! foo{
($p:pat, $e:expr, $b:block) => {{
if let $p = $e $b
- //~^ WARN irrefutable if-let
- //~| WARN irrefutable if-let
+ //~^ WARN irrefutable `if let`
+ //~| WARN irrefutable `if let`
}}
}
macro_rules! bar{
}
pub fn main() {
- if let a = 1 { //~ WARN irrefutable if-let
+ if let a = 1 { //~ WARN irrefutable `if let`
println!("irrefutable pattern");
}
- if let a = 1 { //~ WARN irrefutable if-let
+ if let a = 1 { //~ WARN irrefutable `if let`
println!("irrefutable pattern");
} else if true {
- println!("else-if in irrefutable if-let");
+ println!("else-if in irrefutable `if let`");
} else {
- println!("else in irrefutable if-let");
+ println!("else in irrefutable `if let`");
}
if let 1 = 2 {
println!("refutable pattern");
- } else if let a = 1 { //~ WARN irrefutable if-let
+ } else if let a = 1 { //~ WARN irrefutable `if let`
println!("irrefutable pattern");
}
if true {
println!("if");
- } else if let a = 1 { //~ WARN irrefutable if-let
+ } else if let a = 1 { //~ WARN irrefutable `if let`
println!("irrefutable pattern");
}
}
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
--> $DIR/if-let.rs:6:13
|
LL | if let $p = $e $b
| |_______- in this macro invocation
|
= note: `#[warn(irrefutable_let_patterns)]` on by default
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
--> $DIR/if-let.rs:6:13
|
LL | if let $p = $e $b
LL | | });
| |_______- in this macro invocation
|
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
--> $DIR/if-let.rs:26:5
|
LL | / if let a = 1 {
LL | | println!("irrefutable pattern");
LL | | }
| |_____^
+ |
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
--> $DIR/if-let.rs:30:5
|
LL | / if let a = 1 {
LL | | println!("irrefutable pattern");
LL | | } else if true {
-LL | | println!("else-if in irrefutable if-let");
+LL | | println!("else-if in irrefutable `if let`");
LL | | } else {
-LL | | println!("else in irrefutable if-let");
+LL | | println!("else in irrefutable `if let`");
LL | | }
| |_____^
+ |
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
--> $DIR/if-let.rs:40:12
|
LL | } else if let a = 1 {
LL | | println!("irrefutable pattern");
LL | | }
| |_____^
+ |
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
--> $DIR/if-let.rs:46:12
|
LL | } else if let a = 1 {
LL | | println!("irrefutable pattern");
LL | | }
| |_____^
+ |
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
warning: 6 warnings emitted
--- /dev/null
+fn main() {
+ let a = if true {
+ 0
+ } else if false {
+//~^ ERROR `if` may be missing an `else` clause
+//~| expected `()`, found integer
+ 1
+ };
+}
--- /dev/null
+error[E0317]: `if` may be missing an `else` clause
+ --> $DIR/issue-4201.rs:4:12
+ |
+LL | } else if false {
+ | ____________^
+LL | |
+LL | |
+LL | | 1
+ | | - found here
+LL | | };
+ | |_____^ expected `()`, found integer
+ |
+ = note: `if` expressions without `else` evaluate to `()`
+ = help: consider adding an `else` block that evaluates to the expected type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0317`.
--- /dev/null
+// run-pass
+// This test verifies that temporaries created for `while`'s and `if`
+// conditions are dropped after the condition is evaluated.
+
+#![feature(box_syntax)]
+
+struct Temporary;
+
+static mut DROPPED: isize = 0;
+
+impl Drop for Temporary {
+ fn drop(&mut self) {
+ unsafe { DROPPED += 1; }
+ }
+}
+
+impl Temporary {
+ fn do_stuff(&self) -> bool {true}
+}
+
+fn borrow() -> Box<Temporary> { box Temporary }
+
+
+pub fn main() {
+ let mut i = 0;
+
+ // This loop's condition
+ // should call `Temporary`'s
+ // `drop` 6 times.
+ while borrow().do_stuff() {
+ i += 1;
+ unsafe { assert_eq!(DROPPED, i) }
+ if i > 5 {
+ break;
+ }
+ }
+
+ // This if condition should
+ // call it 1 time
+ if borrow().do_stuff() {
+ unsafe { assert_eq!(DROPPED, i + 1) }
+ }
+}
error: implementation of `Foo` is not general enough
--> $DIR/auto-trait-regions.rs:31:5
|
-LL | auto trait Foo {}
- | ----------------- trait `Foo` defined here
-...
LL | assert_foo(gen);
| ^^^^^^^^^^ implementation of `Foo` is not general enough
|
- = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`...
- = note: ...but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1`
+ = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`...
+ = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef`
error: implementation of `Foo` is not general enough
--> $DIR/auto-trait-regions.rs:31:5
|
-LL | auto trait Foo {}
- | ----------------- trait `Foo` defined here
-...
LL | assert_foo(gen);
| ^^^^^^^^^^ implementation of `Foo` is not general enough
|
- = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`...
- = note: ...but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1`
+ = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`...
+ = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef`
error: implementation of `Foo` is not general enough
--> $DIR/auto-trait-regions.rs:50:5
|
-LL | auto trait Foo {}
- | ----------------- trait `Foo` defined here
-...
LL | assert_foo(gen);
| ^^^^^^^^^^ implementation of `Foo` is not general enough
|
error: implementation of `Foo` is not general enough
--> $DIR/auto-trait-regions.rs:50:5
|
-LL | auto trait Foo {}
- | ----------------- trait `Foo` defined here
-...
LL | assert_foo(gen);
| ^^^^^^^^^^ implementation of `Foo` is not general enough
|
--- /dev/null
+#![feature(generators)]
+
+fn main() {
+ yield || for i in 0 { }
+ //~^ ERROR yield expression outside of generator literal
+ //~| ERROR `{integer}` is not an iterator
+}
--- /dev/null
+error[E0627]: yield expression outside of generator literal
+ --> $DIR/yield-outside-generator-issue-78653.rs:4:5
+ |
+LL | yield || for i in 0 { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: `{integer}` is not an iterator
+ --> $DIR/yield-outside-generator-issue-78653.rs:4:23
+ |
+LL | yield || for i in 0 { }
+ | ^ `{integer}` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `{integer}`
+ = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+ = note: required because of the requirements on the impl of `IntoIterator` for `{integer}`
+ = note: required by `into_iter`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0627.
+For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+// Test that correct syntax is used in suggestion to constrain associated type
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete
+
+trait X {
+ type Y<T>;
+}
+
+fn f<T: X>(a: T::Y<i32>) {
+ //~^ HELP consider constraining the associated type `<T as X>::Y<i32>` to `Vec<i32>`
+ //~| SUGGESTION Y<i32> = Vec<i32>>
+ let b: Vec<i32> = a;
+ //~^ ERROR mismatched types
+}
+
+fn main() {}
--- /dev/null
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/constraint-assoc-type-suggestion.rs:3:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0308]: mismatched types
+ --> $DIR/constraint-assoc-type-suggestion.rs:13:23
+ |
+LL | let b: Vec<i32> = a;
+ | -------- ^ expected struct `Vec`, found associated type
+ | |
+ | expected due to this
+ |
+ = note: expected struct `Vec<i32>`
+ found associated type `<T as X>::Y<i32>`
+help: consider constraining the associated type `<T as X>::Y<i32>` to `Vec<i32>`
+ |
+LL | fn f<T: X<Y<i32> = Vec<i32>>>(a: T::Y<i32>) {
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+
+pub trait X {
+ type Y<'a>;
+ fn m(&self) -> Self::Y<'_>;
+}
+
+impl X for () {
+ type Y<'a> = &'a ();
+
+ fn m(&self) -> Self::Y<'_> {
+ self
+ }
+}
+
+fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &() {
+ x.m()
+}
+
+fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &() {
+ x.m()
+}
+
+fn h(x: &()) -> &() {
+ x.m()
+}
+
+fn main() {
+ f(&());
+ g(&());
+ h(&());
+}
#![feature(generic_associated_types)]
- //~^ WARNING the feature
+//~^ WARNING the feature
pub trait SubTrait {}
pub trait SuperTrait {
type SubType<'a>: SubTrait;
- //~^ ERROR missing generics for associated
+ //~^ ERROR missing generics for associated
fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
}
fn main() {
let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
- //~^ ERROR the trait
- //~| ERROR the trait
}
LL | type SubType<'a><'a>: SubTrait;
| ^^^^
-error[E0038]: the trait `SuperTrait` cannot be made into an object
- --> $DIR/issue-76535.rs:38:14
- |
-LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
- |
- = help: consider moving `get_sub` to another trait
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
- --> $DIR/issue-76535.rs:10:37
- |
-LL | pub trait SuperTrait {
- | ---------- this trait cannot be made into an object...
-...
-LL | fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
- | ^^^^^^^^^^^^^^^^^ ...because method `get_sub` references the `Self` type in its return type
-
-error[E0038]: the trait `SuperTrait` cannot be made into an object
- --> $DIR/issue-76535.rs:38:57
- |
-LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
- |
- = help: consider moving `get_sub` to another trait
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
- --> $DIR/issue-76535.rs:10:37
- |
-LL | pub trait SuperTrait {
- | ---------- this trait cannot be made into an object...
-...
-LL | fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
- | ^^^^^^^^^^^^^^^^^ ...because method `get_sub` references the `Self` type in its return type
- = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn SuperTrait<SubType = SubStruct<'_>>>>` for `Box<SuperStruct>`
- = note: required by cast to type `Box<dyn SuperTrait<SubType = SubStruct<'_>>>`
-
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to previous error; 1 warning emitted
-Some errors have detailed explanations: E0038, E0107.
-For more information about an error, try `rustc --explain E0038`.
+For more information about this error, try `rustc --explain E0107`.
trait MapLike<K, V> {
type VRefCont<'a>: RefCont<'a, V>;
- //~^ ERROR missing generics
+ //~^ ERROR missing generics
fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
}
fn main() {
let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
- //~^ ERROR the trait
- //~^^^ ERROR the trait
+ //~^^ ERROR type mismatch resolving
}
LL | type VRefCont<'a><'a>: RefCont<'a, V>;
| ^^^^
-error[E0038]: the trait `MapLike` cannot be made into an object
- --> $DIR/issue-79422.rs:44:12
- |
-LL | as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
- |
- = help: consider moving `get` to another trait
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
- --> $DIR/issue-79422.rs:23:38
- |
-LL | trait MapLike<K, V> {
- | ------- this trait cannot be made into an object...
-...
-LL | fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `get` references the `Self` type in its return type
-
-error[E0038]: the trait `MapLike` cannot be made into an object
+error[E0271]: type mismatch resolving `<BTreeMap<u8, u8> as MapLike<u8, u8>>::VRefCont<'static> == (dyn RefCont<'_, u8> + 'static)`
--> $DIR/issue-79422.rs:43:13
|
LL | let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
- |
- = help: consider moving `get` to another trait
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
- --> $DIR/issue-79422.rs:23:38
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn RefCont`, found reference
|
-LL | trait MapLike<K, V> {
- | ------- this trait cannot be made into an object...
-...
-LL | fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `get` references the `Self` type in its return type
- = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>>` for `Box<BTreeMap<u8, u8>>`
- = note: required by cast to type `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`
+ = note: expected trait object `(dyn RefCont<'_, u8> + 'static)`
+ found reference `&'static u8`
+ = note: required for the cast to the object type `dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>`
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0038, E0107.
-For more information about an error, try `rustc --explain E0038`.
+Some errors have detailed explanations: E0107, E0271.
+For more information about an error, try `rustc --explain E0107`.
--- /dev/null
+// Test that the predicate printed in an unresolved method error prints the
+// generics for a generic associated type.
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete
+//~| NOTE `#[warn(incomplete_features)]` on by default
+//~| NOTE see issue #44265
+
+trait X {
+ type Y<T>;
+}
+
+trait M {
+ fn f(&self) {}
+}
+
+impl<T: X<Y<i32> = i32>> M for T {}
+
+struct S;
+//~^ NOTE method `f` not found for this
+//~| NOTE doesn't satisfy `<S as X>::Y<i32> = i32`
+//~| NOTE doesn't satisfy `S: M`
+
+impl X for S {
+ type Y<T> = bool;
+}
+
+fn f(a: S) {
+ a.f();
+ //~^ ERROR the method `f` exists for struct `S`, but its trait bounds were not satisfied
+ //~| NOTE method cannot be called on `S` due to unsatisfied trait bounds
+ //~| NOTE the following trait bounds were not satisfied:
+}
+
+fn main() {}
--- /dev/null
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/method-unsatified-assoc-type-predicate.rs:4:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied
+ --> $DIR/method-unsatified-assoc-type-predicate.rs:29:7
+ |
+LL | struct S;
+ | ---------
+ | |
+ | method `f` not found for this
+ | doesn't satisfy `<S as X>::Y<i32> = i32`
+ | doesn't satisfy `S: M`
+...
+LL | a.f();
+ | ^ method cannot be called on `S` due to unsatisfied trait bounds
+ |
+ = note: the following trait bounds were not satisfied:
+ `<S as X>::Y<i32> = i32`
+ which is required by `S: M`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0599`.
--- /dev/null
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+
+pub trait X {
+ type Y<'a>;
+ fn m(&self) -> Self::Y<'_>;
+}
+
+impl X for () {
+ type Y<'a> = &'a ();
+
+ fn m(&self) -> Self::Y<'_> {
+ self
+ }
+}
+
+fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &'static () {
+ x.m()
+ //~^ ERROR explicit lifetime required
+}
+
+fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &'static () {
+ x.m()
+ //~^ ERROR explicit lifetime required
+}
+
+fn h(x: &()) -> &'static () {
+ x.m()
+ //~^ ERROR explicit lifetime required
+}
+
+fn main() {
+ f(&());
+ g(&());
+ h(&());
+}
--- /dev/null
+error[E0621]: explicit lifetime required in the type of `x`
+ --> $DIR/projection-type-lifetime-mismatch.rs:18:5
+ |
+LL | fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &'static () {
+ | ------------------------------- help: add explicit lifetime `'static` to the type of `x`: `&'static impl for<'a> X<Y<'a> = &'a ()>`
+LL | x.m()
+ | ^^^^^ lifetime `'static` required
+
+error[E0621]: explicit lifetime required in the type of `x`
+ --> $DIR/projection-type-lifetime-mismatch.rs:23:5
+ |
+LL | fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &'static () {
+ | -- help: add explicit lifetime `'static` to the type of `x`: `&'static T`
+LL | x.m()
+ | ^^^^^ lifetime `'static` required
+
+error[E0621]: explicit lifetime required in the type of `x`
+ --> $DIR/projection-type-lifetime-mismatch.rs:28:5
+ |
+LL | fn h(x: &()) -> &'static () {
+ | --- help: add explicit lifetime `'static` to the type of `x`: `&'static ()`
+LL | x.m()
+ | ^^^^^ lifetime `'static` required
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0621`.
--- /dev/null
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+
+pub trait X {
+ type Y<'a: 'static>;
+ //~^ WARNING unnecessary lifetime parameter
+}
+
+impl X for () {
+ type Y<'a> = &'a ();
+}
+
+struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> {
+ f: <T as X>::Y<'a>,
+ //~^ ERROR lifetime bound not satisfied
+}
+
+struct C<'a, T: X> {
+ f: <T as X>::Y<'a>,
+ //~^ ERROR lifetime bound not satisfied
+}
+
+struct D<'a> {
+ f: <() as X>::Y<'a>,
+ //~^ ERROR lifetime bound not satisfied
+}
+
+fn main() {}
--- /dev/null
+warning: unnecessary lifetime parameter `'a`
+ --> $DIR/unsatified-item-lifetime-bound.rs:5:12
+ |
+LL | type Y<'a: 'static>;
+ | ^^^^^^^^^^^
+ |
+ = help: you can use the `'static` lifetime directly, in place of `'a`
+
+error[E0478]: lifetime bound not satisfied
+ --> $DIR/unsatified-item-lifetime-bound.rs:14:8
+ |
+LL | f: <T as X>::Y<'a>,
+ | ^^^^^^^^^^^^^^^
+ |
+note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 13:10
+ --> $DIR/unsatified-item-lifetime-bound.rs:13:10
+ |
+LL | struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> {
+ | ^^
+ = note: but lifetime parameter must outlive the static lifetime
+
+error[E0478]: lifetime bound not satisfied
+ --> $DIR/unsatified-item-lifetime-bound.rs:19:8
+ |
+LL | f: <T as X>::Y<'a>,
+ | ^^^^^^^^^^^^^^^
+ |
+note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 18:10
+ --> $DIR/unsatified-item-lifetime-bound.rs:18:10
+ |
+LL | struct C<'a, T: X> {
+ | ^^
+ = note: but lifetime parameter must outlive the static lifetime
+
+error[E0478]: lifetime bound not satisfied
+ --> $DIR/unsatified-item-lifetime-bound.rs:24:8
+ |
+LL | f: <() as X>::Y<'a>,
+ | ^^^^^^^^^^^^^^^^
+ |
+note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 23:10
+ --> $DIR/unsatified-item-lifetime-bound.rs:23:10
+ |
+LL | struct D<'a> {
+ | ^^
+ = note: but lifetime parameter must outlive the static lifetime
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0478`.
|
LL | test::<FooS>(&mut 42);
| ^^^^^^^^^^^^ implementation of `Foo` is not general enough
-...
-LL | trait Foo<'a> {}
- | ---------------- trait `Foo` defined here
|
= note: `FooS<'_>` must implement `Foo<'0>`, for any lifetime `'0`...
= note: ...but `FooS<'_>` actually implements `Foo<'1>`, for some specific lifetime `'1`
error: implementation of `Deserialize` is not general enough
--> $DIR/hrtb-cache-issue-54302.rs:19:5
|
-LL | trait Deserialize<'de> {}
- | ------------------------- trait `Deserialize` defined here
-...
LL | assert_deserialize_owned::<&'static str>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
|
error: implementation of `Foo` is not general enough
--> $DIR/hrtb-conflate-regions.rs:27:10
|
-LL | / trait Foo<X> {
-LL | | fn foo(&self, x: X) { }
-LL | | }
- | |_- trait `Foo` defined here
-...
-LL | fn b() { want_foo2::<SomeStruct>(); }
- | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL | fn b() { want_foo2::<SomeStruct>(); }
+ | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
= note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
- = note: ...but `SomeStruct` actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+ = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: aborting due to previous error
error: implementation of `Trait` is not general enough
--> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
|
-LL | trait Trait<T> {}
- | ----------------- trait `Trait` defined here
-...
LL | foo::<()>();
| ^^^^^^^^^ implementation of `Trait` is not general enough
|
= note: `()` must implement `Trait<for<'b> fn(&'b u32)>`
- = note: ...but `()` actually implements `Trait<fn(&'0 u32)>`, for some specific lifetime `'0`
+ = note: ...but it actually implements `Trait<fn(&'0 u32)>`, for some specific lifetime `'0`
error: aborting due to previous error
error: implementation of `Trait` is not general enough
--> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
|
-LL | trait Trait<T> {}
- | ----------------- trait `Trait` defined here
-...
LL | foo::<()>();
| ^^^^^^^^^ implementation of `Trait` is not general enough
|
= note: `()` must implement `Trait<for<'b> fn(Cell<&'b u32>)>`
- = note: ...but `()` actually implements `Trait<fn(Cell<&'0 u32>)>`, for some specific lifetime `'0`
+ = note: ...but it actually implements `Trait<fn(Cell<&'0 u32>)>`, for some specific lifetime `'0`
error: aborting due to previous error
error: implementation of `Foo` is not general enough
--> $DIR/hrtb-just-for-static.rs:24:5
|
-LL | / trait Foo<X> {
-LL | | fn foo(&self, x: X) { }
-LL | | }
- | |_- trait `Foo` defined here
-...
-LL | want_hrtb::<StaticInt>()
- | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL | want_hrtb::<StaticInt>()
+ | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
= note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`...
- = note: ...but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1`
+ = note: ...but it actually implements `Foo<&'static isize>`
error: implementation of `Foo` is not general enough
--> $DIR/hrtb-just-for-static.rs:30:5
|
-LL | / trait Foo<X> {
-LL | | fn foo(&self, x: X) { }
-LL | | }
- | |_- trait `Foo` defined here
-...
-LL | want_hrtb::<&'a u32>()
- | ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL | want_hrtb::<&'a u32>()
+ | ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
= note: `Foo<&'0 isize>` would have to be implemented for the type `&'a u32`, for any lifetime `'0`...
= note: ...but `Foo<&'1 isize>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
warning: function cannot return without recursing
- --> $DIR/hrtb-perfect-forwarding.rs:22:1
+ --> $DIR/hrtb-perfect-forwarding.rs:16:1
|
-LL | / fn no_hrtb<'b,T>(mut t: T)
-LL | | where T : Bar<&'b isize>
+LL | / fn no_hrtb<'b, T>(mut t: T)
+LL | | where
+LL | | T: Bar<&'b isize>,
LL | | {
-LL | | // OK -- `T : Bar<&'b isize>`, and thus the impl above ensures that
-LL | | // `&mut T : Bar<&'b isize>`.
+... |
LL | | no_hrtb(&mut t);
| | --------------- recursive call site
LL | | }
= help: a `loop` may express intention better if this is on purpose
warning: function cannot return without recursing
- --> $DIR/hrtb-perfect-forwarding.rs:30:1
+ --> $DIR/hrtb-perfect-forwarding.rs:25:1
|
LL | / fn bar_hrtb<T>(mut t: T)
-LL | | where T : for<'b> Bar<&'b isize>
+LL | | where
+LL | | T: for<'b> Bar<&'b isize>,
LL | | {
-LL | | // OK -- `T : for<'b> Bar<&'b isize>`, and thus the impl above
... |
LL | | bar_hrtb(&mut t);
| | ---------------- recursive call site
= help: a `loop` may express intention better if this is on purpose
warning: function cannot return without recursing
- --> $DIR/hrtb-perfect-forwarding.rs:39:1
+ --> $DIR/hrtb-perfect-forwarding.rs:35:1
|
-LL | / fn foo_hrtb_bar_not<'b,T>(mut t: T)
-LL | | where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
+LL | / fn foo_hrtb_bar_not<'b, T>(mut t: T)
+LL | | where
+LL | | T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
LL | | {
-LL | | // Not OK -- The forwarding impl for `Foo` requires that `Bar` also
... |
LL | | foo_hrtb_bar_not(&mut t);
| | ------------------------ recursive call site
LL | |
+LL | |
LL | | }
| |_^ cannot return without recursing
|
= help: a `loop` may express intention better if this is on purpose
error: lifetime may not live long enough
- --> $DIR/hrtb-perfect-forwarding.rs:46:5
+ --> $DIR/hrtb-perfect-forwarding.rs:43:5
|
-LL | fn foo_hrtb_bar_not<'b,T>(mut t: T)
+LL | fn foo_hrtb_bar_not<'b, T>(mut t: T)
| -- lifetime `'b` defined here
...
LL | foo_hrtb_bar_not(&mut t);
= help: consider replacing `'b` with `'static`
error: higher-ranked subtype error
- --> $DIR/hrtb-perfect-forwarding.rs:46:5
+ --> $DIR/hrtb-perfect-forwarding.rs:43:5
|
LL | foo_hrtb_bar_not(&mut t);
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: function cannot return without recursing
- --> $DIR/hrtb-perfect-forwarding.rs:50:1
+ --> $DIR/hrtb-perfect-forwarding.rs:48:1
|
LL | / fn foo_hrtb_bar_hrtb<T>(mut t: T)
-LL | | where T : for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>
+LL | | where
+LL | | T: for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>,
LL | | {
-LL | | // OK -- now we have `T : for<'b> Bar&'b isize>`.
+LL | | // OK -- now we have `T : for<'b> Bar<&'b isize>`.
LL | | foo_hrtb_bar_hrtb(&mut t);
| | ------------------------- recursive call site
LL | | }
// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730.
trait Foo<X> {
- fn foo(&mut self, x: X) { }
+ fn foo(&mut self, x: X) {}
}
trait Bar<X> {
- fn bar(&mut self, x: X) { }
+ fn bar(&mut self, x: X) {}
}
-impl<'a,X,F> Foo<X> for &'a mut F
- where F : Foo<X> + Bar<X>
-{
-}
+impl<'a, X, F> Foo<X> for &'a mut F where F: Foo<X> + Bar<X> {}
-impl<'a,X,F> Bar<X> for &'a mut F
- where F : Bar<X>
-{
-}
+impl<'a, X, F> Bar<X> for &'a mut F where F: Bar<X> {}
-fn no_hrtb<'b,T>(mut t: T)
- where T : Bar<&'b isize>
+fn no_hrtb<'b, T>(mut t: T)
+where
+ T: Bar<&'b isize>,
{
// OK -- `T : Bar<&'b isize>`, and thus the impl above ensures that
// `&mut T : Bar<&'b isize>`.
}
fn bar_hrtb<T>(mut t: T)
- where T : for<'b> Bar<&'b isize>
+where
+ T: for<'b> Bar<&'b isize>,
{
// OK -- `T : for<'b> Bar<&'b isize>`, and thus the impl above
// ensures that `&mut T : for<'b> Bar<&'b isize>`. This is an
bar_hrtb(&mut t);
}
-fn foo_hrtb_bar_not<'b,T>(mut t: T)
- where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
+fn foo_hrtb_bar_not<'b, T>(mut t: T)
+where
+ T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
{
// Not OK -- The forwarding impl for `Foo` requires that `Bar` also
// be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a
// isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where
// clause only specifies `T : Bar<&'b isize>`.
- foo_hrtb_bar_not(&mut t); //~ ERROR mismatched types
- //~| ERROR mismatched types
+ foo_hrtb_bar_not(&mut t);
+ //~^ ERROR implementation of `Bar` is not general enough
+ //~| ERROR implementation of `Bar` is not general enough
}
fn foo_hrtb_bar_hrtb<T>(mut t: T)
- where T : for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>
+where
+ T: for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>,
{
- // OK -- now we have `T : for<'b> Bar&'b isize>`.
+ // OK -- now we have `T : for<'b> Bar<&'b isize>`.
foo_hrtb_bar_hrtb(&mut t);
}
-fn main() { }
+fn main() {}
-error[E0308]: mismatched types
- --> $DIR/hrtb-perfect-forwarding.rs:46:5
+error: implementation of `Bar` is not general enough
+ --> $DIR/hrtb-perfect-forwarding.rs:43:5
|
LL | foo_hrtb_bar_not(&mut t);
- | ^^^^^^^^^^^^^^^^ lifetime mismatch
+ | ^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
|
- = note: expected type `Bar<&'a isize>`
- found type `Bar<&'b isize>`
-note: the required lifetime does not necessarily outlive the lifetime `'b` as defined on the function body at 39:21
- --> $DIR/hrtb-perfect-forwarding.rs:39:21
- |
-LL | fn foo_hrtb_bar_not<'b,T>(mut t: T)
- | ^^
-note: the lifetime requirement is introduced here
- --> $DIR/hrtb-perfect-forwarding.rs:40:15
- |
-LL | where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
- | ^^^^^^^^^^^^^^^^^^^^^^
+ = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Bar<&'b isize>`
-error[E0308]: mismatched types
- --> $DIR/hrtb-perfect-forwarding.rs:46:5
+error: implementation of `Bar` is not general enough
+ --> $DIR/hrtb-perfect-forwarding.rs:43:5
|
LL | foo_hrtb_bar_not(&mut t);
- | ^^^^^^^^^^^^^^^^ lifetime mismatch
- |
- = note: expected type `Bar<&'a isize>`
- found type `Bar<&'b isize>`
-note: the lifetime `'b` as defined on the function body at 39:21 doesn't meet the lifetime requirements
- --> $DIR/hrtb-perfect-forwarding.rs:39:21
- |
-LL | fn foo_hrtb_bar_not<'b,T>(mut t: T)
- | ^^
-note: the lifetime requirement is introduced here
- --> $DIR/hrtb-perfect-forwarding.rs:40:15
+ | ^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
|
-LL | where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
- | ^^^^^^^^^^^^^^^^^^^^^^
+ = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Bar<&'b isize>`
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0308`.
error: implementation of `Foo` is not general enough
--> $DIR/issue-46989.rs:38:5
|
-LL | trait Foo {}
- | ------------ trait `Foo` defined here
-...
LL | assert_foo::<fn(&i32)>();
| ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
+++ /dev/null
-// run-pass
-
-#![allow(non_camel_case_types)]
-// A test of the macro system. Can we do HTML literals?
-
-/*
-
-This is an HTML parser written as a macro. It's all CPS, and we have
-to carry around a bunch of state. The arguments to macros all look like this:
-
-{ tag_stack* # expr* # tokens }
-
-The stack keeps track of where we are in the tree. The expr is a list
-of children of the current node. The tokens are everything that's
-left.
-
-*/
-use HTMLFragment::{tag, text};
-
-macro_rules! html {
- ( $($body:tt)* ) => (
- parse_node!( []; []; $($body)* )
- )
-}
-
-macro_rules! parse_node {
- (
- [:$head:ident ($(:$head_nodes:expr),*)
- $(:$tags:ident ($(:$tag_nodes:expr),*))*];
- [$(:$nodes:expr),*];
- </$tag:ident> $($rest:tt)*
- ) => (
- parse_node!(
- [$(: $tags ($(:$tag_nodes),*))*];
- [$(:$head_nodes,)* :tag(stringify!($head).to_string(),
- vec![$($nodes),*])];
- $($rest)*
- )
- );
-
- (
- [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
- [$(:$nodes:expr),*];
- <$tag:ident> $($rest:tt)*
- ) => (
- parse_node!(
- [:$tag ($(:$nodes)*) $(: $tags ($(:$tag_nodes),*) )*];
- [];
- $($rest)*
- )
- );
-
- (
- [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
- [$(:$nodes:expr),*];
- . $($rest:tt)*
- ) => (
- parse_node!(
- [$(: $tags ($(:$tag_nodes),*))*];
- [$(:$nodes,)* :text(".".to_string())];
- $($rest)*
- )
- );
-
- (
- [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
- [$(:$nodes:expr),*];
- $word:ident $($rest:tt)*
- ) => (
- parse_node!(
- [$(: $tags ($(:$tag_nodes),*))*];
- [$(:$nodes,)* :text(stringify!($word).to_string())];
- $($rest)*
- )
- );
-
- ( []; [:$e:expr]; ) => ( $e );
-}
-
-pub fn main() {
- let _page = html! (
- <html>
- <head><title>This is the title.</title></head>
- <body>
- <p>This is some text</p>
- </body>
- </html>
- );
-}
-
-enum HTMLFragment {
- tag(String, Vec<HTMLFragment> ),
- text(String),
-}
--- /dev/null
+// run-pass
+macro_rules! gen {
+ ($name:ident ( $($dol:tt $var:ident)* ) $($body:tt)*) => {
+ macro_rules! $name {
+ ($($dol $var:ident)*) => {
+ $($body)*
+ }
+ }
+ }
+}
+
+gen!(m($var) $var);
+
+fn main() {
+ let x = 1;
+ assert_eq!(m!(x), 1);
+}
--- /dev/null
+// run-pass
+// pretty-expanded FIXME #23616
+
+pub trait OpInt { fn call(&mut self, _: isize, _: isize) -> isize; }
+
+impl<F> OpInt for F where F: FnMut(isize, isize) -> isize {
+ fn call(&mut self, a:isize, b:isize) -> isize {
+ (*self)(a, b)
+ }
+}
+
+fn squarei<'a>(x: isize, op: &'a mut dyn OpInt) -> isize { op.call(x, x) }
+
+fn muli(x:isize, y:isize) -> isize { x * y }
+
+pub fn main() {
+ let mut f = |x, y| muli(x, y);
+ {
+ let g = &mut f;
+ let h = g as &mut dyn OpInt;
+ squarei(3, h);
+ }
+}
+++ /dev/null
-// check-pass
-#![allow(dead_code)]
-// pretty-expanded FIXME #23616
-
-struct TestStruct {
- x: *const [isize; 2]
-}
-
-unsafe impl Sync for TestStruct {}
-
-static TEST_VALUE : TestStruct = TestStruct{x: 0x1234 as *const [isize; 2]};
-
-fn main() {}
+++ /dev/null
-#![allow(warnings)]
-
-struct Struct { a: usize }
-
-const C: usize = 1;
-static S: usize = 1;
-
-const T1: &'static usize = &C;
-const T2: &'static usize = &S; //~ ERROR: constants cannot refer to statics
-static T3: &'static usize = &C;
-static T4: &'static usize = &S;
-
-const T5: usize = C;
-const T6: usize = S; //~ ERROR: constants cannot refer to statics
-static T7: usize = C;
-static T8: usize = S;
-
-const T9: Struct = Struct { a: C };
-const T10: Struct = Struct { a: S };
-//~^ ERROR: constants cannot refer to statics
-static T11: Struct = Struct { a: C };
-static T12: Struct = Struct { a: S };
-
-fn main() {}
+++ /dev/null
-error[E0013]: constants cannot refer to statics
- --> $DIR/issue-17718-references.rs:9:29
- |
-LL | const T2: &'static usize = &S;
- | ^
- |
- = help: consider extracting the value of the `static` to a `const`, and referring to that
-
-error[E0013]: constants cannot refer to statics
- --> $DIR/issue-17718-references.rs:14:19
- |
-LL | const T6: usize = S;
- | ^
- |
- = help: consider extracting the value of the `static` to a `const`, and referring to that
-
-error[E0013]: constants cannot refer to statics
- --> $DIR/issue-17718-references.rs:19:33
- |
-LL | const T10: Struct = Struct { a: S };
- | ^
- |
- = help: consider extracting the value of the `static` to a `const`, and referring to that
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0013`.
-// Test if the sugared if-let construct correctly prints "missing an else clause" when an else
+// Test if the sugared `if let` construct correctly prints "missing an else clause" when an else
// clause does not exist, instead of the unsympathetic "`match` arms have incompatible types"
fn main() {
+++ /dev/null
-// We need all these 9 issue-20616-N.rs files
-// because we can only catch one parsing error at a time
-
-type Type_1_<'a, T> = &'a T;
-
-
-//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
-
-
-//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
-
-
-type Type_3<T> = Box<T,,>;
-//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
-
-
-//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
-
-
-type Type_5_<'a> = Type_1_<'a, ()>;
-
-
-//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
-
-
-//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
-
-
-//type Type_7 = Box<(),,>; // error: expected type, found `,`
-
-
-//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
-
-
-//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
+++ /dev/null
-error: expected one of `>`, a const expression, lifetime, or type, found `,`
- --> $DIR/issue-20616-3.rs:13:24
- |
-LL | type Type_3<T> = Box<T,,>;
- | ^ expected one of `>`, a const expression, lifetime, or type
-
-error: aborting due to previous error
-
+++ /dev/null
-// check-pass
-#![allow(dead_code)]
-// Regression test for #21726: an issue arose around the rules for
-// subtyping of projection types that resulted in an unconstrained
-// region, yielding region inference failures.
-
-// pretty-expanded FIXME #23616
-
-fn main() { }
-
-fn foo<'a>(s: &'a str) {
- let b: B<()> = B::new(s, ());
- b.get_short();
-}
-
-trait IntoRef<'a> {
- type T: Clone;
- fn into_ref(self, _: &'a str) -> Self::T;
-}
-
-impl<'a> IntoRef<'a> for () {
- type T = &'a str;
- fn into_ref(self, s: &'a str) -> &'a str {
- s
- }
-}
-
-struct B<'a, P: IntoRef<'a>>(P::T);
-
-impl<'a, P: IntoRef<'a>> B<'a, P> {
- fn new(s: &'a str, i: P) -> B<'a, P> {
- B(i.into_ref(s))
- }
-
- fn get_short(&self) -> P::T {
- self.0.clone()
- }
-}
+++ /dev/null
-trait Add<Rhs=Self> {
- type Output;
-}
-
-trait Sub<Rhs=Self> {
- type Output;
-}
-
-type Test = dyn Add + Sub;
-//~^ ERROR E0393
-//~| ERROR E0191
-//~| ERROR E0393
-//~| ERROR E0225
-
-fn main() { }
+++ /dev/null
-error[E0393]: the type parameter `Rhs` must be explicitly specified
- --> $DIR/issue-22560.rs:9:23
- |
-LL | / trait Sub<Rhs=Self> {
-LL | | type Output;
-LL | | }
- | |_- type parameter `Rhs` must be specified for this
-LL |
-LL | type Test = dyn Add + Sub;
- | ^^^ help: set the type parameter to the desired type: `Sub<Rhs>`
- |
- = note: because of the default `Self` reference, type parameters must be specified on object types
-
-error[E0393]: the type parameter `Rhs` must be explicitly specified
- --> $DIR/issue-22560.rs:9:17
- |
-LL | / trait Add<Rhs=Self> {
-LL | | type Output;
-LL | | }
- | |_- type parameter `Rhs` must be specified for this
-...
-LL | type Test = dyn Add + Sub;
- | ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
- |
- = note: because of the default `Self` reference, type parameters must be specified on object types
-
-error[E0225]: only auto traits can be used as additional traits in a trait object
- --> $DIR/issue-22560.rs:9:23
- |
-LL | type Test = dyn Add + Sub;
- | --- ^^^ additional non-auto trait
- | |
- | first non-auto trait
- |
- = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}`
- = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
-
-error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified
- --> $DIR/issue-22560.rs:9:17
- |
-LL | type Output;
- | ------------ `Output` defined here
-...
-LL | type Output;
- | ------------ `Output` defined here
-...
-LL | type Test = dyn Add + Sub;
- | ^^^ ^^^ associated type `Output` must be specified
- | |
- | associated type `Output` must be specified
- |
-help: specify the associated types
- |
-LL | type Test = dyn Add<Output = Type> + Sub<Output = Type>;
- | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0191, E0225, E0393.
-For more information about an error, try `rustc --explain E0191`.
+++ /dev/null
-#![feature(associated_type_defaults)]
-
-pub struct C<AType: A> {a:AType}
-
-pub trait A {
- type B = C<Self::anything_here_kills_it>;
- //~^ ERROR: associated type `anything_here_kills_it` not found for `Self`
-}
-
-fn main() {}
+++ /dev/null
-error[E0220]: associated type `anything_here_kills_it` not found for `Self`
- --> $DIR/issue-23595-2.rs:6:22
- |
-LL | type B = C<Self::anything_here_kills_it>;
- | ^^^^^^^^^^^^^^^^^^^^^^ associated type `anything_here_kills_it` not found
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0220`.
+++ /dev/null
-// check-pass
-
-#![allow(dead_code)]
-
-trait MultiDispatch<T> {
- type O;
-}
-
-trait Trait: Sized {
- type A: MultiDispatch<Self::B, O = Self>;
- type B;
-
- fn new<U>(u: U) -> <Self::A as MultiDispatch<U>>::O
- where
- Self::A: MultiDispatch<U>;
-}
-
-fn test<T: Trait<B = i32>>(b: i32) -> T
-where
- T::A: MultiDispatch<i32>,
-{
- T::new(b)
-}
-
-fn main() {}
+++ /dev/null
-// check-pass
-
-#![deny(non_snake_case)]
-
-#[no_mangle]
-pub extern "C" fn SparklingGenerationForeignFunctionInterface() {} // OK
-
-fn main() {}
+++ /dev/null
-static S : u64 = { { panic!("foo"); 0 } };
-//~^ ERROR panicking in statics is unstable
-
-fn main() {
- println!("{:?}", S);
-}
+++ /dev/null
-error[E0658]: panicking in statics is unstable
- --> $DIR/issue-32829.rs:1:22
- |
-LL | static S : u64 = { { panic!("foo"); 0 } };
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #51999 <https://github.com/rust-lang/rust/issues/51999> for more information
- = help: add `#![feature(const_panic)]` to the crate attributes to enable
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// run-pass
-
-const fn foo() -> *const i8 {
- b"foo" as *const _ as *const i8
-}
-
-const fn bar() -> i32 {
- *&{(1, 2, 3).1}
-}
-
-fn main() {
- assert_eq!(foo(), b"foo" as *const _ as *const i8);
- assert_eq!(bar(), 2);
-}
+++ /dev/null
-// run-pass
-macro_rules! gen {
- ($name:ident ( $($dol:tt $var:ident)* ) $($body:tt)*) => {
- macro_rules! $name {
- ($($dol $var:ident)*) => {
- $($body)*
- }
- }
- }
-}
-
-gen!(m($var) $var);
-
-fn main() {
- let x = 1;
- assert_eq!(m!(x), 1);
-}
+++ /dev/null
-fn main() {
- let a = if true {
- 0
- } else if false {
-//~^ ERROR `if` may be missing an `else` clause
-//~| expected `()`, found integer
- 1
- };
-}
+++ /dev/null
-error[E0317]: `if` may be missing an `else` clause
- --> $DIR/issue-4201.rs:4:12
- |
-LL | } else if false {
- | ____________^
-LL | |
-LL | |
-LL | | 1
- | | - found here
-LL | | };
- | |_____^ expected `()`, found integer
- |
- = note: `if` expressions without `else` evaluate to `()`
- = help: consider adding an `else` block that evaluates to the expected type
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0317`.
+++ /dev/null
-pub trait Partial<X: ?Sized>: Copy {
-}
-
-pub trait Complete {
- type Assoc: Partial<Self>;
-}
-
-impl<T> Partial<T> for T::Assoc where
- T: Complete
-{
-}
-
-impl<T> Complete for T {
- type Assoc = T; //~ ERROR the trait bound `T: Copy` is not satisfied
-}
-
-fn main() {}
+++ /dev/null
-error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/issue-43784-associated-type.rs:14:5
- |
-LL | type Assoc: Partial<Self>;
- | ------------- required by this bound in `Complete::Assoc`
-...
-LL | type Assoc = T;
- | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
- |
-help: consider restricting type parameter `T`
- |
-LL | impl<T: Copy> Complete for T {
- | ^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-macro_rules! foo {
- ($rest: tt) => {
- bar(baz: $rest)
- }
-}
-
-fn main() {
- foo!(true); //~ ERROR expected type, found keyword
- //~^ ERROR expected identifier, found keyword
-}
+++ /dev/null
-error: expected identifier, found keyword `true`
- --> $DIR/issue-44406.rs:8:10
- |
-LL | foo!(true);
- | ^^^^ expected identifier, found keyword
- |
-help: you can escape reserved keywords to use them as identifiers
- |
-LL | foo!(r#true);
- | ^^^^^^
-
-error: expected type, found keyword `true`
- --> $DIR/issue-44406.rs:8:10
- |
-LL | bar(baz: $rest)
- | - help: try using a semicolon: `;`
-...
-LL | foo!(true);
- | ^^^^ expected type
- |
- = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
- = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
-
-error: aborting due to 2 previous errors
-
error[E0601]: `main` function not found in crate `issue_49040`
--> $DIR/issue-49040.rs:1:1
|
-LL | / #![allow(unused_variables)];
-LL | |
-LL | | fn foo() {}
- | |__^ consider adding a `main` function to `$DIR/issue-49040.rs`
+LL | #![allow(unused_variables)];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/issue-49040.rs`
error: aborting due to 2 previous errors
error: implementation of `Foo` is not general enough
--> $DIR/issue-54302-cases.rs:63:5
|
-LL | / trait Foo<'x, T> {
-LL | | fn foo(self) -> &'x T;
-LL | | }
- | |_- trait `Foo` defined here
-...
-LL | <u32 as RefFoo<u32>>::ref_foo(a)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL | <u32 as RefFoo<u32>>::ref_foo(a)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
= note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
= note: ...but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: implementation of `Foo` is not general enough
--> $DIR/issue-54302-cases.rs:69:5
|
-LL | / trait Foo<'x, T> {
-LL | | fn foo(self) -> &'x T;
-LL | | }
- | |_- trait `Foo` defined here
-...
-LL | <i32 as RefFoo<i32>>::ref_foo(a)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL | <i32 as RefFoo<i32>>::ref_foo(a)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
= note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`...
= note: ...but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1`
error: implementation of `Foo` is not general enough
--> $DIR/issue-54302-cases.rs:75:5
|
-LL | / trait Foo<'x, T> {
-LL | | fn foo(self) -> &'x T;
-LL | | }
- | |_- trait `Foo` defined here
-...
-LL | <u64 as RefFoo<u64>>::ref_foo(a)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL | <u64 as RefFoo<u64>>::ref_foo(a)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
= note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`...
= note: ...but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1`
error: implementation of `Foo` is not general enough
--> $DIR/issue-54302-cases.rs:81:5
|
-LL | / trait Foo<'x, T> {
-LL | | fn foo(self) -> &'x T;
-LL | | }
- | |_- trait `Foo` defined here
-...
-LL | <i64 as RefFoo<i64>>::ref_foo(a)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL | <i64 as RefFoo<i64>>::ref_foo(a)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
= note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`...
= note: ...but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1`
error: implementation of `Deserialize` is not general enough
--> $DIR/issue-54302.rs:13:5
|
-LL | trait Deserialize<'de> {}
- | ------------------------- trait `Deserialize` defined here
-...
LL | assert_deserialize_owned::<&'static str>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
|
error: implementation of `DistributedIteratorMulti` is not general enough
--> $DIR/issue-55731.rs:48:5
|
-LL | / trait DistributedIteratorMulti<Source> {
-LL | | type Item;
-LL | | }
- | |_- trait `DistributedIteratorMulti` defined here
-...
-LL | multi(Map {
- | ^^^^^ implementation of `DistributedIteratorMulti` is not general enough
+LL | multi(Map {
+ | ^^^^^ implementation of `DistributedIteratorMulti` is not general enough
|
= note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`...
= note: ...but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1`
error: higher-ranked subtype error
- --> $DIR/issue-57843.rs:23:9
+ --> $DIR/issue-57843.rs:25:9
|
LL | Foo(Box::new(|_| ()));
| ^^^^^^^^^^^^^^^^
}
impl<T, F: 'static> ClonableFn<T> for F
-where F: Fn(T) + Clone {
+where
+ F: Fn(T) + Clone,
+{
fn clone(&self) -> Box<dyn Fn(T)> {
Box::new(self.clone())
}
struct Foo(Box<dyn for<'a> ClonableFn<&'a bool>>);
fn main() {
- Foo(Box::new(|_| ())); //~ ERROR mismatched types
+ Foo(Box::new(|_| ())); //~ ERROR implementation of `FnOnce` is not general enough
}
-error[E0308]: mismatched types
- --> $DIR/issue-57843.rs:23:9
+error: implementation of `FnOnce` is not general enough
+ --> $DIR/issue-57843.rs:25:9
|
LL | Foo(Box::new(|_| ()));
- | ^^^^^^^^^^^^^^^^ one type is more general than the other
+ | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
- = note: expected type `FnOnce<(&'a bool,)>`
- found type `FnOnce<(&bool,)>`
-note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57843.rs:23:18
- |
-LL | Foo(Box::new(|_| ()));
- | ^^^^^^
+ = note: closure with signature `fn(&'2 bool)` must implement `FnOnce<(&'1 bool,)>`, for any lifetime `'1`...
+ = note: ...but it actually implements `FnOnce<(&'2 bool,)>`, for some specific lifetime `'2`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// run-pass
-// pretty-expanded FIXME #23616
-
-pub trait OpInt { fn call(&mut self, _: isize, _: isize) -> isize; }
-
-impl<F> OpInt for F where F: FnMut(isize, isize) -> isize {
- fn call(&mut self, a:isize, b:isize) -> isize {
- (*self)(a, b)
- }
-}
-
-fn squarei<'a>(x: isize, op: &'a mut dyn OpInt) -> isize { op.call(x, x) }
-
-fn muli(x:isize, y:isize) -> isize { x * y }
-
-pub fn main() {
- let mut f = |x, y| muli(x, y);
- {
- let g = &mut f;
- let h = g as &mut dyn OpInt;
- squarei(3, h);
- }
-}
+++ /dev/null
-// edition:2018
-
-async fn test() -> Result<(), Box<dyn std::error::Error>> {
- macro!();
- //~^ ERROR expected identifier, found `!`
- Ok(())
-}
-
-fn main() {}
+++ /dev/null
-error: expected identifier, found `!`
- --> $DIR/issue-77993-2.rs:4:10
- |
-LL | macro!();
- | ^ expected identifier
-
-error: aborting due to previous error
-
fn main() {
let f = |_| ();
- thing(f); //~ERROR mismatched types
+ thing(f); //~ERROR implementation of `FnOnce` is not general enough
}
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
--> $DIR/issue-79187.rs:5:5
|
LL | thing(f);
- | ^^^^^ lifetime mismatch
+ | ^^^^^ implementation of `FnOnce` is not general enough
|
- = note: expected type `FnOnce<(&u32,)>`
- found type `FnOnce<(&u32,)>`
-note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-79187.rs:4:13
- |
-LL | let f = |_| ();
- | ^^^^^^
-note: the lifetime requirement is introduced here
- --> $DIR/issue-79187.rs:1:18
- |
-LL | fn thing(x: impl FnOnce(&u32)) {}
- | ^^^^^^^^^^^^
+ = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`...
+ = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-pass
+
+#![deny(non_snake_case)]
+
+#[no_mangle]
+pub extern "C" fn SparklingGenerationForeignFunctionInterface() {} // OK
+
+fn main() {}
--- /dev/null
+// run-pass
+
+#![allow(non_camel_case_types)]
+// A test of the macro system. Can we do HTML literals?
+
+/*
+
+This is an HTML parser written as a macro. It's all CPS, and we have
+to carry around a bunch of state. The arguments to macros all look like this:
+
+{ tag_stack* # expr* # tokens }
+
+The stack keeps track of where we are in the tree. The expr is a list
+of children of the current node. The tokens are everything that's
+left.
+
+*/
+use HTMLFragment::{tag, text};
+
+macro_rules! html {
+ ( $($body:tt)* ) => (
+ parse_node!( []; []; $($body)* )
+ )
+}
+
+macro_rules! parse_node {
+ (
+ [:$head:ident ($(:$head_nodes:expr),*)
+ $(:$tags:ident ($(:$tag_nodes:expr),*))*];
+ [$(:$nodes:expr),*];
+ </$tag:ident> $($rest:tt)*
+ ) => (
+ parse_node!(
+ [$(: $tags ($(:$tag_nodes),*))*];
+ [$(:$head_nodes,)* :tag(stringify!($head).to_string(),
+ vec![$($nodes),*])];
+ $($rest)*
+ )
+ );
+
+ (
+ [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
+ [$(:$nodes:expr),*];
+ <$tag:ident> $($rest:tt)*
+ ) => (
+ parse_node!(
+ [:$tag ($(:$nodes)*) $(: $tags ($(:$tag_nodes),*) )*];
+ [];
+ $($rest)*
+ )
+ );
+
+ (
+ [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
+ [$(:$nodes:expr),*];
+ . $($rest:tt)*
+ ) => (
+ parse_node!(
+ [$(: $tags ($(:$tag_nodes),*))*];
+ [$(:$nodes,)* :text(".".to_string())];
+ $($rest)*
+ )
+ );
+
+ (
+ [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
+ [$(:$nodes:expr),*];
+ $word:ident $($rest:tt)*
+ ) => (
+ parse_node!(
+ [$(: $tags ($(:$tag_nodes),*))*];
+ [$(:$nodes,)* :text(stringify!($word).to_string())];
+ $($rest)*
+ )
+ );
+
+ ( []; [:$e:expr]; ) => ( $e );
+}
+
+pub fn main() {
+ let _page = html! (
+ <html>
+ <head><title>This is the title.</title></head>
+ <body>
+ <p>This is some text</p>
+ </body>
+ </html>
+ );
+}
+
+enum HTMLFragment {
+ tag(String, Vec<HTMLFragment> ),
+ text(String),
+}
fn baz<F: Fn(*mut &u32)>(_: F) {}
fn _test<'a>(f: fn(*mut &'a u32)) {
baz(f);
- //~^ ERROR mismatched types
- //~| ERROR mismatched types
+ //~^ ERROR implementation of `FnOnce` is not general enough
+ //~| ERROR implementation of `FnOnce` is not general enough
//~| ERROR mismatched types
//~| ERROR mismatched types
}
LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
| ^^^^^^^^^^^^^
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
--> $DIR/closure-arg-type-mismatch.rs:10:5
|
LL | baz(f);
- | ^^^ lifetime mismatch
- |
- = note: expected type `FnOnce<(*mut &u32,)>`
- found type `FnOnce<(*mut &'a u32,)>`
-note: the required lifetime does not necessarily outlive the lifetime `'a` as defined on the function body at 9:10
- --> $DIR/closure-arg-type-mismatch.rs:9:10
- |
-LL | fn _test<'a>(f: fn(*mut &'a u32)) {
- | ^^
-note: the lifetime requirement is introduced here
- --> $DIR/closure-arg-type-mismatch.rs:8:11
+ | ^^^ implementation of `FnOnce` is not general enough
|
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
- | ^^^^^^^^^^^^^
+ = note: `fn(*mut &'a u32)` must implement `FnOnce<(*mut &'0 u32,)>`, for any lifetime `'0`...
+ = note: ...but it actually implements `FnOnce<(*mut &'a u32,)>`
error[E0308]: mismatched types
--> $DIR/closure-arg-type-mismatch.rs:10:5
LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
| ^^^^^^^^^^^^^
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
--> $DIR/closure-arg-type-mismatch.rs:10:5
|
LL | baz(f);
- | ^^^ lifetime mismatch
- |
- = note: expected type `FnOnce<(*mut &u32,)>`
- found type `FnOnce<(*mut &'a u32,)>`
-note: the lifetime `'a` as defined on the function body at 9:10 doesn't meet the lifetime requirements
- --> $DIR/closure-arg-type-mismatch.rs:9:10
- |
-LL | fn _test<'a>(f: fn(*mut &'a u32)) {
- | ^^
-note: the lifetime requirement is introduced here
- --> $DIR/closure-arg-type-mismatch.rs:8:11
+ | ^^^ implementation of `FnOnce` is not general enough
|
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
- | ^^^^^^^^^^^^^
+ = note: `fn(*mut &'a u32)` must implement `FnOnce<(*mut &'0 u32,)>`, for any lifetime `'0`...
+ = note: ...but it actually implements `FnOnce<(*mut &'a u32,)>`
error: aborting due to 7 previous errors
+++ /dev/null
-fn main() {
- let a = 1_is; //~ ERROR invalid suffix
- let b = 2_us; //~ ERROR invalid suffix
-}
+++ /dev/null
-error: invalid suffix `is` for number literal
- --> $DIR/old-suffixes-are-really-forbidden.rs:2:13
- |
-LL | let a = 1_is;
- | ^^^^ invalid suffix `is`
- |
- = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
-
-error: invalid suffix `us` for number literal
- --> $DIR/old-suffixes-are-really-forbidden.rs:3:13
- |
-LL | let b = 2_us;
- | ^^^^ invalid suffix `us`
- |
- = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// run-pass
-// Why one-tuples? Because macros.
-
-
-pub fn main() {
- match ('c',) {
- (x,) => {
- assert_eq!(x, 'c');
- }
- }
- // test the 1-tuple type too
- let x: (char,) = ('d',);
- let (y,) = x;
- assert_eq!(y, 'd');
-}
= help: add `#![feature(or_patterns)]` to the crate attributes to enable
error[E0658]: or-patterns syntax is experimental
- --> $DIR/feature-gate-or_patterns.rs:28:11
+ --> $DIR/feature-gate-or_patterns.rs:28:9
|
LL | let | A | B;
- | ^^^^^
+ | ^^^^^^^
|
= note: see issue #54883 <https://github.com/rust-lang/rust/issues/54883> for more information
= help: add `#![feature(or_patterns)]` to the crate attributes to enable
= help: add `#![feature(or_patterns)]` to the crate attributes to enable
error[E0658]: or-patterns syntax is experimental
- --> $DIR/feature-gate-or_patterns.rs:30:11
+ --> $DIR/feature-gate-or_patterns.rs:30:9
|
LL | for | A | B in 0 {}
- | ^^^^^
+ | ^^^^^^^
|
= note: see issue #54883 <https://github.com/rust-lang/rust/issues/54883> for more information
= help: add `#![feature(or_patterns)]` to the crate attributes to enable
use E::*;
#[cfg(FALSE)]
-fn fun1((A | B): E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis
+fn fun1((A | B): E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses
use E::*;
#[cfg(FALSE)]
-fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis
+fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses
-error: an or-pattern parameter must be wrapped in parenthesis
+error: an or-pattern parameter must be wrapped in parentheses
--> $DIR/fn-param-wrap-parens.rs:14:9
|
LL | fn fun1(A | B: E) {}
- | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)`
+ | ^^^^^ help: wrap the pattern in parentheses: `(A | B)`
error: aborting due to previous error
let x = 3;
match x {
- 1 | 2 || 3 => (), //~ ERROR unexpected token `||` after pattern
+ 1 | 2 || 3 => (), //~ ERROR unexpected token `||` in pattern
_ => (),
}
match x {
- (1 | 2 || 3) => (), //~ ERROR unexpected token `||` after pattern
+ (1 | 2 || 3) => (), //~ ERROR unexpected token `||` in pattern
_ => (),
}
match (x,) {
- (1 | 2 || 3,) => (), //~ ERROR unexpected token `||` after pattern
+ (1 | 2 || 3,) => (), //~ ERROR unexpected token `||` in pattern
_ => (),
}
struct TS(u8);
match TS(x) {
- TS(1 | 2 || 3) => (), //~ ERROR unexpected token `||` after pattern
+ TS(1 | 2 || 3) => (), //~ ERROR unexpected token `||` in pattern
_ => (),
}
struct NS { f: u8 }
match (NS { f: x }) {
- NS { f: 1 | 2 || 3 } => (), //~ ERROR unexpected token `||` after pattern
+ NS { f: 1 | 2 || 3 } => (), //~ ERROR unexpected token `||` in pattern
_ => (),
}
match [x] {
- [1 | 2 || 3] => (), //~ ERROR unexpected token `||` after pattern
+ [1 | 2 || 3] => (), //~ ERROR unexpected token `||` in pattern
_ => (),
}
match x {
- || 1 | 2 | 3 => (), //~ ERROR unexpected token `||` after pattern
+ || 1 | 2 | 3 => (), //~ ERROR unexpected token `||` in pattern
_ => (),
}
}
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
--> $DIR/multiple-pattern-typo.rs:7:15
|
LL | 1 | 2 || 3 => (),
| |
| while parsing this or-pattern starting here
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
--> $DIR/multiple-pattern-typo.rs:12:16
|
LL | (1 | 2 || 3) => (),
| |
| while parsing this or-pattern starting here
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
--> $DIR/multiple-pattern-typo.rs:17:16
|
LL | (1 | 2 || 3,) => (),
| |
| while parsing this or-pattern starting here
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
--> $DIR/multiple-pattern-typo.rs:24:18
|
LL | TS(1 | 2 || 3) => (),
| |
| while parsing this or-pattern starting here
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
--> $DIR/multiple-pattern-typo.rs:31:23
|
LL | NS { f: 1 | 2 || 3 } => (),
| |
| while parsing this or-pattern starting here
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
--> $DIR/multiple-pattern-typo.rs:36:16
|
LL | [1 | 2 || 3] => (),
| |
| while parsing this or-pattern starting here
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
--> $DIR/multiple-pattern-typo.rs:41:9
|
LL | || 1 | 2 | 3 => (),
// -------- This looks like an or-pattern but is in fact `|A| (B: E | ())`.
// ...and for now neither do we allow or-patterns at the top level of functions.
- fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis
+ fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses
fn fun2(| A | B: E) {}
- //~^ ERROR a leading `|` is not allowed in a parameter pattern
- //~| ERROR an or-pattern parameter must be wrapped in parenthesis
-}
-
-// We also do not allow a leading `|` when not in a top level position:
-
-fn no_leading_inner() {
- struct TS(E);
- struct NS { f: E }
-
- let ( | A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let ( | A | B,) = (E::B,); //~ ERROR a leading `|` is only allowed in a top-level pattern
- let [ | A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let TS( | A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern
- let NS { f: | A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern
-
- let ( || A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let [ || A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let TS( || A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern
- let NS { f: || A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern
-
- let recovery_witness: String = 0; //~ ERROR mismatched types
+ //~^ ERROR an or-pattern parameter must be wrapped in parentheses
}
-error: an or-pattern parameter must be wrapped in parenthesis
+error: an or-pattern parameter must be wrapped in parentheses
--> $DIR/or-patterns-syntactic-fail.rs:17:13
|
LL | fn fun1(A | B: E) {}
- | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)`
+ | ^^^^^ help: wrap the pattern in parentheses: `(A | B)`
-error: a leading `|` is not allowed in a parameter pattern
+error: an or-pattern parameter must be wrapped in parentheses
--> $DIR/or-patterns-syntactic-fail.rs:19:13
|
LL | fn fun2(| A | B: E) {}
- | ^ help: remove the `|`
-
-error: an or-pattern parameter must be wrapped in parenthesis
- --> $DIR/or-patterns-syntactic-fail.rs:19:15
- |
-LL | fn fun2(| A | B: E) {}
- | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)`
-
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/or-patterns-syntactic-fail.rs:30:11
- |
-LL | let ( | A | B) = E::A;
- | ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/or-patterns-syntactic-fail.rs:31:11
- |
-LL | let ( | A | B,) = (E::B,);
- | ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/or-patterns-syntactic-fail.rs:32:11
- |
-LL | let [ | A | B ] = [E::A];
- | ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/or-patterns-syntactic-fail.rs:33:13
- |
-LL | let TS( | A | B );
- | ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/or-patterns-syntactic-fail.rs:34:17
- |
-LL | let NS { f: | A | B };
- | ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/or-patterns-syntactic-fail.rs:36:11
- |
-LL | let ( || A | B) = E::A;
- | ^^ help: remove the `||`
- |
- = note: alternatives in or-patterns are separated with `|`, not `||`
-
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/or-patterns-syntactic-fail.rs:37:11
- |
-LL | let [ || A | B ] = [E::A];
- | ^^ help: remove the `||`
- |
- = note: alternatives in or-patterns are separated with `|`, not `||`
-
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/or-patterns-syntactic-fail.rs:38:13
- |
-LL | let TS( || A | B );
- | ^^ help: remove the `||`
- |
- = note: alternatives in or-patterns are separated with `|`, not `||`
-
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/or-patterns-syntactic-fail.rs:39:17
- |
-LL | let NS { f: || A | B };
- | ^^ help: remove the `||`
- |
- = note: alternatives in or-patterns are separated with `|`, not `||`
+ | ^^^^^^^ help: wrap the pattern in parentheses: `(A | B)`
error[E0369]: no implementation for `E | ()`
--> $DIR/or-patterns-syntactic-fail.rs:13:22
|
= note: an implementation of `std::ops::BitOr` might be missing for `E`
-error[E0308]: mismatched types
- --> $DIR/or-patterns-syntactic-fail.rs:41:36
- |
-LL | let recovery_witness: String = 0;
- | ------ ^
- | | |
- | | expected struct `String`, found integer
- | | help: try using a conversion method: `0.to_string()`
- | expected due to this
-
-error: aborting due to 14 previous errors
+error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0308, E0369.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0369`.
#[cfg(FALSE)]
fn leading() {
- fn fun1( A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
- fn fun2( A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
- let ( A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let ( A): (E); //~ ERROR a leading `|` is only allowed in a top-level pattern
- let ( A,): (E,); //~ ERROR a leading `|` is only allowed in a top-level pattern
- let [ A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let [ A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let TS( A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let TS( A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let NS { f: A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let NS { f: A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
+ fn fun1( A: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses
+ fn fun2( A: E) {} //~ ERROR unexpected `||` before function parameter
+ let ( | A): E;
+ let ( | A): (E); //~ ERROR unexpected token `||` in pattern
+ let ( | A,): (E,);
+ let [ | A ]: [E; 1];
+ let [ | A ]: [E; 1]; //~ ERROR unexpected token `||` in pattern
+ let TS( | A ): TS;
+ let TS( | A ): TS; //~ ERROR unexpected token `||` in pattern
+ let NS { f: | A }: NS;
+ let NS { f: | A }: NS; //~ ERROR unexpected token `||` in pattern
}
#[cfg(FALSE)]
let ( A | B ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
let [ A | B ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern
let S { f: B }; //~ ERROR a trailing `|` is not allowed in an or-pattern
- let ( A | B ): E; //~ ERROR unexpected token `||` after pattern
+ let ( A | B ): E; //~ ERROR unexpected token `||` in pattern
//~^ ERROR a trailing `|` is not allowed in an or-pattern
match A {
A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
- A | B => {} //~ ERROR unexpected token `||` after pattern
+ A | B => {} //~ ERROR unexpected token `||` in pattern
//~^ ERROR a trailing `|` is not allowed in an or-pattern
| A | B => {}
//~^ ERROR a trailing `|` is not allowed in an or-pattern
#[cfg(FALSE)]
fn leading() {
- fn fun1( | A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
- fn fun2( || A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
- let ( | A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let ( || A): (E); //~ ERROR a leading `|` is only allowed in a top-level pattern
- let ( | A,): (E,); //~ ERROR a leading `|` is only allowed in a top-level pattern
- let [ | A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let [ || A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let TS( | A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let TS( || A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let NS { f: | A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
- let NS { f: || A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
+ fn fun1( | A: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses
+ fn fun2( || A: E) {} //~ ERROR unexpected `||` before function parameter
+ let ( | A): E;
+ let ( || A): (E); //~ ERROR unexpected token `||` in pattern
+ let ( | A,): (E,);
+ let [ | A ]: [E; 1];
+ let [ || A ]: [E; 1]; //~ ERROR unexpected token `||` in pattern
+ let TS( | A ): TS;
+ let TS( || A ): TS; //~ ERROR unexpected token `||` in pattern
+ let NS { f: | A }: NS;
+ let NS { f: || A }: NS; //~ ERROR unexpected token `||` in pattern
}
#[cfg(FALSE)]
let ( A | B | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
let [ A | B | ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern
let S { f: B | }; //~ ERROR a trailing `|` is not allowed in an or-pattern
- let ( A || B | ): E; //~ ERROR unexpected token `||` after pattern
+ let ( A || B | ): E; //~ ERROR unexpected token `||` in pattern
//~^ ERROR a trailing `|` is not allowed in an or-pattern
match A {
A | => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
A || => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
- A || B | => {} //~ ERROR unexpected token `||` after pattern
+ A || B | => {} //~ ERROR unexpected token `||` in pattern
//~^ ERROR a trailing `|` is not allowed in an or-pattern
| A | B | => {}
//~^ ERROR a trailing `|` is not allowed in an or-pattern
-error: a leading `|` is not allowed in a parameter pattern
+error: an or-pattern parameter must be wrapped in parentheses
--> $DIR/remove-leading-vert.rs:12:14
|
LL | fn fun1( | A: E) {}
- | ^ help: remove the `|`
+ | ^^^ help: remove the leading `|`: `A`
-error: a leading `|` is not allowed in a parameter pattern
+error: unexpected `||` before function parameter
--> $DIR/remove-leading-vert.rs:13:14
|
LL | fn fun2( || A: E) {}
|
= note: alternatives in or-patterns are separated with `|`, not `||`
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/remove-leading-vert.rs:14:11
- |
-LL | let ( | A): E;
- | ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
+error: unexpected token `||` in pattern
--> $DIR/remove-leading-vert.rs:15:11
|
LL | let ( || A): (E);
- | ^^ help: remove the `||`
- |
- = note: alternatives in or-patterns are separated with `|`, not `||`
-
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/remove-leading-vert.rs:16:11
- |
-LL | let ( | A,): (E,);
- | ^ help: remove the `|`
+ | ^^ help: use a single `|` to separate multiple alternative patterns: `|`
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/remove-leading-vert.rs:17:11
- |
-LL | let [ | A ]: [E; 1];
- | ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
+error: unexpected token `||` in pattern
--> $DIR/remove-leading-vert.rs:18:11
|
LL | let [ || A ]: [E; 1];
- | ^^ help: remove the `||`
- |
- = note: alternatives in or-patterns are separated with `|`, not `||`
-
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/remove-leading-vert.rs:19:13
- |
-LL | let TS( | A ): TS;
- | ^ help: remove the `|`
+ | ^^ help: use a single `|` to separate multiple alternative patterns: `|`
-error: a leading `|` is only allowed in a top-level pattern
+error: unexpected token `||` in pattern
--> $DIR/remove-leading-vert.rs:20:13
|
LL | let TS( || A ): TS;
- | ^^ help: remove the `||`
- |
- = note: alternatives in or-patterns are separated with `|`, not `||`
-
-error: a leading `|` is only allowed in a top-level pattern
- --> $DIR/remove-leading-vert.rs:21:17
- |
-LL | let NS { f: | A }: NS;
- | ^ help: remove the `|`
+ | ^^ help: use a single `|` to separate multiple alternative patterns: `|`
-error: a leading `|` is only allowed in a top-level pattern
+error: unexpected token `||` in pattern
--> $DIR/remove-leading-vert.rs:22:17
|
LL | let NS { f: || A }: NS;
- | ^^ help: remove the `||`
- |
- = note: alternatives in or-patterns are separated with `|`, not `||`
+ | ^^ help: use a single `|` to separate multiple alternative patterns: `|`
error: a trailing `|` is not allowed in an or-pattern
--> $DIR/remove-leading-vert.rs:27:13
| |
| while parsing this or-pattern starting here
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
--> $DIR/remove-leading-vert.rs:32:13
|
LL | let ( A || B | ): E;
|
= note: alternatives in or-patterns are separated with `|`, not `||`
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
--> $DIR/remove-leading-vert.rs:37:11
|
LL | A || B | => {}
--> $DIR/remove-leading-vert.rs:39:17
|
LL | | A | B | => {}
- | - ^ help: remove the `|`
- | |
- | while parsing this or-pattern starting here
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
error: a trailing `|` is not allowed in an or-pattern
--> $DIR/remove-leading-vert.rs:43:11
| |
| while parsing this or-pattern starting here
-error: aborting due to 26 previous errors
+error: aborting due to 21 previous errors
--- /dev/null
+fn main() {
+ let _redemptive = 1...21;
+ //~^ ERROR unexpected token
+}
--- /dev/null
+error: unexpected token: `...`
+ --> $DIR/dotdotdot-expr.rs:2:24
+ |
+LL | let _redemptive = 1...21;
+ | ^^^
+ |
+help: use `..` for an exclusive range
+ |
+LL | let _redemptive = 1..21;
+ | ^^
+help: or `..=` for an inclusive range
+ |
+LL | let _redemptive = 1..=21;
+ | ^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// We need all these 9 issue-20616-N.rs files
+// because we can only catch one parsing error at a time
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+type Type_3<T> = Box<T,,>;
+//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /dev/null
+error: expected one of `>`, a const expression, lifetime, or type, found `,`
+ --> $DIR/issue-20616-3.rs:13:24
+ |
+LL | type Type_3<T> = Box<T,,>;
+ | ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to previous error
+
--- /dev/null
+macro_rules! foo {
+ ($rest: tt) => {
+ bar(baz: $rest)
+ }
+}
+
+fn main() {
+ foo!(true); //~ ERROR expected type, found keyword
+ //~^ ERROR expected identifier, found keyword
+}
--- /dev/null
+error: expected identifier, found keyword `true`
+ --> $DIR/issue-44406.rs:8:10
+ |
+LL | foo!(true);
+ | ^^^^ expected identifier, found keyword
+ |
+help: you can escape reserved keywords to use them as identifiers
+ |
+LL | foo!(r#true);
+ | ^^^^^^
+
+error: expected type, found keyword `true`
+ --> $DIR/issue-44406.rs:8:10
+ |
+LL | bar(baz: $rest)
+ | - help: try using a semicolon: `;`
+...
+LL | foo!(true);
+ | ^^^^ expected type
+ |
+ = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+ = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+fn main() {
+ let a = 1_is; //~ ERROR invalid suffix
+ let b = 2_us; //~ ERROR invalid suffix
+}
--- /dev/null
+error: invalid suffix `is` for number literal
+ --> $DIR/old-suffixes-are-really-forbidden.rs:2:13
+ |
+LL | let a = 1_is;
+ | ^^^^ invalid suffix `is`
+ |
+ = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+error: invalid suffix `us` for number literal
+ --> $DIR/old-suffixes-are-really-forbidden.rs:3:13
+ |
+LL | let b = 2_us;
+ | ^^^^ invalid suffix `us`
+ |
+ = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+enum E {
+ V { field: bool },
+ I { field1: bool, field2: usize },
+ J { field: isize },
+ K { field: &'static str},
+}
+fn test_E(x: E) {
+ let field = true;
+ if x == E::V { field } {}
+ //~^ ERROR expected value, found struct variant `E::V`
+ //~| ERROR mismatched types
+ if x == E::I { field1: true, field2: 42 } {}
+ //~^ ERROR struct literals are not allowed here
+ if x == E::V { field: false } {}
+ //~^ ERROR struct literals are not allowed here
+ if x == E::J { field: -42 } {}
+ //~^ ERROR struct literals are not allowed here
+ if x == E::K { field: "" } {}
+ //~^ ERROR struct literals are not allowed here
+ let y: usize = ();
+ //~^ ERROR mismatched types
+}
+
+fn main() {}
--- /dev/null
+error: struct literals are not allowed here
+ --> $DIR/struct-literal-variant-in-if.rs:13:13
+ |
+LL | if x == E::I { field1: true, field2: 42 } {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: surround the struct literal with parentheses
+ |
+LL | if x == (E::I { field1: true, field2: 42 }) {}
+ | ^ ^
+
+error: struct literals are not allowed here
+ --> $DIR/struct-literal-variant-in-if.rs:15:13
+ |
+LL | if x == E::V { field: false } {}
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+help: surround the struct literal with parentheses
+ |
+LL | if x == (E::V { field: false }) {}
+ | ^ ^
+
+error: struct literals are not allowed here
+ --> $DIR/struct-literal-variant-in-if.rs:17:13
+ |
+LL | if x == E::J { field: -42 } {}
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: surround the struct literal with parentheses
+ |
+LL | if x == (E::J { field: -42 }) {}
+ | ^ ^
+
+error: struct literals are not allowed here
+ --> $DIR/struct-literal-variant-in-if.rs:19:13
+ |
+LL | if x == E::K { field: "" } {}
+ | ^^^^^^^^^^^^^^^^^^
+ |
+help: surround the struct literal with parentheses
+ |
+LL | if x == (E::K { field: "" }) {}
+ | ^ ^
+
+error[E0423]: expected value, found struct variant `E::V`
+ --> $DIR/struct-literal-variant-in-if.rs:10:13
+ |
+LL | if x == E::V { field } {}
+ | ^^^^ not a value
+ |
+help: surround the struct literal with parentheses
+ |
+LL | if x == (E::V { field }) {}
+ | ^ ^
+
+error[E0308]: mismatched types
+ --> $DIR/struct-literal-variant-in-if.rs:10:20
+ |
+LL | if x == E::V { field } {}
+ | ---------------^^^^^--- help: consider using a semicolon here
+ | | |
+ | | expected `()`, found `bool`
+ | expected this to be `()`
+
+error[E0308]: mismatched types
+ --> $DIR/struct-literal-variant-in-if.rs:21:20
+ |
+LL | let y: usize = ();
+ | ----- ^^ expected `usize`, found `()`
+ | |
+ | expected due to this
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0308, E0423.
+For more information about an error, try `rustc --explain E0308`.
| ^^ no implementation for `&T == T`
|
= help: the trait `PartialEq<T>` is not implemented for `&T`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+ |
+LL | fn foo<T: PartialEq>(a: &T, b: T) where &T: PartialEq<T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
+#![feature(if_let_guard)]
+#![allow(incomplete_features)]
+
#![deny(irrefutable_let_patterns)]
fn main() {
- if let _ = 5 {} //~ ERROR irrefutable if-let pattern
+ if let _ = 5 {} //~ ERROR irrefutable `if let` pattern
- while let _ = 5 { //~ ERROR irrefutable while-let pattern
+ while let _ = 5 { //~ ERROR irrefutable `while let` pattern
break;
}
+
+ match 5 {
+ _ if let _ = 2 => {} //~ ERROR irrefutable `if let` guard pattern
+ _ => {}
+ }
}
-error: irrefutable if-let pattern
- --> $DIR/deny-irrefutable-let-patterns.rs:4:5
+error: irrefutable `if let` pattern
+ --> $DIR/deny-irrefutable-let-patterns.rs:7:5
|
LL | if let _ = 5 {}
| ^^^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/deny-irrefutable-let-patterns.rs:1:9
+ --> $DIR/deny-irrefutable-let-patterns.rs:4:9
|
LL | #![deny(irrefutable_let_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
-error: irrefutable while-let pattern
- --> $DIR/deny-irrefutable-let-patterns.rs:6:5
+error: irrefutable `while let` pattern
+ --> $DIR/deny-irrefutable-let-patterns.rs:9:5
|
LL | / while let _ = 5 {
LL | | break;
LL | | }
| |_____^
+ |
+ = note: this pattern will always match, so the loop will never exit
+ = help: consider instead using a `loop { ... }` with a `let` inside it
+
+error: irrefutable `if let` guard pattern
+ --> $DIR/deny-irrefutable-let-patterns.rs:14:18
+ |
+LL | _ if let _ = 2 => {}
+ | ^
+ |
+ = note: this pattern will always match, so the guard is useless
+ = help: consider removing the guard and adding a `let` inside the match arm
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
+++ /dev/null
-// run-pass
-
-#![allow(dead_code)]
-#![allow(unused_variables)]
-#![allow(unreachable_code)]
-// A regression test extracted from image-0.3.11. The point of
-// failure was in `index_colors` below.
-
-use std::ops::{Deref, DerefMut};
-
-#[derive(Copy, Clone)]
-pub struct Luma<T: Primitive> { pub data: [T; 1] }
-
-impl<T: Primitive + 'static> Pixel for Luma<T> {
- type Subpixel = T;
-}
-
-pub struct ImageBuffer<P: Pixel, Container> {
- pixels: P,
- c: Container,
-}
-
-pub trait GenericImage: Sized {
- type Pixel: Pixel;
-}
-
-pub trait Pixel: Copy + Clone {
- type Subpixel: Primitive;
-}
-
-pub trait Primitive: Copy + PartialOrd<Self> + Clone {
-}
-
-impl<P, Container> GenericImage for ImageBuffer<P, Container>
-where P: Pixel + 'static,
- Container: Deref<Target=[P::Subpixel]> + DerefMut,
- P::Subpixel: 'static {
-
- type Pixel = P;
-}
-
-impl Primitive for u8 { }
-
-impl<P, Container> ImageBuffer<P, Container>
-where P: Pixel + 'static,
- P::Subpixel: 'static,
- Container: Deref<Target=[P::Subpixel]>
-{
- pub fn pixels<'a>(&'a self) -> Pixels<'a, Self> {
- loop { }
- }
-
- pub fn pixels_mut(&mut self) -> PixelsMut<P> {
- loop { }
- }
-}
-
-pub struct Pixels<'a, I: 'a> {
- image: &'a I,
- x: u32,
- y: u32,
- width: u32,
- height: u32
-}
-
-impl<'a, I: GenericImage> Iterator for Pixels<'a, I> {
- type Item = (u32, u32, I::Pixel);
-
- fn next(&mut self) -> Option<(u32, u32, I::Pixel)> {
- loop { }
- }
-}
-
-pub struct PixelsMut<'a, P: Pixel + 'a> where P::Subpixel: 'a {
- chunks: &'a mut P::Subpixel
-}
-
-impl<'a, P: Pixel + 'a> Iterator for PixelsMut<'a, P> where P::Subpixel: 'a {
- type Item = &'a mut P;
-
- fn next(&mut self) -> Option<&'a mut P> {
- loop { }
- }
-}
-
-pub fn index_colors<Pix>(image: &ImageBuffer<Pix, Vec<u8>>)
- -> ImageBuffer<Luma<u8>, Vec<u8>>
-where Pix: Pixel<Subpixel=u8> + 'static,
-{
- // When NLL-enabled, `let mut` below is deemed unnecessary (due to
- // the remaining code being unreachable); so ignore that lint.
- #![allow(unused_mut)]
-
- let mut indices: ImageBuffer<_,Vec<_>> = loop { };
- for (pixel, idx) in image.pixels().zip(indices.pixels_mut()) {
- // failured occurred here ^^ because we were requiring that we
- // could project Pixel or Subpixel from `T_indices` (type of
- // `indices`), but the type is insufficiently constrained
- // until we reach the return below.
- }
- indices
-}
-
-fn main() { }
+++ /dev/null
-// run-pass
-
-#![allow(unused_comparisons)]
-// Test that you only need the syntax gate if you don't mention the structs.
-// (Obsoleted since both features are stabilized)
-
-fn main() {
- let mut count = 0;
- for i in 0_usize..=10 {
- assert!(i >= 0 && i <= 10);
- count += i;
- }
- assert_eq!(count, 55);
-}
+++ /dev/null
-error: higher-ranked subtype error
- --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:5
- |
-LL | want_G(baz);
- | ^^^^^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// In this fn, the type `F` is a function that takes a reference to a
-// struct and returns another reference with the same lifetime.
-//
-// Meanwhile, the bare fn `foo` takes a reference to a struct with
-// *ANY* lifetime and returns a reference with the 'static lifetime.
-// This can safely be considered to be an instance of `F` because all
-// lifetimes are sublifetimes of 'static.
-
-#![allow(dead_code)]
-#![allow(unused_variables)]
-
-struct S;
-
-// Given 'cx, return 'cx
-type F = for<'cx> fn(&'cx S) -> &'cx S;
-fn want_F(f: F) {}
-
-// Given anything, return 'static
-type G = for<'cx> fn(&'cx S) -> &'static S;
-fn want_G(f: G) {}
-
-// Should meet both.
-fn foo(x: &S) -> &'static S {
- panic!()
-}
-
-// Should meet both.
-fn bar<'a, 'b>(x: &'a S) -> &'b S {
- panic!()
-}
-
-// Meets F, but not G.
-fn baz(x: &S) -> &S {
- panic!()
-}
-
-fn supply_F() {
- want_F(foo);
-
- want_F(bar);
-
- want_F(baz);
-}
-
-fn supply_G() {
- want_G(foo);
- want_G(bar);
- want_G(baz); //~ ERROR mismatched types
-}
-
-pub fn main() {}
+++ /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: higher-ranked subtype error
+ --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:5
+ |
+LL | want_G(baz);
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// In this fn, the type `F` is a function that takes a reference to a
+// struct and returns another reference with the same lifetime.
+//
+// Meanwhile, the bare fn `foo` takes a reference to a struct with
+// *ANY* lifetime and returns a reference with the 'static lifetime.
+// This can safely be considered to be an instance of `F` because all
+// lifetimes are sublifetimes of 'static.
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct S;
+
+// Given 'cx, return 'cx
+type F = for<'cx> fn(&'cx S) -> &'cx S;
+fn want_F(f: F) {}
+
+// Given anything, return 'static
+type G = for<'cx> fn(&'cx S) -> &'static S;
+fn want_G(f: G) {}
+
+// Should meet both.
+fn foo(x: &S) -> &'static S {
+ panic!()
+}
+
+// Should meet both.
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
+ panic!()
+}
+
+// Meets F, but not G.
+fn baz(x: &S) -> &S {
+ panic!()
+}
+
+fn supply_F() {
+ want_F(foo);
+
+ want_F(bar);
+
+ want_F(baz);
+}
+
+fn supply_G() {
+ want_G(foo);
+ want_G(bar);
+ want_G(baz); //~ ERROR mismatched types
+}
+
+pub fn main() {}
--- /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
-// check-pass
-// edition:2018
-// compile-flags: --crate-type=lib
-
-pub async fn test() {
- const C: usize = 4;
- foo(&mut [0u8; C]).await;
-}
-
-async fn foo(_: &mut [u8]) {}
--- /dev/null
+fn main() {
+ super(); //~ ERROR failed to resolve: there are too many leading `super` keywords
+}
--- /dev/null
+error[E0433]: failed to resolve: there are too many leading `super` keywords
+ --> $DIR/issue-82156.rs:2:5
+ |
+LL | super();
+ | ^^^^^ there are too many leading `super` keywords
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
fn irrefutable_let_guard() {
match Some(()) {
Some(x) if let () = x => {}
- //~^ ERROR irrefutable if-let guard
+ //~^ ERROR irrefutable `if let` guard
_ => {}
}
}
-error: irrefutable if-let guard
+error: irrefutable `if let` guard pattern
--> $DIR/warns.rs:7:24
|
LL | Some(x) if let () = x => {}
|
LL | #[deny(irrefutable_let_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: this pattern will always match, so the guard is useless
+ = help: consider removing the guard and adding a `let` inside the match arm
error: unreachable pattern
--> $DIR/warns.rs:16:25
foo: &Foo { bools: &[false, true] },
bar: &Bar { bools: &[true, true] },
f: &id,
- //~^ ERROR mismatched types
+ //~^ ERROR implementation of `FnOnce` is not general enough
};
// very simple test for a 'static static with default lifetime
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
--> $DIR/rfc1623.rs:24:8
|
LL | f: &id,
- | ^^^ one type is more general than the other
+ | ^^^ implementation of `FnOnce` is not general enough
|
- = note: expected type `FnOnce<(&'a Foo<'b>,)>`
- found type `FnOnce<(&Foo<'_>,)>`
+ = 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: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+{"artifact":"$TEST_BUILD_DIR/rmeta/emit-artifact-notifications.nll/libemit_artifact_notifications.rmeta","emit":"metadata"}
--- /dev/null
+{"artifact":"$TEST_BUILD_DIR/rmeta/emit-artifact-notifications.polonius/libemit_artifact_notifications.rmeta","emit":"metadata"}
--- /dev/null
+// compile-flags:--emit=metadata --error-format=json --json artifacts
+// build-pass
+// ignore-pass
+// ^-- needed because `--pass check` does not emit the output needed.
+
+// A very basic test for the emission of artifact notifications in JSON output.
+
+fn main() {}
--- /dev/null
+{"artifact":"$TEST_BUILD_DIR/rmeta/emit-artifact-notifications/libemit_artifact_notifications.rmeta","emit":"metadata"}
--- /dev/null
+// compile-flags:--emit=metadata,obj
+// build-pass
+
+// A test for the emission of metadata + obj and other metadata + non-link
+// combinations. See issue #81117.
+
+fn main() {}
+++ /dev/null
-// run-pass
-
-use std::cell::Cell;
-
-const NONE_CELL_STRING: Option<Cell<String>> = None;
-
-struct Foo<T>(T);
-impl<T> Foo<T> {
- const FOO: Option<Box<T>> = None;
-}
-
-fn main() {
- let _: &'static u32 = &42;
- let _: &'static Option<u32> = &None;
-
- // We should be able to peek at consts and see they're None.
- let _: &'static Option<Cell<String>> = &NONE_CELL_STRING;
- let _: &'static Option<Box<()>> = &Foo::FOO;
-}
--- /dev/null
+fn x˂- //~ ERROR: unknown start of token
+ //~^ ERROR: expected one of `#`, `>`, `const`, identifier, or lifetime, found `-`
--- /dev/null
+error: unknown start of token: \u{2c2}
+ --> $DIR/issue-81800.rs:1:5
+ |
+LL | fn x˂-
+ | ^
+ |
+help: Unicode character '˂' (Modifier Letter Left Arrowhead) looks like '<' (Less-Than Sign), but it is not
+ |
+LL | fn x<-
+ | ^
+
+error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `-`
+ --> $DIR/issue-81800.rs:1:6
+ |
+LL | fn x˂-
+ | ^ expected one of `#`, `>`, `const`, identifier, or lifetime
+
+error: aborting due to 2 previous errors
+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B`
|
= help: the trait `PartialEq<B>` is not implemented for `&'static B`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+ |
+LL | impl<B: 'static, T> X<B> for T where &'static B: PartialEq<B> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error; 1 warning emitted
error: aborting due to 19 previous errors
-Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0546, E0547, E0550.
+Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0546, E0547, E0549, E0550.
For more information about an error, try `rustc --explain E0539`.
+++ /dev/null
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-enum E {
- V { field: bool },
- I { field1: bool, field2: usize },
- J { field: isize },
- K { field: &'static str},
-}
-fn test_E(x: E) {
- let field = true;
- if x == E::V { field } {}
- //~^ ERROR expected value, found struct variant `E::V`
- //~| ERROR mismatched types
- if x == E::I { field1: true, field2: 42 } {}
- //~^ ERROR struct literals are not allowed here
- if x == E::V { field: false } {}
- //~^ ERROR struct literals are not allowed here
- if x == E::J { field: -42 } {}
- //~^ ERROR struct literals are not allowed here
- if x == E::K { field: "" } {}
- //~^ ERROR struct literals are not allowed here
- let y: usize = ();
- //~^ ERROR mismatched types
-}
-
-fn main() {}
+++ /dev/null
-error: struct literals are not allowed here
- --> $DIR/struct-literal-variant-in-if.rs:13:13
- |
-LL | if x == E::I { field1: true, field2: 42 } {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: surround the struct literal with parentheses
- |
-LL | if x == (E::I { field1: true, field2: 42 }) {}
- | ^ ^
-
-error: struct literals are not allowed here
- --> $DIR/struct-literal-variant-in-if.rs:15:13
- |
-LL | if x == E::V { field: false } {}
- | ^^^^^^^^^^^^^^^^^^^^^
- |
-help: surround the struct literal with parentheses
- |
-LL | if x == (E::V { field: false }) {}
- | ^ ^
-
-error: struct literals are not allowed here
- --> $DIR/struct-literal-variant-in-if.rs:17:13
- |
-LL | if x == E::J { field: -42 } {}
- | ^^^^^^^^^^^^^^^^^^^
- |
-help: surround the struct literal with parentheses
- |
-LL | if x == (E::J { field: -42 }) {}
- | ^ ^
-
-error: struct literals are not allowed here
- --> $DIR/struct-literal-variant-in-if.rs:19:13
- |
-LL | if x == E::K { field: "" } {}
- | ^^^^^^^^^^^^^^^^^^
- |
-help: surround the struct literal with parentheses
- |
-LL | if x == (E::K { field: "" }) {}
- | ^ ^
-
-error[E0423]: expected value, found struct variant `E::V`
- --> $DIR/struct-literal-variant-in-if.rs:10:13
- |
-LL | if x == E::V { field } {}
- | ^^^^ not a value
- |
-help: surround the struct literal with parentheses
- |
-LL | if x == (E::V { field }) {}
- | ^ ^
-
-error[E0308]: mismatched types
- --> $DIR/struct-literal-variant-in-if.rs:10:20
- |
-LL | if x == E::V { field } {}
- | ---------------^^^^^--- help: consider using a semicolon here
- | | |
- | | expected `()`, found `bool`
- | expected this to be `()`
-
-error[E0308]: mismatched types
- --> $DIR/struct-literal-variant-in-if.rs:21:20
- |
-LL | let y: usize = ();
- | ----- ^^ expected `usize`, found `()`
- | |
- | expected due to this
-
-error: aborting due to 7 previous errors
-
-Some errors have detailed explanations: E0308, E0423.
-For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+// run-pass
+
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+#![feature(never_type)]
+
+use std::mem::size_of;
+use std::num::NonZeroU8;
+
+struct t {a: u8, b: i8}
+struct u {a: u8, b: i8, c: u8}
+struct v {a: u8, b: i8, c: v2, d: u32}
+struct v2 {u: char, v: u8}
+struct w {a: isize, b: ()}
+struct x {a: isize, b: (), c: ()}
+struct y {x: isize}
+
+enum e1 {
+ a(u8, u32), b(u32), c
+}
+enum e2 {
+ a(u32), b
+}
+
+#[repr(C, u8)]
+enum e3 {
+ a([u16; 0], u8), b
+}
+
+struct ReorderedStruct {
+ a: u8,
+ b: u16,
+ c: u8
+}
+
+enum ReorderedEnum {
+ A(u8, u16, u8),
+ B(u8, u16, u8),
+}
+
+enum ReorderedEnum2 {
+ A(u8, u32, u8),
+ B(u16, u8, u16, u8),
+
+ // 0x100 niche variants.
+ _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F,
+ _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F,
+ _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F,
+ _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F,
+ _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F,
+ _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F,
+ _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F,
+ _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F,
+ _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F,
+ _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F,
+ _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF,
+ _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF,
+ _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF,
+ _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF,
+ _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF,
+ _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF,
+}
+
+enum EnumEmpty {}
+
+enum EnumSingle1 {
+ A,
+}
+
+enum EnumSingle2 {
+ A = 42 as isize,
+}
+
+enum EnumSingle3 {
+ A,
+ B(!),
+}
+
+#[repr(u8)]
+enum EnumSingle4 {
+ A,
+}
+
+#[repr(u8)]
+enum EnumSingle5 {
+ A = 42 as u8,
+}
+
+enum EnumWithMaybeUninhabitedVariant<T> {
+ A(&'static ()),
+ B(&'static (), T),
+ C,
+}
+
+enum NicheFilledEnumWithAbsentVariant {
+ A(&'static ()),
+ B((), !),
+ C,
+}
+
+enum Option2<A, B> {
+ Some(A, B),
+ None
+}
+
+// Two layouts are considered for `CanBeNicheFilledButShouldnt`:
+// Niche-filling:
+// { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) }
+// Tagged:
+// { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) }
+// Both are the same size (due to padding),
+// but the tagged layout is better as the tag creates a niche with 254 invalid values,
+// allowing types like `Option<Option<CanBeNicheFilledButShouldnt>>` to fit into 8 bytes.
+pub enum CanBeNicheFilledButShouldnt {
+ A(NonZeroU8, u32),
+ B
+}
+pub enum AlwaysTaggedBecauseItHasNoNiche {
+ A(u8, u32),
+ B
+}
+
+pub fn main() {
+ assert_eq!(size_of::<u8>(), 1 as usize);
+ assert_eq!(size_of::<u32>(), 4 as usize);
+ assert_eq!(size_of::<char>(), 4 as usize);
+ assert_eq!(size_of::<i8>(), 1 as usize);
+ assert_eq!(size_of::<i32>(), 4 as usize);
+ assert_eq!(size_of::<t>(), 2 as usize);
+ assert_eq!(size_of::<u>(), 3 as usize);
+ // Alignment causes padding before the char and the u32.
+
+ assert_eq!(size_of::<v>(),
+ 16 as usize);
+ assert_eq!(size_of::<isize>(), size_of::<usize>());
+ assert_eq!(size_of::<w>(), size_of::<isize>());
+ assert_eq!(size_of::<x>(), size_of::<isize>());
+ assert_eq!(size_of::<isize>(), size_of::<y>());
+
+ // Make sure enum types are the appropriate size, mostly
+ // around ensuring alignment is handled properly
+
+ assert_eq!(size_of::<e1>(), 8 as usize);
+ assert_eq!(size_of::<e2>(), 8 as usize);
+ assert_eq!(size_of::<e3>(), 4 as usize);
+ assert_eq!(size_of::<ReorderedStruct>(), 4);
+ assert_eq!(size_of::<ReorderedEnum>(), 6);
+ assert_eq!(size_of::<ReorderedEnum2>(), 8);
+
+
+ assert_eq!(size_of::<EnumEmpty>(), 0);
+ assert_eq!(size_of::<EnumSingle1>(), 0);
+ assert_eq!(size_of::<EnumSingle2>(), 0);
+ assert_eq!(size_of::<EnumSingle3>(), 0);
+ assert_eq!(size_of::<EnumSingle4>(), 1);
+ assert_eq!(size_of::<EnumSingle5>(), 1);
+
+ assert_eq!(size_of::<EnumWithMaybeUninhabitedVariant<!>>(),
+ size_of::<EnumWithMaybeUninhabitedVariant<()>>());
+ assert_eq!(size_of::<NicheFilledEnumWithAbsentVariant>(), size_of::<&'static ()>());
+
+ assert_eq!(size_of::<Option<Option<(bool, &())>>>(), size_of::<(bool, &())>());
+ assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
+ assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
+ assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>());
+
+ assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8);
+ assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8);
+ assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8);
+ assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
+ assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
+ assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
+}
--- /dev/null
+// edition:2018
+
+pub struct Test {}
+
+impl Test {
+ pub async fn answer_str(&self, _s: &str) -> Test {
+ Test {}
+ }
+}
--- /dev/null
+// aux-build:issue-81839.rs
+// edition:2018
+
+extern crate issue_81839;
+
+async fn test(ans: &str, num: i32, cx: &issue_81839::Test) -> u32 {
+ match num {
+ 1 => {
+ cx.answer_str("hi");
+ }
+ _ => cx.answer_str("hi"), //~ `match` arms have incompatible types
+ }
+
+ 1
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: `match` arms have incompatible types
+ --> $DIR/issue-81839.rs:11:14
+ |
+LL | / match num {
+LL | | 1 => {
+LL | | cx.answer_str("hi");
+ | | --------------------
+ | | | |
+ | | | help: consider removing this semicolon
+ | | this is found to be of type `()`
+LL | | }
+LL | | _ => cx.answer_str("hi"),
+ | | ^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type
+LL | | }
+ | |_____- `match` arms have incompatible types
+ |
+ ::: $DIR/auxiliary/issue-81839.rs:6:49
+ |
+LL | pub async fn answer_str(&self, _s: &str) -> Test {
+ | ---- the `Output` of this `async fn`'s found opaque type
+ |
+ = note: expected type `()`
+ found opaque type `impl Future`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
|
LL | false => async_dummy().await,
| ^^^^^^
-help: consider removing this semicolon and boxing the expressions
- |
-LL | Box::new(async_dummy())
-LL |
-LL | }
-LL | false => Box::new(async_dummy()),
+help: consider removing this semicolon
|
+LL | async_dummy()
+ | --
error[E0308]: `match` arms have incompatible types
--> $DIR/match-prev-arm-needing-semi.rs:39:18
use std::io::{BufRead, BufReader, Read, Write};
-fn issue_81421<T: Read + Write>(mut stream: T) {
+fn issue_81421<T: Read + Write>(mut stream: T) { //~ HELP consider introducing a `where` bound
let initial_message = format!("Hello world");
let mut buffer: Vec<u8> = Vec::new();
let bytes_written = stream.write_all(initial_message.as_bytes());
|
LL | let mut stream_reader = BufReader::new(stream);
| --
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+ |
+LL | fn issue_81421<T: Read + Write>(mut stream: T) where &T: std::io::Read {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
help: consider changing this borrow's mutability
|
LL | let mut stream_reader = BufReader::new(&mut stream);
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `From<T>` is not implemented for `u64`
|
= note: required by `from`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+ |
+LL | fn check<T: Iterator, U: ?Sized>() where u64: From<T> {
+ | ^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `u64: From<<T as Iterator>::Item>` is not satisfied
--> $DIR/suggest-where-clause.rs:18:5
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<<T as Iterator>::Item>` is not implemented for `u64`
|
= note: required by `from`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+ |
+LL | fn check<T: Iterator, U: ?Sized>() where u64: From<<T as Iterator>::Item> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `Misc<_>: From<T>` is not satisfied
--> $DIR/suggest-where-clause.rs:23:5
--- /dev/null
+// run-pass
+// Why one-tuples? Because macros.
+
+
+pub fn main() {
+ match ('c',) {
+ (x,) => {
+ assert_eq!(x, 'c');
+ }
+ }
+ // test the 1-tuple type too
+ let x: (char,) = ('d',);
+ let (y,) = x;
+ assert_eq!(y, 'd');
+}
LL | |x| x
| ^^^^^
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
--> $DIR/issue-57611-trait-alias.rs:17:16
|
LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
- = note: expected type `FnOnce<(&X,)>`
- found type `FnOnce<(&'static X,)>`
-note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57611-trait-alias.rs:25:9
- |
-LL | |x| x
- | ^^^^^
+ = note: closure with signature `fn(&'static X) -> &'static X` must implement `FnOnce<(&'0 X,)>`, for any lifetime `'0`...
+ = note: ...but it actually implements `FnOnce<(&'static X,)>`
error: aborting due to 4 previous errors
impl Foo for X {
type Bar = impl Baz<Self, Self>;
- //~^ ERROR mismatched types
- //~| ERROR mismatched types
- //~| ERROR mismatched types
+ //~^ ERROR implementation of `FnOnce` is not general enough
+ //~| ERROR implementation of `FnOnce` is not general enough
+ //~| ERROR implementation of `FnOnce` is not general enough
//~| ERROR mismatched types
//~| ERROR mismatched types
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
--> $DIR/issue-57611-trait-alias.rs:17:16
|
LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
- |
- = note: expected type `FnOnce<(&X,)>`
- found type `FnOnce<(&X,)>`
-note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57611-trait-alias.rs:25:9
+ | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
-LL | |x| x
- | ^^^^^
+ = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
+ = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
error[E0308]: mismatched types
--> $DIR/issue-57611-trait-alias.rs:17:16
LL | |x| x
| ^^^^^
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
--> $DIR/issue-57611-trait-alias.rs:17:16
|
LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
- = note: expected type `FnOnce<(&X,)>`
- found type `FnOnce<(&'<empty> X,)>`
-note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57611-trait-alias.rs:25:9
- |
-LL | |x| x
- | ^^^^^
+ = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
+ = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
error[E0308]: mismatched types
--> $DIR/issue-57611-trait-alias.rs:17:16
LL | |x| x
| ^^^^^
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
--> $DIR/issue-57611-trait-alias.rs:17:16
|
LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
- = note: expected type `FnOnce<(&X,)>`
- found type `FnOnce<(&'<empty> X,)>`
-note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57611-trait-alias.rs:25:9
- |
-LL | |x| x
- | ^^^^^
+ = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
+ = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
error: aborting due to 5 previous errors
+++ /dev/null
-// run-pass
-// Test that type IDs correctly account for higher-rank lifetimes
-// Also acts as a regression test for an ICE (issue #19791)
-
-use std::any::{Any, TypeId};
-
-struct Struct<'a>(&'a ());
-trait Trait<'a> {}
-
-fn main() {
- // Bare fns
- {
- let a = TypeId::of::<fn(&'static isize, &'static isize)>();
- let b = TypeId::of::<for<'a> fn(&'static isize, &'a isize)>();
- let c = TypeId::of::<for<'a, 'b> fn(&'a isize, &'b isize)>();
- let d = TypeId::of::<for<'a, 'b> fn(&'b isize, &'a isize)>();
- assert!(a != b);
- assert!(a != c);
- assert!(a != d);
- assert!(b != c);
- assert!(b != d);
- assert_eq!(c, d);
-
- // Make sure De Bruijn indices are handled correctly
- let e = TypeId::of::<for<'a> fn(fn(&'a isize) -> &'a isize)>();
- let f = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a isize)>();
- assert!(e != f);
-
- // Make sure lifetime parameters of items are not ignored.
- let g = TypeId::of::<for<'a> fn(&'a dyn Trait<'a>) -> Struct<'a>>();
- let h = TypeId::of::<for<'a> fn(&'a dyn Trait<'a>) -> Struct<'static>>();
- let i = TypeId::of::<for<'a, 'b> fn(&'a dyn Trait<'b>) -> Struct<'b>>();
- assert!(g != h);
- assert!(g != i);
- assert!(h != i);
-
- // Make sure lifetime anonymization handles nesting correctly
- let j = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a usize)>();
- let k = TypeId::of::<fn(for<'b> fn(&'b isize) -> &'b usize)>();
- assert_eq!(j, k);
- }
- // Boxed unboxed closures
- {
- let a = TypeId::of::<Box<dyn Fn(&'static isize, &'static isize)>>();
- let b = TypeId::of::<Box<dyn for<'a> Fn(&'static isize, &'a isize)>>();
- let c = TypeId::of::<Box<dyn for<'a, 'b> Fn(&'a isize, &'b isize)>>();
- let d = TypeId::of::<Box<dyn for<'a, 'b> Fn(&'b isize, &'a isize)>>();
- assert!(a != b);
- assert!(a != c);
- assert!(a != d);
- assert!(b != c);
- assert!(b != d);
- assert_eq!(c, d);
-
- // Make sure De Bruijn indices are handled correctly
- let e = TypeId::of::<Box<dyn for<'a> Fn(Box<dyn Fn(&'a isize) -> &'a isize>)>>();
- let f = TypeId::of::<Box<dyn Fn(Box<dyn for<'a> Fn(&'a isize) -> &'a isize>)>>();
- assert!(e != f);
- }
- // Raw unboxed closures
- // Note that every unboxed closure has its own anonymous type,
- // so no two IDs should equal each other, even when compatible
- {
- let a = id(|_: &isize, _: &isize| {});
- let b = id(|_: &isize, _: &isize| {});
- assert!(a != b);
- }
-
- fn id<T:Any>(_: T) -> TypeId {
- TypeId::of::<T>()
- }
-}
+++ /dev/null
-// run-pass
-
-#![allow(non_camel_case_types)]
-#![allow(dead_code)]
-#![feature(never_type)]
-
-use std::mem::size_of;
-use std::num::NonZeroU8;
-
-struct t {a: u8, b: i8}
-struct u {a: u8, b: i8, c: u8}
-struct v {a: u8, b: i8, c: v2, d: u32}
-struct v2 {u: char, v: u8}
-struct w {a: isize, b: ()}
-struct x {a: isize, b: (), c: ()}
-struct y {x: isize}
-
-enum e1 {
- a(u8, u32), b(u32), c
-}
-enum e2 {
- a(u32), b
-}
-
-#[repr(C, u8)]
-enum e3 {
- a([u16; 0], u8), b
-}
-
-struct ReorderedStruct {
- a: u8,
- b: u16,
- c: u8
-}
-
-enum ReorderedEnum {
- A(u8, u16, u8),
- B(u8, u16, u8),
-}
-
-enum ReorderedEnum2 {
- A(u8, u32, u8),
- B(u16, u8, u16, u8),
-
- // 0x100 niche variants.
- _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F,
- _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F,
- _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F,
- _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F,
- _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F,
- _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F,
- _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F,
- _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F,
- _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F,
- _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F,
- _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF,
- _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF,
- _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF,
- _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF,
- _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF,
- _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF,
-}
-
-enum EnumEmpty {}
-
-enum EnumSingle1 {
- A,
-}
-
-enum EnumSingle2 {
- A = 42 as isize,
-}
-
-enum EnumSingle3 {
- A,
- B(!),
-}
-
-#[repr(u8)]
-enum EnumSingle4 {
- A,
-}
-
-#[repr(u8)]
-enum EnumSingle5 {
- A = 42 as u8,
-}
-
-enum EnumWithMaybeUninhabitedVariant<T> {
- A(&'static ()),
- B(&'static (), T),
- C,
-}
-
-enum NicheFilledEnumWithAbsentVariant {
- A(&'static ()),
- B((), !),
- C,
-}
-
-enum Option2<A, B> {
- Some(A, B),
- None
-}
-
-// Two layouts are considered for `CanBeNicheFilledButShouldnt`:
-// Niche-filling:
-// { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) }
-// Tagged:
-// { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) }
-// Both are the same size (due to padding),
-// but the tagged layout is better as the tag creates a niche with 254 invalid values,
-// allowing types like `Option<Option<CanBeNicheFilledButShouldnt>>` to fit into 8 bytes.
-pub enum CanBeNicheFilledButShouldnt {
- A(NonZeroU8, u32),
- B
-}
-pub enum AlwaysTaggedBecauseItHasNoNiche {
- A(u8, u32),
- B
-}
-
-pub fn main() {
- assert_eq!(size_of::<u8>(), 1 as usize);
- assert_eq!(size_of::<u32>(), 4 as usize);
- assert_eq!(size_of::<char>(), 4 as usize);
- assert_eq!(size_of::<i8>(), 1 as usize);
- assert_eq!(size_of::<i32>(), 4 as usize);
- assert_eq!(size_of::<t>(), 2 as usize);
- assert_eq!(size_of::<u>(), 3 as usize);
- // Alignment causes padding before the char and the u32.
-
- assert_eq!(size_of::<v>(),
- 16 as usize);
- assert_eq!(size_of::<isize>(), size_of::<usize>());
- assert_eq!(size_of::<w>(), size_of::<isize>());
- assert_eq!(size_of::<x>(), size_of::<isize>());
- assert_eq!(size_of::<isize>(), size_of::<y>());
-
- // Make sure enum types are the appropriate size, mostly
- // around ensuring alignment is handled properly
-
- assert_eq!(size_of::<e1>(), 8 as usize);
- assert_eq!(size_of::<e2>(), 8 as usize);
- assert_eq!(size_of::<e3>(), 4 as usize);
- assert_eq!(size_of::<ReorderedStruct>(), 4);
- assert_eq!(size_of::<ReorderedEnum>(), 6);
- assert_eq!(size_of::<ReorderedEnum2>(), 8);
-
-
- assert_eq!(size_of::<EnumEmpty>(), 0);
- assert_eq!(size_of::<EnumSingle1>(), 0);
- assert_eq!(size_of::<EnumSingle2>(), 0);
- assert_eq!(size_of::<EnumSingle3>(), 0);
- assert_eq!(size_of::<EnumSingle4>(), 1);
- assert_eq!(size_of::<EnumSingle5>(), 1);
-
- assert_eq!(size_of::<EnumWithMaybeUninhabitedVariant<!>>(),
- size_of::<EnumWithMaybeUninhabitedVariant<()>>());
- assert_eq!(size_of::<NicheFilledEnumWithAbsentVariant>(), size_of::<&'static ()>());
-
- assert_eq!(size_of::<Option<Option<(bool, &())>>>(), size_of::<(bool, &())>());
- assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
- assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
- assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>());
-
- assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8);
- assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8);
- assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8);
- assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
- assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
- assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
-}
error: higher-ranked subtype error
- --> $DIR/issue-30906.rs:15:5
+ --> $DIR/issue-30906.rs:18:5
|
LL | test(Compose(f, |_| {}));
| ^^^^^^^^^^^^^^^^^^^^^^^^
fn test<F: for<'x> FnOnce<(&'x str,)>>(_: F) {}
-struct Compose<F,G>(F,G);
-impl<T,F,G> FnOnce<(T,)> for Compose<F,G>
-where F: FnOnce<(T,)>, G: FnOnce<(F::Output,)> {
+struct Compose<F, G>(F, G);
+impl<T, F, G> FnOnce<(T,)> for Compose<F, G>
+where
+ F: FnOnce<(T,)>,
+ G: FnOnce<(F::Output,)>,
+{
type Output = G::Output;
extern "rust-call" fn call_once(self, (x,): (T,)) -> G::Output {
(self.1)((self.0)(x))
}
fn bad<T>(f: fn(&'static str) -> T) {
- test(Compose(f, |_| {})); //~ ERROR: mismatched types
+ test(Compose(f, |_| {}));
+ //~^ ERROR: implementation of `FnOnce` is not general enough
}
fn main() {}
-error[E0308]: mismatched types
- --> $DIR/issue-30906.rs:15:5
+error: implementation of `FnOnce` is not general enough
+ --> $DIR/issue-30906.rs:18:5
|
LL | test(Compose(f, |_| {}));
- | ^^^^ lifetime mismatch
+ | ^^^^ implementation of `FnOnce` is not general enough
|
- = note: expected type `FnOnce<(&'x str,)>`
- found type `FnOnce<(&str,)>`
-note: the lifetime requirement is introduced here
- --> $DIR/issue-30906.rs:3:12
- |
-LL | fn test<F: for<'x> FnOnce<(&'x str,)>>(_: F) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `fn(&'2 str) -> T` must implement `FnOnce<(&'1 str,)>`, for any lifetime `'1`...
+ = note: ...but it actually implements `FnOnce<(&'2 str,)>`, for some specific lifetime `'2`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-pass
+// Test that type IDs correctly account for higher-rank lifetimes
+// Also acts as a regression test for an ICE (issue #19791)
+
+use std::any::{Any, TypeId};
+
+struct Struct<'a>(&'a ());
+trait Trait<'a> {}
+
+fn main() {
+ // Bare fns
+ {
+ let a = TypeId::of::<fn(&'static isize, &'static isize)>();
+ let b = TypeId::of::<for<'a> fn(&'static isize, &'a isize)>();
+ let c = TypeId::of::<for<'a, 'b> fn(&'a isize, &'b isize)>();
+ let d = TypeId::of::<for<'a, 'b> fn(&'b isize, &'a isize)>();
+ assert!(a != b);
+ assert!(a != c);
+ assert!(a != d);
+ assert!(b != c);
+ assert!(b != d);
+ assert_eq!(c, d);
+
+ // Make sure De Bruijn indices are handled correctly
+ let e = TypeId::of::<for<'a> fn(fn(&'a isize) -> &'a isize)>();
+ let f = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a isize)>();
+ assert!(e != f);
+
+ // Make sure lifetime parameters of items are not ignored.
+ let g = TypeId::of::<for<'a> fn(&'a dyn Trait<'a>) -> Struct<'a>>();
+ let h = TypeId::of::<for<'a> fn(&'a dyn Trait<'a>) -> Struct<'static>>();
+ let i = TypeId::of::<for<'a, 'b> fn(&'a dyn Trait<'b>) -> Struct<'b>>();
+ assert!(g != h);
+ assert!(g != i);
+ assert!(h != i);
+
+ // Make sure lifetime anonymization handles nesting correctly
+ let j = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a usize)>();
+ let k = TypeId::of::<fn(for<'b> fn(&'b isize) -> &'b usize)>();
+ assert_eq!(j, k);
+ }
+ // Boxed unboxed closures
+ {
+ let a = TypeId::of::<Box<dyn Fn(&'static isize, &'static isize)>>();
+ let b = TypeId::of::<Box<dyn for<'a> Fn(&'static isize, &'a isize)>>();
+ let c = TypeId::of::<Box<dyn for<'a, 'b> Fn(&'a isize, &'b isize)>>();
+ let d = TypeId::of::<Box<dyn for<'a, 'b> Fn(&'b isize, &'a isize)>>();
+ assert!(a != b);
+ assert!(a != c);
+ assert!(a != d);
+ assert!(b != c);
+ assert!(b != d);
+ assert_eq!(c, d);
+
+ // Make sure De Bruijn indices are handled correctly
+ let e = TypeId::of::<Box<dyn for<'a> Fn(Box<dyn Fn(&'a isize) -> &'a isize>)>>();
+ let f = TypeId::of::<Box<dyn Fn(Box<dyn for<'a> Fn(&'a isize) -> &'a isize>)>>();
+ assert!(e != f);
+ }
+ // Raw unboxed closures
+ // Note that every unboxed closure has its own anonymous type,
+ // so no two IDs should equal each other, even when compatible
+ {
+ let a = id(|_: &isize, _: &isize| {});
+ let b = id(|_: &isize, _: &isize| {});
+ assert!(a != b);
+ }
+
+ fn id<T:Any>(_: T) -> TypeId {
+ TypeId::of::<T>()
+ }
+}
error: implementation of `Bar` is not general enough
--> $DIR/where-for-self-2.rs:23:5
|
-LL | / trait Bar {
-LL | | fn bar(&self);
-LL | | }
- | |_- trait `Bar` defined here
-...
-LL | foo(&X);
- | ^^^ implementation of `Bar` is not general enough
+LL | foo(&X);
+ | ^^^ implementation of `Bar` is not general enough
|
- = note: `Bar` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
- = note: ...but `Bar` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
+ = note: `&'0 u32` must implement `Bar`, for any lifetime `'0`...
+ = note: ...but `Bar` is actually implemented for the type `&'static u32`
error: aborting due to previous error
macro_rules! foo{
($p:pat, $e:expr, $b:block) => {{
while let $p = $e $b
- //~^ WARN irrefutable while-let
- //~| WARN irrefutable while-let
+ //~^ WARN irrefutable `while let`
+ //~| WARN irrefutable `while let`
}}
}
macro_rules! bar{
}
pub fn main() {
- while let _a = 1 { //~ WARN irrefutable while-let
+ while let _a = 1 { //~ WARN irrefutable `while let`
println!("irrefutable pattern");
break;
}
-warning: irrefutable while-let pattern
+warning: irrefutable `while let` pattern
--> $DIR/while-let.rs:7:13
|
LL | while let $p = $e $b
| |_______- in this macro invocation
|
= note: `#[warn(irrefutable_let_patterns)]` on by default
+ = note: this pattern will always match, so the loop will never exit
+ = help: consider instead using a `loop { ... }` with a `let` inside it
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: irrefutable while-let pattern
+warning: irrefutable `while let` pattern
--> $DIR/while-let.rs:7:13
|
LL | while let $p = $e $b
LL | | });
| |_______- in this macro invocation
|
+ = note: this pattern will always match, so the loop will never exit
+ = help: consider instead using a `loop { ... }` with a `let` inside it
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: irrefutable while-let pattern
+warning: irrefutable `while let` pattern
--> $DIR/while-let.rs:27:5
|
LL | / while let _a = 1 {
LL | | break;
LL | | }
| |_____^
+ |
+ = note: this pattern will always match, so the loop will never exit
+ = help: consider instead using a `loop { ... }` with a `let` inside it
warning: 3 warnings emitted
+++ /dev/null
-pub static mut A: u32 = 0;
-pub static mut B: () = unsafe { A = 1; };
-//~^ ERROR could not evaluate static initializer
-
-pub static mut C: u32 = unsafe { C = 1; 0 };
-//~^ ERROR cycle detected
-
-pub static D: u32 = D;
-
-fn main() {}
+++ /dev/null
-error[E0080]: could not evaluate static initializer
- --> $DIR/write-to-static-mut-in-static.rs:2:33
- |
-LL | pub static mut B: () = unsafe { A = 1; };
- | ^^^^^ modifying a static's initial value from another static's initializer
-
-error[E0391]: cycle detected when const-evaluating + checking `C`
- --> $DIR/write-to-static-mut-in-static.rs:5:1
- |
-LL | pub static mut C: u32 = unsafe { C = 1; 0 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: ...which requires const-evaluating + checking `C`...
- --> $DIR/write-to-static-mut-in-static.rs:5:1
- |
-LL | pub static mut C: u32 = unsafe { C = 1; 0 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: ...which again requires const-evaluating + checking `C`, completing the cycle
- = note: cycle used when running analysis passes on this crate
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0080, E0391.
-For more information about an error, try `rustc --explain E0080`.
-Subproject commit ab64d1393b5b77c66b6534ef5023a1b89ee7bf64
+Subproject commit bf5a5d5e5d3ae842a63bfce6d070dfd438cf6070
/// ```
pub WHILE_LET_ON_ITERATOR,
style,
- "using a while-let loop instead of a for loop on an iterator"
+ "using a `while let` loop instead of a for loop on an iterator"
}
declare_clippy_lint! {
&& eq_generics(lg, rg)
&& both(lb, rb, |l, r| eq_block(l, r))
}
- (Mod(l), Mod(r)) => {
- l.inline == r.inline && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_item_kind))
- }
+ (Mod(lu, lmk), Mod(ru, rmk)) => lu == ru && match (lmk, rmk) {
+ (ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) =>
+ linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind)),
+ (ModKind::Unloaded, ModKind::Unloaded) => true,
+ _ => false,
+ },
(ForeignMod(l), ForeignMod(r)) => {
both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r))
&& over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 1459;
-const ISSUES_ENTRY_LIMIT: usize = 2615;
+const ROOT_ENTRY_LIMIT: usize = 1418;
+const ISSUES_ENTRY_LIMIT: usize = 2582;
fn check_entries(path: &Path, bad: &mut bool) {
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))