Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forbid generic parameters in anon consts inside of type defaults #74487

Merged
merged 3 commits into from
Jul 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/librustc_resolve/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ impl<'a> Resolver<'a> {
);
err
}
ResolutionError::ParamInTyOfConstArg(name) => {
ResolutionError::ParamInTyOfConstParam(name) => {
let mut err = struct_span_err!(
self.session,
span,
Expand All @@ -455,6 +455,17 @@ impl<'a> Resolver<'a> {
);
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 => {
let mut err = struct_span_err!(
self.session,
Expand Down
14 changes: 12 additions & 2 deletions src/librustc_resolve/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,15 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {

if let Some(ref ty) = default {
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();
}

Expand Down Expand Up @@ -1081,7 +1089,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) {
debug!("with_constant_rib");
self.with_rib(ValueNS, ConstantItemRibKind, |this| {
this.with_label_rib(ConstantItemRibKind, f);
this.with_rib(TypeNS, ConstantItemRibKind, |this| {
this.with_label_rib(ConstantItemRibKind, f);
})
});
}

Expand Down
67 changes: 57 additions & 10 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,9 @@ enum ResolutionError<'a> {
/// Error E0128: type parameters with a default cannot use forward-declared identifiers.
ForwardDeclaredTyParam, // FIXME(const_generics:defaults)
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
ParamInTyOfConstArg(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`
SelfInTyParamDefault,
/// Error E0767: use of unreachable label
Expand Down Expand Up @@ -2514,7 +2516,7 @@ impl<'a> Resolver<'a> {
}
ConstParamTyRibKind => {
if record_used {
self.report_error(span, ParamInTyOfConstArg(rib_ident.name));
self.report_error(span, ParamInTyOfConstParam(rib_ident.name));
}
return Res::Err;
}
Expand All @@ -2526,26 +2528,48 @@ impl<'a> Resolver<'a> {
}
}
Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
let mut in_ty_param_default = false;
for rib in ribs {
let has_generic_params = match rib.kind {
NormalRibKind
| ClosureOrAsyncRibKind
| AssocItemRibKind
| ModuleRibKind(..)
| MacroDefinition(..)
| ForwardTyParamBanRibKind
| ConstantItemRibKind => {
| MacroDefinition(..) => {
// Nothing to do. 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.
ItemRibKind(has_generic_params) => has_generic_params,
FnItemRibKind => HasGenericParams::Yes,
ConstParamTyRibKind => {
if record_used {
self.report_error(
span,
ResolutionError::ParamInTyOfConstArg(rib_ident.name),
ResolutionError::ParamInTyOfConstParam(rib_ident.name),
);
}
return Res::Err;
Expand All @@ -2572,22 +2596,45 @@ impl<'a> Resolver<'a> {
// (spuriously) conflicting with the const param.
ribs.next();
}

let mut in_ty_param_default = false;
for rib in ribs {
let has_generic_params = match rib.kind {
NormalRibKind
| ClosureOrAsyncRibKind
| AssocItemRibKind
| ModuleRibKind(..)
| MacroDefinition(..)
| ForwardTyParamBanRibKind
| ConstantItemRibKind => continue,
| MacroDefinition(..) => 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,
FnItemRibKind => HasGenericParams::Yes,
ConstParamTyRibKind => {
if record_used {
self.report_error(
span,
ResolutionError::ParamInTyOfConstArg(rib_ident.name),
ResolutionError::ParamInTyOfConstParam(rib_ident.name),
);
}
return Res::Err;
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#![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
//~| ERROR type parameters with a default

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
error: type parameters with a default must be trailing
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:12
|
LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^
|
= note: using type defaults and const parameters in the same parameter list is currently not permitted

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 3 previous errors; 1 warning emitted

4 changes: 4 additions & 0 deletions src/test/ui/generic/param-in-ct-in-ty-param-default.rs
Original file line number Diff line number Diff line change
@@ -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() {}
8 changes: 8 additions & 0 deletions src/test/ui/generic/param-in-ct-in-ty-param-default.stderr
Original file line number Diff line number Diff line change
@@ -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