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() {}