Rollup merge of #91907 - lcnr:const-arg-infer, r=BoxyUwU

Allow `_` as the length of array types and repeat expressions

r? `@BoxyUwU` cc `@varkor`
This commit is contained in:
Matthias Krüger 2022-01-04 21:23:06 +01:00 committed by GitHub
commit ac7a867715
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 268 additions and 85 deletions

View File

@ -34,7 +34,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'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)),

View File

@ -56,6 +56,7 @@
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 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, '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 @@ fn lower_block_expr(&mut self, b: &Block) -> hir::Expr<'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),

View File

@ -1407,6 +1407,20 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// A literal.
pub type Lit = Spanned<LitKind>;
#[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 <expr>`).
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`).

View File

@ -383,6 +383,9 @@ fn visit_arm(&mut self, a: &'v Arm<'v>) {
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);

View File

@ -358,7 +358,7 @@ pub fn print_type(&mut self, ty: &hir::Ty<'_>) {
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 @@ pub fn print_if(
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 @@ fn print_expr_anon_const(&mut self, anon_const: &hir::AnonConst) {
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()
}

View File

@ -583,9 +583,12 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'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 }
}

View File

@ -1326,12 +1326,18 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty<'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 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'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.

View File

@ -310,9 +310,9 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
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))
}

View File

@ -104,7 +104,7 @@ fn generic_arg_mismatch_err(
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(),

View File

@ -2363,8 +2363,14 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
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)
}

View File

@ -1238,12 +1238,12 @@ fn check_expr_const_block(
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() {

View File

@ -498,6 +498,13 @@ pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'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);

View File

@ -182,7 +182,7 @@ struct CollectItemTypesVisitor<'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 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'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<Span>,
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 @@ fn ct_infer(
_: 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() {

View File

@ -13,7 +13,7 @@
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 fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
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);

View File

@ -1350,17 +1350,23 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
}
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()),

View File

@ -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();
}

View File

@ -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`.

View File

@ -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());
}

View File

@ -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
}

View File

@ -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`.

View File

@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.

View File

@ -7,7 +7,17 @@
[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();
}

View File

@ -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);

View File

@ -6,7 +6,7 @@
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 @@ macro_rules! kind {
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) => {

View File

@ -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);

View File

@ -8,7 +8,7 @@
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 @@ fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
}
}
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 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
}
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 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
},
(&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 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
(&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 @@ pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_
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 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
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 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
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 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
}
}
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));

View File

@ -79,7 +79,7 @@
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 {

View File

@ -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 {