diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ac149be4b2a..c9b9898fb41 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -814,7 +814,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { debug!("(resolving function) entering function"); let (rib_kind, asyncness) = match function_kind { FnKind::ItemFn(_, ref header, ..) => - (ItemRibKind, header.asyncness.node), + (FnItemRibKind, header.asyncness.node), FnKind::Method(_, ref sig, _, _) => (TraitOrImplItemRibKind, sig.header.asyncness.node), FnKind::Closure(_) => @@ -950,6 +950,10 @@ enum RibKind<'a> { /// upvars). TraitOrImplItemRibKind, + /// We passed through a function definition. Disallow upvars. + /// Permit only those const parameters specified in the function's generics. + FnItemRibKind, + /// We passed through an item scope. Disallow upvars. ItemRibKind, @@ -3863,7 +3867,7 @@ impl<'a> Resolver<'a> { seen.insert(node_id, depth); } } - ItemRibKind | TraitOrImplItemRibKind => { + ItemRibKind | FnItemRibKind | TraitOrImplItemRibKind => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we // report an error. @@ -3897,7 +3901,7 @@ impl<'a> Resolver<'a> { ConstantItemRibKind => { // Nothing to do. Continue. } - ItemRibKind => { + ItemRibKind | FnItemRibKind => { // This was an attempt to use a type parameter outside its scope. if record_used { resolve_error( @@ -3912,21 +3916,27 @@ impl<'a> Resolver<'a> { } } Def::ConstParam(..) => { - // A const param is always declared in a signature, which is always followed by - // some kind of function rib kind (specifically, ItemRibKind in the case of a - // normal function), so we can skip the first rib as it will be guaranteed to - // (spuriously) conflict with the const param. - for rib in &ribs[1..] { - if let ItemRibKind = rib.kind { - // This was an attempt to use a const parameter outside its scope. - if record_used { - resolve_error( - self, - span, - ResolutionError::GenericParamsFromOuterFunction(def), - ); + let mut ribs = ribs.iter().peekable(); + if let Some(Rib { kind: FnItemRibKind, .. }) = ribs.peek() { + // When declaring const parameters inside function signatures, the first rib + // is always a `FnItemRibKind`. In this case, we can skip it, to avoid it + // (spuriously) conflicting with the const param. + ribs.next(); + } + for rib in ribs { + match rib.kind { + ItemRibKind | FnItemRibKind => { + // This was an attempt to use a const parameter outside its scope. + if record_used { + resolve_error( + self, + span, + ResolutionError::GenericParamsFromOuterFunction(def), + ); + } + return Def::Err; } - return Def::Err; + _ => {} } } } diff --git a/src/test/ui/const-generics/struct-with-invalid-const-param.rs b/src/test/ui/const-generics/struct-with-invalid-const-param.rs new file mode 100644 index 00000000000..207b07bf695 --- /dev/null +++ b/src/test/ui/const-generics/struct-with-invalid-const-param.rs @@ -0,0 +1,6 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct S(C); //~ ERROR expected type, found const parameter + +fn main() {} diff --git a/src/test/ui/const-generics/struct-with-invalid-const-param.stderr b/src/test/ui/const-generics/struct-with-invalid-const-param.stderr new file mode 100644 index 00000000000..561464b21cc --- /dev/null +++ b/src/test/ui/const-generics/struct-with-invalid-const-param.stderr @@ -0,0 +1,15 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/struct-with-invalid-const-param.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0573]: expected type, found const parameter `C` + --> $DIR/struct-with-invalid-const-param.rs:4:23 + | +LL | struct S(C); + | ^ help: a struct with a similar name exists: `S` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0573`.