From eb0afe1845c970f6dd16bc53fa7f3464ee76daff Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 30 May 2019 23:43:04 +0100 Subject: [PATCH 01/14] Add more information in ConstEvalFailure error --- src/librustc/traits/error_reporting.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index a29b173880a08..95312d55b3be1 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -914,8 +914,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } // already reported in the query - ConstEvalFailure(_) => { - self.tcx.sess.delay_span_bug(span, "constant in type had an ignored error"); + ConstEvalFailure(err) => { + self.tcx.sess.delay_span_bug( + span, + &format!("constant in type had an ignored error: {:?}", err), + ); return; } From 7e92607f5a622e6fd9b32492a70217762cb709c4 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 30 May 2019 23:44:28 +0100 Subject: [PATCH 02/14] Fix unwrapping usize issue in HasMutInterior --- src/librustc_mir/transform/qualify_consts.rs | 5 +++-- .../mut-ref-const-param-array.rs | 19 +++++++++++++++++++ .../mut-ref-const-param-array.stderr | 6 ++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/const-generics/mut-ref-const-param-array.rs create mode 100644 src/test/ui/const-generics/mut-ref-const-param-array.stderr diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index a416792101f73..fe94181047fcd 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -316,8 +316,9 @@ impl Qualif for HasMutInterior { } else if let ty::Array(_, len) = ty.sty { // FIXME(eddyb) the `cx.mode == Mode::Fn` condition // seems unnecessary, given that this is merely a ZST. - if !(len.unwrap_usize(cx.tcx) == 0 && cx.mode == Mode::Fn) { - return true; + match len.assert_usize(cx.tcx) { + Some(0) if cx.mode == Mode::Fn => {}, + _ => return true, } } else { return true; diff --git a/src/test/ui/const-generics/mut-ref-const-param-array.rs b/src/test/ui/const-generics/mut-ref-const-param-array.rs new file mode 100644 index 0000000000000..f930fb8796325 --- /dev/null +++ b/src/test/ui/const-generics/mut-ref-const-param-array.rs @@ -0,0 +1,19 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +use std::ops::AddAssign; + +fn inc(v: &mut [T; N]) -> &mut [T; N] { + for x in v.iter_mut() { + *x += x.clone(); + } + v +} + +fn main() { + let mut v = [1, 2, 3]; + inc(&mut v); + assert_eq!(v, [2, 4, 6]); +} diff --git a/src/test/ui/const-generics/mut-ref-const-param-array.stderr b/src/test/ui/const-generics/mut-ref-const-param-array.stderr new file mode 100644 index 0000000000000..261d3578a11ac --- /dev/null +++ b/src/test/ui/const-generics/mut-ref-const-param-array.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/mut-ref-const-param-array.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + From 8e595f561045756d33e99d4a1d418d4da504d31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 31 May 2019 22:19:30 -0700 Subject: [PATCH 03/14] Make generics always have a valid span --- src/librustc/hir/map/mod.rs | 4 --- src/librustc_typeck/check/compare_method.rs | 4 +-- src/libsyntax/parse/parser.rs | 25 ++++++++++--------- ...regions-bound-missing-bound-in-impl.stderr | 4 +-- ...type-arg-mismatch-due-to-impl-trait.stderr | 4 +-- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index fd42c6f469e1e..cbdcf9d3918b5 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -628,10 +628,6 @@ impl<'hir> Map<'hir> { }) } - pub fn get_generics_span(&self, id: DefId) -> Option { - self.get_generics(id).map(|generics| generics.span).filter(|sp| *sp != DUMMY_SP) - } - /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. pub fn find(&self, id: NodeId) -> Option> { let hir_id = self.node_to_hir_id(id); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 1165890fe6432..cc074b64cc01c 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -385,7 +385,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // the moment, give a kind of vague error message. if trait_params != impl_params { let def_span = tcx.sess.source_map().def_span(span); - let span = tcx.hir().get_generics_span(impl_m.def_id).unwrap_or(def_span); + let span = tcx.hir().get_generics(impl_m.def_id).map(|g| g.span).unwrap_or(def_span); let mut err = struct_span_err!( tcx.sess, span, @@ -396,7 +396,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, err.span_label(span, "lifetimes do not match method in trait"); if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) { let def_sp = tcx.sess.source_map().def_span(sp); - let sp = tcx.hir().get_generics_span(trait_m.def_id).unwrap_or(def_sp); + let sp = tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp); err.span_label(sp, "lifetimes in impl do not match this method in trait"); } err.emit(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 746e9cad4962c..36460e75d879e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5050,21 +5050,22 @@ impl<'a> Parser<'a> { /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { let span_lo = self.span; - if self.eat_lt() { + let (params, span) = if self.eat_lt() { let params = self.parse_generic_params()?; self.expect_gt()?; - Ok(ast::Generics { - params, - where_clause: WhereClause { - id: ast::DUMMY_NODE_ID, - predicates: Vec::new(), - span: DUMMY_SP, - }, - span: span_lo.to(self.prev_span), - }) + (params, span_lo.to(self.prev_span)) } else { - Ok(ast::Generics::default()) - } + (vec![], self.prev_span.between(self.span)) + }; + Ok(ast::Generics { + params, + where_clause: WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: Vec::new(), + span: DUMMY_SP, + }, + span, + }) } /// Parses generic args (within a path segment) with recovery for extra leading angle brackets. diff --git a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr index cc6d5c55bd58f..4c7c0d1a0dfa5 100644 --- a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr +++ b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr @@ -36,13 +36,13 @@ LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d | ^^ error[E0195]: lifetime parameters or bounds on method `wrong_bound2` do not match the trait declaration - --> $DIR/regions-bound-missing-bound-in-impl.rs:41:5 + --> $DIR/regions-bound-missing-bound-in-impl.rs:41:20 | LL | fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>); | ---------------- lifetimes in impl do not match this method in trait ... LL | fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait + | ^ lifetimes do not match method in trait error[E0276]: impl has stricter requirements than trait --> $DIR/regions-bound-missing-bound-in-impl.rs:48:5 diff --git a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr index af7fdde9a8ed1..3f1b10fab27f3 100644 --- a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr +++ b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr @@ -1,11 +1,11 @@ error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:5 + --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:11 | LL | fn foo(&self, t: Self::T); | -------------------------- expected 0 type parameters ... LL | fn foo(&self, t: impl Clone) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found 1 type parameter + | ^ found 1 type parameter error: aborting due to previous error From e71f4665f6cf2e200a40eaed12bcaa603dfbc08f Mon Sep 17 00:00:00 2001 From: David Wood Date: Sat, 1 Jun 2019 11:37:11 +0100 Subject: [PATCH 04/14] codegen: change `$6d$` to `$u6d$` This changes a mistake introduced in #61195 where the mangling workaround used was incorrect. --- src/librustc_codegen_utils/symbol_names/legacy.rs | 2 +- src/test/ui/symbol-names/issue-60925.legacy.stderr | 6 +++--- src/test/ui/symbol-names/issue-60925.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc_codegen_utils/symbol_names/legacy.rs b/src/librustc_codegen_utils/symbol_names/legacy.rs index 53682b9bdc2c8..6eaa22afce19a 100644 --- a/src/librustc_codegen_utils/symbol_names/legacy.rs +++ b/src/librustc_codegen_utils/symbol_names/legacy.rs @@ -440,7 +440,7 @@ impl fmt::Write for SymbolPrinter<'_, '_> { '-' | ':' => self.path.temp_buf.push('.'), // Avoid crashing LLVM in certain (LTO-related) situations, see #60925. - 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$6d$"), + 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$u6d$"), // These are legal symbols 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.path.temp_buf.push(c), diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr index 0bbe424aa025b..7fcd2ede31b69 100644 --- a/src/test/ui/symbol-names/issue-60925.legacy.stderr +++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr @@ -1,16 +1,16 @@ -error: symbol-name(_ZN11issue_609253foo36Foo$LT$issue_60925..llv$6d$..Foo$GT$3foo17h059a991a004536adE) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h059a991a004536adE) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling-alt(issue_60925::foo::Foo $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/issue-60925.rs b/src/test/ui/symbol-names/issue-60925.rs index 09d68eebb950e..89de15cc0f3e4 100644 --- a/src/test/ui/symbol-names/issue-60925.rs +++ b/src/test/ui/symbol-names/issue-60925.rs @@ -19,9 +19,9 @@ mod foo { impl Foo<::llvm::Foo> { #[rustc_symbol_name] - //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo36Foo$LT$issue_60925..llv$6d$..Foo$GT$3foo - //[legacy]~| ERROR demangling(issue_60925::foo::Foo>::foo) //[v0]~| ERROR demangling-alt(>::foo) From 28859472f71cea497dbea12523e69dc23daaff76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 1 Jun 2019 10:35:31 -0700 Subject: [PATCH 05/14] Point at individual type arguments on arg count mismatch --- src/librustc/hir/mod.rs | 10 +++- src/librustc_typeck/check/compare_method.rs | 56 ++++++++++++------- src/test/ui/error-codes/E0049.rs | 10 ++++ src/test/ui/error-codes/E0049.stderr | 19 +++++-- src/test/ui/issues/issue-36708.stderr | 4 +- ...type-arg-mismatch-due-to-impl-trait.stderr | 6 +- 6 files changed, 76 insertions(+), 29 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f03a8ddc90825..d9c98d60b958d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -16,7 +16,7 @@ use crate::util::nodemap::{NodeMap, FxHashSet}; use crate::mir::mono::Linkage; use errors::FatalError; -use syntax_pos::{Span, DUMMY_SP, symbol::InternedString}; +use syntax_pos::{Span, DUMMY_SP, symbol::InternedString, MultiSpan}; use syntax::source_map::Spanned; use rustc_target::spec::abi::Abi; use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, AsmDialect}; @@ -624,6 +624,14 @@ impl Generics { } None } + + pub fn spans(&self) -> MultiSpan { + if self.params.is_empty() { + self.span.into() + } else { + self.params.iter().map(|p| p.span).collect::>().into() + } + } } /// Synthetic type parameters are converted to another form during lowering; this allows diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index cc074b64cc01c..742f6ed5215cb 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -583,7 +583,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn compare_number_of_generics<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_: &ty::AssocItem, - impl_span: Span, + _impl_span: Span, trait_: &ty::AssocItem, trait_span: Option, ) -> Result<(), ErrorReported> { @@ -600,17 +600,25 @@ fn compare_number_of_generics<'a, 'tcx>( if impl_count != trait_count { err_occurred = true; - let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap(); - let impl_item = tcx.hir().expect_impl_item(impl_hir_id); - let span = if impl_item.generics.params.is_empty() - || impl_item.generics.span.is_dummy() { // argument position impl Trait (#55374) - impl_span + let trait_spans = if let Some(trait_hir_id) = tcx.hir().as_local_hir_id(trait_.def_id) { + let trait_item = tcx.hir().expect_trait_item(trait_hir_id); + Some(if trait_item.generics.params.is_empty() { + vec![trait_item.generics.span] + } else { + trait_item.generics.params.iter().map(|p| p.span).collect::>() + }) } else { - impl_item.generics.span + trait_span.map(|s| vec![s]) }; + let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap(); + let impl_item = tcx.hir().expect_impl_item(impl_hir_id); + // let span = impl_item.generics.span; + let spans = impl_item.generics.spans(); + let span = spans.primary_span(); + let mut err = tcx.sess.struct_span_err_with_code( - span, + spans, &format!( "method `{}` has {} {kind} parameter{} but its trait \ declaration has {} {kind} parameter{}", @@ -626,22 +634,32 @@ fn compare_number_of_generics<'a, 'tcx>( let mut suffix = None; - if let Some(span) = trait_span { - err.span_label( - span, - format!("expected {} {} parameter{}", trait_count, kind, - if trait_count != 1 { "s" } else { "" }) - ); + if let Some(spans) = trait_spans { + let mut spans = spans.iter(); + if let Some(span) = spans.next() { + err.span_label(*span, format!( + "expected {} {} parameter{}", + trait_count, + kind, + if trait_count != 1 { "s" } else { "" }, + )); + } + for span in spans { + err.span_label(*span, ""); + } } else { suffix = Some(format!(", expected {}", trait_count)); } - err.span_label( - span, - format!("found {} {} parameter{}{}", impl_count, kind, + if let Some(span) = span { + err.span_label(span, format!( + "found {} {} parameter{}{}", + impl_count, + kind, if impl_count != 1 { "s" } else { "" }, - suffix.unwrap_or_else(|| String::new())), - ); + suffix.unwrap_or_else(|| String::new()), + )); + } err.emit(); } diff --git a/src/test/ui/error-codes/E0049.rs b/src/test/ui/error-codes/E0049.rs index c141f8a882820..3dd910019bfd0 100644 --- a/src/test/ui/error-codes/E0049.rs +++ b/src/test/ui/error-codes/E0049.rs @@ -8,5 +8,15 @@ impl Foo for Bar { fn foo(x: bool) -> Self { Bar } //~ ERROR E0049 } +trait Fuzz { + fn fuzz(x: A, y: B) -> Self; +} + +struct Baz; + +impl Fuzz for Baz { + fn fuzz(x: bool, y: bool) -> Self { Baz } //~ ERROR E0049 +} + fn main() { } diff --git a/src/test/ui/error-codes/E0049.stderr b/src/test/ui/error-codes/E0049.stderr index 7e9b9e8efb9a8..c0cd31faa90d6 100644 --- a/src/test/ui/error-codes/E0049.stderr +++ b/src/test/ui/error-codes/E0049.stderr @@ -1,12 +1,23 @@ error[E0049]: method `foo` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/E0049.rs:8:5 + --> $DIR/E0049.rs:8:11 | LL | fn foo(x: T) -> Self; - | --------------------------------- expected 1 type parameter + | - expected 1 type parameter ... LL | fn foo(x: bool) -> Self { Bar } - | ^^^^^^^^^^^^^^^^^^^^^^^ found 0 type parameters + | ^ found 0 type parameters -error: aborting due to previous error +error[E0049]: method `fuzz` has 0 type parameters but its trait declaration has 2 type parameters + --> $DIR/E0049.rs:18:12 + | +LL | fn fuzz(x: A, y: B) -> Self; + | - - + | | + | expected 2 type parameters +... +LL | fn fuzz(x: bool, y: bool) -> Self { Baz } + | ^ found 0 type parameters + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0049`. diff --git a/src/test/ui/issues/issue-36708.stderr b/src/test/ui/issues/issue-36708.stderr index 835094c4fdc5e..140f19f1ff774 100644 --- a/src/test/ui/issues/issue-36708.stderr +++ b/src/test/ui/issues/issue-36708.stderr @@ -1,8 +1,8 @@ error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/issue-36708.rs:8:11 + --> $DIR/issue-36708.rs:8:12 | LL | fn foo() {} - | ^^^ found 1 type parameter, expected 0 + | ^ found 1 type parameter, expected 0 error: aborting due to previous error diff --git a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr index 3f1b10fab27f3..953284735553c 100644 --- a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr +++ b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr @@ -1,11 +1,11 @@ error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:11 + --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:22 | LL | fn foo(&self, t: Self::T); - | -------------------------- expected 0 type parameters + | - expected 0 type parameters ... LL | fn foo(&self, t: impl Clone) {} - | ^ found 1 type parameter + | ^^^^^^^^^^ found 1 type parameter error: aborting due to previous error From 0754c8461182252f5f86eca09845ece04b533696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 1 Jun 2019 11:33:38 -0700 Subject: [PATCH 06/14] Explain that `impl Trait` introduces an implicit type argument --- src/librustc_typeck/check/compare_method.rs | 35 +++++++++++++++---- .../type-arg-mismatch-due-to-impl-trait.rs | 1 + ...type-arg-mismatch-due-to-impl-trait.stderr | 5 ++- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 742f6ed5215cb..fb83f877ccce2 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -600,20 +600,37 @@ fn compare_number_of_generics<'a, 'tcx>( if impl_count != trait_count { err_occurred = true; - let trait_spans = if let Some(trait_hir_id) = tcx.hir().as_local_hir_id(trait_.def_id) { + let ( + trait_spans, + impl_trait_spans, + ) = if let Some(trait_hir_id) = tcx.hir().as_local_hir_id(trait_.def_id) { let trait_item = tcx.hir().expect_trait_item(trait_hir_id); - Some(if trait_item.generics.params.is_empty() { - vec![trait_item.generics.span] + if trait_item.generics.params.is_empty() { + (Some(vec![trait_item.generics.span]), vec![]) } else { - trait_item.generics.params.iter().map(|p| p.span).collect::>() - }) + let arg_spans: Vec = trait_item.generics.params.iter() + .map(|p| p.span) + .collect(); + let impl_trait_spans: Vec = trait_item.generics.params.iter() + .filter_map(|p| if !trait_item.generics.span.overlaps(p.span) { + Some(p.span) + } else { + None + }).collect(); + (Some(arg_spans), impl_trait_spans) + } } else { - trait_span.map(|s| vec![s]) + (trait_span.map(|s| vec![s]), vec![]) }; let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap(); let impl_item = tcx.hir().expect_impl_item(impl_hir_id); - // let span = impl_item.generics.span; + let impl_item_impl_trait_spans: Vec = impl_item.generics.params.iter() + .filter_map(|p| if !impl_item.generics.span.overlaps(p.span) { + Some(p.span) + } else { + None + }).collect(); let spans = impl_item.generics.spans(); let span = spans.primary_span(); @@ -661,6 +678,10 @@ fn compare_number_of_generics<'a, 'tcx>( )); } + for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) { + err.span_label(*span, "`impl Trait` introduces an implicit type parameter"); + } + err.emit(); } } diff --git a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs index 4a71932d1df18..ecfa5c69e2f03 100644 --- a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs +++ b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs @@ -10,6 +10,7 @@ impl Foo for u32 { fn foo(&self, t: impl Clone) {} //~^ ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters //~| NOTE found 1 type parameter +//~| NOTE `impl Trait` introduces an implicit type parameter } fn main() {} diff --git a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr index 953284735553c..30322f88cca42 100644 --- a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr +++ b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr @@ -5,7 +5,10 @@ LL | fn foo(&self, t: Self::T); | - expected 0 type parameters ... LL | fn foo(&self, t: impl Clone) {} - | ^^^^^^^^^^ found 1 type parameter + | ^^^^^^^^^^ + | | + | found 1 type parameter + | `impl Trait` introduces an implicit type parameter error: aborting due to previous error From 3d0eae18c6aca881a3daf72110386b805d1e1dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 1 Jun 2019 13:34:53 -0700 Subject: [PATCH 07/14] Tweak wording when encountering `fn` call in pattern --- src/librustc_typeck/check/_match.rs | 14 ++++++++++++-- src/test/ui/fn-in-pat.stderr | 4 +++- src/test/ui/issues/issue-55587.stderr | 4 +++- src/test/ui/match/match-fn-call.stderr | 8 ++++++-- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 5cd95a9d834c4..26af5bd656061 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -1080,8 +1080,18 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let msg = format!("expected tuple struct/variant, found {} `{}`", res.descr(), hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false))); - struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg) - .span_label(pat.span, "not a tuple variant or struct").emit(); + let mut err = struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg); + match (res, &pat.node) { + (Res::Def(DefKind::Fn, _), _) | (Res::Def(DefKind::Method, _), _) => { + err.span_label(pat.span, "`fn` calls are not allowed in patterns"); + err.help("for more information, visit \ + https://doc.rust-lang.org/book/ch18-00-patterns.html"); + } + _ => { + err.span_label(pat.span, "not a tuple variant or struct"); + } + } + err.emit(); on_error(); }; diff --git a/src/test/ui/fn-in-pat.stderr b/src/test/ui/fn-in-pat.stderr index eee97fe9587c2..0bb24365ef42b 100644 --- a/src/test/ui/fn-in-pat.stderr +++ b/src/test/ui/fn-in-pat.stderr @@ -2,7 +2,9 @@ error[E0164]: expected tuple struct/variant, found method `::new` --> $DIR/fn-in-pat.rs:11:9 | LL | A::new() => (), - | ^^^^^^^^ not a tuple variant or struct + | ^^^^^^^^ `fn` calls are not allowed in patterns + | + = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html error: aborting due to previous error diff --git a/src/test/ui/issues/issue-55587.stderr b/src/test/ui/issues/issue-55587.stderr index 1334f249256d6..3928a3cd53201 100644 --- a/src/test/ui/issues/issue-55587.stderr +++ b/src/test/ui/issues/issue-55587.stderr @@ -2,7 +2,9 @@ error[E0164]: expected tuple struct/variant, found method `::new` --> $DIR/issue-55587.rs:4:9 | LL | let Path::new(); - | ^^^^^^^^^^^ not a tuple variant or struct + | ^^^^^^^^^^^ `fn` calls are not allowed in patterns + | + = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html error: aborting due to previous error diff --git a/src/test/ui/match/match-fn-call.stderr b/src/test/ui/match/match-fn-call.stderr index 4e24621706bdb..bd918428351b9 100644 --- a/src/test/ui/match/match-fn-call.stderr +++ b/src/test/ui/match/match-fn-call.stderr @@ -2,13 +2,17 @@ error[E0164]: expected tuple struct/variant, found method `::new` --> $DIR/match-fn-call.rs:6:9 | LL | Path::new("foo") => println!("foo"), - | ^^^^^^^^^^^^^^^^ not a tuple variant or struct + | ^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns + | + = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html error[E0164]: expected tuple struct/variant, found method `::new` --> $DIR/match-fn-call.rs:8:9 | LL | Path::new("bar") => println!("bar"), - | ^^^^^^^^^^^^^^^^ not a tuple variant or struct + | ^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns + | + = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html error: aborting due to 2 previous errors From c2b663c6669e68f00644b8402ebd177c0ba925b8 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 31 May 2019 00:12:24 +0100 Subject: [PATCH 08/14] Fix unwrapping usize issue with transparent MaybeUnit array wrapper --- src/librustc/ty/layout.rs | 2 +- .../transparent-maybeunit-array-wrapper.rs | 11 +++++++++++ .../transparent-maybeunit-array-wrapper.stderr | 6 ++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs create mode 100644 src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 6d7b0926c7ae2..6415122dd3905 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -549,8 +549,8 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } } + let count = count.assert_usize(tcx).ok_or(LayoutError::Unknown(ty))?; let element = self.layout_of(element)?; - let count = count.unwrap_usize(tcx); let size = element.size.checked_mul(count, dl) .ok_or(LayoutError::SizeOverflow(ty))?; diff --git a/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs new file mode 100644 index 0000000000000..794048174f903 --- /dev/null +++ b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs @@ -0,0 +1,11 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +use std::mem::MaybeUninit; + +#[repr(transparent)] +pub struct MaybeUninitWrapper(MaybeUninit<[u64; N]>); + +fn main() {} diff --git a/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr new file mode 100644 index 0000000000000..661bbd113bc0d --- /dev/null +++ b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/transparent-maybeunit-array-wrapper.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + From 21551359a5e5272b5a71a69a9115fdd83379fcb7 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 31 May 2019 00:26:30 +0100 Subject: [PATCH 09/14] Use `assert_usize` instead of `unwrap_usize` in several places --- src/librustc_codegen_llvm/debuginfo/metadata.rs | 4 +--- src/librustc_mir/borrow_check/places_conflict.rs | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index b000628a3f706..42bd790ca2e9c 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -342,9 +342,7 @@ fn fixed_vec_metadata( let (size, align) = cx.size_and_align_of(array_or_slice_type); let upper_bound = match array_or_slice_type.sty { - ty::Array(_, len) => { - len.unwrap_usize(cx.tcx) as c_longlong - } + ty::Array(_, len) => len.unwrap_usize(cx.tcx) as c_longlong, _ => -1 }; diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 74da3f96653e4..8aa27eef72a5e 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -332,8 +332,8 @@ fn place_base_conflict<'a, 'gcx: 'tcx, 'tcx>( }, (StaticKind::Promoted(promoted_1), StaticKind::Promoted(promoted_2)) => { if promoted_1 == promoted_2 { - if let ty::Array(_, size) = s1.ty.sty { - if size.unwrap_usize(tcx) == 0 { + if let ty::Array(_, len) = s1.ty.sty { + if let Some(0) = len.assert_usize(tcx) { // Ignore conflicts with promoted [T; 0]. debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED"); return Overlap::Disjoint; From 5a2410a07c8b151cd518792f41fce3341af004cf Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 31 May 2019 22:27:26 +0100 Subject: [PATCH 10/14] Add error for pattern-matching on arrays without a fixed size --- src/librustc_typeck/check/_match.rs | 45 +++++++++++++++++----------- src/librustc_typeck/error_codes.rs | 32 ++++++++++++++++++++ src/test/ui/error-codes/E0730.rs | 11 +++++++ src/test/ui/error-codes/E0730.stderr | 15 ++++++++++ 4 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/error-codes/E0730.rs create mode 100644 src/test/ui/error-codes/E0730.stderr diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 5cd95a9d834c4..64e2eedd721ef 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -400,27 +400,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_ty = self.structurally_resolved_type(pat.span, expected); let (inner_ty, slice_ty) = match expected_ty.sty { ty::Array(inner_ty, size) => { - let size = size.unwrap_usize(tcx); - let min_len = before.len() as u64 + after.len() as u64; - if slice.is_none() { - if min_len != size { - struct_span_err!( - tcx.sess, pat.span, E0527, - "pattern requires {} elements but array has {}", - min_len, size) - .span_label(pat.span, format!("expected {} elements", size)) + if let Some(size) = size.assert_usize(tcx) { + let min_len = before.len() as u64 + after.len() as u64; + if slice.is_none() { + if min_len != size { + struct_span_err!( + tcx.sess, pat.span, E0527, + "pattern requires {} elements but array has {}", + min_len, size) + .span_label(pat.span, format!("expected {} elements", size)) + .emit(); + } + (inner_ty, tcx.types.err) + } else if let Some(rest) = size.checked_sub(min_len) { + (inner_ty, tcx.mk_array(inner_ty, rest)) + } else { + struct_span_err!(tcx.sess, pat.span, E0528, + "pattern requires at least {} elements but array has {}", + min_len, size) + .span_label(pat.span, + format!("pattern cannot match array of {} elements", size)) .emit(); + (inner_ty, tcx.types.err) } - (inner_ty, tcx.types.err) - } else if let Some(rest) = size.checked_sub(min_len) { - (inner_ty, tcx.mk_array(inner_ty, rest)) } else { - struct_span_err!(tcx.sess, pat.span, E0528, - "pattern requires at least {} elements but array has {}", - min_len, size) - .span_label(pat.span, - format!("pattern cannot match array of {} elements", size)) - .emit(); + struct_span_err!( + tcx.sess, + pat.span, + E0730, + "cannot pattern-match on an array without a fixed length", + ).emit(); (inner_ty, tcx.types.err) } } diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs index 6dd3c0113cdcd..b5a50f4387581 100644 --- a/src/librustc_typeck/error_codes.rs +++ b/src/librustc_typeck/error_codes.rs @@ -4648,6 +4648,38 @@ fn make_recursive_type() -> impl Sized { ``` "##, +E0730: r##" +An array without a fixed length was pattern-matched. + +Example of erroneous code: + +```compile_fail,E0730 +#![feature(const_generics)] + +fn is_123(x: [u32; N]) -> bool { + match x { + [1, 2, 3] => true, // error: cannot pattern-match on an + // array without a fixed length + _ => false + } +} +``` + +Ensure that the pattern is consistent with the size of the matched +array. Additional elements can be matched with `..`: + +``` +#![feature(slice_patterns)] + +let r = &[1, 2, 3, 4]; +match r { + &[a, b, ..] => { // ok! + println!("a={}, b={}", a, b); + } +} +``` +"##, + } register_diagnostics! { diff --git a/src/test/ui/error-codes/E0730.rs b/src/test/ui/error-codes/E0730.rs new file mode 100644 index 0000000000000..e5048d6e6e320 --- /dev/null +++ b/src/test/ui/error-codes/E0730.rs @@ -0,0 +1,11 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn is_123(x: [u32; N]) -> bool { + match x { + [1, 2, 3] => true, //~ ERROR cannot pattern-match on an array without a fixed length + _ => false + } +} + +fn main() {} diff --git a/src/test/ui/error-codes/E0730.stderr b/src/test/ui/error-codes/E0730.stderr new file mode 100644 index 0000000000000..f9281262bb71b --- /dev/null +++ b/src/test/ui/error-codes/E0730.stderr @@ -0,0 +1,15 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/E0730.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0730]: cannot pattern-match on an array without a fixed length + --> $DIR/E0730.rs:6:9 + | +LL | [1, 2, 3] => true, + | ^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0730`. From e82cd9528c127aff90d58a25573b9aeb43616c2b Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 1 Jun 2019 11:57:22 +0100 Subject: [PATCH 11/14] Add regression test for #61422 --- src/test/ui/const-generics/issue-61422.rs | 15 +++++++++++++++ src/test/ui/const-generics/issue-61422.stderr | 6 ++++++ 2 files changed, 21 insertions(+) create mode 100644 src/test/ui/const-generics/issue-61422.rs create mode 100644 src/test/ui/const-generics/issue-61422.stderr diff --git a/src/test/ui/const-generics/issue-61422.rs b/src/test/ui/const-generics/issue-61422.rs new file mode 100644 index 0000000000000..3ccf38e561977 --- /dev/null +++ b/src/test/ui/const-generics/issue-61422.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +use std::mem; + +fn foo() { + let arr: [u8; SIZE] = unsafe { + let mut array: [u8; SIZE] = mem::uninitialized(); + array + }; +} + +fn main() {} diff --git a/src/test/ui/const-generics/issue-61422.stderr b/src/test/ui/const-generics/issue-61422.stderr new file mode 100644 index 0000000000000..4cb76ec4fe18c --- /dev/null +++ b/src/test/ui/const-generics/issue-61422.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-61422.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + From 31918d6eef4d5c6459fc4e16e4ddedf9d8ab698d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 1 Jun 2019 15:39:12 -0700 Subject: [PATCH 12/14] review comments: use param kind type to identify impl Trait --- src/librustc_typeck/check/compare_method.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index fb83f877ccce2..b4548ac70911e 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -612,10 +612,11 @@ fn compare_number_of_generics<'a, 'tcx>( .map(|p| p.span) .collect(); let impl_trait_spans: Vec = trait_item.generics.params.iter() - .filter_map(|p| if !trait_item.generics.span.overlaps(p.span) { - Some(p.span) - } else { - None + .filter_map(|p| match p.kind { + GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. + } => Some(p.span), + _ => None, }).collect(); (Some(arg_spans), impl_trait_spans) } @@ -626,10 +627,11 @@ fn compare_number_of_generics<'a, 'tcx>( let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap(); let impl_item = tcx.hir().expect_impl_item(impl_hir_id); let impl_item_impl_trait_spans: Vec = impl_item.generics.params.iter() - .filter_map(|p| if !impl_item.generics.span.overlaps(p.span) { - Some(p.span) - } else { - None + .filter_map(|p| match p.kind { + GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. + } => Some(p.span), + _ => None, }).collect(); let spans = impl_item.generics.spans(); let span = spans.primary_span(); From b3fdde431b18d237b9e4aa00071eff2f87b81648 Mon Sep 17 00:00:00 2001 From: 0x1793d1 <2362128+0x1793d1@users.noreply.github.com> Date: Sun, 2 Jun 2019 10:23:33 +0200 Subject: [PATCH 13/14] Fix missing semicolon in doc A semicolon is missing in the examples of compile_error. Macros that expand to items must be delimited with braces or followed by a semicolon. --- src/libstd/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 9af7bba97aa58..ef7179f0b6f90 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -405,7 +405,7 @@ mod builtin { /// /// ```compile_fail /// #[cfg(not(any(feature = "foo", feature = "bar")))] - /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate.") + /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate."); /// ``` /// /// [`panic!`]: ../std/macro.panic.html From 95833989230bb8f34137738eb6345b7b65262683 Mon Sep 17 00:00:00 2001 From: Fabian Drinck Date: Sun, 2 Jun 2019 14:12:06 +0200 Subject: [PATCH 14/14] Fix typo in AsRef doc --- src/libcore/convert.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index a2796ad0cf0b0..6215bf5cd6572 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -129,7 +129,7 @@ pub const fn identity(x: T) -> T { x } /// # Examples /// /// By using trait bounds we can accept arguments of different types as long as they can be -/// converted a the specified type `T`. +/// converted to the specified type `T`. /// /// For example: By creating a generic function that takes an `AsRef` we express that we /// want to accept all references that can be converted to `&str` as an argument.