From 52c771377f865f04940c294815309e6005663e88 Mon Sep 17 00:00:00 2001 From: Yves Dorfsman Date: Thu, 17 Oct 2019 23:07:29 -0600 Subject: [PATCH 1/7] Added doc on keyword break --- src/libstd/keyword_docs.rs | 66 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index a8dfe924fdf06..7d678ee3879a0 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -33,9 +33,71 @@ mod as_keyword { } // /// Exit early from a loop. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// When `break` is encountered, execution of the associated loop body is +/// immediately terminated. +/// +/// ```rust +/// let mut last = 0; +/// +/// for x in 1..100 { +/// if x > 12 { +/// break; +/// } +/// last = x; +/// } +/// +/// assert_eq!(last, 12); +/// println!("{}", last); +/// ``` +/// +/// A break expression is normally associated with the innermost loop enclosing the +/// `break` but a label can be used to specify which enclosing loop is affected. +/// +///```rust +/// 'outer: for i in 1..=5 { +/// println!("outer iteration (i): {}", i); +/// +/// 'inner: for j in 1..=200 { +/// println!(" inner iteration (j): {}", j); +/// if j >= 3 { +/// // breaks from inner loop, let's outer loop continue. +/// break; +/// } +/// if i >= 2 { +/// // breaks from outer loop, and directly to "Bye". +/// break 'outer; +/// } +/// } +/// } +/// println!("Bye."); +///``` +/// +/// When associated with `loop`, but not with any other kind of loop expression, +/// `break` can return a value. When no value is specified, `break;` returns `()`. +/// Every `break` within a loop must return the same type. +/// +/// ```rust +/// let (mut a, mut b) = (1, 1); +/// let result = loop { +/// if b > 10 { +/// break b; +/// } +/// let c = a + b; +/// a = b; +/// b = c; +/// }; +/// // first number in Fibonacci sequence over 10: +/// assert_eq!(result, 13); +/// println!("{}", result); +/// ``` +/// +/// For more details consult the [Reference on "break expression"] and the [Reference on "break and +/// loop values"]. +/// +/// [Reference on "break expression"]: ../reference/expressions/loop-expr.html#break-expressions +/// [Reference on "break and loop values"]: +/// ../reference/expressions/loop-expr.html#break-and-loop-values /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 mod break_keyword { } #[doc(keyword = "const")] From 11214a63125efc187ef0c3acd90f8f8cf7c93dc6 Mon Sep 17 00:00:00 2001 From: Yves Dorfsman Date: Fri, 18 Oct 2019 19:49:09 -0600 Subject: [PATCH 2/7] reworded loop value sentence --- src/libstd/keyword_docs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 7d678ee3879a0..ab8a55660cb0c 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -72,8 +72,9 @@ mod as_keyword { } /// println!("Bye."); ///``` /// -/// When associated with `loop`, but not with any other kind of loop expression, -/// `break` can return a value. When no value is specified, `break;` returns `()`. +/// When associated with `loop`, a break expression may be used to return a value from that loop. +/// This is only valid with `loop` and not with any other type of loop. +/// If no value is specified, `break;` returns `()`. /// Every `break` within a loop must return the same type. /// /// ```rust From 101e1f6f8f92c896ecef76dcc0a51d782c423de1 Mon Sep 17 00:00:00 2001 From: Ryo Onodera Date: Sun, 20 Oct 2019 15:40:44 +0900 Subject: [PATCH 3/7] Correctly note code as Ok not error for E0573 --- src/librustc_resolve/error_codes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index cd6189c681da1..b82cba8c83dc4 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -1682,7 +1682,7 @@ enum Wizard { } trait Isengard { - fn wizard(w: Wizard) { // error! + fn wizard(w: Wizard) { // ok! match w { Wizard::Saruman => { // do something From 4592a9eb3f240cef2994ee76f6975c4946d4d269 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 12 Oct 2019 08:21:51 -0400 Subject: [PATCH 4/7] Cleanup `ConstProp::visit_statement()` --- src/librustc_mir/transform/const_prop.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 780b49cd9db0d..4a3a182cea204 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -431,7 +431,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { place_layout: TyLayout<'tcx>, source_info: SourceInfo, place: &Place<'tcx>, - ) -> Option> { + ) -> Option<()> { let span = source_info.span; let overflow_check = self.tcx.sess.overflow_checks(); @@ -553,7 +553,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { self.use_ecx(source_info, |this| { trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place); this.ecx.eval_rvalue_into_place(rvalue, place)?; - this.ecx.eval_place_to_op(place, Some(place_layout)) + Ok(()) }) } @@ -717,16 +717,15 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { base: PlaceBase::Local(local), projection: box [], } = *place { - if let Some(value) = self.const_prop(rval, - place_layout, - statement.source_info, - place) { - trace!("checking whether {:?} can be stored to {:?}", value, local); + let source = statement.source_info; + if let Some(()) = self.const_prop(rval, place_layout, source, place) { if self.can_const_prop[local] { - trace!("stored {:?} to {:?}", value, local); - assert_eq!(self.get_const(local), Some(value)); + trace!("propagated into {:?}", local); if self.should_const_prop() { + let value = + self.get_const(local).expect("local was dead/uninitialized"); + trace!("replacing {:?} with {:?}", rval, value); self.replace_with_const( rval, value, @@ -734,7 +733,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { ); } } else { - trace!("can't propagate {:?} to {:?}", value, local); + trace!("can't propagate into {:?}", local); self.remove_const(local); } } From 2ec73395b985a028062cc40faed6ace50be0c67d Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 17 Oct 2019 06:46:51 -0400 Subject: [PATCH 5/7] Improve SimplifyLocals pass so it can remove unused consts The `ConstProp` can cause many locals to be initialized to a constant value and then never read from. `ConstProp` can also evaluate ZSTs into constant values. Previously, many of these would be removed by other parts of the MIR optimization pipeline. However, evaluating ZSTs (especially `()`) into constant values defeated those parts of the optimizer and so in a2e3ed5c054b544df6ceeb9e612d39af819f4aae, I added a hack to `ConstProp` that skips evaluating ZSTs to avoid that regression. This commit changes `SimplifyLocals` so that it doesn't consider writes of const values to a local to be a use of that local. In doing so, `SimplifyLocals` is able to remove otherwise unused locals left behind by other optimization passes (`ConstProp` in particular). --- src/librustc_mir/transform/const_prop.rs | 7 -- src/librustc_mir/transform/simplify.rs | 76 +++++++++++----- src/test/incremental/hashes/for_loops.rs | 2 +- .../incremental/hashes/let_expressions.rs | 8 +- .../incremental/hashes/loop_expressions.rs | 2 +- .../incremental/hashes/while_let_loops.rs | 2 +- src/test/incremental/hashes/while_loops.rs | 2 +- .../simplify-locals-removes-unused-consts.rs | 89 +++++++++++++++++++ src/test/mir-opt/slice-drop-shim.rs | 4 +- 9 files changed, 154 insertions(+), 38 deletions(-) create mode 100644 src/test/mir-opt/simplify-locals-removes-unused-consts.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 4a3a182cea204..108c6c9786b2a 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -540,13 +540,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } - // Work around: avoid extra unnecessary locals. FIXME(wesleywiser) - // Const eval will turn this into a `const Scalar()` that - // `SimplifyLocals` doesn't know it can remove. - Rvalue::Aggregate(_, operands) if operands.len() == 0 => { - return None; - } - _ => { } } diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 606c1a3a1cc09..e41b4678dbd0d 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -31,7 +31,7 @@ use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; use rustc::ty::TyCtxt; use rustc::mir::*; -use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext}; +use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext, MutatingUseContext}; use rustc::session::config::DebugInfo; use std::borrow::Cow; use crate::transform::{MirPass, MirSource}; @@ -293,23 +293,31 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { pub struct SimplifyLocals; impl<'tcx> MirPass<'tcx> for SimplifyLocals { - fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { - let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()) }; - marker.visit_body(body); - // Return pointer and arguments are always live - marker.locals.insert(RETURN_PLACE); - for arg in body.args_iter() { - marker.locals.insert(arg); - } + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + trace!("running SimplifyLocals on {:?}", source); + let locals = { + let mut marker = DeclMarker { + locals: BitSet::new_empty(body.local_decls.len()), + body, + }; + marker.visit_body(body); + // Return pointer and arguments are always live + marker.locals.insert(RETURN_PLACE); + for arg in body.args_iter() { + marker.locals.insert(arg); + } - // We may need to keep dead user variables live for debuginfo. - if tcx.sess.opts.debuginfo == DebugInfo::Full { - for local in body.vars_iter() { - marker.locals.insert(local); + // We may need to keep dead user variables live for debuginfo. + if tcx.sess.opts.debuginfo == DebugInfo::Full { + for local in body.vars_iter() { + marker.locals.insert(local); + } } - } - let map = make_local_map(&mut body.local_decls, marker.locals); + marker.locals + }; + + let map = make_local_map(&mut body.local_decls, locals); // Update references to all vars and tmps now LocalUpdater { map }.visit_body(body); body.local_decls.shrink_to_fit(); @@ -334,18 +342,35 @@ fn make_local_map( map } -struct DeclMarker { +struct DeclMarker<'a, 'tcx> { pub locals: BitSet, + pub body: &'a Body<'tcx>, } -impl<'tcx> Visitor<'tcx> for DeclMarker { - fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) { +impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> { + fn visit_local(&mut self, local: &Local, ctx: PlaceContext, location: Location) { // Ignore storage markers altogether, they get removed along with their otherwise unused // decls. // FIXME: Extend this to all non-uses. - if !ctx.is_storage_marker() { - self.locals.insert(*local); + if ctx.is_storage_marker() { + return; } + + // Ignore stores of constants because `ConstProp` and `CopyProp` can remove uses of many + // of these locals. However, if the local is still needed, then it will be referenced in + // another place and we'll mark it as being used there. + if ctx == PlaceContext::MutatingUse(MutatingUseContext::Store) { + let stmt = + &self.body.basic_blocks()[location.block].statements[location.statement_index]; + if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(c)))) = &stmt.kind { + if p.as_local().is_some() { + trace!("skipping store of const value {:?} to {:?}", c, local); + return; + } + } + } + + self.locals.insert(*local); } } @@ -357,9 +382,16 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater { fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { // Remove unnecessary StorageLive and StorageDead annotations. data.statements.retain(|stmt| { - match stmt.kind { + match &stmt.kind { StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => { - self.map[l].is_some() + self.map[*l].is_some() + } + StatementKind::Assign(box (place, _)) => { + if let Some(local) = place.as_local() { + self.map[local].is_some() + } else { + true + } } _ => true } diff --git a/src/test/incremental/hashes/for_loops.rs b/src/test/incremental/hashes/for_loops.rs index 70820dfaea4a0..8e134ad14fc14 100644 --- a/src/test/incremental/hashes/for_loops.rs +++ b/src/test/incremental/hashes/for_loops.rs @@ -25,7 +25,7 @@ pub fn change_loop_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_body() { let mut _x = 0; diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs index 68545b7daaa5c..4e8ba5a209df8 100644 --- a/src/test/incremental/hashes/let_expressions.rs +++ b/src/test/incremental/hashes/let_expressions.rs @@ -22,7 +22,7 @@ pub fn change_name() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir")] + except="HirBody,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_name() { let _y = 2u64; @@ -86,7 +86,7 @@ pub fn change_mutability_of_slot() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_slot() { let _x: u64 = 0; @@ -182,7 +182,7 @@ pub fn add_initializer() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn add_initializer() { let _x: i16 = 3i16; @@ -198,7 +198,7 @@ pub fn change_initializer() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir")] + except="HirBody,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_initializer() { let _x = 5u16; diff --git a/src/test/incremental/hashes/loop_expressions.rs b/src/test/incremental/hashes/loop_expressions.rs index a2222db4c59ad..ca85ee39e3671 100644 --- a/src/test/incremental/hashes/loop_expressions.rs +++ b/src/test/incremental/hashes/loop_expressions.rs @@ -25,7 +25,7 @@ pub fn change_loop_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_body() { let mut _x = 0; diff --git a/src/test/incremental/hashes/while_let_loops.rs b/src/test/incremental/hashes/while_let_loops.rs index da3c957741fb2..1e628d019196b 100644 --- a/src/test/incremental/hashes/while_let_loops.rs +++ b/src/test/incremental/hashes/while_let_loops.rs @@ -25,7 +25,7 @@ pub fn change_loop_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_body() { let mut _x = 0; diff --git a/src/test/incremental/hashes/while_loops.rs b/src/test/incremental/hashes/while_loops.rs index 3be42e7a4ee7a..295c2244879f8 100644 --- a/src/test/incremental/hashes/while_loops.rs +++ b/src/test/incremental/hashes/while_loops.rs @@ -25,7 +25,7 @@ pub fn change_loop_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_body() { let mut _x = 0; diff --git a/src/test/mir-opt/simplify-locals-removes-unused-consts.rs b/src/test/mir-opt/simplify-locals-removes-unused-consts.rs new file mode 100644 index 0000000000000..6f03438ff7234 --- /dev/null +++ b/src/test/mir-opt/simplify-locals-removes-unused-consts.rs @@ -0,0 +1,89 @@ +// compile-flags: -C overflow-checks=no + +fn use_zst(_: ((), ())) { } + +struct Temp { + x: u8 +} + +fn use_u8(_: u8) { } + +fn main() { + let ((), ()) = ((), ()); + use_zst(((), ())); + + use_u8((Temp { x : 40 }).x + 2); +} + +// END RUST SOURCE + +// START rustc.main.SimplifyLocals.before.mir +// let mut _0: (); +// let mut _1: ((), ()); +// let mut _2: (); +// let mut _3: (); +// let _4: (); +// let mut _5: ((), ()); +// let mut _6: (); +// let mut _7: (); +// let _8: (); +// let mut _9: u8; +// let mut _10: u8; +// let mut _11: Temp; +// scope 1 { +// } +// bb0: { +// StorageLive(_1); +// StorageLive(_2); +// _2 = const Scalar() : (); +// StorageLive(_3); +// _3 = const Scalar() : (); +// _1 = const Scalar() : ((), ()); +// StorageDead(_3); +// StorageDead(_2); +// StorageDead(_1); +// StorageLive(_4); +// StorageLive(_6); +// _6 = const Scalar() : (); +// StorageLive(_7); +// _7 = const Scalar() : (); +// StorageDead(_7); +// StorageDead(_6); +// _4 = const use_zst(const Scalar() : ((), ())) -> bb1; +// } +// bb1: { +// StorageDead(_4); +// StorageLive(_8); +// StorageLive(_10); +// StorageLive(_11); +// _11 = const Scalar(0x28) : Temp; +// _10 = const 40u8; +// StorageDead(_10); +// _8 = const use_u8(const 42u8) -> bb2; +// } +// bb2: { +// StorageDead(_11); +// StorageDead(_8); +// return; +// } +// END rustc.main.SimplifyLocals.before.mir +// START rustc.main.SimplifyLocals.after.mir +// let mut _0: (); +// let _1: (); +// let _2: (); +// scope 1 { +// } +// bb0: { +// StorageLive(_1); +// _1 = const use_zst(const Scalar() : ((), ())) -> bb1; +// } +// bb1: { +// StorageDead(_1); +// StorageLive(_2); +// _2 = const use_u8(const 42u8) -> bb2; +// } +// bb2: { +// StorageDead(_2); +// return; +// } +// END rustc.main.SimplifyLocals.after.mir diff --git a/src/test/mir-opt/slice-drop-shim.rs b/src/test/mir-opt/slice-drop-shim.rs index 754fad51b21e7..f270dec5fe232 100644 --- a/src/test/mir-opt/slice-drop-shim.rs +++ b/src/test/mir-opt/slice-drop-shim.rs @@ -1,5 +1,7 @@ +// compile-flags: -Zmir-opt-level=0 + fn main() { - std::ptr::drop_in_place::<[String]> as unsafe fn(_); + let _fn = std::ptr::drop_in_place::<[String]> as unsafe fn(_); } // END RUST SOURCE From 642da6e12ae337928fcc0dc9f0c84436a0954f85 Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Mon, 21 Oct 2019 14:18:09 +0800 Subject: [PATCH 6/7] use unwrap_or in lint code --- src/librustc/lint/levels.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 60b1b192d10db..8ed06cbdc7623 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -202,11 +202,7 @@ impl<'a> LintLevelsBuilder<'a> { let meta = unwrap_or!(attr.meta(), continue); attr::mark_used(attr); - let mut metas = if let Some(metas) = meta.meta_item_list() { - metas - } else { - continue; - }; + let mut metas = unwrap_or!(meta.meta_item_list(), continue); if metas.is_empty() { // FIXME (#55112): issue unused-attributes lint for `#[level()]` From aa3d28f9a8e0fa2915e5321648d57af6c922799f Mon Sep 17 00:00:00 2001 From: ben Date: Mon, 21 Oct 2019 14:42:54 +1300 Subject: [PATCH 7/7] Fix `canonicalize_const_var` from leaking inference variables through it's type. --- src/librustc/infer/canonical/canonicalizer.rs | 2 +- .../incremental/const-generics/issue-61338.rs | 14 ++++++++++++++ .../incremental/const-generics/issue-61516.rs | 16 ++++++++++++++++ .../incremental/const-generics/issue-62536.rs | 12 ++++++++++++ .../incremental/const-generics/issue-64087.rs | 11 +++++++++++ .../incremental/const-generics/issue-65623.rs | 14 ++++++++++++++ 6 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/test/incremental/const-generics/issue-61338.rs create mode 100644 src/test/incremental/const-generics/issue-61516.rs create mode 100644 src/test/incremental/const-generics/issue-62536.rs create mode 100644 src/test/incremental/const-generics/issue-64087.rs create mode 100644 src/test/incremental/const-generics/issue-65623.rs diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index b9474f869ee29..e69719806a81d 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -701,7 +701,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { self.tcx().mk_const( ty::Const { val: ConstValue::Infer(InferConst::Canonical(self.binder_index, var.into())), - ty: const_var.ty, + ty: self.fold_ty(const_var.ty), } ) } diff --git a/src/test/incremental/const-generics/issue-61338.rs b/src/test/incremental/const-generics/issue-61338.rs new file mode 100644 index 0000000000000..00b3b29698bed --- /dev/null +++ b/src/test/incremental/const-generics/issue-61338.rs @@ -0,0 +1,14 @@ +// revisions:rpass1 + +#![feature(const_generics)] + +struct Struct(T); + +impl Struct<[T; N]> { + fn f() {} + fn g() { Self::f(); } +} + +fn main() { + Struct::<[u32; 3]>::g(); +} diff --git a/src/test/incremental/const-generics/issue-61516.rs b/src/test/incremental/const-generics/issue-61516.rs new file mode 100644 index 0000000000000..a7465b77267a5 --- /dev/null +++ b/src/test/incremental/const-generics/issue-61516.rs @@ -0,0 +1,16 @@ +// revisions:rpass1 + +#![feature(const_generics)] + +struct FakeArray(T); + +impl FakeArray { + fn len(&self) -> usize { + N + } +} + +fn main() { + let fa = FakeArray::(1); + assert_eq!(fa.len(), 32); +} diff --git a/src/test/incremental/const-generics/issue-62536.rs b/src/test/incremental/const-generics/issue-62536.rs new file mode 100644 index 0000000000000..90e279bfc7433 --- /dev/null +++ b/src/test/incremental/const-generics/issue-62536.rs @@ -0,0 +1,12 @@ +// revisions:cfail1 +#![feature(const_generics)] +//[cfail1]~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct S([T; N]); + +fn f(x: T) -> S { panic!() } + +fn main() { + f(0u8); + //[cfail1]~^ ERROR type annotations needed +} diff --git a/src/test/incremental/const-generics/issue-64087.rs b/src/test/incremental/const-generics/issue-64087.rs new file mode 100644 index 0000000000000..b3c12fbb6e813 --- /dev/null +++ b/src/test/incremental/const-generics/issue-64087.rs @@ -0,0 +1,11 @@ +// revisions:cfail1 +#![feature(const_generics)] +//[cfail1]~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn combinator() -> [T; S] {} +//[cfail1]~^ ERROR mismatched types + +fn main() { + combinator().into_iter(); + //[cfail1]~^ ERROR type annotations needed +} diff --git a/src/test/incremental/const-generics/issue-65623.rs b/src/test/incremental/const-generics/issue-65623.rs new file mode 100644 index 0000000000000..353e323e67b44 --- /dev/null +++ b/src/test/incremental/const-generics/issue-65623.rs @@ -0,0 +1,14 @@ +// revisions:rpass1 +#![feature(const_generics)] + +pub struct Foo([T; 0]); + +impl Foo { + pub fn new() -> Self { + Foo([]) + } +} + +fn main() { + let _: Foo = Foo::new(); +}