diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 60aa12b0511c7..6160450d76676 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -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 diff --git a/src/librustc_error_codes/error_codes/E0671.md b/src/librustc_error_codes/error_codes/E0671.md index 449fb8ffc8945..a993ce826a737 100644 --- a/src/librustc_error_codes/error_codes/E0671.md +++ b/src/librustc_error_codes/error_codes/E0671.md @@ -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 { // error diff --git a/src/librustc_error_codes/error_codes/E0770.md b/src/librustc_error_codes/error_codes/E0770.md new file mode 100644 index 0000000000000..278bf9b907b24 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0770.md @@ -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() {} // error! +``` + +To fix this error, use a concrete type for the const parameter: + +``` +#![feature(const_generics)] +fn foo() {} +``` diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 07b489a756267..9204f778a24b9 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2687,7 +2687,7 @@ pub enum Node<'hir> { Crate(&'hir CrateItem<'hir>), } -impl Node<'_> { +impl<'hir> Node<'hir> { pub fn ident(&self) -> Option { match self { Node::TraitItem(TraitItem { ident, .. }) @@ -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, _), .. }) @@ -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), diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 4f25b948eb66e..575049c6bac2f 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -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, diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 274f93dd50b0d..ed88e54969215 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -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<'_> { @@ -135,7 +139,8 @@ impl RibKind<'_> { | FnItemRibKind | ConstantItemRibKind | ModuleRibKind(_) - | MacroDefinition(_) => false, + | MacroDefinition(_) + | ConstParamTyRibKind => false, AssocItemRibKind | ItemRibKind(_) | ForwardTyParamBanRibKind => true, } } @@ -576,7 +581,11 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { for bound in ¶m.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(); } } } @@ -814,7 +823,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { | ItemRibKind(..) | ConstantItemRibKind | ModuleRibKind(..) - | ForwardTyParamBanRibKind => { + | ForwardTyParamBanRibKind + | ConstParamTyRibKind => { return false; } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a265c15c18bc9..c3686ca4899bc 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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 @@ -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 { @@ -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 { @@ -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. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4354996614b2a..17212187e6a01 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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}; @@ -1155,6 +1155,35 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option Visitor<'v> for AnonConstInParamListDetector { + type Map = intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + 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::*; @@ -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)`, + // and the types of const parameters, e.g. `struct V();`. + 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)); diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs new file mode 100644 index 0000000000000..5aa3617d1d7e0 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs @@ -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([(); N]); +//~^ ERROR: the type of const parameters must not depend on other generic parameters + +pub struct SelfDependent; +//~^ ERROR: the type of const parameters must not depend on other generic parameters + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr new file mode 100644 index 0000000000000..f6606aea726ad --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr @@ -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([(); 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; + | ^ 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 for more information + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs index 86ab8075896aa..db15ececfa436 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; struct B(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() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr index 92a7edf96bccb..35996e833610d 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr @@ -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(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 | @@ -7,15 +13,7 @@ LL | struct B(PhantomData<[T; N]>); = note: see issue #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(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`. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs index 654e36df37e98..7fe04a43412a1 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs @@ -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([(); 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() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr index ed05264161e53..d081dcbbc7a4e 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr @@ -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([(); 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 | @@ -7,14 +13,15 @@ LL | #![feature(const_generics)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #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([(); 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`. diff --git a/src/test/ui/const-generics/issues/issue-71169.rs b/src/test/ui/const-generics/issues/issue-71169.rs new file mode 100644 index 0000000000000..943a16cfcd6a7 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71169.rs @@ -0,0 +1,10 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn foo() {} +//~^ ERROR the type of const parameters must not +fn main() { + const DATA: [u8; 4] = *b"ABCD"; + foo::<4, DATA>(); + //~^ ERROR constant expression depends on +} diff --git a/src/test/ui/const-generics/issues/issue-71169.stderr b/src/test/ui/const-generics/issues/issue-71169.stderr new file mode 100644 index 0000000000000..6d4cf4027c146 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71169.stderr @@ -0,0 +1,17 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71169.rs:4:43 + | +LL | fn foo() {} + | ^^^ the type must not depend on the parameter `LEN` + +error: constant expression depends on a generic parameter + --> $DIR/issue-71169.rs:8:14 + | +LL | foo::<4, DATA>(); + | ^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71381.rs b/src/test/ui/const-generics/issues/issue-71381.rs index c32bd2847f837..08f9482394218 100644 --- a/src/test/ui/const-generics/issues/issue-71381.rs +++ b/src/test/ui/const-generics/issues/issue-71381.rs @@ -12,6 +12,7 @@ unsafe extern "C" fn pass(args: PassArg) { impl Test { pub fn call_me(&self) { //~^ ERROR: using function pointers as const generic parameters is forbidden + //~| ERROR: the type of const parameters must not depend on other generic parameters self.0 = Self::trampiline:: as _ } @@ -20,6 +21,7 @@ impl Test { const IDX: usize, const FN: unsafe extern "C" fn(Args), //~^ ERROR: using function pointers as const generic parameters is forbidden + //~| ERROR: the type of const parameters must not depend on other generic parameters >( args: Args, ) { diff --git a/src/test/ui/const-generics/issues/issue-71381.stderr b/src/test/ui/const-generics/issues/issue-71381.stderr index 6bb776fcfc017..fd4ebe3dead81 100644 --- a/src/test/ui/const-generics/issues/issue-71381.stderr +++ b/src/test/ui/const-generics/issues/issue-71381.stderr @@ -1,3 +1,15 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71381.rs:13:82 + | +LL | pub fn call_me(&self) { + | ^^^^ the type must not depend on the parameter `Args` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71381.rs:22:40 + | +LL | const FN: unsafe extern "C" fn(Args), + | ^^^^ the type must not depend on the parameter `Args` + error: using function pointers as const generic parameters is forbidden --> $DIR/issue-71381.rs:13:61 | @@ -5,10 +17,11 @@ LL | pub fn call_me $DIR/issue-71381.rs:21:19 + --> $DIR/issue-71381.rs:22:19 | LL | const FN: unsafe extern "C" fn(Args), | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71611.rs b/src/test/ui/const-generics/issues/issue-71611.rs index 64a049e743faf..06ff38dec66c7 100644 --- a/src/test/ui/const-generics/issues/issue-71611.rs +++ b/src/test/ui/const-generics/issues/issue-71611.rs @@ -3,6 +3,7 @@ fn func(outer: A) { //~^ ERROR: using function pointers as const generic parameters is forbidden + //~| ERROR: the type of const parameters must not depend on other generic parameters F(outer); } diff --git a/src/test/ui/const-generics/issues/issue-71611.stderr b/src/test/ui/const-generics/issues/issue-71611.stderr index 9a7bf1c0a8841..e2c9f22361ebe 100644 --- a/src/test/ui/const-generics/issues/issue-71611.stderr +++ b/src/test/ui/const-generics/issues/issue-71611.stderr @@ -1,8 +1,15 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71611.rs:4:31 + | +LL | fn func(outer: A) { + | ^ the type must not depend on the parameter `A` + error: using function pointers as const generic parameters is forbidden --> $DIR/issue-71611.rs:4:21 | LL | fn func(outer: A) { | ^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-73491.rs b/src/test/ui/const-generics/issues/issue-73491.rs new file mode 100644 index 0000000000000..05e1513bb75df --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73491.rs @@ -0,0 +1,9 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +const LEN: usize = 1024; + +fn hoge() {} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-74101.rs b/src/test/ui/const-generics/issues/issue-74101.rs new file mode 100644 index 0000000000000..2f427ef3a27dc --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74101.rs @@ -0,0 +1,9 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn test() {} + +struct Foo; + +fn main() {}