forbid generic params in complex consts
This commit is contained in:
parent
375bccb8b3
commit
289e5fca7e
8 changed files with 194 additions and 18 deletions
|
@ -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<GenericBound> {
|
pub fn to_bound(&self) -> Option<GenericBound> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
ExprKind::Path(None, path) => Some(GenericBound::Trait(
|
ExprKind::Path(None, path) => Some(GenericBound::Trait(
|
||||||
|
|
|
@ -466,6 +466,23 @@ impl<'a> Resolver<'a> {
|
||||||
);
|
);
|
||||||
err
|
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 => {
|
ResolutionError::SelfInTyParamDefault => {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self.session,
|
self.session,
|
||||||
|
|
|
@ -111,7 +111,7 @@ crate enum RibKind<'a> {
|
||||||
ItemRibKind(HasGenericParams),
|
ItemRibKind(HasGenericParams),
|
||||||
|
|
||||||
/// We're in a constant item. Can't refer to dynamic stuff.
|
/// We're in a constant item. Can't refer to dynamic stuff.
|
||||||
ConstantItemRibKind,
|
ConstantItemRibKind(bool),
|
||||||
|
|
||||||
/// We passed through a module.
|
/// We passed through a module.
|
||||||
ModuleRibKind(Module<'a>),
|
ModuleRibKind(Module<'a>),
|
||||||
|
@ -137,7 +137,7 @@ impl RibKind<'_> {
|
||||||
NormalRibKind
|
NormalRibKind
|
||||||
| ClosureOrAsyncRibKind
|
| ClosureOrAsyncRibKind
|
||||||
| FnItemRibKind
|
| FnItemRibKind
|
||||||
| ConstantItemRibKind
|
| ConstantItemRibKind(_)
|
||||||
| ModuleRibKind(_)
|
| ModuleRibKind(_)
|
||||||
| MacroDefinition(_)
|
| MacroDefinition(_)
|
||||||
| ConstParamTyRibKind => false,
|
| ConstParamTyRibKind => false,
|
||||||
|
@ -426,7 +426,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
}
|
}
|
||||||
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
|
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
|
||||||
debug!("visit_anon_const {:?}", constant);
|
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);
|
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) {
|
if !check_ns(TypeNS) && check_ns(ValueNS) {
|
||||||
// This must be equivalent to `visit_anon_const`, but we cannot call it
|
// 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.
|
// 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(
|
this.smart_resolve_path(
|
||||||
ty.id,
|
ty.id,
|
||||||
qself.as_ref(),
|
qself.as_ref(),
|
||||||
|
@ -829,7 +829,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
| ClosureOrAsyncRibKind
|
| ClosureOrAsyncRibKind
|
||||||
| FnItemRibKind
|
| FnItemRibKind
|
||||||
| ItemRibKind(..)
|
| ItemRibKind(..)
|
||||||
| ConstantItemRibKind
|
| ConstantItemRibKind(_)
|
||||||
| ModuleRibKind(..)
|
| ModuleRibKind(..)
|
||||||
| ForwardTyParamBanRibKind
|
| ForwardTyParamBanRibKind
|
||||||
| ConstParamTyRibKind => {
|
| ConstParamTyRibKind => {
|
||||||
|
@ -948,7 +948,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
// Only impose the restrictions of `ConstRibKind` for an
|
// Only impose the restrictions of `ConstRibKind` for an
|
||||||
// actual constant expression in a provided default.
|
// actual constant expression in a provided default.
|
||||||
if let Some(expr) = 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, _) => {
|
AssocItemKind::Fn(_, _, generics, _) => {
|
||||||
|
@ -989,7 +992,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
self.with_item_rib(HasGenericParams::No, |this| {
|
self.with_item_rib(HasGenericParams::No, |this| {
|
||||||
this.visit_ty(ty);
|
this.visit_ty(ty);
|
||||||
if let Some(expr) = expr {
|
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))
|
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");
|
debug!("with_constant_rib");
|
||||||
self.with_rib(ValueNS, ConstantItemRibKind, |this| {
|
self.with_rib(ValueNS, ConstantItemRibKind(trivial), |this| {
|
||||||
this.with_rib(TypeNS, ConstantItemRibKind, |this| {
|
this.with_rib(TypeNS, ConstantItemRibKind(trivial), |this| {
|
||||||
this.with_label_rib(ConstantItemRibKind, f);
|
this.with_label_rib(ConstantItemRibKind(trivial), f);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1220,7 +1225,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
for item in impl_items {
|
for item in impl_items {
|
||||||
use crate::ResolutionError::*;
|
use crate::ResolutionError::*;
|
||||||
match &item.kind {
|
match &item.kind {
|
||||||
AssocItemKind::Const(..) => {
|
AssocItemKind::Const(_default, _ty, expr) => {
|
||||||
debug!("resolve_implementation AssocItemKind::Const",);
|
debug!("resolve_implementation AssocItemKind::Const",);
|
||||||
// If this is a trait impl, ensure the const
|
// If this is a trait impl, ensure the const
|
||||||
// exists in trait
|
// exists in trait
|
||||||
|
@ -1231,9 +1236,18 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
|n, s| ConstNotMemberOfTrait(n, s),
|
|n, s| ConstNotMemberOfTrait(n, s),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.with_constant_rib(|this| {
|
this.with_constant_rib(
|
||||||
visit::walk_assoc_item(this, item, AssocCtxt::Impl)
|
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, _) => {
|
AssocItemKind::Fn(_, _, generics, _) => {
|
||||||
// We also need a new scope for the impl item type parameters.
|
// We also need a new scope for the impl item type parameters.
|
||||||
|
|
|
@ -218,6 +218,10 @@ enum ResolutionError<'a> {
|
||||||
ParamInTyOfConstParam(Symbol),
|
ParamInTyOfConstParam(Symbol),
|
||||||
/// constant values inside of type parameter defaults must not depend on generic parameters.
|
/// constant values inside of type parameter defaults must not depend on generic parameters.
|
||||||
ParamInAnonConstInTyDefault(Symbol),
|
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`
|
/// Error E0735: type parameters with a default cannot use `Self`
|
||||||
SelfInTyParamDefault,
|
SelfInTyParamDefault,
|
||||||
/// Error E0767: use of unreachable label
|
/// Error E0767: use of unreachable label
|
||||||
|
@ -2507,7 +2511,7 @@ impl<'a> Resolver<'a> {
|
||||||
res_err = Some(CannotCaptureDynamicEnvironmentInFnItem);
|
res_err = Some(CannotCaptureDynamicEnvironmentInFnItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConstantItemRibKind => {
|
ConstantItemRibKind(_) => {
|
||||||
// Still doesn't deal with upvars
|
// Still doesn't deal with upvars
|
||||||
if record_used {
|
if record_used {
|
||||||
self.report_error(span, AttemptToUseNonConstantValueInConstant);
|
self.report_error(span, AttemptToUseNonConstantValueInConstant);
|
||||||
|
@ -2546,7 +2550,18 @@ impl<'a> Resolver<'a> {
|
||||||
in_ty_param_default = true;
|
in_ty_param_default = true;
|
||||||
continue;
|
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 in_ty_param_default {
|
||||||
if record_used {
|
if record_used {
|
||||||
self.report_error(
|
self.report_error(
|
||||||
|
@ -2612,7 +2627,18 @@ impl<'a> Resolver<'a> {
|
||||||
in_ty_param_default = true;
|
in_ty_param_default = true;
|
||||||
continue;
|
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 in_ty_param_default {
|
||||||
if record_used {
|
if record_used {
|
||||||
self.report_error(
|
self.report_error(
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
#![feature(min_const_generics)]
|
||||||
|
|
||||||
|
fn test<const N: usize>() {}
|
||||||
|
|
||||||
|
fn ok<const M: usize>() -> [u8; M] {
|
||||||
|
[0; { M }]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Break0<const N: usize>([u8; { N + 1 }]);
|
||||||
|
//~^ ERROR generic parameters must not be used inside of non trivial constant values
|
||||||
|
|
||||||
|
struct Break1<const N: usize>([u8; { { N } }]);
|
||||||
|
//~^ ERROR generic parameters must not be used inside of non trivial constant values
|
||||||
|
|
||||||
|
fn break2<const N: usize>() {
|
||||||
|
let _: [u8; N + 1];
|
||||||
|
//~^ ERROR generic parameters must not be used inside of non trivial constant values
|
||||||
|
}
|
||||||
|
|
||||||
|
fn break3<const N: usize>() {
|
||||||
|
let _ = [0; N + 1];
|
||||||
|
//~^ ERROR generic parameters must not be used inside of non trivial constant values
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
const ASSOC: usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> 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() {}
|
|
@ -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<const N: usize>([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<const N: usize>([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
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn test<const N: usize>() {}
|
||||||
|
//~^ ERROR const generics are unstable
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0658]: const generics are unstable
|
||||||
|
--> $DIR/feature-gate-min_const_generics.rs:1:15
|
||||||
|
|
|
||||||
|
LL | fn test<const N: usize>() {}
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/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`.
|
Loading…
Add table
Add a link
Reference in a new issue