1
Fork 0

Auto merge of #82447 - Amanieu:legacy_const_generics, r=oli-obk

Add #[rustc_legacy_const_generics]

This is the first step towards removing `#[rustc_args_required_const]`: a new attribute is added which rewrites function calls of the form `func(a, b, c)` to `func::<{b}>(a, c)`. This allows previously stabilized functions in `stdarch` which use `rustc_args_required_const` to use const generics instead.

This new attribute is not intended to ever be stabilized, it is only intended for use in `stdarch` as a replacement for `#[rustc_args_required_const]`.

```rust
#[rustc_legacy_const_generics(1)]
pub fn foo<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
    [x, Y, z]
}

fn main() {
    assert_eq!(foo(0 + 0, 1 + 1, 2 + 2), [0, 2, 4]);
    assert_eq!(foo::<{1 + 1}>(0 + 0, 2 + 2), [0, 2, 4]);
}
```

r? `@oli-obk`
This commit is contained in:
bors 2021-02-25 18:14:50 +00:00
commit 98f8cce6db
16 changed files with 429 additions and 4 deletions

View file

@ -2326,8 +2326,22 @@ 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.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,
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) => {

View file

@ -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;
@ -995,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<LocalDefId>,
legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>,
}
/// Nothing really interesting here; it just provides memory for the rest of the crate.
@ -1076,6 +1079,10 @@ impl ResolverAstLowering for Resolver<'_> {
self.cstore().item_generics_num_lifetimes(def_id, sess)
}
fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> {
self.legacy_const_generic_args(expr)
}
fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes> {
self.partial_res_map.get(&id).cloned()
}
@ -1316,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);
@ -3308,6 +3316,61 @@ impl<'a> Resolver<'a> {
pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
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(&mut self, expr: &Expr) -> Option<Vec<usize>> {
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;
}
if let Some(v) = self.legacy_const_generic_args.get(&def_id) {
return v.clone();
}
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
}
}
fn names_to_string(names: &[Symbol]) -> String {