From 127489a89636898bf40101e39faaf91f2f0a308f Mon Sep 17 00:00:00 2001 From: DarkEld3r Date: Tue, 9 Aug 2016 13:13:04 +0300 Subject: [PATCH 01/18] Update compiler error 0093 to use new error format --- src/librustc_typeck/check/intrinsic.rs | 7 +++++-- src/test/compile-fail/E0093.rs | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 8a53c59b4c7..33452b441ca 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -297,8 +297,11 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { } ref other => { - span_err!(tcx.sess, it.span, E0093, - "unrecognized intrinsic function: `{}`", *other); + struct_span_err!(tcx.sess, it.span, E0093, + "unrecognized intrinsic function: `{}`", + *other) + .span_label(it.span, &format!("unrecognized intrinsic")) + .emit(); return; } }; diff --git a/src/test/compile-fail/E0093.rs b/src/test/compile-fail/E0093.rs index 9b23f6d984e..fdc48455a67 100644 --- a/src/test/compile-fail/E0093.rs +++ b/src/test/compile-fail/E0093.rs @@ -10,7 +10,9 @@ #![feature(intrinsics)] extern "rust-intrinsic" { - fn foo(); //~ ERROR E0093 + fn foo(); + //~^ ERROR E0093 + //~| NOTE unrecognized intrinsic } fn main() { From 1cf9cafeb14c4e9b16727b10953da95c5c5b0b1d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 16 Aug 2016 17:07:55 -0500 Subject: [PATCH 02/18] add mips-uclibc targets These targets cover OpenWRT 15.05 devices, which use the soft float ABI and the uclibc library. None of the other built-in mips targets covered those devices (mips-gnu is hard float and glibc-based, mips-musl is musl-based). With this commit one can now build std for these devices using these commands: ``` $ configure --enable-rustbuild --target=mips-unknown-linux-uclibc $ make ``` cc #35673 --- mk/cfg/mips-unknown-linux-uclibc.mk | 1 + mk/cfg/mipsel-unknown-linux-uclibc.mk | 1 + .../target/mips_unknown_linux_uclibc.rs | 30 ++++++++++++++++++ .../target/mipsel_unknown_linux_uclibc.rs | 31 +++++++++++++++++++ src/librustc_back/target/mod.rs | 2 ++ 5 files changed, 65 insertions(+) create mode 100644 mk/cfg/mips-unknown-linux-uclibc.mk create mode 100644 mk/cfg/mipsel-unknown-linux-uclibc.mk create mode 100644 src/librustc_back/target/mips_unknown_linux_uclibc.rs create mode 100644 src/librustc_back/target/mipsel_unknown_linux_uclibc.rs diff --git a/mk/cfg/mips-unknown-linux-uclibc.mk b/mk/cfg/mips-unknown-linux-uclibc.mk new file mode 100644 index 00000000000..34aee77ae21 --- /dev/null +++ b/mk/cfg/mips-unknown-linux-uclibc.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/mk/cfg/mipsel-unknown-linux-uclibc.mk b/mk/cfg/mipsel-unknown-linux-uclibc.mk new file mode 100644 index 00000000000..34aee77ae21 --- /dev/null +++ b/mk/cfg/mipsel-unknown-linux-uclibc.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/src/librustc_back/target/mips_unknown_linux_uclibc.rs b/src/librustc_back/target/mips_unknown_linux_uclibc.rs new file mode 100644 index 00000000000..529bd310391 --- /dev/null +++ b/src/librustc_back/target/mips_unknown_linux_uclibc.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mips-unknown-linux-uclibc".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), + arch: "mips".to_string(), + target_os: "linux".to_string(), + target_env: "uclibc".to_string(), + target_vendor: "unknown".to_string(), + options: TargetOptions { + cpu: "mips32r2".to_string(), + features: "+mips32r2,+soft-float".to_string(), + max_atomic_width: 32, + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs new file mode 100644 index 00000000000..1040a0fbe17 --- /dev/null +++ b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mipsel-unknown-linux-uclibc".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), + arch: "mips".to_string(), + target_os: "linux".to_string(), + target_env: "uclibc".to_string(), + target_vendor: "unknown".to_string(), + + options: TargetOptions { + cpu: "mips32".to_string(), + features: "+mips32,+soft-float".to_string(), + max_atomic_width: 32, + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 18686e3f1d6..86cd86d282c 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -143,6 +143,8 @@ supported_targets! { ("i686-unknown-linux-musl", i686_unknown_linux_musl), ("mips-unknown-linux-musl", mips_unknown_linux_musl), ("mipsel-unknown-linux-musl", mipsel_unknown_linux_musl), + ("mips-unknown-linux-uclibc", mips_unknown_linux_uclibc), + ("mipsel-unknown-linux-uclibc", mipsel_unknown_linux_uclibc), ("i686-linux-android", i686_linux_android), ("arm-linux-androideabi", arm_linux_androideabi), From f0ff2d32c89c2bdec65f55c8a82eb92bd562d231 Mon Sep 17 00:00:00 2001 From: Chris Stankus Date: Tue, 16 Aug 2016 20:47:45 -0500 Subject: [PATCH 03/18] E0403 update error format --- src/librustc_resolve/lib.rs | 30 ++++++++++++++++++------------ src/test/compile-fail/E0403.rs | 2 ++ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 962509be324..8242bf97b11 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -103,7 +103,7 @@ enum ResolutionError<'a> { /// error E0402: cannot use an outer type parameter in this context OuterTypeParameterContext, /// error E0403: the name is already used for a type parameter in this type parameter list - NameAlreadyUsedInTypeParameterList(Name), + NameAlreadyUsedInTypeParameterList(Name, &'a Span), /// error E0404: is not a trait IsNotATrait(&'a str), /// error E0405: use of undeclared trait name @@ -210,13 +210,17 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, E0402, "cannot use an outer type parameter in this context") } - ResolutionError::NameAlreadyUsedInTypeParameterList(name) => { - struct_span_err!(resolver.session, - span, - E0403, - "the name `{}` is already used for a type parameter in this type \ - parameter list", - name) + ResolutionError::NameAlreadyUsedInTypeParameterList(name, first_use_span) => { + let mut err = struct_span_err!(resolver.session, + span, + E0403, + "the name `{}` is already used for a type parameter \ + in this type parameter list", + name); + err.span_label(span, &format!("already used")); + err.span_label(first_use_span.clone(), &format!("first use of `{}`", name)); + err + } ResolutionError::IsNotATrait(name) => { let mut err = struct_span_err!(resolver.session, @@ -1731,17 +1735,19 @@ impl<'a> Resolver<'a> { match type_parameters { HasTypeParameters(generics, space, rib_kind) => { let mut function_type_rib = Rib::new(rib_kind); - let mut seen_bindings = HashSet::new(); + let mut seen_bindings = HashMap::new(); for (index, type_parameter) in generics.ty_params.iter().enumerate() { let name = type_parameter.ident.name; debug!("with_type_parameter_rib: {}", type_parameter.id); - if seen_bindings.contains(&name) { + if seen_bindings.contains_key(&name) { + let span = seen_bindings.get(&name).unwrap(); resolve_error(self, type_parameter.span, - ResolutionError::NameAlreadyUsedInTypeParameterList(name)); + ResolutionError::NameAlreadyUsedInTypeParameterList(name, + span)); } - seen_bindings.insert(name); + seen_bindings.entry(name).or_insert(type_parameter.span); // plain insert (no renaming) let def_id = self.definitions.local_def_id(type_parameter.id); diff --git a/src/test/compile-fail/E0403.rs b/src/test/compile-fail/E0403.rs index 6a68013dc6f..cd8532fc4c3 100644 --- a/src/test/compile-fail/E0403.rs +++ b/src/test/compile-fail/E0403.rs @@ -9,6 +9,8 @@ // except according to those terms. fn foo(s: T, u: T) {} //~ ERROR E0403 + //~| NOTE already used + //~| NOTE first use of `T` fn main() { } From 34f856e905e99606c5d358a74d792fe1afda2040 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 17 Aug 2016 05:37:48 +0300 Subject: [PATCH 04/18] Update LLVM to include 4 backported commits by @majnemer. --- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm b/src/llvm index 786aad117be..c3eb3c7608f 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 786aad117be48547f4ca50fae84c4879fa992d4d +Subproject commit c3eb3c7608f439231d0c1340af6b720f113b4bf4 diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 378810a8b89..59c6d53bfa3 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-08-07 +2016-08-17 From 4254b31078ea9a84f9e87f5829711ffd7d13a314 Mon Sep 17 00:00:00 2001 From: Neil Williams Date: Tue, 16 Aug 2016 21:30:17 -0700 Subject: [PATCH 05/18] Update minimum CMake version in README The minimum got bumped in the LLVM upgrade of #34743. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 283efdd2411..dbe48a50cfa 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Read ["Installing Rust"] from [The Book]. * `g++` 4.7 or later or `clang++` 3.x * `python` 2.7 (but not 3.x) * GNU `make` 3.81 or later - * `cmake` 2.8.8 or later + * `cmake` 3.4.3 or later * `curl` * `git` From 7675e4b514f9ad3095ad830488861777cfd6c198 Mon Sep 17 00:00:00 2001 From: Jacob Date: Tue, 16 Aug 2016 22:21:31 -0700 Subject: [PATCH 06/18] Update E0009 to new format --- src/librustc_const_eval/check_match.rs | 9 +++++---- src/test/compile-fail/E0009.rs | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 20673dc1e18..a85fd896f0f 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -1120,10 +1120,11 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, .span_label(p.span, &format!("moves value into pattern guard")) .emit(); } else if by_ref_span.is_some() { - let mut err = struct_span_err!(cx.tcx.sess, p.span, E0009, - "cannot bind by-move and by-ref in the same pattern"); - span_note!(&mut err, by_ref_span.unwrap(), "by-ref binding occurs here"); - err.emit(); + struct_span_err!(cx.tcx.sess, p.span, E0009, + "cannot bind by-move and by-ref in the same pattern") + .span_label(p.span, &format!("by-move pattern here")) + .span_label(by_ref_span.unwrap(), &format!("both by-ref and by-move used")) + .emit(); } }; diff --git a/src/test/compile-fail/E0009.rs b/src/test/compile-fail/E0009.rs index 51f71ea10c9..4ce3b72e449 100644 --- a/src/test/compile-fail/E0009.rs +++ b/src/test/compile-fail/E0009.rs @@ -12,7 +12,10 @@ fn main() { struct X { x: (), } let x = Some((X { x: () }, X { x: () })); match x { - Some((y, ref z)) => {}, //~ ERROR E0009 + Some((y, ref z)) => {}, + //~^ ERROR E0009 + //~| NOTE by-move pattern here + //~| NOTE both by-ref and by-move used None => panic!() } } From 12a159abeaaf54eaf85c0d5fd6b41a7787cb3571 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 17 Aug 2016 16:23:11 +0200 Subject: [PATCH 07/18] Add 'make help' for rustbuild It is still advertised by the configure script. --- src/bootstrap/mk/Makefile.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index c657785d78b..cc44d45c2cc 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -22,6 +22,10 @@ BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py $(BOOTSTRAP_ all: $(Q)$(BOOTSTRAP) +# Don’t use $(Q) here, always show how to invoke the bootstrap script directly +help: + $(BOOTSTRAP) --help + clean: $(Q)$(BOOTSTRAP) --clean From feeed0b51bb4af89c300ee9c15bd3dfbf86778b1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 17 Aug 2016 15:59:27 +0200 Subject: [PATCH 08/18] Fixes issue #11004 --- src/librustc_typeck/check/mod.rs | 4 +++ src/test/compile-fail/issue-11004.rs | 39 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/test/compile-fail/issue-11004.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e573655b8c9..ff0b86aa595 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3000,6 +3000,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { but no field with that name was found", field.node, actual) }, expr_t); + if let ty::TyRawPtr(..) = expr_t.sty { + err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \ + `(*{0}).{1}`", pprust::expr_to_string(base), field.node)); + } if let ty::TyStruct(def, _) = expr_t.sty { Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]); } diff --git a/src/test/compile-fail/issue-11004.rs b/src/test/compile-fail/issue-11004.rs new file mode 100644 index 00000000000..308be462715 --- /dev/null +++ b/src/test/compile-fail/issue-11004.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; + +struct A { x: i32, y: f64 } + +#[cfg(not(works))] +unsafe fn access(n:*mut A) -> (i32, f64) { + let x : i32 = n.x; //~ ERROR attempted access of field `x` + //~| NOTE `n` is a native pointer; perhaps you need to deref with `(*n).x` + let y : f64 = n.y; //~ ERROR attempted access of field `y` + //~| NOTE `n` is a native pointer; perhaps you need to deref with `(*n).y` + (x, y) +} + +#[cfg(works)] +unsafe fn access(n:*mut A) -> (i32, f64) { + let x : i32 = (*n).x; + let y : f64 = (*n).y; + (x, y) +} + +fn main() { + let a : A = A { x: 3, y: 3.14 }; + let p : &A = &a; + let (x,y) = unsafe { + let n : *mut A = mem::transmute(p); + access(n) + }; + println!("x: {}, y: {}", x, y); +} From d01bfb122e195696e72178e967191999c8745df4 Mon Sep 17 00:00:00 2001 From: Jacob Date: Wed, 17 Aug 2016 10:21:15 -0700 Subject: [PATCH 09/18] Remove trailing white space --- src/test/compile-fail/E0009.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/E0009.rs b/src/test/compile-fail/E0009.rs index 4ce3b72e449..767fc0cc5dc 100644 --- a/src/test/compile-fail/E0009.rs +++ b/src/test/compile-fail/E0009.rs @@ -12,7 +12,7 @@ fn main() { struct X { x: (), } let x = Some((X { x: () }, X { x: () })); match x { - Some((y, ref z)) => {}, + Some((y, ref z)) => {}, //~^ ERROR E0009 //~| NOTE by-move pattern here //~| NOTE both by-ref and by-move used From 2179defa0425b88644de283f672cda6695ded942 Mon Sep 17 00:00:00 2001 From: crypto-universe Date: Wed, 17 Aug 2016 00:03:53 +0200 Subject: [PATCH 10/18] New output for E0407 Issue #35697 as a part of #35233. r? @jonathandturner --- src/librustc_resolve/lib.rs | 14 ++++++++------ src/test/compile-fail/E0407.rs | 4 +++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 65e14eee4bc..0d37d0f9384 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -237,12 +237,14 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, err } ResolutionError::MethodNotMemberOfTrait(method, trait_) => { - struct_span_err!(resolver.session, - span, - E0407, - "method `{}` is not a member of trait `{}`", - method, - trait_) + let mut err = struct_span_err!(resolver.session, + span, + E0407, + "method `{}` is not a member of trait `{}`", + method, + trait_); + err.span_label(span, &format!("not a member of `{}`", trait_)); + err } ResolutionError::TypeNotMemberOfTrait(type_, trait_) => { struct_span_err!(resolver.session, diff --git a/src/test/compile-fail/E0407.rs b/src/test/compile-fail/E0407.rs index b861cf1b378..2a150b74512 100644 --- a/src/test/compile-fail/E0407.rs +++ b/src/test/compile-fail/E0407.rs @@ -16,7 +16,9 @@ struct Bar; impl Foo for Bar { fn a() {} - fn b() {} //~ ERROR E0407 + fn b() {} + //~^ ERROR E0407 + //~| NOTE not a member of `Foo` } fn main() { From 2d366428cc50d1f20c139ffc854a603de1c1470c Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 17 Aug 2016 04:13:43 +0300 Subject: [PATCH 11/18] Properly invalidate the early exit cache Fixes #35737 --- src/librustc_mir/build/scope.rs | 43 +++++++++++---------- src/test/run-pass/mir_early_return_scope.rs | 37 ++++++++++++++++++ 2 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 src/test/run-pass/mir_early_return_scope.rs diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index cae9e837989..ca9e108bb41 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -198,8 +198,11 @@ impl<'tcx> Scope<'tcx> { /// /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a /// larger extent of code. - fn invalidate_cache(&mut self) { - self.cached_exits = FnvHashMap(); + /// + /// `unwind` controls whether caches for the unwind branch are also invalidated. + fn invalidate_cache(&mut self, unwind: bool) { + self.cached_exits.clear(); + if !unwind { return; } for dropdata in &mut self.drops { if let DropKind::Value { ref mut cached_block } = dropdata.kind { *cached_block = None; @@ -455,25 +458,29 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; for scope in self.scopes.iter_mut().rev() { - if scope.extent == extent { + let this_scope = scope.extent == extent; + // We must invalidate all the caches leading up to the scope we’re looking for, because + // the cached blocks will branch into build of scope not containing the new drop. If we + // add stuff to the currently inspected scope, then in some cases the non-unwind caches + // may become invalid, therefore we should invalidate these as well. The unwind caches + // will stay correct, because the already generated unwind blocks cannot be influenced + // by just added drop. + // + // If we’re scheduling cleanup for non-droppable type (i.e. DropKind::Storage), then we + // do not need to invalidate unwind branch, because DropKind::Storage does not end up + // built in the unwind branch currently. + let invalidate_unwind = needs_drop && !this_scope; + scope.invalidate_cache(invalidate_unwind); + if this_scope { if let DropKind::Value { .. } = drop_kind { scope.needs_cleanup = true; } - - // No need to invalidate any caches here. The just-scheduled drop will branch into - // the drop that comes before it in the vector. scope.drops.push(DropData { span: span, location: lvalue.clone(), kind: drop_kind }); return; - } else { - // We must invalidate all the cached_blocks leading up to the scope we’re - // looking for, because all of the blocks in the chain will become incorrect. - if let DropKind::Value { .. } = drop_kind { - scope.invalidate_cache() - } } } span_bug!(span, "extent {:?} not in scope to drop {:?}", extent, lvalue); @@ -490,11 +497,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value: &Lvalue<'tcx>, item_ty: Ty<'tcx>) { for scope in self.scopes.iter_mut().rev() { + // We must invalidate all the caches leading up to and including the scope we’re + // looking for, because otherwise some of the blocks in the chain will become + // incorrect and must be rebuilt. + scope.invalidate_cache(true); if scope.extent == extent { assert!(scope.free.is_none(), "scope already has a scheduled free!"); - // We also must invalidate the caches in the scope for which the free is scheduled - // because the drops must branch into the free we schedule here. - scope.invalidate_cache(); scope.needs_cleanup = true; scope.free = Some(FreeData { span: span, @@ -503,11 +511,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { cached_block: None }); return; - } else { - // We must invalidate all the cached_blocks leading up to the scope we’re looking - // for, because otherwise some/most of the blocks in the chain will become - // incorrect. - scope.invalidate_cache(); } } span_bug!(span, "extent {:?} not in scope to free {:?}", extent, value); diff --git a/src/test/run-pass/mir_early_return_scope.rs b/src/test/run-pass/mir_early_return_scope.rs new file mode 100644 index 00000000000..c27e57358b0 --- /dev/null +++ b/src/test/run-pass/mir_early_return_scope.rs @@ -0,0 +1,37 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +static mut DROP: bool = false; + +struct ConnWrap(Conn); +impl ::std::ops::Deref for ConnWrap { + type Target=Conn; + fn deref(&self) -> &Conn { &self.0 } +} + +struct Conn; +impl Drop for Conn { + fn drop(&mut self) { unsafe { DROP = true; } } +} + +fn inner() { + let conn = &*match Some(ConnWrap(Conn)) { + Some(val) => val, + None => return, + }; + return; +} + +fn main() { + inner(); + unsafe { + assert_eq!(DROP, true); + } +} From 2c3250adfa4676467f9ab31201a26187a66cbe0b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 18 Aug 2016 00:38:30 +0300 Subject: [PATCH 12/18] Nice graphs --- src/librustc_mir/build/scope.rs | 60 ++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index ca9e108bb41..dc1d63a2911 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -459,16 +459,52 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { for scope in self.scopes.iter_mut().rev() { let this_scope = scope.extent == extent; - // We must invalidate all the caches leading up to the scope we’re looking for, because - // the cached blocks will branch into build of scope not containing the new drop. If we - // add stuff to the currently inspected scope, then in some cases the non-unwind caches - // may become invalid, therefore we should invalidate these as well. The unwind caches - // will stay correct, because the already generated unwind blocks cannot be influenced - // by just added drop. + // When building drops, we try to cache chains of drops in such a way so these drops + // could be reused by the drops which would branch into the cached (already built) + // blocks. This, however, means that whenever we add a drop into a scope which already + // had some blocks built (and thus, cached) for it, we must invalidate all caches which + // might branch into the scope which had a drop just added to it. This is necessary, + // because otherwise some other code might use the cache to branch into already built + // chain of drops, essentially ignoring the newly added drop. // - // If we’re scheduling cleanup for non-droppable type (i.e. DropKind::Storage), then we - // do not need to invalidate unwind branch, because DropKind::Storage does not end up - // built in the unwind branch currently. + // For example consider there’s two scopes with a drop in each. These are built and + // thus the caches are filled: + // + // +--------------------------------------------------------+ + // | +---------------------------------+ | + // | | +--------+ +-------------+ | +---------------+ | + // | | | return | <-+ | drop(outer) | <-+ | drop(middle) | | + // | | +--------+ +-------------+ | +---------------+ | + // | +------------|outer_scope cache|--+ | + // +------------------------------|middle_scope cache|------+ + // + // Now, a new, inner-most scope is added along with a new drop into both inner-most and + // outer-most scopes: + // + // +------------------------------------------------------------+ + // | +----------------------------------+ | + // | | +--------+ +-------------+ | +---------------+ | +-------------+ + // | | | return | <+ | drop(new) | <-+ | drop(middle) | <--+| drop(inner) | + // | | +--------+ | | drop(outer) | | +---------------+ | +-------------+ + // | | +-+ +-------------+ | | + // | +---|invalid outer_scope cache|----+ | + // +----=----------------|invalid middle_scope cache|-----------+ + // + // If, when adding `drop(new)` we do not invalidate the cached blocks for both + // outer_scope and middle_scope, then, when building drops for the inner (right-most) + // scope, the old, cached blocks, without `drop(new)` will get used, producing the + // wrong results. + // + // The cache and its invalidation for unwind branch is somewhat special. The cache is + // per-drop, rather than per scope, which has a several different implications. Adding + // a new drop into a scope will not invalidate cached blocks of the prior drops in the + // scope. That is true, because none of the already existing drops will have an edge + // into a block with the newly added drop. + // + // Note that this code iterates scopes from the inner-most to the outer-most, + // invalidating caches of each scope visited. This way bare minimum of the + // caches gets invalidated. i.e. if a new drop is added into the middle scope, the + // cache of outer scpoe stays intact. let invalidate_unwind = needs_drop && !this_scope; scope.invalidate_cache(invalidate_unwind); if this_scope { @@ -497,9 +533,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value: &Lvalue<'tcx>, item_ty: Ty<'tcx>) { for scope in self.scopes.iter_mut().rev() { - // We must invalidate all the caches leading up to and including the scope we’re - // looking for, because otherwise some of the blocks in the chain will become - // incorrect and must be rebuilt. + // See the comment in schedule_drop above. The primary difference is that we invalidate + // the unwind blocks unconditionally. That’s because the box free may be considered + // outer-most cleanup within the scope. scope.invalidate_cache(true); if scope.extent == extent { assert!(scope.free.is_none(), "scope already has a scheduled free!"); From 8d78237701f9646cd0ddc4645512e7cde3c58e5e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 17 Aug 2016 23:45:10 +0200 Subject: [PATCH 13/18] Add new error code tests --- src/librustc_resolve/diagnostics.rs | 2 +- src/test/compile-fail/E0423.rs | 15 +++++++++++++++ src/test/compile-fail/E0424.rs | 22 ++++++++++++++++++++++ src/test/compile-fail/E0425.rs | 18 ++++++++++++++++++ src/test/compile-fail/E0426.rs | 15 +++++++++++++++ src/test/compile-fail/E0428.rs | 16 ++++++++++++++++ src/test/compile-fail/E0429.rs | 15 +++++++++++++++ src/test/compile-fail/E0430.rs | 15 +++++++++++++++ src/test/compile-fail/E0431.rs | 14 ++++++++++++++ src/test/compile-fail/E0432.rs | 14 ++++++++++++++ src/test/compile-fail/E0433.rs | 13 +++++++++++++ src/test/compile-fail/E0434.rs | 19 +++++++++++++++++++ src/test/compile-fail/E0435.rs | 14 ++++++++++++++ src/test/compile-fail/E0437.rs | 18 ++++++++++++++++++ src/test/compile-fail/E0438.rs | 20 ++++++++++++++++++++ src/test/compile-fail/E0439.rs | 18 ++++++++++++++++++ src/test/compile-fail/E0440.rs | 22 ++++++++++++++++++++++ 17 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/E0423.rs create mode 100644 src/test/compile-fail/E0424.rs create mode 100644 src/test/compile-fail/E0425.rs create mode 100644 src/test/compile-fail/E0426.rs create mode 100644 src/test/compile-fail/E0428.rs create mode 100644 src/test/compile-fail/E0429.rs create mode 100644 src/test/compile-fail/E0430.rs create mode 100644 src/test/compile-fail/E0431.rs create mode 100644 src/test/compile-fail/E0432.rs create mode 100644 src/test/compile-fail/E0433.rs create mode 100644 src/test/compile-fail/E0434.rs create mode 100644 src/test/compile-fail/E0435.rs create mode 100644 src/test/compile-fail/E0437.rs create mode 100644 src/test/compile-fail/E0438.rs create mode 100644 src/test/compile-fail/E0439.rs create mode 100644 src/test/compile-fail/E0440.rs diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 11ef75ee6a8..5183d68065c 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -891,7 +891,7 @@ A `struct` variant name was used like a function name. Erroneous code example: ```compile_fail,E0423 -struct Foo { a: bool}; +struct Foo { a: bool }; let f = Foo(); // error: `Foo` is a struct variant name, but this expression uses diff --git a/src/test/compile-fail/E0423.rs b/src/test/compile-fail/E0423.rs new file mode 100644 index 00000000000..f5fea77cf96 --- /dev/null +++ b/src/test/compile-fail/E0423.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main () { + struct Foo { a: bool }; + + let f = Foo(); //~ ERROR E0423 +} diff --git a/src/test/compile-fail/E0424.rs b/src/test/compile-fail/E0424.rs new file mode 100644 index 00000000000..445d0c5f3ed --- /dev/null +++ b/src/test/compile-fail/E0424.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo; + +impl Foo { + fn bar(self) {} + + fn foo() { + self.bar(); //~ ERROR E0424 + } +} + +fn main () { +} diff --git a/src/test/compile-fail/E0425.rs b/src/test/compile-fail/E0425.rs new file mode 100644 index 00000000000..70f4b1107ad --- /dev/null +++ b/src/test/compile-fail/E0425.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + fn bar() { + Self; //~ ERROR E0425 + } +} + +fn main () { +} diff --git a/src/test/compile-fail/E0426.rs b/src/test/compile-fail/E0426.rs new file mode 100644 index 00000000000..2eb4c2d3b5e --- /dev/null +++ b/src/test/compile-fail/E0426.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main () { + loop { + break 'a; //~ ERROR E0426 + } +} diff --git a/src/test/compile-fail/E0428.rs b/src/test/compile-fail/E0428.rs new file mode 100644 index 00000000000..42e237d31cb --- /dev/null +++ b/src/test/compile-fail/E0428.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Bar; +struct Bar; //~ ERROR E0428 + //~^ ERROR E0428 + +fn main () { +} diff --git a/src/test/compile-fail/E0429.rs b/src/test/compile-fail/E0429.rs new file mode 100644 index 00000000000..a7d19744f3f --- /dev/null +++ b/src/test/compile-fail/E0429.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt::self; //~ ERROR E0429 + //~^ ERROR E0432 + +fn main () { +} diff --git a/src/test/compile-fail/E0430.rs b/src/test/compile-fail/E0430.rs new file mode 100644 index 00000000000..992876dd294 --- /dev/null +++ b/src/test/compile-fail/E0430.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt::{self, self}; //~ ERROR E0430 + //~^ ERROR E0252 + +fn main () { +} diff --git a/src/test/compile-fail/E0431.rs b/src/test/compile-fail/E0431.rs new file mode 100644 index 00000000000..09ddc1efaf4 --- /dev/null +++ b/src/test/compile-fail/E0431.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use {self}; //~ ERROR E0431 + +fn main () { +} diff --git a/src/test/compile-fail/E0432.rs b/src/test/compile-fail/E0432.rs new file mode 100644 index 00000000000..08d699ee4ca --- /dev/null +++ b/src/test/compile-fail/E0432.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use something::Foo; //~ ERROR E0432 + +fn main () { +} diff --git a/src/test/compile-fail/E0433.rs b/src/test/compile-fail/E0433.rs new file mode 100644 index 00000000000..916d6220eb9 --- /dev/null +++ b/src/test/compile-fail/E0433.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main () { + let map = HashMap::new(); //~ ERROR E0433 +} diff --git a/src/test/compile-fail/E0434.rs b/src/test/compile-fail/E0434.rs new file mode 100644 index 00000000000..747d9f72c42 --- /dev/null +++ b/src/test/compile-fail/E0434.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() { + let y = 5; + fn bar() -> u32 { + y //~ ERROR E0434 + } +} + +fn main () { +} diff --git a/src/test/compile-fail/E0435.rs b/src/test/compile-fail/E0435.rs new file mode 100644 index 00000000000..f6cba15a0bf --- /dev/null +++ b/src/test/compile-fail/E0435.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main () { + let foo = 42u32; + const FOO : u32 = foo; //~ ERROR E0435 +} diff --git a/src/test/compile-fail/E0437.rs b/src/test/compile-fail/E0437.rs new file mode 100644 index 00000000000..7440a82773e --- /dev/null +++ b/src/test/compile-fail/E0437.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo {} + +impl Foo for i32 { + type Bar = bool; //~ ERROR E0437 +} + +fn main () { +} diff --git a/src/test/compile-fail/E0438.rs b/src/test/compile-fail/E0438.rs new file mode 100644 index 00000000000..b3d45307204 --- /dev/null +++ b/src/test/compile-fail/E0438.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_consts)] + +trait Foo {} + +impl Foo for i32 { + const BAR: bool = true; //~ ERROR E0438 +} + +fn main () { +} diff --git a/src/test/compile-fail/E0439.rs b/src/test/compile-fail/E0439.rs new file mode 100644 index 00000000000..52443432021 --- /dev/null +++ b/src/test/compile-fail/E0439.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_shuffle(a: A, b: A, c: [u32; 8]) -> B; //~ ERROR E0439 +} + +fn main () { +} diff --git a/src/test/compile-fail/E0440.rs b/src/test/compile-fail/E0440.rs new file mode 100644 index 00000000000..04e7584008d --- /dev/null +++ b/src/test/compile-fail/E0440.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd)] +#![feature(platform_intrinsics)] + +#[repr(simd)] +struct f64x2(f64, f64); + +extern "platform-intrinsic" { + fn x86_mm_movemask_pd(x: f64x2) -> i32; //~ ERROR E0440 +} + +fn main () { +} From de5aaee0c5ee48a3ebaffa922846ed19321a8d2a Mon Sep 17 00:00:00 2001 From: crypto-universe Date: Thu, 18 Aug 2016 00:07:24 +0200 Subject: [PATCH 14/18] Updated test for E0221 As a part of issue #35233 ?r @GuillaumeGomez --- src/test/compile-fail/E0221.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/E0221.rs b/src/test/compile-fail/E0221.rs index 213ec5a0488..c67bfb822c0 100644 --- a/src/test/compile-fail/E0221.rs +++ b/src/test/compile-fail/E0221.rs @@ -18,7 +18,11 @@ trait Foo { trait Bar : Foo { type A: T2; fn do_something() { - let _: Self::A; //~ ERROR E0221 + let _: Self::A; + //~^ ERROR E0221 + //~| NOTE ambiguous associated type `A` + //~| NOTE associated type `Self` could derive from `Foo` + //~| NOTE associated type `Self` could derive from `Bar` } } From 3c4ecc9e7ce47667e05dcea001bbe91453c3ca22 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 10 Aug 2016 01:43:12 -0700 Subject: [PATCH 15/18] Display secondary span for E0053 for Sort TypeErrors --- src/librustc/hir/map/mod.rs | 7 ++ src/librustc/infer/error_reporting.rs | 6 +- src/librustc/traits/error_reporting.rs | 2 +- src/librustc_typeck/check/compare_method.rs | 78 +++++++++++++++------ 4 files changed, 70 insertions(+), 23 deletions(-) diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 7e82a4a05a7..04031fabc58 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -569,6 +569,13 @@ impl<'ast> Map<'ast> { } } + pub fn expect_impl_item(&self, id: NodeId) -> &'ast ImplItem { + match self.find(id) { + Some(NodeImplItem(item)) => item, + _ => bug!("expected impl item, found {}", self.node_to_string(id)) + } + } + pub fn expect_trait_item(&self, id: NodeId) -> &'ast TraitItem { match self.find(id) { Some(NodeTraitItem(item)) => item, diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 9a6375719c1..1e053d6bfda 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -523,6 +523,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn note_type_err(&self, diag: &mut DiagnosticBuilder<'tcx>, origin: TypeOrigin, + secondary_span: Option<(Span, String)>, values: Option>, terr: &TypeError<'tcx>) { @@ -553,6 +554,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } diag.span_label(span, &terr); + if let Some((sp, msg)) = secondary_span { + diag.span_label(sp, &msg); + } self.note_error_origin(diag, &origin); self.check_and_note_conflicting_crates(diag, terr, span); @@ -569,7 +573,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.sess, trace.origin.span(), E0308, "{}", trace.origin.as_failure_str() ); - self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr); + self.note_type_err(&mut diag, trace.origin, None, Some(trace.values), terr); diag } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 33db0053cda..d6f263fcebe 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -161,7 +161,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.sess, origin.span(), E0271, "type mismatch resolving `{}`", predicate ); - self.note_type_err(&mut diag, origin, values, err); + self.note_type_err(&mut diag, origin, None, values, err); self.note_obligation_cause(&mut diag, obligation); diag.emit(); }); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 6bcf21563cb..93badd98130 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -12,10 +12,9 @@ use middle::free_region::FreeRegionMap; use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::ty; use rustc::traits::{self, Reveal}; -use rustc::ty::error::ExpectedFound; +use rustc::ty::error::{ExpectedFound, TypeError}; use rustc::ty::subst::{Subst, Substs}; -use rustc::hir::map::Node; -use rustc::hir::{ImplItemKind, TraitItem_}; +use rustc::hir::{ImplItemKind, TraitItem_, Ty_}; use syntax::ast; use syntax_pos::Span; @@ -300,6 +299,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_span, impl_m_body_id, &impl_sig); + let impl_args = impl_sig.inputs.clone(); let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: impl_m.fty.unsafety, abi: impl_m.fty.abi, @@ -318,6 +318,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_span, impl_m_body_id, &trait_sig); + let trait_args = trait_sig.inputs.clone(); let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: trait_m.fty.unsafety, abi: trait_m.fty.abi, @@ -331,16 +332,54 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_fty, trait_fty); + let impl_m_iter = match tcx.map.expect_impl_item(impl_m_node_id).node { + ImplItemKind::Method(ref impl_m_sig, _) => impl_m_sig.decl.inputs.iter(), + _ => bug!("{:?} is not a method", impl_m) + }; + + let (impl_err_span, trait_err_span) = match terr { + TypeError::Sorts(ExpectedFound { expected, found }) => { + if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { + let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { + TraitItem_::MethodTraitItem(ref trait_m_sig, _) => + trait_m_sig.decl.inputs.iter(), + _ => bug!("{:?} is not a MethodTraitItem", trait_m) + }; + let impl_iter = impl_args.iter(); + let trait_iter = trait_args.iter(); + let arg_idx = impl_iter.zip(trait_iter) + .position(|(impl_arg_ty, trait_arg_ty)| { + *impl_arg_ty == found && *trait_arg_ty == expected + }).unwrap(); + impl_m_iter.zip(trait_m_iter) + .nth(arg_idx) + .map(|(impl_arg, trait_arg)| + (impl_arg.ty.span, Some(trait_arg.ty.span))) + .unwrap_or( + (origin.span(), tcx.map.span_if_local(trait_m.def_id))) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + } + _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + }; + + let origin = TypeOrigin::MethodCompatCheck(impl_err_span); + let mut diag = struct_span_err!( tcx.sess, origin.span(), E0053, "method `{}` has an incompatible type for trait", trait_m.name ); + infcx.note_type_err( - &mut diag, origin, + &mut diag, + origin, + trait_err_span.map(|sp| (sp, format!("original trait requirement"))), Some(infer::ValuePairs::Types(ExpectedFound { - expected: trait_fty, - found: impl_fty - })), &terr + expected: trait_fty, + found: impl_fty + })), + &terr ); diag.emit(); return @@ -487,12 +526,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_ty); // Locate the Span containing just the type of the offending impl - if let Some(impl_trait_node) = tcx.map.get_if_local(impl_c.def_id) { - if let Node::NodeImplItem(impl_trait_item) = impl_trait_node { - if let ImplItemKind::Const(ref ty, _) = impl_trait_item.node { - origin = TypeOrigin::Misc(ty.span); - } - } + match tcx.map.expect_impl_item(impl_c_node_id).node { + ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span), + _ => bug!("{:?} is not a impl const", impl_c) } let mut diag = struct_span_err!( @@ -502,16 +538,16 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ); // Add a label to the Span containing just the type of the item - if let Some(orig_trait_node) = tcx.map.get_if_local(trait_c.def_id) { - if let Node::NodeTraitItem(orig_trait_item) = orig_trait_node { - if let TraitItem_::ConstTraitItem(ref ty, _) = orig_trait_item.node { - diag.span_label(ty.span, &format!("original trait requirement")); - } - } - } + let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap(); + let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node { + TraitItem_::ConstTraitItem(ref ty, _) => ty.span, + _ => bug!("{:?} is not a trait const", trait_c) + }; infcx.note_type_err( - &mut diag, origin, + &mut diag, + origin, + Some((trait_c_span, format!("original trait requirement"))), Some(infer::ValuePairs::Types(ExpectedFound { expected: trait_ty, found: impl_ty From 34bc3c94f2639c16d3c009026e4b0e1d1a83d9a2 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 17 Aug 2016 04:04:14 -0700 Subject: [PATCH 16/18] Display secondary span for E0053 for Mutability TypeErrors --- src/librustc_typeck/check/compare_method.rs | 28 +++++++++++++++++++++ src/test/compile-fail/E0053.rs | 14 ++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 93badd98130..043883df035 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -338,6 +338,34 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }; let (impl_err_span, trait_err_span) = match terr { + TypeError::Mutability => { + if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { + let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { + TraitItem_::MethodTraitItem(ref trait_m_sig, _) => + trait_m_sig.decl.inputs.iter(), + _ => bug!("{:?} is not a MethodTraitItem", trait_m) + }; + + impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| { + match (&impl_arg.ty.node, &trait_arg.ty.node) { + (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) | + (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => + impl_mt.mutbl != trait_mt.mutbl, + _ => false + } + }).map(|(ref impl_arg, ref trait_arg)| { + match (impl_arg.to_self(), trait_arg.to_self()) { + (Some(impl_self), Some(trait_self)) => + (impl_self.span, Some(trait_self.span)), + (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)), + _ => bug!("impl and trait fns have different first args, \ + impl: {:?}, trait: {:?}", impl_arg, trait_arg) + } + }).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id))) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + } TypeError::Sorts(ExpectedFound { expected, found }) => { if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { diff --git a/src/test/compile-fail/E0053.rs b/src/test/compile-fail/E0053.rs index 4effda3c49e..7022010714a 100644 --- a/src/test/compile-fail/E0053.rs +++ b/src/test/compile-fail/E0053.rs @@ -9,15 +9,21 @@ // except according to those terms. trait Foo { - fn foo(x: u16); - fn bar(&self); + fn foo(x: u16); //~ NOTE original trait requirement + fn bar(&self); //~ NOTE original trait requirement } struct Bar; impl Foo for Bar { - fn foo(x: i16) { } //~ ERROR E0053 - fn bar(&mut self) { } //~ ERROR E0053 + fn foo(x: i16) { } + //~^ ERROR method `foo` has an incompatible type for trait + //~| NOTE expected u16 + fn bar(&mut self) { } + //~^ ERROR method `bar` has an incompatible type for trait + //~| NOTE values differ in mutability + //~| NOTE expected type `fn(&Bar)` + //~| NOTE found type `fn(&mut Bar)` } fn main() { From 31d56cb144ead0811935a09d32d7b2febc5b42de Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 17 Aug 2016 04:05:04 -0700 Subject: [PATCH 17/18] Add UI test for E0053 --- .../trait-impl-fn-incompatibility.rs | 27 +++++++++++++++++++ .../trait-impl-fn-incompatibility.stderr | 23 ++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs create mode 100644 src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs new file mode 100644 index 00000000000..099c8699e49 --- /dev/null +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustc-env:RUST_NEW_ERROR_FORMAT + +trait Foo { + fn foo(x: u16); + fn bar(&mut self, bar: &mut Bar); +} + +struct Bar; + +impl Foo for Bar { + fn foo(x: i16) { } + fn bar(&mut self, bar: &Bar) { } +} + +fn main() { +} + diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr new file mode 100644 index 00000000000..e5dfdc8e910 --- /dev/null +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -0,0 +1,23 @@ +error[E0053]: method `foo` has an incompatible type for trait + --> $DIR/trait-impl-fn-incompatibility.rs:21:15 + | +14 | fn foo(x: u16); + | --- original trait requirement +... +21 | fn foo(x: i16) { } + | ^^^ expected u16, found i16 + +error[E0053]: method `bar` has an incompatible type for trait + --> $DIR/trait-impl-fn-incompatibility.rs:22:28 + | +15 | fn bar(&mut self, bar: &mut Bar); + | -------- original trait requirement +... +22 | fn bar(&mut self, bar: &Bar) { } + | ^^^^ values differ in mutability + | + = note: expected type `fn(&mut Bar, &mut Bar)` + = note: found type `fn(&mut Bar, &Bar)` + +error: aborting due to 2 previous errors + From ed54226467f60a6ca15aabe9cc1f58763503a817 Mon Sep 17 00:00:00 2001 From: crypto-universe Date: Thu, 18 Aug 2016 00:43:18 +0200 Subject: [PATCH 18/18] Fix tidy check. --- src/test/compile-fail/E0221.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/E0221.rs b/src/test/compile-fail/E0221.rs index c67bfb822c0..65105458040 100644 --- a/src/test/compile-fail/E0221.rs +++ b/src/test/compile-fail/E0221.rs @@ -18,7 +18,7 @@ trait Foo { trait Bar : Foo { type A: T2; fn do_something() { - let _: Self::A; + let _: Self::A; //~^ ERROR E0221 //~| NOTE ambiguous associated type `A` //~| NOTE associated type `Self` could derive from `Foo`