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 params in the type of const params #74159

Merged
merged 8 commits into from
Jul 16, 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
1 change: 1 addition & 0 deletions src/librustc_error_codes/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ E0766: include_str!("./error_codes/E0766.md"),
E0767: include_str!("./error_codes/E0767.md"),
E0768: include_str!("./error_codes/E0768.md"),
E0769: include_str!("./error_codes/E0769.md"),
E0770: include_str!("./error_codes/E0770.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_error_codes/error_codes/E0671.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Const parameters cannot depend on type parameters.
The following is therefore invalid:

```compile_fail,E0741
```compile_fail,E0770
#![feature(const_generics)]

fn const_id<T, const N: T>() -> T { // error
Expand Down
15 changes: 15 additions & 0 deletions src/librustc_error_codes/error_codes/E0770.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
The type of a const parameter references other generic parameters.

Erroneous code example:

```compile_fail,E0770
#![feature(const_generics)]
fn foo<T, const N: T>() {} // error!
```

To fix this error, use a concrete type for the const parameter:

```
#![feature(const_generics)]
fn foo<T, const N: usize>() {}
```
6 changes: 3 additions & 3 deletions src/librustc_hir/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2687,7 +2687,7 @@ pub enum Node<'hir> {
Crate(&'hir CrateItem<'hir>),
}

impl Node<'_> {
impl<'hir> Node<'hir> {
pub fn ident(&self) -> Option<Ident> {
match self {
Node::TraitItem(TraitItem { ident, .. })
Expand All @@ -2698,7 +2698,7 @@ impl Node<'_> {
}
}

pub fn fn_decl(&self) -> Option<&FnDecl<'_>> {
pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> {
match self {
Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
Expand All @@ -2722,7 +2722,7 @@ impl Node<'_> {
}
}

pub fn generics(&self) -> Option<&Generics<'_>> {
pub fn generics(&self) -> Option<&'hir Generics<'hir>> {
match self {
Node::TraitItem(TraitItem { generics, .. })
| Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
Expand Down
13 changes: 13 additions & 0 deletions src/librustc_resolve/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,19 @@ impl<'a> Resolver<'a> {
);
err
}
ResolutionError::ParamInTyOfConstArg(name) => {
let mut err = struct_span_err!(
self.session,
span,
E0770,
"the type of const parameters must not depend on other generic parameters"
);
err.span_label(
span,
format!("the type 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 @@ -123,6 +123,10 @@ crate enum RibKind<'a> {
/// from the default of a type parameter because they're not declared
/// before said type parameter. Also see the `visit_generics` override.
ForwardTyParamBanRibKind,

/// We are inside of the type of a const parameter. Can't refer to any
/// parameters.
ConstParamTyRibKind,
}

impl RibKind<'_> {
Expand All @@ -135,7 +139,8 @@ impl RibKind<'_> {
| FnItemRibKind
| ConstantItemRibKind
| ModuleRibKind(_)
| MacroDefinition(_) => false,
| MacroDefinition(_)
| ConstParamTyRibKind => false,
AssocItemRibKind | ItemRibKind(_) | ForwardTyParamBanRibKind => true,
}
}
Expand Down Expand Up @@ -562,7 +567,11 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
for bound in &param.bounds {
self.visit_param_bound(bound);
}
self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
self.visit_ty(ty);
self.ribs[TypeNS].pop().unwrap();
self.ribs[ValueNS].pop().unwrap();
}
}
}
Expand Down Expand Up @@ -798,7 +807,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
| ItemRibKind(..)
| ConstantItemRibKind
| ModuleRibKind(..)
| ForwardTyParamBanRibKind => {
| ForwardTyParamBanRibKind
| ConstParamTyRibKind => {
return false;
}
}
Expand Down
34 changes: 33 additions & 1 deletion src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ enum ResolutionError<'a> {
BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'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),
/// Error E0735: type parameters with a default cannot use `Self`
SelfInTyParamDefault,
/// Error E0767: use of unreachable label
Expand Down Expand Up @@ -2480,6 +2482,12 @@ impl<'a> Resolver<'a> {
}
return Res::Err;
}
ConstParamTyRibKind => {
if record_used {
self.report_error(span, ParamInTyOfConstArg(rib_ident.name));
}
return Res::Err;
}
}
}
if let Some(res_err) = res_err {
Expand All @@ -2503,6 +2511,15 @@ impl<'a> Resolver<'a> {
// 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),
);
}
return Res::Err;
}
};

if record_used {
Expand All @@ -2527,9 +2544,24 @@ impl<'a> Resolver<'a> {
}
for rib in ribs {
let has_generic_params = match rib.kind {
NormalRibKind
| ClosureOrAsyncRibKind
| AssocItemRibKind
| ModuleRibKind(..)
| MacroDefinition(..)
| ForwardTyParamBanRibKind
| ConstantItemRibKind => continue,
ItemRibKind(has_generic_params) => has_generic_params,
FnItemRibKind => HasGenericParams::Yes,
_ => continue,
ConstParamTyRibKind => {
if record_used {
self.report_error(
span,
ResolutionError::ParamInTyOfConstArg(rib_ident.name),
);
}
return Res::Err;
}
};

// This was an attempt to use a const parameter outside its scope.
Expand Down
61 changes: 56 additions & 5 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::weak_lang_items;
use rustc_hir::{GenericParamKind, Node};
use rustc_hir::{GenericParamKind, HirId, Node};
use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::hir::map::Map;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
Expand Down Expand Up @@ -1155,6 +1155,35 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
}
}

