diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 6ee1dbe4ae3ee..75f384405bb2b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -34,7 +34,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Repeat(ref expr, ref count) => { let expr = self.lower_expr(expr); - let count = self.lower_anon_const(count); + let count = self.lower_array_length(count); hir::ExprKind::Repeat(expr, count) } ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 77738b2c5cc75..35eb716949a13 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -56,6 +56,7 @@ use rustc_hir::{ConstArg, GenericArg, ParamName}; use rustc_index::vec::{Idx, IndexVec}; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::LintBuffer; +use rustc_session::parse::feature_err; use rustc_session::utils::{FlattenNonterminals, NtToTokenstream}; use rustc_session::Session; use rustc_span::hygiene::ExpnId; @@ -1248,7 +1249,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { )) } TyKind::Array(ref ty, ref length) => { - hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_anon_const(length)) + hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length)) } TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)), TyKind::TraitObject(ref bounds, kind) => { @@ -2039,6 +2040,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.expr_block(block, AttrVec::new()) } + fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen { + match c.value.kind { + ExprKind::Underscore => { + if self.sess.features_untracked().generic_arg_infer { + hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span) + } else { + feature_err( + &self.sess.parse_sess, + sym::generic_arg_infer, + c.value.span, + "using `_` for array lengths is unstable", + ) + .emit(); + hir::ArrayLen::Body(self.lower_anon_const(c)) + } + } + _ => hir::ArrayLen::Body(self.lower_anon_const(c)), + } + } + fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst { self.with_new_scopes(|this| hir::AnonConst { hir_id: this.lower_node_id(c.id), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 3e7371179cc72..01f7868df3492 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -160,17 +160,17 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { // the values should match the ones in the DWARF standard anyway. let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() }; let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() }; - let mut addr_ops = SmallVec::<[_; 8]>::new(); + let mut addr_ops = SmallVec::<[u64; 8]>::new(); if direct_offset.bytes() > 0 { addr_ops.push(op_plus_uconst()); - addr_ops.push(direct_offset.bytes() as i64); + addr_ops.push(direct_offset.bytes() as u64); } for &offset in indirect_offsets { addr_ops.push(op_deref()); if offset.bytes() > 0 { addr_ops.push(op_plus_uconst()); - addr_ops.push(offset.bytes() as i64); + addr_ops.push(offset.bytes() as u64); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 6450b7490bd2b..f2782f84f557b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2108,7 +2108,7 @@ extern "C" { Builder: &DIBuilder<'a>, Val: &'a Value, VarInfo: &'a DIVariable, - AddrOps: *const i64, + AddrOps: *const u64, AddrOpsCount: c_uint, DL: &'a DILocation, InsertAtEnd: &'a BasicBlock, @@ -2199,8 +2199,8 @@ extern "C" { Scope: &'a DIScope, InlinedAt: Option<&'a DILocation>, ) -> &'a DILocation; - pub fn LLVMRustDIBuilderCreateOpDeref() -> i64; - pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64; + pub fn LLVMRustDIBuilderCreateOpDeref() -> u64; + pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64; #[allow(improper_ctypes)] pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index c5412affafe23..3ec9f3ca3b8c2 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -63,7 +63,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( cid.instance, body, Some(&ret.into()), - StackPopCleanup::None { cleanup: false }, + StackPopCleanup::Root { cleanup: false }, )?; // The main interpreter loop. diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 0fc3827d16c7e..0a8112da2aba8 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -156,11 +156,11 @@ pub enum StackPopCleanup { /// `ret` stores the block we jump to on a normal return, while `unwind` /// stores the block used for cleanup during unwinding. Goto { ret: Option, unwind: StackPopUnwind }, - /// Just do nothing: Used by Main and for TLS hooks in miri. + /// The root frame of the stack: nowhere else to jump to. /// `cleanup` says whether locals are deallocated. Static computation /// wants them leaked to intern what they need (and just throw away /// the entire `ecx` when it is done). - None { cleanup: bool }, + Root { cleanup: bool }, } /// State of a local variable including a memoized layout @@ -849,7 +849,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // because this is CTFE and the final value will be thoroughly validated anyway. let cleanup = match return_to_block { StackPopCleanup::Goto { .. } => true, - StackPopCleanup::None { cleanup, .. } => cleanup, + StackPopCleanup::Root { cleanup, .. } => cleanup, }; if !cleanup { @@ -874,8 +874,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Follow the unwind edge. let unwind = match return_to_block { StackPopCleanup::Goto { unwind, .. } => unwind, - StackPopCleanup::None { .. } => { - panic!("Encountered StackPopCleanup::None when unwinding!") + StackPopCleanup::Root { .. } => { + panic!("encountered StackPopCleanup::Root when unwinding!") } }; self.unwind_to_block(unwind) @@ -883,7 +883,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Follow the normal return edge. match return_to_block { StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret), - StackPopCleanup::None { .. } => Ok(()), + StackPopCleanup::Root { .. } => { + assert!( + self.stack().is_empty(), + "only the topmost frame can have StackPopCleanup::Root" + ); + Ok(()) + } } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index b3446e51c7381..d59756239d9da 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1407,6 +1407,20 @@ impl fmt::Display for ConstContext { /// A literal. pub type Lit = Spanned; +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)] +pub enum ArrayLen { + Infer(HirId, Span), + Body(AnonConst), +} + +impl ArrayLen { + pub fn hir_id(&self) -> HirId { + match self { + &ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, body: _ }) => hir_id, + } + } +} + /// A constant (expression) that's not an item or associated item, /// but needs its own `DefId` for type-checking, const-eval, etc. /// These are usually found nested inside types (e.g., array lengths) @@ -1756,7 +1770,7 @@ pub enum ExprKind<'hir> { /// /// E.g., `[1; 5]`. The first expression is the element /// to be repeated; the second is the number of times to repeat it. - Repeat(&'hir Expr<'hir>, AnonConst), + Repeat(&'hir Expr<'hir>, ArrayLen), /// A suspension point for generators (i.e., `yield `). Yield(&'hir Expr<'hir>, YieldSource), @@ -2266,7 +2280,7 @@ pub enum TyKind<'hir> { /// A variable length slice (i.e., `[T]`). Slice(&'hir Ty<'hir>), /// A fixed length array (i.e., `[T; n]`). - Array(&'hir Ty<'hir>, AnonConst), + Array(&'hir Ty<'hir>, ArrayLen), /// A raw pointer (i.e., `*const T` or `*mut T`). Ptr(MutTy<'hir>), /// A reference (i.e., `&'a T` or `&'a mut T`). diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 0fab7cbfeea34..d0eee422202af 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -383,6 +383,9 @@ pub trait Visitor<'v>: Sized { fn visit_pat(&mut self, p: &'v Pat<'v>) { walk_pat(self, p) } + fn visit_array_length(&mut self, len: &'v ArrayLen) { + walk_array_len(self, len) + } fn visit_anon_const(&mut self, c: &'v AnonConst) { walk_anon_const(self, c) } @@ -753,7 +756,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { } TyKind::Array(ref ty, ref length) => { visitor.visit_ty(ty); - visitor.visit_anon_const(length) + visitor.visit_array_length(length) } TyKind::TraitObject(bounds, ref lifetime, _syntax) => { for bound in bounds { @@ -1124,6 +1127,13 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { } } +pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) { + match len { + &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id), + ArrayLen::Body(c) => visitor.visit_anon_const(c), + } +} + pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) { visitor.visit_id(constant.hir_id); visitor.visit_nested_body(constant.body); @@ -1147,7 +1157,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const), ExprKind::Repeat(ref element, ref count) => { visitor.visit_expr(element); - visitor.visit_anon_const(count) + visitor.visit_array_length(count) } ExprKind::Struct(ref qpath, fields, ref optional_base) => { visitor.visit_qpath(qpath, expression.hir_id, expression.span); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index c17286dfbe38e..4c9e2d7fe42b1 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -358,7 +358,7 @@ impl<'a> State<'a> { self.word("["); self.print_type(&ty); self.word("; "); - self.print_anon_const(length); + self.print_array_length(length); self.word("]"); } hir::TyKind::Typeof(ref e) => { @@ -1065,6 +1065,13 @@ impl<'a> State<'a> { self.print_else(elseopt) } + pub fn print_array_length(&mut self, len: &hir::ArrayLen) { + match len { + hir::ArrayLen::Infer(_, _) => self.word("_"), + hir::ArrayLen::Body(ct) => self.print_anon_const(ct), + } + } + pub fn print_anon_const(&mut self, constant: &hir::AnonConst) { self.ann.nested(self, Nested::Body(constant.body)) } @@ -1140,12 +1147,12 @@ impl<'a> State<'a> { self.end() } - fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) { + fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen) { self.ibox(INDENT_UNIT); self.word("["); self.print_expr(element); self.word_space(";"); - self.print_anon_const(count); + self.print_array_length(count); self.word("]"); self.end() } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 025a0ee376e3e..2a0f4fdc77412 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -979,11 +979,11 @@ LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder, extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo, - int64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL, + uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL, LLVMBasicBlockRef InsertAtEnd) { return wrap(Builder->insertDeclare( unwrap(V), unwrap(VarInfo), - Builder->createExpression(llvm::ArrayRef(AddrOps, AddrOpsCount)), + Builder->createExpression(llvm::ArrayRef(AddrOps, AddrOpsCount)), DebugLoc(cast(unwrap(DL))), unwrap(InsertAtEnd))); } @@ -1057,11 +1057,11 @@ LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column, return wrap(Loc); } -extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() { +extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() { return dwarf::DW_OP_deref; } -extern "C" int64_t LLVMRustDIBuilderCreateOpPlusUconst() { +extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() { return dwarf::DW_OP_plus_uconst; } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 092fe13117470..bdde6b4a356c1 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -583,9 +583,12 @@ impl<'tcx> Cx<'tcx> { ExprKind::ConstBlock { value } } // Now comes the rote stuff: - hir::ExprKind::Repeat(ref v, ref count) => { - let count_def_id = self.tcx.hir().local_def_id(count.hir_id); - let count = ty::Const::from_anon_const(self.tcx, count_def_id); + hir::ExprKind::Repeat(ref v, _) => { + let ty = self.typeck_results().expr_ty(expr); + let count = match ty.kind() { + ty::Array(_, ct) => ct, + _ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty), + }; ExprKind::Repeat { value: self.mirror_expr(v), count } } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index ecc8e7a6f1a39..e3ff6ad45490d 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -406,7 +406,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Instance::new(def_id, substs), dummy_body, ret.as_ref(), - StackPopCleanup::None { cleanup: false }, + StackPopCleanup::Root { cleanup: false }, ) .expect("failed to push initial stack frame"); diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index f1a5282b08871..23f5b17fa7889 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -1326,12 +1326,18 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { } intravisit::walk_qpath(self, path, t.hir_id, t.span); } - hir::TyKind::Array(ref ty, ref anon_const) => { + hir::TyKind::Array(ref ty, ref length) => { self.visit_ty(ty); let map = self.tcx.hir(); - self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { - v.visit_expr(&map.body(anon_const.body).value) - }); + match length { + // FIXME(generic_arg_infer): We probably want to + // output the inferred type here? :shrug: + hir::ArrayLen::Infer(..) => {} + hir::ArrayLen::Body(anon_const) => self + .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { + v.visit_expr(&map.body(anon_const.body).value) + }), + } } hir::TyKind::OpaqueDef(item_id, _) => { let item = self.tcx.hir().item(item_id); @@ -1390,12 +1396,18 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { v.visit_expr(&body.value) }); } - hir::ExprKind::Repeat(ref expr, ref anon_const) => { + hir::ExprKind::Repeat(ref expr, ref length) => { self.visit_expr(expr); let map = self.tcx.hir(); - self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { - v.visit_expr(&map.body(anon_const.body).value) - }); + match length { + // FIXME(generic_arg_infer): We probably want to + // output the inferred type here? :shrug: + hir::ArrayLen::Infer(..) => {} + hir::ArrayLen::Body(anon_const) => self + .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { + v.visit_expr(&map.body(anon_const.body).value) + }), + } } // In particular, we take this branch for call and path expressions, // where we'll index the idents involved just by continuing to walk. diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index e43344ad6d9ef..4971bb6d1aad7 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -310,9 +310,9 @@ impl<'hir> Sig for hir::Ty<'hir> { let nested = bounds_to_string(&bounds); Ok(text_sig(nested)) } - hir::TyKind::Array(ref ty, ref anon_const) => { + hir::TyKind::Array(ref ty, ref length) => { let nested_ty = ty.make(offset + 1, id, scx)?; - let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " "); + let expr = id_to_string(&scx.tcx.hir(), length.hir_id()).replace('\n', " "); let text = format!("[{}; {}]", nested_ty.text, expr); Ok(replace_text(nested_ty, text)) } diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index caa5c71e21cd9..956696546da8e 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -104,7 +104,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }), GenericParamDefKind::Const { .. }, ) if tcx.type_of(param.def_id) == tcx.types.usize => { - let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id)); + let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id())); if let Ok(snippet) = snippet { err.span_suggestion( arg.span(), diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 8db706c3709c1..8226ffbccc431 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2363,8 +2363,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs)) } hir::TyKind::Array(ref ty, ref length) => { - let length_def_id = tcx.hir().local_def_id(length.hir_id); - let length = ty::Const::from_anon_const(tcx, length_def_id); + let length = match length { + &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span), + hir::ArrayLen::Body(constant) => { + let length_def_id = tcx.hir().local_def_id(constant.hir_id); + ty::Const::from_anon_const(tcx, length_def_id) + } + }; + let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length)); self.normalize_ty(ast_ty.span, array_ty) } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 8d370e440eaf1..621938c9b783d 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1238,12 +1238,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_expr_repeat( &self, element: &'tcx hir::Expr<'tcx>, - count: &'tcx hir::AnonConst, + count: &'tcx hir::ArrayLen, expected: Expectation<'tcx>, _expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let count = self.to_const(count); + let count = self.array_length_to_const(count); let uty = match expected { ExpectHasType(uty) => match *uty.kind() { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 67630fd4e582b..1aca2911533ad 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -498,6 +498,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } + pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> &'tcx ty::Const<'tcx> { + match length { + &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span), + hir::ArrayLen::Body(anon_const) => self.to_const(anon_const), + } + } + pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); let c = ty::Const::from_anon_const(self.tcx, const_def_id); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 2fb5590016ef8..e1fef84d9d929 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -182,7 +182,7 @@ crate fn placeholder_type_error<'tcx>( sugg.push((span, format!(", {}", type_name))); } - let mut err = bad_placeholder_type(tcx, placeholder_types, kind); + let mut err = bad_placeholder(tcx, "type", placeholder_types, kind); // Suggest, but only if it is not a function in const or static if suggest { @@ -314,8 +314,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { /////////////////////////////////////////////////////////////////////////// // Utility types and common code for the above passes. -fn bad_placeholder_type<'tcx>( +fn bad_placeholder<'tcx>( tcx: TyCtxt<'tcx>, + placeholder_kind: &'static str, mut spans: Vec, kind: &'static str, ) -> rustc_errors::DiagnosticBuilder<'tcx> { @@ -326,7 +327,8 @@ fn bad_placeholder_type<'tcx>( tcx.sess, spans.clone(), E0121, - "the type placeholder `_` is not allowed within types on item signatures for {}", + "the {} placeholder `_` is not allowed within types on item signatures for {}", + placeholder_kind, kind ); for span in spans { @@ -393,7 +395,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { _: Option<&ty::GenericParamDef>, span: Span, ) -> &'tcx Const<'tcx> { - bad_placeholder_type(self.tcx(), vec![span], "generic").emit(); + bad_placeholder(self.tcx(), "const", vec![span], "generic").emit(); // Typeck doesn't expect erased regions to be returned from `type_of`. let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r { ty::ReErased => self.tcx.lifetimes.re_static, @@ -1482,7 +1484,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`), // as they shouldn't be able to cause query cycle errors. Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) - | Node::Variant(Variant { disr_expr: Some(ref constant), .. }) + if constant.hir_id() == hir_id => + { + Some(parent_def_id.to_def_id()) + } + Node::Variant(Variant { disr_expr: Some(ref constant), .. }) if constant.hir_id == hir_id => { Some(parent_def_id.to_def_id()) @@ -1788,7 +1794,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { let mut visitor = PlaceholderHirTyCollector::default(); visitor.visit_ty(ty); - let mut diag = bad_placeholder_type(tcx, visitor.0, "return type"); + let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type"); let ret_ty = fn_sig.skip_binder().output(); if !ret_ty.references_error() { if !ret_ty.is_closure() { diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 99fddcb00ceca..04e887bf7420f 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -13,7 +13,7 @@ use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; use super::ItemCtxt; -use super::{bad_placeholder_type, is_suggestable_infer_ty}; +use super::{bad_placeholder, is_suggestable_infer_ty}; /// Computes the relevant generic parameter for a potential generic const argument. /// @@ -490,7 +490,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { match parent_node { Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. }) | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) - if constant.hir_id == hir_id => + if constant.hir_id() == hir_id => { tcx.types.usize } @@ -788,7 +788,7 @@ fn infer_placeholder_type<'a>( err.emit(); } None => { - let mut diag = bad_placeholder_type(tcx, vec![span], kind); + let mut diag = bad_placeholder(tcx, "type", vec![span], kind); if !ty.references_error() { let mut mk_nameable = MakeNameable::new(tcx); diff --git a/library/core/src/ops/unsize.rs b/library/core/src/ops/unsize.rs index 483362023b22c..a920b9165c18e 100644 --- a/library/core/src/ops/unsize.rs +++ b/library/core/src/ops/unsize.rs @@ -68,7 +68,38 @@ impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} -/// This is used for object safety, to check that a method's receiver type can be dispatched on. +/// `DispatchFromDyn` is used in the implementation of object safety checks (specifically allowing +/// arbitrary self types), to guarantee that a method's receiver type can be dispatched on. +/// +/// Note: `DispatchFromDyn` was briefly named `CoerceSized` (and had a slightly different +/// interpretation). +/// +/// Imagine we have a trait object `t` with type `&dyn Tr`, where `Tr` is some trait with a method +/// `m` defined as `fn m(&self);`. When calling `t.m()`, the receiver `t` is a wide pointer, but an +/// implementation of `m` will expect a narrow pointer as `&self` (a reference to the concrete +/// type). The compiler must generate an implicit conversion from the trait object/wide pointer to +/// the concrete reference/narrow pointer. Implementing `DispatchFromDyn` indicates that that +/// conversion is allowed and thus that the type implementing `DispatchFromDyn` is safe to use as +/// the self type in an object-safe method. (in the above example, the compiler will require +/// `DispatchFromDyn` is implemented for `&'a U`). +/// +/// `DispatchFromDyn` does not specify the conversion from wide pointer to narrow pointer; the +/// conversion is hard-wired into the compiler. For the conversion to work, the following +/// properties must hold (i.e., it is only safe to implement `DispatchFromDyn` for types which have +/// these properties, these are also checked by the compiler): +/// +/// * EITHER `Self` and `T` are either both references or both raw pointers; in either case, with +/// the same mutability. +/// * OR, all of the following hold +/// - `Self` and `T` must have the same type constructor, and only vary in a single type parameter +/// formal (the *coerced type*, e.g., `impl DispatchFromDyn> for Rc` is ok and the +/// single type parameter (instantiated with `T` or `U`) is the coerced type, +/// `impl DispatchFromDyn> for Rc` is not ok). +/// - The definition for `Self` must be a struct. +/// - The definition for `Self` must not be `#[repr(packed)]` or `#[repr(C)]`. +/// - Other than one-aligned, zero-sized fields, the definition for `Self` must have exactly one +/// field and that field's type must be the coerced type. Furthermore, `Self`'s field type must +/// implement `DispatchFromDyn` where `F` is the type of `T`'s field type. /// /// An example implementation of the trait: /// diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 0022df4f65ff7..1ec119a71e42c 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -571,36 +571,6 @@ impl Option { !self.is_some() } - /// Returns `true` if the option is a [`Some`] value containing the given value. - /// - /// # Examples - /// - /// ``` - /// #![feature(option_result_contains)] - /// - /// let x: Option = Some(2); - /// assert_eq!(x.contains(&2), true); - /// - /// let x: Option = Some(3); - /// assert_eq!(x.contains(&2), false); - /// - /// let x: Option = None; - /// assert_eq!(x.contains(&2), false); - /// ``` - #[must_use] - #[inline] - #[unstable(feature = "option_result_contains", issue = "62358")] - #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] - pub const fn contains(&self, x: &U) -> bool - where - U: ~const PartialEq, - { - match self { - Some(y) => x.eq(y), - None => false, - } - } - ///////////////////////////////////////////////////////////////////////// // Adapter for working with references ///////////////////////////////////////////////////////////////////////// @@ -1573,6 +1543,36 @@ impl Option { mem::replace(self, Some(value)) } + /// Returns `true` if the option is a [`Some`] value containing the given value. + /// + /// # Examples + /// + /// ``` + /// #![feature(option_result_contains)] + /// + /// let x: Option = Some(2); + /// assert_eq!(x.contains(&2), true); + /// + /// let x: Option = Some(3); + /// assert_eq!(x.contains(&2), false); + /// + /// let x: Option = None; + /// assert_eq!(x.contains(&2), false); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "option_result_contains", issue = "62358")] + #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + pub const fn contains(&self, x: &U) -> bool + where + U: ~const PartialEq, + { + match self { + Some(y) => x.eq(y), + None => false, + } + } + /// Zips `self` with another `Option`. /// /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`. diff --git a/library/core/src/result.rs b/library/core/src/result.rs index f46632e7a8d20..504a01813ac84 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -563,64 +563,6 @@ impl Result { !self.is_ok() } - /// Returns `true` if the result is an [`Ok`] value containing the given value. - /// - /// # Examples - /// - /// ``` - /// #![feature(option_result_contains)] - /// - /// let x: Result = Ok(2); - /// assert_eq!(x.contains(&2), true); - /// - /// let x: Result = Ok(3); - /// assert_eq!(x.contains(&2), false); - /// - /// let x: Result = Err("Some error message"); - /// assert_eq!(x.contains(&2), false); - /// ``` - #[must_use] - #[inline] - #[unstable(feature = "option_result_contains", issue = "62358")] - pub fn contains(&self, x: &U) -> bool - where - U: PartialEq, - { - match self { - Ok(y) => x == y, - Err(_) => false, - } - } - - /// Returns `true` if the result is an [`Err`] value containing the given value. - /// - /// # Examples - /// - /// ``` - /// #![feature(result_contains_err)] - /// - /// let x: Result = Ok(2); - /// assert_eq!(x.contains_err(&"Some error message"), false); - /// - /// let x: Result = Err("Some error message"); - /// assert_eq!(x.contains_err(&"Some error message"), true); - /// - /// let x: Result = Err("Some other error message"); - /// assert_eq!(x.contains_err(&"Some error message"), false); - /// ``` - #[must_use] - #[inline] - #[unstable(feature = "result_contains_err", issue = "62358")] - pub fn contains_err(&self, f: &F) -> bool - where - F: PartialEq, - { - match self { - Ok(_) => false, - Err(e) => f == e, - } - } - ///////////////////////////////////////////////////////////////////////// // Adapter for each variant ///////////////////////////////////////////////////////////////////////// @@ -1491,6 +1433,68 @@ impl Result { Err(e) => e, } } + + ///////////////////////////////////////////////////////////////////////// + // Misc or niche + ///////////////////////////////////////////////////////////////////////// + + /// Returns `true` if the result is an [`Ok`] value containing the given value. + /// + /// # Examples + /// + /// ``` + /// #![feature(option_result_contains)] + /// + /// let x: Result = Ok(2); + /// assert_eq!(x.contains(&2), true); + /// + /// let x: Result = Ok(3); + /// assert_eq!(x.contains(&2), false); + /// + /// let x: Result = Err("Some error message"); + /// assert_eq!(x.contains(&2), false); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "option_result_contains", issue = "62358")] + pub fn contains(&self, x: &U) -> bool + where + U: PartialEq, + { + match self { + Ok(y) => x == y, + Err(_) => false, + } + } + + /// Returns `true` if the result is an [`Err`] value containing the given value. + /// + /// # Examples + /// + /// ``` + /// #![feature(result_contains_err)] + /// + /// let x: Result = Ok(2); + /// assert_eq!(x.contains_err(&"Some error message"), false); + /// + /// let x: Result = Err("Some error message"); + /// assert_eq!(x.contains_err(&"Some error message"), true); + /// + /// let x: Result = Err("Some other error message"); + /// assert_eq!(x.contains_err(&"Some error message"), false); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "result_contains_err", issue = "62358")] + pub fn contains_err(&self, f: &F) -> bool + where + F: PartialEq, + { + match self { + Ok(_) => false, + Err(e) => f == e, + } + } } impl Result<&T, E> { diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 917abde9de1ce..6ccf8b1d5221c 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -988,10 +988,20 @@ impl<'a> Builder<'a> { } }; - if use_new_symbol_mangling { - rustflags.arg("-Zsymbol-mangling-version=v0"); + // cfg(bootstrap) -- drop the compiler.stage == 0 branch. + if compiler.stage == 0 { + if use_new_symbol_mangling { + rustflags.arg("-Zsymbol-mangling-version=v0"); + } else { + rustflags.arg("-Zsymbol-mangling-version=legacy"); + } } else { - rustflags.arg("-Zsymbol-mangling-version=legacy"); + if use_new_symbol_mangling { + rustflags.arg("-Csymbol-mangling-version=v0"); + } else { + rustflags.arg("-Csymbol-mangling-version=legacy"); + rustflags.arg("-Zunstable-options"); + } } // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`, diff --git a/src/doc/book b/src/doc/book index 8a0bb3c96e719..d3740fb7aad0e 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 8a0bb3c96e71927b80fa2286d7a5a5f2547c6aa4 +Subproject commit d3740fb7aad0ea4a80ae20f64dee3a8cfc0c5c3c diff --git a/src/doc/reference b/src/doc/reference index 06f9e61931bcf..f8ba2f12df60e 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 06f9e61931bcf58b91dfe6c924057e42ce273ee1 +Subproject commit f8ba2f12df60ee19b96de24ae5b73af3de8a446b diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 9bf0028b55779..875464457c410 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 9bf0028b557798ddd07a6f652e4d0c635d3d6620 +Subproject commit 875464457c4104686faf667f47848aa7b0f0a744 diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 959be5478b4ec..d80e79d164a78 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1350,17 +1350,23 @@ impl Clean for hir::Ty<'_> { } TyKind::Slice(ref ty) => Slice(box ty.clean(cx)), TyKind::Array(ref ty, ref length) => { - let def_id = cx.tcx.hir().local_def_id(length.hir_id); - // NOTE(min_const_generics): We can't use `const_eval_poly` for constants - // as we currently do not supply the parent generics to anonymous constants - // but do allow `ConstKind::Param`. - // - // `const_eval_poly` tries to to first substitute generic parameters which - // results in an ICE while manually constructing the constant and using `eval` - // does nothing for `ConstKind::Param`. - let ct = ty::Const::from_anon_const(cx.tcx, def_id); - let param_env = cx.tcx.param_env(def_id); - let length = print_const(cx, ct.eval(cx.tcx, param_env)); + let length = match length { + hir::ArrayLen::Infer(_, _) => "_".to_string(), + hir::ArrayLen::Body(anon_const) => { + let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id); + // NOTE(min_const_generics): We can't use `const_eval_poly` for constants + // as we currently do not supply the parent generics to anonymous constants + // but do allow `ConstKind::Param`. + // + // `const_eval_poly` tries to to first substitute generic parameters which + // results in an ICE while manually constructing the constant and using `eval` + // does nothing for `ConstKind::Param`. + let ct = ty::Const::from_anon_const(cx.tcx, def_id); + let param_env = cx.tcx.param_env(def_id); + print_const(cx, ct.eval(cx.tcx, param_env)) + } + }; + Array(box ty.clean(cx), length) } TyKind::Tup(tys) => Tuple(tys.iter().map(|x| x.clean(cx)).collect()), diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs new file mode 100644 index 0000000000000..56b88a426a1a8 --- /dev/null +++ b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs @@ -0,0 +1,12 @@ +// To avoid having to `or` gate `_` as an expr. +#![feature(generic_arg_infer)] + +fn foo() -> [u8; _] { + //~^ ERROR the const placeholder `_` is not allowed within types on item signatures for generics + // FIXME(generic_arg_infer): this error message should say in the return type or sth like that. + [0; 3] +} + +fn main() { + foo(); +} diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr new file mode 100644 index 0000000000000..eaa12b4192dc6 --- /dev/null +++ b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr @@ -0,0 +1,9 @@ +error[E0121]: the const placeholder `_` is not allowed within types on item signatures for generics + --> $DIR/array-in-sig.rs:4:18 + | +LL | fn foo() -> [u8; _] { + | ^ not allowed in type signatures + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs b/src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs new file mode 100644 index 0000000000000..d3e53d7a89267 --- /dev/null +++ b/src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs @@ -0,0 +1,13 @@ +// run-pass + +// To avoid having to `or` gate `_` as an expr. +#![feature(generic_arg_infer)] + +fn foo() -> [u8; 3] { + let x: [u8; _] = [0; _]; + x +} + +fn main() { + assert_eq!([0; _], foo()); +} diff --git a/src/test/ui/inference/infer-arg-test.rs b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs similarity index 86% rename from src/test/ui/inference/infer-arg-test.rs rename to src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs index 1b67ccd6c4337..29aa0f59d7438 100644 --- a/src/test/ui/inference/infer-arg-test.rs +++ b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs @@ -18,7 +18,5 @@ fn main() { let a: All<_, _, _>; all_fn(); let v: [u8; _]; - //~^ ERROR in expressions let v: [u8; 10] = [0; _]; - //~^ ERROR in expressions } diff --git a/src/test/ui/inference/infer-arg-test.stderr b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr similarity index 64% rename from src/test/ui/inference/infer-arg-test.stderr rename to src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr index 30e171eac2121..e6d0c743d01b9 100644 --- a/src/test/ui/inference/infer-arg-test.stderr +++ b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr @@ -10,18 +10,6 @@ error: expected identifier, found reserved identifier `_` LL | fn bad_infer_fn<_>() {} | ^ expected identifier, found reserved identifier -error: in expressions, `_` can only be used on the left-hand side of an assignment - --> $DIR/infer-arg-test.rs:20:15 - | -LL | let v: [u8; _]; - | ^ `_` not allowed here - -error: in expressions, `_` can only be used on the left-hand side of an assignment - --> $DIR/infer-arg-test.rs:22:25 - | -LL | let v: [u8; 10] = [0; _]; - | ^ `_` not allowed here - error[E0392]: parameter `_` is never used --> $DIR/infer-arg-test.rs:7:17 | @@ -31,6 +19,6 @@ LL | struct BadInfer<_>; = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `_` to be a const parameter, use `const _: usize` instead -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr index c17f02d58f325..49eede4794b37 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr +++ b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr @@ -1,5 +1,35 @@ +error[E0658]: using `_` for array lengths is unstable + --> $DIR/feature-gate-generic_arg_infer.rs:11:27 + | +LL | let _x: [u8; 3] = [0; _]; + | ^ + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/feature-gate-generic_arg_infer.rs:11:27 + | +LL | let _x: [u8; 3] = [0; _]; + | ^ `_` not allowed here + +error[E0658]: using `_` for array lengths is unstable + --> $DIR/feature-gate-generic_arg_infer.rs:14:18 + | +LL | let _y: [u8; _] = [0; 3]; + | ^ + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/feature-gate-generic_arg_infer.rs:14:18 + | +LL | let _y: [u8; _] = [0; 3]; + | ^ `_` not allowed here + error[E0747]: type provided when a constant was expected - --> $DIR/feature-gate-generic_arg_infer.rs:11:20 + --> $DIR/feature-gate-generic_arg_infer.rs:20:20 | LL | let _x = foo::<_>([1,2]); | ^ @@ -7,6 +37,7 @@ LL | let _x = foo::<_>([1,2]); = help: const arguments cannot yet be inferred with `_` = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable -error: aborting due to previous error +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0747`. +Some errors have detailed explanations: E0658, E0747. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs index 4729773b12ef0..afd14b7843e20 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs +++ b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs @@ -7,7 +7,17 @@ fn foo(_: [u8; N]) -> [u8; N] { [0; N] } +fn bar() { + let _x: [u8; 3] = [0; _]; + //[normal]~^ ERROR: using `_` for array lengths is unstable + //[normal]~| ERROR: in expressions, `_` can only be used on the left-hand side of an assignment + let _y: [u8; _] = [0; 3]; + //[normal]~^ ERROR: using `_` for array lengths is unstable + //[normal]~| ERROR: in expressions, `_` can only be used on the left-hand side of an assignment +} + fn main() { let _x = foo::<_>([1,2]); //[normal]~^ ERROR: type provided when a constant was expected + let _y = bar(); } diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs index 47c0a84cd4630..af36f7267004d 100644 --- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs +++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs @@ -59,6 +59,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx if let ItemKind::Struct(data, _) = &item.kind; if let Some(last_field) = data.fields().last(); if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind; + if let rustc_hir::ArrayLen::Body(length) = length; // Then check if that that array zero-sized let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index c1b811c217440..9b06ca4e82493 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::LitIntType; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::{ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind}; +use rustc_hir::{ArrayLen, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::{Ident, Symbol}; @@ -567,7 +567,14 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { bind!(self, value, length); kind!("Repeat({value}, {length})"); self.expr(value); - self.body(field!(length.body)); + match length.value { + ArrayLen::Infer(..) => out!("if let ArrayLen::Infer(..) = length;"), + ArrayLen::Body(anon_const) => { + bind!(self, anon_const); + out!("if let ArrayLen::Body({anon_const}) = {length};"); + self.body(field!(anon_const.body)); + } + } }, ExprKind::Err => kind!("Err"), ExprKind::DropTemps(expr) => { diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index abf4826a06917..c96766e56784f 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -334,12 +334,17 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}anon_const:", ind); print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1); }, - hir::ExprKind::Repeat(val, ref anon_const) => { + hir::ExprKind::Repeat(val, length) => { println!("{}Repeat", ind); println!("{}value:", ind); print_expr(cx, val, indent + 1); println!("{}repeat count:", ind); - print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1); + match length { + hir::ArrayLen::Infer(_, _) => println!("{}repeat count: _", ind), + hir::ArrayLen::Body(anon_const) => { + print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1) + } + } }, hir::ExprKind::Err => { println!("{}Err", ind); diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index ad50759effaf8..ac2b1a0259e3e 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -8,7 +8,7 @@ use rustc_hir::HirIdMap; use rustc_hir::{ BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt, - StmtKind, Ty, TyKind, TypeBinding, + StmtKind, Ty, TyKind, TypeBinding, ArrayLen }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; @@ -170,6 +170,14 @@ impl HirEqInterExpr<'_, '_, '_> { } } + pub fn eq_array_length(&mut self, left: ArrayLen, right: ArrayLen) -> bool { + match (left, right) { + (ArrayLen::Infer(..), ArrayLen::Infer(..)) => true, + (ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_body(l_ct.body, r_ct.body), + (_, _) => false, + } + } + pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool { let cx = self.inner.cx; let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value); @@ -194,8 +202,8 @@ impl HirEqInterExpr<'_, '_, '_> { } let is_eq = match ( - &reduce_exprkind(self.inner.cx, &left.kind), - &reduce_exprkind(self.inner.cx, &right.kind), + reduce_exprkind(self.inner.cx, &left.kind), + reduce_exprkind(self.inner.cx, &right.kind), ) { (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => { lb == rb && l_mut == r_mut && self.eq_expr(le, re) @@ -232,7 +240,7 @@ impl HirEqInterExpr<'_, '_, '_> { }, (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri), (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => { - self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r)) + self.eq_expr(lc, rc) && self.eq_expr(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r)) }, (&ExprKind::Let(l), &ExprKind::Let(r)) => { self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init) @@ -253,8 +261,8 @@ impl HirEqInterExpr<'_, '_, '_> { (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => { self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args) }, - (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => { - self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body) + (&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => { + self.eq_expr(le, re) && self.eq_array_length(ll, rl) }, (&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)), (&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r), @@ -391,8 +399,8 @@ impl HirEqInterExpr<'_, '_, '_> { fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool { match (&left.kind, &right.kind) { (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec), - (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => { - self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body) + (&TyKind::Array(lt, ll), &TyKind::Array(rt, rl)) => { + self.eq_ty(lt, rt) && self.eq_array_length(ll, rl) }, (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => { l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty) @@ -714,9 +722,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { ExprKind::ConstBlock(ref l_id) => { self.hash_body(l_id.body); }, - ExprKind::Repeat(e, ref l_id) => { + ExprKind::Repeat(e, len) => { self.hash_expr(e); - self.hash_body(l_id.body); + self.hash_array_length(len); }, ExprKind::Ret(ref e) => { if let Some(e) = *e { @@ -906,9 +914,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { TyKind::Slice(ty) => { self.hash_ty(ty); }, - TyKind::Array(ty, anon_const) => { + &TyKind::Array(ty, len) => { self.hash_ty(ty); - self.hash_body(anon_const.body); + self.hash_array_length(len); }, TyKind::Ptr(ref mut_ty) => { self.hash_ty(mut_ty.ty); @@ -953,6 +961,13 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } + pub fn hash_array_length(&mut self, length: ArrayLen) { + match length { + ArrayLen::Infer(..) => {} + ArrayLen::Body(anon_const) => self.hash_body(anon_const.body), + } + } + pub fn hash_body(&mut self, body_id: BodyId) { // swap out TypeckResults when hashing a body let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id)); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 54d470ca73820..9179e67c4f4ee 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -79,7 +79,7 @@ use rustc_hir::{ def, Arm, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl, ForeignItem, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, - TraitItemKind, TraitRef, TyKind, UnOp, + TraitItemKind, TraitRef, TyKind, UnOp, ArrayLen }; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::exports::Export; @@ -703,8 +703,9 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { _ => false, }, ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)), - ExprKind::Repeat(x, y) => if_chain! { - if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(y.body).value.kind; + ExprKind::Repeat(x, len) => if_chain! { + if let ArrayLen::Body(len) = len; + if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind; if let LitKind::Int(v, _) = const_lit.node; if v <= 32 && is_default_equivalent(cx, x); then { diff --git a/src/tools/clippy/tests/ui/author/repeat.stdout b/src/tools/clippy/tests/ui/author/repeat.stdout index f16350e4b5e6d..471bbce4f4185 100644 --- a/src/tools/clippy/tests/ui/author/repeat.stdout +++ b/src/tools/clippy/tests/ui/author/repeat.stdout @@ -2,7 +2,8 @@ if_chain! { if let ExprKind::Repeat(value, length) = expr.kind; if let ExprKind::Lit(ref lit) = value.kind; if let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node; - let expr1 = &cx.tcx.hir().body(length.body).value; + if let ArrayLen::Body(anon_const) = length; + let expr1 = &cx.tcx.hir().body(anon_const.body).value; if let ExprKind::Lit(ref lit1) = expr1.kind; if let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node; then {