From 00eca69bffcb4ef95ba1dd6013b840bf12a85804 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 24 Feb 2021 06:46:30 +0000 Subject: [PATCH] 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 701d48a982d36..877633820be52 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 0000000000000..538eee337cc6d --- /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 0000000000000..5a44b8e706553 --- /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`.