diff --git a/RELEASES.md b/RELEASES.md index 766cf64410c77..e6512bb6f6de9 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -47,8 +47,6 @@ Stabilized APIs - [`<*mut T>::cast`] - [`Duration::as_secs_f32`] - [`Duration::as_secs_f64`] -- [`Duration::div_duration_f32`] -- [`Duration::div_duration_f64`] - [`Duration::div_f32`] - [`Duration::div_f64`] - [`Duration::from_secs_f32`] @@ -100,8 +98,6 @@ Compatibility Notes [`<*mut T>::cast`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast [`Duration::as_secs_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_secs_f32 [`Duration::as_secs_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_secs_f64 -[`Duration::div_duration_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_duration_f32 -[`Duration::div_duration_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_duration_f64 [`Duration::div_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_f32 [`Duration::div_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_f64 [`Duration::from_secs_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.from_secs_f32 diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 956cb36c6b139..d2cae4719d935 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -23,8 +23,6 @@ use syntax::source_map::Spanned; use syntax::ext::base::MacroKind; use syntax_pos::{Span, DUMMY_SP}; -use std::result::Result::Err; - pub mod blocks; mod collector; mod def_collector; @@ -183,6 +181,44 @@ pub struct Map<'hir> { hir_to_node_id: FxHashMap, } +struct ParentHirIterator<'map> { + current_id: HirId, + map: &'map Map<'map>, +} + +impl<'map> ParentHirIterator<'map> { + fn new(current_id: HirId, map: &'map Map<'map>) -> ParentHirIterator<'map> { + ParentHirIterator { + current_id, + map, + } + } +} + +impl<'map> Iterator for ParentHirIterator<'map> { + type Item = (HirId, Node<'map>); + + fn next(&mut self) -> Option { + if self.current_id == CRATE_HIR_ID { + return None; + } + loop { // There are nodes that do not have entries, so we need to skip them. + let parent_id = self.map.get_parent_node(self.current_id); + + if parent_id == self.current_id { + self.current_id = CRATE_HIR_ID; + return None; + } + + self.current_id = parent_id; + if let Some(entry) = self.map.find_entry(parent_id) { + return Some((parent_id, entry.node)); + } + // If this `HirId` doesn't have an `Entry`, skip it and look for its `parent_id`. + } + } +} + impl<'hir> Map<'hir> { #[inline] fn lookup(&self, id: HirId) -> Option<&Entry<'hir>> { @@ -682,45 +718,6 @@ impl<'hir> Map<'hir> { } } - - /// If there is some error when walking the parents (e.g., a node does not - /// have a parent in the map or a node can't be found), then we return the - /// last good `HirId` we found. Note that reaching the crate root (`id == 0`), - /// is not an error, since items in the crate module have the crate root as - /// parent. - fn walk_parent_nodes(&self, - start_id: HirId, - found: F, - bail_early: F2) - -> Result - where F: Fn(&Node<'hir>) -> bool, F2: Fn(&Node<'hir>) -> bool - { - let mut id = start_id; - loop { - let parent_id = self.get_parent_node(id); - if parent_id == CRATE_HIR_ID { - return Ok(CRATE_HIR_ID); - } - if parent_id == id { - return Err(id); - } - - if let Some(entry) = self.find_entry(parent_id) { - if let Node::Crate = entry.node { - return Err(id); - } - if found(&entry.node) { - return Ok(parent_id); - } else if bail_early(&entry.node) { - return Err(parent_id); - } - id = parent_id; - } else { - return Err(id); - } - } - } - /// Retrieves the `HirId` for `id`'s enclosing method, unless there's a /// `while` or `loop` before reaching it, as block tail returns are not /// available in them. @@ -744,29 +741,46 @@ impl<'hir> Map<'hir> { /// } /// ``` pub fn get_return_block(&self, id: HirId) -> Option { - let match_fn = |node: &Node<'_>| { - match *node { + let mut iter = ParentHirIterator::new(id, &self).peekable(); + let mut ignore_tail = false; + if let Some(entry) = self.find_entry(id) { + if let Node::Expr(Expr { node: ExprKind::Ret(_), .. }) = entry.node { + // When dealing with `return` statements, we don't care about climbing only tail + // expressions. + ignore_tail = true; + } + } + while let Some((hir_id, node)) = iter.next() { + if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) { + match next_node { + Node::Block(Block { expr: None, .. }) => return None, + Node::Block(Block { expr: Some(expr), .. }) => { + if hir_id != expr.hir_id { + // The current node is not the tail expression of its parent. + return None; + } + } + _ => {} + } + } + match node { Node::Item(_) | Node::ForeignItem(_) | Node::TraitItem(_) | Node::Expr(Expr { node: ExprKind::Closure(..), ..}) | - Node::ImplItem(_) => true, - _ => false, - } - }; - let match_non_returning_block = |node: &Node<'_>| { - match *node { + Node::ImplItem(_) => return Some(hir_id), Node::Expr(ref expr) => { match expr.node { - ExprKind::Loop(..) | ExprKind::Ret(..) => true, - _ => false, + // Ignore `return`s on the first iteration + ExprKind::Ret(..) | ExprKind::Loop(..) => return None, + _ => {} } } - _ => false, + Node::Local(_) => return None, + _ => {} } - }; - - self.walk_parent_nodes(id, match_fn, match_non_returning_block).ok() + } + None } /// Retrieves the `HirId` for `id`'s parent item, or `id` itself if no @@ -774,16 +788,17 @@ impl<'hir> Map<'hir> { /// in the HIR which is recorded by the map and is an item, either an item /// in a module, trait, or impl. pub fn get_parent_item(&self, hir_id: HirId) -> HirId { - match self.walk_parent_nodes(hir_id, |node| match *node { - Node::Item(_) | - Node::ForeignItem(_) | - Node::TraitItem(_) | - Node::ImplItem(_) => true, - _ => false, - }, |_| false) { - Ok(id) => id, - Err(id) => id, + for (hir_id, node) in ParentHirIterator::new(hir_id, &self) { + match node { + Node::Crate | + Node::Item(_) | + Node::ForeignItem(_) | + Node::TraitItem(_) | + Node::ImplItem(_) => return hir_id, + _ => {} + } } + hir_id } /// Returns the `DefId` of `id`'s nearest module parent, or `id` itself if no @@ -795,60 +810,64 @@ impl<'hir> Map<'hir> { /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no /// module parent is in this map. pub fn get_module_parent_node(&self, hir_id: HirId) -> HirId { - match self.walk_parent_nodes(hir_id, |node| match *node { - Node::Item(&Item { node: ItemKind::Mod(_), .. }) => true, - _ => false, - }, |_| false) { - Ok(id) => id, - Err(id) => id, + for (hir_id, node) in ParentHirIterator::new(hir_id, &self) { + if let Node::Item(&Item { node: ItemKind::Mod(_), .. }) = node { + return hir_id; + } } + CRATE_HIR_ID } /// Returns the nearest enclosing scope. A scope is roughly an item or block. pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option { - self.walk_parent_nodes(hir_id, |node| match *node { - Node::Item(i) => { - match i.node { - ItemKind::Fn(..) - | ItemKind::Mod(..) - | ItemKind::Enum(..) - | ItemKind::Struct(..) - | ItemKind::Union(..) - | ItemKind::Trait(..) - | ItemKind::Impl(..) => true, - _ => false, - } - }, - Node::ForeignItem(fi) => { - match fi.node { - ForeignItemKind::Fn(..) => true, - _ => false, - } - }, - Node::TraitItem(ti) => { - match ti.node { - TraitItemKind::Method(..) => true, - _ => false, - } - }, - Node::ImplItem(ii) => { - match ii.node { - ImplItemKind::Method(..) => true, - _ => false, - } - }, - Node::Block(_) => true, - _ => false, - }, |_| false).ok() + for (hir_id, node) in ParentHirIterator::new(hir_id, &self) { + if match node { + Node::Item(i) => { + match i.node { + ItemKind::Fn(..) + | ItemKind::Mod(..) + | ItemKind::Enum(..) + | ItemKind::Struct(..) + | ItemKind::Union(..) + | ItemKind::Trait(..) + | ItemKind::Impl(..) => true, + _ => false, + } + }, + Node::ForeignItem(fi) => { + match fi.node { + ForeignItemKind::Fn(..) => true, + _ => false, + } + }, + Node::TraitItem(ti) => { + match ti.node { + TraitItemKind::Method(..) => true, + _ => false, + } + }, + Node::ImplItem(ii) => { + match ii.node { + ImplItemKind::Method(..) => true, + _ => false, + } + }, + Node::Block(_) => true, + _ => false, + } { + return Some(hir_id); + } + } + None } /// Returns the defining scope for an opaque type definition. - pub fn get_defining_scope(&self, id: HirId) -> Option { + pub fn get_defining_scope(&self, id: HirId) -> HirId { let mut scope = id; loop { - scope = self.get_enclosing_scope(scope)?; + scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID); if scope == CRATE_HIR_ID { - return Some(CRATE_HIR_ID); + return CRATE_HIR_ID; } match self.get(scope) { Node::Item(i) => { @@ -861,7 +880,7 @@ impl<'hir> Map<'hir> { _ => break, } } - Some(scope) + scope } pub fn get_parent_did(&self, id: HirId) -> DefId { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 6fdc126e216aa..97c3e85cf9807 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1563,7 +1563,7 @@ pub enum ExprKind { /// Thus, `x.foo::(a, b, c, d)` is represented as /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`. MethodCall(P, Span, HirVec), - /// A tuple (e.g., `(a, b, c ,d)`). + /// A tuple (e.g., `(a, b, c, d)`). Tup(HirVec), /// A binary operation (e.g., `a + b`, `a * b`). Binary(BinOp, P, P), diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 0b746e5dfb623..512d91f8d2646 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -1215,7 +1215,7 @@ pub fn may_define_opaque_type( let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); // Named opaque types can be defined by any siblings or children of siblings. - let scope = tcx.hir().get_defining_scope(opaque_hir_id).expect("could not get defining scope"); + let scope = tcx.hir().get_defining_scope(opaque_hir_id); // We walk up the node tree until we hit the root or the scope of the opaque type. while hir_id != scope && hir_id != hir::CRATE_HIR_ID { hir_id = tcx.hir().get_parent_item(hir_id); diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index ac99ccd45eafe..71967b513a049 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -389,6 +389,10 @@ pub enum UnsupportedOpInfo<'tcx> { /// Free-form case. Only for errors that are never caught! Unsupported(String), + /// FIXME(#64506) Error used to work around accessing projections of + /// uninhabited types. + UninhabitedValue, + // -- Everything below is not categorized yet -- FunctionAbiMismatch(Abi, Abi), FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>), @@ -552,6 +556,8 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { not a power of two"), Unsupported(ref msg) => write!(f, "{}", msg), + UninhabitedValue => + write!(f, "tried to use an uninhabited value"), } } } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 039973d80dbf1..4696d4da58ec0 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -378,7 +378,15 @@ fn orphan_check_trait_ref<'tcx>( // Let Ti be the first such type. // - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti) // - for input_ty in trait_ref.input_types() { + fn uncover_fundamental_ty(ty: Ty<'_>) -> Vec> { + if fundamental_ty(ty) { + ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(ty)).collect() + } else { + vec![ty] + } + } + + for input_ty in trait_ref.input_types().flat_map(uncover_fundamental_ty) { debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty); if ty_is_local(tcx, input_ty, in_crate) { debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index a1828bb5ab7a7..d3e6789b826a9 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -15,6 +15,7 @@ use errors::DiagnosticBuilder; use errors::Level; use errors::Diagnostic; use errors::FatalError; +use errors::Handler; use rustc_data_structures::fx::{FxHashMap}; use rustc_data_structures::sync::{Lrc, Lock}; use rustc_data_structures::sharded::Sharded; @@ -321,9 +322,12 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn try_print_query_stack() { + pub fn try_print_query_stack(handler: &Handler) { eprintln!("query stack during panic:"); + // Be careful reyling on global state here: this code is called from + // a panic hook, which means that the global `Handler` may be in a weird + // state if it was responsible for triggering the panic. tls::with_context_opt(|icx| { if let Some(icx) = icx { let mut current_query = icx.query.clone(); @@ -336,7 +340,7 @@ impl<'tcx> TyCtxt<'tcx> { query.info.query.name(), query.info.query.describe(icx.tcx))); diag.span = icx.tcx.sess.source_map().def_span(query.info.span).into(); - icx.tcx.sess.diagnostic().force_print_diagnostic(diag); + handler.force_print_diagnostic(diag); current_query = query.parent.clone(); i += 1; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 4a8681367410e..d0a319df2e6dc 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1231,7 +1231,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); if backtrace { - TyCtxt::try_print_query_stack(); + TyCtxt::try_print_query_stack(&handler); } #[cfg(windows)] diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index ca238867421ab..bb02b99dd8d87 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -21,7 +21,7 @@ use syntax::source_map::{Span, DUMMY_SP}; use crate::interpret::{self, PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, Pointer, - RawConst, ConstValue, + RawConst, ConstValue, Machine, InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup, Allocation, AllocId, MemoryKind, Memory, snapshot, RefTracking, intern_const_alloc_recursive, @@ -41,7 +41,7 @@ const DETECTOR_SNAPSHOT_PERIOD: isize = 256; /// that inform us about the generic bounds of the constant. E.g., using an associated constant /// of a function's generic parameter will require knowledge about the bounds on the generic /// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. -pub(crate) fn mk_eval_cx<'mir, 'tcx>( +fn mk_eval_cx<'mir, 'tcx>( tcx: TyCtxt<'tcx>, span: Span, param_env: ty::ParamEnv<'tcx>, @@ -169,7 +169,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( } #[derive(Clone, Debug)] -enum ConstEvalError { +pub enum ConstEvalError { NeedsRfc(String), } @@ -521,8 +521,8 @@ pub fn const_variant_index<'tcx>( /// Turn an interpreter error into something to report to the user. /// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace. /// Should be called only if the error is actually going to to be reported! -pub fn error_to_const_error<'mir, 'tcx>( - ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, +pub fn error_to_const_error<'mir, 'tcx, M: Machine<'mir, 'tcx>>( + ecx: &InterpCx<'mir, 'tcx, M>, mut error: InterpErrorInfo<'tcx>, ) -> ConstEvalErr<'tcx> { error.print_backtrace(); diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index bb74a50156e56..c30c59bbf10c8 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -12,6 +12,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use super::{ Allocation, AllocId, InterpResult, Scalar, AllocationExtra, InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory, + Frame, Operand, }; /// Whether this kind of memory is allowed to leak @@ -184,6 +185,22 @@ pub trait Machine<'mir, 'tcx>: Sized { dest: PlaceTy<'tcx, Self::PointerTag>, ) -> InterpResult<'tcx>; + /// Called to read the specified `local` from the `frame`. + fn access_local( + _ecx: &InterpCx<'mir, 'tcx, Self>, + frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + local: mir::Local, + ) -> InterpResult<'tcx, Operand> { + frame.locals[local].access() + } + + /// Called before a `StaticKind::Static` value is accessed. + fn before_access_static( + _allocation: &Allocation, + ) -> InterpResult<'tcx> { + Ok(()) + } + /// Called to initialize the "extra" state of an allocation and make the pointers /// it contains (in relocations) tagged. The way we construct allocations is /// to always first construct it without extra and then add the extra. diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 62b1760508b4c..924474c53175c 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -462,6 +462,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // Make sure we use the ID of the resolved memory, not the lazy one! let id = raw_const.alloc_id; let allocation = tcx.alloc_map.lock().unwrap_memory(id); + + M::before_access_static(allocation)?; Cow::Borrowed(allocation) } } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index f5d1ec3eb7556..861e5ebef877d 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -458,7 +458,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Do not read from ZST, they might not be initialized Operand::Immediate(Scalar::zst().into()) } else { - frame.locals[local].access()? + M::access_local(&self, frame, local)? }; Ok(OpTy { op, layout }) } @@ -481,7 +481,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Evaluate a place with the goal of reading from it. This lets us sometimes // avoid allocations. - pub(super) fn eval_place_to_op( + pub fn eval_place_to_op( &self, place: &mir::Place<'tcx>, layout: Option>, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 2f1b35757fe9c..1166ca9bf2444 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -9,7 +9,7 @@ use rustc::mir; use rustc::mir::interpret::truncate; use rustc::ty::{self, Ty}; use rustc::ty::layout::{ - self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx, PrimitiveExt + self, Size, Abi, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx, PrimitiveExt }; use rustc::ty::TypeFoldable; @@ -385,6 +385,10 @@ where stride * field } layout::FieldPlacement::Union(count) => { + // FIXME(#64506) `UninhabitedValue` can be removed when this issue is resolved + if base.layout.abi == Abi::Uninhabited { + throw_unsup!(UninhabitedValue); + } assert!(field < count as u64, "Tried to access field {} of union with {} fields", field, count); // Offset is always 0 diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index affca10bf5265..daca7a25787ca 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -132,7 +132,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue /// type writes its results directly into the memory specified by the place. - fn eval_rvalue_into_place( + pub fn eval_rvalue_into_place( &mut self, rvalue: &mir::Rvalue<'tcx>, place: &mir::Place<'tcx>, diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 857757ada53b7..612822b6d9d34 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -1,22 +1,26 @@ //! Propagates constants for early reporting of statically known //! assertion failures +use std::borrow::Cow; use std::cell::Cell; use rustc::hir::def::DefKind; +use rustc::hir::def_id::DefId; use rustc::mir::{ AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, - Local, NullOp, UnOp, StatementKind, Statement, LocalKind, Static, StaticKind, - TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem, - SourceScope, SourceScopeLocalData, LocalDecl, + Local, NullOp, UnOp, StatementKind, Statement, LocalKind, + TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, + SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock, }; use rustc::mir::visit::{ Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, }; -use rustc::mir::interpret::{Scalar, GlobalId, InterpResult, PanicInfo}; +use rustc::mir::interpret::{Scalar, InterpResult, PanicInfo}; use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; +use syntax::ast::Mutability; use syntax_pos::{Span, DUMMY_SP}; use rustc::ty::subst::InternalSubsts; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::IndexVec; use rustc::ty::layout::{ LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, @@ -24,11 +28,11 @@ use rustc::ty::layout::{ use crate::interpret::{ self, InterpCx, ScalarMaybeUndef, Immediate, OpTy, - ImmTy, MemoryKind, StackPopCleanup, LocalValue, LocalState, -}; -use crate::const_eval::{ - CompileTimeInterpreter, error_to_const_error, mk_eval_cx, + StackPopCleanup, LocalValue, LocalState, AllocId, Frame, + Allocation, MemoryKind, ImmTy, Pointer, Memory, PlaceTy, + Operand as InterpOperand, }; +use crate::const_eval::error_to_const_error; use crate::transform::{MirPass, MirSource}; pub struct ConstProp; @@ -57,6 +61,14 @@ impl<'tcx> MirPass<'tcx> for ConstProp { return } + let is_generator = tcx.type_of(source.def_id()).is_generator(); + // FIXME(welseywiser) const prop doesn't work on generators because of query cycles + // computing their layout. + if is_generator { + trace!("ConstProp skipped for generator {:?}", source.def_id()); + return + } + trace!("ConstProp starting for {:?}", source.def_id()); // Steal some data we need from `body`. @@ -103,11 +115,154 @@ impl<'tcx> MirPass<'tcx> for ConstProp { } } +struct ConstPropMachine; + +impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { + type MemoryKinds= !; + type PointerTag = (); + type ExtraFnVal = !; + + type FrameExtra = (); + type MemoryExtra = (); + type AllocExtra = (); + + type MemoryMap = FxHashMap, Allocation)>; + + const STATIC_KIND: Option = None; + + const CHECK_ALIGN: bool = false; + + #[inline(always)] + fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + false + } + + fn find_fn( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _instance: ty::Instance<'tcx>, + _args: &[OpTy<'tcx>], + _dest: Option>, + _ret: Option, + ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> { + Ok(None) + } + + fn call_extra_fn( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + fn_val: !, + _args: &[OpTy<'tcx>], + _dest: Option>, + _ret: Option, + ) -> InterpResult<'tcx> { + match fn_val {} + } + + fn call_intrinsic( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _instance: ty::Instance<'tcx>, + _args: &[OpTy<'tcx>], + _dest: PlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + throw_unsup_format!("calling intrinsics isn't supported in ConstProp"); + } + + fn ptr_to_int( + _mem: &Memory<'mir, 'tcx, Self>, + _ptr: Pointer, + ) -> InterpResult<'tcx, u64> { + throw_unsup_format!("ptr-to-int casts aren't supported in ConstProp"); + } + + fn binary_ptr_op( + _ecx: &InterpCx<'mir, 'tcx, Self>, + _bin_op: BinOp, + _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_unsup_format!("pointer arithmetic or comparisons aren't supported in ConstProp"); + } + + fn find_foreign_static( + _tcx: TyCtxt<'tcx>, + _def_id: DefId, + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { + throw_unsup!(ReadForeignStatic) + } + + #[inline(always)] + fn tag_allocation<'b>( + _memory_extra: &(), + _id: AllocId, + alloc: Cow<'b, Allocation>, + _kind: Option>, + ) -> (Cow<'b, Allocation>, Self::PointerTag) { + // We do not use a tag so we can just cheaply forward the allocation + (alloc, ()) + } + + #[inline(always)] + fn tag_static_base_pointer( + _memory_extra: &(), + _id: AllocId, + ) -> Self::PointerTag { + () + } + + fn box_alloc( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _dest: PlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + throw_unsup_format!("can't const prop `box` keyword"); + } + + fn access_local( + _ecx: &InterpCx<'mir, 'tcx, Self>, + frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + local: Local, + ) -> InterpResult<'tcx, InterpOperand> { + let l = &frame.locals[local]; + + if l.value == LocalValue::Uninitialized { + throw_unsup_format!("tried to access an uninitialized local"); + } + + l.access() + } + + fn before_access_static( + allocation: &Allocation, + ) -> InterpResult<'tcx> { + // if the static allocation is mutable or if it has relocations (it may be legal to mutate + // the memory behind that in the future), then we can't const prop it + if allocation.mutability == Mutability::Mutable || allocation.relocations().len() > 0 { + throw_unsup_format!("can't eval mutable statics in ConstProp"); + } + + Ok(()) + } + + fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + Ok(()) + } + + #[inline(always)] + fn stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + Ok(()) + } + + /// Called immediately before a stack frame gets popped. + #[inline(always)] + fn stack_pop(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _extra: ()) -> InterpResult<'tcx> { + Ok(()) + } +} + type Const<'tcx> = OpTy<'tcx>; /// Finds optimization opportunities on the MIR. struct ConstPropagator<'mir, 'tcx> { - ecx: InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, + ecx: InterpCx<'mir, 'tcx, ConstPropMachine>, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, can_const_prop: IndexVec, @@ -150,7 +305,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let def_id = source.def_id(); let param_env = tcx.param_env(def_id); let span = tcx.def_span(def_id); - let mut ecx = mk_eval_cx(tcx, span, param_env); + let mut ecx = InterpCx::new(tcx.at(span), param_env, ConstPropMachine, ()); let can_const_prop = CanConstProp::check(body); ecx.push_stack_frame( @@ -282,53 +437,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option> { trace!("eval_place(place={:?})", place); - let mut eval = match place.base { - PlaceBase::Local(loc) => self.get_const(loc).clone()?, - PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => { - let generics = self.tcx.generics_of(self.source.def_id()); - if generics.requires_monomorphization(self.tcx) { - // FIXME: can't handle code with generics - return None; - } - let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id()); - let instance = Instance::new(self.source.def_id(), substs); - let cid = GlobalId { - instance, - promoted: Some(promoted), - }; - let res = self.use_ecx(source_info, |this| { - this.ecx.const_eval_raw(cid) - })?; - trace!("evaluated promoted {:?} to {:?}", promoted, res); - res.into() - } - _ => return None, - }; - - for (i, elem) in place.projection.iter().enumerate() { - let proj_base = &place.projection[..i]; - - match elem { - ProjectionElem::Field(field, _) => { - trace!("field proj on {:?}", proj_base); - eval = self.use_ecx(source_info, |this| { - this.ecx.operand_field(eval, field.index() as u64) - })?; - }, - ProjectionElem::Deref => { - trace!("processing deref"); - eval = self.use_ecx(source_info, |this| { - this.ecx.deref_operand(eval) - })?.into(); - } - // We could get more projections by using e.g., `operand_projection`, - // but we do not even have the stack frame set up properly so - // an `Index` projection would throw us off-track. - _ => return None, - } - } - - Some(eval) + self.use_ecx(source_info, |this| { + this.ecx.eval_place_to_op(place, None) + }) } fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option> { @@ -344,166 +455,118 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { rvalue: &Rvalue<'tcx>, place_layout: TyLayout<'tcx>, source_info: SourceInfo, + place: &Place<'tcx>, ) -> Option> { let span = source_info.span; - match *rvalue { - Rvalue::Use(ref op) => { - self.eval_operand(op, source_info) - }, - Rvalue::Ref(_, _, ref place) => { - let src = self.eval_place(place, source_info)?; - let mplace = src.try_as_mplace().ok()?; - Some(ImmTy::from_scalar(mplace.ptr.into(), place_layout).into()) - }, + + // if this isn't a supported operation, then return None + match rvalue { Rvalue::Repeat(..) | Rvalue::Aggregate(..) | Rvalue::NullaryOp(NullOp::Box, _) | - Rvalue::Discriminant(..) => None, - - Rvalue::Cast(kind, ref operand, _) => { - let op = self.eval_operand(operand, source_info)?; - self.use_ecx(source_info, |this| { - let dest = this.ecx.allocate(place_layout, MemoryKind::Stack); - this.ecx.cast(op, kind, dest.into())?; - Ok(dest.into()) - }) - }, - Rvalue::Len(ref place) => { - let place = self.eval_place(&place, source_info)?; - let mplace = place.try_as_mplace().ok()?; - - if let ty::Slice(_) = mplace.layout.ty.kind { - let len = mplace.meta.unwrap().to_usize(&self.ecx).unwrap(); - - Some(ImmTy::from_uint( - len, - self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?, - ).into()) - } else { - trace!("not slice: {:?}", mplace.layout.ty.kind); - None - } - }, - Rvalue::NullaryOp(NullOp::SizeOf, ty) => { - type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some( - ImmTy::from_uint( - n, - self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?, - ).into() - )) - } - Rvalue::UnaryOp(op, ref arg) => { - let def_id = if self.tcx.is_closure(self.source.def_id()) { - self.tcx.closure_base_def_id(self.source.def_id()) - } else { - self.source.def_id() - }; - let generics = self.tcx.generics_of(def_id); - if generics.requires_monomorphization(self.tcx) { - // FIXME: can't handle code with generics - return None; - } + Rvalue::Discriminant(..) => return None, + + Rvalue::Use(_) | + Rvalue::Len(_) | + Rvalue::Cast(..) | + Rvalue::NullaryOp(..) | + Rvalue::CheckedBinaryOp(..) | + Rvalue::Ref(..) | + Rvalue::UnaryOp(..) | + Rvalue::BinaryOp(..) => { } + } - let arg = self.eval_operand(arg, source_info)?; - let oflo_check = self.tcx.sess.overflow_checks(); - let val = self.use_ecx(source_info, |this| { - let prim = this.ecx.read_immediate(arg)?; - match op { - UnOp::Neg => { - // We check overflow in debug mode already - // so should only check in release mode. - if !oflo_check - && prim.layout.ty.is_signed() - && prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { - throw_panic!(OverflowNeg) - } - } - UnOp::Not => { - // Cannot overflow + // perform any special checking for specific Rvalue types + if let Rvalue::UnaryOp(op, arg) = rvalue { + trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg); + let overflow_check = self.tcx.sess.overflow_checks(); + + self.use_ecx(source_info, |this| { + // We check overflow in debug mode already + // so should only check in release mode. + if *op == UnOp::Neg && !overflow_check { + let ty = arg.ty(&this.local_decls, this.tcx); + + if ty.is_integral() { + let arg = this.ecx.eval_operand(arg, None)?; + let prim = this.ecx.read_immediate(arg)?; + // Need to do overflow check here: For actual CTFE, MIR + // generation emits code that does this before calling the op. + if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { + throw_panic!(OverflowNeg) } } - // Now run the actual operation. - this.ecx.unary_op(op, prim) - })?; - Some(val.into()) - } - Rvalue::CheckedBinaryOp(op, ref left, ref right) | - Rvalue::BinaryOp(op, ref left, ref right) => { - trace!("rvalue binop {:?} for {:?} and {:?}", op, left, right); - let right = self.eval_operand(right, source_info)?; - let def_id = if self.tcx.is_closure(self.source.def_id()) { - self.tcx.closure_base_def_id(self.source.def_id()) - } else { - self.source.def_id() - }; - let generics = self.tcx.generics_of(def_id); - if generics.requires_monomorphization(self.tcx) { - // FIXME: can't handle code with generics + } + + Ok(()) + })?; + } else if let Rvalue::BinaryOp(op, left, right) = rvalue { + trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); + + let r = self.use_ecx(source_info, |this| { + this.ecx.read_immediate(this.ecx.eval_operand(right, None)?) + })?; + if *op == BinOp::Shr || *op == BinOp::Shl { + let left_bits = place_layout.size.bits(); + let right_size = r.layout.size; + let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); + if r_bits.ok().map_or(false, |b| b >= left_bits as u128) { + let source_scope_local_data = match self.source_scope_local_data { + ClearCrossCrate::Set(ref data) => data, + ClearCrossCrate::Clear => return None, + }; + let dir = if *op == BinOp::Shr { + "right" + } else { + "left" + }; + let hir_id = source_scope_local_data[source_info.scope].lint_root; + self.tcx.lint_hir( + ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, + hir_id, + span, + &format!("attempt to shift {} with overflow", dir)); return None; } + } + self.use_ecx(source_info, |this| { + let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?; + let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?; + + // We check overflow in debug mode already + // so should only check in release mode. + if !this.tcx.sess.overflow_checks() && overflow { + let err = err_panic!(Overflow(*op)).into(); + return Err(err); + } - let r = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(right) - })?; - if op == BinOp::Shr || op == BinOp::Shl { - let left_ty = left.ty(&self.local_decls, self.tcx); - let left_bits = self - .tcx - .layout_of(self.param_env.and(left_ty)) - .unwrap() - .size - .bits(); - let right_size = right.layout.size; - let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); - if r_bits.ok().map_or(false, |b| b >= left_bits as u128) { - let source_scope_local_data = match self.source_scope_local_data { - ClearCrossCrate::Set(ref data) => data, - ClearCrossCrate::Clear => return None, - }; - let dir = if op == BinOp::Shr { - "right" - } else { - "left" - }; - let hir_id = source_scope_local_data[source_info.scope].lint_root; - self.tcx.lint_hir( - ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, - hir_id, - span, - &format!("attempt to shift {} with overflow", dir)); - return None; - } + Ok(()) + })?; + } else if let Rvalue::Ref(_, _, place) = rvalue { + trace!("checking Ref({:?})", place); + // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref + // from a function argument that hasn't been assigned to in this function. + if let Place { + base: PlaceBase::Local(local), + projection: box [] + } = place { + let alive = + if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value { + true + } else { false }; + + if local.as_usize() <= self.ecx.frame().body.arg_count && !alive { + trace!("skipping Ref({:?})", place); + return None; } - let left = self.eval_operand(left, source_info)?; - let l = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(left) - })?; - trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); - let (val, overflow, _ty) = self.use_ecx(source_info, |this| { - this.ecx.overflowing_binary_op(op, l, r) - })?; - let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue { - Immediate::ScalarPair( - val.into(), - Scalar::from_bool(overflow).into(), - ) - } else { - // We check overflow in debug mode already - // so should only check in release mode. - if !self.tcx.sess.overflow_checks() && overflow { - let err = err_panic!(Overflow(op)).into(); - let _: Option<()> = self.use_ecx(source_info, |_| Err(err)); - return None; - } - Immediate::Scalar(val.into()) - }; - let res = ImmTy { - imm: val, - layout: place_layout, - }; - Some(res.into()) - }, + } } + + self.use_ecx(source_info, |this| { + trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place); + this.ecx.eval_rvalue_into_place(rvalue, place)?; + this.ecx.eval_place_to_op(place, Some(place_layout)) + }) } fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>, span: Span) -> Operand<'tcx> { @@ -577,14 +640,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } -fn type_size_of<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, -) -> Option { - tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes()) -} - struct CanConstProp { can_const_prop: IndexVec, // false at the beginning, once set, there are not allowed to be any more assignments @@ -670,15 +725,19 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { .ty(&self.local_decls, self.tcx) .ty; if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { - if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) { - if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *place { + if let Place { + base: PlaceBase::Local(local), + projection: box [], + } = *place { + if let Some(value) = self.const_prop(rval, + place_layout, + statement.source_info, + place) { trace!("checking whether {:?} can be stored to {:?}", value, local); if self.can_const_prop[local] { trace!("storing {:?} to {:?}", value, local); - assert!(self.get_const(local).is_none()); + assert!(self.get_const(local).is_none() || + self.get_const(local) == Some(value)); self.set_const(local, value); if self.should_const_prop() { @@ -692,7 +751,22 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { } } } + } else { + match statement.kind { + StatementKind::StorageLive(local) | + StatementKind::StorageDead(local) if self.can_const_prop[local] => { + let frame = self.ecx.frame_mut(); + frame.locals[local].value = + if let StatementKind::StorageLive(_) = statement.kind { + LocalValue::Uninitialized + } else { + LocalValue::Dead + }; + } + _ => {} + } } + self.super_statement(statement, location); } diff --git a/src/librustc_target/spec/aarch64_unknown_none.rs b/src/librustc_target/spec/aarch64_unknown_none.rs index 8c02bc61088b4..b9549ec2120dd 100644 --- a/src/librustc_target/spec/aarch64_unknown_none.rs +++ b/src/librustc_target/spec/aarch64_unknown_none.rs @@ -1,4 +1,4 @@ -// Generic AArch64 target for bare-metal code +// Generic AArch64 target for bare-metal code - Floating point enabled // // Can be used in conjunction with the `target-feature` and // `target-cpu` compiler flags to opt-in more hardware-specific @@ -11,7 +11,7 @@ use super::{LldFlavor, LinkerFlavor, Target, TargetOptions, PanicStrategy}; pub fn target() -> Result { let opts = TargetOptions { linker: Some("rust-lld".to_owned()), - features: "+strict-align".to_string(), + features: "+strict-align,+neon,+fp-armv8".to_string(), executables: true, relocation_model: "static".to_string(), disable_redzone: true, diff --git a/src/librustc_target/spec/aarch64_unknown_none_softfloat.rs b/src/librustc_target/spec/aarch64_unknown_none_softfloat.rs new file mode 100644 index 0000000000000..b91f2af68ecb8 --- /dev/null +++ b/src/librustc_target/spec/aarch64_unknown_none_softfloat.rs @@ -0,0 +1,37 @@ +// Generic AArch64 target for bare-metal code - Floating point disabled +// +// Can be used in conjunction with the `target-feature` and +// `target-cpu` compiler flags to opt-in more hardware-specific +// features. +// +// For example, `-C target-cpu=cortex-a53`. + +use super::{LldFlavor, LinkerFlavor, Target, TargetOptions, PanicStrategy}; + +pub fn target() -> Result { + let opts = TargetOptions { + linker: Some("rust-lld".to_owned()), + features: "+strict-align,-neon,-fp-armv8".to_string(), + executables: true, + relocation_model: "static".to_string(), + disable_redzone: true, + linker_is_gnu: true, + max_atomic_width: Some(128), + panic_strategy: PanicStrategy::Abort, + abi_blacklist: super::arm_base::abi_blacklist(), + .. Default::default() + }; + Ok(Target { + llvm_target: "aarch64-unknown-none".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + target_c_int_width: "32".to_string(), + target_os: "none".to_string(), + target_env: String::new(), + target_vendor: String::new(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), + arch: "aarch64".to_string(), + linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), + options: opts, + }) +} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 626fa374a1bd4..25add0cc6a4be 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -489,6 +489,7 @@ supported_targets! { ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf), ("aarch64-unknown-none", aarch64_unknown_none), + ("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat), ("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx), diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 97fcfd7151a1c..27fdd6caa2b0a 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -620,8 +620,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr ) -> Ty<'tcx> { if self.ret_coercion.is_none() { - struct_span_err!(self.tcx.sess, expr.span, E0572, - "return statement outside of function body").emit(); + struct_span_err!( + self.tcx.sess, + expr.span, + E0572, + "return statement outside of function body", + ).emit(); } else if let Some(ref e) = expr_opt { if self.ret_coercion_span.borrow().is_none() { *self.ret_coercion_span.borrow_mut() = Some(e.span); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 82d55e0df599b..9c7d2736e197f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1717,9 +1717,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let scope = tcx.hir() - .get_defining_scope(hir_id) - .expect("could not get defining scope"); + let scope = tcx.hir().get_defining_scope(hir_id); let mut locator = ConstraintLocator { def_id, tcx, diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 8758ab1969116..853170542e083 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -35,7 +35,7 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { match ty { clean::Generic(s) => params.entry(s).or_default() .extend(bounds), - t => tybounds.push((t, ty_bounds(bounds))), + t => tybounds.push((t, bounds)), } } WP::RegionPredicate { lifetime, bounds } => { @@ -45,11 +45,6 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { } } - // Simplify the type parameter bounds on all the generics - let mut params = params.into_iter().map(|(k, v)| { - (k, ty_bounds(v)) - }).collect::>(); - // Look for equality predicates on associated types that can be merged into // general bound predicates equalities.retain(|&(ref lhs, ref rhs)| { @@ -73,7 +68,7 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { // And finally, let's reassemble everything let mut clauses = Vec::new(); clauses.extend(lifetimes.into_iter().map(|(lt, bounds)| { - WP::RegionPredicate { lifetime: lt, bounds: bounds } + WP::RegionPredicate { lifetime: lt, bounds } })); clauses.extend(params.into_iter().map(|(k, v)| { WP::BoundPredicate { @@ -82,10 +77,10 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { } })); clauses.extend(tybounds.into_iter().map(|(ty, bounds)| { - WP::BoundPredicate { ty: ty, bounds: bounds } + WP::BoundPredicate { ty, bounds } })); clauses.extend(equalities.into_iter().map(|(lhs, rhs)| { - WP::EqPredicate { lhs: lhs, rhs: rhs } + WP::EqPredicate { lhs, rhs } })); clauses } @@ -122,9 +117,9 @@ pub fn merge_bounds( }, }); } - PP::Parenthesized { ref mut output, .. } => { - assert!(output.is_none()); - if *rhs != clean::Type::Tuple(Vec::new()) { + PP::Parenthesized { ref mut output, .. } => match output { + Some(o) => assert_eq!(o, rhs), + None => if *rhs != clean::Type::Tuple(Vec::new()) { *output = Some(rhs.clone()); } } @@ -137,7 +132,7 @@ pub fn ty_params(mut params: Vec) -> Vec { - *bounds = ty_bounds(mem::take(bounds)); + *bounds = mem::take(bounds); } _ => panic!("expected only type parameters"), } @@ -145,10 +140,6 @@ pub fn ty_params(mut params: Vec) -> Vec) -> Vec { - bounds -} - fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) -> bool { if child == trait_ { diff --git a/src/libstd/sys/vxworks/process/process_vxworks.rs b/src/libstd/sys/vxworks/process/process_vxworks.rs index beb20aa48169a..7446471ae3122 100644 --- a/src/libstd/sys/vxworks/process/process_vxworks.rs +++ b/src/libstd/sys/vxworks/process/process_vxworks.rs @@ -54,8 +54,8 @@ impl Command { let ret = libc::rtpSpawn( self.get_argv()[0], // executing program - self.get_argv().as_ptr() as *const _, // argv - *sys::os::environ() as *const *const c_char, + self.get_argv().as_ptr() as *mut *const c_char, // argv + *sys::os::environ() as *mut *const c_char, 100 as c_int, // initial priority thread::min_stack(), // initial stack size. 0, // options diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 2765346b333cf..8fc64021b51fc 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -695,7 +695,7 @@ impl<'a, 'b> Context<'a, 'b> { // Now create a vector containing all the arguments let args = locals.into_iter().chain(counts.into_iter()); - let args_array = self.ecx.expr_vec(self.fmtsp, args.collect()); + let args_array = self.ecx.expr_vec(self.macsp, args.collect()); // Constructs an AST equivalent to: // @@ -724,12 +724,12 @@ impl<'a, 'b> Context<'a, 'b> { // // But the nested match expression is proved to perform not as well // as series of let's; the first approach does. - let pat = self.ecx.pat_tuple(self.fmtsp, pats); - let arm = self.ecx.arm(self.fmtsp, pat, args_array); - let head = self.ecx.expr(self.fmtsp, ast::ExprKind::Tup(heads)); - let result = self.ecx.expr_match(self.fmtsp, head, vec![arm]); + let pat = self.ecx.pat_tuple(self.macsp, pats); + let arm = self.ecx.arm(self.macsp, pat, args_array); + let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads)); + let result = self.ecx.expr_match(self.macsp, head, vec![arm]); - let args_slice = self.ecx.expr_addr_of(self.fmtsp, result); + let args_slice = self.ecx.expr_addr_of(self.macsp, result); // Now create the fmt::Arguments struct with all our locals we created. let (fn_name, fn_args) = if self.all_pieces_simple { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index e441514e59738..bcda5384204d8 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -1546,6 +1546,7 @@ fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> } } } + (&ShouldPanic::Yes, Ok(())) => TrFailedMsg("test did not panic as expected".to_string()), _ if desc.allow_fail => TrAllowedFail, _ => TrFailed, } diff --git a/src/libtest/tests.rs b/src/libtest/tests.rs index 13ac8eb91f411..38ec7bd70930c 100644 --- a/src/libtest/tests.rs +++ b/src/libtest/tests.rs @@ -2,7 +2,7 @@ use super::*; use crate::test::{ filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored, - ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg, + ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailedMsg, TrIgnored, TrOk, }; use std::sync::mpsc::channel; @@ -167,7 +167,7 @@ fn test_should_panic_but_succeeds() { let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); let (_, res, _, _) = rx.recv().unwrap(); - assert!(res == TrFailed); + assert!(res == TrFailedMsg("test did not panic as expected".to_string())); } fn report_time_test_template(report_time: bool) -> Option { diff --git a/src/test/mir-opt/const_prop/read_immutable_static.rs b/src/test/mir-opt/const_prop/read_immutable_static.rs new file mode 100644 index 0000000000000..d16f812ad95db --- /dev/null +++ b/src/test/mir-opt/const_prop/read_immutable_static.rs @@ -0,0 +1,27 @@ +static FOO: u8 = 2; + +fn main() { + let x = FOO + FOO; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _2 = (FOO: u8); +// ... +// _3 = (FOO: u8); +// _1 = Add(move _2, move _3); +// ... +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _2 = const 2u8; +// ... +// _3 = const 2u8; +// _1 = Add(move _2, move _3); +// ... +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.rs b/src/test/mir-opt/const_prop/reify_fn_ptr.rs index 7e36b2a6b1b39..e9b61690cf89e 100644 --- a/src/test/mir-opt/const_prop/reify_fn_ptr.rs +++ b/src/test/mir-opt/const_prop/reify_fn_ptr.rs @@ -16,7 +16,7 @@ fn main() { // START rustc.main.ConstProp.after.mir // bb0: { // ... -// _3 = const Scalar(AllocId(1).0x0) : fn(); +// _3 = const Scalar(AllocId(0).0x0) : fn(); // _2 = move _3 as usize (Misc); // ... // _1 = move _2 as *const fn() (Misc); diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs index 5babeb195a826..05595ce147c96 100644 --- a/src/test/mir-opt/const_prop/slice_len.rs +++ b/src/test/mir-opt/const_prop/slice_len.rs @@ -34,7 +34,7 @@ fn main() { // assert(const true, "index out of bounds: the len is move _7 but the index is _6") -> bb1; // } // bb1: { -// _1 = (*_2)[_6]; +// _1 = const 2u32; // ... // return; // } diff --git a/src/test/run-fail/overflowing-lsh-1.rs b/src/test/run-fail/overflowing-lsh-1.rs index c69da0f49adf1..37fbf01e487dc 100644 --- a/src/test/run-fail/overflowing-lsh-1.rs +++ b/src/test/run-fail/overflowing-lsh-1.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _x = 1_i32 << 32; diff --git a/src/test/run-fail/overflowing-lsh-2.rs b/src/test/run-fail/overflowing-lsh-2.rs index 21659bd52393a..7b0b37dfed043 100644 --- a/src/test/run-fail/overflowing-lsh-2.rs +++ b/src/test/run-fail/overflowing-lsh-2.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _x = 1 << -1; diff --git a/src/test/run-fail/overflowing-lsh-3.rs b/src/test/run-fail/overflowing-lsh-3.rs index 8f06cd1153354..1768a8e6d3138 100644 --- a/src/test/run-fail/overflowing-lsh-3.rs +++ b/src/test/run-fail/overflowing-lsh-3.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _x = 1_u64 << 64; diff --git a/src/test/run-fail/overflowing-lsh-4.rs b/src/test/run-fail/overflowing-lsh-4.rs index 084c147094dee..ec304b4144e0f 100644 --- a/src/test/run-fail/overflowing-lsh-4.rs +++ b/src/test/run-fail/overflowing-lsh-4.rs @@ -5,6 +5,7 @@ // sidestep the overflow checking. #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { // this signals overflow when checking is on diff --git a/src/test/run-fail/overflowing-rsh-1.rs b/src/test/run-fail/overflowing-rsh-1.rs index 24a77da896d9e..14514540c06e1 100644 --- a/src/test/run-fail/overflowing-rsh-1.rs +++ b/src/test/run-fail/overflowing-rsh-1.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _x = -1_i32 >> 32; diff --git a/src/test/run-fail/overflowing-rsh-2.rs b/src/test/run-fail/overflowing-rsh-2.rs index b5615cacc2055..83dcbd13d2ad8 100644 --- a/src/test/run-fail/overflowing-rsh-2.rs +++ b/src/test/run-fail/overflowing-rsh-2.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _x = -1_i32 >> -1; diff --git a/src/test/run-fail/overflowing-rsh-3.rs b/src/test/run-fail/overflowing-rsh-3.rs index 7598e026d8139..3521c0506591c 100644 --- a/src/test/run-fail/overflowing-rsh-3.rs +++ b/src/test/run-fail/overflowing-rsh-3.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _x = -1_i64 >> 64; diff --git a/src/test/run-fail/overflowing-rsh-4.rs b/src/test/run-fail/overflowing-rsh-4.rs index a8d3b69392a97..ed1191849e57c 100644 --- a/src/test/run-fail/overflowing-rsh-4.rs +++ b/src/test/run-fail/overflowing-rsh-4.rs @@ -5,6 +5,7 @@ // truncation does not sidestep the overflow checking. #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { // this signals overflow when checking is on diff --git a/src/test/rustdoc/auxiliary/issue-57180.rs b/src/test/rustdoc/auxiliary/issue-57180.rs new file mode 100644 index 0000000000000..4e2f4b87c020e --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-57180.rs @@ -0,0 +1,16 @@ +// compile-flags: -Cmetadata=aux + +pub trait Trait { +} + +pub struct Struct +{ + _p: ::std::marker::PhantomData, +} + +impl u32> +Trait for Struct + where + F: Fn() -> u32, +{ +} diff --git a/src/test/rustdoc/issue-57180.rs b/src/test/rustdoc/issue-57180.rs new file mode 100644 index 0000000000000..14bd2b0fec0d5 --- /dev/null +++ b/src/test/rustdoc/issue-57180.rs @@ -0,0 +1,7 @@ +// aux-build:issue-57180.rs + +extern crate issue_57180; +use issue_57180::Trait; + +fn main() { +} diff --git a/src/test/ui/coherence/auxiliary/coherence_lib.rs b/src/test/ui/coherence/auxiliary/coherence_lib.rs index 9a5ec82430639..c22819831ab24 100644 --- a/src/test/ui/coherence/auxiliary/coherence_lib.rs +++ b/src/test/ui/coherence/auxiliary/coherence_lib.rs @@ -5,11 +5,11 @@ pub trait Remote { } pub trait Remote1 { - fn foo(&self, t: T) { } + fn foo(&self, _t: T) { } } pub trait Remote2 { - fn foo(&self, t: T, u: U) { } + fn foo(&self, _t: T, _u: U) { } } pub struct Pair(T,U); diff --git a/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.rs new file mode 100644 index 0000000000000..b08fedc5e11c2 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for f64 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.stderr b/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.stderr new file mode 100644 index 0000000000000..04e96f29230fb --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.stderr @@ -0,0 +1,12 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign[foreign]-for-foreign.rs:12:1 + | +LL | impl Remote1 for f64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign[foreign]-for-local.rs b/src/test/ui/coherence/impl-foreign[foreign]-for-local.rs new file mode 100644 index 0000000000000..33e85c164763e --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[foreign]-for-local.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Local { +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign[t]_local]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[foreign[t]_local]-for-foreign.rs new file mode 100644 index 0000000000000..54d4bf04a583c --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign[t]_local]-for-foreign.rs @@ -0,0 +1,14 @@ +#![feature(re_rebalance_coherence)] + +// check-pass +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +impl Remote2, Local> for usize { } + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].rs new file mode 100644 index 0000000000000..66a4d9d273469 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl<'a, T> Remote1 for &'a T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr new file mode 100644 index 0000000000000..2467097b1a8b3 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[foreign]-for-fundamental[t].rs:12:1 + | +LL | impl Remote1 for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[foreign]-for-fundamental[t].rs:16:1 + | +LL | impl<'a, T> Remote1 for &'a T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.rs b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.rs new file mode 100644 index 0000000000000..0a67ebcbba44c --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr new file mode 100644 index 0000000000000..5c28406f113fc --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[foreign]-for-t.rs:12:1 + | +LL | impl Remote1 for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.rs new file mode 100644 index 0000000000000..71598dae96ab3 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1> for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl<'a, T> Remote1<&'a T> for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr new file mode 100644 index 0000000000000..dd9702650795e --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-foreign.rs:12:1 + | +LL | impl Remote1> for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-foreign.rs:16:1 + | +LL | impl<'a, T> Remote1<&'a T> for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs new file mode 100644 index 0000000000000..7bf0306f29ba4 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs @@ -0,0 +1,19 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl<'a, T> Remote1> for &'a T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} +impl<'a, T> Remote1<&'a T> for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr new file mode 100644 index 0000000000000..eec57fccea762 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs:12:1 + | +LL | impl<'a, T> Remote1> for &'a T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs:15:1 + | +LL | impl<'a, T> Remote1<&'a T> for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-local.rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-local.rs new file mode 100644 index 0000000000000..54d577c749248 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-local.rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1> for Local {} + +impl<'a, T> Remote1<&'a T> for Local {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.rs new file mode 100644 index 0000000000000..7af929006ef7f --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.rs @@ -0,0 +1,19 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1> for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} +impl<'a, T> Remote1<&'a T> for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr new file mode 100644 index 0000000000000..e017c3ffe6c05 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-t.rs:12:1 + | +LL | impl Remote1> for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-t.rs:15:1 + | +LL | impl<'a, T> Remote1<&'a T> for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.rs new file mode 100644 index 0000000000000..24e0f309c4555 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote2, Local> for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl<'a, T> Remote2<&'a T, Local> for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.stderr new file mode 100644 index 0000000000000..3d8561956ae7f --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]_local]-for-foreign.rs:12:1 + | +LL | impl Remote2, Local> for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]_local]-for-foreign.rs:16:1 + | +LL | impl<'a, T> Remote2<&'a T, Local> for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign.rs new file mode 100644 index 0000000000000..81cf3c3f6eca9 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Rc {} +impl Remote1 for Vec> {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].rs new file mode 100644 index 0000000000000..54425b6d708aa --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl Remote1 for &T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr new file mode 100644 index 0000000000000..7859665a7bb58 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[local]-for-fundamental[t].rs:12:1 + | +LL | impl Remote1 for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[local]-for-fundamental[t].rs:16:1 + | +LL | impl Remote1 for &T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-local.rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-local.rs new file mode 100644 index 0000000000000..6b1d93cd94442 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-local.rs @@ -0,0 +1,15 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Local {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-t.rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.rs new file mode 100644 index 0000000000000..6f35c6c9dbc88 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr new file mode 100644 index 0000000000000..be7de8cccb467 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[local]-for-t.rs:12:1 + | +LL | impl Remote1 for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[local_fundamental[t]]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[local_fundamental[t]]-for-foreign.rs new file mode 100644 index 0000000000000..be0875d0110fd --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local_fundamental[t]]-for-foreign.rs @@ -0,0 +1,19 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local2(Rc); + +impl Remote2> for u32 {} +impl<'a, T> Remote2 for u32 {} +impl Remote2, Box> for u32 {} +impl<'a, T> Remote2, &'a T> for u32 {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.rs new file mode 100644 index 0000000000000..5e89c2077330a --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr new file mode 100644 index 0000000000000..5544729b5d640 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[t]-for-foreign.rs:12:1 + | +LL | impl Remote1 for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.rs b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.rs new file mode 100644 index 0000000000000..300a2c4d48a9c --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl<'a, A, B> Remote1 for &'a B { + //~^ ERROR type parameter `B` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr new file mode 100644 index 0000000000000..be8cc29a6e5b0 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[t]-for-fundamental.rs:12:1 + | +LL | impl Remote1 for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `B` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[t]-for-fundamental.rs:16:1 + | +LL | impl<'a, A, B> Remote1 for &'a B { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `B` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-local.rs b/src/test/ui/coherence/impl[t]-foreign[t]-for-local.rs new file mode 100644 index 0000000000000..769147ea7eabd --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-local.rs @@ -0,0 +1,15 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Local {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-t.rs b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.rs new file mode 100644 index 0000000000000..c8513380ff73e --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr new file mode 100644 index 0000000000000..de857afd20b15 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[t]-for-t.rs:12:1 + | +LL | impl Remote1 for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/re-rebalance-coherence-rpass.rs b/src/test/ui/coherence/re-rebalance-coherence-rpass.rs deleted file mode 100644 index bacd3b89fad29..0000000000000 --- a/src/test/ui/coherence/re-rebalance-coherence-rpass.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![allow(dead_code)] -#![feature(re_rebalance_coherence)] - -// run-pass -// aux-build:re_rebalance_coherence_lib.rs - -extern crate re_rebalance_coherence_lib as lib; -use lib::*; - -struct Oracle; -impl Backend for Oracle {} -impl<'a, T:'a, Tab> QueryFragment for BatchInsert<'a, T, Tab> {} - -fn main() {} diff --git a/src/test/ui/consts/const-eval/issue-50814.rs b/src/test/ui/consts/const-eval/issue-50814.rs index b85cecda16e95..274967ef60de5 100644 --- a/src/test/ui/consts/const-eval/issue-50814.rs +++ b/src/test/ui/consts/const-eval/issue-50814.rs @@ -11,6 +11,7 @@ struct Sum(A,B); impl Unsigned for Sum { const MAX: u8 = A::MAX + B::MAX; //~ ERROR any use of this value will cause an error + //~| ERROR any use of this value will cause an error } fn foo(_: T) -> &'static u8 { diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr index 707dfee7cd5b8..de3459c72dd2b 100644 --- a/src/test/ui/consts/const-eval/issue-50814.stderr +++ b/src/test/ui/consts/const-eval/issue-50814.stderr @@ -9,13 +9,21 @@ LL | const MAX: u8 = A::MAX + B::MAX; = note: `#[deny(const_err)]` on by default error[E0080]: evaluation of constant expression failed - --> $DIR/issue-50814.rs:17:5 + --> $DIR/issue-50814.rs:18:5 | LL | &Sum::::MAX | ^----------------- | | | referenced constant has errors -error: aborting due to 2 previous errors +error: any use of this value will cause an error + --> $DIR/issue-50814.rs:13:21 + | +LL | const MAX: u8 = A::MAX + B::MAX; + | ----------------^^^^^^^^^^^^^^^- + | | + | attempt to add with overflow + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-prop-read-static-in-const.rs b/src/test/ui/consts/const-prop-read-static-in-const.rs new file mode 100644 index 0000000000000..7504fd525955a --- /dev/null +++ b/src/test/ui/consts/const-prop-read-static-in-const.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +// run-pass + +#![allow(dead_code)] + +const TEST: u8 = MY_STATIC; +//~^ skipping const checks + +static MY_STATIC: u8 = 4; + +fn main() { +} diff --git a/src/test/ui/consts/const-prop-read-static-in-const.stderr b/src/test/ui/consts/const-prop-read-static-in-const.stderr new file mode 100644 index 0000000000000..bbd5b12ed7dfc --- /dev/null +++ b/src/test/ui/consts/const-prop-read-static-in-const.stderr @@ -0,0 +1,6 @@ +warning: skipping const checks + --> $DIR/const-prop-read-static-in-const.rs:6:18 + | +LL | const TEST: u8 = MY_STATIC; + | ^^^^^^^^^ + diff --git a/src/test/ui/issues/issue-27592.rs b/src/test/ui/issues/issue-27592.rs index b023ea18ac9a9..88f70f584022d 100644 --- a/src/test/ui/issues/issue-27592.rs +++ b/src/test/ui/issues/issue-27592.rs @@ -15,5 +15,5 @@ impl ::std::fmt::Write for Stream { fn main() { write(|| format_args!("{}", String::from("Hello world"))); //~^ ERROR cannot return value referencing temporary value - //~| ERROR cannot return value referencing temporary value + //~| ERROR cannot return reference to temporary value } diff --git a/src/test/ui/issues/issue-27592.stderr b/src/test/ui/issues/issue-27592.stderr index 9d3eaa9705d44..c8649d82d7451 100644 --- a/src/test/ui/issues/issue-27592.stderr +++ b/src/test/ui/issues/issue-27592.stderr @@ -7,14 +7,11 @@ LL | write(|| format_args!("{}", String::from("Hello world"))); | | temporary value created here | returns a value referencing data owned by the current function -error[E0515]: cannot return value referencing temporary value +error[E0515]: cannot return reference to temporary value --> $DIR/issue-27592.rs:16:14 | LL | write(|| format_args!("{}", String::from("Hello world"))); - | ^^^^^^^^^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | temporary value created here - | returns a value referencing data owned by the current function + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a reference to data owned by the current function error: aborting due to 2 previous errors diff --git a/src/test/ui/struct-literal-variant-in-if.stderr b/src/test/ui/struct-literal-variant-in-if.stderr index f91b9d7dce60f..85cbc787bc2db 100644 --- a/src/test/ui/struct-literal-variant-in-if.stderr +++ b/src/test/ui/struct-literal-variant-in-if.stderr @@ -49,9 +49,6 @@ LL | if x == E::V { field } {} error[E0308]: mismatched types --> $DIR/struct-literal-variant-in-if.rs:10:20 | -LL | fn test_E(x: E) { - | - help: try adding a return type: `-> bool` -LL | let field = true; LL | if x == E::V { field } {} | ^^^^^ expected (), found bool |