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

Fix ICE with const generic param in struct #59355

Merged
merged 2 commits into from
Mar 24, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
44 changes: 27 additions & 17 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(_) =>
Expand Down Expand Up @@ -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.
varkor marked this conversation as resolved.
Show resolved Hide resolved
FnItemRibKind,

/// We passed through an item scope. Disallow upvars.
ItemRibKind,

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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(
Expand All @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you give an example of "spuriously conflicting with the const param"? Is there a test?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any function definition with a const generic parameter would conflict. E.g.

fn i32_identity<const X: i32>() -> i32 {
5
}

ribs.next();
}
for rib in ribs {
match rib.kind {
ItemRibKind | FnItemRibKind => {
varkor marked this conversation as resolved.
Show resolved Hide resolved
// 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;
_ => {}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/test/ui/const-generics/struct-with-invalid-const-param.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash

struct S<const C: u8>(C); //~ ERROR expected type, found const parameter

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/const-generics/struct-with-invalid-const-param.stderr
Original file line number Diff line number Diff line change
@@ -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<const C: u8>(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`.