From 18b4fe0e3eb9c68a966fce2fec12d892db00014a Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 11 Dec 2015 20:59:11 +1300 Subject: [PATCH 1/6] Make name resolution errors non-fatal --- src/librustc/middle/check_static_recursion.rs | 5 +- src/librustc/middle/def.rs | 6 +- src/librustc/middle/mem_categorization.rs | 6 +- src/librustc/middle/resolve_lifetime.rs | 17 +- src/librustc/middle/ty/mod.rs | 3 +- src/librustc/session/mod.rs | 9 + src/librustc_metadata/astencode.rs | 3 +- src/librustc_resolve/build_reduced_graph.rs | 3 +- src/librustc_resolve/lib.rs | 29 ++- src/librustc_trans/save/dump_csv.rs | 3 +- src/librustc_trans/trans/callee.rs | 2 +- src/librustc_typeck/astconv.rs | 6 + src/librustc_typeck/check/_match.rs | 73 ++++-- src/librustc_typeck/check/callee.rs | 3 +- src/librustc_typeck/check/mod.rs | 231 +++++++++--------- src/librustc_typeck/check/writeback.rs | 6 +- src/librustc_typeck/coherence/orphan.rs | 3 + src/librustc_typeck/lib.rs | 15 +- src/test/compile-fail-fulldeps/qquote.rs | 3 +- .../associated-types-coherence-failure.rs | 4 +- src/test/compile-fail/bogus-tag.rs | 8 +- ...erence-impl-trait-for-trait-object-safe.rs | 6 +- src/test/compile-fail/coherence-impls-copy.rs | 4 - .../compile-fail/coherence-impls-sized.rs | 1 - .../compile-fail/duplicate-type-parameter.rs | 1 + .../inner-static-type-parameter.rs | 2 +- src/test/compile-fail/issue-12796.rs | 4 +- src/test/compile-fail/issue-14254.rs | 2 +- src/test/compile-fail/issue-19883.rs | 2 +- src/test/compile-fail/issue-20427.rs | 4 +- src/test/compile-fail/issue-23305.rs | 1 + src/test/compile-fail/issue-2356.rs | 4 +- src/test/compile-fail/issue-28109.rs | 14 +- src/test/compile-fail/issue-3021-d.rs | 4 +- src/test/compile-fail/issue-3021.rs | 2 +- src/test/compile-fail/issue-3214.rs | 2 + src/test/compile-fail/issue-3521.rs | 1 + src/test/compile-fail/issue-3973.rs | 2 + src/test/compile-fail/issue-5927.rs | 8 +- src/test/compile-fail/issue-9725.rs | 1 + .../compile-fail/mod_file_correct_spans.rs | 2 +- src/test/compile-fail/opt-in-copy.rs | 2 - .../resolve-inconsistent-binding-mode.rs | 3 + .../resolve-type-param-in-item-in-trait.rs | 3 + .../compile-fail/syntax-extension-minor.rs | 2 +- .../trait-safety-trait-impl-cc.rs | 2 +- .../compile-fail/trait-safety-trait-impl.rs | 4 +- 47 files changed, 308 insertions(+), 213 deletions(-) diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index 85a3117196acf..0882f3f1137ec 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -99,8 +99,9 @@ pub fn check_crate<'ast>(sess: &Session, ast_map: ast_map, discriminant_map: RefCell::new(NodeMap()), }; - krate.visit_all_items(&mut visitor); - sess.abort_if_errors(); + sess.abort_if_new_errors(|| { + krate.visit_all_items(&mut visitor); + }); } struct CheckItemRecursionVisitor<'a, 'ast: 'a> { diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index b1d2418795753..809c6084b769f 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -52,6 +52,7 @@ pub enum Def { DefStruct(DefId), DefLabel(ast::NodeId), DefMethod(DefId), + DefErr, } /// The result of resolving a path. @@ -124,7 +125,7 @@ impl Def { DefVariant(..) | DefTy(..) | DefAssociatedTy(..) | DefTyParam(..) | DefUse(..) | DefStruct(..) | DefTrait(..) | DefMethod(..) | DefConst(..) | DefAssociatedConst(..) | - DefPrimTy(..) | DefLabel(..) | DefSelfTy(..) => { + DefPrimTy(..) | DefLabel(..) | DefSelfTy(..) | DefErr => { panic!("attempted .def_id() on invalid {:?}", self) } } @@ -142,7 +143,8 @@ impl Def { DefLabel(..) | DefPrimTy(..) | - DefSelfTy(..) => { + DefSelfTy(..) | + DefErr => { panic!("attempted .def_id() on invalid def: {:?}", self) } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 70ef112efbaab..f869cac9236f6 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -609,6 +609,8 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { note: NoteNone })) } + + def::DefErr => panic!("DefErr in memory categorization") } } @@ -1196,7 +1198,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { (*op)(self, cmt.clone(), pat); let opt_def = if let Some(path_res) = self.tcx().def_map.borrow().get(&pat.id) { - if path_res.depth != 0 { + if path_res.depth != 0 || path_res.base_def == def::DefErr { // Since patterns can be associated constants // which are resolved during typeck, we might have // some unresolved patterns reaching this stage @@ -1261,7 +1263,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { _ => { self.tcx().sess.span_bug( pat.span, - "enum pattern didn't resolve to enum or struct"); + &format!("enum pattern didn't resolve to enum or struct {:?}", opt_def)); } } } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index b37b30703101a..15d1546d2d548 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -95,15 +95,16 @@ static ROOT_SCOPE: ScopeChain<'static> = RootScope; pub fn krate(sess: &Session, krate: &hir::Crate, def_map: &DefMap) -> NamedRegionMap { let mut named_region_map = NodeMap(); - krate.visit_all_items(&mut LifetimeContext { - sess: sess, - named_region_map: &mut named_region_map, - scope: &ROOT_SCOPE, - def_map: def_map, - trait_ref_hack: false, - labels_in_fn: vec![], + sess.abort_if_new_errors(|| { + krate.visit_all_items(&mut LifetimeContext { + sess: sess, + named_region_map: &mut named_region_map, + scope: &ROOT_SCOPE, + def_map: def_map, + trait_ref_hack: false, + labels_in_fn: vec![], + }); }); - sess.abort_if_errors(); named_region_map } diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 7477c4dead031..5161a28ca31e8 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -2100,9 +2100,8 @@ impl<'tcx> ctxt<'tcx> { }) => { true } - + Some(&def::PathResolution { base_def: def::DefErr, .. })=> true, Some(..) => false, - None => self.sess.span_bug(expr.span, &format!( "no def for path {}", expr.id)) } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 7bf96b41dce7f..b7bfc2f8db53e 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -156,6 +156,15 @@ impl Session { _ => {} } } + pub fn abort_if_new_errors(&self, mut f: F) + where F: FnMut() + { + let count = self.err_count(); + f(); + if self.err_count() > count { + self.abort_if_errors(); + } + } pub fn span_warn(&self, sp: Span, msg: &str) { if self.can_print_warnings { self.diagnostic().span_warn(sp, msg) diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 4c47d3ab99063..d43ffb0fc3f3e 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -407,7 +407,8 @@ impl tr for def::Def { def::DefUpvar(did1, nid1, index, nid2) } def::DefStruct(did) => def::DefStruct(did.tr(dcx)), - def::DefLabel(nid) => def::DefLabel(dcx.tr_id(nid)) + def::DefLabel(nid) => def::DefLabel(dcx.tr_id(nid)), + def::DefErr => def::DefErr, } } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 0deef91a0f6b0..8b5b6ff781e07 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -709,7 +709,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { DefUse(..) | DefUpvar(..) | DefLabel(..) | - DefSelfTy(..) => { + DefSelfTy(..) | + DefErr => { panic!("didn't expect `{:?}`", def); } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c32acb7bb269f..4d5978f556078 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -566,6 +566,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { Ok(def) => self.record_def(tref.trait_ref.ref_id, def), Err(_) => { // error already reported + self.record_def(tref.trait_ref.ref_id, err_path_resolution()) } } intravisit::walk_poly_trait_ref(self, tref, m); @@ -2005,6 +2006,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { prefix.span, ResolutionError::FailedToResolve( &path_names_to_string(prefix, 0))); + self.record_def(item.id, err_path_resolution()); } } } @@ -2164,6 +2166,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { resolve_error(self, eq_pred.span, ResolutionError::UndeclaredAssociatedType); + self.record_def(eq_pred.id, err_path_resolution()); } } } @@ -2194,6 +2197,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.record_def(trait_ref.ref_id, path_res); new_val = Some((path_res.base_def.def_id(), trait_ref.clone())); new_id = Some(path_res.base_def.def_id()); + } else { + self.record_def(trait_ref.ref_id, err_path_resolution()); } intravisit::walk_trait_ref(self, trait_ref); } @@ -2463,6 +2468,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.record_def(ty.id, def); } None => { + self.record_def(ty.id, err_path_resolution()); + // Keep reporting some errors even if they're ignored above. self.resolve_path(ty.id, path, 0, TypeNS, true); @@ -2545,6 +2552,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct( renamed) ); + self.record_def(pattern.id, err_path_resolution()); } FoundConst(def, lp, _) if const_ok => { debug!("(resolving pattern) resolving `{}` to constant", renamed); @@ -2564,6 +2572,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolutionError::OnlyIrrefutablePatternsAllowedHere(def.def_id(), name) ); + self.record_def(pattern.id, err_path_resolution()); } BareIdentifierPatternUnresolved => { debug!("(resolving pattern) binding `{}`", renamed); @@ -2647,6 +2656,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { resolve_error(&self, path.span, ResolutionError::StaticVariableReference); + self.record_def(pattern.id, err_path_resolution()); } _ => { // If anything ends up here entirely resolved, @@ -2665,6 +2675,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .name .as_str()) ); + self.record_def(pattern.id, err_path_resolution()); } else { let const_name = path.segments .last() @@ -2684,6 +2695,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolutionError::UnresolvedEnumVariantStructOrConst( &path.segments.last().unwrap().identifier.name.as_str()) ); + self.record_def(pattern.id, err_path_resolution()); } intravisit::walk_path(self, path); } @@ -2726,6 +2738,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &path.segments.last().unwrap().identifier.name.as_str() ) ); + self.record_def(pattern.id, err_path_resolution()); } } } else { @@ -2737,6 +2750,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .identifier .name .as_str())); + self.record_def(pattern.id, err_path_resolution()); } intravisit::walk_pat(self, pattern); } @@ -2754,6 +2768,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolutionError::DoesNotNameAStruct( &*path_names_to_string(path, 0)) ); + self.record_def(pattern.id, err_path_resolution()); } } intravisit::walk_path(self, path); @@ -3430,6 +3445,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } else { self.session.span_help(expr.span, &msg); } + self.record_def(expr.id, err_path_resolution()); } else { // Write the result into the def map. debug!("(resolving expr) resolved `{}`", @@ -3454,6 +3470,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let type_res = self.with_no_errors(|this| { this.resolve_path(expr.id, path, 0, TypeNS, false) }); + + self.record_def(expr.id, err_path_resolution()); match type_res.map(|r| r.base_def) { Some(DefTy(struct_id, _)) if self.structs.contains_key(&struct_id) => { resolve_error( @@ -3540,6 +3558,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolutionError::DoesNotNameAStruct( &*path_names_to_string(path, 0)) ); + self.record_def(expr.id, err_path_resolution()); } } @@ -3562,6 +3581,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ExprBreak(Some(label)) | ExprAgain(Some(label)) => { match self.search_label(label.node.name) { None => { + self.record_def(expr.id, err_path_resolution()); resolve_error(self, label.span, ResolutionError::UndeclaredLabel(&label.node.name.as_str())) @@ -3811,6 +3831,14 @@ fn module_to_string(module: &Module) -> String { names_to_string(&names.into_iter().rev().collect::>()) } +fn err_path_resolution() -> PathResolution { + PathResolution { + base_def: DefErr, + last_private: LastMod(AllPublic), + depth: 0, + } +} + pub struct CrateMap { pub def_map: RefCell, @@ -3836,7 +3864,6 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session, let mut resolver = create_resolver(session, ast_map, krate, make_glob_map, None); resolver.resolve_crate(krate); - session.abort_if_errors(); check_unused::check_crate(&mut resolver, krate); diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index 2964d87ec1c09..b3e7ed7ed5e8e 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -276,7 +276,8 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { def::DefTyParam(..) | def::DefUse(_) | def::DefMethod(..) | - def::DefPrimTy(_) => { + def::DefPrimTy(_) | + def::DefErr => { self.sess.span_bug(span, &format!("lookup_def_kind for unexpected item: {:?}", def)); } diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 4aa7c0ff587f0..a22c12588e5f7 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -216,7 +216,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr) def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) | def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) | def::DefUse(..) | def::DefLabel(..) | def::DefTyParam(..) | - def::DefSelfTy(..) => { + def::DefSelfTy(..) | def::DefErr => { bcx.tcx().sess.span_bug( ref_expr.span, &format!("cannot translate def {:?} \ diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index b83f0a5be6f04..752dd6e57f64f 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -719,6 +719,9 @@ fn trait_def_id<'tcx>(this: &AstConv<'tcx>, trait_ref: &hir::TraitRef) -> DefId let path = &trait_ref.path; match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) { def::DefTrait(trait_def_id) => trait_def_id, + def::DefErr => { + this.tcx().sess.fatal("cannot continue compilation due to previous error"); + } _ => { span_fatal!(this.tcx().sess, path.span, E0245, "`{}` is not a trait", path); @@ -1533,6 +1536,9 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, def::DefPrimTy(prim_ty) => { prim_ty_to_ty(tcx, base_segments, prim_ty) } + def::DefErr => { + return this.tcx().types.err; + } _ => { let id_node = tcx.map.as_local_node_id(def.def_id()).unwrap(); span_err!(tcx.sess, span, E0248, diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 38c714fa8f292..efcc08c69f824 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -142,20 +142,24 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, return; } } - let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id(); - let const_scheme = tcx.lookup_item_type(const_did); - assert!(const_scheme.generics.is_empty()); - let const_ty = pcx.fcx.instantiate_type_scheme(pat.span, - &Substs::empty(), - &const_scheme.ty); - fcx.write_ty(pat.id, const_ty); - - // FIXME(#20489) -- we should limit the types here to scalars or something! - - // As with PatLit, what we really want here is that there - // exist a LUB, but for the cases that can occur, subtype - // is good enough. - demand::suptype(fcx, pat.span, expected, const_ty); + if let Some(pat_def) = tcx.def_map.borrow().get(&pat.id) { + let const_did = pat_def.def_id(); + let const_scheme = tcx.lookup_item_type(const_did); + assert!(const_scheme.generics.is_empty()); + let const_ty = pcx.fcx.instantiate_type_scheme(pat.span, + &Substs::empty(), + &const_scheme.ty); + fcx.write_ty(pat.id, const_ty); + + // FIXME(#20489) -- we should limit the types here to scalars or something! + + // As with PatLit, what we really want here is that there + // exist a LUB, but for the cases that can occur, subtype + // is good enough. + demand::suptype(fcx, pat.span, expected, const_ty); + } else { + fcx.write_error(pat.id); + } } hir::PatIdent(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map.borrow(), pat) => { let typ = fcx.local_ty(pat.span, pat.id); @@ -186,14 +190,15 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // if there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be - let canon_id = *pcx.map.get(&path.node.name).unwrap(); - if canon_id != pat.id { - let ct = fcx.local_ty(pat.span, canon_id); - demand::eqtype(fcx, pat.span, ct, typ); - } + if let Some(&canon_id) = pcx.map.get(&path.node.name) { + if canon_id != pat.id { + let ct = fcx.local_ty(pat.span, canon_id); + demand::eqtype(fcx, pat.span, ct, typ); + } - if let Some(ref p) = *sub { - check_pat(pcx, &**p, expected); + if let Some(ref p) = *sub { + check_pat(pcx, &**p, expected); + } } } hir::PatIdent(_, ref path, _) => { @@ -208,6 +213,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, hir::PatQPath(ref qself, ref path) => { let self_ty = fcx.to_ty(&qself.ty); let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) { + if d.base_def == def::DefErr { + fcx.write_error(pat.id); + return; + } d } else if qself.position == 0 { // This is just a sentinel for finish_resolving_def_to_ty. @@ -218,8 +227,9 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, depth: path.segments.len() } } else { - tcx.sess.span_bug(pat.span, - &format!("unbound path {:?}", pat)) + debug!("unbound path {:?}", pat); + fcx.write_error(pat.id); + return; }; if let Some((opt_ty, segments, def)) = resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty), @@ -597,7 +607,20 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; - let path_res = *tcx.def_map.borrow().get(&pat.id).unwrap(); + let path_res = match tcx.def_map.borrow().get(&pat.id) { + Some(&path_res) if path_res.base_def != def::DefErr => path_res, + _ => { + fcx.write_error(pat.id); + + if let Some(subpats) = subpats { + for pat in subpats { + check_pat(pcx, &**pat, tcx.types.err); + } + } + + return; + } + }; let (opt_ty, segments, def) = match resolve_ty_and_def_ufcs(fcx, path_res, None, path, @@ -636,7 +659,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let report_bad_struct_kind = |is_warning| { bad_struct_kind_err(tcx.sess, pat.span, path, is_warning); if is_warning { - return + return; } fcx.write_error(pat.id); diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 6a23be682e9d3..1e20cd3985467 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -26,6 +26,7 @@ use super::write_call; use CrateCtxt; use middle::cstore::LOCAL_CRATE; +use middle::def; use middle::def_id::DefId; use middle::infer; use middle::ty::{self, LvaluePreference, Ty}; @@ -234,7 +235,7 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, if let hir::ExprCall(ref expr, _) = call_expr.node { let tcx = fcx.tcx(); if let Some(pr) = tcx.def_map.borrow().get(&expr.id) { - if pr.depth == 0 { + if pr.depth == 0 && pr.base_def != def::DefErr { if let Some(span) = tcx.map.span_if_local(pr.def_id()) { tcx.sess.span_note(span, "defined here") } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a50213202b82c..e43c806dc41e6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -385,61 +385,60 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { } pub fn check_wf_old(ccx: &CrateCtxt) { - // FIXME(#25759). The new code below is much more reliable but (for now) - // only generates warnings. So as to ensure that we continue - // getting errors where we used to get errors, we run the old wf - // code first and abort if it encounters any errors. If no abort - // comes, we run the new code and issue warnings. - let krate = ccx.tcx.map.krate(); - let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx); - krate.visit_all_items(&mut visit); - // If types are not well-formed, it leads to all manner of errors // downstream, so stop reporting errors at this point. - ccx.tcx.sess.abort_if_errors(); + ccx.tcx.sess.abort_if_new_errors(|| { + // FIXME(#25759). The new code below is much more reliable but (for now) + // only generates warnings. So as to ensure that we continue + // getting errors where we used to get errors, we run the old wf + // code first and abort if it encounters any errors. If no abort + // comes, we run the new code and issue warnings. + let krate = ccx.tcx.map.krate(); + let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx); + krate.visit_all_items(&mut visit); + }); } pub fn check_wf_new(ccx: &CrateCtxt) { - let krate = ccx.tcx.map.krate(); - let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx); - krate.visit_all_items(&mut visit); - - // If types are not well-formed, it leads to all manner of errors - // downstream, so stop reporting errors at this point. - ccx.tcx.sess.abort_if_errors(); + ccx.tcx.sess.abort_if_new_errors(|| { + let krate = ccx.tcx.map.krate(); + let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx); + krate.visit_all_items(&mut visit); + }); } pub fn check_item_types(ccx: &CrateCtxt) { - let krate = ccx.tcx.map.krate(); - let mut visit = CheckItemTypesVisitor { ccx: ccx }; - krate.visit_all_items(&mut visit); - ccx.tcx.sess.abort_if_errors(); + ccx.tcx.sess.abort_if_new_errors(|| { + let krate = ccx.tcx.map.krate(); + let mut visit = CheckItemTypesVisitor { ccx: ccx }; + krate.visit_all_items(&mut visit); + }); } pub fn check_item_bodies(ccx: &CrateCtxt) { - let krate = ccx.tcx.map.krate(); - let mut visit = CheckItemBodiesVisitor { ccx: ccx }; - krate.visit_all_items(&mut visit); - - ccx.tcx.sess.abort_if_errors(); + ccx.tcx.sess.abort_if_new_errors(|| { + let krate = ccx.tcx.map.krate(); + let mut visit = CheckItemBodiesVisitor { ccx: ccx }; + krate.visit_all_items(&mut visit); + }); } pub fn check_drop_impls(ccx: &CrateCtxt) { - let drop_trait = match ccx.tcx.lang_items.drop_trait() { - Some(id) => ccx.tcx.lookup_trait_def(id), None => { return } - }; - drop_trait.for_each_impl(ccx.tcx, |drop_impl_did| { - if drop_impl_did.is_local() { - match dropck::check_drop_impl(ccx.tcx, drop_impl_did) { - Ok(()) => {} - Err(()) => { - assert!(ccx.tcx.sess.has_errors()); + ccx.tcx.sess.abort_if_new_errors(|| { + let drop_trait = match ccx.tcx.lang_items.drop_trait() { + Some(id) => ccx.tcx.lookup_trait_def(id), None => { return } + }; + drop_trait.for_each_impl(ccx.tcx, |drop_impl_did| { + if drop_impl_did.is_local() { + match dropck::check_drop_impl(ccx.tcx, drop_impl_did) { + Ok(()) => {} + Err(()) => { + assert!(ccx.tcx.sess.has_errors()); + } } } - } + }); }); - - ccx.tcx.sess.abort_if_errors(); } fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, @@ -891,75 +890,71 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, for impl_item in impl_items { let ty_impl_item = ccx.tcx.impl_or_trait_item(ccx.tcx.map.local_def_id(impl_item.id)); let ty_trait_item = trait_items.iter() - .find(|ac| ac.name() == ty_impl_item.name()) - .unwrap_or_else(|| { - // This is checked by resolve - tcx.sess.span_bug(impl_item.span, - &format!("impl-item `{}` is not a member of `{:?}`", - ty_impl_item.name(), - impl_trait_ref)); - }); - match impl_item.node { - hir::ImplItemKind::Const(..) => { - let impl_const = match ty_impl_item { - ty::ConstTraitItem(ref cti) => cti, - _ => tcx.sess.span_bug(impl_item.span, "non-const impl-item for const") - }; + .find(|ac| ac.name() == ty_impl_item.name()); - // Find associated const definition. - if let &ty::ConstTraitItem(ref trait_const) = ty_trait_item { - compare_const_impl(ccx.tcx, - &impl_const, - impl_item.span, - trait_const, - &*impl_trait_ref); - } else { - span_err!(tcx.sess, impl_item.span, E0323, - "item `{}` is an associated const, \ - which doesn't match its trait `{:?}`", - impl_const.name, - impl_trait_ref) + if let Some(ty_trait_item) = ty_trait_item { + match impl_item.node { + hir::ImplItemKind::Const(..) => { + let impl_const = match ty_impl_item { + ty::ConstTraitItem(ref cti) => cti, + _ => tcx.sess.span_bug(impl_item.span, "non-const impl-item for const") + }; + + // Find associated const definition. + if let &ty::ConstTraitItem(ref trait_const) = ty_trait_item { + compare_const_impl(ccx.tcx, + &impl_const, + impl_item.span, + trait_const, + &*impl_trait_ref); + } else { + span_err!(tcx.sess, impl_item.span, E0323, + "item `{}` is an associated const, \ + which doesn't match its trait `{:?}`", + impl_const.name, + impl_trait_ref) + } } - } - hir::ImplItemKind::Method(ref sig, ref body) => { - check_trait_fn_not_const(ccx, impl_item.span, sig.constness); + hir::ImplItemKind::Method(ref sig, ref body) => { + check_trait_fn_not_const(ccx, impl_item.span, sig.constness); - let impl_method = match ty_impl_item { - ty::MethodTraitItem(ref mti) => mti, - _ => tcx.sess.span_bug(impl_item.span, "non-method impl-item for method") - }; + let impl_method = match ty_impl_item { + ty::MethodTraitItem(ref mti) => mti, + _ => tcx.sess.span_bug(impl_item.span, "non-method impl-item for method") + }; - if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item { - compare_impl_method(ccx.tcx, - &impl_method, - impl_item.span, - body.id, - &trait_method, - &impl_trait_ref); - } else { - span_err!(tcx.sess, impl_item.span, E0324, - "item `{}` is an associated method, \ - which doesn't match its trait `{:?}`", - impl_method.name, - impl_trait_ref) + if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item { + compare_impl_method(ccx.tcx, + &impl_method, + impl_item.span, + body.id, + &trait_method, + &impl_trait_ref); + } else { + span_err!(tcx.sess, impl_item.span, E0324, + "item `{}` is an associated method, \ + which doesn't match its trait `{:?}`", + impl_method.name, + impl_trait_ref) + } } - } - hir::ImplItemKind::Type(_) => { - let impl_type = match ty_impl_item { - ty::TypeTraitItem(ref tti) => tti, - _ => tcx.sess.span_bug(impl_item.span, "non-type impl-item for type") - }; + hir::ImplItemKind::Type(_) => { + let impl_type = match ty_impl_item { + ty::TypeTraitItem(ref tti) => tti, + _ => tcx.sess.span_bug(impl_item.span, "non-type impl-item for type") + }; - if let &ty::TypeTraitItem(ref at) = ty_trait_item { - if let Some(_) = at.ty { - overridden_associated_type = Some(impl_item); + if let &ty::TypeTraitItem(ref at) = ty_trait_item { + if let Some(_) = at.ty { + overridden_associated_type = Some(impl_item); + } + } else { + span_err!(tcx.sess, impl_item.span, E0325, + "item `{}` is an associated type, \ + which doesn't match its trait `{:?}`", + impl_type.name, + impl_trait_ref) } - } else { - span_err!(tcx.sess, impl_item.span, E0325, - "item `{}` is an associated type, \ - which doesn't match its trait `{:?}`", - impl_type.name, - impl_trait_ref) } } } @@ -3192,6 +3187,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Find the relevant variant let def = lookup_full_def(tcx, path.span, expr.id); + if def == def::DefErr { + check_struct_fields_on_error(fcx, expr.id, fields, base_expr); + return; + } let (adt, variant) = match fcx.def_struct_variant(def, path.span) { Some((adt, variant)) => (adt, variant), None => { @@ -3370,17 +3369,21 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, if let Some((opt_ty, segments, def)) = resolve_ty_and_def_ufcs(fcx, path_res, opt_self_ty, path, expr.span, expr.id) { - let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, - expr.span, - def); - instantiate_path(fcx, - segments, - scheme, - &predicates, - opt_ty, - def, - expr.span, - id); + if def != def::DefErr { + let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, + expr.span, + def); + instantiate_path(fcx, + segments, + scheme, + &predicates, + opt_ty, + def, + expr.span, + id); + } else { + fcx.write_ty(id, fcx.tcx().types.err); + } } // We always require that the type provided as the value for @@ -4325,7 +4328,8 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefForeignMod(..) | def::DefUse(..) | def::DefLabel(..) | - def::DefSelfTy(..) => { + def::DefSelfTy(..) | + def::DefErr => { fcx.ccx.tcx.sess.span_bug(sp, &format!("expected value, found {:?}", defn)); } } @@ -4495,7 +4499,8 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefLocal(..) | def::DefUse(..) | def::DefLabel(..) | - def::DefUpvar(..) => { + def::DefUpvar(..) | + def::DefErr => { segment_spaces = vec![None; segments.len()]; } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 984f227cebe79..c24a416a0109c 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -122,10 +122,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } else { let tcx = self.tcx(); - if let hir::ExprAssignOp(..) = e.node { + if let hir::ExprAssignOp(_, ref lhs, ref rhs) = e.node { if !tcx.sess.features.borrow().augmented_assignments && - !self.fcx.expr_ty(e).references_error() + !self.fcx.expr_ty(e).references_error() && + !self.fcx.expr_ty(lhs).references_error() && + !self.fcx.expr_ty(rhs).references_error() { tcx.sess.span_err( e.span, diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index e6e31ba0819c5..b436a5ee524ac 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -205,6 +205,9 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { "f64", item.span); } + ty::TyError => { + return; + } _ => { span_err!(self.tcx.sess, item.span, E0118, "no base type found for inherent implementation; \ diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 495b8995ceea2..02c1f3973c61a 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -331,18 +331,21 @@ pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) { tcx: tcx }; - time(time_passes, "type collecting", || - collect::collect_item_types(tcx)); - // this ensures that later parts of type checking can assume that items // have valid types and not error - tcx.sess.abort_if_errors(); + tcx.sess.abort_if_new_errors(|| { + time(time_passes, "type collecting", || + collect::collect_item_types(tcx)); + + }); time(time_passes, "variance inference", || variance::infer_variance(tcx)); - time(time_passes, "coherence checking", || - coherence::check_coherence(&ccx)); + tcx.sess.abort_if_new_errors(|| { + time(time_passes, "coherence checking", || + coherence::check_coherence(&ccx)); + }); time(time_passes, "wf checking (old)", || check::check_wf_old(&ccx)); diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs index 7ffbbe69c3d6b..3e153a21e5d38 100644 --- a/src/test/compile-fail-fulldeps/qquote.rs +++ b/src/test/compile-fail-fulldeps/qquote.rs @@ -23,7 +23,8 @@ fn main() { let ps = syntax::parse::ParseSess::new(); let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], - syntax::ext::expand::ExpansionConfig::default("qquote".to_string())); + syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), + &mut Vec::new()); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { diff --git a/src/test/compile-fail/associated-types-coherence-failure.rs b/src/test/compile-fail/associated-types-coherence-failure.rs index 915cb077787ea..6d68da54112f2 100644 --- a/src/test/compile-fail/associated-types-coherence-failure.rs +++ b/src/test/compile-fail/associated-types-coherence-failure.rs @@ -32,13 +32,13 @@ impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned { impl<'a, B: ?Sized> IntoCow<'a, B> for ::Owned where B: ToOwned { //~^ ERROR E0119 fn into_cow(self) -> Cow<'a, B> { - Cow + Cow(PhantomData) } } impl<'a, B: ?Sized> IntoCow<'a, B> for &'a B where B: ToOwned { fn into_cow(self) -> Cow<'a, B> { - Cow + Cow(PhantomData) } } diff --git a/src/test/compile-fail/bogus-tag.rs b/src/test/compile-fail/bogus-tag.rs index 704d856f106b2..a1021500be3d7 100644 --- a/src/test/compile-fail/bogus-tag.rs +++ b/src/test/compile-fail/bogus-tag.rs @@ -9,14 +9,12 @@ // except according to those terms. -// error-pattern: unresolved - enum color { rgb(isize, isize, isize), rgba(isize, isize, isize, isize), } fn main() { - let red: color = rgb(255, 0, 0); + let red: color = color::rgb(255, 0, 0); match red { - rgb(r, g, b) => { println!("rgb"); } - hsl(h, s, l) => { println!("hsl"); } + color::rgb(r, g, b) => { println!("rgb"); } + color::hsl(h, s, l) => { println!("hsl"); } //~ ERROR no associated } } diff --git a/src/test/compile-fail/coherence-impl-trait-for-trait-object-safe.rs b/src/test/compile-fail/coherence-impl-trait-for-trait-object-safe.rs index ce6baeb204c93..b08e4bad1e9c9 100644 --- a/src/test/compile-fail/coherence-impl-trait-for-trait-object-safe.rs +++ b/src/test/compile-fail/coherence-impl-trait-for-trait-object-safe.rs @@ -13,7 +13,9 @@ // If the trait is not object-safe, we give a more tailored message // because we're such schnuckels: -trait NotObjectSafe { fn eq(&self, other: Self); } -impl NotObjectSafe for NotObjectSafe { } //~ ERROR E0372 +trait NotObjectSafe { fn eq(&self, other: &Self); } +impl NotObjectSafe for NotObjectSafe { //~ ERROR E0372 + fn eq(&self, other: &Self) { panic!(); } +} fn main() { } diff --git a/src/test/compile-fail/coherence-impls-copy.rs b/src/test/compile-fail/coherence-impls-copy.rs index 1be606c3546fd..9c210c132a313 100644 --- a/src/test/compile-fail/coherence-impls-copy.rs +++ b/src/test/compile-fail/coherence-impls-copy.rs @@ -28,8 +28,6 @@ impl Copy for MyType {} impl Copy for &'static mut MyType {} //~^ ERROR E0206 -//~| ERROR E0277 -//~| ERROR E0277 impl Clone for MyType { fn clone(&self) -> Self { *self } } impl Copy for (MyType, MyType) {} @@ -42,8 +40,6 @@ impl Copy for &'static NotSync {} impl Copy for [MyType] {} //~^ ERROR E0206 //~| ERROR E0117 -//~| ERROR E0277 -//~| ERROR E0277 impl Copy for &'static [NotSync] {} //~^ ERROR E0206 diff --git a/src/test/compile-fail/coherence-impls-sized.rs b/src/test/compile-fail/coherence-impls-sized.rs index 2ac4bb0492b1f..167067cb5fc0a 100644 --- a/src/test/compile-fail/coherence-impls-sized.rs +++ b/src/test/compile-fail/coherence-impls-sized.rs @@ -30,7 +30,6 @@ impl Sized for (MyType, MyType) {} //~ ERROR E0117 impl Sized for &'static NotSync {} //~ ERROR E0322 impl Sized for [MyType] {} //~ ERROR E0117 -//~^ ERROR E0277 impl Sized for &'static [NotSync] {} //~ ERROR E0117 diff --git a/src/test/compile-fail/duplicate-type-parameter.rs b/src/test/compile-fail/duplicate-type-parameter.rs index 42b67337c64e5..3b0f8ee5bda7a 100644 --- a/src/test/compile-fail/duplicate-type-parameter.rs +++ b/src/test/compile-fail/duplicate-type-parameter.rs @@ -33,6 +33,7 @@ trait Qux {} impl Qux for Option {} //~^ ERROR the name `T` is already used +//~^^ ERROR the type parameter `T` is not constrained fn main() { } diff --git a/src/test/compile-fail/inner-static-type-parameter.rs b/src/test/compile-fail/inner-static-type-parameter.rs index cf2a70deee513..56b681378cc9d 100644 --- a/src/test/compile-fail/inner-static-type-parameter.rs +++ b/src/test/compile-fail/inner-static-type-parameter.rs @@ -10,7 +10,7 @@ // see #9186 -enum Bar { What } +enum Bar { What } //~ ERROR parameter `T` is never used fn foo() { static a: Bar = Bar::What; diff --git a/src/test/compile-fail/issue-12796.rs b/src/test/compile-fail/issue-12796.rs index 2249741cdaac5..33fbdce4ee25a 100644 --- a/src/test/compile-fail/issue-12796.rs +++ b/src/test/compile-fail/issue-12796.rs @@ -9,8 +9,8 @@ // except according to those terms. trait Trait { - fn outer(self) { - fn inner(_: Self) { + fn outer(&self) { + fn inner(_: &Self) { //~^ ERROR can't use type parameters from outer function //~^^ ERROR use of `Self` outside of an impl or trait } diff --git a/src/test/compile-fail/issue-14254.rs b/src/test/compile-fail/issue-14254.rs index ce5fa1f1fe1a5..5f8ccd0b0634e 100644 --- a/src/test/compile-fail/issue-14254.rs +++ b/src/test/compile-fail/issue-14254.rs @@ -11,7 +11,7 @@ trait Foo { fn bar(&self); fn baz(&self) { } - fn bah(_: Option) { } + fn bah(_: Option<&Self>) { } } struct BarTy { diff --git a/src/test/compile-fail/issue-19883.rs b/src/test/compile-fail/issue-19883.rs index c6ff82364b3e7..7ec3093a6e058 100644 --- a/src/test/compile-fail/issue-19883.rs +++ b/src/test/compile-fail/issue-19883.rs @@ -14,7 +14,7 @@ trait From { fn from(src: Src) -> >::Output; } -trait To { +trait To: Sized { fn to>(self) -> >::Dst //~^ ERROR use of undeclared associated type `From::Dst` diff --git a/src/test/compile-fail/issue-20427.rs b/src/test/compile-fail/issue-20427.rs index a4b25ab9e56b3..99dd22a888cb5 100644 --- a/src/test/compile-fail/issue-20427.rs +++ b/src/test/compile-fail/issue-20427.rs @@ -62,7 +62,7 @@ fn usize<'usize>(usize: &'usize usize) -> &'usize usize { usize } fn main() { let bool = true; match bool { - str @ true => if str { i32 as i64 } else { 0 }, + str @ true => if str { i32 as i64 } else { i64 }, false => i64, - } + }; } diff --git a/src/test/compile-fail/issue-23305.rs b/src/test/compile-fail/issue-23305.rs index 4b1010781ff3b..68f053c357bed 100644 --- a/src/test/compile-fail/issue-23305.rs +++ b/src/test/compile-fail/issue-23305.rs @@ -13,5 +13,6 @@ pub trait ToNbt { } impl ToNbt {} //~ ERROR use of `Self` outside of an impl or trait +//~^ WARNING the trait `ToNbt` cannot be made into an object fn main() {} diff --git a/src/test/compile-fail/issue-2356.rs b/src/test/compile-fail/issue-2356.rs index 48cc27e228940..6b81afe13c671 100644 --- a/src/test/compile-fail/issue-2356.rs +++ b/src/test/compile-fail/issue-2356.rs @@ -9,7 +9,7 @@ // except according to those terms. trait Groom { - fn shave(); + fn shave(other: usize); } pub struct cat { @@ -30,7 +30,7 @@ impl MaybeDog { } impl Groom for cat { - fn shave(&self, other: usize) { + fn shave(other: usize) { whiskers -= other; //~^ ERROR: unresolved name `whiskers`. Did you mean `self.whiskers`? shave(4); diff --git a/src/test/compile-fail/issue-28109.rs b/src/test/compile-fail/issue-28109.rs index 73163caa455fc..0d372d300154a 100644 --- a/src/test/compile-fail/issue-28109.rs +++ b/src/test/compile-fail/issue-28109.rs @@ -11,10 +11,12 @@ // Make sure that label for continue and break is spanned correctly fn main() { - continue - 'b //~ ERROR use of undeclared label - ; - break - 'c //~ ERROR use of undeclared label - ; + loop { + continue + 'b //~ ERROR use of undeclared label + ; + break + 'c //~ ERROR use of undeclared label + ; + } } diff --git a/src/test/compile-fail/issue-3021-d.rs b/src/test/compile-fail/issue-3021-d.rs index 594f68e1812af..ecc8ac34ecf2b 100644 --- a/src/test/compile-fail/issue-3021-d.rs +++ b/src/test/compile-fail/issue-3021-d.rs @@ -13,13 +13,13 @@ trait siphash { fn reset(&self); } -fn siphash(k0 : u64, k1 : u64) -> siphash { +fn siphash(k0 : u64, k1 : u64) { struct SipState { v0: u64, v1: u64, } - fn mk_result(st : SipState) -> u64 { + fn mk_result(st : &SipState) -> u64 { let v0 = st.v0; let v1 = st.v1; diff --git a/src/test/compile-fail/issue-3021.rs b/src/test/compile-fail/issue-3021.rs index 719eef1b63d5d..7cf772b072879 100644 --- a/src/test/compile-fail/issue-3021.rs +++ b/src/test/compile-fail/issue-3021.rs @@ -12,7 +12,7 @@ trait SipHash { fn reset(&self); } -fn siphash(k0 : u64) -> SipHash { +fn siphash(k0 : u64) { struct SipState { v0: u64, } diff --git a/src/test/compile-fail/issue-3214.rs b/src/test/compile-fail/issue-3214.rs index be49ca1fe06a7..27b7fb7527503 100644 --- a/src/test/compile-fail/issue-3214.rs +++ b/src/test/compile-fail/issue-3214.rs @@ -15,6 +15,8 @@ fn foo() { } impl Drop for foo { + //~^ ERROR wrong number of type arguments + //~^^ ERROR the type parameter `T` is not constrained fn drop(&mut self) {} } } diff --git a/src/test/compile-fail/issue-3521.rs b/src/test/compile-fail/issue-3521.rs index f06aa45ac38fd..34cd8cae2de32 100644 --- a/src/test/compile-fail/issue-3521.rs +++ b/src/test/compile-fail/issue-3521.rs @@ -16,6 +16,7 @@ fn main() { Bar = foo //~^ ERROR attempt to use a non-constant value in a constant //~| ERROR unresolved name `foo` + //~^^^ ERROR constant evaluation error: non-constant path in constant expression } println!("{}", Stuff::Bar); diff --git a/src/test/compile-fail/issue-3973.rs b/src/test/compile-fail/issue-3973.rs index 2652fb5dfc2fd..1fda423e9ee8d 100644 --- a/src/test/compile-fail/issue-3973.rs +++ b/src/test/compile-fail/issue-3973.rs @@ -30,5 +30,7 @@ impl ToString_ for Point { fn main() { let p = Point::new(0.0, 0.0); + //~^ ERROR no associated item named `new` found for type `Point` in the current scope println!("{}", p.to_string()); + //~^ ERROR the type of this value must be known in this context } diff --git a/src/test/compile-fail/issue-5927.rs b/src/test/compile-fail/issue-5927.rs index 0359248b36a49..e5f091d873df9 100644 --- a/src/test/compile-fail/issue-5927.rs +++ b/src/test/compile-fail/issue-5927.rs @@ -9,12 +9,10 @@ // except according to those terms. - -// error-pattern:unresolved enum variant - fn main() { let z = match 3 { - x(1) => x(1) + x(1) => x(1) //~ ERROR unresolved enum variant + //~^ ERROR unresolved name `x` }; - assert_eq!(z,3); + assert!(z == 3); } diff --git a/src/test/compile-fail/issue-9725.rs b/src/test/compile-fail/issue-9725.rs index 1a3c926ba384b..f53122d19c1bd 100644 --- a/src/test/compile-fail/issue-9725.rs +++ b/src/test/compile-fail/issue-9725.rs @@ -13,4 +13,5 @@ struct A { foo: isize } fn main() { let A { foo, foo } = A { foo: 3 }; //~^ ERROR: identifier `foo` is bound more than once in the same pattern + //~^^ ERROR: field `foo` bound multiple times } diff --git a/src/test/compile-fail/mod_file_correct_spans.rs b/src/test/compile-fail/mod_file_correct_spans.rs index 3b794da10536e..f8ea5dda18336 100644 --- a/src/test/compile-fail/mod_file_correct_spans.rs +++ b/src/test/compile-fail/mod_file_correct_spans.rs @@ -13,5 +13,5 @@ mod mod_file_aux; fn main() { - assert_eq!(mod_file_aux::bar(), 10); //~ ERROR unresolved name + assert!(mod_file_aux::bar() == 10); //~ ERROR unresolved name } diff --git a/src/test/compile-fail/opt-in-copy.rs b/src/test/compile-fail/opt-in-copy.rs index be321b6290354..bc18b52a0c1c9 100644 --- a/src/test/compile-fail/opt-in-copy.rs +++ b/src/test/compile-fail/opt-in-copy.rs @@ -16,7 +16,6 @@ struct IWantToCopyThis { impl Copy for IWantToCopyThis {} //~^ ERROR the trait `Copy` may not be implemented for this type -//~| ERROR E0277 enum CantCopyThisEither { A, @@ -29,6 +28,5 @@ enum IWantToCopyThisToo { impl Copy for IWantToCopyThisToo {} //~^ ERROR the trait `Copy` may not be implemented for this type -//~| ERROR E0277 fn main() {} diff --git a/src/test/compile-fail/resolve-inconsistent-binding-mode.rs b/src/test/compile-fail/resolve-inconsistent-binding-mode.rs index cdb812790480c..284c08ef09b28 100644 --- a/src/test/compile-fail/resolve-inconsistent-binding-mode.rs +++ b/src/test/compile-fail/resolve-inconsistent-binding-mode.rs @@ -16,6 +16,7 @@ fn matcher1(x: opts) { match x { opts::a(ref i) | opts::b(i) => {} //~^ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1 + //~^^ ERROR mismatched types opts::c(_) => {} } } @@ -24,6 +25,7 @@ fn matcher2(x: opts) { match x { opts::a(ref i) | opts::b(i) => {} //~^ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1 + //~^^ ERROR mismatched types opts::c(_) => {} } } @@ -32,6 +34,7 @@ fn matcher4(x: opts) { match x { opts::a(ref mut i) | opts::b(ref i) => {} //~^ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1 + //~^^ ERROR mismatched types opts::c(_) => {} } } diff --git a/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs b/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs index 341fe173a03f4..88f09233d107e 100644 --- a/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs +++ b/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs @@ -15,6 +15,7 @@ trait TraitA { fn outer(self) { enum Foo { + //~^ ERROR parameter `B` is never used Variance(A) //~^ ERROR can't use type parameters from outer function //~^^ ERROR use of undeclared type name `A` @@ -27,6 +28,7 @@ trait TraitB { struct Foo(A); //~^ ERROR can't use type parameters from outer function //~^^ ERROR use of undeclared type name `A` + //~^^^ ERROR parameter `B` is never used } } @@ -35,6 +37,7 @@ trait TraitC { struct Foo { a: A } //~^ ERROR can't use type parameters from outer function //~^^ ERROR use of undeclared type name `A` + //~^^^ ERROR parameter `B` is never used } } diff --git a/src/test/compile-fail/syntax-extension-minor.rs b/src/test/compile-fail/syntax-extension-minor.rs index 506aed6b2ee1d..38a6834a9c460 100644 --- a/src/test/compile-fail/syntax-extension-minor.rs +++ b/src/test/compile-fail/syntax-extension-minor.rs @@ -14,7 +14,7 @@ pub fn main() { let asdf_fdsa = "<.<".to_string(); - assert_eq!(concat_idents!(asd, f_f, dsa), "<.<".to_string()); + assert!(concat_idents!(asd, f_f, dsa) == "<.<".to_string()); //~^ ERROR: unresolved name `asdf_fdsa` assert_eq!(stringify!(use_mention_distinction), "use_mention_distinction"); diff --git a/src/test/compile-fail/trait-safety-trait-impl-cc.rs b/src/test/compile-fail/trait-safety-trait-impl-cc.rs index 6050b549b656f..f30c8f521bdc7 100644 --- a/src/test/compile-fail/trait-safety-trait-impl-cc.rs +++ b/src/test/compile-fail/trait-safety-trait-impl-cc.rs @@ -18,7 +18,7 @@ extern crate trait_safety_lib as lib; struct Bar; impl lib::Foo for Bar { //~ ERROR requires an `unsafe impl` declaration fn foo(&self) -> isize { - *self as isize + panic!(); } } diff --git a/src/test/compile-fail/trait-safety-trait-impl.rs b/src/test/compile-fail/trait-safety-trait-impl.rs index 1bd6d76360768..e846b660c2a17 100644 --- a/src/test/compile-fail/trait-safety-trait-impl.rs +++ b/src/test/compile-fail/trait-safety-trait-impl.rs @@ -12,11 +12,11 @@ // impls cannot be unsafe. trait SafeTrait { - fn foo(self) { } + fn foo(&self) { } } unsafe trait UnsafeTrait { - fn foo(self) { } + fn foo(&self) { } } unsafe impl UnsafeTrait for u8 { } // OK From 08bffdd5c0c0916d9caed05f42419076e1e89359 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 12 Dec 2015 19:02:33 +0200 Subject: [PATCH 2/6] fix dropck performance regression Turns out that calling `resolve_type_variables_if_possible` in a O(n^2) loop is a bad idea. Now we just resolve each copy of the region variable to its lowest name each time (we resolve the region variable to its lowest name, rather than to its unify-table name to avoid the risk of the unify-table name changing infinitely many times. That may be not a problem in practice, but I am not sure of it). --- .../middle/infer/region_inference/mod.rs | 12 +++++--- src/librustc/middle/infer/unify_key.rs | 24 +++++++++++++-- src/librustc_data_structures/unify/mod.rs | 21 ++++++++++++-- src/librustc_typeck/check/dropck.rs | 29 +++++++++---------- 4 files changed, 61 insertions(+), 25 deletions(-) diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 30cf6344e2332..e148aecd241f2 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -18,6 +18,7 @@ pub use self::RegionResolutionError::*; pub use self::VarValue::*; use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; +use super::unify_key; use rustc_data_structures::graph::{self, Direction, NodeIndex}; use rustc_data_structures::unify::{self, UnificationTable}; @@ -345,10 +346,13 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid { - let id = self.num_vars(); + let vid = RegionVid { index: self.num_vars() }; self.var_origins.borrow_mut().push(origin.clone()); - let vid = self.unification_table.borrow_mut().new_key(()); - assert_eq!(vid.index, id); + + let u_vid = self.unification_table.borrow_mut().new_key( + unify_key::RegionVidKey { min_vid: vid } + ); + assert_eq!(vid, u_vid); if self.in_snapshot() { self.undo_log.borrow_mut().push(AddVar(vid)); } @@ -581,7 +585,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> ty::Region { - ty::ReVar(self.unification_table.borrow_mut().find(rid)) + ty::ReVar(self.unification_table.borrow_mut().find_value(rid).min_vid) } fn combine_map(&self, t: CombineMapType) -> &RefCell { diff --git a/src/librustc/middle/infer/unify_key.rs b/src/librustc/middle/infer/unify_key.rs index 85d7d67a0e3ca..c83231930f502 100644 --- a/src/librustc/middle/infer/unify_key.rs +++ b/src/librustc/middle/infer/unify_key.rs @@ -10,7 +10,7 @@ use syntax::ast; use middle::ty::{self, IntVarValue, Ty}; -use rustc_data_structures::unify::UnifyKey; +use rustc_data_structures::unify::{Combine, UnifyKey}; pub trait ToType<'tcx> { fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>; @@ -23,8 +23,28 @@ impl UnifyKey for ty::IntVid { fn tag(_: Option) -> &'static str { "IntVid" } } +#[derive(PartialEq, Copy, Clone, Debug)] +pub struct RegionVidKey { + /// The minimum region vid in the unification set. This is needed + /// to have a canonical name for a type to prevent infinite + /// recursion. + pub min_vid: ty::RegionVid +} + +impl Combine for RegionVidKey { + fn combine(&self, other: &RegionVidKey) -> RegionVidKey { + let min_vid = if self.min_vid.index < other.min_vid.index { + self.min_vid + } else { + other.min_vid + }; + + RegionVidKey { min_vid: min_vid } + } +} + impl UnifyKey for ty::RegionVid { - type Value = (); + type Value = RegionVidKey; fn index(&self) -> u32 { self.index } fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid { index: i } } fn tag(_: Option) -> &'static str { "RegionVid" } diff --git a/src/librustc_data_structures/unify/mod.rs b/src/librustc_data_structures/unify/mod.rs index 4d79b1a64c191..c6da70eef750a 100644 --- a/src/librustc_data_structures/unify/mod.rs +++ b/src/librustc_data_structures/unify/mod.rs @@ -37,6 +37,16 @@ pub trait UnifyKey : Copy + Clone + Debug + PartialEq { fn tag(k: Option) -> &'static str; } +/// This trait is implemented for unify values that can be +/// combined. This relation should be a monoid. +pub trait Combine { + fn combine(&self, other: &Self) -> Self; +} + +impl Combine for () { + fn combine(&self, _other: &()) {} +} + /// Value of a unification key. We implement Tarjan's union-find /// algorithm: when two keys are unified, one of them is converted /// into a "redirect" pointing at the other. These redirects form a @@ -243,8 +253,8 @@ impl sv::SnapshotVecDelegate for Delegate { /////////////////////////////////////////////////////////////////////////// // Base union-find algorithm, where we are just making sets -impl<'tcx,K> UnificationTable - where K : UnifyKey, +impl<'tcx,K:UnifyKey> UnificationTable + where K::Value: Combine { pub fn union(&mut self, a_id: K, b_id: K) { let node_a = self.get(a_id); @@ -252,7 +262,8 @@ impl<'tcx,K> UnificationTable let a_id = node_a.key(); let b_id = node_b.key(); if a_id != b_id { - self.unify(node_a, node_b, ()); + let new_value = node_a.value.combine(&node_b.value); + self.unify(node_a, node_b, new_value); } } @@ -260,6 +271,10 @@ impl<'tcx,K> UnificationTable self.get(id).key() } + pub fn find_value(&mut self, id: K) -> K::Value { + self.get(id).value + } + pub fn unioned(&mut self, a_id: K, b_id: K) -> bool { self.find(a_id) == self.find(b_id) } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 0fbe83674931c..59025346ce3bd 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -17,6 +17,7 @@ use middle::region; use middle::subst::{self, Subst}; use middle::traits; use middle::ty::{self, Ty}; +use util::nodemap::FnvHashSet; use syntax::ast; use syntax::codemap::{self, Span}; @@ -279,7 +280,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx> rcx: rcx, span: span, parent_scope: parent_scope, - breadcrumbs: Vec::new(), + breadcrumbs: FnvHashSet() }, TypeContext::Root, typ, @@ -340,7 +341,7 @@ enum TypeContext { struct DropckContext<'a, 'b: 'a, 'tcx: 'b> { rcx: &'a mut Rcx<'b, 'tcx>, /// types that have already been traversed - breadcrumbs: Vec>, + breadcrumbs: FnvHashSet>, /// span for error reporting span: Span, /// the scope reachable dtorck types must outlive @@ -355,8 +356,6 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( depth: usize) -> Result<(), Error<'tcx>> { let tcx = cx.rcx.tcx(); - let ty = cx.rcx.infcx().resolve_type_and_region_vars_if_possible(&ty); - // Issue #22443: Watch out for overflow. While we are careful to // handle regular types properly, non-regular ones cause problems. let recursion_limit = tcx.sess.recursion_limit.get(); @@ -367,19 +366,17 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( return Err(Error::Overflow(context, ty)) } - for breadcrumb in &mut cx.breadcrumbs { - *breadcrumb = - cx.rcx.infcx().resolve_type_and_region_vars_if_possible(breadcrumb); - if *breadcrumb == ty { - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} scope: {:?} - cached", - (0..depth).map(|_| ' ').collect::(), - ty, cx.parent_scope); - return Ok(()); // we already visited this type - } - } - cx.breadcrumbs.push(ty); + // canoncialize the regions in `ty` before inserting - infinitely many + // region variables can refer to the same region. + let ty = cx.rcx.infcx().resolve_type_and_region_vars_if_possible(&ty); + if !cx.breadcrumbs.insert(ty) { + debug!("iterate_over_potentially_unsafe_regions_in_type \ + {}ty: {} scope: {:?} - cached", + (0..depth).map(|_| ' ').collect::(), + ty, cx.parent_scope); + return Ok(()); // we already visited this type + } debug!("iterate_over_potentially_unsafe_regions_in_type \ {}ty: {} scope: {:?}", (0..depth).map(|_| ' ').collect::(), From 37b8e22c681a092510e150e5eb5268e749a5a34b Mon Sep 17 00:00:00 2001 From: Ori Avtalion Date: Mon, 14 Dec 2015 00:12:17 +0200 Subject: [PATCH 3/6] Add links in BTreeSet docs --- src/libcollections/btree/set.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index a2c09c36795e4..12d3465e5188d 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -26,12 +26,17 @@ use Bound; /// A set based on a B-Tree. /// -/// See BTreeMap's documentation for a detailed discussion of this collection's performance +/// See [`BTreeMap`]'s documentation for a detailed discussion of this collection's performance /// benefits and drawbacks. /// /// It is a logic error for an item to be modified in such a way that the item's ordering relative -/// to any other item, as determined by the `Ord` trait, changes while it is in the set. This is -/// normally only possible through `Cell`, `RefCell`, global state, I/O, or unsafe code. +/// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is +/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// +/// [`BTreeMap`]: ../struct.BTreeMap.html +/// [`Ord`]: ../../core/cmp/trait.Ord.html +/// [`Cell`]: ../../std/cell/struct.Cell.html +/// [`RefCell`]: ../../std/cell/struct.RefCell.html #[derive(Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] #[stable(feature = "rust1", since = "1.0.0")] pub struct BTreeSet { From 2dcd791d46523e75da5c594033383e90c08d4ae3 Mon Sep 17 00:00:00 2001 From: Daniel Campbell Date: Tue, 15 Dec 2015 17:31:54 +1300 Subject: [PATCH 4/6] Generated code spans now point to callsite parameters (where applicable) --- src/libsyntax/ext/tt/macro_parser.rs | 9 +++++--- src/libsyntax/ext/tt/transcribe.rs | 4 ++-- src/libsyntax/fold.rs | 3 ++- src/libsyntax/parse/token.rs | 2 +- src/libsyntax/print/pprust.rs | 2 +- src/test/compile-fail/macro-parameter-span.rs | 23 +++++++++++++++++++ 6 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 src/test/compile-fail/macro-parameter-span.rs diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 5b8307eb6c6f2..16764e5af5cce 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -79,8 +79,8 @@ pub use self::ParseResult::*; use self::TokenTreeOrTokenTreeVec::*; use ast; -use ast::{TokenTree, Name}; -use codemap::{BytePos, mk_sp, Span}; +use ast::{TokenTree, Name, Ident}; +use codemap::{BytePos, mk_sp, Span, Spanned}; use codemap; use parse::lexer::*; //resolve bug? use parse::ParseSess; @@ -526,7 +526,10 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal { "ty" => token::NtTy(panictry!(p.parse_ty())), // this could be handled like a token, since it is one "ident" => match p.token { - token::Ident(sn,b) => { panictry!(p.bump()); token::NtIdent(Box::new(sn),b) } + token::Ident(sn,b) => { + panictry!(p.bump()); + token::NtIdent(Box::new(Spanned::{node: sn, span: p.span}),b) + } _ => { let token_str = pprust::token_to_string(&p.token); panic!(p.fatal(&format!("expected ident, found {}", diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 0fc31f3fd08af..ba781ae3cc212 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -293,8 +293,8 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { // (a) idents can be in lots of places, so it'd be a pain // (b) we actually can, since it's a token. MatchedNonterminal(NtIdent(ref sn, b)) => { - r.cur_span = sp; - r.cur_tok = token::Ident(**sn, b); + r.cur_span = sn.span; + r.cur_tok = token::Ident(sn.node, b); return ret_val; } MatchedNonterminal(ref other_whole_nt) => { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 73f2c51b24622..944dd44a0b6c4 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -663,7 +663,8 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)), token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)), token::NtIdent(id, is_mod_name) => - token::NtIdent(Box::new(fld.fold_ident(*id)), is_mod_name), + token::NtIdent(Box::new(Spanned::{node: fld.fold_ident(id.node), .. *id}), + is_mod_name), token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)), token::NtPath(path) => token::NtPath(Box::new(fld.fold_path(*path))), token::NtTT(tt) => token::NtTT(P(fld.fold_tt(&tt))), diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 17b7d8dbaece9..b942954c1874a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -377,7 +377,7 @@ pub enum Nonterminal { NtPat(P), NtExpr(P), NtTy(P), - NtIdent(Box, IdentStyle), + NtIdent(Box, IdentStyle), /// Stuff inside brackets for attributes NtMeta(P), NtPath(Box), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f710595129672..d3c570de248c0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -296,7 +296,7 @@ pub fn token_to_string(tok: &Token) -> String { token::NtBlock(ref e) => block_to_string(&**e), token::NtStmt(ref e) => stmt_to_string(&**e), token::NtPat(ref e) => pat_to_string(&**e), - token::NtIdent(ref e, _) => ident_to_string(**e), + token::NtIdent(ref e, _) => ident_to_string(e.node), token::NtTT(ref e) => tt_to_string(&**e), token::NtArm(ref e) => arm_to_string(&*e), token::NtImplItem(ref e) => impl_item_to_string(&**e), diff --git a/src/test/compile-fail/macro-parameter-span.rs b/src/test/compile-fail/macro-parameter-span.rs new file mode 100644 index 0000000000000..2ef697591284d --- /dev/null +++ b/src/test/compile-fail/macro-parameter-span.rs @@ -0,0 +1,23 @@ +// Copyright 2015 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. + +macro_rules! foo { + ($id: ident) => { + $id + } +} + +// Testing that the error span points to the parameter 'x' in the callsite, +// not to the macro variable '$id' +fn main() { + foo!( + x //~ ERROR unresolved name `x` + ); +} From eb2572106374ba39b5787cf2495782f4538a4c24 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Tue, 15 Dec 2015 18:03:55 +0900 Subject: [PATCH 5/6] Use --cfg when running doctests Previously passed --cfg was used only when collecting doctests. --- src/librustdoc/lib.rs | 2 +- src/librustdoc/markdown.rs | 4 ++-- src/librustdoc/test.rs | 14 ++++++++++---- src/test/rustdoc/issue-30252.rs | 16 ++++++++++++++++ 4 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 src/test/rustdoc/issue-30252.rs diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 1b450092dbd5d..af6510cb3870e 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -261,7 +261,7 @@ pub fn main_args(args: &[String]) -> isize { match (should_test, markdown_input) { (true, true) => { - return markdown::test(input, libs, externs, test_args) + return markdown::test(input, cfgs, libs, externs, test_args) } (true, false) => { return test::run(input, cfgs, libs, externs, test_args, crate_name) diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index ac64fd3bec0e7..03d2c1a1b4d0d 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -142,13 +142,13 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, } /// Run any tests/code examples in the markdown file `input`. -pub fn test(input: &str, libs: SearchPaths, externs: core::Externs, +pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: core::Externs, mut test_args: Vec) -> isize { let input_str = load_or_return!(input, 1, 2); let mut opts = TestOptions::default(); opts.no_crate_inject = true; - let mut collector = Collector::new(input.to_string(), libs, externs, + let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, true, opts); find_testable_code(&input_str, &mut collector); test_args.insert(0, "rustdoctest".to_string()); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 3e303b29d5c7a..3322794c7781e 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -85,7 +85,7 @@ pub fn run(input: &str, rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess); - cfg.extend(config::parse_cfgspecs(cfgs)); + cfg.extend(config::parse_cfgspecs(cfgs.clone())); let krate = driver::phase_1_parse_input(&sess, cfg, &input); let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "rustdoc-test", None) @@ -122,6 +122,7 @@ pub fn run(input: &str, let (krate, _) = passes::unindent_comments(krate); let mut collector = Collector::new(krate.name.to_string(), + cfgs, libs, externs, false, @@ -168,7 +169,7 @@ fn scrape_test_config(krate: &::rustc_front::hir::Crate) -> TestOptions { return opts; } -fn runtest(test: &str, cratename: &str, libs: SearchPaths, +fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, externs: core::Externs, should_panic: bool, no_run: bool, as_test_harness: bool, opts: &TestOptions) { @@ -239,7 +240,8 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths, let outdir = TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir"); let out = Some(outdir.path().to_path_buf()); - let cfg = config::build_configuration(&sess); + let mut cfg = config::build_configuration(&sess); + cfg.extend(config::parse_cfgspecs(cfgs)); let libdir = sess.target_filesearch(PathKind::All).get_lib_path(); let mut control = driver::CompileController::basic(); if no_run { @@ -349,6 +351,7 @@ fn partition_source(s: &str) -> (String, String) { pub struct Collector { pub tests: Vec, names: Vec, + cfgs: Vec, libs: SearchPaths, externs: core::Externs, cnt: usize, @@ -359,11 +362,12 @@ pub struct Collector { } impl Collector { - pub fn new(cratename: String, libs: SearchPaths, externs: core::Externs, + pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: core::Externs, use_headers: bool, opts: TestOptions) -> Collector { Collector { tests: Vec::new(), names: Vec::new(), + cfgs: cfgs, libs: libs, externs: externs, cnt: 0, @@ -384,6 +388,7 @@ impl Collector { format!("{}_{}", self.names.join("::"), self.cnt) }; self.cnt += 1; + let cfgs = self.cfgs.clone(); let libs = self.libs.clone(); let externs = self.externs.clone(); let cratename = self.cratename.to_string(); @@ -399,6 +404,7 @@ impl Collector { testfn: testing::DynTestFn(Box::new(move|| { runtest(&test, &cratename, + cfgs, libs, externs, should_panic, diff --git a/src/test/rustdoc/issue-30252.rs b/src/test/rustdoc/issue-30252.rs new file mode 100644 index 0000000000000..11d161fe188e9 --- /dev/null +++ b/src/test/rustdoc/issue-30252.rs @@ -0,0 +1,16 @@ +// Copyright 2015 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. + +// compile-flags:--test --cfg feature="bar" + +/// ```rust +/// assert_eq!(cfg!(feature = "bar"), true); +/// ``` +pub fn foo() {} From 9a0ab50ac08a01cea1d4170fa90dc851f42971c7 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Tue, 15 Dec 2015 16:15:59 +0100 Subject: [PATCH 6/6] Stop re-exporting RestrictionResult variants. --- .../borrowck/gather_loans/mod.rs | 6 +++-- .../borrowck/gather_loans/restrictions.rs | 22 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 47f29a26db145..c07a27043c275 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -33,6 +33,8 @@ use rustc_front::hir::{Expr, FnDecl, Block, Pat}; use rustc_front::intravisit; use rustc_front::intravisit::Visitor; +use self::restrictions::RestrictionResult; + mod lifetime; mod restrictions; mod gather_moves; @@ -354,12 +356,12 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { // Create the loan record (if needed). let loan = match restr { - restrictions::Safe => { + RestrictionResult::Safe => { // No restrictions---no loan record necessary return; } - restrictions::SafeIf(loan_path, restricted_paths) => { + RestrictionResult::SafeIf(loan_path, restricted_paths) => { let loan_scope = match loan_region { ty::ReScope(scope) => scope, diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index cb75180b47466..2a0d8ef276648 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -10,8 +10,6 @@ //! Computes the restrictions that result from a borrow. -pub use self::RestrictionResult::*; - use borrowck::*; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; @@ -69,19 +67,19 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { // are inherently non-aliasable, they can only be // accessed later through the borrow itself and hence // must inherently comply with its terms. - Safe + RestrictionResult::Safe } Categorization::Local(local_id) => { // R-Variable, locally declared let lp = new_lp(LpVar(local_id)); - SafeIf(lp.clone(), vec![lp]) + RestrictionResult::SafeIf(lp.clone(), vec![lp]) } Categorization::Upvar(mc::Upvar { id, .. }) => { // R-Variable, captured into closure let lp = new_lp(LpUpvar(id)); - SafeIf(lp.clone(), vec![lp]) + RestrictionResult::SafeIf(lp.clone(), vec![lp]) } Categorization::Downcast(cmt_base, _) => { @@ -106,7 +104,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { } Categorization::StaticItem => { - Safe + RestrictionResult::Safe } Categorization::Deref(cmt_base, _, pk) => { @@ -133,11 +131,11 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { cmt: cmt_base, code: err_borrowed_pointer_too_short( self.loan_region, lt)}); - return Safe; + return RestrictionResult::Safe; } match bk { - ty::ImmBorrow => Safe, + ty::ImmBorrow => RestrictionResult::Safe, ty::MutBorrow | ty::UniqueImmBorrow => { // R-Deref-Mut-Borrowed // @@ -150,7 +148,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { } } // Borrowck is not relevant for raw pointers - mc::UnsafePtr(..) => Safe + mc::UnsafePtr(..) => RestrictionResult::Safe } } } @@ -161,12 +159,12 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { cmt: &mc::cmt<'tcx>, elem: LoanPathElem) -> RestrictionResult<'tcx> { match result { - Safe => Safe, - SafeIf(base_lp, mut base_vec) => { + RestrictionResult::Safe => RestrictionResult::Safe, + RestrictionResult::SafeIf(base_lp, mut base_vec) => { let v = LpExtend(base_lp, cmt.mutbl, elem); let lp = Rc::new(LoanPath::new(v, cmt.ty)); base_vec.push(lp.clone()); - SafeIf(lp, base_vec) + RestrictionResult::SafeIf(lp, base_vec) } } }