forbid generic params inside of anon consts in ty defaults

This commit is contained in:
Bastian Kauschke 2020-07-18 23:42:10 +02:00
parent cb19cdb711
commit 33a05b40f7
7 changed files with 121 additions and 8 deletions

View File

@ -455,6 +455,17 @@ impl<'a> Resolver<'a> {
); );
err err
} }
ResolutionError::ParamInAnonConstInTyDefault(name) => {
let mut err = self.session.struct_span_err(
span,
"constant values inside of type parameter defaults must not depend on generic parameters",
);
err.span_label(
span,
format!("the anonymous constant must not depend on the parameter `{}`", name),
);
err
}
ResolutionError::SelfInTyParamDefault => { ResolutionError::SelfInTyParamDefault => {
let mut err = struct_span_err!( let mut err = struct_span_err!(
self.session, self.session,

View File

@ -570,7 +570,15 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
if let Some(ref ty) = default { if let Some(ref ty) = default {
self.ribs[TypeNS].push(default_ban_rib); self.ribs[TypeNS].push(default_ban_rib);
self.visit_ty(ty); self.with_rib(ValueNS, ForwardTyParamBanRibKind, |this| {
// HACK: We use an empty `ForwardTyParamBanRibKind` here which
// is only used to forbid the use of const parameters inside of
// type defaults.
//
// While the rib name doesn't really fit here, it does allow us to use the same
// code for both const and type parameters.
this.visit_ty(ty);
});
default_ban_rib = self.ribs[TypeNS].pop().unwrap(); default_ban_rib = self.ribs[TypeNS].pop().unwrap();
} }
@ -1081,7 +1089,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) { fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) {
debug!("with_constant_rib"); debug!("with_constant_rib");
self.with_rib(ValueNS, ConstantItemRibKind, |this| { self.with_rib(ValueNS, ConstantItemRibKind, |this| {
this.with_rib(TypeNS, ConstantItemRibKind, |this| {
this.with_label_rib(ConstantItemRibKind, f); this.with_label_rib(ConstantItemRibKind, f);
})
}); });
} }

View File

@ -216,6 +216,8 @@ enum ResolutionError<'a> {
ForwardDeclaredTyParam, // FIXME(const_generics:defaults) ForwardDeclaredTyParam, // FIXME(const_generics:defaults)
/// ERROR E0770: the type of const parameters must not depend on other generic parameters. /// ERROR E0770: the type of const parameters must not depend on other generic parameters.
ParamInTyOfConstParam(Symbol), ParamInTyOfConstParam(Symbol),
/// constant values inside of type parameter defaults must not depend on generic parameters.
ParamInAnonConstInTyDefault(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
@ -2526,18 +2528,40 @@ impl<'a> Resolver<'a> {
} }
} }
Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => { Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
let mut in_ty_param_default = false;
for rib in ribs { for rib in ribs {
let has_generic_params = match rib.kind { let has_generic_params = match rib.kind {
NormalRibKind NormalRibKind
| ClosureOrAsyncRibKind | ClosureOrAsyncRibKind
| AssocItemRibKind | AssocItemRibKind
| ModuleRibKind(..) | ModuleRibKind(..)
| MacroDefinition(..) | MacroDefinition(..) => {
| ForwardTyParamBanRibKind
| ConstantItemRibKind => {
// Nothing to do. Continue. // Nothing to do. Continue.
continue; continue;
} }
// We only forbid constant items if we are inside of type defaults,
// for example `struct Foo<T, U = [u8; std::mem::size_of::<T>()]>`
ForwardTyParamBanRibKind => {
in_ty_param_default = true;
continue;
}
ConstantItemRibKind => {
if in_ty_param_default {
if record_used {
self.report_error(
span,
ResolutionError::ParamInAnonConstInTyDefault(
rib_ident.name,
),
);
}
return Res::Err;
} else {
continue;
}
}
// This was an attempt to use a type parameter outside its scope. // This was an attempt to use a type parameter outside its scope.
ItemRibKind(has_generic_params) => has_generic_params, ItemRibKind(has_generic_params) => has_generic_params,
FnItemRibKind => HasGenericParams::Yes, FnItemRibKind => HasGenericParams::Yes,
@ -2572,15 +2596,38 @@ impl<'a> Resolver<'a> {
// (spuriously) conflicting with the const param. // (spuriously) conflicting with the const param.
ribs.next(); ribs.next();
} }
let mut in_ty_param_default = false;
for rib in ribs { for rib in ribs {
let has_generic_params = match rib.kind { let has_generic_params = match rib.kind {
NormalRibKind NormalRibKind
| ClosureOrAsyncRibKind | ClosureOrAsyncRibKind
| AssocItemRibKind | AssocItemRibKind
| ModuleRibKind(..) | ModuleRibKind(..)
| MacroDefinition(..) | MacroDefinition(..) => continue,
| ForwardTyParamBanRibKind
| ConstantItemRibKind => continue, // We only forbid constant items if we are inside of type defaults,
// for example `struct Foo<T, U = [u8; std::mem::size_of::<T>()]>`
ForwardTyParamBanRibKind => {
in_ty_param_default = true;
continue;
}
ConstantItemRibKind => {
if in_ty_param_default {
if record_used {
self.report_error(
span,
ResolutionError::ParamInAnonConstInTyDefault(
rib_ident.name,
),
);
}
return Res::Err;
} else {
continue;
}
}
ItemRibKind(has_generic_params) => has_generic_params, ItemRibKind(has_generic_params) => has_generic_params,
FnItemRibKind => HasGenericParams::Yes, FnItemRibKind => HasGenericParams::Yes,
ConstParamTyRibKind => { ConstParamTyRibKind => {

View File

@ -0,0 +1,10 @@
#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
//~^ ERROR constant values inside of type parameter defaults
// FIXME(const_generics:defaults): We still don't know how to we deal with type defaults.
struct Bar<T = [u8; N], const N: usize>(T);
//~^ ERROR constant values inside of type parameter defaults
fn main() {}

View File

@ -0,0 +1,23 @@
error: constant values inside of type parameter defaults must not depend on generic parameters
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:3:44
|
LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
| ^ the anonymous constant must not depend on the parameter `T`
error: constant values inside of type parameter defaults must not depend on generic parameters
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:21
|
LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^ the anonymous constant must not depend on the parameter `N`
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:1:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
error: aborting due to 2 previous errors; 1 warning emitted

View File

@ -0,0 +1,4 @@
struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
//~^ ERROR constant values inside of type parameter defaults
fn main() {}

View File

@ -0,0 +1,8 @@
error: constant values inside of type parameter defaults must not depend on generic parameters
--> $DIR/param-in-ct-in-ty-param-default.rs:1:44
|
LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
| ^ the anonymous constant must not depend on the parameter `T`
error: aborting due to previous error