struct AnonConstInParamListDetector {
in_param_list: bool,
found_anon_const_in_list: bool,
ct: HirId,
}

impl<'v> Visitor<'v> for AnonConstInParamListDetector {
type Map = intravisit::ErasedMap<'v>;

fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::None
}

fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
let prev = self.in_param_list;
self.in_param_list = true;
intravisit::walk_generic_param(self, p);
self.in_param_list = prev;
}

fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
if self.in_param_list && self.ct == c.hir_id {
self.found_anon_const_in_list = true;
} else {
intravisit::walk_anon_const(self, c)
}
}
}

fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
use rustc_hir::*;

Expand All @@ -1176,10 +1205,32 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
let parent_id = tcx.hir().get_parent_item(hir_id);
let parent_def_id = tcx.hir().local_def_id(parent_id);

// HACK(eddyb) this provides the correct generics when
// `feature(const_generics)` is enabled, so that const expressions
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
if tcx.lazy_normalization() {
let mut in_param_list = false;
for (_parent, node) in tcx.hir().parent_iter(hir_id) {
if let Some(generics) = node.generics() {
let mut visitor = AnonConstInParamListDetector {
in_param_list: false,
found_anon_const_in_list: false,
ct: hir_id,
};

visitor.visit_generics(generics);
in_param_list = visitor.found_anon_const_in_list;
break;
}
}

if in_param_list {
// We do not allow generic parameters in anon consts if we are inside
// of a param list.
//
// This affects both default type bindings, e.g. `struct<T, U = [u8; std::mem::size_of::<T>()]>(T, U)`,
// and the types of const parameters, e.g. `struct V<const N: usize, const M: [u8; N]>();`.
None
} else if tcx.lazy_normalization() {
// HACK(eddyb) this provides the correct generics when
// `feature(const_generics)` is enabled, so that const expressions
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
Some(parent_def_id.to_def_id())
} else {
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete

// Currently, const parameters cannot depend on other generic parameters,
// as our current implementation can't really support this.
//
// We may want to lift this restriction in the future.

pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
//~^ ERROR: the type of const parameters must not depend on other generic parameters

pub struct SelfDependent<const N: [u8; N]>;
//~^ ERROR: the type of const parameters must not depend on other generic parameters

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
error[E0770]: the type of const parameters must not depend on other generic parameters
--> $DIR/const-param-type-depends-on-const-param.rs:9:52
|
LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
| ^ the type must not depend on the parameter `N`

error[E0770]: the type of const parameters must not depend on other generic parameters
--> $DIR/const-param-type-depends-on-const-param.rs:12:40
|
LL | pub struct SelfDependent<const N: [u8; N]>;
| ^ the type 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/const-param-type-depends-on-const-param.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

For more information about this error, try `rustc --explain E0770`.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::marker::PhantomData;

struct B<T, const N: T>(PhantomData<[T; N]>); //~ ERROR const generics are unstable
//~^ ERROR `T` is not guaranteed to `#[derive(PartialEq, Eq)]`
//~^ ERROR the type of const parameters must not depend on other generic parameters

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
error[E0770]: the type of const parameters must not depend on other generic parameters
--> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22
|
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
| ^ the type must not depend on the parameter `T`

error[E0658]: const generics are unstable
--> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19
|
Expand All @@ -7,15 +13,7 @@ LL | struct B<T, const N: T>(PhantomData<[T; N]>);
= 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[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter
--> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22
|
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
| ^ `T` may not derive both `PartialEq` and `Eq`
|
= note: it is not currently possible to use a type parameter as the type of a const parameter

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0658, E0741.
Some errors have detailed explanations: E0658, E0770.
For more information about an error, try `rustc --explain E0658`.
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete

// Currently, const parameters cannot depend on type parameters, because there is no way to
// enforce the structural-match property on an arbitrary type parameter. This restriction
// may be relaxed in the future. See https://github.com/rust-lang/rfcs/pull/2000 for more
// details.
// Currently, const parameters cannot depend on other generic parameters,
// as our current implementation can't really support this.
//
// We may want to lift this restriction in the future.

pub struct Dependent<T, const X: T>([(); X]);
//~^ ERROR `T` is not guaranteed to `#[derive(PartialEq, Eq)]`
//~^ ERROR: the type of const parameters must not depend on other generic parameters
//~| ERROR: parameter `T` is never used

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
error[E0770]: the type of const parameters must not depend on other generic parameters
--> $DIR/const-param-type-depends-on-type-param.rs:9:34
|
LL | pub struct Dependent<T, const X: T>([(); X]);
| ^ the type must not depend on the parameter `T`

warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/const-param-type-depends-on-type-param.rs:1:12
|
Expand All @@ -7,14 +13,15 @@ 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[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter
--> $DIR/const-param-type-depends-on-type-param.rs:9:34
error[E0392]: parameter `T` is never used
--> $DIR/const-param-type-depends-on-type-param.rs:9:22
|
LL | pub struct Dependent<T, const X: T>([(); X]);
| ^ `T` may not derive both `PartialEq` and `Eq`
| ^ unused parameter
|
= note: it is not currently possible to use a type parameter as the type of a const parameter
= help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData`

error: aborting due to previous error; 1 warning emitted
error: aborting due to 2 previous errors; 1 warning emitted

For more information about this error, try `rustc --explain E0741`.
Some errors have detailed explanations: E0392, E0770.
For more information about an error, try `rustc --explain E0392`.
Loading