From d87eec1bf67959977c8ebaadc2ddcf4bdc14658a Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 23 Feb 2021 15:12:28 +0000 Subject: [PATCH 1/8] Add #[rustc_legacy_const_generics] --- compiler/rustc_ast_lowering/src/expr.rs | 90 ++++++++++++++++++- compiler/rustc_ast_lowering/src/lib.rs | 12 +++ compiler/rustc_feature/src/builtin_attrs.rs | 1 + .../src/rmeta/decoder/cstore_impl.rs | 4 + compiler/rustc_passes/src/check_attr.rs | 75 ++++++++++++++++ compiler/rustc_resolve/src/lib.rs | 4 + compiler/rustc_span/src/symbol.rs | 1 + .../ui/auxiliary/legacy-const-generics.rs | 6 ++ ...d-rustc_legacy_const_generics-arguments.rs | 35 ++++++++ ...stc_legacy_const_generics-arguments.stderr | 66 ++++++++++++++ src/test/ui/legacy-const-generics.rs | 18 ++++ 11 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/auxiliary/legacy-const-generics.rs create mode 100644 src/test/ui/invalid-rustc_legacy_const_generics-arguments.rs create mode 100644 src/test/ui/invalid-rustc_legacy_const_generics-arguments.stderr create mode 100644 src/test/ui/legacy-const-generics.rs diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b118c0eaed4..145a9784010 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -9,7 +9,9 @@ use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::Res; +use rustc_hir::definitions::DefPathData; use rustc_session::parse::feature_err; +use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP}; @@ -42,8 +44,12 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), ExprKind::Call(ref f, ref args) => { - let f = self.lower_expr(f); - hir::ExprKind::Call(f, self.lower_exprs(args)) + if let Some(legacy_args) = self.legacy_const_generic_args(f) { + self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args) + } else { + let f = self.lower_expr(f); + hir::ExprKind::Call(f, self.lower_exprs(args)) + } } ExprKind::MethodCall(ref seg, ref args, span) => { let hir_seg = self.arena.alloc(self.lower_path_segment( @@ -292,6 +298,86 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + /// Checks if an expression refers to a function marked with + /// `#[rustc_legacy_const_generics]` and returns the argument index list + /// from the attribute. + fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option> { + if let ExprKind::Path(None, path) = &expr.kind { + if path.segments.last().unwrap().args.is_some() { + return None; + } + if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { + if partial_res.unresolved_segments() != 0 { + return None; + } + if let Res::Def(hir::def::DefKind::Fn, def_id) = partial_res.base_res() { + let attrs = self.item_attrs(def_id); + let attr = attrs + .iter() + .find(|a| self.sess.check_name(a, sym::rustc_legacy_const_generics))?; + let mut ret = vec![]; + for meta in attr.meta_item_list()? { + match meta.literal()?.kind { + LitKind::Int(a, _) => { + ret.push(a as usize); + } + _ => panic!("invalid arg index"), + } + } + return Some(ret); + } + } + } + None + } + + fn lower_legacy_const_generics( + &mut self, + mut f: Expr, + args: Vec>, + legacy_args_idx: &[usize], + ) -> hir::ExprKind<'hir> { + let path = match f.kind { + ExprKind::Path(None, ref mut path) => path, + _ => unreachable!(), + }; + + // Split the arguments into const generics and normal arguments + let mut real_args = vec![]; + let mut generic_args = vec![]; + for (idx, arg) in args.into_iter().enumerate() { + if legacy_args_idx.contains(&idx) { + let parent_def_id = self.current_hir_id_owner.last().unwrap().0; + let node_id = self.resolver.next_node_id(); + + // Add a definition for the in-band const def. + self.resolver.create_def( + parent_def_id, + node_id, + DefPathData::AnonConst, + ExpnId::root(), + arg.span, + ); + + let anon_const = AnonConst { id: node_id, value: arg }; + generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const))); + } else { + real_args.push(arg); + } + } + + // Add generic args to the last element of the path + path.segments.last_mut().unwrap().args = + Some(AstP(GenericArgs::AngleBracketed(AngleBracketedArgs { + span: DUMMY_SP, + args: generic_args, + }))); + + // Now lower everything as normal. + let f = self.lower_expr(&f); + hir::ExprKind::Call(f, self.lower_exprs(&real_args)) + } + /// Emit an error and lower `ast::ExprKind::Let(pat, scrutinee)` into: /// ```rust /// match scrutinee { pats => true, _ => false } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 05b417effd4..4a438541211 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -175,6 +175,8 @@ pub trait ResolverAstLowering { fn item_generics_num_lifetimes(&self, def: DefId, sess: &Session) -> usize; + fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec; + /// Obtains resolution for a `NodeId` with a single resolution. fn get_partial_res(&mut self, id: NodeId) -> Option; @@ -2826,6 +2828,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } } + + fn item_attrs(&self, def_id: DefId) -> Vec { + if let Some(_local_def_id) = def_id.as_local() { + // TODO: This doesn't actually work, items doesn't include everything? + //self.items[&hir::ItemId { def_id: local_def_id }].attrs.into() + Vec::new() + } else { + self.resolver.item_attrs(def_id, self.sess) + } + } } fn body_ids(bodies: &BTreeMap>) -> Vec { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index ac50703b544..072062dd615 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -470,6 +470,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL), rustc_attr!(rustc_args_required_const, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE), + rustc_attr!(rustc_legacy_const_generics, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE), // ========================================================================== // Internal attributes, Layout related: diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 828c025d38d..0f860d11dc2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -468,6 +468,10 @@ impl CStore { pub fn num_def_ids(&self, cnum: CrateNum) -> usize { self.get_crate_data(cnum).num_def_ids() } + + pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec { + self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect() + } } impl CrateStore for CStore { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index bf9b7e588bd..947cca3c725 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -91,6 +91,8 @@ impl CheckAttrVisitor<'tcx> { self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target) } else if self.tcx.sess.check_name(attr, sym::naked) { self.check_naked(hir_id, attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::rustc_legacy_const_generics) { + self.check_rustc_legacy_const_generics(&attr, span, target, item) } else { // lint-only checks if self.tcx.sess.check_name(attr, sym::cold) { @@ -750,6 +752,79 @@ impl CheckAttrVisitor<'tcx> { } } + /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument. + fn check_rustc_legacy_const_generics( + &self, + attr: &Attribute, + span: &Span, + target: Target, + item: Option>, + ) -> bool { + let is_function = matches!(target, Target::Fn | Target::Method(..) | Target::ForeignFn); + if !is_function { + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a function") + .span_label(*span, "not a function") + .emit(); + return false; + } + + let list = match attr.meta_item_list() { + // The attribute form is validated on AST. + None => return false, + Some(it) => it, + }; + + let mut invalid_args = vec![]; + for meta in list { + if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) { + if let Some(ItemLike::Item(Item { + kind: ItemKind::Fn(FnSig { decl, .. }, generics, _), + .. + })) + | Some(ItemLike::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(decl, _, generics), + .. + })) = item + { + let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128; + if *val >= arg_count { + let span = meta.span(); + self.tcx + .sess + .struct_span_err(span, "index exceeds number of arguments") + .span_label( + span, + format!( + "there {} only {} argument{}", + if arg_count != 1 { "are" } else { "is" }, + arg_count, + pluralize!(arg_count) + ), + ) + .emit(); + return false; + } + } else { + bug!("should be a function item"); + } + } else { + invalid_args.push(meta.span()); + } + } + + if !invalid_args.is_empty() { + self.tcx + .sess + .struct_span_err(invalid_args, "arguments should be non-negative integers") + .emit(); + false + } else { + true + } + } + /// Checks if `#[link_section]` is applied to a function or static. fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { match target { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 77fbbaa1532..7e663444595 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1076,6 +1076,10 @@ impl ResolverAstLowering for Resolver<'_> { self.cstore().item_generics_num_lifetimes(def_id, sess) } + fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec { + self.cstore().item_attrs(def_id, sess) + } + fn get_partial_res(&mut self, id: NodeId) -> Option { self.partial_res_map.get(&id).cloned() } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 653d70b6cf2..a3dadc372a9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -973,6 +973,7 @@ symbols! { rustc_layout, rustc_layout_scalar_valid_range_end, rustc_layout_scalar_valid_range_start, + rustc_legacy_const_generics, rustc_macro_transparency, rustc_mir, rustc_nonnull_optimization_guaranteed, diff --git a/src/test/ui/auxiliary/legacy-const-generics.rs b/src/test/ui/auxiliary/legacy-const-generics.rs new file mode 100644 index 00000000000..67352a2fbbb --- /dev/null +++ b/src/test/ui/auxiliary/legacy-const-generics.rs @@ -0,0 +1,6 @@ +#![feature(rustc_attrs)] + +#[rustc_legacy_const_generics(1)] +pub fn foo(x: usize, z: usize) -> [usize; 3] { + [x, Y, z] +} diff --git a/src/test/ui/invalid-rustc_legacy_const_generics-arguments.rs b/src/test/ui/invalid-rustc_legacy_const_generics-arguments.rs new file mode 100644 index 00000000000..e044cd7a1f5 --- /dev/null +++ b/src/test/ui/invalid-rustc_legacy_const_generics-arguments.rs @@ -0,0 +1,35 @@ +#![feature(rustc_attrs)] + +#[rustc_legacy_const_generics(0)] //~ ERROR index exceeds number of arguments +fn foo1() {} + +#[rustc_legacy_const_generics(1)] //~ ERROR index exceeds number of arguments +fn foo2(_: u8) {} + +#[rustc_legacy_const_generics(2)] //~ ERROR index exceeds number of arguments +fn foo3(_: u8) {} + +#[rustc_legacy_const_generics(a)] //~ ERROR arguments should be non-negative integers +fn foo4() {} + +#[rustc_legacy_const_generics(1, a, 2, b)] //~ ERROR arguments should be non-negative integers +fn foo5(_: u8, _: u8, _: u8) {} + +#[rustc_legacy_const_generics(0)] //~ ERROR attribute should be applied to a function +struct S; + +#[rustc_legacy_const_generics(0usize)] //~ ERROR suffixed literals are not allowed in attributes +fn foo6(_: u8) {} + +extern { + #[rustc_legacy_const_generics(1)] //~ ERROR index exceeds number of arguments + fn foo7(_: u8); +} + +#[rustc_legacy_const_generics] //~ ERROR malformed `rustc_legacy_const_generics` attribute +fn bar1() {} + +#[rustc_legacy_const_generics = 1] //~ ERROR malformed `rustc_legacy_const_generics` attribute +fn bar2() {} + +fn main() {} diff --git a/src/test/ui/invalid-rustc_legacy_const_generics-arguments.stderr b/src/test/ui/invalid-rustc_legacy_const_generics-arguments.stderr new file mode 100644 index 00000000000..92fad679257 --- /dev/null +++ b/src/test/ui/invalid-rustc_legacy_const_generics-arguments.stderr @@ -0,0 +1,66 @@ +error: suffixed literals are not allowed in attributes + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:21:31 + | +LL | #[rustc_legacy_const_generics(0usize)] + | ^^^^^^ + | + = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) + +error: malformed `rustc_legacy_const_generics` attribute input + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:29:1 + | +LL | #[rustc_legacy_const_generics] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]` + +error: malformed `rustc_legacy_const_generics` attribute input + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:32:1 + | +LL | #[rustc_legacy_const_generics = 1] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]` + +error: index exceeds number of arguments + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:3:31 + | +LL | #[rustc_legacy_const_generics(0)] + | ^ there are only 0 arguments + +error: index exceeds number of arguments + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:6:31 + | +LL | #[rustc_legacy_const_generics(1)] + | ^ there is only 1 argument + +error: index exceeds number of arguments + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:9:31 + | +LL | #[rustc_legacy_const_generics(2)] + | ^ there are only 2 arguments + +error: arguments should be non-negative integers + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:12:31 + | +LL | #[rustc_legacy_const_generics(a)] + | ^ + +error: arguments should be non-negative integers + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:15:34 + | +LL | #[rustc_legacy_const_generics(1, a, 2, b)] + | ^ ^ + +error: attribute should be applied to a function + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:18:1 + | +LL | #[rustc_legacy_const_generics(0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | struct S; + | --------- not a function + +error: index exceeds number of arguments + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:35 + | +LL | #[rustc_legacy_const_generics(1)] + | ^ there is only 1 argument + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/legacy-const-generics.rs b/src/test/ui/legacy-const-generics.rs new file mode 100644 index 00000000000..00ab4b6cccf --- /dev/null +++ b/src/test/ui/legacy-const-generics.rs @@ -0,0 +1,18 @@ +// aux-build:legacy-const-generics.rs +// run-pass + +#![feature(rustc_attrs)] + +extern crate legacy_const_generics; + +#[rustc_legacy_const_generics(1)] +pub fn bar(x: usize, z: usize) -> [usize; 3] { + [x, Y, z] +} + +fn main() { + assert_eq!(legacy_const_generics::foo(0 + 0, 1 + 1, 2 + 2), [0, 2, 4]); + assert_eq!(legacy_const_generics::foo::<{1 + 1}>(0 + 0, 2 + 2), [0, 2, 4]); + // TODO: Only works cross-crate + //assert_eq!(bar(0, 1, 2), [0, 1, 2]); +} From e604d01fede6a272f5cb4aae283a7db2219f0adc Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 23 Feb 2021 17:38:34 +0000 Subject: [PATCH 2/8] Move tests to subdirectory --- .../{ => invalid}/invalid-rustc_args_required_const-arguments.rs | 0 .../invalid-rustc_args_required_const-arguments.stderr | 0 .../invalid-rustc_legacy_const_generics-arguments.rs | 0 .../invalid-rustc_legacy_const_generics-arguments.stderr | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{ => invalid}/invalid-rustc_args_required_const-arguments.rs (100%) rename src/test/ui/{ => invalid}/invalid-rustc_args_required_const-arguments.stderr (100%) rename src/test/ui/{ => invalid}/invalid-rustc_legacy_const_generics-arguments.rs (100%) rename src/test/ui/{ => invalid}/invalid-rustc_legacy_const_generics-arguments.stderr (100%) diff --git a/src/test/ui/invalid-rustc_args_required_const-arguments.rs b/src/test/ui/invalid/invalid-rustc_args_required_const-arguments.rs similarity index 100% rename from src/test/ui/invalid-rustc_args_required_const-arguments.rs rename to src/test/ui/invalid/invalid-rustc_args_required_const-arguments.rs diff --git a/src/test/ui/invalid-rustc_args_required_const-arguments.stderr b/src/test/ui/invalid/invalid-rustc_args_required_const-arguments.stderr similarity index 100% rename from src/test/ui/invalid-rustc_args_required_const-arguments.stderr rename to src/test/ui/invalid/invalid-rustc_args_required_const-arguments.stderr diff --git a/src/test/ui/invalid-rustc_legacy_const_generics-arguments.rs b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs similarity index 100% rename from src/test/ui/invalid-rustc_legacy_const_generics-arguments.rs rename to src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs diff --git a/src/test/ui/invalid-rustc_legacy_const_generics-arguments.stderr b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr similarity index 100% rename from src/test/ui/invalid-rustc_legacy_const_generics-arguments.stderr rename to src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr From 69cde44390de43748904bceb808e2e1b097e62a8 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 24 Feb 2021 02:36:45 +0000 Subject: [PATCH 3/8] TODO -> FIXME --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- src/test/ui/legacy-const-generics.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 4a438541211..6429dabbea8 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2831,7 +2831,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn item_attrs(&self, def_id: DefId) -> Vec { if let Some(_local_def_id) = def_id.as_local() { - // TODO: This doesn't actually work, items doesn't include everything? + // FIXME: This doesn't actually work, items doesn't include everything? //self.items[&hir::ItemId { def_id: local_def_id }].attrs.into() Vec::new() } else { diff --git a/src/test/ui/legacy-const-generics.rs b/src/test/ui/legacy-const-generics.rs index 00ab4b6cccf..9abc72d98e6 100644 --- a/src/test/ui/legacy-const-generics.rs +++ b/src/test/ui/legacy-const-generics.rs @@ -13,6 +13,6 @@ pub fn bar(x: usize, z: usize) -> [usize; 3] { fn main() { assert_eq!(legacy_const_generics::foo(0 + 0, 1 + 1, 2 + 2), [0, 2, 4]); assert_eq!(legacy_const_generics::foo::<{1 + 1}>(0 + 0, 2 + 2), [0, 2, 4]); - // TODO: Only works cross-crate + // FIXME: Only works cross-crate //assert_eq!(bar(0, 1, 2), [0, 1, 2]); } From 00eca69bffcb4ef95ba1dd6013b840bf12a85804 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 24 Feb 2021 06:46:30 +0000 Subject: [PATCH 4/8] Properly reject non-const arguments --- compiler/rustc_resolve/src/late.rs | 52 +++++++++++++++++++- src/test/ui/legacy-const-generics-bad.rs | 16 ++++++ src/test/ui/legacy-const-generics-bad.stderr | 20 ++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/legacy-const-generics-bad.rs create mode 100644 src/test/ui/legacy-const-generics-bad.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 701d48a982d..877633820be 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2326,8 +2326,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::Call(ref callee, ref arguments) => { self.resolve_expr(callee, Some(expr)); - for argument in arguments { - self.resolve_expr(argument, None); + let const_args = self.legacy_const_generic_args(callee).unwrap_or(Vec::new()); + for (idx, argument) in arguments.iter().enumerate() { + if const_args.contains(&idx) { + self.with_constant_rib( + IsRepeatExpr::No, + argument.is_potential_trivial_const_param(), + None, + |this| { + this.resolve_expr(argument, None); + }, + ); + } else { + self.resolve_expr(argument, None); + } } } ExprKind::Type(ref type_expr, ref ty) => { @@ -2406,6 +2418,42 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { Some((ident.name, ns)), ) } + + /// Checks if an expression refers to a function marked with + /// `#[rustc_legacy_const_generics]` and returns the argument index list + /// from the attribute. + fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option> { + if let ExprKind::Path(None, path) = &expr.kind { + if path.segments.last().unwrap().args.is_some() { + return None; + } + if let Some(partial_res) = self.r.get_partial_res(expr.id) { + if partial_res.unresolved_segments() != 0 { + return None; + } + if let Res::Def(def::DefKind::Fn, def_id) = partial_res.base_res() { + if def_id.is_local() { + return None; + } + let attrs = self.r.cstore().item_attrs(def_id, self.r.session); + let attr = attrs + .iter() + .find(|a| self.r.session.check_name(a, sym::rustc_legacy_const_generics))?; + let mut ret = vec![]; + for meta in attr.meta_item_list()? { + match meta.literal()?.kind { + LitKind::Int(a, _) => { + ret.push(a as usize); + } + _ => panic!("invalid arg index"), + } + } + return Some(ret); + } + } + } + None + } } impl<'a> Resolver<'a> { diff --git a/src/test/ui/legacy-const-generics-bad.rs b/src/test/ui/legacy-const-generics-bad.rs new file mode 100644 index 00000000000..538eee337cc --- /dev/null +++ b/src/test/ui/legacy-const-generics-bad.rs @@ -0,0 +1,16 @@ +// aux-build:legacy-const-generics.rs + +extern crate legacy_const_generics; + +fn foo() { + let a = 1; + legacy_const_generics::foo(0, a, 2); + //~^ ERROR attempt to use a non-constant value in a constant + + legacy_const_generics::foo(0, N, 2); + + legacy_const_generics::foo(0, N + 1, 2); + //~^ ERROR generic parameters may not be used in const operations +} + +fn main() {} diff --git a/src/test/ui/legacy-const-generics-bad.stderr b/src/test/ui/legacy-const-generics-bad.stderr new file mode 100644 index 00000000000..5a44b8e7065 --- /dev/null +++ b/src/test/ui/legacy-const-generics-bad.stderr @@ -0,0 +1,20 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/legacy-const-generics-bad.rs:7:35 + | +LL | let a = 1; + | ----- help: consider using `const` instead of `let`: `const a` +LL | legacy_const_generics::foo(0, a, 2); + | ^ non-constant value + +error: generic parameters may not be used in const operations + --> $DIR/legacy-const-generics-bad.rs:12:35 + | +LL | legacy_const_generics::foo(0, N + 1, 2); + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0435`. From 2451f124c95b2edfcaac9706500163c0224502df Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 25 Feb 2021 00:09:33 +0000 Subject: [PATCH 5/8] Address review comments --- compiler/rustc_ast_lowering/src/expr.rs | 48 ++++--------------- compiler/rustc_ast_lowering/src/lib.rs | 12 +---- compiler/rustc_passes/src/check_attr.rs | 17 +++++++ compiler/rustc_resolve/src/late.rs | 40 ++-------------- compiler/rustc_resolve/src/lib.rs | 48 ++++++++++++++++++- ...d-rustc_legacy_const_generics-arguments.rs | 3 ++ 6 files changed, 78 insertions(+), 90 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 145a9784010..f090bfbf2b2 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -44,7 +44,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), ExprKind::Call(ref f, ref args) => { - if let Some(legacy_args) = self.legacy_const_generic_args(f) { + if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) { self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args) } else { let f = self.lower_expr(f); @@ -298,39 +298,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - /// Checks if an expression refers to a function marked with - /// `#[rustc_legacy_const_generics]` and returns the argument index list - /// from the attribute. - fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option> { - if let ExprKind::Path(None, path) = &expr.kind { - if path.segments.last().unwrap().args.is_some() { - return None; - } - if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { - if partial_res.unresolved_segments() != 0 { - return None; - } - if let Res::Def(hir::def::DefKind::Fn, def_id) = partial_res.base_res() { - let attrs = self.item_attrs(def_id); - let attr = attrs - .iter() - .find(|a| self.sess.check_name(a, sym::rustc_legacy_const_generics))?; - let mut ret = vec![]; - for meta in attr.meta_item_list()? { - match meta.literal()?.kind { - LitKind::Int(a, _) => { - ret.push(a as usize); - } - _ => panic!("invalid arg index"), - } - } - return Some(ret); - } - } - } - None - } - fn lower_legacy_const_generics( &mut self, mut f: Expr, @@ -366,12 +333,13 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - // Add generic args to the last element of the path - path.segments.last_mut().unwrap().args = - Some(AstP(GenericArgs::AngleBracketed(AngleBracketedArgs { - span: DUMMY_SP, - args: generic_args, - }))); + // Add generic args to the last element of the path. + let last_segment = path.segments.last_mut().unwrap(); + assert!(last_segment.args.is_none()); + last_segment.args = Some(AstP(GenericArgs::AngleBracketed(AngleBracketedArgs { + span: DUMMY_SP, + args: generic_args, + }))); // Now lower everything as normal. let f = self.lower_expr(&f); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6429dabbea8..644e1d1139f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -175,7 +175,7 @@ pub trait ResolverAstLowering { fn item_generics_num_lifetimes(&self, def: DefId, sess: &Session) -> usize; - fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec; + fn legacy_const_generic_args(&self, expr: &Expr) -> Option>; /// Obtains resolution for a `NodeId` with a single resolution. fn get_partial_res(&mut self, id: NodeId) -> Option; @@ -2828,16 +2828,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } } - - fn item_attrs(&self, def_id: DefId) -> Vec { - if let Some(_local_def_id) = def_id.as_local() { - // FIXME: This doesn't actually work, items doesn't include everything? - //self.items[&hir::ItemId { def_id: local_def_id }].attrs.into() - Vec::new() - } else { - self.resolver.item_attrs(def_id, self.sess) - } - } } fn body_ids(bodies: &BTreeMap>) -> Vec { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 947cca3c725..022f1858878 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -789,6 +789,23 @@ impl CheckAttrVisitor<'tcx> { })) = item { let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128; + for param in generics.params { + match param.kind { + hir::GenericParamKind::Const { .. } => {} + _ => { + self.tcx + .sess + .struct_span_err( + meta.span(), + "#[rustc_legacy_const_generics] functions must \ + only have const generics", + ) + .span_label(param.span, "non-const generic parameter") + .emit(); + break; + } + } + } if *val >= arg_count { let span = meta.span(); self.tcx diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 877633820be..6f24d7e9413 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2326,8 +2326,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::Call(ref callee, ref arguments) => { self.resolve_expr(callee, Some(expr)); - let const_args = self.legacy_const_generic_args(callee).unwrap_or(Vec::new()); + let const_args = self.r.legacy_const_generic_args(callee).unwrap_or(Vec::new()); for (idx, argument) in arguments.iter().enumerate() { + // Constant arguments need to be treated as AnonConst since + // that is how they will be later lowered to HIR. if const_args.contains(&idx) { self.with_constant_rib( IsRepeatExpr::No, @@ -2418,42 +2420,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { Some((ident.name, ns)), ) } - - /// Checks if an expression refers to a function marked with - /// `#[rustc_legacy_const_generics]` and returns the argument index list - /// from the attribute. - fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option> { - if let ExprKind::Path(None, path) = &expr.kind { - if path.segments.last().unwrap().args.is_some() { - return None; - } - if let Some(partial_res) = self.r.get_partial_res(expr.id) { - if partial_res.unresolved_segments() != 0 { - return None; - } - if let Res::Def(def::DefKind::Fn, def_id) = partial_res.base_res() { - if def_id.is_local() { - return None; - } - let attrs = self.r.cstore().item_attrs(def_id, self.r.session); - let attr = attrs - .iter() - .find(|a| self.r.session.check_name(a, sym::rustc_legacy_const_generics))?; - let mut ret = vec![]; - for meta in attr.meta_item_list()? { - match meta.literal()?.kind { - LitKind::Int(a, _) => { - ret.push(a as usize); - } - _ => panic!("invalid arg index"), - } - } - return Some(ret); - } - } - } - None - } } impl<'a> Resolver<'a> { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7e663444595..d703ed221a7 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -29,6 +29,7 @@ use rustc_ast::unwrap_or; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, NodeId}; use rustc_ast::{Crate, CRATE_NODE_ID}; +use rustc_ast::{Expr, ExprKind, LitKind}; use rustc_ast::{ItemKind, ModKind, Path}; use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_pretty::pprust; @@ -1076,8 +1077,8 @@ impl ResolverAstLowering for Resolver<'_> { self.cstore().item_generics_num_lifetimes(def_id, sess) } - fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec { - self.cstore().item_attrs(def_id, sess) + fn legacy_const_generic_args(&self, expr: &Expr) -> Option> { + self.legacy_const_generic_args(expr) } fn get_partial_res(&mut self, id: NodeId) -> Option { @@ -3312,6 +3313,49 @@ impl<'a> Resolver<'a> { pub fn opt_span(&self, def_id: DefId) -> Option { if let Some(def_id) = def_id.as_local() { Some(self.def_id_to_span[def_id]) } else { None } } + + /// Checks if an expression refers to a function marked with + /// `#[rustc_legacy_const_generics]` and returns the argument index list + /// from the attribute. + pub fn legacy_const_generic_args(&self, expr: &Expr) -> Option> { + if let ExprKind::Path(None, path) = &expr.kind { + // Don't perform legacy const generics rewriting if the path already + // has generic arguments. + if path.segments.last().unwrap().args.is_some() { + return None; + } + + let partial_res = self.partial_res_map.get(&expr.id)?; + if partial_res.unresolved_segments() != 0 { + return None; + } + + if let Res::Def(def::DefKind::Fn, def_id) = partial_res.base_res() { + // We only support cross-crate argument rewriting. Uses + // within the same crate should be updated to use the new + // const generics style. + if def_id.is_local() { + return None; + } + + let attrs = self.cstore().item_attrs(def_id, self.session); + let attr = attrs + .iter() + .find(|a| self.session.check_name(a, sym::rustc_legacy_const_generics))?; + let mut ret = vec![]; + for meta in attr.meta_item_list()? { + match meta.literal()?.kind { + LitKind::Int(a, _) => { + ret.push(a as usize); + } + _ => panic!("invalid arg index"), + } + } + return Some(ret); + } + } + None + } } fn names_to_string(names: &[Symbol]) -> String { diff --git a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs index e044cd7a1f5..880e2199dc4 100644 --- a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs +++ b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs @@ -26,6 +26,9 @@ extern { fn foo7(_: u8); } +#[rustc_legacy_const_generics(0)] //~ ERROR #[rustc_legacy_const_generics] functions must only have +fn foo3() {} + #[rustc_legacy_const_generics] //~ ERROR malformed `rustc_legacy_const_generics` attribute fn bar1() {} From cccd77955b9312be8c476ff07f2c96f08ec3a25c Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 25 Feb 2021 00:37:42 +0000 Subject: [PATCH 6/8] Fix tests --- ...nvalid-rustc_legacy_const_generics-arguments.rs | 2 +- ...id-rustc_legacy_const_generics-arguments.stderr | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs index 880e2199dc4..bf3f80807e6 100644 --- a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs +++ b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs @@ -27,7 +27,7 @@ extern { } #[rustc_legacy_const_generics(0)] //~ ERROR #[rustc_legacy_const_generics] functions must only have -fn foo3() {} +fn foo8() {} #[rustc_legacy_const_generics] //~ ERROR malformed `rustc_legacy_const_generics` attribute fn bar1() {} diff --git a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr index 92fad679257..0d9960a663e 100644 --- a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr +++ b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr @@ -7,13 +7,13 @@ LL | #[rustc_legacy_const_generics(0usize)] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: malformed `rustc_legacy_const_generics` attribute input - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:29:1 + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:32:1 | LL | #[rustc_legacy_const_generics] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]` error: malformed `rustc_legacy_const_generics` attribute input - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:32:1 + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:35:1 | LL | #[rustc_legacy_const_generics = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]` @@ -56,11 +56,19 @@ LL | #[rustc_legacy_const_generics(0)] LL | struct S; | --------- not a function +error: #[rustc_legacy_const_generics] functions must only have const generics + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:29:31 + | +LL | #[rustc_legacy_const_generics(0)] + | ^ +LL | fn foo8() {} + | - non-const generic parameter + error: index exceeds number of arguments --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:35 | LL | #[rustc_legacy_const_generics(1)] | ^ there is only 1 argument -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors From 22184a0f5d0e83d07425d6058e7ad93c78160233 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 25 Feb 2021 00:37:56 +0000 Subject: [PATCH 7/8] Add a cache for rustc_legacy_const_generics --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 45 +++++++++++++++++--------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 644e1d1139f..c564ada0395 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -175,7 +175,7 @@ pub trait ResolverAstLowering { fn item_generics_num_lifetimes(&self, def: DefId, sess: &Session) -> usize; - fn legacy_const_generic_args(&self, expr: &Expr) -> Option>; + fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option>; /// Obtains resolution for a `NodeId` with a single resolution. fn get_partial_res(&mut self, id: NodeId) -> Option; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d703ed221a7..e63fd4ce635 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -996,6 +996,8 @@ pub struct Resolver<'a> { /// Some way to know that we are in a *trait* impl in `visit_assoc_item`. /// FIXME: Replace with a more general AST map (together with some other fields). trait_impl_items: FxHashSet, + + legacy_const_generic_args: FxHashMap>>, } /// Nothing really interesting here; it just provides memory for the rest of the crate. @@ -1077,7 +1079,7 @@ impl ResolverAstLowering for Resolver<'_> { self.cstore().item_generics_num_lifetimes(def_id, sess) } - fn legacy_const_generic_args(&self, expr: &Expr) -> Option> { + fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option> { self.legacy_const_generic_args(expr) } @@ -1321,6 +1323,7 @@ impl<'a> Resolver<'a> { invocation_parents, next_disambiguator: Default::default(), trait_impl_items: Default::default(), + legacy_const_generic_args: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -3317,7 +3320,7 @@ impl<'a> Resolver<'a> { /// Checks if an expression refers to a function marked with /// `#[rustc_legacy_const_generics]` and returns the argument index list /// from the attribute. - pub fn legacy_const_generic_args(&self, expr: &Expr) -> Option> { + pub fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option> { if let ExprKind::Path(None, path) = &expr.kind { // Don't perform legacy const generics rewriting if the path already // has generic arguments. @@ -3338,20 +3341,32 @@ impl<'a> Resolver<'a> { return None; } - let attrs = self.cstore().item_attrs(def_id, self.session); - let attr = attrs - .iter() - .find(|a| self.session.check_name(a, sym::rustc_legacy_const_generics))?; - let mut ret = vec![]; - for meta in attr.meta_item_list()? { - match meta.literal()?.kind { - LitKind::Int(a, _) => { - ret.push(a as usize); - } - _ => panic!("invalid arg index"), - } + if let Some(v) = self.legacy_const_generic_args.get(&def_id) { + return v.clone(); } - return Some(ret); + + let parse_attrs = || { + let attrs = self.cstore().item_attrs(def_id, self.session); + let attr = attrs + .iter() + .find(|a| self.session.check_name(a, sym::rustc_legacy_const_generics))?; + let mut ret = vec![]; + for meta in attr.meta_item_list()? { + match meta.literal()?.kind { + LitKind::Int(a, _) => { + ret.push(a as usize); + } + _ => panic!("invalid arg index"), + } + } + Some(ret) + }; + + // Cache the lookup to avoid parsing attributes for an iterm + // multiple times. + let ret = parse_attrs(); + self.legacy_const_generic_args.insert(def_id, ret.clone()); + return ret; } } None From 00afbe70f2f5cb0b6455036f4b97537ff77f2052 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 25 Feb 2021 09:04:43 +0000 Subject: [PATCH 8/8] Improve checking for attribute --- compiler/rustc_passes/src/check_attr.rs | 103 ++++++++++-------- ...d-rustc_legacy_const_generics-arguments.rs | 14 +-- ...stc_legacy_const_generics-arguments.stderr | 31 ++++-- 3 files changed, 85 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 022f1858878..cf08881cd47 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -760,7 +760,7 @@ impl CheckAttrVisitor<'tcx> { target: Target, item: Option>, ) -> bool { - let is_function = matches!(target, Target::Fn | Target::Method(..) | Target::ForeignFn); + let is_function = matches!(target, Target::Fn | Target::Method(..)); if !is_function { self.tcx .sess @@ -776,55 +776,64 @@ impl CheckAttrVisitor<'tcx> { Some(it) => it, }; + let (decl, generics) = match item { + Some(ItemLike::Item(Item { + kind: ItemKind::Fn(FnSig { decl, .. }, generics, _), + .. + })) => (decl, generics), + _ => bug!("should be a function item"), + }; + + for param in generics.params { + match param.kind { + hir::GenericParamKind::Const { .. } => {} + _ => { + self.tcx + .sess + .struct_span_err( + attr.span, + "#[rustc_legacy_const_generics] functions must \ + only have const generics", + ) + .span_label(param.span, "non-const generic parameter") + .emit(); + return false; + } + } + } + + if list.len() != generics.params.len() { + self.tcx + .sess + .struct_span_err( + attr.span, + "#[rustc_legacy_const_generics] must have one index for each generic parameter", + ) + .span_label(generics.span, "generic parameters") + .emit(); + return false; + } + + let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128; let mut invalid_args = vec![]; for meta in list { if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) { - if let Some(ItemLike::Item(Item { - kind: ItemKind::Fn(FnSig { decl, .. }, generics, _), - .. - })) - | Some(ItemLike::ForeignItem(ForeignItem { - kind: ForeignItemKind::Fn(decl, _, generics), - .. - })) = item - { - let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128; - for param in generics.params { - match param.kind { - hir::GenericParamKind::Const { .. } => {} - _ => { - self.tcx - .sess - .struct_span_err( - meta.span(), - "#[rustc_legacy_const_generics] functions must \ - only have const generics", - ) - .span_label(param.span, "non-const generic parameter") - .emit(); - break; - } - } - } - if *val >= arg_count { - let span = meta.span(); - self.tcx - .sess - .struct_span_err(span, "index exceeds number of arguments") - .span_label( - span, - format!( - "there {} only {} argument{}", - if arg_count != 1 { "are" } else { "is" }, - arg_count, - pluralize!(arg_count) - ), - ) - .emit(); - return false; - } - } else { - bug!("should be a function item"); + if *val >= arg_count { + let span = meta.span(); + self.tcx + .sess + .struct_span_err(span, "index exceeds number of arguments") + .span_label( + span, + format!( + "there {} only {} argument{}", + if arg_count != 1 { "are" } else { "is" }, + arg_count, + pluralize!(arg_count) + ), + ) + .emit(); + return false; } } else { invalid_args.push(meta.span()); diff --git a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs index bf3f80807e6..3d8478f06db 100644 --- a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs +++ b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs @@ -1,29 +1,29 @@ #![feature(rustc_attrs)] -#[rustc_legacy_const_generics(0)] //~ ERROR index exceeds number of arguments +#[rustc_legacy_const_generics(0)] //~ ERROR #[rustc_legacy_const_generics] must have one index for fn foo1() {} #[rustc_legacy_const_generics(1)] //~ ERROR index exceeds number of arguments -fn foo2(_: u8) {} +fn foo2() {} #[rustc_legacy_const_generics(2)] //~ ERROR index exceeds number of arguments fn foo3(_: u8) {} #[rustc_legacy_const_generics(a)] //~ ERROR arguments should be non-negative integers -fn foo4() {} +fn foo4() {} #[rustc_legacy_const_generics(1, a, 2, b)] //~ ERROR arguments should be non-negative integers -fn foo5(_: u8, _: u8, _: u8) {} +fn foo5() {} #[rustc_legacy_const_generics(0)] //~ ERROR attribute should be applied to a function struct S; #[rustc_legacy_const_generics(0usize)] //~ ERROR suffixed literals are not allowed in attributes -fn foo6(_: u8) {} +fn foo6() {} extern { - #[rustc_legacy_const_generics(1)] //~ ERROR index exceeds number of arguments - fn foo7(_: u8); + #[rustc_legacy_const_generics(1)] //~ ERROR attribute should be applied to a function + fn foo7(); //~ ERROR foreign items may not have const parameters } #[rustc_legacy_const_generics(0)] //~ ERROR #[rustc_legacy_const_generics] functions must only have diff --git a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr index 0d9960a663e..1f55a8e72d2 100644 --- a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr +++ b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr @@ -18,11 +18,13 @@ error: malformed `rustc_legacy_const_generics` attribute input LL | #[rustc_legacy_const_generics = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]` -error: index exceeds number of arguments - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:3:31 +error: #[rustc_legacy_const_generics] must have one index for each generic parameter + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:3:1 | LL | #[rustc_legacy_const_generics(0)] - | ^ there are only 0 arguments + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo1() {} + | - generic parameters error: index exceeds number of arguments --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:6:31 @@ -57,18 +59,29 @@ LL | struct S; | --------- not a function error: #[rustc_legacy_const_generics] functions must only have const generics - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:29:31 + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:29:1 | LL | #[rustc_legacy_const_generics(0)] - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | fn foo8() {} | - non-const generic parameter -error: index exceeds number of arguments - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:35 +error: attribute should be applied to a function + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:5 | LL | #[rustc_legacy_const_generics(1)] - | ^ there is only 1 argument + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo7(); + | -------------------------- not a function -error: aborting due to 11 previous errors +error[E0044]: foreign items may not have const parameters + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:26:5 + | +LL | fn foo7(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters + | + = help: replace the const parameters with concrete consts +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0044`.