summary refs log tree commit diff
path: root/compiler/rustc_ast_lowering/src/expr.rs
diff options
context:
space:
mode:
authorAmanieu d'Antras <amanieu@gmail.com>2021-02-23 15:12:28 +0000
committerAmanieu d'Antras <amanieu@gmail.com>2021-02-23 17:25:55 +0000
commitd87eec1bf67959977c8ebaadc2ddcf4bdc14658a (patch)
tree1f777c2c1702ec27d57c346a8c9f7c1b876df372 /compiler/rustc_ast_lowering/src/expr.rs
parent9b471a3f5fe57e5c6e08acf665f2094422415a3d (diff)
downloadrust-d87eec1bf67959977c8ebaadc2ddcf4bdc14658a.tar.gz
rust-d87eec1bf67959977c8ebaadc2ddcf4bdc14658a.zip
Add #[rustc_legacy_const_generics]
Diffstat (limited to 'compiler/rustc_ast_lowering/src/expr.rs')
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs90
1 files changed, 88 insertions, 2 deletions
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<Vec<usize>> {
+        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<AstP<Expr>>,
+        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 }