From e38e954a0d249f88d0a55504f70d6055e865a931 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Mon, 17 Dec 2018 15:57:38 +0900 Subject: [PATCH 01/20] Simplify MIR generation for logical ops --- src/librustc_mir/build/expr/into.rs | 53 +++++++++++++---------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 0e7305e076ede..a26b0055a048c 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -126,18 +126,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::LogicalOp { op, lhs, rhs } => { // And: // - // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block] - // | | (false) - // +----------false-----------+------------------> [false_block] + // [block: If(lhs)] -true-> [else_block: dest = (rhs)] + // | (false) + // [shortcurcuit_block: dest = false] // // Or: // - // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block] - // | (true) | (false) - // [true_block] [false_block] + // [block: If(lhs)] -false-> [else_block: dest = (rhs)] + // | (true) + // [shortcurcuit_block: dest = true] - let (true_block, false_block, mut else_block, join_block) = ( - this.cfg.start_new_block(), + let (shortcircuit_block, mut else_block, join_block) = ( this.cfg.start_new_block(), this.cfg.start_new_block(), this.cfg.start_new_block(), @@ -145,47 +144,41 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let lhs = unpack!(block = this.as_local_operand(block, lhs)); let blocks = match op { - LogicalOp::And => (else_block, false_block), - LogicalOp::Or => (true_block, else_block), + LogicalOp::And => (else_block, shortcircuit_block), + LogicalOp::Or => (shortcircuit_block, else_block), }; let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1); this.cfg.terminate(block, source_info, term); - let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs)); - let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block); - this.cfg.terminate(else_block, source_info, term); - this.cfg.push_assign_constant( - true_block, + shortcircuit_block, source_info, destination, Constant { span: expr_span, ty: this.hir.bool_ty(), user_ty: None, - literal: this.hir.true_literal(), + literal: match op { + LogicalOp::And => this.hir.false_literal(), + LogicalOp::Or => this.hir.true_literal(), + }, }, ); - - this.cfg.push_assign_constant( - false_block, + this.cfg.terminate( + shortcircuit_block, source_info, - destination, - Constant { - span: expr_span, - ty: this.hir.bool_ty(), - user_ty: None, - literal: this.hir.false_literal(), - }, + TerminatorKind::Goto { target: join_block }, ); - this.cfg.terminate( - true_block, + let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs)); + this.cfg.push_assign( + else_block, source_info, - TerminatorKind::Goto { target: join_block }, + destination, + Rvalue::Use(rhs), ); this.cfg.terminate( - false_block, + else_block, source_info, TerminatorKind::Goto { target: join_block }, ); From f7314456d03d2bfed188baf3a988c77b40864dc8 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 18 Dec 2018 15:52:32 +0100 Subject: [PATCH 02/20] Mark tuple structs as live if their constructors are used --- src/librustc/hir/mod.rs | 2 +- src/librustc/middle/dead.rs | 80 ++++++++++----------- src/test/ui/dead-code-tuple-struct-field.rs | 22 ++++++ 3 files changed, 61 insertions(+), 43 deletions(-) create mode 100644 src/test/ui/dead-code-tuple-struct-field.rs diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 156d55b9e2fe6..3f5b614df9dc2 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2119,7 +2119,7 @@ impl StructField { /// Id of the whole enum lives in `Item`. /// /// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually -/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of +/// used for `Struct`-structs (but still present). Structures don't have an analogue of "Id of /// the variant itself" from enum variants. /// Id of the whole struct lives in `Item`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 934d7c12be552..d2175c28309b1 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -25,6 +25,8 @@ use middle::privacy; use ty::{self, TyCtxt}; use util::nodemap::FxHashSet; +use rustc_data_structures::fx::FxHashMap; + use syntax::{ast, source_map}; use syntax::attr; use syntax_pos; @@ -55,12 +57,15 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> { in_pat: bool, inherited_pub_visibility: bool, ignore_variant_stack: Vec, + // maps from tuple struct constructors to tuple struct items + struct_constructors: FxHashMap, } impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn check_def_id(&mut self, def_id: DefId) { if let Some(node_id) = self.tcx.hir().as_local_node_id(def_id) { - if should_explore(self.tcx, node_id) { + if should_explore(self.tcx, node_id) || + self.struct_constructors.contains_key(&node_id) { self.worklist.push(node_id); } self.live_symbols.insert(node_id); @@ -137,19 +142,23 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { continue } - if let Some(ref node) = self.tcx.hir().find(id) { + // in the case of tuple struct constructors we want to check the item, not the generated + // tuple struct constructor function + let id = self.struct_constructors.get(&id).cloned().unwrap_or(id); + + if let Some(node) = self.tcx.hir().find(id) { self.live_symbols.insert(id); self.visit_node(node); } } } - fn visit_node(&mut self, node: &Node<'tcx>) { + fn visit_node(&mut self, node: Node<'tcx>) { let had_repr_c = self.repr_has_repr_c; self.repr_has_repr_c = false; let had_inherited_pub_visibility = self.inherited_pub_visibility; self.inherited_pub_visibility = false; - match *node { + match node { Node::Item(item) => { match item.node { hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { @@ -337,6 +346,8 @@ struct LifeSeeder<'k, 'tcx: 'k> { worklist: Vec, krate: &'k hir::Crate, tcx: TyCtxt<'k, 'tcx, 'tcx>, + // see `MarkSymbolVisitor::struct_constructors` + struct_constructors: FxHashMap, } impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { @@ -379,6 +390,9 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } } + hir::ItemKind::Struct(ref variant_data, _) => { + self.struct_constructors.insert(variant_data.id(), item.id); + } _ => () } } @@ -392,11 +406,11 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } -fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &privacy::AccessLevels, - krate: &hir::Crate) - -> Vec -{ +fn create_and_seed_worklist<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + access_levels: &privacy::AccessLevels, + krate: &hir::Crate, +) -> (Vec, FxHashMap) { let worklist = access_levels.map.iter().filter_map(|(&id, level)| { if level >= &privacy::AccessLevel::Reachable { Some(id) @@ -413,17 +427,18 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, worklist, krate, tcx, + struct_constructors: Default::default(), }; krate.visit_all_item_likes(&mut life_seeder); - return life_seeder.worklist; + (life_seeder.worklist, life_seeder.struct_constructors) } fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: &privacy::AccessLevels, krate: &hir::Crate) -> FxHashSet { - let worklist = create_and_seed_worklist(tcx, access_levels, krate); + let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels, krate); let mut symbol_visitor = MarkSymbolVisitor { worklist, tcx, @@ -433,20 +448,12 @@ fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, in_pat: false, inherited_pub_visibility: false, ignore_variant_stack: vec![], + struct_constructors, }; symbol_visitor.mark_live_symbols(); symbol_visitor.live_symbols } -fn get_struct_ctor_id(item: &hir::Item) -> Option { - match item.node { - hir::ItemKind::Struct(ref struct_def, _) if !struct_def.is_struct() => { - Some(struct_def.id()) - } - _ => None - } -} - struct DeadVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, live_symbols: FxHashSet, @@ -464,46 +471,35 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { | hir::ItemKind::Union(..) => true, _ => false }; - let ctor_id = get_struct_ctor_id(item); - should_warn && !self.symbol_is_live(item.id, ctor_id) + should_warn && !self.symbol_is_live(item.id) } fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool { let field_type = self.tcx.type_of(self.tcx.hir().local_def_id(field.id)); !field.is_positional() - && !self.symbol_is_live(field.id, None) + && !self.symbol_is_live(field.id) && !field_type.is_phantom_data() && !has_allow_dead_code_or_lang_attr(self.tcx, field.id, &field.attrs) } fn should_warn_about_variant(&mut self, variant: &hir::VariantKind) -> bool { - !self.symbol_is_live(variant.data.id(), None) + !self.symbol_is_live(variant.data.id()) && !has_allow_dead_code_or_lang_attr(self.tcx, variant.data.id(), &variant.attrs) } fn should_warn_about_foreign_item(&mut self, fi: &hir::ForeignItem) -> bool { - !self.symbol_is_live(fi.id, None) + !self.symbol_is_live(fi.id) && !has_allow_dead_code_or_lang_attr(self.tcx, fi.id, &fi.attrs) } // id := node id of an item's definition. - // ctor_id := `Some` if the item is a struct_ctor (tuple struct), - // `None` otherwise. - // If the item is a struct_ctor, then either its `id` or - // `ctor_id` (unwrapped) is in the live_symbols set. More specifically, - // DefMap maps the ExprKind::Path of a struct_ctor to the node referred by - // `ctor_id`. On the other hand, in a statement like - // `type = ;` where refers to a struct_ctor, - // DefMap maps to `id` instead. - fn symbol_is_live(&mut self, - id: ast::NodeId, - ctor_id: Option) - -> bool { - if self.live_symbols.contains(&id) - || ctor_id.map_or(false, |ctor| self.live_symbols.contains(&ctor)) - { + fn symbol_is_live( + &mut self, + id: ast::NodeId, + ) -> bool { + if self.live_symbols.contains(&id) { return true; } // If it's a type whose items are live, then it's live, too. @@ -611,7 +607,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { match impl_item.node { hir::ImplItemKind::Const(_, body_id) => { - if !self.symbol_is_live(impl_item.id, None) { + if !self.symbol_is_live(impl_item.id) { self.warn_dead_code(impl_item.id, impl_item.span, impl_item.ident.name, @@ -621,7 +617,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { self.visit_nested_body(body_id) } hir::ImplItemKind::Method(_, body_id) => { - if !self.symbol_is_live(impl_item.id, None) { + if !self.symbol_is_live(impl_item.id) { let span = self.tcx.sess.source_map().def_span(impl_item.span); self.warn_dead_code(impl_item.id, span, impl_item.ident.name, "method", "used"); } diff --git a/src/test/ui/dead-code-tuple-struct-field.rs b/src/test/ui/dead-code-tuple-struct-field.rs new file mode 100644 index 0000000000000..f4989fa1037d3 --- /dev/null +++ b/src/test/ui/dead-code-tuple-struct-field.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +#![deny(dead_code)] + +const LEN: usize = 4; + +#[derive(Debug)] +struct Wrapper([u8; LEN]); + +fn main() { + println!("{:?}", Wrapper([0, 1, 2, 3])); +} From c2402dca85716aa4b452352bec11ff949c5a1cbb Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 18 Dec 2018 22:58:49 +0000 Subject: [PATCH 03/20] Replace "native pointer" in error message with "raw pointer" --- src/librustc_typeck/check/mod.rs | 2 +- src/test/ui/issues/issue-11004.stderr | 4 ++-- src/test/ui/unsafe/unsafe-fn-autoderef.stderr | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 957c8d9f19f0e..cb14078fb93ca 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3387,7 +3387,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } ty::RawPtr(..) => { let base = self.tcx.hir().node_to_pretty_string(base.id); - let msg = format!("`{}` is a native pointer; try dereferencing it", base); + let msg = format!("`{}` is a raw pointer; try dereferencing it", base); let suggestion = format!("(*{}).{}", base, field); err.span_suggestion_with_applicability( field.span, diff --git a/src/test/ui/issues/issue-11004.stderr b/src/test/ui/issues/issue-11004.stderr index 215120c9c25ea..46b4c4bdba201 100644 --- a/src/test/ui/issues/issue-11004.stderr +++ b/src/test/ui/issues/issue-11004.stderr @@ -2,13 +2,13 @@ error[E0609]: no field `x` on type `*mut A` --> $DIR/issue-11004.rs:17:21 | LL | let x : i32 = n.x; //~ no field `x` on type `*mut A` - | ^ help: `n` is a native pointer; try dereferencing it: `(*n).x` + | ^ help: `n` is a raw pointer; try dereferencing it: `(*n).x` error[E0609]: no field `y` on type `*mut A` --> $DIR/issue-11004.rs:18:21 | LL | let y : f64 = n.y; //~ no field `y` on type `*mut A` - | ^ help: `n` is a native pointer; try dereferencing it: `(*n).y` + | ^ help: `n` is a raw pointer; try dereferencing it: `(*n).y` error: aborting due to 2 previous errors diff --git a/src/test/ui/unsafe/unsafe-fn-autoderef.stderr b/src/test/ui/unsafe/unsafe-fn-autoderef.stderr index 13fcbb347c94b..81f15b2931df3 100644 --- a/src/test/ui/unsafe/unsafe-fn-autoderef.stderr +++ b/src/test/ui/unsafe/unsafe-fn-autoderef.stderr @@ -2,7 +2,7 @@ error[E0609]: no field `f` on type `*const Rec` --> $DIR/unsafe-fn-autoderef.rs:29:14 | LL | return p.f; //~ ERROR no field `f` on type `*const Rec` - | ^ help: `p` is a native pointer; try dereferencing it: `(*p).f` + | ^ help: `p` is a raw pointer; try dereferencing it: `(*p).f` error: aborting due to previous error From d6969ac2fbc07d646a6c46631c9c96165a1774fe Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 18 Dec 2018 23:42:42 +0000 Subject: [PATCH 04/20] Fix string for raw pointer deref suggestion --- src/librustc_typeck/check/mod.rs | 6 ++++-- src/test/ui/issues/issue-11004.stderr | 8 ++++++-- src/test/ui/parenthesised-deref-suggestion.rs | 8 ++++++++ src/test/ui/parenthesised-deref-suggestion.stderr | 12 ++++++++++++ src/test/ui/unsafe/unsafe-fn-autoderef.stderr | 4 +++- 5 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/parenthesised-deref-suggestion.rs create mode 100644 src/test/ui/parenthesised-deref-suggestion.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index cb14078fb93ca..500bdbf6acd85 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3386,11 +3386,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } ty::RawPtr(..) => { - let base = self.tcx.hir().node_to_pretty_string(base.id); + let base = self.tcx.sess.source_map() + .span_to_snippet(base.span) + .unwrap_or_else(|_| self.tcx.hir().node_to_pretty_string(base.id)); let msg = format!("`{}` is a raw pointer; try dereferencing it", base); let suggestion = format!("(*{}).{}", base, field); err.span_suggestion_with_applicability( - field.span, + expr.span, &msg, suggestion, Applicability::MaybeIncorrect, diff --git a/src/test/ui/issues/issue-11004.stderr b/src/test/ui/issues/issue-11004.stderr index 46b4c4bdba201..eb5b568b34738 100644 --- a/src/test/ui/issues/issue-11004.stderr +++ b/src/test/ui/issues/issue-11004.stderr @@ -2,13 +2,17 @@ error[E0609]: no field `x` on type `*mut A` --> $DIR/issue-11004.rs:17:21 | LL | let x : i32 = n.x; //~ no field `x` on type `*mut A` - | ^ help: `n` is a raw pointer; try dereferencing it: `(*n).x` + | --^ + | | + | help: `n` is a raw pointer; try dereferencing it: `(*n).x` error[E0609]: no field `y` on type `*mut A` --> $DIR/issue-11004.rs:18:21 | LL | let y : f64 = n.y; //~ no field `y` on type `*mut A` - | ^ help: `n` is a raw pointer; try dereferencing it: `(*n).y` + | --^ + | | + | help: `n` is a raw pointer; try dereferencing it: `(*n).y` error: aborting due to 2 previous errors diff --git a/src/test/ui/parenthesised-deref-suggestion.rs b/src/test/ui/parenthesised-deref-suggestion.rs new file mode 100644 index 0000000000000..bcbb51ccd6b65 --- /dev/null +++ b/src/test/ui/parenthesised-deref-suggestion.rs @@ -0,0 +1,8 @@ +struct Session { + opts: u8, +} + +fn main() { + let sess: &Session = &Session { opts: 0 }; + (sess as *const Session).opts; //~ ERROR no field `opts` on type `*const Session` +} diff --git a/src/test/ui/parenthesised-deref-suggestion.stderr b/src/test/ui/parenthesised-deref-suggestion.stderr new file mode 100644 index 0000000000000..2e122f38f3855 --- /dev/null +++ b/src/test/ui/parenthesised-deref-suggestion.stderr @@ -0,0 +1,12 @@ +error[E0609]: no field `opts` on type `*const Session` + --> $DIR/parenthesised-deref-suggestion.rs:7:30 + | +LL | (sess as *const Session).opts; //~ ERROR no field `opts` on type `*const Session` + | ^^^^ +help: `(sess as *const Session)` is a raw pointer; try dereferencing it + | +LL | (*(sess as *const Session)).opts; //~ ERROR no field `opts` on type `*const Session` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/unsafe/unsafe-fn-autoderef.stderr b/src/test/ui/unsafe/unsafe-fn-autoderef.stderr index 81f15b2931df3..7525f67051567 100644 --- a/src/test/ui/unsafe/unsafe-fn-autoderef.stderr +++ b/src/test/ui/unsafe/unsafe-fn-autoderef.stderr @@ -2,7 +2,9 @@ error[E0609]: no field `f` on type `*const Rec` --> $DIR/unsafe-fn-autoderef.rs:29:14 | LL | return p.f; //~ ERROR no field `f` on type `*const Rec` - | ^ help: `p` is a raw pointer; try dereferencing it: `(*p).f` + | --^ + | | + | help: `p` is a raw pointer; try dereferencing it: `(*p).f` error: aborting due to previous error From 030987481b339616954d36b4c421e86077f00e75 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 18 Dec 2018 23:43:00 +0000 Subject: [PATCH 05/20] Fix string for array access suggestion --- src/librustc_typeck/check/mod.rs | 4 +++- src/test/ui/parenthesised-deref-suggestion.rs | 3 +++ src/test/ui/parenthesised-deref-suggestion.stderr | 9 +++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 500bdbf6acd85..2f6de21d884f5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3372,7 +3372,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { len.assert_usize(self.tcx), field.as_str().parse::() ) { - let base = self.tcx.hir().node_to_pretty_string(base.id); + let base = self.tcx.sess.source_map() + .span_to_snippet(base.span) + .unwrap_or_else(|_| self.tcx.hir().node_to_pretty_string(base.id)); let help = "instead of using tuple indexing, use array indexing"; let suggestion = format!("{}[{}]", base, field); let applicability = if len < user_index { diff --git a/src/test/ui/parenthesised-deref-suggestion.rs b/src/test/ui/parenthesised-deref-suggestion.rs index bcbb51ccd6b65..0b4ccdd5a56d4 100644 --- a/src/test/ui/parenthesised-deref-suggestion.rs +++ b/src/test/ui/parenthesised-deref-suggestion.rs @@ -5,4 +5,7 @@ struct Session { fn main() { let sess: &Session = &Session { opts: 0 }; (sess as *const Session).opts; //~ ERROR no field `opts` on type `*const Session` + + let x = [0u32]; + (x as [u32; 1]).0; //~ ERROR no field `0` on type `[u32; 1]` } diff --git a/src/test/ui/parenthesised-deref-suggestion.stderr b/src/test/ui/parenthesised-deref-suggestion.stderr index 2e122f38f3855..71a2bf67f06ae 100644 --- a/src/test/ui/parenthesised-deref-suggestion.stderr +++ b/src/test/ui/parenthesised-deref-suggestion.stderr @@ -7,6 +7,15 @@ help: `(sess as *const Session)` is a raw pointer; try dereferencing it | LL | (*(sess as *const Session)).opts; //~ ERROR no field `opts` on type `*const Session` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0609]: no field `0` on type `[u32; 1]` + --> $DIR/parenthesised-deref-suggestion.rs:10:21 + | +LL | (x as [u32; 1]).0; //~ ERROR no field `0` on type `[u32; 1]` + | ----------------^ + | | + | help: instead of using tuple indexing, use array indexing: `(x as [u32; 1])[0]` + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0609`. From e7c5146c5d801c020f13c81b8b550f465c33d03a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 20 Dec 2018 09:50:14 +1100 Subject: [PATCH 06/20] Remove `TokenStream::JointTree`. This is done by adding a new `IsJoint` field to `TokenStream::Tree`, which simplifies a lot of `match` statements. And likewise for `CursorKind`. The commit also adds a new method `TokenTree:stream()` which can replace a choice between `.into()` and `.joint()`. --- src/libsyntax/parse/lexer/tokentrees.rs | 5 +- src/libsyntax/tokenstream.rs | 93 +++++++++++-------------- src/libsyntax_ext/proc_macro_server.rs | 8 +-- 3 files changed, 46 insertions(+), 60 deletions(-) diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index 0906c25cab361..72abcb03410ec 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -11,7 +11,7 @@ use print::pprust::token_to_string; use parse::lexer::StringReader; use parse::{token, PResult}; -use tokenstream::{DelimSpan, TokenStream, TokenTree}; +use tokenstream::{DelimSpan, IsJoint::*, TokenStream, TokenTree}; impl<'a> StringReader<'a> { // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`. @@ -178,8 +178,7 @@ impl<'a> StringReader<'a> { let raw = self.span_src_raw; self.real_token(); let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token); - - Ok(if is_joint { tt.joint() } else { tt.into() }) + Ok(TokenStream::Tree(tt, if is_joint { Joint } else { NonJoint })) } } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index c11ef33f931d8..620035413a553 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -123,7 +123,7 @@ impl TokenTree { } pub fn joint(self) -> TokenStream { - TokenStream::JointTree(self) + TokenStream::Tree(self, Joint) } /// Returns the opening delimiter as a token tree. @@ -156,8 +156,7 @@ impl TokenTree { #[derive(Clone, Debug)] pub enum TokenStream { Empty, - Tree(TokenTree), - JointTree(TokenTree), + Tree(TokenTree, IsJoint), Stream(Lrc>), } @@ -165,6 +164,14 @@ pub enum TokenStream { #[cfg(target_arch = "x86_64")] static_assert!(MEM_SIZE_OF_TOKEN_STREAM: mem::size_of::() == 32); +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum IsJoint { + Joint, + NonJoint +} + +use self::IsJoint::*; + impl TokenStream { /// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream` /// separating the two arguments with a comma for diagnostic suggestions. @@ -176,16 +183,16 @@ impl TokenStream { while let Some((pos, ts)) = iter.next() { if let Some((_, next)) = iter.peek() { let sp = match (&ts, &next) { - (TokenStream::Tree(TokenTree::Token(_, token::Token::Comma)), _) | - (_, TokenStream::Tree(TokenTree::Token(_, token::Token::Comma))) => { - continue; - } - (TokenStream::Tree(TokenTree::Token(sp, _)), _) => *sp, - (TokenStream::Tree(TokenTree::Delimited(sp, ..)), _) => sp.entire(), + (TokenStream::Tree(TokenTree::Token(_, token::Token::Comma), NonJoint), _) | + (_, TokenStream::Tree(TokenTree::Token(_, token::Token::Comma), NonJoint)) + => continue, + (TokenStream::Tree(TokenTree::Token(sp, _), NonJoint), _) => *sp, + (TokenStream::Tree(TokenTree::Delimited(sp, ..), NonJoint), _) => + sp.entire(), _ => continue, }; let sp = sp.shrink_to_hi(); - let comma = TokenStream::Tree(TokenTree::Token(sp, token::Comma)); + let comma = TokenStream::Tree(TokenTree::Token(sp, token::Comma), NonJoint); suggestion = Some((pos, comma, sp)); } } @@ -204,7 +211,7 @@ impl TokenStream { impl From for TokenStream { fn from(tt: TokenTree) -> TokenStream { - TokenStream::Tree(tt) + TokenStream::Tree(tt, NonJoint) } } @@ -232,7 +239,7 @@ impl Extend for TokenStream { vec.reserve(iter.size_hint().0); vec } - TokenStream::Tree(_) | TokenStream::JointTree(_) => { + TokenStream::Tree(..) => { let mut vec = Vec::new(); vec.reserve(1 + iter.size_hint().0); vec.push(this); @@ -367,8 +374,7 @@ impl TokenStream { /// Returns true if the token tree is a joint operation w.r.t. `proc_macro::TokenNode`. pub fn as_tree(self) -> (TokenTree, bool /* joint? */) { match self { - TokenStream::Tree(tree) => (tree, false), - TokenStream::JointTree(tree) => (tree, true), + TokenStream::Tree(tree, is_joint) => (tree, is_joint == Joint), _ => unreachable!(), } } @@ -379,8 +385,7 @@ impl TokenStream { let mut i = 0; while let Some(stream) = trees.next_as_stream() { result.push(match stream { - TokenStream::Tree(tree) => f(i, tree).into(), - TokenStream::JointTree(tree) => f(i, tree).joint(), + TokenStream::Tree(tree, is_joint) => TokenStream::Tree(f(i, tree), is_joint), _ => unreachable!() }); i += 1; @@ -393,27 +398,25 @@ impl TokenStream { let mut result = Vec::new(); while let Some(stream) = trees.next_as_stream() { result.push(match stream { - TokenStream::Tree(tree) => f(tree).into(), - TokenStream::JointTree(tree) => f(tree).joint(), + TokenStream::Tree(tree, is_joint) => TokenStream::Tree(f(tree), is_joint), _ => unreachable!() }); } TokenStream::new(result) } - fn first_tree_and_joint(&self) -> Option<(TokenTree, bool)> { + fn first_tree_and_joint(&self) -> Option<(TokenTree, IsJoint)> { match self { TokenStream::Empty => None, - TokenStream::Tree(ref tree) => Some((tree.clone(), false)), - TokenStream::JointTree(ref tree) => Some((tree.clone(), true)), + TokenStream::Tree(ref tree, is_joint) => Some((tree.clone(), *is_joint)), TokenStream::Stream(ref stream) => stream.first().unwrap().first_tree_and_joint(), } } fn last_tree_if_joint(&self) -> Option { match self { - TokenStream::Empty | TokenStream::Tree(..) => None, - TokenStream::JointTree(ref tree) => Some(tree.clone()), + TokenStream::Empty | TokenStream::Tree(_, NonJoint) => None, + TokenStream::Tree(ref tree, Joint) => Some(tree.clone()), TokenStream::Stream(ref stream) => stream.last().unwrap().last_tree_if_joint(), } } @@ -437,11 +440,7 @@ impl TokenStreamBuilder { self.push_all_but_last_tree(&last_stream); let glued_span = last_span.to(span); let glued_tt = TokenTree::Token(glued_span, glued_tok); - let glued_tokenstream = if is_joint { - glued_tt.joint() - } else { - glued_tt.into() - }; + let glued_tokenstream = TokenStream::Tree(glued_tt, is_joint); self.0.push(glued_tokenstream); self.push_all_but_first_tree(&stream); return @@ -491,8 +490,7 @@ pub struct Cursor(CursorKind); #[derive(Clone)] enum CursorKind { Empty, - Tree(TokenTree, bool /* consumed? */), - JointTree(TokenTree, bool /* consumed? */), + Tree(TokenTree, IsJoint, bool /* consumed? */), Stream(StreamCursor), } @@ -514,9 +512,9 @@ impl StreamCursor { self.index += 1; let next = self.stream[self.index - 1].clone(); match next { - TokenStream::Tree(..) | TokenStream::JointTree(..) => return Some(next), - TokenStream::Stream(stream) => self.insert(stream), TokenStream::Empty => {} + TokenStream::Tree(..) => return Some(next), + TokenStream::Stream(stream) => self.insert(stream), } } else if let Some((stream, index)) = self.stack.pop() { self.stream = stream; @@ -538,7 +536,7 @@ impl Iterator for Cursor { fn next(&mut self) -> Option { self.next_as_stream().map(|stream| match stream { - TokenStream::Tree(tree) | TokenStream::JointTree(tree) => tree, + TokenStream::Tree(tree, _) => tree, _ => unreachable!() }) } @@ -548,18 +546,15 @@ impl Cursor { fn new(stream: TokenStream) -> Self { Cursor(match stream { TokenStream::Empty => CursorKind::Empty, - TokenStream::Tree(tree) => CursorKind::Tree(tree, false), - TokenStream::JointTree(tree) => CursorKind::JointTree(tree, false), + TokenStream::Tree(tree, is_joint) => CursorKind::Tree(tree, is_joint, false), TokenStream::Stream(stream) => CursorKind::Stream(StreamCursor::new(stream)), }) } pub fn next_as_stream(&mut self) -> Option { let (stream, consumed) = match self.0 { - CursorKind::Tree(ref tree, ref mut consumed @ false) => - (tree.clone().into(), consumed), - CursorKind::JointTree(ref tree, ref mut consumed @ false) => - (tree.clone().joint(), consumed), + CursorKind::Tree(ref tree, ref is_joint, ref mut consumed @ false) => + (TokenStream::Tree(tree.clone(), *is_joint), consumed), CursorKind::Stream(ref mut cursor) => return cursor.next_as_stream(), _ => return None, }; @@ -572,7 +567,7 @@ impl Cursor { match self.0 { _ if stream.is_empty() => return, CursorKind::Empty => *self = stream.trees(), - CursorKind::Tree(_, consumed) | CursorKind::JointTree(_, consumed) => { + CursorKind::Tree(_, _, consumed) => { *self = TokenStream::new(vec![self.original_stream(), stream]).trees(); if consumed { self.next(); @@ -587,8 +582,8 @@ impl Cursor { pub fn original_stream(&self) -> TokenStream { match self.0 { CursorKind::Empty => TokenStream::empty(), - CursorKind::Tree(ref tree, _) => tree.clone().into(), - CursorKind::JointTree(ref tree, _) => tree.clone().joint(), + CursorKind::Tree(ref tree, ref is_joint, _) => + TokenStream::Tree(tree.clone(), *is_joint), CursorKind::Stream(ref cursor) => TokenStream::Stream( cursor.stack.get(0).cloned().map(|(stream, _)| stream) .unwrap_or_else(|| cursor.stream.clone()) @@ -600,9 +595,8 @@ impl Cursor { fn look_ahead(streams: &[TokenStream], mut n: usize) -> Result { for stream in streams { n = match stream { - TokenStream::Tree(ref tree) | TokenStream::JointTree(ref tree) - if n == 0 => return Ok(tree.clone()), - TokenStream::Tree(..) | TokenStream::JointTree(..) => n - 1, + TokenStream::Tree(ref tree, _) if n == 0 => return Ok(tree.clone()), + TokenStream::Tree(..) => n - 1, TokenStream::Stream(ref stream) => match look_ahead(stream, n) { Ok(tree) => return Ok(tree), Err(n) => n, @@ -615,10 +609,8 @@ impl Cursor { match self.0 { CursorKind::Empty | - CursorKind::Tree(_, true) | - CursorKind::JointTree(_, true) => Err(n), - CursorKind::Tree(ref tree, false) | - CursorKind::JointTree(ref tree, false) => look_ahead(&[tree.clone().into()], n), + CursorKind::Tree(_, _, true) => Err(n), + CursorKind::Tree(ref tree, _, false) => look_ahead(&[tree.clone().into()], n), CursorKind::Stream(ref cursor) => { look_ahead(&cursor.stream[cursor.index ..], n).or_else(|mut n| { for &(ref stream, index) in cursor.stack.iter().rev() { @@ -651,8 +643,7 @@ impl From for ThinTokenStream { fn from(stream: TokenStream) -> ThinTokenStream { ThinTokenStream(match stream { TokenStream::Empty => None, - TokenStream::Tree(tree) => Some(Lrc::new(vec![tree.into()])), - TokenStream::JointTree(tree) => Some(Lrc::new(vec![tree.joint()])), + TokenStream::Tree(..) => Some(Lrc::new(vec![stream])), TokenStream::Stream(stream) => Some(stream), }) } diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs index a04d6c92b7817..fa41022b7b675 100644 --- a/src/libsyntax_ext/proc_macro_server.rs +++ b/src/libsyntax_ext/proc_macro_server.rs @@ -21,7 +21,7 @@ use syntax::ast; use syntax::ext::base::ExtCtxt; use syntax::parse::lexer::comments; use syntax::parse::{self, token, ParseSess}; -use syntax::tokenstream::{self, DelimSpan, TokenStream}; +use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream}; use syntax_pos::hygiene::{SyntaxContext, Transparency}; use syntax_pos::symbol::{keywords, Symbol}; use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span}; @@ -297,11 +297,7 @@ impl ToInternal for TokenTree { }; let tree = tokenstream::TokenTree::Token(span, token); - if joint { - tree.joint() - } else { - tree.into() - } + TokenStream::Tree(tree, if joint { Joint } else { NonJoint }) } } From 405d8b0bb3d749e3baad25f68455873b66b219be Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 20 Dec 2018 14:31:40 +0100 Subject: [PATCH 07/20] Copyrite --- src/test/ui/dead-code-tuple-struct-field.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/test/ui/dead-code-tuple-struct-field.rs b/src/test/ui/dead-code-tuple-struct-field.rs index f4989fa1037d3..496ce4fb378ae 100644 --- a/src/test/ui/dead-code-tuple-struct-field.rs +++ b/src/test/ui/dead-code-tuple-struct-field.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // compile-pass #![deny(dead_code)] From 59f643fc5f7f9de0896680ec41fc64087311bead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 20 Dec 2018 14:00:30 -0800 Subject: [PATCH 08/20] Point to return span when writing `return;` on non-() fn --- src/librustc/hir/mod.rs | 9 +++++++++ src/librustc_typeck/check/coercion.rs | 3 +-- src/librustc_typeck/check/mod.rs | 19 ++++++++++++++++++- src/test/ui/error-codes/E0069.stderr | 4 +++- src/test/ui/ret-non-nil.stderr | 4 +++- .../return/return-unit-from-diverging.stderr | 4 +++- 6 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 156d55b9e2fe6..58733a83b253b 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1979,6 +1979,15 @@ pub enum FunctionRetTy { Return(P), } +impl fmt::Display for FunctionRetTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Return(ref ty) => print::to_string(print::NO_ANN, |s| s.print_type(ty)).fmt(f), + DefaultReturn(_) => "()".fmt(f), + } + } +} + impl FunctionRetTy { pub fn span(&self) -> Span { match *self { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8d844fe3a69e4..0b99a30b67dc8 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1143,7 +1143,6 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> // `expression_ty` will be unit). // // Another example is `break` with no argument expression. - assert!(expression_ty.is_unit()); assert!(expression_ty.is_unit(), "if let hack without unit type"); fcx.at(cause, fcx.param_env) .eq_exp(label_expression_as_expected, expression_ty, self.merged_ty()) @@ -1190,7 +1189,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> db = struct_span_err!( fcx.tcx.sess, cause.span, E0069, "`return;` in a function whose return type is not `()`"); - db.span_label(cause.span, "return type is not ()"); + db.span_label(cause.span, "return type is not `()`"); } ObligationCauseCode::BlockTailExpression(blk_id) => { db = fcx.report_mismatched_types(cause, expected, found, err); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8901f4b6b291b..d40afbbc3025b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4103,7 +4103,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); - coercion.coerce_forced_unit(self, &cause, &mut |_| (), true); + if let Some((fn_decl, _)) = self.get_fn_decl(expr.id) { + coercion.coerce_forced_unit( + self, + &cause, + &mut |db| { + db.span_label( + fn_decl.output.span(), + format!( + "expected `{}` because of this return type", + fn_decl.output, + ), + ); + }, + true, + ); + } else { + coercion.coerce_forced_unit(self, &cause, &mut |_| (), true); + } } tcx.types.never } diff --git a/src/test/ui/error-codes/E0069.stderr b/src/test/ui/error-codes/E0069.stderr index 0ba1ed456635f..12b778f42e22c 100644 --- a/src/test/ui/error-codes/E0069.stderr +++ b/src/test/ui/error-codes/E0069.stderr @@ -1,8 +1,10 @@ error[E0069]: `return;` in a function whose return type is not `()` --> $DIR/E0069.rs:12:5 | +LL | fn foo() -> u8 { + | -- expected `u8` because of this return type LL | return; - | ^^^^^^ return type is not () + | ^^^^^^ return type is not `()` error: aborting due to previous error diff --git a/src/test/ui/ret-non-nil.stderr b/src/test/ui/ret-non-nil.stderr index 01f126bd11ea2..e0fdc8c67edf7 100644 --- a/src/test/ui/ret-non-nil.stderr +++ b/src/test/ui/ret-non-nil.stderr @@ -2,7 +2,9 @@ error[E0069]: `return;` in a function whose return type is not `()` --> $DIR/ret-non-nil.rs:15:19 | LL | fn g() -> isize { return; } - | ^^^^^^ return type is not () + | ----- ^^^^^^ return type is not `()` + | | + | expected `isize` because of this return type error: aborting due to previous error diff --git a/src/test/ui/return/return-unit-from-diverging.stderr b/src/test/ui/return/return-unit-from-diverging.stderr index 38d4ca37366ff..5a9f0877cc6b6 100644 --- a/src/test/ui/return/return-unit-from-diverging.stderr +++ b/src/test/ui/return/return-unit-from-diverging.stderr @@ -1,8 +1,10 @@ error[E0069]: `return;` in a function whose return type is not `()` --> $DIR/return-unit-from-diverging.rs:15:5 | +LL | fn fail() -> ! { + | - expected `!` because of this return type LL | return; //~ ERROR in a function whose return type is not - | ^^^^^^ return type is not () + | ^^^^^^ return type is not `()` error: aborting due to previous error From cdbccf50a7746a07c44a404c270f188f64c5abf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 20 Dec 2018 16:52:52 -0800 Subject: [PATCH 09/20] Point at coercion source on type errors for fn returning `impl Trait` --- src/librustc_typeck/check/coercion.rs | 15 +++++++++++++++ src/librustc_typeck/check/mod.rs | 4 ++++ src/libsyntax_pos/lib.rs | 7 +++++++ src/test/ui/impl-trait/equality.stderr | 3 +++ 4 files changed, 29 insertions(+) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 0b99a30b67dc8..c7adf2982272c 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1183,6 +1183,11 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> (self.final_ty.unwrap_or(self.expected_ty), expression_ty) }; + let reason_label = if label_expression_as_expected { + "found because of this statement" + } else { + "expected because of this statement" + }; let mut db; match cause.code { ObligationCauseCode::ReturnNoExpression => { @@ -1207,9 +1212,19 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> cause.span, blk_id, ); + if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() { + if !sp.overlaps(cause.span) { + db.span_label(*sp, reason_label); + } + } } _ => { db = fcx.report_mismatched_types(cause, expected, found, err); + if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() { + if !sp.overlaps(cause.span) { + db.span_label(*sp, reason_label); + } + } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d40afbbc3025b..50cf5ef1655fa 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -535,6 +535,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { err_count_on_creation: usize, ret_coercion: Option>>, + ret_coercion_span: RefCell>, yield_ty: Option>, @@ -1984,6 +1985,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { param_env, err_count_on_creation: inh.tcx.sess.err_count(), ret_coercion: None, + ret_coercion_span: RefCell::new(None), yield_ty: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), @@ -4099,9 +4101,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { struct_span_err!(self.tcx.sess, expr.span, E0572, "return statement outside of function body").emit(); } else if let Some(ref e) = *expr_opt { + *self.ret_coercion_span.borrow_mut() = Some(e.span); self.check_return_expr(e); } else { let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); + *self.ret_coercion_span.borrow_mut() = Some(expr.span); let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); if let Some((fn_decl, _)) = self.get_fn_decl(expr.id) { coercion.coerce_forced_unit( diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 8b7ffa499cd71..514dea7fb1704 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -331,6 +331,13 @@ impl Span { span.lo <= other.lo && other.hi <= span.hi } + /// Return `true` if `self` touches `other`. + pub fn overlaps(self, other: Span) -> bool { + let span = self.data(); + let other = other.data(); + span.lo < other.hi && other.lo < span.hi + } + /// Return true if the spans are equal with regards to the source text. /// /// Use this instead of `==` when either span could be generated code, diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index e277d4e28cb2b..f1d2071bbdb9e 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -1,6 +1,9 @@ error[E0308]: mismatched types --> $DIR/equality.rs:25:5 | +LL | return 1_i32; + | ----- expected because of this statement +LL | } LL | 0_u32 | ^^^^^ expected i32, found u32 | From f8e508cde4854cc4da4333a33696f0e67d366d78 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 17 Dec 2018 14:20:42 +0100 Subject: [PATCH 10/20] Fix a recently introduces regression --- src/librustc_mir/transform/qualify_consts.rs | 2 +- .../consts/static_mut_containing_mut_ref.rs | 7 +++++++ .../consts/static_mut_containing_mut_ref2.rs | 8 ++++++++ .../static_mut_containing_mut_ref2.stderr | 9 +++++++++ src/test/ui/write-to-static-mut-in-static.rs | 4 ++-- .../ui/write-to-static-mut-in-static.stderr | 20 ++++++++++++++++--- 6 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/consts/static_mut_containing_mut_ref.rs create mode 100644 src/test/ui/consts/static_mut_containing_mut_ref2.rs create mode 100644 src/test/ui/consts/static_mut_containing_mut_ref2.stderr diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index b854f029e5106..646a671d4a2ce 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -518,7 +518,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Only allow statics (not consts) to refer to other statics. if self.mode == Mode::Static || self.mode == Mode::StaticMut { - if context.is_mutating_use() { + if self.mode == Mode::Static && context.is_mutating_use() { // this is not strictly necessary as miri will also bail out // For interior mutability we can't really catch this statically as that // goes through raw pointers and intermediate temporaries, so miri has diff --git a/src/test/ui/consts/static_mut_containing_mut_ref.rs b/src/test/ui/consts/static_mut_containing_mut_ref.rs new file mode 100644 index 0000000000000..27e1a111163b1 --- /dev/null +++ b/src/test/ui/consts/static_mut_containing_mut_ref.rs @@ -0,0 +1,7 @@ +// compile-pass + +static mut STDERR_BUFFER_SPACE: [u8; 42] = [0u8; 42]; + +pub static mut STDERR_BUFFER: *mut [u8] = unsafe { &mut STDERR_BUFFER_SPACE }; + +fn main() {} diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs new file mode 100644 index 0000000000000..aa9bfb4aeab2d --- /dev/null +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs @@ -0,0 +1,8 @@ +#![feature(const_let)] + +static mut STDERR_BUFFER_SPACE: u8 = 0; + +pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; +//~^ references in statics may only refer to immutable values + +fn main() {} diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stderr new file mode 100644 index 0000000000000..72923431c90ed --- /dev/null +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stderr @@ -0,0 +1,9 @@ +error[E0017]: references in statics may only refer to immutable values + --> $DIR/static_mut_containing_mut_ref2.rs:5:46 + | +LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0017`. diff --git a/src/test/ui/write-to-static-mut-in-static.rs b/src/test/ui/write-to-static-mut-in-static.rs index 191f09b54ee73..983b5d48e60fc 100644 --- a/src/test/ui/write-to-static-mut-in-static.rs +++ b/src/test/ui/write-to-static-mut-in-static.rs @@ -12,10 +12,10 @@ pub static mut A: u32 = 0; pub static mut B: () = unsafe { A = 1; }; -//~^ ERROR cannot mutate statics in the initializer of another static +//~^ ERROR could not evaluate static initializer pub static mut C: u32 = unsafe { C = 1; 0 }; -//~^ ERROR cannot mutate statics in the initializer of another static +//~^ ERROR cycle detected pub static D: u32 = D; diff --git a/src/test/ui/write-to-static-mut-in-static.stderr b/src/test/ui/write-to-static-mut-in-static.stderr index 673a71b4642f3..335f849fb2472 100644 --- a/src/test/ui/write-to-static-mut-in-static.stderr +++ b/src/test/ui/write-to-static-mut-in-static.stderr @@ -1,14 +1,28 @@ -error: cannot mutate statics in the initializer of another static +error[E0080]: could not evaluate static initializer --> $DIR/write-to-static-mut-in-static.rs:14:33 | LL | pub static mut B: () = unsafe { A = 1; }; - | ^^^^^ + | ^^^^^ tried to modify a static's initial value from another static's initializer -error: cannot mutate statics in the initializer of another static +error[E0391]: cycle detected when const-evaluating `C` --> $DIR/write-to-static-mut-in-static.rs:17:34 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^ + | +note: ...which requires const-evaluating `C`... + --> $DIR/write-to-static-mut-in-static.rs:17:1 + | +LL | pub static mut C: u32 = unsafe { C = 1; 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires const-evaluating `C`, completing the cycle +note: cycle used when const-evaluating + checking `C` + --> $DIR/write-to-static-mut-in-static.rs:17:1 + | +LL | pub static mut C: u32 = unsafe { C = 1; 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors +Some errors occurred: E0080, E0391. +For more information about an error, try `rustc --explain E0080`. From b9d74fc3ceec744ac6dbfb6b0d8d1003b54668e8 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 17 Dec 2018 14:36:10 +0100 Subject: [PATCH 11/20] Also test projections --- src/test/ui/consts/static_mut_containing_mut_ref2.rs | 2 +- src/test/ui/consts/static_mut_containing_mut_ref3.rs | 8 ++++++++ src/test/ui/consts/static_mut_containing_mut_ref3.stderr | 9 +++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/consts/static_mut_containing_mut_ref3.rs create mode 100644 src/test/ui/consts/static_mut_containing_mut_ref3.stderr diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs index aa9bfb4aeab2d..aeb69b2652cbf 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.rs +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs @@ -3,6 +3,6 @@ static mut STDERR_BUFFER_SPACE: u8 = 0; pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; -//~^ references in statics may only refer to immutable values +//~^ ERROR references in statics may only refer to immutable values fn main() {} diff --git a/src/test/ui/consts/static_mut_containing_mut_ref3.rs b/src/test/ui/consts/static_mut_containing_mut_ref3.rs new file mode 100644 index 0000000000000..0bc7faa9afdec --- /dev/null +++ b/src/test/ui/consts/static_mut_containing_mut_ref3.rs @@ -0,0 +1,8 @@ +#![feature(const_let)] + +static mut FOO: (u8, u8) = (42, 43); + +static mut BAR: () = unsafe { FOO.0 = 99; }; +//~^ ERROR could not evaluate static initializer + +fn main() {} diff --git a/src/test/ui/consts/static_mut_containing_mut_ref3.stderr b/src/test/ui/consts/static_mut_containing_mut_ref3.stderr new file mode 100644 index 0000000000000..cae53c6fee9dd --- /dev/null +++ b/src/test/ui/consts/static_mut_containing_mut_ref3.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/static_mut_containing_mut_ref3.rs:5:31 + | +LL | static mut BAR: () = unsafe { FOO.0 = 99; }; + | ^^^^^^^^^^ tried to modify a static's initial value from another static's initializer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. From 3414be0b3eb6192c13865e794817de396eeccd4b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Dec 2018 11:33:29 +0100 Subject: [PATCH 12/20] fix deprecation warnings in liballoc benches --- Cargo.lock | 1 + src/liballoc/Cargo.toml | 1 + src/liballoc/benches/btree/map.rs | 4 ++-- src/liballoc/benches/lib.rs | 1 + src/liballoc/benches/slice.rs | 3 ++- src/liballoc/benches/str.rs | 8 ++++---- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e03474565d85..06d01ab78f3a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,7 @@ dependencies = [ "compiler_builtins 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index b2eb3566c04a7..861c7cecb8879 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -15,6 +15,7 @@ compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = "0.6" +rand_xorshift = "0.1" [[test]] name = "collectionstests" diff --git a/src/liballoc/benches/btree/map.rs b/src/liballoc/benches/btree/map.rs index 20b9091a07bfc..6e2b5e06b7a91 100644 --- a/src/liballoc/benches/btree/map.rs +++ b/src/liballoc/benches/btree/map.rs @@ -12,7 +12,7 @@ use std::iter::Iterator; use std::vec::Vec; use std::collections::BTreeMap; -use rand::{Rng, thread_rng}; +use rand::{Rng, seq::SliceRandom, thread_rng}; use test::{Bencher, black_box}; macro_rules! map_insert_rand_bench { @@ -78,7 +78,7 @@ macro_rules! map_find_rand_bench { map.insert(k, k); } - rng.shuffle(&mut keys); + keys.shuffle(&mut rng); // measure let mut i = 0; diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index b4f4fd74f3a39..9502a7dc3c075 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -13,6 +13,7 @@ #![feature(test)] extern crate rand; +extern crate rand_xorshift; extern crate test; mod btree; diff --git a/src/liballoc/benches/slice.rs b/src/liballoc/benches/slice.rs index 490320f57cbf7..fc58899406332 100644 --- a/src/liballoc/benches/slice.rs +++ b/src/liballoc/benches/slice.rs @@ -12,8 +12,9 @@ use rand::{thread_rng}; use std::mem; use std::ptr; -use rand::{Rng, SeedableRng, XorShiftRng}; +use rand::{Rng, SeedableRng}; use rand::distributions::{Standard, Alphanumeric}; +use rand_xorshift::XorShiftRng; use test::{Bencher, black_box}; #[bench] diff --git a/src/liballoc/benches/str.rs b/src/liballoc/benches/str.rs index 38c94d4d8b5f3..c5e1576d24e26 100644 --- a/src/liballoc/benches/str.rs +++ b/src/liballoc/benches/str.rs @@ -274,11 +274,11 @@ make_test!(split_a_str, s, s.split("a").count()); make_test!(trim_ascii_char, s, { s.trim_matches(|c: char| c.is_ascii()) }); -make_test!(trim_left_ascii_char, s, { - s.trim_left_matches(|c: char| c.is_ascii()) +make_test!(trim_start_ascii_char, s, { + s.trim_start_matches(|c: char| c.is_ascii()) }); -make_test!(trim_right_ascii_char, s, { - s.trim_right_matches(|c: char| c.is_ascii()) +make_test!(trim_end_ascii_char, s, { + s.trim_end_matches(|c: char| c.is_ascii()) }); make_test!(find_underscore_char, s, s.find('_')); From 6ed596ebe245df1a8de8a609222c8e217508f6dd Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 21 Dec 2018 13:39:45 +0100 Subject: [PATCH 13/20] Update tests to changes on master --- src/test/ui/consts/static_mut_containing_mut_ref2.rs | 1 + .../ui/consts/static_mut_containing_mut_ref2.stderr | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs index aeb69b2652cbf..4180b1e295ab0 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.rs +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs @@ -4,5 +4,6 @@ static mut STDERR_BUFFER_SPACE: u8 = 0; pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; //~^ ERROR references in statics may only refer to immutable values +//~| ERROR static contains unimplemented expression type fn main() {} diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stderr index 72923431c90ed..f0ae1545056b7 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stderr @@ -4,6 +4,13 @@ error[E0017]: references in statics may only refer to immutable values LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values -error: aborting due to previous error +error[E0019]: static contains unimplemented expression type + --> $DIR/static_mut_containing_mut_ref2.rs:5:45 + | +LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0017`. +Some errors occurred: E0017, E0019. +For more information about an error, try `rustc --explain E0017`. From 097d39d8ecb2d8aa828393c66e85716081188793 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 21 Dec 2018 23:12:15 +0100 Subject: [PATCH 14/20] Fix alignment for array indexing We need to reduce the alignment with the used offset. If the offset isn't known, we need to reduce with the element size to support arbitrary offsets. --- src/librustc_codegen_ssa/mir/place.rs | 13 ++++++-- src/librustc_codegen_ssa/mir/rvalue.rs | 3 +- src/test/codegen/issue-56927.rs | 44 ++++++++++++++++++++++++++ src/test/codegen/packed.rs | 36 +++++++++++++++++++++ 4 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 src/test/codegen/issue-56927.rs diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 90aa9f6cbc763..5fad4a24b262e 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -335,11 +335,20 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, llindex: V ) -> Self { + // Statically compute the offset if we can, otherwise just use the element size, + // as this will yield the lowest alignment. + let layout = self.layout.field(bx, 0); + let offset = if bx.is_const_integral(llindex) { + layout.size.checked_mul(bx.const_to_uint(llindex), bx).unwrap_or(layout.size) + } else { + layout.size + }; + PlaceRef { llval: bx.inbounds_gep(self.llval, &[bx.cx().const_usize(0), llindex]), llextra: None, - layout: self.layout.field(bx.cx(), 0), - align: self.align + layout, + align: self.align.restrict_for_offset(offset), } } diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index c932ffd1c1bda..052342dd7597b 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -131,8 +131,9 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end); header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb()); + let align = dest.align.restrict_for_offset(dest.layout.field(bx.cx(), 0).size); cg_elem.val.store(&mut body_bx, - PlaceRef::new_sized(current, cg_elem.layout, dest.align)); + PlaceRef::new_sized(current, cg_elem.layout, align)); let next = body_bx.inbounds_gep(current, &[bx.cx().const_usize(1)]); body_bx.br(header_bx.llbb()); diff --git a/src/test/codegen/issue-56927.rs b/src/test/codegen/issue-56927.rs new file mode 100644 index 0000000000000..0544ff86aacfa --- /dev/null +++ b/src/test/codegen/issue-56927.rs @@ -0,0 +1,44 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type="rlib"] +use std::usize; + +#[repr(align(16))] +pub struct S { + arr: [u32; 4], +} + +// CHECK-LABEL: @test1 +// CHECK: store i32 0, i32* %{{.+}}, align 16 +// CHECK: store i32 1, i32* %{{.+}}, align 4 +// CHECK: store i32 2, i32* %{{.+}}, align 8 +// CHECK: store i32 3, i32* %{{.+}}, align 4 +#[no_mangle] +pub fn test1(s: &mut S) { + s.arr[0] = 0; + s.arr[1] = 1; + s.arr[2] = 2; + s.arr[3] = 3; +} + +// CHECK-LABEL: @test2 +// CHECK: store i32 4, i32* %{{.+}}, align 4 +#[allow(const_err)] +#[no_mangle] +pub fn test2(s: &mut S) { + s.arr[usize::MAX / 4 + 1] = 4; +} + +// CHECK-LABEL: @test3 +// CHECK: store i32 5, i32* %{{.+}}, align 4 +#[no_mangle] +pub fn test3(s: &mut S, i: usize) { + s.arr[i] = 5; +} + +// CHECK-LABEL: @test4 +// CHECK: store i32 6, i32* %{{.+}}, align 4 +#[no_mangle] +pub fn test4(s: &mut S) { + s.arr = [6; 4]; +} diff --git a/src/test/codegen/packed.rs b/src/test/codegen/packed.rs index b50f5b6f16fed..e60051de559b5 100644 --- a/src/test/codegen/packed.rs +++ b/src/test/codegen/packed.rs @@ -84,6 +84,42 @@ pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 { BigPacked2 { dealign: 0, data: f() } } +// CHECK-LABEL: @write_packed_array1 +// CHECK: store i32 0, i32* %{{.+}}, align 1 +// CHECK: store i32 1, i32* %{{.+}}, align 1 +// CHECK: store i32 2, i32* %{{.+}}, align 1 +#[no_mangle] +pub fn write_packed_array1(p: &mut BigPacked1) { + p.data.0[0] = 0; + p.data.0[1] = 1; + p.data.0[2] = 2; +} + +// CHECK-LABEL: @write_packed_array2 +// CHECK: store i32 0, i32* %{{.+}}, align 2 +// CHECK: store i32 1, i32* %{{.+}}, align 2 +// CHECK: store i32 2, i32* %{{.+}}, align 2 +#[no_mangle] +pub fn write_packed_array2(p: &mut BigPacked2) { + p.data.0[0] = 0; + p.data.0[1] = 1; + p.data.0[2] = 2; +} + +// CHECK-LABEL: @repeat_packed_array1 +// CHECK: store i32 42, i32* %{{.+}}, align 1 +#[no_mangle] +pub fn repeat_packed_array1(p: &mut BigPacked1) { + p.data.0 = [42; 8]; +} + +// CHECK-LABEL: @repeat_packed_array2 +// CHECK: store i32 42, i32* %{{.+}}, align 2 +#[no_mangle] +pub fn repeat_packed_array2(p: &mut BigPacked2) { + p.data.0 = [42; 8]; +} + #[repr(packed)] #[derive(Copy, Clone)] pub struct Packed1Pair(u8, u32); From 3986c964481a048100565c8d30b1937ec2eb516d Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Sun, 18 Nov 2018 22:21:38 -0800 Subject: [PATCH 15/20] enum type instead of variant suggestion unification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Weirdly, we were deciding between a help note and a structured suggestion based on whether the import candidate span was a dummy—but we weren't using that span in any case! The dummy-ness of the span (which appears to be a matter of this-crate vs. other-crate definition) isn't the right criterion by which we should decide whether it's germane to mention that "there is an enum variant"; instead, let's use the someness of `def` (which is used as the `has_unexpected_resolution` argument to `error_code`). Since `import_candidate_to_paths` has no other callers, we are free to stop returning the span and rename the function. By using `span_suggestions_`, we leverage the max-suggestions output limit already built in to the emitter, thus resolving #56028. In the matter of message wording, "you can" is redundant (and perhaps too informal); prefer the imperative. --- src/librustc_resolve/lib.rs | 46 +++++++++++-------- .../issue-56028-there-is-an-enum-variant.rs | 13 ++++++ ...ssue-56028-there-is-an-enum-variant.stderr | 38 +++++++++++++++ src/test/ui/enum/enum-variant-type-2.stderr | 2 +- src/test/ui/issues/issue-17546.stderr | 4 +- src/test/ui/issues/issue-30535.stderr | 7 +-- src/test/ui/issues/issue-35075.stderr | 18 ++++---- src/test/ui/issues/issue-35675.stderr | 32 ++++++++----- .../ui/variants/variant-used-as-type.stderr | 16 +++---- 9 files changed, 122 insertions(+), 54 deletions(-) create mode 100644 src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.rs create mode 100644 src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 794e5741d62ca..8f329283b1a28 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3213,23 +3213,33 @@ impl<'a> Resolver<'a> { let enum_candidates = this.lookup_import_candidates(ident, ns, is_enum_variant); let mut enum_candidates = enum_candidates.iter() - .map(|suggestion| import_candidate_to_paths(&suggestion)).collect::>(); + .map(|suggestion| { + import_candidate_to_enum_paths(&suggestion) + }).collect::>(); enum_candidates.sort(); - for (sp, variant_path, enum_path) in enum_candidates { - if sp.is_dummy() { - let msg = format!("there is an enum variant `{}`, \ - try using `{}`?", - variant_path, - enum_path); - err.help(&msg); + + if !enum_candidates.is_empty() { + // contextualize for E0412 "cannot find type", but don't belabor the point + // (that it's a variant) for E0573 "expected type, found variant" + let preamble = if def.is_none() { + let others = match enum_candidates.len() { + 1 => String::new(), + 2 => " and 1 other".to_owned(), + n => format!(" and {} others", n) + }; + format!("there is an enum variant `{}`{}; ", + enum_candidates[0].0, others) } else { - err.span_suggestion_with_applicability( - span, - "you can try using the variant's enum", - enum_path, - Applicability::MachineApplicable, - ); - } + String::new() + }; + let msg = format!("{}try using the variant's enum", preamble); + + err.span_suggestions_with_applicability( + span, + &msg, + enum_candidates.into_iter().map(|(_variant, enum_ty)| enum_ty), + Applicability::MachineApplicable, + ); } } if path.len() == 1 && this.self_type_is_available(span) { @@ -5128,8 +5138,8 @@ fn path_names_to_string(path: &Path) -> String { .collect::>()) } -/// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant. -fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, String) { +/// Get the stringified path for an enum from an `ImportSuggestion` for an enum variant. +fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) { let variant_path = &suggestion.path; let variant_path_string = path_names_to_string(variant_path); @@ -5140,7 +5150,7 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, St }; let enum_path_string = path_names_to_string(&enum_path); - (suggestion.path.span, variant_path_string, enum_path_string) + (variant_path_string, enum_path_string) } diff --git a/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.rs b/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.rs new file mode 100644 index 0000000000000..ec41c41141616 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.rs @@ -0,0 +1,13 @@ +enum PutDown { Set } +enum AffixHeart { Set } +enum CauseToBe { Set } +enum Determine { Set } +enum TableDishesAction { Set } +enum Solidify { Set } +enum UnorderedCollection { Set } + +fn setup() -> Set { Set } + +fn main() { + setup(); +} diff --git a/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr b/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr new file mode 100644 index 0000000000000..6107ca32a5d75 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr @@ -0,0 +1,38 @@ +error[E0412]: cannot find type `Set` in this scope + --> $DIR/issue-56028-there-is-an-enum-variant.rs:9:15 + | +LL | fn setup() -> Set { Set } + | ^^^ not found in this scope +help: there is an enum variant `AffixHeart::Set` and 7 others; try using the variant's enum + | +LL | fn setup() -> AffixHeart { Set } + | ^^^^^^^^^^ +LL | fn setup() -> CauseToBe { Set } + | ^^^^^^^^^ +LL | fn setup() -> Determine { Set } + | ^^^^^^^^^ +LL | fn setup() -> PutDown { Set } + | ^^^^^^^ +and 3 other candidates + +error[E0425]: cannot find value `Set` in this scope + --> $DIR/issue-56028-there-is-an-enum-variant.rs:9:21 + | +LL | fn setup() -> Set { Set } + | ^^^ not found in this scope +help: possible candidates are found in other modules, you can import them into scope + | +LL | use AffixHeart::Set; + | +LL | use CauseToBe::Set; + | +LL | use Determine::Set; + | +LL | use PutDown::Set; + | +and 3 other candidates + +error: aborting due to 2 previous errors + +Some errors occurred: E0412, E0425. +For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/enum/enum-variant-type-2.stderr b/src/test/ui/enum/enum-variant-type-2.stderr index 7a786af71bb3f..eb869f5539f36 100644 --- a/src/test/ui/enum/enum-variant-type-2.stderr +++ b/src/test/ui/enum/enum-variant-type-2.stderr @@ -5,7 +5,7 @@ LL | fn foo(x: Foo::Bar) {} //~ ERROR expected type, found variant `Foo::Bar` | ^^^^^^^^ | | | not a type - | help: you can try using the variant's enum: `Foo` + | help: try using the variant's enum: `Foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17546.stderr b/src/test/ui/issues/issue-17546.stderr index 39f7d5fcc04bc..a8ab5e8eb7745 100644 --- a/src/test/ui/issues/issue-17546.stderr +++ b/src/test/ui/issues/issue-17546.stderr @@ -5,7 +5,7 @@ LL | fn new() -> NoResult { | --------^^^^^^^^^^^^^^^^ | | | did you mean `Result`? - | help: you can try using the variant's enum: `foo::MyEnum` + | help: try using the variant's enum: `foo::MyEnum` error[E0573]: expected type, found variant `Result` --> $DIR/issue-17546.rs:32:17 @@ -48,7 +48,7 @@ LL | fn newer() -> NoResult { | --------^^^^^^^^^^^^^^^^^^^^^ | | | did you mean `Result`? - | help: you can try using the variant's enum: `foo::MyEnum` + | help: try using the variant's enum: `foo::MyEnum` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-30535.stderr b/src/test/ui/issues/issue-30535.stderr index c3838fdb9cf07..35ef227acfce6 100644 --- a/src/test/ui/issues/issue-30535.stderr +++ b/src/test/ui/issues/issue-30535.stderr @@ -2,9 +2,10 @@ error[E0573]: expected type, found variant `foo::Foo::FooV` --> $DIR/issue-30535.rs:16:8 | LL | _: foo::Foo::FooV //~ ERROR expected type, found variant `foo::Foo::FooV` - | ^^^^^^^^^^^^^^ not a type - | - = help: there is an enum variant `foo::Foo::FooV`, try using `foo::Foo`? + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `foo::Foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-35075.stderr b/src/test/ui/issues/issue-35075.stderr index 9b2f17f038b8f..ead07a5f0c8fe 100644 --- a/src/test/ui/issues/issue-35075.stderr +++ b/src/test/ui/issues/issue-35075.stderr @@ -2,19 +2,21 @@ error[E0412]: cannot find type `Foo` in this scope --> $DIR/issue-35075.rs:12:12 | LL | inner: Foo //~ ERROR cannot find type `Foo` in this scope - | ^^^--- - | | - | not found in this scope - | help: you can try using the variant's enum: `Baz` + | ^^^ not found in this scope +help: there is an enum variant `Baz::Foo`; try using the variant's enum + | +LL | inner: Baz //~ ERROR cannot find type `Foo` in this scope + | ^^^ error[E0412]: cannot find type `Foo` in this scope --> $DIR/issue-35075.rs:16:9 | LL | Foo(Foo) //~ ERROR cannot find type `Foo` in this scope - | ^^^--- - | | - | not found in this scope - | help: you can try using the variant's enum: `Baz` + | ^^^ not found in this scope +help: there is an enum variant `Baz::Foo`; try using the variant's enum + | +LL | Foo(Baz) //~ ERROR cannot find type `Foo` in this scope + | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-35675.stderr b/src/test/ui/issues/issue-35675.stderr index fef8de3a28d9e..2f07ee7124d07 100644 --- a/src/test/ui/issues/issue-35675.stderr +++ b/src/test/ui/issues/issue-35675.stderr @@ -2,10 +2,11 @@ error[E0412]: cannot find type `Apple` in this scope --> $DIR/issue-35675.rs:17:29 | LL | fn should_return_fruit() -> Apple { + | ^^^^^ not found in this scope +help: there is an enum variant `Fruit::Apple`; try using the variant's enum + | +LL | fn should_return_fruit() -> Fruit { | ^^^^^ - | | - | not found in this scope - | help: you can try using the variant's enum: `Fruit` error[E0425]: cannot find function `Apple` in this scope --> $DIR/issue-35675.rs:19:5 @@ -24,7 +25,7 @@ LL | fn should_return_fruit_too() -> Fruit::Apple { | ^^^^^^^^^^^^ | | | not a type - | help: you can try using the variant's enum: `Fruit` + | help: try using the variant's enum: `Fruit` error[E0425]: cannot find function `Apple` in this scope --> $DIR/issue-35675.rs:25:5 @@ -41,27 +42,34 @@ error[E0573]: expected type, found variant `Ok` | LL | fn foo() -> Ok { | ^^ not a type +help: try using the variant's enum | - = help: there is an enum variant `std::prelude::v1::Ok`, try using `std::prelude::v1`? - = help: there is an enum variant `std::result::Result::Ok`, try using `std::result::Result`? +LL | fn foo() -> std::prelude::v1 { + | ^^^^^^^^^^^^^^^^ +LL | fn foo() -> std::result::Result { + | ^^^^^^^^^^^^^^^^^^^ error[E0412]: cannot find type `Variant3` in this scope --> $DIR/issue-35675.rs:34:13 | LL | fn bar() -> Variant3 { - | ^^^^^^^^ - | | - | not found in this scope - | help: you can try using the variant's enum: `x::Enum` + | ^^^^^^^^ not found in this scope +help: there is an enum variant `x::Enum::Variant3`; try using the variant's enum + | +LL | fn bar() -> x::Enum { + | ^^^^^^^ error[E0573]: expected type, found variant `Some` --> $DIR/issue-35675.rs:38:13 | LL | fn qux() -> Some { | ^^^^ not a type +help: try using the variant's enum | - = help: there is an enum variant `std::prelude::v1::Option::Some`, try using `std::prelude::v1::Option`? - = help: there is an enum variant `std::prelude::v1::Some`, try using `std::prelude::v1`? +LL | fn qux() -> std::prelude::v1::Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn qux() -> std::prelude::v1 { + | ^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/variants/variant-used-as-type.stderr b/src/test/ui/variants/variant-used-as-type.stderr index 972fe8a8a616b..c72729923ef6d 100644 --- a/src/test/ui/variants/variant-used-as-type.stderr +++ b/src/test/ui/variants/variant-used-as-type.stderr @@ -3,28 +3,24 @@ error[E0573]: expected type, found variant `Ty::A` | LL | B(Ty::A), | ^^^^^ not a type -help: you can try using the variant's enum - | -LL | B(Ty), - | ^^ -help: you can try using the variant's enum +help: try using the variant's enum | LL | B(E), | ^ +LL | B(Ty), + | ^^ error[E0573]: expected type, found variant `E::A` --> $DIR/variant-used-as-type.rs:27:6 | LL | impl E::A {} | ^^^^ not a type -help: you can try using the variant's enum - | -LL | impl Ty {} - | ^^ -help: you can try using the variant's enum +help: try using the variant's enum | LL | impl E {} | ^ +LL | impl Ty {} + | ^^ error: aborting due to 2 previous errors From 64ad3e2c423f701b856a6780380a0dbb03f90c22 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Fri, 23 Nov 2018 12:57:03 -0800 Subject: [PATCH 16/20] adjust enum type instead of variant suggestions for prelude enums The present author regrets not thinking of a more eloquent way to do this. --- src/librustc_resolve/lib.rs | 12 +++++++++- src/librustc_typeck/check/demand.rs | 1 + .../issue-56028-there-is-an-enum-variant.rs | 2 ++ src/test/ui/issues/issue-35675.stderr | 22 +++++++------------ 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8f329283b1a28..e543677ef0621 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3237,7 +3237,17 @@ impl<'a> Resolver<'a> { err.span_suggestions_with_applicability( span, &msg, - enum_candidates.into_iter().map(|(_variant, enum_ty)| enum_ty), + enum_candidates.into_iter() + .map(|(_variant_path, enum_ty_path)| enum_ty_path) + // variants reëxported in prelude doesn't mean `prelude::v1` is the + // type name! FIXME: is there a more principled way to do this that + // would work for other reëxports? + .filter(|enum_ty_path| enum_ty_path != "std::prelude::v1") + // also say `Option` rather than `std::prelude::v1::Option` + .map(|enum_ty_path| { + // FIXME #56861: DRYer prelude filtering + enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned() + }), Applicability::MachineApplicable, ); } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index db4b68611c51b..996b57f558cc5 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -123,6 +123,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let sole_field_ty = sole_field.ty(self.tcx, substs); if self.can_coerce(expr_ty, sole_field_ty) { let variant_path = self.tcx.item_path_str(variant.did); + // FIXME #56861: DRYer prelude filtering Some(variant_path.trim_start_matches("std::prelude::v1::").to_string()) } else { None diff --git a/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.rs b/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.rs index ec41c41141616..264cfa449942c 100644 --- a/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.rs +++ b/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.rs @@ -7,6 +7,8 @@ enum Solidify { Set } enum UnorderedCollection { Set } fn setup() -> Set { Set } +//~^ ERROR cannot find type `Set` in this scope +//~| ERROR cannot find value `Set` in this scope fn main() { setup(); diff --git a/src/test/ui/issues/issue-35675.stderr b/src/test/ui/issues/issue-35675.stderr index 2f07ee7124d07..652e1695a85a6 100644 --- a/src/test/ui/issues/issue-35675.stderr +++ b/src/test/ui/issues/issue-35675.stderr @@ -41,13 +41,10 @@ error[E0573]: expected type, found variant `Ok` --> $DIR/issue-35675.rs:29:13 | LL | fn foo() -> Ok { - | ^^ not a type -help: try using the variant's enum - | -LL | fn foo() -> std::prelude::v1 { - | ^^^^^^^^^^^^^^^^ -LL | fn foo() -> std::result::Result { - | ^^^^^^^^^^^^^^^^^^^ + | ^^ + | | + | not a type + | help: try using the variant's enum: `std::result::Result` error[E0412]: cannot find type `Variant3` in this scope --> $DIR/issue-35675.rs:34:13 @@ -63,13 +60,10 @@ error[E0573]: expected type, found variant `Some` --> $DIR/issue-35675.rs:38:13 | LL | fn qux() -> Some { - | ^^^^ not a type -help: try using the variant's enum - | -LL | fn qux() -> std::prelude::v1::Option { - | ^^^^^^^^^^^^^^^^^^^^^^^^ -LL | fn qux() -> std::prelude::v1 { - | ^^^^^^^^^^^^^^^^ + | ^^^^ + | | + | not a type + | help: try using the variant's enum: `Option` error: aborting due to 7 previous errors From 2820dc868a35c02adb9225492d575c7d5e72338c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 22 Dec 2018 19:20:13 -0800 Subject: [PATCH 17/20] Remove dead code --- src/librustc_typeck/check/coercion.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index c7adf2982272c..58cbb0ea538f1 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1183,11 +1183,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> (self.final_ty.unwrap_or(self.expected_ty), expression_ty) }; - let reason_label = if label_expression_as_expected { - "found because of this statement" - } else { - "expected because of this statement" - }; + let reason_label = "expected because of this statement"; let mut db; match cause.code { ObligationCauseCode::ReturnNoExpression => { From b42a3acaeca0f14df7d35b87d0045b4d58c95b55 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 22 Dec 2018 18:06:20 +0100 Subject: [PATCH 18/20] stabilize min_const_unsafe_fn in 1.33. --- src/librustc/ich/impls_mir.rs | 1 - src/librustc/mir/mod.rs | 3 - src/librustc_mir/transform/check_unsafety.rs | 29 +-------- src/libstd/lib.rs | 1 - src/libsyntax/feature_gate.rs | 5 +- src/test/run-pass-fulldeps/newtype_index.rs | 2 +- src/test/rustdoc/const-display.rs | 1 - .../min_const_fn/min_const_fn_unsafe.rs | 51 +++++++++++++--- .../min_const_fn/min_const_fn_unsafe.stderr | 49 +++++++-------- .../min_const_fn_unsafe_feature_gate.rs | 61 ------------------- .../min_const_fn_unsafe_feature_gate.stderr | 44 ------------- .../min_const_unsafe_fn_libstd_stability.rs | 1 - .../min_const_unsafe_fn_libstd_stability2.rs | 1 - 13 files changed, 72 insertions(+), 177 deletions(-) delete mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs delete mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index d82020f59a10e..6852e2c69618b 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -47,7 +47,6 @@ impl_stable_hash_for!(enum mir::BorrowKind { impl_stable_hash_for!(enum mir::UnsafetyViolationKind { General, GeneralAndConstFn, - GatedConstFnCall, ExternStatic(lint_node_id), BorrowPacked(lint_node_id), }); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index dc14450e8d22d..120350a573b6e 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2792,9 +2792,6 @@ impl Location { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum UnsafetyViolationKind { General, - /// Right now function calls to `const unsafe fn` are only permitted behind a feature gate - /// Also, even `const unsafe fn` need an `unsafe` block to do the allowed operations. - GatedConstFnCall, /// Permitted in const fn and regular fns GeneralAndConstFn, ExternStatic(ast::NodeId), diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index f6b7f817aad53..89d9c03f74e3e 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -23,7 +23,6 @@ use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext}; use syntax::ast; use syntax::symbol::Symbol; -use syntax::feature_gate::{emit_feature_err, GateIssue}; use std::ops::Bound; @@ -97,7 +96,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { if let hir::Unsafety::Unsafe = sig.unsafety() { self.require_unsafe("call to unsafe function", "consult the function's documentation for information on how to avoid \ - undefined behavior", UnsafetyViolationKind::GatedConstFnCall) + undefined behavior", UnsafetyViolationKind::GeneralAndConstFn) } } } @@ -325,11 +324,6 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { // compat lint violation.kind = UnsafetyViolationKind::General; }, - UnsafetyViolationKind::GatedConstFnCall => { - // safe code can't call unsafe const fns, this `UnsafetyViolationKind` - // is only relevant for `Safety::ExplicitUnsafe` in `unsafe const fn`s - violation.kind = UnsafetyViolationKind::General; - } } if !self.violations.contains(&violation) { self.violations.push(violation) @@ -346,19 +340,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } // only some unsafety is allowed in const fn if self.min_const_fn { - let min_const_unsafe_fn = self.tcx.features().min_const_unsafe_fn; for violation in violations { match violation.kind { - UnsafetyViolationKind::GatedConstFnCall if min_const_unsafe_fn => { - // these function calls to unsafe functions are allowed - // if `#![feature(min_const_unsafe_fn)]` is active - }, - UnsafetyViolationKind::GatedConstFnCall => { - // without the feature gate, we report errors - if !self.violations.contains(&violation) { - self.violations.push(violation.clone()) - } - } // these unsafe things are stable in const fn UnsafetyViolationKind::GeneralAndConstFn => {}, // these things are forbidden in const fns @@ -620,16 +603,6 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { .note(&details.as_str()[..]) .emit(); } - UnsafetyViolationKind::GatedConstFnCall => { - emit_feature_err( - &tcx.sess.parse_sess, - "min_const_unsafe_fn", - source_info.span, - GateIssue::Language, - "calls to `const unsafe fn` in const fns are unstable", - ); - - } UnsafetyViolationKind::ExternStatic(lint_node_id) => { tcx.lint_node_note(SAFE_EXTERN_STATICS, lint_node_id, diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0d3de34fe6438..99a682832286e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -273,7 +273,6 @@ #![feature(libc)] #![feature(link_args)] #![feature(linkage)] -#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))] #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(nll)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 941a3a288da5c..2238e429a58e0 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -486,9 +486,6 @@ declare_features! ( // `extern crate self as foo;` puts local crate root into extern prelude under name `foo`. (active, extern_crate_self, "1.31.0", Some(56409), None), - - // Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. - (active, min_const_unsafe_fn, "1.31.0", Some(55607), None), ); declare_features! ( @@ -694,6 +691,8 @@ declare_features! ( (accepted, underscore_imports, "1.33.0", Some(48216), None), // Allows `#[repr(packed(N))]` attribute on structs. (accepted, repr_packed, "1.33.0", Some(33158), None), + // Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. + (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), ); // If you change this, please modify `src/doc/unstable-book` as well. You must diff --git a/src/test/run-pass-fulldeps/newtype_index.rs b/src/test/run-pass-fulldeps/newtype_index.rs index 0fd7ccd55fb2d..3cd622a33b173 100644 --- a/src/test/run-pass-fulldeps/newtype_index.rs +++ b/src/test/run-pass-fulldeps/newtype_index.rs @@ -1,4 +1,4 @@ -#![feature(rustc_attrs, rustc_private, step_trait, min_const_unsafe_fn)] +#![feature(rustc_attrs, rustc_private, step_trait)] #[macro_use] extern crate rustc_data_structures; extern crate rustc_serialize; diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs index 8ac0d07ceefe4..f38fab91de7c4 100644 --- a/src/test/rustdoc/const-display.rs +++ b/src/test/rustdoc/const-display.rs @@ -15,7 +15,6 @@ issue = "0")] #![feature(rustc_const_unstable, const_fn, foo, foo2)] -#![feature(min_const_unsafe_fn)] #![feature(staged_api)] // @has 'foo/fn.foo.html' '//pre' 'pub unsafe fn foo() -> u32' diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs index 92e99c6228a9b..da875fe7a6b77 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs @@ -8,27 +8,62 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// gate-test-min_const_unsafe_fn +//------------------------------------------------------------------------------ +// OK +//------------------------------------------------------------------------------ -// ok const unsafe fn ret_i32_no_unsafe() -> i32 { 42 } const unsafe fn ret_null_ptr_no_unsafe() -> *const T { 0 as *const T } const unsafe fn ret_null_mut_ptr_no_unsafe() -> *mut T { 0 as *mut T } const fn no_unsafe() { unsafe {} } -// not ok const fn call_unsafe_const_fn() -> i32 { - unsafe { ret_i32_no_unsafe() } //~ ERROR calls to `const unsafe fn` in const fns are unstable + unsafe { ret_i32_no_unsafe() } } const fn call_unsafe_generic_const_fn() -> *const String { unsafe { ret_null_ptr_no_unsafe::() } - //~^ ERROR calls to `const unsafe fn` in const fns are unstable } -const fn call_unsafe_generic_cell_const_fn() -> *const Vec> { +const fn call_unsafe_generic_cell_const_fn() + -> *const Vec> +{ unsafe { ret_null_mut_ptr_no_unsafe::>>() } - //~^ ERROR calls to `const unsafe fn` in const fns } -const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } + +const unsafe fn call_unsafe_const_unsafe_fn() -> i32 { + unsafe { ret_i32_no_unsafe() } +} +const unsafe fn call_unsafe_generic_const_unsafe_fn() -> *const String { + unsafe { ret_null_ptr_no_unsafe::() } +} +const unsafe fn call_unsafe_generic_cell_const_unsafe_fn() + -> *const Vec> +{ + unsafe { ret_null_mut_ptr_no_unsafe::>>() } +} + +const unsafe fn call_unsafe_const_unsafe_fn_immediate() -> i32 { + ret_i32_no_unsafe() +} +const unsafe fn call_unsafe_generic_const_unsafe_fn_immediate() -> *const String { + ret_null_ptr_no_unsafe::() +} +const unsafe fn call_unsafe_generic_cell_const_unsafe_fn_immediate() + -> *const Vec> +{ + ret_null_mut_ptr_no_unsafe::>>() +} + +//------------------------------------------------------------------------------ +// NOT OK +//------------------------------------------------------------------------------ + +const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe +//~^ dereferencing raw pointers in constant functions + +const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } +//~^ dereferencing raw pointers in constant functions + +const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } //~^ dereferencing raw pointers in constant functions fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr index fafc89d149368..1ce23bc21bb3e 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr @@ -1,43 +1,44 @@ error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe.rs:31:59 + --> $DIR/min_const_fn_unsafe.rs:54:77 | -LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } - | ^^ +LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe + | ^^^ | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable -error[E0658]: unions in const fn are unstable (see issue #51909) - --> $DIR/min_const_fn_unsafe.rs:38:5 +error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) + --> $DIR/min_const_fn_unsafe.rs:57:70 | -LL | Foo { x: () }.y - | ^^^^^^^^^^^^^^^ +LL | const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } + | ^^ | - = help: add #![feature(const_fn_union)] to the crate attributes to enable + = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable -error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607) - --> $DIR/min_const_fn_unsafe.rs:21:14 +error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) + --> $DIR/min_const_fn_unsafe.rs:60:83 | -LL | unsafe { ret_i32_no_unsafe() } //~ ERROR calls to `const unsafe fn` in const fns are unstable - | ^^^^^^^^^^^^^^^^^^^ +LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } + | ^^^ | - = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable + = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable -error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607) - --> $DIR/min_const_fn_unsafe.rs:24:14 +error[E0658]: unions in const fn are unstable (see issue #51909) + --> $DIR/min_const_fn_unsafe.rs:67:5 | -LL | unsafe { ret_null_ptr_no_unsafe::() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Foo { x: () }.y + | ^^^^^^^^^^^^^^^ | - = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable + = help: add #![feature(const_fn_union)] to the crate attributes to enable -error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607) - --> $DIR/min_const_fn_unsafe.rs:28:14 +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/min_const_fn_unsafe.rs:54:77 | -LL | unsafe { ret_null_mut_ptr_no_unsafe::>>() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe + | ^^^ dereference of raw pointer | - = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable + = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors occurred: E0133, E0658. +For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs deleted file mode 100644 index 67a4820612642..0000000000000 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(min_const_unsafe_fn)] - -// ok -const unsafe fn foo4() -> i32 { 42 } -const unsafe fn foo5() -> *const T { 0 as *const T } -const unsafe fn foo6() -> *mut T { 0 as *mut T } -const fn no_unsafe() { unsafe {} } - -const fn foo8() -> i32 { - unsafe { foo4() } -} -const fn foo9() -> *const String { - unsafe { foo5::() } -} -const fn foo10() -> *const Vec> { - unsafe { foo6::>>() } -} -const unsafe fn foo8_3() -> i32 { - unsafe { foo4() } -} -const unsafe fn foo9_3() -> *const String { - unsafe { foo5::() } -} -const unsafe fn foo10_3() -> *const Vec> { - unsafe { foo6::>>() } -} -const unsafe fn foo8_2() -> i32 { - foo4() -} -const unsafe fn foo9_2() -> *const String { - foo5::() -} -const unsafe fn foo10_2() -> *const Vec> { - foo6::>>() -} -const unsafe fn foo30_3(x: *mut usize) -> usize { *x } -//~^ dereferencing raw pointers in constant functions - -const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } -//~^ dereferencing raw pointers in constant functions - -const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe -//~^ dereferencing raw pointers in constant functions - -fn main() {} - -const unsafe fn no_union() { - union Foo { x: (), y: () } - Foo { x: () }.y - //~^ unions in const fn -} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr deleted file mode 100644 index 63bf9a53e509c..0000000000000 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr +++ /dev/null @@ -1,44 +0,0 @@ -error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:46:51 - | -LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } - | ^^ - | - = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable - -error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:49:60 - | -LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } - | ^^^ - | - = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable - -error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:52:62 - | -LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe - | ^^^ - | - = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable - -error[E0658]: unions in const fn are unstable (see issue #51909) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:59:5 - | -LL | Foo { x: () }.y - | ^^^^^^^^^^^^^^^ - | - = help: add #![feature(const_fn_union)] to the crate attributes to enable - -error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/min_const_fn_unsafe_feature_gate.rs:52:62 - | -LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe - | ^^^ dereference of raw pointer - | - = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior - -error: aborting due to 5 previous errors - -Some errors occurred: E0133, E0658. -For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index f559c23ff0f54..33fcea9818959 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -14,7 +14,6 @@ issue = "0")] #![feature(rustc_const_unstable, const_fn, foo, foo2)] -#![feature(min_const_unsafe_fn)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs index 131bc97c85a2a..68205edd63bc9 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs @@ -14,7 +14,6 @@ issue = "0")] #![feature(rustc_const_unstable, const_fn, foo, foo2)] -#![feature(min_const_unsafe_fn)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] From bd1d5bc629ef43eb1574c0904b024bc0f9666616 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 22 Dec 2018 18:58:06 +0100 Subject: [PATCH 19/20] stabilize min_const_unsafe_fn --bless tests. --- src/test/ui/consts/const-size_of-cycle.stderr | 4 ---- .../ui/consts/min_const_fn/min_const_fn_unsafe.stderr | 10 +++++----- .../min_const_unsafe_fn_libstd_stability.stderr | 8 ++++---- .../min_const_unsafe_fn_libstd_stability2.stderr | 6 +++--- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index e824657f8afda..68f81f408f70a 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -5,10 +5,6 @@ LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires const-evaluating `Foo::bytes::{{constant}}`... - --> $SRC_DIR/libcore/mem.rs:LL:COL - | -LL | intrinsics::size_of::() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires computing layout of `Foo`... note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All }, value: [u8; _] }`... note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}`... diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr index 1ce23bc21bb3e..68b782bf0e7ea 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr @@ -1,5 +1,5 @@ error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe.rs:54:77 + --> $DIR/min_const_fn_unsafe.rs:60:77 | LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe | ^^^ @@ -7,7 +7,7 @@ LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe.rs:57:70 + --> $DIR/min_const_fn_unsafe.rs:63:70 | LL | const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } | ^^ @@ -15,7 +15,7 @@ LL | const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe.rs:60:83 + --> $DIR/min_const_fn_unsafe.rs:66:83 | LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } | ^^^ @@ -23,7 +23,7 @@ LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static u = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error[E0658]: unions in const fn are unstable (see issue #51909) - --> $DIR/min_const_fn_unsafe.rs:67:5 + --> $DIR/min_const_fn_unsafe.rs:73:5 | LL | Foo { x: () }.y | ^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | Foo { x: () }.y = help: add #![feature(const_fn_union)] to the crate attributes to enable error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/min_const_fn_unsafe.rs:54:77 + --> $DIR/min_const_fn_unsafe.rs:60:77 | LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe | ^^^ dereference of raw pointer diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index 37be2889173f8..2a0ef0e6b9651 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -1,23 +1,23 @@ error: can only call other `min_const_fn` within a `min_const_fn` - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:26:41 + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:25:41 | LL | const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn` | ^^^^^ error: can only call other `min_const_fn` within a `min_const_fn` - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:42 + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:32:42 | LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn` | ^^^^^^ error: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:37:33 + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:36:33 | LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op | ^^^^^^^^^^^^^ error: can only call other `min_const_fn` within a `min_const_fn` - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:45:48 + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:44:48 | LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other | ^^^^^^^^^^^^ diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr index 0b58dc1294be0..6153301518563 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -1,17 +1,17 @@ error: can only call other `min_const_fn` within a `min_const_fn` - --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:26:32 + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:25:32 | LL | const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn` | ^^^^^ error: can only call other `min_const_fn` within a `min_const_fn` - --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:33 + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:32:33 | LL | const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn` | ^^^^^^ error: can only call other `min_const_fn` within a `min_const_fn` - --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:41:39 + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:40:39 | LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn` | ^^^^^^^^^^^^ From 7ae6fb215250d7515cc1ff7545c37d589104eda0 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 22 Dec 2018 21:06:32 +0100 Subject: [PATCH 20/20] stabilize min_const_unsafe_fn -- revert const-size_of-cycle changes --- src/test/ui/consts/const-size_of-cycle.stderr | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 68f81f408f70a..e824657f8afda 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -5,6 +5,10 @@ LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires const-evaluating `Foo::bytes::{{constant}}`... + --> $SRC_DIR/libcore/mem.rs:LL:COL + | +LL | intrinsics::size_of::() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires computing layout of `Foo`... note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All }, value: [u8; _] }`... note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}`...