From 78f01eca3f4d6843125199578d3f2186655ddf62 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 14 Mar 2020 19:44:11 +0300 Subject: [PATCH] resolve: Prevent fresh bindings from shadowing ambiguity items Correctly treat const generic parameters in fresh binding disambiguation --- .../hair/pattern/check_match.rs | 3 ++ src/librustc_mir_build/hair/pattern/mod.rs | 7 +++- src/librustc_resolve/late.rs | 39 +++++++++++------- src/librustc_resolve/lib.rs | 7 ---- src/librustc_typeck/check/pat.rs | 3 +- src/test/ui/binding/ambiguity-item.rs | 18 ++++++++ src/test/ui/binding/ambiguity-item.stderr | 41 +++++++++++++++++++ src/test/ui/binding/const-param.rs | 12 ++++++ src/test/ui/binding/const-param.stderr | 17 ++++++++ 9 files changed, 123 insertions(+), 24 deletions(-) create mode 100644 src/test/ui/binding/ambiguity-item.rs create mode 100644 src/test/ui/binding/ambiguity-item.stderr create mode 100644 src/test/ui/binding/const-param.rs create mode 100644 src/test/ui/binding/const-param.stderr diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs index d0eefb2e4d14f..b817470b4c30f 100644 --- a/src/librustc_mir_build/hair/pattern/check_match.rs +++ b/src/librustc_mir_build/hair/pattern/check_match.rs @@ -87,6 +87,9 @@ impl PatCtxt<'_, '_> { PatternError::AssocConstInPattern(span) => { self.span_e0158(span, "associated consts cannot be referenced in patterns") } + PatternError::ConstParamInPattern(span) => { + self.span_e0158(span, "const parameters cannot be referenced in patterns") + } PatternError::FloatBug => { // FIXME(#31407) this is only necessary because float parsing is buggy ::rustc::mir::interpret::struct_error( diff --git a/src/librustc_mir_build/hair/pattern/mod.rs b/src/librustc_mir_build/hair/pattern/mod.rs index f58216fbb4e76..6786c35629308 100644 --- a/src/librustc_mir_build/hair/pattern/mod.rs +++ b/src/librustc_mir_build/hair/pattern/mod.rs @@ -31,6 +31,7 @@ use std::fmt; #[derive(Clone, Debug)] crate enum PatternError { AssocConstInPattern(Span), + ConstParamInPattern(Span), StaticInPattern(Span), FloatBug, NonConstPath(Span), @@ -727,7 +728,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { | Res::SelfCtor(..) => PatKind::Leaf { subpatterns }, _ => { - self.errors.push(PatternError::NonConstPath(span)); + let pattern_error = match res { + Res::Def(DefKind::ConstParam, _) => PatternError::ConstParamInPattern(span), + _ => PatternError::NonConstPath(span), + }; + self.errors.push(pattern_error); PatKind::Wild } }; diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 97f3ad72ee37f..30ba48f797007 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -1517,9 +1517,17 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ident: Ident, has_sub: bool, ) -> Option { - let binding = - self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span)?.item()?; - let res = binding.res(); + let ls_binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span)?; + let (res, binding) = match ls_binding { + LexicalScopeBinding::Item(binding) if binding.is_ambiguity() => { + // For ambiguous bindings we don't know all their definitions and cannot check + // whether they can be shadowed by fresh bindings or not, so force an error. + self.r.record_use(ident, ValueNS, binding, false); + return None; + } + LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)), + LexicalScopeBinding::Res(res) => (res, None), + }; // An immutable (no `mut`) by-value (no `ref`) binding pattern without // a sub pattern (no `@ $pat`) is syntactically ambiguous as it could @@ -1527,11 +1535,15 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not); match res { - Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::Def(DefKind::Const, _) + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) + | Res::Def(DefKind::Const, _) + | Res::Def(DefKind::ConstParam, _) if is_syntactic_ambiguity => { // Disambiguate in favor of a unit struct/variant or constant pattern. - self.r.record_use(ident, ValueNS, binding, false); + if let Some(binding) = binding { + self.r.record_use(ident, ValueNS, binding, false); + } Some(res) } Res::Def(DefKind::Ctor(..), _) @@ -1547,23 +1559,20 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ResolutionError::BindingShadowsSomethingUnacceptable( pat_src.descr(), ident.name, - binding, + binding.expect("no binding for a ctor or static"), ), ); None } - Res::Def(DefKind::Fn, _) | Res::Err => { + Res::Def(DefKind::Fn, _) | Res::Local(..) | Res::Err => { // These entities are explicitly allowed to be shadowed by fresh bindings. None } - res => { - span_bug!( - ident.span, - "unexpected resolution for an \ - identifier in pattern: {:?}", - res - ); - } + _ => span_bug!( + ident.span, + "unexpected resolution for an identifier in pattern: {:?}", + res + ), } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 948b86225f38b..37a800a0b7bdb 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -323,13 +323,6 @@ enum LexicalScopeBinding<'a> { } impl<'a> LexicalScopeBinding<'a> { - fn item(self) -> Option<&'a NameBinding<'a>> { - match self { - LexicalScopeBinding::Item(binding) => Some(binding), - _ => None, - } - } - fn res(self) -> Res { match self { LexicalScopeBinding::Item(binding) => binding.res(), diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 60132dde9caec..fabf3dd1153b7 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -716,7 +716,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::SelfCtor(..) | Res::Def(DefKind::Const, _) - | Res::Def(DefKind::AssocConst, _) => {} // OK + | Res::Def(DefKind::AssocConst, _) + | Res::Def(DefKind::ConstParam, _) => {} // OK _ => bug!("unexpected pattern resolution: {:?}", res), } diff --git a/src/test/ui/binding/ambiguity-item.rs b/src/test/ui/binding/ambiguity-item.rs new file mode 100644 index 0000000000000..10613cc616413 --- /dev/null +++ b/src/test/ui/binding/ambiguity-item.rs @@ -0,0 +1,18 @@ +// Identifier pattern referring to an ambiguity item is an error (issue #46079). + +mod m { + pub fn f() {} +} +use m::*; + +mod n { + pub fn f() {} +} +use n::*; // OK, no conflict with `use m::*;` + +fn main() { + let v = f; //~ ERROR `f` is ambiguous + match v { + f => {} //~ ERROR `f` is ambiguous + } +} diff --git a/src/test/ui/binding/ambiguity-item.stderr b/src/test/ui/binding/ambiguity-item.stderr new file mode 100644 index 0000000000000..615193c0d02db --- /dev/null +++ b/src/test/ui/binding/ambiguity-item.stderr @@ -0,0 +1,41 @@ +error[E0659]: `f` is ambiguous (glob import vs glob import in the same module) + --> $DIR/ambiguity-item.rs:14:13 + | +LL | let v = f; + | ^ ambiguous name + | +note: `f` could refer to the function imported here + --> $DIR/ambiguity-item.rs:6:5 + | +LL | use m::*; + | ^^^^ + = help: consider adding an explicit import of `f` to disambiguate +note: `f` could also refer to the function imported here + --> $DIR/ambiguity-item.rs:11:5 + | +LL | use n::*; // OK, no conflict with `use m::*;` + | ^^^^ + = help: consider adding an explicit import of `f` to disambiguate + +error[E0659]: `f` is ambiguous (glob import vs glob import in the same module) + --> $DIR/ambiguity-item.rs:16:9 + | +LL | f => {} + | ^ ambiguous name + | +note: `f` could refer to the function imported here + --> $DIR/ambiguity-item.rs:6:5 + | +LL | use m::*; + | ^^^^ + = help: consider adding an explicit import of `f` to disambiguate +note: `f` could also refer to the function imported here + --> $DIR/ambiguity-item.rs:11:5 + | +LL | use n::*; // OK, no conflict with `use m::*;` + | ^^^^ + = help: consider adding an explicit import of `f` to disambiguate + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/binding/const-param.rs b/src/test/ui/binding/const-param.rs new file mode 100644 index 0000000000000..3c7f4d071f694 --- /dev/null +++ b/src/test/ui/binding/const-param.rs @@ -0,0 +1,12 @@ +// Identifier pattern referring to a const generic parameter is an error (issue #68853). + +#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete + +fn check() { + match 1 { + N => {} //~ ERROR const parameters cannot be referenced in patterns + _ => {} + } +} + +fn main() {} diff --git a/src/test/ui/binding/const-param.stderr b/src/test/ui/binding/const-param.stderr new file mode 100644 index 0000000000000..25b1c75c9a004 --- /dev/null +++ b/src/test/ui/binding/const-param.stderr @@ -0,0 +1,17 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-param.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0158]: const parameters cannot be referenced in patterns + --> $DIR/const-param.rs:7:9 + | +LL | N => {} + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0158`.