Skip to content

Commit

Permalink
Rollup merge of #74487 - lcnr:const-in-ty-default, r=varkor
Browse files Browse the repository at this point in the history
Forbid generic parameters in anon consts inside of type defaults

Emit a resolution error for `struct Foo<T, U = [u8; std::mem::size_of::<T>()]>`.
We are unable to support this with the way `ty::Generics` is currently used,
so let's just forbid it entirely for now.

Fixes some ICE on stable, e.g.
```rust
struct Foo<T, U = [u8; std::mem::size_of::<*mut T>()]>(T, U);
```

r? @varkor @eddyb
  • Loading branch information
Manishearth authored Jul 27, 2020
2 parents 7864c3f + 952fd0c commit e054340
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 13 deletions.
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

0 comments on commit e054340

Please sign in to comment.