Skip to content

Commit

Permalink
Rollup merge of #85478 - FabianWolff:issue-85348, r=petrochenkov
Browse files Browse the repository at this point in the history
Disallow shadowing const parameters

This pull request fixes #85348. Trying to shadow a `const` parameter as follows:
```rust
fn foo<const N: i32>() {
    let N @ _ = 0;
}
```
currently causes an ICE. With my changes, I get:
```
error[E0530]: let bindings cannot shadow const parameters
 --> test.rs:2:9
  |
1 | fn foo<const N: i32>() {
  |              - the const parameter `N` is defined here
2 |     let N @ _ = 0;
  |         ^ cannot be named the same as a const parameter

error: aborting due to previous error
```
This is the same error you get when trying to shadow a constant:
```rust
const N: i32 = 0;
let N @ _ = 0;
```
```
error[E0530]: let bindings cannot shadow constants
 --> src/lib.rs:3:5
  |
2 | const N: i32 = 0;
  | ----------------- the constant `N` is defined here
3 | let N @ _ = 0;
  |     ^ cannot be named the same as a constant

error: aborting due to previous error
```
The reason for disallowing shadowing in both cases is described [here](#33118 (comment)) (the comment there only talks about constants, but the same reasoning applies to `const` parameters).
  • Loading branch information
Dylan-DPC authored May 26, 2021
2 parents 1969c2e + f749d88 commit 69c78a9
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 15 deletions.
23 changes: 14 additions & 9 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,24 +425,29 @@ impl<'a> Resolver<'a> {
}
err
}
ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
let res = binding.res();
let shadows_what = res.descr();
ResolutionError::BindingShadowsSomethingUnacceptable {
shadowing_binding_descr,
name,
participle,
article,
shadowed_binding_descr,
shadowed_binding_span,
} => {
let mut err = struct_span_err!(
self.session,
span,
E0530,
"{}s cannot shadow {}s",
what_binding,
shadows_what
shadowing_binding_descr,
shadowed_binding_descr,
);
err.span_label(
span,
format!("cannot be named the same as {} {}", res.article(), shadows_what),
format!("cannot be named the same as {} {}", article, shadowed_binding_descr),
);
let participle = if binding.is_import() { "imported" } else { "defined" };
let msg = format!("the {} `{}` is {} here", shadows_what, name, participle);
err.span_label(binding.span, msg);
let msg =
format!("the {} `{}` is {} here", shadowed_binding_descr, name, participle);
err.span_label(shadowed_binding_span, msg);
err
}
ResolutionError::ForwardDeclaredTyParam => {
Expand Down
30 changes: 25 additions & 5 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1763,13 +1763,33 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// to something unusable as a pattern (e.g., constructor function),
// but we still conservatively report an error, see
// issues/33118#issuecomment-233962221 for one reason why.
let binding = binding.expect("no binding for a ctor or static");
self.report_error(
ident.span,
ResolutionError::BindingShadowsSomethingUnacceptable(
pat_src.descr(),
ident.name,
binding.expect("no binding for a ctor or static"),
),
ResolutionError::BindingShadowsSomethingUnacceptable {
shadowing_binding_descr: pat_src.descr(),
name: ident.name,
participle: if binding.is_import() { "imported" } else { "defined" },
article: binding.res().article(),
shadowed_binding_descr: binding.res().descr(),
shadowed_binding_span: binding.span,
},
);
None
}
Res::Def(DefKind::ConstParam, def_id) => {
// Same as for DefKind::Const above, but here, `binding` is `None`, so we
// have to construct the error differently
self.report_error(
ident.span,
ResolutionError::BindingShadowsSomethingUnacceptable {
shadowing_binding_descr: pat_src.descr(),
name: ident.name,
participle: "defined",
article: res.article(),
shadowed_binding_descr: res.descr(),
shadowed_binding_span: self.r.opt_span(def_id).expect("const parameter defined outside of local crate"),
}
);
None
}
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,14 @@ enum ResolutionError<'a> {
/* current */ &'static str,
),
/// Error E0530: `X` bindings cannot shadow `Y`s.
BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>),
BindingShadowsSomethingUnacceptable {
shadowing_binding_descr: &'static str,
name: Symbol,
participle: &'static str,
article: &'static str,
shadowed_binding_descr: &'static str,
shadowed_binding_span: Span,
},
/// Error E0128: generic 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.
Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/resolve/issue-85348.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Checks whether shadowing a const parameter leads to an ICE (#85348).

impl<const N: usize> ArrayWindowsExample {
//~^ ERROR: cannot find type `ArrayWindowsExample` in this scope [E0412]
fn next() {
let mut N;
//~^ ERROR: let bindings cannot shadow const parameters [E0530]
//~| ERROR: type annotations needed [E0282]
}
}

fn main() {}
25 changes: 25 additions & 0 deletions src/test/ui/resolve/issue-85348.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
error[E0530]: let bindings cannot shadow const parameters
--> $DIR/issue-85348.rs:6:17
|
LL | impl<const N: usize> ArrayWindowsExample {
| - the const parameter `N` is defined here
...
LL | let mut N;
| ^ cannot be named the same as a const parameter

error[E0412]: cannot find type `ArrayWindowsExample` in this scope
--> $DIR/issue-85348.rs:3:22
|
LL | impl<const N: usize> ArrayWindowsExample {
| ^^^^^^^^^^^^^^^^^^^ not found in this scope

error[E0282]: type annotations needed
--> $DIR/issue-85348.rs:6:13
|
LL | let mut N;
| ^^^^^ consider giving `N` a type

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0282, E0412, E0530.
For more information about an error, try `rustc --explain E0282`.
20 changes: 20 additions & 0 deletions src/test/ui/resolve/shadow-const-param.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Checks that const parameters cannot be shadowed with fresh bindings
// even in syntactically unambiguous contexts. See
// https://github.com/rust-lang/rust/issues/33118#issuecomment-233962221

fn foo<const N: i32>(i: i32) -> bool {
match i {
N @ _ => true,
//~^ ERROR: match bindings cannot shadow const parameters [E0530]
}
}

fn bar<const N: i32>(i: i32) -> bool {
let N @ _ = 0;
//~^ ERROR: let bindings cannot shadow const parameters [E0530]
match i {
N @ _ => true,
}
}

fn main() {}
20 changes: 20 additions & 0 deletions src/test/ui/resolve/shadow-const-param.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0530]: match bindings cannot shadow const parameters
--> $DIR/shadow-const-param.rs:7:9
|
LL | fn foo<const N: i32>(i: i32) -> bool {
| - the const parameter `N` is defined here
LL | match i {
LL | N @ _ => true,
| ^ cannot be named the same as a const parameter

error[E0530]: let bindings cannot shadow const parameters
--> $DIR/shadow-const-param.rs:13:9
|
LL | fn bar<const N: i32>(i: i32) -> bool {
| - the const parameter `N` is defined here
LL | let N @ _ = 0;
| ^ cannot be named the same as a const parameter

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0530`.

0 comments on commit 69c78a9

Please sign in to comment.