diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 305df40651969..5032d7d6fbb6a 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -230,6 +230,7 @@ impl<'hir> LoweringContext<'_, 'hir> { e.id, expr_hir_id, *coroutine_kind, + *constness, fn_decl, body, *fn_decl_span, @@ -1060,7 +1061,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, - constness: Const, + mut constness: Const, movability: Movability, decl: &FnDecl, body: &Expr, @@ -1070,11 +1071,18 @@ impl<'hir> LoweringContext<'_, 'hir> { let closure_def_id = self.local_def_id(closure_id); let (binder_clause, generic_params) = self.lower_closure_binder(binder); + if let Const::Yes(span) = constness { + if !self.is_in_const_context { + self.dcx().span_err(span, "cannot use `const` closures outside of const contexts"); + constness = Const::No; + } + } + let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| { let mut coroutine_kind = find_attr!(attrs, Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable)); // FIXME(contracts): Support contracts on closures? - let body_id = this.lower_fn_body(decl, None, |this| { + let body_id = this.lower_fn_body(decl, None, constness, |this| { this.coroutine_kind = coroutine_kind; let e = this.lower_expr_mut(body); coroutine_kind = this.coroutine_kind; @@ -1157,6 +1165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { closure_id: NodeId, closure_hir_id: HirId, coroutine_kind: CoroutineKind, + constness: Const, decl: &FnDecl, body: &Expr, fn_decl_span: Span, @@ -1203,6 +1212,10 @@ impl<'hir> LoweringContext<'_, 'hir> { let fn_decl = self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None); + if let Const::Yes(span) = constness { + self.dcx().span_err(span, "const coroutines are not supported"); + } + let c = self.arena.alloc(hir::Closure { def_id: closure_def_id, binder: binder_clause, @@ -1216,7 +1229,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // knows that a `FnDecl` output type like `-> &str` actually means // "coroutine that returns &str", rather than directly returning a `&str`. kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring), - constness: hir::Constness::NotConst, + constness: self.lower_constness(constness), }); hir::ExprKind::Closure(c) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ed78b77a704f6..e2ac38caf2950 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,3 +1,5 @@ +use std::mem; + use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; @@ -345,6 +347,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body.as_deref(), attrs, contract.as_deref(), + header.constness, ); let itctx = ImplTraitContext::Universal; @@ -1024,6 +1027,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(body), attrs, contract.as_deref(), + sig.header.constness, ); let (generics, sig) = self.lower_method_sig( generics, @@ -1217,6 +1221,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body.as_deref(), attrs, contract.as_deref(), + sig.header.constness, ); let (generics, sig) = self.lower_method_sig( generics, @@ -1346,11 +1351,13 @@ impl<'hir> LoweringContext<'_, 'hir> { f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>), ) -> hir::BodyId { let prev_coroutine_kind = self.coroutine_kind.take(); + let prev_is_in_const_context = mem::take(&mut self.is_in_const_context); let task_context = self.task_context.take(); let (parameters, result) = f(self); let body_id = self.record_body(parameters, result); self.task_context = task_context; self.coroutine_kind = prev_coroutine_kind; + self.is_in_const_context = prev_is_in_const_context; body_id } @@ -1369,9 +1376,13 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, decl: &FnDecl, contract: Option<&FnContract>, + constness: Const, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> hir::BodyId { self.lower_body(|this| { + if let Const::Yes(_) = constness { + this.is_in_const_context = true; + } let params = this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x))); @@ -1389,8 +1400,9 @@ impl<'hir> LoweringContext<'_, 'hir> { decl: &FnDecl, body: &Block, contract: Option<&FnContract>, + constness: Const, ) -> hir::BodyId { - self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body)) + self.lower_fn_body(decl, contract, constness, |this| this.lower_block_expr(body)) } pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId { @@ -1398,7 +1410,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ( &[], match expr { - Some(expr) => this.lower_expr_mut(expr), + Some(expr) => { + this.is_in_const_context = true; + this.lower_expr_mut(expr) + } None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")), }, ) @@ -1417,12 +1432,13 @@ impl<'hir> LoweringContext<'_, 'hir> { body: Option<&Block>, attrs: &'hir [hir::Attribute], contract: Option<&FnContract>, + constness: Const, ) -> hir::BodyId { let Some(body) = body else { // Functions without a body are an error, except if this is an intrinsic. For those we // create a fake body so that the entire rest of the compiler doesn't have to deal with // this as a special case. - return self.lower_fn_body(decl, contract, |this| { + return self.lower_fn_body(decl, contract, constness, |this| { if find_attr!(attrs, RustcIntrinsic) || this.tcx.is_sdylib_interface_build() { let span = this.lower_span(span); let empty_block = hir::Block { @@ -1447,7 +1463,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let Some(coroutine_kind) = coroutine_kind else { // Typical case: not a coroutine. - return self.lower_fn_body_block(decl, body, contract); + return self.lower_fn_body_block(decl, body, contract, constness); }; // FIXME(contracts): Support contracts on async fn. self.lower_body(|this| { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c3525d1246705..e8092b540ec87 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -129,6 +129,7 @@ struct LoweringContext<'a, 'hir> { loop_scope: Option, is_in_loop_condition: bool, is_in_dyn_type: bool, + is_in_const_context: bool, current_hir_id_owner: hir::OwnerId, item_local_id_counter: hir::ItemLocalId, @@ -190,6 +191,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { loop_scope: None, is_in_loop_condition: false, is_in_dyn_type: false, + is_in_const_context: false, coroutine_kind: None, task_context: None, current_item: None, diff --git a/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs b/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs index ecb0095626b4a..2223e85a24957 100644 --- a/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs @@ -23,6 +23,7 @@ use std::fmt::Debug; use rustc_index::bit_set::DenseBitSet; +use rustc_index::{Idx, IndexSlice, IndexVec}; use tracing::debug; #[cfg(test)] @@ -45,13 +46,13 @@ mod tests; /// and does not implement those traits, so it has its own implementations of a /// few basic graph algorithms. pub struct LinkedGraph { - nodes: Vec>, + nodes: IndexVec>, edges: Vec>, } pub struct Node { first_edge: [EdgeIndex; 2], // see module comment - pub data: N, + pub data: Option, } #[derive(Debug)] @@ -62,7 +63,7 @@ pub struct Edge { pub data: E, } -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct NodeIndex(pub usize); #[derive(Copy, Clone, PartialEq, Debug)] @@ -87,19 +88,29 @@ impl NodeIndex { } } +impl Idx for NodeIndex { + fn new(idx: usize) -> NodeIndex { + NodeIndex(idx) + } + + fn index(self) -> usize { + self.0 + } +} + impl LinkedGraph { pub fn new() -> Self { - Self { nodes: Vec::new(), edges: Vec::new() } + Self { nodes: IndexVec::new(), edges: Vec::new() } } pub fn with_capacity(nodes: usize, edges: usize) -> Self { - Self { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) } + Self { nodes: IndexVec::with_capacity(nodes), edges: Vec::with_capacity(edges) } } // # Simple accessors #[inline] - pub fn all_nodes(&self) -> &[Node] { + pub fn all_nodes(&self) -> &IndexSlice> { &self.nodes } @@ -124,22 +135,34 @@ impl LinkedGraph { NodeIndex(self.nodes.len()) } + fn ensure_node(&mut self, idx: NodeIndex) -> &mut Node { + self.nodes.ensure_contains_elem(idx, || Node { + first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], + data: None, + }) + } + + pub fn add_node_with_idx(&mut self, idx: NodeIndex, data: N) { + let old_data = self.ensure_node(idx).data.replace(data); + debug_assert!(old_data.is_none()); + } + pub fn add_node(&mut self, data: N) -> NodeIndex { let idx = self.next_node_index(); - self.nodes.push(Node { first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], data }); + self.add_node_with_idx(idx, data); idx } pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N { - &mut self.nodes[idx.0].data + self.nodes[idx].data.as_mut().unwrap() } pub fn node_data(&self, idx: NodeIndex) -> &N { - &self.nodes[idx.0].data + self.nodes[idx].data.as_ref().unwrap() } pub fn node(&self, idx: NodeIndex) -> &Node { - &self.nodes[idx.0] + &self.nodes[idx] } // # Edge construction and queries @@ -154,16 +177,16 @@ impl LinkedGraph { let idx = self.next_edge_index(); // read current first of the list of edges from each node - let source_first = self.nodes[source.0].first_edge[OUTGOING.repr]; - let target_first = self.nodes[target.0].first_edge[INCOMING.repr]; + let source_first = self.ensure_node(source).first_edge[OUTGOING.repr]; + let target_first = self.ensure_node(target).first_edge[INCOMING.repr]; // create the new edge, with the previous firsts from each node // as the next pointers self.edges.push(Edge { next_edge: [source_first, target_first], source, target, data }); // adjust the firsts for each node target be the next object. - self.nodes[source.0].first_edge[OUTGOING.repr] = idx; - self.nodes[target.0].first_edge[INCOMING.repr] = idx; + self.nodes[source].first_edge[OUTGOING.repr] = idx; + self.nodes[target].first_edge[INCOMING.repr] = idx; idx } diff --git a/compiler/rustc_data_structures/src/graph/linked_graph/tests.rs b/compiler/rustc_data_structures/src/graph/linked_graph/tests.rs index 357aa81a57ca3..da416cd638d47 100644 --- a/compiler/rustc_data_structures/src/graph/linked_graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/linked_graph/tests.rs @@ -40,7 +40,7 @@ fn each_node() { let expected = ["A", "B", "C", "D", "E", "F"]; graph.each_node(|idx, node| { assert_eq!(&expected[idx.0], graph.node_data(idx)); - assert_eq!(expected[idx.0], node.data); + assert_eq!(expected[idx.0], node.data.unwrap()); true }); } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index ebb912ed90d0b..c508344b9cc1f 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -431,7 +431,7 @@ declare_features! ( /// Allows defining and calling c-variadic functions in const contexts. (unstable, const_c_variadic, "1.95.0", Some(151787)), /// Allows `const || {}` closures in const contexts. - (incomplete, const_closures, "1.68.0", Some(106003)), + (unstable, const_closures, "1.68.0", Some(106003)), /// Allows using `[const] Destruct` bounds and calling drop impls in const contexts. (unstable, const_destruct, "1.85.0", Some(133214)), /// Allows `for _ in _` loops in const contexts. diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index e16fa5492979f..98999232a7435 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1069,6 +1069,9 @@ pub(super) fn const_conditions<'tcx>( }, // N.B. Tuple ctors are unconditionally constant. Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(), + Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_), .. }) => { + (hir::Generics::empty(), None, tcx.is_conditionally_const(tcx.local_parent(def_id))) + } _ => bug!("const_conditions called on wrong item: {def_id:?}"), }; diff --git a/compiler/rustc_middle/src/dep_graph/retained.rs b/compiler/rustc_middle/src/dep_graph/retained.rs index 4427982e3708f..626b3b7821794 100644 --- a/compiler/rustc_middle/src/dep_graph/retained.rs +++ b/compiler/rustc_middle/src/dep_graph/retained.rs @@ -1,6 +1,5 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::linked_graph::{Direction, INCOMING, LinkedGraph, NodeIndex}; -use rustc_index::IndexVec; use super::{DepNode, DepNodeIndex}; @@ -13,7 +12,6 @@ use super::{DepNode, DepNodeIndex}; pub struct RetainedDepGraph { pub inner: LinkedGraph, pub indices: FxHashMap, - pub dep_index_to_index: IndexVec>, } impl RetainedDepGraph { @@ -23,27 +21,22 @@ impl RetainedDepGraph { let inner = LinkedGraph::with_capacity(node_count, edge_count); let indices = FxHashMap::default(); - let dep_index_to_index = IndexVec::new(); - Self { inner, indices, dep_index_to_index } + Self { inner, indices } } pub fn push(&mut self, index: DepNodeIndex, node: DepNode, edges: &[DepNodeIndex]) { - let source = self.inner.add_node(node); - self.dep_index_to_index.insert(index, source); + let source = NodeIndex(index.as_usize()); + self.inner.add_node_with_idx(source, node); self.indices.insert(node, source); for &target in edges.iter() { - // We may miss the edges that are pushed while the `DepGraphQuery` is being accessed. - // Skip them to issues. - if let Some(&Some(target)) = self.dep_index_to_index.get(target) { - self.inner.add_edge(source, target, ()); - } + self.inner.add_edge(source, NodeIndex(target.as_usize()), ()); } } pub fn nodes(&self) -> Vec<&DepNode> { - self.inner.all_nodes().iter().map(|n| &n.data).collect() + self.inner.all_nodes().iter().map(|n| n.data.as_ref().unwrap()).collect() } pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index cf1b863f754c8..fc2a7fbd4fa9c 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -310,16 +310,18 @@ impl<'tcx> TyCtxt<'tcx> { /// This should only be used for determining the context of a body, a return /// value of `Some` does not always suggest that the owner of the body is `const`, /// just that it has to be checked as if it were. - pub fn hir_body_const_context(self, def_id: LocalDefId) -> Option { - let def_id = def_id.into(); + pub fn hir_body_const_context(self, local_def_id: LocalDefId) -> Option { + let def_id = local_def_id.into(); let ccx = match self.hir_body_owner_kind(def_id) { BodyOwnerKind::Const { inline } => ConstContext::Const { inline }, BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability), BodyOwnerKind::Fn if self.is_constructor(def_id) => return None, - BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.is_const_fn(def_id) => { - ConstContext::ConstFn + // Const closures use their parent's const context + BodyOwnerKind::Closure if self.is_const_fn(def_id) => { + return self.hir_body_const_context(self.local_parent(local_def_id)); } + BodyOwnerKind::Fn if self.is_const_fn(def_id) => ConstContext::ConstFn, BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None, }; diff --git a/compiler/rustc_middle/src/query/job.rs b/compiler/rustc_middle/src/query/job.rs index 2747935942b55..b2e5649106ce9 100644 --- a/compiler/rustc_middle/src/query/job.rs +++ b/compiler/rustc_middle/src/query/job.rs @@ -65,7 +65,7 @@ impl<'tcx> QueryJob<'tcx> { #[derive(Debug)] pub struct QueryWaiter<'tcx> { - pub query: Option, + pub parent: Option, pub condvar: Condvar, pub span: Span, pub cycle: Mutex>>, @@ -94,8 +94,12 @@ impl<'tcx> QueryLatch<'tcx> { return Ok(()); // already complete }; - let waiter = - Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() }); + let waiter = Arc::new(QueryWaiter { + parent: query, + span, + cycle: Mutex::new(None), + condvar: Condvar::new(), + }); // We push the waiter on to the `waiters` list. It can be accessed inside // the `wait` call below, by 1) the `set` method or 2) by deadlock detection. diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index e59573976af52..5179a77d6cb6f 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -402,6 +402,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.is_conditionally_const(def_id) } + fn closure_is_const(self, def_id: DefId) -> bool { + debug_assert_matches!(self.def_kind(def_id), DefKind::Closure); + self.constness(def_id) == hir::Constness::Const + } + fn alias_has_const_conditions(self, def_id: DefId) -> bool { debug_assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::OpaqueTy); self.is_conditionally_const(def_id) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6abe7d1466990..01c351de93198 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2118,11 +2118,7 @@ impl<'tcx> TyCtxt<'tcx> { // FIXME(const_trait_impl): ATPITs could be conditionally const? hir::OpaqueTyOrigin::TyAlias { .. } => false, }, - DefKind::Closure => { - // Closures and RPITs will eventually have const conditions - // for `[const]` bounds. - false - } + DefKind::Closure => self.constness(def_id) == hir::Constness::Const, DefKind::Ctor(_, CtorKind::Const) | DefKind::Mod | DefKind::Struct diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 05ea217c1de08..cd74e87b670f1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -661,10 +661,11 @@ fn coroutine_closure_to_ambiguous_coroutine( /// /// Doing so on all calls to `extract_tupled_inputs_and_output_from_callable` /// would be wasteful. +#[instrument(level = "trace", skip(cx), ret)] pub(in crate::solve) fn extract_fn_def_from_const_callable( cx: I, self_ty: I::Ty, -) -> Result<(ty::Binder, I::FunctionId, I::GenericArgs), NoSolution> { +) -> Result<(ty::Binder, I::DefId, I::GenericArgs), NoSolution> { match self_ty.kind() { ty::FnDef(def_id, args) => { let sig = cx.fn_sig(def_id); @@ -675,7 +676,7 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable( Ok(( sig.instantiate(cx, args) .map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())), - def_id, + def_id.into(), args, )) } else { @@ -686,9 +687,19 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable( ty::FnPtr(..) => { return Err(NoSolution); } - // `Closure`s are not const for now. - ty::Closure(..) => { - return Err(NoSolution); + ty::Closure(def, args) => { + if cx.closure_is_const(def) { + let closure_args = args.as_closure(); + Ok(( + closure_args + .sig() + .map_bound(|sig| (sig.inputs().get(0).unwrap(), sig.output())), + def.into(), + args, + )) + } else { + return Err(NoSolution); + } } // `CoroutineClosure`s are not const for now. ty::CoroutineClosure(..) => { diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 4da76b88b5de0..4b1e4b2de571d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -272,6 +272,7 @@ where todo!("Fn* are not yet const") } + #[instrument(level = "trace", skip_all, ret)] fn consider_builtin_fn_trait_candidates( ecx: &mut EvalCtxt<'_, D>, goal: Goal, @@ -289,7 +290,7 @@ where let output_is_sized_pred = ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]); let requirements = cx - .const_conditions(def_id.into()) + .const_conditions(def_id) .iter_instantiated(cx, args) .map(|trait_ref| { ( diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index 2b535d64cf706..eae91a2b2e566 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -18,9 +18,9 @@ use rustc_span::{DUMMY_SP, Span}; use tracing::warn; use crate::dep_graph::{DepNode, DepNodeIndex}; -use crate::for_each_query_vtable; use crate::job::{QueryJobInfo, QueryJobMap, find_cycle_in_stack, report_cycle}; use crate::plumbing::{current_query_job, next_job_id, start_query}; +use crate::query_impl::for_each_query_vtable; #[inline] fn equivalent_key(k: K) -> impl Fn(&(K, V)) -> bool { diff --git a/compiler/rustc_query_impl/src/from_cycle_error.rs b/compiler/rustc_query_impl/src/from_cycle_error.rs index 6a3155c02949e..8214f80cda410 100644 --- a/compiler/rustc_query_impl/src/from_cycle_error.rs +++ b/compiler/rustc_query_impl/src/from_cycle_error.rs @@ -21,21 +21,6 @@ use rustc_span::{ErrorGuaranteed, Span}; use crate::job::report_cycle; pub(crate) fn specialize_query_vtables<'tcx>(vtables: &mut QueryVTables<'tcx>) { - vtables.type_of.value_from_cycle_error = |tcx, _, _, err| { - let guar = err.emit(); - erase_val(ty::EarlyBinder::bind(Ty::new_error(tcx, guar))) - }; - - vtables.type_of_opaque_hir_typeck.value_from_cycle_error = |tcx, _, _, err| { - let guar = err.emit(); - erase_val(ty::EarlyBinder::bind(Ty::new_error(tcx, guar))) - }; - - vtables.erase_and_anonymize_regions_ty.value_from_cycle_error = |tcx, _, _, err| { - let guar = err.emit(); - erase_val(Ty::new_error(tcx, guar)) - }; - vtables.fn_sig.value_from_cycle_error = |tcx, key, _, err| { let guar = err.delay_as_bug(); erase_val(fn_sig(tcx, key, guar)) diff --git a/compiler/rustc_query_impl/src/job.rs b/compiler/rustc_query_impl/src/job.rs index 64ed9b6b51bf2..7151d0b52fe23 100644 --- a/compiler/rustc_query_impl/src/job.rs +++ b/compiler/rustc_query_impl/src/job.rs @@ -111,38 +111,44 @@ pub(crate) fn find_dep_kind_root<'tcx>( last_layout } -/// A resumable waiter of a query. The usize is the index into waiters in the query's latch -type Waiter = (QueryJobId, usize); - -/// Visits all the non-resumable and resumable waiters of a query. -/// Only waiters in a query are visited. -/// `visit` is called for every waiter and is passed a query waiting on `query` -/// and a span indicating the reason the query waited on `query`. -/// If `visit` returns `Break`, this function also returns `Break`, -/// and if all `visit` calls returns `Continue` it also returns `Continue`. -/// For visits of non-resumable waiters it returns the return value of `visit`. -/// For visits of resumable waiters it returns information required to resume that waiter. -fn visit_waiters<'tcx>( - job_map: &QueryJobMap<'tcx>, - query: QueryJobId, - mut visit: impl FnMut(Span, QueryJobId) -> ControlFlow>, -) -> ControlFlow> { - // Visit the parent query which is a non-resumable waiter since it's on the same stack - if let Some(parent) = job_map.parent_of(query) { - visit(job_map.span_of(query), parent)?; - } +/// The locaton of a resumable waiter. The usize is the index into waiters in the query's latch. +/// We'll use this to remove the waiter using `QueryLatch::extract_waiter` if we're waking it up. +type ResumableWaiterLocation = (QueryJobId, usize); + +/// This abstracts over non-resumable waiters which are found in `QueryJob`'s `parent` field +/// and resumable waiters are in `latch` field. +struct AbstractedWaiter { + /// The span corresponding to the reason for why we're waiting on this query. + span: Span, + /// The query which we are waiting from, if none the waiter is from a compiler root. + parent: Option, + resumable: Option, +} + +/// Returns all the non-resumable and resumable waiters of a query. +/// This is used so we can uniformly loop over both non-resumable and resumable waiters. +fn abstracted_waiters_of(job_map: &QueryJobMap<'_>, query: QueryJobId) -> Vec { + let mut result = Vec::new(); - // Visit the explicit waiters which use condvars and are resumable + // Add the parent which is a non-resumable waiter since it's on the same stack + result.push(AbstractedWaiter { + span: job_map.span_of(query), + parent: job_map.parent_of(query), + resumable: None, + }); + + // Add the explicit waiters which use condvars and are resumable if let Some(latch) = job_map.latch_of(query) { for (i, waiter) in latch.waiters.lock().as_ref().unwrap().iter().enumerate() { - if let Some(waiter_query) = waiter.query { - // Return a value which indicates that this waiter can be resumed - visit(waiter.span, waiter_query).map_break(|_| Some((query, i)))?; - } + result.push(AbstractedWaiter { + span: waiter.span, + parent: waiter.parent, + resumable: Some((query, i)), + }); } } - ControlFlow::Continue(()) + result } /// Look for query cycles by doing a depth first search starting at `query`. @@ -155,13 +161,13 @@ fn cycle_check<'tcx>( span: Span, stack: &mut Vec<(Span, QueryJobId)>, visited: &mut FxHashSet, -) -> ControlFlow> { +) -> ControlFlow> { if !visited.insert(query) { - return if let Some(p) = stack.iter().position(|q| q.1 == query) { + return if let Some(pos) = stack.iter().position(|q| q.1 == query) { // We detected a query cycle, fix up the initial span and return Some // Remove previous stack entries - stack.drain(0..p); + stack.drain(0..pos); // Replace the span for the first query with the cycle cause stack[0].0 = span; ControlFlow::Break(None) @@ -174,16 +180,23 @@ fn cycle_check<'tcx>( stack.push((span, query)); // Visit all the waiters - let r = visit_waiters(job_map, query, |span, successor| { - cycle_check(job_map, successor, span, stack, visited) - }); - - // Remove the entry in our stack if we didn't find a cycle - if r.is_continue() { - stack.pop(); + for abstracted_waiter in abstracted_waiters_of(job_map, query) { + let Some(parent) = abstracted_waiter.parent else { + // Skip waiters which are not queries + continue; + }; + if let ControlFlow::Break(maybe_resumable) = + cycle_check(job_map, parent, abstracted_waiter.span, stack, visited) + { + // Return the resumable waiter in `waiter.resumable` if present + return ControlFlow::Break(abstracted_waiter.resumable.or(maybe_resumable)); + } } - r + // Remove the entry in our stack since we didn't find a cycle + stack.pop(); + + ControlFlow::Continue(()) } /// Finds out if there's a path to the compiler root (aka. code which isn't in a query) @@ -193,18 +206,26 @@ fn connected_to_root<'tcx>( job_map: &QueryJobMap<'tcx>, query: QueryJobId, visited: &mut FxHashSet, -) -> ControlFlow> { +) -> bool { // We already visited this or we're deliberately ignoring it if !visited.insert(query) { - return ControlFlow::Continue(()); + return false; } - // This query is connected to the root (it has no query parent), return true - if job_map.parent_of(query).is_none() { - return ControlFlow::Break(None); + // Visit all the waiters + for abstracted_waiter in abstracted_waiters_of(job_map, query) { + match abstracted_waiter.parent { + // This query is connected to the root + None => return true, + Some(parent) => { + if connected_to_root(job_map, parent, visited) { + return true; + } + } + } } - visit_waiters(job_map, query, |_, successor| connected_to_root(job_map, successor, visited)) + false } /// Looks for query cycles starting from the last query in `jobs`. @@ -220,7 +241,7 @@ fn remove_cycle<'tcx>( let mut visited = FxHashSet::default(); let mut stack = Vec::new(); // Look for a cycle starting with the last query in `jobs` - if let ControlFlow::Break(waiter) = + if let ControlFlow::Break(resumable) = cycle_check(job_map, jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited) { // The stack is a vector of pairs of spans and queries; reverse it so that @@ -242,7 +263,7 @@ fn remove_cycle<'tcx>( struct EntryPoint { query_in_cycle: QueryJobId, - waiter: Option<(Span, QueryJobId)>, + query_waiting_on_cycle: Option<(Span, QueryJobId)>, } // Find the queries in the cycle which are @@ -250,36 +271,36 @@ fn remove_cycle<'tcx>( let entry_points = stack .iter() .filter_map(|&(_, query_in_cycle)| { - if job_map.parent_of(query_in_cycle).is_none() { - // This query is connected to the root (it has no query parent) - Some(EntryPoint { query_in_cycle, waiter: None }) - } else { - let mut waiter_on_cycle = None; - // Find a direct waiter who leads to the root - let _ = visit_waiters(job_map, query_in_cycle, |span, waiter| { - // Mark all the other queries in the cycle as already visited - let mut visited = FxHashSet::from_iter(stack.iter().map(|q| q.1)); - - if connected_to_root(job_map, waiter, &mut visited).is_break() { - waiter_on_cycle = Some((span, waiter)); - ControlFlow::Break(None) - } else { - ControlFlow::Continue(()) - } - }); - - waiter_on_cycle.map(|waiter_on_cycle| EntryPoint { - query_in_cycle, - waiter: Some(waiter_on_cycle), - }) + let mut entrypoint = false; + let mut query_waiting_on_cycle = None; + + // Find a direct waiter who leads to the root + for abstracted_waiter in abstracted_waiters_of(job_map, query_in_cycle) { + let Some(parent) = abstracted_waiter.parent else { + // The query in the cycle is directly connected to root. + entrypoint = true; + continue; + }; + + // Mark all the other queries in the cycle as already visited, + // so paths to the root through the cycle itself won't count. + let mut visited = FxHashSet::from_iter(stack.iter().map(|q| q.1)); + + if connected_to_root(job_map, parent, &mut visited) { + query_waiting_on_cycle = Some((abstracted_waiter.span, parent)); + entrypoint = true; + break; + } } + + entrypoint.then_some(EntryPoint { query_in_cycle, query_waiting_on_cycle }) }) .collect::>(); // Pick an entry point, preferring ones with waiters let entry_point = entry_points .iter() - .find(|entry_point| entry_point.waiter.is_some()) + .find(|entry_point| entry_point.query_waiting_on_cycle.is_some()) .unwrap_or(&entry_points[0]); // Shift the stack so that our entry point is first @@ -289,7 +310,9 @@ fn remove_cycle<'tcx>( stack.rotate_left(pos); } - let usage = entry_point.waiter.map(|(span, job)| (span, job_map.frame_of(job).clone())); + let usage = entry_point + .query_waiting_on_cycle + .map(|(span, job)| (span, job_map.frame_of(job).clone())); // Create the cycle error let error = CycleError { @@ -300,9 +323,9 @@ fn remove_cycle<'tcx>( .collect(), }; - // We unwrap `waiter` here since there must always be one + // We unwrap `resumable` here since there must always be one // edge which is resumable / waited using a query latch - let (waitee_query, waiter_idx) = waiter.unwrap(); + let (waitee_query, waiter_idx) = resumable.unwrap(); // Extract the waiter we want to resume let waiter = job_map.latch_of(waitee_query).unwrap().extract_waiter(waiter_idx); diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 44c97d19914c9..c62ea3e289fcb 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -10,26 +10,24 @@ use rustc_data_structures::sync::AtomicU64; use rustc_middle::dep_graph; -use rustc_middle::queries::{self, ExternProviders, Providers, TaggedQueryKey}; +use rustc_middle::queries::{ExternProviders, Providers}; +use rustc_middle::query::QueryCache; use rustc_middle::query::on_disk_cache::OnDiskCache; use rustc_middle::query::plumbing::{QuerySystem, QueryVTable}; -use rustc_middle::query::{AsLocalQueryKey, QueryCache, QueryMode}; use rustc_middle::ty::TyCtxt; -use rustc_span::Span; pub use crate::dep_kind_vtables::make_dep_kind_vtables; pub use crate::execution::{CollectActiveJobsKind, collect_active_jobs_from_all_queries}; pub use crate::job::{QueryJobMap, break_query_cycles, print_query_stack}; -#[macro_use] -mod plumbing; - mod dep_kind_vtables; mod error; mod execution; mod from_cycle_error; mod job; +mod plumbing; mod profiling_support; +mod query_impl; /// Trait that knows how to look up the [`QueryVTable`] for a particular query. /// @@ -51,7 +49,7 @@ pub fn query_system<'tcx>( on_disk_cache: Option, incremental: bool, ) -> QuerySystem<'tcx> { - let mut query_vtables = make_query_vtables(incremental); + let mut query_vtables = query_impl::make_query_vtables(incremental); from_cycle_error::specialize_query_vtables(&mut query_vtables); QuerySystem { arenas: Default::default(), @@ -63,8 +61,6 @@ pub fn query_system<'tcx>( } } -rustc_middle::rustc_with_all_queries! { define_queries! } - pub fn provide(providers: &mut rustc_middle::util::Providers) { providers.hooks.alloc_self_profile_query_strings = profiling_support::alloc_self_profile_query_strings; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index bece2e56c0a86..a346836057d93 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -1,7 +1,3 @@ -//! The implementation of the query system itself. This defines the macros that -//! generate the actual methods on tcx which find and execute the provider, -//! manage the caches, and so forth. - use std::num::NonZero; use rustc_data_structures::sync::{DynSend, DynSync}; @@ -29,10 +25,8 @@ use rustc_span::def_id::LOCAL_CRATE; use crate::error::{QueryOverflow, QueryOverflowNote}; use crate::execution::{all_inactive, force_query}; use crate::job::find_dep_kind_root; -use crate::{ - CollectActiveJobsKind, GetQueryVTable, collect_active_jobs_from_all_queries, - for_each_query_vtable, -}; +use crate::query_impl::for_each_query_vtable; +use crate::{CollectActiveJobsKind, GetQueryVTable, collect_active_jobs_from_all_queries}; fn depth_limit_error<'tcx>(tcx: TyCtxt<'tcx>, job: QueryJobId) { let job_map = collect_active_jobs_from_all_queries(tcx, CollectActiveJobsKind::Full); @@ -283,256 +277,3 @@ pub(crate) fn force_from_dep_node_inner<'tcx, Q: GetQueryVTable<'tcx>>( false } } - -macro_rules! define_queries { - ( - // Note: `$K` and `$V` are unused but present so this can be called by - // `rustc_with_all_queries`. - queries { - $( - $(#[$attr:meta])* - fn $name:ident($K:ty) -> $V:ty - { - // Search for (QMODLIST) to find all occurrences of this query modifier list. - anon: $anon:literal, - arena_cache: $arena_cache:literal, - cache_on_disk: $cache_on_disk:literal, - depth_limit: $depth_limit:literal, - eval_always: $eval_always:literal, - feedable: $feedable:literal, - no_hash: $no_hash:literal, - returns_error_guaranteed: $returns_error_guaranteed:literal, - separate_provide_extern: $separate_provide_extern:literal, - } - )* - } - // Non-queries are unused here. - non_queries { $($_:tt)* } - ) => { - pub(crate) mod query_impl { $(pub(crate) mod $name { - use super::super::*; - use ::rustc_middle::query::erase::{self, Erased}; - - // It seems to be important that every query has its own monomorphic - // copy of `execute_query_incr` and `execute_query_non_incr`. - // Trying to inline these wrapper functions into their generic - // "inner" helpers tends to break `tests/run-make/short-ice`. - - pub(crate) mod execute_query_incr { - use super::*; - - // Adding `__rust_end_short_backtrace` marker to backtraces so that we emit the frames - // when `RUST_BACKTRACE=1`, add a new mod with `$name` here is to allow duplicate naming - #[inline(never)] - pub(crate) fn __rust_end_short_backtrace<'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - key: queries::$name::Key<'tcx>, - mode: QueryMode, - ) -> Option>> { - #[cfg(debug_assertions)] - let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); - execution::execute_query_incr_inner( - &tcx.query_system.query_vtables.$name, - tcx, - span, - key, - mode - ) - } - } - - pub(crate) mod execute_query_non_incr { - use super::*; - - #[inline(never)] - pub(crate) fn __rust_end_short_backtrace<'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - key: queries::$name::Key<'tcx>, - __mode: QueryMode, - ) -> Option>> { - Some(execution::execute_query_non_incr_inner( - &tcx.query_system.query_vtables.$name, - tcx, - span, - key, - )) - } - } - - /// Defines an `invoke_provider` function that calls the query's provider, - /// to be used as a function pointer in the query's vtable. - /// - /// To mark a short-backtrace boundary, the function's actual name - /// (after demangling) must be `__rust_begin_short_backtrace`. - mod invoke_provider_fn { - use super::*; - use ::rustc_middle::queries::$name::{Key, Value, provided_to_erased}; - - #[inline(never)] - pub(crate) fn __rust_begin_short_backtrace<'tcx>( - tcx: TyCtxt<'tcx>, - key: Key<'tcx>, - ) -> Erased> { - #[cfg(debug_assertions)] - let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); - - // Call the actual provider function for this query. - - #[cfg($separate_provide_extern)] - let provided_value = if let Some(local_key) = key.as_local_key() { - (tcx.query_system.local_providers.$name)(tcx, local_key) - } else { - (tcx.query_system.extern_providers.$name)(tcx, key) - }; - - #[cfg(not($separate_provide_extern))] - let provided_value = (tcx.query_system.local_providers.$name)(tcx, key); - - rustc_middle::ty::print::with_reduced_queries!({ - tracing::trace!(?provided_value); - }); - - // Erase the returned value, because `QueryVTable` uses erased values. - // For queries with `arena_cache`, this also arena-allocates the value. - provided_to_erased(tcx, provided_value) - } - } - - pub(crate) fn make_query_vtable<'tcx>(incremental: bool) - -> QueryVTable<'tcx, queries::$name::Cache<'tcx>> - { - QueryVTable { - name: stringify!($name), - anon: $anon, - eval_always: $eval_always, - depth_limit: $depth_limit, - feedable: $feedable, - dep_kind: dep_graph::DepKind::$name, - state: Default::default(), - cache: Default::default(), - - invoke_provider_fn: self::invoke_provider_fn::__rust_begin_short_backtrace, - - #[cfg($cache_on_disk)] - will_cache_on_disk_for_key_fn: - rustc_middle::queries::_cache_on_disk_if_fns::$name, - #[cfg(not($cache_on_disk))] - will_cache_on_disk_for_key_fn: |_, _| false, - - #[cfg($cache_on_disk)] - try_load_from_disk_fn: |tcx, key, prev_index, index| { - // Check the `cache_on_disk_if` condition for this key. - if !rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) { - return None; - } - - let value: queries::$name::ProvidedValue<'tcx> = - $crate::plumbing::try_load_from_disk(tcx, prev_index, index)?; - - // Arena-alloc the value if appropriate, and erase it. - Some(queries::$name::provided_to_erased(tcx, value)) - }, - #[cfg(not($cache_on_disk))] - try_load_from_disk_fn: |_tcx, _key, _prev_index, _index| None, - - #[cfg($cache_on_disk)] - is_loadable_from_disk_fn: |tcx, key, index| -> bool { - rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) && - $crate::plumbing::loadable_from_disk(tcx, index) - }, - #[cfg(not($cache_on_disk))] - is_loadable_from_disk_fn: |_tcx, _key, _index| false, - - // The default just emits `err` and then aborts. - // `from_cycle_error::specialize_query_vtables` overwrites this default for - // certain queries. - value_from_cycle_error: |_tcx, _key, _cycle, err| { - $crate::from_cycle_error::default(err) - }, - - #[cfg($no_hash)] - hash_value_fn: None, - #[cfg(not($no_hash))] - hash_value_fn: Some(|hcx, erased_value: &erase::Erased>| { - let value = erase::restore_val(*erased_value); - rustc_middle::dep_graph::hash_result(hcx, &value) - }), - - format_value: |value| format!("{:?}", erase::restore_val::>(*value)), - create_tagged_key: TaggedQueryKey::$name, - execute_query_fn: if incremental { - query_impl::$name::execute_query_incr::__rust_end_short_backtrace - } else { - query_impl::$name::execute_query_non_incr::__rust_end_short_backtrace - }, - } - } - - /// Marker type that implements [`GetQueryVTable`] for this query. - pub(crate) enum VTableGetter {} - - impl<'tcx> GetQueryVTable<'tcx> for VTableGetter { - type Cache = rustc_middle::queries::$name::Cache<'tcx>; - - #[inline(always)] - fn query_vtable(tcx: TyCtxt<'tcx>) -> &'tcx QueryVTable<'tcx, Self::Cache> { - &tcx.query_system.query_vtables.$name - } - } - })*} - - pub fn make_query_vtables<'tcx>(incremental: bool) -> queries::QueryVTables<'tcx> { - queries::QueryVTables { - $( - $name: query_impl::$name::make_query_vtable(incremental), - )* - } - } - - /// Given a filter condition (e.g. `ALL` or `CACHE_ON_DISK`), a `tcx`, - /// and a closure expression that accepts `&QueryVTable`, this macro - /// calls that closure with each query vtable that satisfies the filter - /// condition. - /// - /// This needs to be a macro, because the vtables can have different - /// key/value/cache types for different queries. - /// - /// This macro's argument syntax is specifically intended to look like - /// plain Rust code, so that `for_each_query_vtable!(..)` calls will be - /// formatted by rustfmt. - /// - /// To avoid too much nested-macro complication, filter conditions are - /// implemented by hand as needed. - macro_rules! for_each_query_vtable { - // Call with all queries. - (ALL, $tcx:expr, $closure:expr) => {{ - let tcx: rustc_middle::ty::TyCtxt<'_> = $tcx; - $( - let query: &rustc_middle::query::plumbing::QueryVTable<'_, _> = - &tcx.query_system.query_vtables.$name; - $closure(query); - )* - }}; - - // Only call with queries that can potentially cache to disk. - // - // This allows the use of trait bounds that only need to be satisfied - // by the subset of queries that actually cache to disk. - (CACHE_ON_DISK, $tcx:expr, $closure:expr) => {{ - let tcx: rustc_middle::ty::TyCtxt<'_> = $tcx; - $( - #[cfg($cache_on_disk)] - { - let query: &rustc_middle::query::plumbing::QueryVTable<'_, _> = - &tcx.query_system.query_vtables.$name; - $closure(query); - } - )* - }} - } - - pub(crate) use for_each_query_vtable; - } -} diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index c88bc8845ebdb..c34938cdb3866 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -10,7 +10,7 @@ use rustc_middle::query::QueryCache; use rustc_middle::query::plumbing::QueryVTable; use rustc_middle::ty::TyCtxt; -use crate::for_each_query_vtable; +use crate::query_impl::for_each_query_vtable; pub(crate) struct QueryKeyStringCache { def_id_cache: FxHashMap, diff --git a/compiler/rustc_query_impl/src/query_impl.rs b/compiler/rustc_query_impl/src/query_impl.rs new file mode 100644 index 0000000000000..d5fb90871e76e --- /dev/null +++ b/compiler/rustc_query_impl/src/query_impl.rs @@ -0,0 +1,275 @@ +use rustc_middle::queries::TaggedQueryKey; +use rustc_middle::query::erase::{self, Erased}; +use rustc_middle::query::plumbing::QueryVTable; +use rustc_middle::query::{AsLocalQueryKey, QueryMode}; +use rustc_middle::ty::TyCtxt; +use rustc_span::Span; + +use crate::GetQueryVTable; + +macro_rules! define_queries { + ( + // Note: `$K` and `$V` are unused but present so this can be called by + // `rustc_with_all_queries`. + queries { + $( + $(#[$attr:meta])* + fn $name:ident($K:ty) -> $V:ty + { + // Search for (QMODLIST) to find all occurrences of this query modifier list. + anon: $anon:literal, + arena_cache: $arena_cache:literal, + cache_on_disk: $cache_on_disk:literal, + depth_limit: $depth_limit:literal, + eval_always: $eval_always:literal, + feedable: $feedable:literal, + no_hash: $no_hash:literal, + returns_error_guaranteed: $returns_error_guaranteed:literal, + separate_provide_extern: $separate_provide_extern:literal, + } + )* + } + // Non-queries are unused here. + non_queries { $($_:tt)* } + ) => { + // This macro expects to be expanded into `crate::query_impl`, which is this file. + $( + pub(crate) mod $name { + use super::*; + + // It seems to be important that every query has its own monomorphic + // copy of `execute_query_incr` and `execute_query_non_incr`. + // Trying to inline these wrapper functions into their generic + // "inner" helpers tends to break `tests/run-make/short-ice`. + + pub(crate) mod execute_query_incr { + use super::*; + use rustc_middle::queries::$name::{Key, Value}; + + // Adding `__rust_end_short_backtrace` marker to backtraces so that we emit the frames + // when `RUST_BACKTRACE=1`, add a new mod with `$name` here is to allow duplicate naming + #[inline(never)] + pub(crate) fn __rust_end_short_backtrace<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + key: Key<'tcx>, + mode: QueryMode, + ) -> Option>> { + #[cfg(debug_assertions)] + let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); + crate::execution::execute_query_incr_inner( + &tcx.query_system.query_vtables.$name, + tcx, + span, + key, + mode + ) + } + } + + pub(crate) mod execute_query_non_incr { + use super::*; + use rustc_middle::queries::$name::{Key, Value}; + + #[inline(never)] + pub(crate) fn __rust_end_short_backtrace<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + key: Key<'tcx>, + __mode: QueryMode, + ) -> Option>> { + Some(crate::execution::execute_query_non_incr_inner( + &tcx.query_system.query_vtables.$name, + tcx, + span, + key, + )) + } + } + + /// Defines an `invoke_provider` function that calls the query's provider, + /// to be used as a function pointer in the query's vtable. + /// + /// To mark a short-backtrace boundary, the function's actual name + /// (after demangling) must be `__rust_begin_short_backtrace`. + mod invoke_provider_fn { + use super::*; + use rustc_middle::queries::$name::{Key, Value, provided_to_erased}; + + #[inline(never)] + pub(crate) fn __rust_begin_short_backtrace<'tcx>( + tcx: TyCtxt<'tcx>, + key: Key<'tcx>, + ) -> Erased> { + #[cfg(debug_assertions)] + let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); + + // Call the actual provider function for this query. + + #[cfg($separate_provide_extern)] + let provided_value = if let Some(local_key) = key.as_local_key() { + (tcx.query_system.local_providers.$name)(tcx, local_key) + } else { + (tcx.query_system.extern_providers.$name)(tcx, key) + }; + + #[cfg(not($separate_provide_extern))] + let provided_value = (tcx.query_system.local_providers.$name)(tcx, key); + + rustc_middle::ty::print::with_reduced_queries!({ + tracing::trace!(?provided_value); + }); + + // Erase the returned value, because `QueryVTable` uses erased values. + // For queries with `arena_cache`, this also arena-allocates the value. + provided_to_erased(tcx, provided_value) + } + } + + pub(crate) fn make_query_vtable<'tcx>(incremental: bool) + -> QueryVTable<'tcx, rustc_middle::queries::$name::Cache<'tcx>> + { + use rustc_middle::queries::$name::Value; + + QueryVTable { + name: stringify!($name), + anon: $anon, + eval_always: $eval_always, + depth_limit: $depth_limit, + feedable: $feedable, + dep_kind: rustc_middle::dep_graph::DepKind::$name, + state: Default::default(), + cache: Default::default(), + + invoke_provider_fn: self::invoke_provider_fn::__rust_begin_short_backtrace, + + #[cfg($cache_on_disk)] + will_cache_on_disk_for_key_fn: + rustc_middle::queries::_cache_on_disk_if_fns::$name, + #[cfg(not($cache_on_disk))] + will_cache_on_disk_for_key_fn: |_, _| false, + + #[cfg($cache_on_disk)] + try_load_from_disk_fn: |tcx, key, prev_index, index| { + use rustc_middle::queries::$name::{ProvidedValue, provided_to_erased}; + + // Check the `cache_on_disk_if` condition for this key. + if !rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) { + return None; + } + + let loaded_value: ProvidedValue<'tcx> = + $crate::plumbing::try_load_from_disk(tcx, prev_index, index)?; + + // Arena-alloc the value if appropriate, and erase it. + Some(provided_to_erased(tcx, loaded_value)) + }, + #[cfg(not($cache_on_disk))] + try_load_from_disk_fn: |_tcx, _key, _prev_index, _index| None, + + #[cfg($cache_on_disk)] + is_loadable_from_disk_fn: |tcx, key, index| -> bool { + rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) && + $crate::plumbing::loadable_from_disk(tcx, index) + }, + #[cfg(not($cache_on_disk))] + is_loadable_from_disk_fn: |_tcx, _key, _index| false, + + // The default just emits `err` and then aborts. + // `from_cycle_error::specialize_query_vtables` overwrites this default for + // certain queries. + value_from_cycle_error: |_tcx, _key, _cycle, err| { + $crate::from_cycle_error::default(err) + }, + + #[cfg($no_hash)] + hash_value_fn: None, + #[cfg(not($no_hash))] + hash_value_fn: Some(|hcx, erased_value: &erase::Erased>| { + let value = erase::restore_val(*erased_value); + rustc_middle::dep_graph::hash_result(hcx, &value) + }), + + format_value: |erased_value: &erase::Erased>| { + format!("{:?}", erase::restore_val(*erased_value)) + }, + create_tagged_key: TaggedQueryKey::$name, + execute_query_fn: if incremental { + crate::query_impl::$name::execute_query_incr::__rust_end_short_backtrace + } else { + crate::query_impl::$name::execute_query_non_incr::__rust_end_short_backtrace + }, + } + } + + /// Marker type that implements [`GetQueryVTable`] for this query. + pub(crate) enum VTableGetter {} + + impl<'tcx> GetQueryVTable<'tcx> for VTableGetter { + type Cache = rustc_middle::queries::$name::Cache<'tcx>; + + #[inline(always)] + fn query_vtable(tcx: TyCtxt<'tcx>) -> &'tcx QueryVTable<'tcx, Self::Cache> { + &tcx.query_system.query_vtables.$name + } + } + } + )* + + pub(crate) fn make_query_vtables<'tcx>(incremental: bool) + -> rustc_middle::queries::QueryVTables<'tcx> + { + rustc_middle::queries::QueryVTables { + $( + $name: crate::query_impl::$name::make_query_vtable(incremental), + )* + } + } + + /// Given a filter condition (e.g. `ALL` or `CACHE_ON_DISK`), a `tcx`, + /// and a closure expression that accepts `&QueryVTable`, this macro + /// calls that closure with each query vtable that satisfies the filter + /// condition. + /// + /// This needs to be a macro, because the vtables can have different + /// key/value/cache types for different queries. + /// + /// This macro's argument syntax is specifically intended to look like + /// plain Rust code, so that `for_each_query_vtable!(..)` calls will be + /// formatted by rustfmt. + /// + /// To avoid too much nested-macro complication, filter conditions are + /// implemented by hand as needed. + macro_rules! for_each_query_vtable { + // Call with all queries. + (ALL, $tcx:expr, $closure:expr) => {{ + let tcx: rustc_middle::ty::TyCtxt<'_> = $tcx; + $( + let query: &rustc_middle::query::plumbing::QueryVTable<'_, _> = + &tcx.query_system.query_vtables.$name; + $closure(query); + )* + }}; + + // Only call with queries that can potentially cache to disk. + // + // This allows the use of trait bounds that only need to be satisfied + // by the subset of queries that actually cache to disk. + (CACHE_ON_DISK, $tcx:expr, $closure:expr) => {{ + let tcx: rustc_middle::ty::TyCtxt<'_> = $tcx; + $( + #[cfg($cache_on_disk)] + { + let query: &rustc_middle::query::plumbing::QueryVTable<'_, _> = + &tcx.query_system.query_vtables.$name; + $closure(query); + } + )* + }} + } + + pub(crate) use for_each_query_vtable; + } +} + +rustc_middle::rustc_with_all_queries! { define_queries! } diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 66c949a38cea7..026ab3a527a1c 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -519,10 +519,21 @@ fn evaluate_host_effect_for_fn_goal<'tcx>( // We may support function pointers at some point in the future ty::FnPtr(..) => return Err(EvaluationFailure::NoSolution), - // Closures could implement `[const] Fn`, + // Coroutines could implement `[const] Fn`, // but they don't really need to right now. - ty::Closure(..) | ty::CoroutineClosure(_, _) => { - return Err(EvaluationFailure::NoSolution); + ty::CoroutineClosure(_, _) => return Err(EvaluationFailure::NoSolution), + + ty::Closure(def, args) => { + // For now we limit ourselves to closures without binders. The next solver can handle them. + let sig = + args.as_closure().sig().no_bound_vars().ok_or(EvaluationFailure::NoSolution)?; + ( + def, + tcx.mk_args_from_iter( + [ty::GenericArg::from(*sig.inputs().get(0).unwrap()), sig.output().into()] + .into_iter(), + ), + ) } // Everything else needs explicit impls or cannot have an impl diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index e77e7af071b90..25f7c36e9985d 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -308,6 +308,7 @@ pub trait Interner: fn impl_is_const(self, def_id: Self::ImplId) -> bool; fn fn_is_const(self, def_id: Self::FunctionId) -> bool; + fn closure_is_const(self, def_id: Self::ClosureId) -> bool; fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool; fn const_conditions( self, diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 39e374174646c..0d96958b6cca1 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -16,7 +16,7 @@ use crate::io; use crate::os::hermit::io::OwnedFd; #[cfg(all(not(target_os = "hermit"), not(target_os = "motor")))] use crate::os::raw; -#[cfg(all(doc, not(target_arch = "wasm32")))] +#[cfg(all(doc, not(any(target_arch = "wasm32", target_env = "sgx"))))] use crate::os::unix::io::AsFd; #[cfg(unix)] use crate::os::unix::io::OwnedFd; diff --git a/library/std/src/sys/net/connection/sgx.rs b/library/std/src/sys/net/connection/sgx.rs index 8c9c17d3f1714..6a625664494b5 100644 --- a/library/std/src/sys/net/connection/sgx.rs +++ b/library/std/src/sys/net/connection/sgx.rs @@ -68,8 +68,8 @@ impl fmt::Debug for TcpStream { /// /// SGX doesn't support DNS resolution but rather accepts hostnames in /// the same place as socket addresses. So, to make e.g. -/// ```rust -/// TcpStream::connect("example.com:80")` +/// ```rust,ignore (incomplete example) +/// TcpStream::connect("example.com:80") /// ``` /// work, the DNS lookup returns a special error (`NonIpSockAddr`) instead, /// which contains the hostname being looked up. When `.to_socket_addrs()` diff --git a/tests/incremental/const-generic-type-cycle.rs b/tests/incremental/const-generic-type-cycle.rs index 5bcbc1d5dafef..85b8092787e2c 100644 --- a/tests/incremental/const-generic-type-cycle.rs +++ b/tests/incremental/const-generic-type-cycle.rs @@ -13,7 +13,5 @@ trait Bar {} #[cfg(cfail)] trait Bar {} //[cfail]~^ ERROR cycle detected when computing type of `Bar::N` -//[cfail]~| ERROR cycle detected when computing type of `Bar::N` -//[cfail]~| ERROR `(dyn Bar<{ 2 + 1 }> + 'static)` is forbidden as the type of a const generic parameter trait BB = Bar<{ 2 + 1 }>; diff --git a/tests/ui/consts/issue-103790.rs b/tests/ui/consts/issue-103790.rs index 869a43e4018b3..a85833a565372 100644 --- a/tests/ui/consts/issue-103790.rs +++ b/tests/ui/consts/issue-103790.rs @@ -5,6 +5,5 @@ struct S; //~^ ERROR the name `S` is already used for a generic parameter in this item's generic parameters //~| ERROR missing generics for struct `S` //~| ERROR cycle detected when computing type of `S::S` -//~| ERROR `()` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/consts/issue-103790.stderr b/tests/ui/consts/issue-103790.stderr index adfac02bd0ceb..e442c64e70ce1 100644 --- a/tests/ui/consts/issue-103790.stderr +++ b/tests/ui/consts/issue-103790.stderr @@ -36,19 +36,7 @@ LL | struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: `()` is forbidden as the type of a const generic parameter - --> $DIR/issue-103790.rs:4:19 - | -LL | struct S; - | ^^ - | - = note: the only supported types are integers, `bool`, and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0107, E0391, E0403. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/delegation/unsupported.current.stderr b/tests/ui/delegation/unsupported.current.stderr index 9bc2eec068fef..657f990271734 100644 --- a/tests/ui/delegation/unsupported.current.stderr +++ b/tests/ui/delegation/unsupported.current.stderr @@ -29,18 +29,13 @@ note: ...which requires comparing an impl and trait method signature, inferring LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle - = note: cycle used when checking effective visibilities - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error[E0283]: type annotations needed - --> $DIR/unsupported.rs:54:18 - | -LL | reuse Trait::foo; - | ^^^ cannot infer type +note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition + --> $DIR/unsupported.rs:33:24 | - = note: cannot satisfy `_: effects::Trait` +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0283, E0391. -For more information about an error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/delegation/unsupported.next.stderr b/tests/ui/delegation/unsupported.next.stderr index 08bc49513bad5..90b17752cd8b1 100644 --- a/tests/ui/delegation/unsupported.next.stderr +++ b/tests/ui/delegation/unsupported.next.stderr @@ -25,18 +25,9 @@ note: ...which requires comparing an impl and trait method signature, inferring LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle - = note: cycle used when checking effective visibilities + = note: cycle used when computing implied outlives bounds for `::opaque_ret::{anon_assoc#0}` (hack disabled = false) = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0283]: type annotations needed - --> $DIR/unsupported.rs:54:18 - | -LL | reuse Trait::foo; - | ^^^ cannot infer type - | - = note: cannot satisfy `_: effects::Trait` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0283, E0391. -For more information about an error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs index 1681888e34ea6..adb798aab71d0 100644 --- a/tests/ui/delegation/unsupported.rs +++ b/tests/ui/delegation/unsupported.rs @@ -52,7 +52,6 @@ mod effects { } reuse Trait::foo; - //~^ ERROR type annotations needed } fn main() {} diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr index f0a20367a4a1a..87640517ddb20 100644 --- a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr @@ -57,66 +57,6 @@ LL | fn foo(b: bool) -> impl Sized { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `::foo::{anon_assoc#0}` - --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^ - | -note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires computing type of `::foo::{opaque#0}`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^ -note: ...which requires computing type of opaque `::foo::{opaque#0}`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^ -note: ...which requires borrow-checking `::foo`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires promoting constants in MIR for `::foo`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires checking if `::foo` contains FFI-unwind calls... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `::foo`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires match-checking `::foo`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `::foo`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `::foo::{anon_assoc#0}`, completing the cycle -note: cycle used when checking assoc item `::foo` is compatible with trait definition - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/issues/issue-34373.rs b/tests/ui/issues/issue-34373.rs index 765bfc20a4517..a9bd79f6830b8 100644 --- a/tests/ui/issues/issue-34373.rs +++ b/tests/ui/issues/issue-34373.rs @@ -6,7 +6,6 @@ trait Trait { pub struct Foo>>; //~^ ERROR cycle detected when computing type of `Foo::T` -//~| ERROR type parameter `T` is never used type DefaultFoo = Foo; fn main() { diff --git a/tests/ui/issues/issue-34373.stderr b/tests/ui/issues/issue-34373.stderr index 6d68de8fb3b8a..995f2f4022b62 100644 --- a/tests/ui/issues/issue-34373.stderr +++ b/tests/ui/issues/issue-34373.stderr @@ -5,7 +5,7 @@ LL | pub struct Foo>>; | ^^^^^^^^^^ | note: ...which requires expanding type alias `DefaultFoo`... - --> $DIR/issue-34373.rs:10:19 + --> $DIR/issue-34373.rs:9:19 | LL | type DefaultFoo = Foo; | ^^^ @@ -17,16 +17,6 @@ LL | pub struct Foo>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0392]: type parameter `T` is never used - --> $DIR/issue-34373.rs:7:16 - | -LL | pub struct Foo>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused type parameter - | - = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0391, E0392. -For more information about an error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/moves/move-1-unique.rs b/tests/ui/moves/move-1-unique.rs deleted file mode 100644 index c97bfaaaf1a5a..0000000000000 --- a/tests/ui/moves/move-1-unique.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ run-pass -#![allow(unused_mut)] -#![allow(dead_code)] - -#[derive(Clone)] -struct Triple { - x: isize, - y: isize, - z: isize, -} - -fn test(x: bool, foo: Box) -> isize { - let bar = foo; - let mut y: Box; - if x { y = bar; } else { y = Box::new(Triple{x: 4, y: 5, z: 6}); } - return y.y; -} - -pub fn main() { - let x: Box<_> = Box::new(Triple{x: 1, y: 2, z: 3}); - assert_eq!(test(true, x.clone()), 2); - assert_eq!(test(true, x.clone()), 2); - assert_eq!(test(true, x.clone()), 2); - assert_eq!(test(false, x), 5); -} diff --git a/tests/ui/moves/move-2-unique.rs b/tests/ui/moves/move-2-unique.rs deleted file mode 100644 index 2204ea95741db..0000000000000 --- a/tests/ui/moves/move-2-unique.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -struct X { x: isize, y: isize, z: isize } - -pub fn main() { - let x: Box<_> = Box::new(X {x: 1, y: 2, z: 3}); - let y = x; - assert_eq!(y.y, 2); -} diff --git a/tests/ui/moves/move-4-unique.rs b/tests/ui/moves/move-4-unique.rs deleted file mode 100644 index 09e0f11a8b442..0000000000000 --- a/tests/ui/moves/move-4-unique.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -struct Triple {a: isize, b: isize, c: isize} - -fn test(foo: Box) -> Box { - let foo = foo; - let bar = foo; - let baz = bar; - let quux = baz; - return quux; -} - -pub fn main() { - let x = Box::new(Triple{a: 1, b: 2, c: 3}); - let y = test(x); - assert_eq!(y.c, 3); -} diff --git a/tests/ui/moves/move-arg-2-unique.rs b/tests/ui/moves/move-arg-2-unique.rs deleted file mode 100644 index d9a03be0ed2dc..0000000000000 --- a/tests/ui/moves/move-arg-2-unique.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ run-pass - -fn test(foo: Box> ) { assert_eq!((*foo)[0], 10); } - -pub fn main() { - let x = Box::new(vec![10]); - // Test forgetting a local by move-in - test(x); - - // Test forgetting a temporary by move-in. - test(Box::new(vec![10])); -} diff --git a/tests/ui/moves/move-scalar.rs b/tests/ui/moves/move-scalar.rs deleted file mode 100644 index e8cf5632b322a..0000000000000 --- a/tests/ui/moves/move-scalar.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -#![allow(unused_mut)] - -pub fn main() { - - let y: isize = 42; - let mut x: isize; - x = y; - assert_eq!(x, 42); -} diff --git a/tests/ui/traits/const-traits/call-const-closure.stderr b/tests/ui/traits/const-traits/call-const-closure.next.stderr similarity index 82% rename from tests/ui/traits/const-traits/call-const-closure.stderr rename to tests/ui/traits/const-traits/call-const-closure.next.stderr index 9a851a97f186a..16b936d58aaf6 100644 --- a/tests/ui/traits/const-traits/call-const-closure.stderr +++ b/tests/ui/traits/const-traits/call-const-closure.next.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `(): [const] Bar` is not satisfied +error[E0277]: the trait bound `(): const Bar` is not satisfied --> $DIR/call-const-closure.rs:16:18 | LL | (const || ().foo())(); diff --git a/tests/ui/traits/const-traits/call-const-closure.old.stderr b/tests/ui/traits/const-traits/call-const-closure.old.stderr new file mode 100644 index 0000000000000..16b936d58aaf6 --- /dev/null +++ b/tests/ui/traits/const-traits/call-const-closure.old.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `(): const Bar` is not satisfied + --> $DIR/call-const-closure.rs:16:18 + | +LL | (const || ().foo())(); + | ^^^ + | +help: make the `impl` of trait `Bar` `const` + | +LL | impl const Bar for () { + | +++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/call-const-closure.rs b/tests/ui/traits/const-traits/call-const-closure.rs index c4293579aea8e..2cf561ae6db14 100644 --- a/tests/ui/traits/const-traits/call-const-closure.rs +++ b/tests/ui/traits/const-traits/call-const-closure.rs @@ -1,8 +1,8 @@ -//@ compile-flags: -Znext-solver +//@[next] compile-flags: -Znext-solver +//@ revisions: next old //@ edition:2021 #![feature(const_trait_impl, const_closures)] -#![allow(incomplete_features)] const trait Bar { fn foo(&self); @@ -14,8 +14,7 @@ impl Bar for () { const FOO: () = { (const || ().foo())(); - //~^ ERROR the trait bound `(): [const] Bar` is not satisfied - // FIXME(const_trait_impl): The constness environment for const closures is wrong. + //~^ ERROR the trait bound `(): const Bar` is not satisfied }; fn main() {} diff --git a/tests/ui/traits/const-traits/call.rs b/tests/ui/traits/const-traits/call.rs index 360c08e1b7fe9..71dea1ef4e049 100644 --- a/tests/ui/traits/const-traits/call.rs +++ b/tests/ui/traits/const-traits/call.rs @@ -1,11 +1,10 @@ -// FIXME(const_trait_impl) check-pass -//@ compile-flags: -Znext-solver +//@ check-pass +//@[next] compile-flags: -Znext-solver +//@revisions: next old #![feature(const_closures, const_trait_impl)] -#![allow(incomplete_features)] const _: () = { assert!((const || true)()); - //~^ ERROR }: [const] Fn()` is not satisfied }; fn main() {} diff --git a/tests/ui/traits/const-traits/call.stderr b/tests/ui/traits/const-traits/call.stderr deleted file mode 100644 index 8e32cab6dfcfb..0000000000000 --- a/tests/ui/traits/const-traits/call.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0277]: the trait bound `{closure@$DIR/call.rs:7:14: 7:22}: [const] Fn()` is not satisfied - --> $DIR/call.rs:7:13 - | -LL | assert!((const || true)()); - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs b/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs index 7a44920bb729d..55fae27eb6dd7 100644 --- a/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs +++ b/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs @@ -1,4 +1,3 @@ -#![allow(incomplete_features)] #![feature(const_closures, const_trait_impl)] const fn create_array(mut f: impl FnMut(usize) -> u32 + Copy) -> [u32; N] { @@ -16,9 +15,9 @@ const fn create_array(mut f: impl FnMut(usize) -> u32 + Copy) -> } fn main() { - let x = create_array(const |i| 2 * i as u32); + let x = const { create_array(const |i| 2 * i as u32) }; assert_eq!(x, [0, 2, 4, 6, 8]); - let y = create_array(const |i| 2 * i as u32 + 1); + let y = const { create_array(const |i| 2 * i as u32 + 1) }; assert_eq!(y, [1, 3, 5, 7, 9]); } diff --git a/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr b/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr index 1eadd1d842691..448b343e2caa4 100644 --- a/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr +++ b/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `impl FnMut(usize) -> u32 + Copy: [const] FnMut(usize)` is not satisfied - --> $DIR/const-closure-issue-125866-error.rs:8:22 + --> $DIR/const-closure-issue-125866-error.rs:7:22 | LL | array[i] = f(i); | - ^ diff --git a/tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs b/tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs deleted file mode 100644 index af7375172e674..0000000000000 --- a/tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ check-pass - -#![allow(incomplete_features)] -#![feature(const_closures, const_trait_impl)] - -const fn create_array(mut f: impl [const] FnMut(usize) -> u32 + Copy) -> [u32; N] { - let mut array = [0; N]; - let mut i = 0; - loop { - array[i] = f(i); - i += 1; - if i == N { - break; - } - } - array -} - -fn main() { - let x = create_array(const |i| 2 * i as u32); - assert_eq!(x, [0, 2, 4, 6, 8]); - - let y = create_array(const |i| 2 * i as u32 + 1); - assert_eq!(y, [1, 3, 5, 7, 9]); -} diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.rs b/tests/ui/traits/const-traits/const-closure-parse-not-item.rs index 35127eda5c039..ce20b05a8133c 100644 --- a/tests/ui/traits/const-traits/const-closure-parse-not-item.rs +++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.rs @@ -1,8 +1,6 @@ -//@ known-bug: #110395 -// FIXME check-pass +//@check-pass #![feature(const_trait_impl, const_closures)] -#![allow(incomplete_features)] const fn test() -> impl [const] Fn() { const move || {} diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr deleted file mode 100644 index 1d8d5ff1b4f2e..0000000000000 --- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0277]: the trait bound `{closure@$DIR/const-closure-parse-not-item.rs:8:5: 8:18}: [const] Fn()` is not satisfied - --> $DIR/const-closure-parse-not-item.rs:7:20 - | -LL | const fn test() -> impl [const] Fn() { - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs deleted file mode 100644 index e355ee724d1bd..0000000000000 --- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #110395 -//@ compile-flags: -Znext-solver -#![feature(const_closures, const_trait_impl)] -#![allow(incomplete_features)] - -trait Foo { - fn foo(&self); -} - -impl Foo for () { - fn foo(&self) {} -} - -fn main() { - (const || (()).foo())(); -} diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr deleted file mode 100644 index dab3f14161fac..0000000000000 --- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0277]: the trait bound `{closure@$DIR/const_closure-const_trait_impl-ice-113381.rs:15:6: 15:14}: [const] Fn()` is not satisfied - --> $DIR/const_closure-const_trait_impl-ice-113381.rs:15:5 - | -LL | (const || (()).foo())(); - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/gate.rs b/tests/ui/traits/const-traits/gate.rs index 3f348c8413930..c9f56df35531f 100644 --- a/tests/ui/traits/const-traits/gate.rs +++ b/tests/ui/traits/const-traits/gate.rs @@ -1,13 +1,14 @@ // gate-test-const_closures fn main() { - (const || {})(); + const { (const || {})() }; //~^ ERROR: const closures are experimental - //~| ERROR: the trait bound `{closure@$DIR/gate.rs:4:6: 4:14}: [const] Fn()` is not satisfied + //~| ERROR: cannot call conditionally-const closure in constants + //~| ERROR: `Fn` is not yet stable as a const trait } macro_rules! e { - ($e:expr) => {} + ($e:expr) => {}; } e!((const || {})); diff --git a/tests/ui/traits/const-traits/gate.stderr b/tests/ui/traits/const-traits/gate.stderr index 6bef2c511ce7d..788878292b6ff 100644 --- a/tests/ui/traits/const-traits/gate.stderr +++ b/tests/ui/traits/const-traits/gate.stderr @@ -1,15 +1,15 @@ error[E0658]: const closures are experimental - --> $DIR/gate.rs:4:6 + --> $DIR/gate.rs:4:14 | -LL | (const || {})(); - | ^^^^^ +LL | const { (const || {})() }; + | ^^^^^ | = note: see issue #106003 for more information = help: add `#![feature(const_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: const closures are experimental - --> $DIR/gate.rs:13:5 + --> $DIR/gate.rs:14:5 | LL | e!((const || {})); | ^^^^^ @@ -18,13 +18,29 @@ LL | e!((const || {})); = help: add `#![feature(const_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0277]: the trait bound `{closure@$DIR/gate.rs:4:6: 4:14}: [const] Fn()` is not satisfied - --> $DIR/gate.rs:4:5 +error[E0658]: cannot call conditionally-const closure in constants + --> $DIR/gate.rs:4:13 + | +LL | const { (const || {})() }; + | ^^^^^^^^^^^^^^^ + | + = note: closures need an RFC before allowed to be called in constants + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: see issue #143874 for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: `Fn` is not yet stable as a const trait + --> $DIR/gate.rs:4:13 + | +LL | const { (const || {})() }; + | ^^^^^^^^^^^^^^^ + | +help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + | +LL + #![feature(const_trait_impl)] | -LL | (const || {})(); - | ^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0658. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs index 8ee3db445d072..1f35abbb9d6af 100644 --- a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs +++ b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs @@ -1,14 +1,13 @@ -#![feature(const_trait_impl)] +#![feature(const_trait_impl, const_closures, const_cmp)] const fn test() -> impl [const] Fn() { - //~^ ERROR: }: [const] Fn()` is not satisfied - const move || { //~ ERROR const closures are experimental + const move || { let sl: &[u8] = b"foo"; match sl { [first, remainder @ ..] => { assert_eq!(first, &b'f'); - // FIXME(const_closures) ^ ERROR cannot call non-const function + //~^ ERROR cannot call non-const function } [] => panic!(), } diff --git a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr index abbe0a0070aa2..73340f15cbb8a 100644 --- a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr +++ b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr @@ -1,20 +1,13 @@ -error[E0658]: const closures are experimental - --> $DIR/ice-112822-expected-type-for-param.rs:5:5 +error[E0015]: cannot call non-const function `core::panicking::assert_failed::<&u8, &u8>` in constant functions + --> $DIR/ice-112822-expected-type-for-param.rs:9:17 | -LL | const move || { - | ^^^^^ +LL | assert_eq!(first, &b'f'); + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #106003 for more information - = help: add `#![feature(const_closures)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +note: function `assert_failed` is not const + --> $SRC_DIR/core/src/panicking.rs:LL:COL + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error[E0277]: the trait bound `{closure@$DIR/ice-112822-expected-type-for-param.rs:5:5: 5:18}: [const] Fn()` is not satisfied - --> $DIR/ice-112822-expected-type-for-param.rs:3:20 - | -LL | const fn test() -> impl [const] Fn() { - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0277, E0658. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs index de5bedf0ace76..58402cbaec81b 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs @@ -1,5 +1,4 @@ #![feature(const_closures, const_trait_impl)] -#![allow(incomplete_features)] trait Foo { fn foo(&self); @@ -13,5 +12,5 @@ fn main() { // #150052 deduplicate diagnostics for const trait supertraits // so we only get one error here (const || { (()).foo() })(); - //~^ ERROR: }: [const] Fn()` is not satisfied + //~^ ERROR: cannot use `const` closures outside of const contexts } diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr index efbedca1c7e7f..f5521b90cc2d9 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr @@ -1,9 +1,8 @@ -error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:15:6: 15:14}: [const] Fn()` is not satisfied - --> $DIR/non-const-op-const-closure-non-const-outer.rs:15:5 +error: cannot use `const` closures outside of const contexts + --> $DIR/non-const-op-const-closure-non-const-outer.rs:14:6 | LL | (const || { (()).foo() })(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs index 072a699a6b5b9..732a5c334e50d 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs @@ -4,7 +4,6 @@ trait Trait { fn fnc(&self) -> dyn Trait { //~^ ERROR the name `N` is already used for a generic parameter in this item's generic parameters //~| ERROR expected value, found builtin type `u32` - //~| ERROR defaults for generic parameters are not allowed here bar //~^ ERROR cannot find value `bar` in this scope } diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr index 47f3e83fae21a..ce567b9043f06 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr @@ -20,7 +20,7 @@ LL | fn fnc(&self) -> dyn Trait { | ^^^ not a value error[E0425]: cannot find value `bar` in this scope - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:8:9 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:7:9 | LL | bar | ^^^ not found in this scope @@ -39,13 +39,7 @@ LL | trait Trait { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: defaults for generic parameters are not allowed here - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:12 - | -LL | fn fnc(&self) -> dyn Trait { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0391, E0403, E0423, E0425. For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs index 13d7a800c51fd..f2b9f037ea5f3 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs @@ -4,13 +4,11 @@ trait Foo> { //~^ WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! //~| ERROR cycle detected when computing type of `Foo::N` - //~| ERROR `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter fn func() {} } trait Bar> {} //~^ WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! -//~| ERROR `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr index f9a855d3b93b7..4024f57af4ffd 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr @@ -13,7 +13,7 @@ LL | trait Foo> { | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:10:20 | LL | trait Bar> {} | ^^^^^^ @@ -32,7 +32,7 @@ LL | trait Foo> { | ^^^^^^^^^^^^^^^ | note: ...which requires computing type of `Bar::M`... - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:10:11 | LL | trait Bar> {} | ^^^^^^^^^^^^^^^ @@ -44,22 +44,6 @@ LL | trait Foo> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:3:20 - | -LL | trait Foo> { - | ^^^^^^ - | - = note: the only supported types are integers, `bool`, and `char` - -error: `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic parameter - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20 - | -LL | trait Bar> {} - | ^^^^^^ - | - = note: the only supported types are integers, `bool`, and `char` - -error: aborting due to 3 previous errors; 2 warnings emitted +error: aborting due to 1 previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0391`.