From 289e5fca7ecdb03db97be9d89ae908f253a3f263 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 28 Jul 2020 15:55:42 +0200 Subject: [PATCH] forbid generic params in complex consts --- src/librustc_ast/ast.rs | 24 ++++++++++ src/librustc_resolve/diagnostics.rs | 17 +++++++ src/librustc_resolve/late.rs | 44 ++++++++++++------- src/librustc_resolve/lib.rs | 32 ++++++++++++-- .../min_const_generics/complex-expression.rs | 37 ++++++++++++++++ .../complex-expression.stderr | 42 ++++++++++++++++++ .../feature-gate-min_const_generics.rs | 4 ++ .../feature-gate-min_const_generics.stderr | 12 +++++ 8 files changed, 194 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/const-generics/min_const_generics/complex-expression.rs create mode 100644 src/test/ui/const-generics/min_const_generics/complex-expression.stderr create mode 100644 src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs create mode 100644 src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 6543117774a..594a20e5513 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -1052,6 +1052,30 @@ impl Expr { } } + /// Is this expr either `N`, or `{ N }`. + /// + /// If this is not the case, name resolution does not resolve `N` when using + /// `feature(min_const_generics)` as more complex expressions are not supported. + pub fn is_potential_trivial_const_param(&self) -> bool { + let this = if let ExprKind::Block(ref block, None) = self.kind { + if block.stmts.len() == 1 { + if let StmtKind::Expr(ref expr) = block.stmts[0].kind { expr } else { self } + } else { + self + } + } else { + self + }; + + if let ExprKind::Path(None, ref path) = this.kind { + if path.segments.len() == 1 && path.segments[0].args.is_none() { + return true; + } + } + + false + } + pub fn to_bound(&self) -> Option { match &self.kind { ExprKind::Path(None, path) => Some(GenericBound::Trait( diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 81e29047dc5..6fe923b839c 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -466,6 +466,23 @@ impl<'a> Resolver<'a> { ); err } + ResolutionError::ParamInNonTrivialAnonConst(name) => { + let mut err = self.session.struct_span_err( + span, + "generic parameters must not be used inside of non trivial constant values", + ); + err.span_label( + span, + &format!( + "non-trivial anonymous constants must not depend on the parameter `{}`", + name + ), + ); + err.help( + &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", name) + ); + err + } ResolutionError::SelfInTyParamDefault => { let mut err = struct_span_err!( self.session, diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 44ff4209095..853085fbc00 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -111,7 +111,7 @@ crate enum RibKind<'a> { ItemRibKind(HasGenericParams), /// We're in a constant item. Can't refer to dynamic stuff. - ConstantItemRibKind, + ConstantItemRibKind(bool), /// We passed through a module. ModuleRibKind(Module<'a>), @@ -137,7 +137,7 @@ impl RibKind<'_> { NormalRibKind | ClosureOrAsyncRibKind | FnItemRibKind - | ConstantItemRibKind + | ConstantItemRibKind(_) | ModuleRibKind(_) | MacroDefinition(_) | ConstParamTyRibKind => false, @@ -426,7 +426,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } fn visit_anon_const(&mut self, constant: &'ast AnonConst) { debug!("visit_anon_const {:?}", constant); - self.with_constant_rib(|this| { + self.with_constant_rib(constant.value.is_potential_trivial_const_param(), |this| { visit::walk_anon_const(this, constant); }); } @@ -628,7 +628,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { if !check_ns(TypeNS) && check_ns(ValueNS) { // This must be equivalent to `visit_anon_const`, but we cannot call it // directly due to visitor lifetimes so we have to copy-paste some code. - self.with_constant_rib(|this| { + self.with_constant_rib(true, |this| { this.smart_resolve_path( ty.id, qself.as_ref(), @@ -829,7 +829,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { | ClosureOrAsyncRibKind | FnItemRibKind | ItemRibKind(..) - | ConstantItemRibKind + | ConstantItemRibKind(_) | ModuleRibKind(..) | ForwardTyParamBanRibKind | ConstParamTyRibKind => { @@ -948,7 +948,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Only impose the restrictions of `ConstRibKind` for an // actual constant expression in a provided default. if let Some(expr) = default { - this.with_constant_rib(|this| this.visit_expr(expr)); + this.with_constant_rib( + expr.is_potential_trivial_const_param(), + |this| this.visit_expr(expr), + ); } } AssocItemKind::Fn(_, _, generics, _) => { @@ -989,7 +992,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_item_rib(HasGenericParams::No, |this| { this.visit_ty(ty); if let Some(expr) = expr { - this.with_constant_rib(|this| this.visit_expr(expr)); + this.with_constant_rib(expr.is_potential_trivial_const_param(), |this| { + this.visit_expr(expr) + }); } }); } @@ -1086,11 +1091,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f)) } - fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) { + fn with_constant_rib(&mut self, trivial: bool, f: impl FnOnce(&mut Self)) { debug!("with_constant_rib"); - self.with_rib(ValueNS, ConstantItemRibKind, |this| { - this.with_rib(TypeNS, ConstantItemRibKind, |this| { - this.with_label_rib(ConstantItemRibKind, f); + self.with_rib(ValueNS, ConstantItemRibKind(trivial), |this| { + this.with_rib(TypeNS, ConstantItemRibKind(trivial), |this| { + this.with_label_rib(ConstantItemRibKind(trivial), f); }) }); } @@ -1220,7 +1225,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { for item in impl_items { use crate::ResolutionError::*; match &item.kind { - AssocItemKind::Const(..) => { + AssocItemKind::Const(_default, _ty, expr) => { debug!("resolve_implementation AssocItemKind::Const",); // If this is a trait impl, ensure the const // exists in trait @@ -1231,9 +1236,18 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { |n, s| ConstNotMemberOfTrait(n, s), ); - this.with_constant_rib(|this| { - visit::walk_assoc_item(this, item, AssocCtxt::Impl) - }); + this.with_constant_rib( + expr.as_ref().map_or(false, |e| { + e.is_potential_trivial_const_param() + }), + |this| { + visit::walk_assoc_item( + this, + item, + AssocCtxt::Impl, + ) + }, + ); } AssocItemKind::Fn(_, _, generics, _) => { // We also need a new scope for the impl item type parameters. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 234fcd789ee..1425efcb54d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -218,6 +218,10 @@ enum ResolutionError<'a> { ParamInTyOfConstParam(Symbol), /// constant values inside of type parameter defaults must not depend on generic parameters. ParamInAnonConstInTyDefault(Symbol), + /// generic parameters must not be used inside of non trivial constant values. + /// + /// This error is only emitted when using `min_const_generics`. + ParamInNonTrivialAnonConst(Symbol), /// Error E0735: type parameters with a default cannot use `Self` SelfInTyParamDefault, /// Error E0767: use of unreachable label @@ -2507,7 +2511,7 @@ impl<'a> Resolver<'a> { res_err = Some(CannotCaptureDynamicEnvironmentInFnItem); } } - ConstantItemRibKind => { + ConstantItemRibKind(_) => { // Still doesn't deal with upvars if record_used { self.report_error(span, AttemptToUseNonConstantValueInConstant); @@ -2546,7 +2550,18 @@ impl<'a> Resolver<'a> { in_ty_param_default = true; continue; } - ConstantItemRibKind => { + ConstantItemRibKind(trivial) => { + // HACK(min_const_generics): We currently only allow `N` or `{ N }`. + if !trivial && self.session.features_untracked().min_const_generics { + if record_used { + self.report_error( + span, + ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name), + ); + } + return Res::Err; + } + if in_ty_param_default { if record_used { self.report_error( @@ -2612,7 +2627,18 @@ impl<'a> Resolver<'a> { in_ty_param_default = true; continue; } - ConstantItemRibKind => { + ConstantItemRibKind(trivial) => { + // HACK(min_const_generics): We currently only allow `N` or `{ N }`. + if !trivial && self.session.features_untracked().min_const_generics { + if record_used { + self.report_error( + span, + ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name), + ); + } + return Res::Err; + } + if in_ty_param_default { if record_used { self.report_error( diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.rs b/src/test/ui/const-generics/min_const_generics/complex-expression.rs new file mode 100644 index 00000000000..201af9fcef3 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/complex-expression.rs @@ -0,0 +1,37 @@ +#![feature(min_const_generics)] + +fn test() {} + +fn ok() -> [u8; M] { + [0; { M }] +} + +struct Break0([u8; { N + 1 }]); +//~^ ERROR generic parameters must not be used inside of non trivial constant values + +struct Break1([u8; { { N } }]); +//~^ ERROR generic parameters must not be used inside of non trivial constant values + +fn break2() { + let _: [u8; N + 1]; + //~^ ERROR generic parameters must not be used inside of non trivial constant values +} + +fn break3() { + let _ = [0; N + 1]; + //~^ ERROR generic parameters must not be used inside of non trivial constant values +} + +trait Foo { + const ASSOC: usize; +} + +impl Foo for [u8; N] { + const ASSOC: usize = N + 1; + //~^ ERROR generic parameters must not be used inside of non trivial constant values + // FIXME(min_const_generics): We probably have to allow this as we can + // already allow referencing type parameters here on stable. +} + + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr new file mode 100644 index 00000000000..03857aee076 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr @@ -0,0 +1,42 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/complex-expression.rs:9:38 + | +LL | struct Break0([u8; { N + 1 }]); + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/complex-expression.rs:12:40 + | +LL | struct Break1([u8; { { N } }]); + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/complex-expression.rs:16:17 + | +LL | let _: [u8; N + 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/complex-expression.rs:21:17 + | +LL | let _ = [0; N + 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/complex-expression.rs:30:26 + | +LL | const ASSOC: usize = N + 1; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs b/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs new file mode 100644 index 00000000000..423deae4600 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs @@ -0,0 +1,4 @@ +fn test() {} +//~^ ERROR const generics are unstable + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr b/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr new file mode 100644 index 00000000000..80cfdc2d28c --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr @@ -0,0 +1,12 @@ +error[E0658]: const generics are unstable + --> $DIR/feature-gate-min_const_generics.rs:1:15 + | +LL | fn test() {} + | ^ + | + = note: see issue #44580 for more information + = help: add `#![feature(const_generics)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`.