diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a7a005bdeb9f2..81e29047dc5e2 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -442,7 +442,7 @@ impl<'a> Resolver<'a> { ); err } - ResolutionError::ParamInTyOfConstArg(name) => { + ResolutionError::ParamInTyOfConstParam(name) => { let mut err = struct_span_err!( self.session, span, @@ -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, diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 4b5ab03df4327..bcd2c6c1f1c27 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -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(); } @@ -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); + }) }); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index dfc50a30c121e..234fcd789eee4 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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 @@ -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; } @@ -2526,18 +2528,40 @@ 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()]>` + 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, @@ -2545,7 +2569,7 @@ impl<'a> Resolver<'a> { if record_used { self.report_error( span, - ResolutionError::ParamInTyOfConstArg(rib_ident.name), + ResolutionError::ParamInTyOfConstParam(rib_ident.name), ); } return Res::Err; @@ -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()]>` + 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; diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs new file mode 100644 index 0000000000000..84bbea5b88057 --- /dev/null +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs @@ -0,0 +1,11 @@ +#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete + +struct Foo()]>(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); +//~^ ERROR constant values inside of type parameter defaults +//~| ERROR type parameters with a default + +fn main() {} diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.stderr new file mode 100644 index 0000000000000..571be91683b7c --- /dev/null +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.stderr @@ -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); + | ^ + | + = 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); + | ^ 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); + | ^ 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 for more information + +error: aborting due to 3 previous errors; 1 warning emitted + diff --git a/src/test/ui/generic/param-in-ct-in-ty-param-default.rs b/src/test/ui/generic/param-in-ct-in-ty-param-default.rs new file mode 100644 index 0000000000000..dd89bc0f7a0ff --- /dev/null +++ b/src/test/ui/generic/param-in-ct-in-ty-param-default.rs @@ -0,0 +1,4 @@ +struct Foo()]>(T, U); +//~^ ERROR constant values inside of type parameter defaults + +fn main() {} diff --git a/src/test/ui/generic/param-in-ct-in-ty-param-default.stderr b/src/test/ui/generic/param-in-ct-in-ty-param-default.stderr new file mode 100644 index 0000000000000..ea867240269ef --- /dev/null +++ b/src/test/ui/generic/param-in-ct-in-ty-param-default.stderr @@ -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); + | ^ the anonymous constant must not depend on the parameter `T` + +error: aborting due to previous error +