From bd10ef7b27e7c6ab6e4e68898aa6ccd240fc57f3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 10 Feb 2018 09:54:27 -0500 Subject: [PATCH 01/35] rustc_typeck/check/closure: rustfmt --- src/librustc_typeck/check/closure.rs | 51 +++++++++++++++------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index df15f781ae8c9..5e9c283a0c6e8 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -42,8 +42,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ) -> Ty<'tcx> { debug!( "check_expr_closure(expr={:?},expected={:?})", - expr, - expected + expr, expected ); // It's always helpful for inference if we know the kind of @@ -68,8 +67,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ) -> Ty<'tcx> { debug!( "check_closure(opt_kind={:?}, expected_sig={:?})", - opt_kind, - expected_sig + opt_kind, expected_sig ); let expr_def_id = self.tcx.hir.local_def_id(expr.id); @@ -109,19 +107,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let closure_type = self.tcx.mk_closure(expr_def_id, substs); if let Some(GeneratorTypes { yield_ty, interior }) = generator_types { - self.demand_eqtype(expr.span, - yield_ty, - substs.generator_yield_ty(expr_def_id, self.tcx)); - self.demand_eqtype(expr.span, - liberated_sig.output(), - substs.generator_return_ty(expr_def_id, self.tcx)); + self.demand_eqtype( + expr.span, + yield_ty, + substs.generator_yield_ty(expr_def_id, self.tcx), + ); + self.demand_eqtype( + expr.span, + liberated_sig.output(), + substs.generator_return_ty(expr_def_id, self.tcx), + ); return self.tcx.mk_generator(expr_def_id, substs, interior); } debug!( "check_closure: expr.id={:?} closure_type={:?}", - expr.id, - closure_type + expr.id, closure_type ); // Tuple up the arguments and insert the resulting function type into @@ -138,20 +139,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!( "check_closure: expr_def_id={:?}, sig={:?}, opt_kind={:?}", - expr_def_id, - sig, - opt_kind + expr_def_id, sig, opt_kind ); let sig_fn_ptr_ty = self.tcx.mk_fn_ptr(sig); - self.demand_eqtype(expr.span, - sig_fn_ptr_ty, - substs.closure_sig_ty(expr_def_id, self.tcx)); + self.demand_eqtype( + expr.span, + sig_fn_ptr_ty, + substs.closure_sig_ty(expr_def_id, self.tcx), + ); if let Some(kind) = opt_kind { - self.demand_eqtype(expr.span, - kind.to_ty(self.tcx), - substs.closure_kind_ty(expr_def_id, self.tcx)); + self.demand_eqtype( + expr.span, + kind.to_ty(self.tcx), + substs.closure_kind_ty(expr_def_id, self.tcx), + ); } closure_type @@ -314,8 +317,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let self_ty = self.shallow_resolve(trait_ref.self_ty()); debug!( "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})", - trait_ref, - self_ty + trait_ref, self_ty ); match self_ty.sty { ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref), @@ -564,7 +566,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { body: &hir::Body, bound_sig: ty::PolyFnSig<'tcx>, ) -> ClosureSignatures<'tcx> { - let liberated_sig = self.tcx().liberate_late_bound_regions(expr_def_id, &bound_sig); + let liberated_sig = self.tcx() + .liberate_late_bound_regions(expr_def_id, &bound_sig); let liberated_sig = self.inh.normalize_associated_types_in( body.value.span, body.value.id, From cc05561048f07ae5e99b25bbe5db04eebe0c7cd2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 12 Feb 2018 16:00:15 -0500 Subject: [PATCH 02/35] detect wrong number of args when type-checking a closure Instead of creating inference variables for those argument types, use the trait error-reporting code to give a nicer error. --- src/librustc/traits/error_reporting.rs | 42 +++++- src/librustc/traits/mod.rs | 2 +- src/librustc_typeck/check/closure.rs | 131 +++++++++++++++--- ...ure-arg-count-expected-type-issue-47244.rs | 29 ++++ ...arg-count-expected-type-issue-47244.stderr | 14 ++ 5 files changed, 191 insertions(+), 27 deletions(-) create mode 100644 src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.rs create mode 100644 src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.stderr diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index a290839425ebe..f3aab4020594b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -747,7 +747,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyTuple(ref tys, _) => tys.iter() .map(|t| match t.sty { ty::TypeVariants::TyTuple(ref tys, _) => ArgKind::Tuple( - span, + Some(span), tys.iter() .map(|ty| ("_".to_owned(), format!("{}", ty.sty))) .collect::>() @@ -815,7 +815,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - fn get_fn_like_arguments(&self, node: hir::map::Node) -> (Span, Vec) { + /// Given some node representing a fn-like thing in the HIR map, + /// returns a span and `ArgKind` information that describes the + /// arguments it expects. This can be supplied to + /// `report_arg_count_mismatch`. + pub fn get_fn_like_arguments(&self, node: hir::map::Node) -> (Span, Vec) { match node { hir::map::NodeExpr(&hir::Expr { node: hir::ExprClosure(_, ref _decl, id, span, _), @@ -829,7 +833,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .. } = arg.pat.clone().into_inner() { ArgKind::Tuple( - span, + Some(span), args.iter().map(|pat| { let snippet = self.tcx.sess.codemap() .span_to_snippet(pat.span).unwrap(); @@ -862,7 +866,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { (self.tcx.sess.codemap().def_span(span), decl.inputs.iter() .map(|arg| match arg.clone().into_inner().node { hir::TyTup(ref tys) => ArgKind::Tuple( - arg.span, + Some(arg.span), tys.iter() .map(|_| ("_".to_owned(), "_".to_owned())) .collect::>(), @@ -874,7 +878,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - fn report_arg_count_mismatch( + /// Reports an error when the number of arguments needed by a + /// trait match doesn't match the number that the expression + /// provides. + pub fn report_arg_count_mismatch( &self, span: Span, found_span: Option, @@ -1363,13 +1370,34 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -enum ArgKind { +/// Summarizes information +pub enum ArgKind { + /// An argument of non-tuple type. Parameters are (name, ty) Arg(String, String), - Tuple(Span, Vec<(String, String)>), + + /// An argument of tuple type. For a "found" argument, the span is + /// the locationo in the source of the pattern. For a "expected" + /// argument, it will be None. The vector is a list of (name, ty) + /// strings for the components of the tuple. + Tuple(Option, Vec<(String, String)>), } impl ArgKind { fn empty() -> ArgKind { ArgKind::Arg("_".to_owned(), "_".to_owned()) } + + /// Creates an `ArgKind` from the expected type of an + /// argument. This has no name (`_`) and no source spans.. + pub fn from_expected_ty(t: Ty<'_>) -> ArgKind { + match t.sty { + ty::TyTuple(ref tys, _) => ArgKind::Tuple( + None, + tys.iter() + .map(|ty| ("_".to_owned(), format!("{}", ty.sty))) + .collect::>() + ), + _ => ArgKind::Arg("_".to_owned(), format!("{}", t.sty)), + } + } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 80819a86b7c46..a80e91df03de1 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -49,7 +49,7 @@ pub use self::util::SupertraitDefIds; pub use self::util::transitive_bounds; mod coherence; -mod error_reporting; +pub mod error_reporting; mod fulfill; mod project; mod object_safety; diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 5e9c283a0c6e8..794d466ee7cdb 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -17,14 +17,24 @@ use rustc::hir::def_id::DefId; use rustc::infer::{InferOk, InferResult}; use rustc::infer::LateBoundRegionConversionTime; use rustc::infer::type_variable::TypeVariableOrigin; +use rustc::traits::error_reporting::ArgKind; use rustc::ty::{self, ToPolyTraitRef, Ty}; use rustc::ty::subst::Substs; use rustc::ty::TypeFoldable; use std::cmp; use std::iter; use syntax::abi::Abi; +use syntax::codemap::Span; use rustc::hir; +/// What signature do we *expect* the closure to have from context? +#[derive(Debug)] +struct ExpectedSig<'tcx> { + /// Span that gave us this expectation, if we know that. + cause_span: Option, + sig: ty::FnSig<'tcx>, +} + struct ClosureSignatures<'tcx> { bound_sig: ty::PolyFnSig<'tcx>, liberated_sig: ty::FnSig<'tcx>, @@ -63,7 +73,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { decl: &'gcx hir::FnDecl, body: &'gcx hir::Body, gen: Option, - expected_sig: Option>, + expected_sig: Option>, ) -> Ty<'tcx> { debug!( "check_closure(opt_kind={:?}, expected_sig={:?})", @@ -160,10 +170,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { closure_type } + /// Given the expected type, figures out what it can about this closure we + /// are about to type check: fn deduce_expectations_from_expected_type( &self, expected_ty: Ty<'tcx>, - ) -> (Option>, Option) { + ) -> (Option>, Option) { debug!( "deduce_expectations_from_expected_type(expected_ty={:?})", expected_ty @@ -175,7 +187,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .projection_bounds() .filter_map(|pb| { let pb = pb.with_self_ty(self.tcx, self.tcx.types.err); - self.deduce_sig_from_projection(&pb) + self.deduce_sig_from_projection(None, &pb) }) .next(); let kind = object_type @@ -184,7 +196,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (sig, kind) } ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid), - ty::TyFnPtr(sig) => (Some(sig.skip_binder().clone()), Some(ty::ClosureKind::Fn)), + ty::TyFnPtr(sig) => { + let expected_sig = ExpectedSig { + cause_span: None, + sig: sig.skip_binder().clone(), + }; + (Some(expected_sig), Some(ty::ClosureKind::Fn)) + } _ => (None, None), } } @@ -192,7 +210,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn deduce_expectations_from_obligations( &self, expected_vid: ty::TyVid, - ) -> (Option>, Option) { + ) -> (Option>, Option) { let fulfillment_cx = self.fulfillment_cx.borrow(); // Here `expected_ty` is known to be a type inference variable. @@ -212,7 +230,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(ref proj_predicate) => { let trait_ref = proj_predicate.to_poly_trait_ref(self.tcx); self.self_type_matches_expected_vid(trait_ref, expected_vid) - .and_then(|_| self.deduce_sig_from_projection(proj_predicate)) + .and_then(|_| { + self.deduce_sig_from_projection( + Some(obligation.cause.span), + proj_predicate, + ) + }) } _ => None, } @@ -262,10 +285,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Given a projection like "::Result == Y", we can deduce /// everything we need to know about a closure. + /// + /// The `cause_span` should be the span that caused us to + /// have this expected signature, or `None` if we can't readily + /// know that. fn deduce_sig_from_projection( &self, + cause_span: Option, projection: &ty::PolyProjectionPredicate<'tcx>, - ) -> Option> { + ) -> Option> { let tcx = self.tcx; debug!("deduce_sig_from_projection({:?})", projection); @@ -297,16 +325,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ret_param_ty ); - let fn_sig = self.tcx.mk_fn_sig( + let sig = self.tcx.mk_fn_sig( input_tys.cloned(), ret_param_ty, false, hir::Unsafety::Normal, Abi::Rust, ); - debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig); + debug!("deduce_sig_from_projection: sig {:?}", sig); - Some(fn_sig) + Some(ExpectedSig { cause_span, sig }) } fn self_type_matches_expected_vid( @@ -330,7 +358,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr_def_id: DefId, decl: &hir::FnDecl, body: &hir::Body, - expected_sig: Option>, + expected_sig: Option>, ) -> ClosureSignatures<'tcx> { if let Some(e) = expected_sig { self.sig_of_closure_with_expectation(expr_def_id, decl, body, e) @@ -406,7 +434,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr_def_id: DefId, decl: &hir::FnDecl, body: &hir::Body, - expected_sig: ty::FnSig<'tcx>, + expected_sig: ExpectedSig<'tcx>, ) -> ClosureSignatures<'tcx> { debug!( "sig_of_closure_with_expectation(expected_sig={:?})", @@ -416,20 +444,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Watch out for some surprises and just ignore the // expectation if things don't see to match up with what we // expect. - if expected_sig.variadic != decl.variadic { - return self.sig_of_closure_no_expectation(expr_def_id, decl, body); - } else if expected_sig.inputs_and_output.len() != decl.inputs.len() + 1 { - // we could probably handle this case more gracefully + if expected_sig.sig.variadic != decl.variadic { return self.sig_of_closure_no_expectation(expr_def_id, decl, body); + } else if expected_sig.sig.inputs_and_output.len() != decl.inputs.len() + 1 { + return self.sig_of_closure_with_mismatched_number_of_arguments( + expr_def_id, + decl, + body, + expected_sig, + ); } // Create a `PolyFnSig`. Note the oddity that late bound // regions appearing free in `expected_sig` are now bound up // in this binder we are creating. - assert!(!expected_sig.has_regions_escaping_depth(1)); + assert!(!expected_sig.sig.has_regions_escaping_depth(1)); let bound_sig = ty::Binder(self.tcx.mk_fn_sig( - expected_sig.inputs().iter().cloned(), - expected_sig.output(), + expected_sig.sig.inputs().iter().cloned(), + expected_sig.sig.output(), decl.variadic, hir::Unsafety::Normal, Abi::RustCall, @@ -455,6 +487,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { closure_sigs } + fn sig_of_closure_with_mismatched_number_of_arguments( + &self, + expr_def_id: DefId, + decl: &hir::FnDecl, + body: &hir::Body, + expected_sig: ExpectedSig<'tcx>, + ) -> ClosureSignatures<'tcx> { + let expr_map_node = self.tcx.hir.get_if_local(expr_def_id).unwrap(); + let expected_args: Vec<_> = expected_sig + .sig + .inputs() + .iter() + .map(|ty| ArgKind::from_expected_ty(ty)) + .collect(); + let (closure_span, found_args) = self.get_fn_like_arguments(expr_map_node); + let expected_span = expected_sig.cause_span.unwrap_or(closure_span); + self.report_arg_count_mismatch( + expected_span, + Some(closure_span), + expected_args, + found_args, + true, + ).emit(); + + let error_sig = self.error_sig_of_closure(decl); + + self.closure_sigs(expr_def_id, body, error_sig) + } + /// Enforce the user's types against the expectation. See /// `sig_of_closure_with_expectation` for details on the overall /// strategy. @@ -560,6 +621,38 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { result } + /// Converts the types that the user supplied, in case that doing + /// so should yield an error, but returns back a signature where + /// all parameters are of type `TyErr`. + fn error_sig_of_closure(&self, decl: &hir::FnDecl) -> ty::PolyFnSig<'tcx> { + let astconv: &AstConv = self; + + let supplied_arguments = decl.inputs.iter().map(|a| { + // Convert the types that the user supplied (if any), but ignore them. + astconv.ast_ty_to_ty(a); + self.tcx.types.err + }); + + match decl.output { + hir::Return(ref output) => { + astconv.ast_ty_to_ty(&output); + } + hir::DefaultReturn(_) => {} + } + + let result = ty::Binder(self.tcx.mk_fn_sig( + supplied_arguments, + self.tcx.types.err, + decl.variadic, + hir::Unsafety::Normal, + Abi::RustCall, + )); + + debug!("supplied_sig_of_closure: result={:?}", result); + + result + } + fn closure_sigs( &self, expr_def_id: DefId, diff --git a/src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.rs b/src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.rs new file mode 100644 index 0000000000000..b6463ca067b7f --- /dev/null +++ b/src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.rs @@ -0,0 +1,29 @@ +// 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. + +// Regression test for #47244: in this specific scenario, when the +// expected type indicated 1 argument but the closure takes two, we +// would (early on) create type variables for the type of `b`. If the +// user then attempts to invoke a method on `b`, we would get an error +// saying that the type of `b` must be known, which was not very +// helpful. + +use std::collections::HashMap; +fn main() { + + let m = HashMap::new(); + m.insert( "foo", "bar" ); + + m.iter().map( |_, b| { + //~^ ERROR closure is expected to take a single 2-tuple + + b.to_string() + }); +} diff --git a/src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.stderr b/src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.stderr new file mode 100644 index 0000000000000..34934b8d19598 --- /dev/null +++ b/src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.stderr @@ -0,0 +1,14 @@ +error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments + --> $DIR/closure-arg-count-expected-type-issue-47244.rs:24:14 + | +24 | m.iter().map( |_, b| { + | ^^^ ------ takes 2 distinct arguments + | | + | expected closure that takes a single 2-tuple as argument +help: change the closure to accept a tuple instead of individual arguments + | +24 | m.iter().map( |(_, b)| { + | ^^^^^^^^ + +error: aborting due to previous error + From 3118cbe41c7ce50c3451fd4575ca04a83b0d3e05 Mon Sep 17 00:00:00 2001 From: bobtwinkles Date: Tue, 13 Feb 2018 20:28:10 -0500 Subject: [PATCH 03/35] Allow two-phase borrows of &mut self in ops We need two-phase borrows of ops to be in the initial NLL release since without them lots of existing code will break. Fixes #48129 --- src/librustc_typeck/check/op.rs | 14 +++-- .../borrowck/two-phase-nonrecv-autoref.rs | 53 ------------------- .../run-pass/borrowck/two-phase-bin-ops.rs | 49 +++++++++++++++++ 3 files changed, 55 insertions(+), 61 deletions(-) create mode 100644 src/test/run-pass/borrowck/two-phase-bin-ops.rs diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index a6776a0fe8612..a3dbf344ab7e0 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -201,10 +201,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mutbl = match mt.mutbl { hir::MutImmutable => AutoBorrowMutability::Immutable, hir::MutMutable => AutoBorrowMutability::Mutable { - // For initial two-phase borrow - // deployment, conservatively omit - // overloaded binary ops. - allow_two_phase_borrow: false, + // Allow two-phase borrows for binops in initial deployment + // since they desugar to methods + allow_two_phase_borrow: true, } }; let autoref = Adjustment { @@ -219,10 +218,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mutbl = match mt.mutbl { hir::MutImmutable => AutoBorrowMutability::Immutable, hir::MutMutable => AutoBorrowMutability::Mutable { - // For initial two-phase borrow - // deployment, conservatively omit - // overloaded binary ops. - allow_two_phase_borrow: false, + // Allow two-phase borrows for binops in initial deployment + // since they desugar to methods + allow_two_phase_borrow: true, } }; let autoref = Adjustment { diff --git a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs index 795d45a776db5..a57e2fe1cc6d3 100644 --- a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs +++ b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs @@ -30,8 +30,6 @@ // #![feature(rustc_attrs)] use std::ops::{Index, IndexMut}; -use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; -use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; // This is case outlined by Niko that we want to ensure we reject // (at least initially). @@ -186,56 +184,6 @@ fn coerce_index_op() { //[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502] } -struct A(i32); - -macro_rules! trivial_binop { - ($Trait:ident, $m:ident) => { - impl $Trait for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } } - } -} - -trivial_binop!(AddAssign, add_assign); -trivial_binop!(SubAssign, sub_assign); -trivial_binop!(MulAssign, mul_assign); -trivial_binop!(DivAssign, div_assign); -trivial_binop!(RemAssign, rem_assign); -trivial_binop!(BitAndAssign, bitand_assign); -trivial_binop!(BitOrAssign, bitor_assign); -trivial_binop!(BitXorAssign, bitxor_assign); -trivial_binop!(ShlAssign, shl_assign); -trivial_binop!(ShrAssign, shr_assign); - -fn overloaded_binops() { - let mut a = A(10); - a += a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a -= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a *= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a /= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a &= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a |= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a ^= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a <<= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a >>= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed -} - fn main() { // As a reminder, this is the basic case we want to ensure we handle. @@ -256,5 +204,4 @@ fn main() { coerce_unsized(); coerce_index_op(); - overloaded_binops(); } diff --git a/src/test/run-pass/borrowck/two-phase-bin-ops.rs b/src/test/run-pass/borrowck/two-phase-bin-ops.rs new file mode 100644 index 0000000000000..9bded41e1f933 --- /dev/null +++ b/src/test/run-pass/borrowck/two-phase-bin-ops.rs @@ -0,0 +1,49 @@ +// Copyright 2018 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. + +// revisions: lxl nll +//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows + +#![cfg_attr(nll, feature(nll))] + +use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; +use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; + +struct A(i32); + +macro_rules! trivial_binop { + ($Trait:ident, $m:ident) => { + impl $Trait for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } } + } +} + +trivial_binop!(AddAssign, add_assign); +trivial_binop!(SubAssign, sub_assign); +trivial_binop!(MulAssign, mul_assign); +trivial_binop!(DivAssign, div_assign); +trivial_binop!(RemAssign, rem_assign); +trivial_binop!(BitAndAssign, bitand_assign); +trivial_binop!(BitOrAssign, bitor_assign); +trivial_binop!(BitXorAssign, bitxor_assign); +trivial_binop!(ShlAssign, shl_assign); +trivial_binop!(ShrAssign, shr_assign); + +fn main() { + let mut a = A(10); + a += a.0; + a -= a.0; + a *= a.0; + a /= a.0; + a &= a.0; + a |= a.0; + a ^= a.0; + a <<= a.0; + a >>= a.0; +} From 75f72c0de141573eef56f13fd48a3af12deaee4f Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Thu, 8 Feb 2018 15:40:27 -0800 Subject: [PATCH 04/35] Make nested impl Trait a hard error --- src/librustc_passes/ast_validation.rs | 69 ++++++++++++++++++ src/librustc_passes/diagnostics.rs | 1 + src/libsyntax/feature_gate.rs | 70 +------------------ .../compile-fail/impl-trait/where-allowed.rs | 4 +- src/test/run-pass/impl-trait/lifetimes.rs | 11 ++- src/test/ui/error-codes/E0657.rs | 6 +- .../nested_impl_trait.rs} | 10 +-- src/test/ui/nested_impl_trait.stderr | 50 +++++++++++++ 8 files changed, 138 insertions(+), 83 deletions(-) rename src/test/{compile-fail/feature-gate-nested_impl_trait.rs => ui/nested_impl_trait.rs} (80%) create mode 100644 src/test/ui/nested_impl_trait.stderr diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 6971033c8994b..826f27c2ddbf4 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -420,6 +420,75 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } +// Bans nested `impl Trait`, e.g. `impl Into`. +// Nested `impl Trait` _is_ allowed in associated type position, +// e.g `impl Iterator` +struct NestedImplTraitVisitor<'a> { + session: &'a Session, + outer_impl_trait: Option, +} + +impl<'a> NestedImplTraitVisitor<'a> { + fn with_impl_trait(&mut self, outer_impl_trait: Option, f: F) + where F: FnOnce(&mut NestedImplTraitVisitor<'a>) + { + let old_outer_impl_trait = self.outer_impl_trait; + self.outer_impl_trait = outer_impl_trait; + f(self); + self.outer_impl_trait = old_outer_impl_trait; + } +} + + +impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { + fn visit_ty(&mut self, t: &'a Ty) { + if let TyKind::ImplTrait(_) = t.node { + if let Some(outer_impl_trait) = self.outer_impl_trait { + struct_span_err!(self.session, t.span, E0666, + "nested `impl Trait` is not allowed") + .span_label(outer_impl_trait, "outer `impl Trait`") + .span_label(t.span, "devilishly nested `impl Trait` here") + .emit(); + + } + self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)); + } else { + visit::walk_ty(self, t); + } + } + fn visit_path_parameters(&mut self, _: Span, path_parameters: &'a PathParameters) { + match *path_parameters { + PathParameters::AngleBracketed(ref params) => { + for type_ in ¶ms.types { + self.visit_ty(type_); + } + for type_binding in ¶ms.bindings { + // Type bindings such as `Item=impl Debug` in `Iterator` + // are allowed to contain nested `impl Trait`. + self.with_impl_trait(None, |this| visit::walk_ty(this, &type_binding.ty)); + } + } + PathParameters::Parenthesized(ref params) => { + for type_ in ¶ms.inputs { + self.visit_ty(type_); + } + if let Some(ref type_) = params.output { + // `-> Foo` syntax is essentially an associated type binding, + // so it is also allowed to contain nested `impl Trait`. + self.with_impl_trait(None, |this| visit::walk_ty(this, type_)); + } + } + } + } +} + + pub fn check_crate(session: &Session, krate: &Crate) { + visit::walk_crate( + &mut NestedImplTraitVisitor { + session, + outer_impl_trait: None, + }, krate); + visit::walk_crate(&mut AstValidator { session: session }, krate) } diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 743f7b7326e9e..6dfc52f842e16 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -320,4 +320,5 @@ register_diagnostics! { E0567, // auto traits can not have generic parameters E0568, // auto traits can not have super traits E0642, // patterns aren't allowed in methods without bodies + E0666, // nested `impl Trait` is illegal } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ea916d5168c33..a3eba63706cb0 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -432,9 +432,6 @@ declare_features! ( // `foo.rs` as an alternative to `foo/mod.rs` (active, non_modrs_mods, "1.24.0", Some(44660)), - // Nested `impl Trait` - (active, nested_impl_trait, "1.24.0", Some(34511)), - // Termination trait in main (RFC 1937) (active, termination_trait, "1.24.0", Some(43301)), @@ -1352,73 +1349,8 @@ fn contains_novel_literal(item: &ast::MetaItem) -> bool { } } -// Bans nested `impl Trait`, e.g. `impl Into`. -// Nested `impl Trait` _is_ allowed in associated type position, -// e.g `impl Iterator` -struct NestedImplTraitVisitor<'a> { - context: &'a Context<'a>, - is_in_impl_trait: bool, -} - -impl<'a> NestedImplTraitVisitor<'a> { - fn with_impl_trait(&mut self, is_in_impl_trait: bool, f: F) - where F: FnOnce(&mut NestedImplTraitVisitor<'a>) - { - let old_is_in_impl_trait = self.is_in_impl_trait; - self.is_in_impl_trait = is_in_impl_trait; - f(self); - self.is_in_impl_trait = old_is_in_impl_trait; - } -} - - -impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { - fn visit_ty(&mut self, t: &'a ast::Ty) { - if let ast::TyKind::ImplTrait(_) = t.node { - if self.is_in_impl_trait { - gate_feature_post!(&self, nested_impl_trait, t.span, - "nested `impl Trait` is experimental" - ); - } - self.with_impl_trait(true, |this| visit::walk_ty(this, t)); - } else { - visit::walk_ty(self, t); - } - } - fn visit_path_parameters(&mut self, _: Span, path_parameters: &'a ast::PathParameters) { - match *path_parameters { - ast::PathParameters::AngleBracketed(ref params) => { - for type_ in ¶ms.types { - self.visit_ty(type_); - } - for type_binding in ¶ms.bindings { - // Type bindings such as `Item=impl Debug` in `Iterator` - // are allowed to contain nested `impl Trait`. - self.with_impl_trait(false, |this| visit::walk_ty(this, &type_binding.ty)); - } - } - ast::PathParameters::Parenthesized(ref params) => { - for type_ in ¶ms.inputs { - self.visit_ty(type_); - } - if let Some(ref type_) = params.output { - // `-> Foo` syntax is essentially an associated type binding, - // so it is also allowed to contain nested `impl Trait`. - self.with_impl_trait(false, |this| visit::walk_ty(this, type_)); - } - } - } - } -} - impl<'a> PostExpansionVisitor<'a> { - fn whole_crate_feature_gates(&mut self, krate: &ast::Crate) { - visit::walk_crate( - &mut NestedImplTraitVisitor { - context: self.context, - is_in_impl_trait: false, - }, krate); - + fn whole_crate_feature_gates(&mut self, _krate: &ast::Crate) { for &(ident, span) in &*self.context.parse_sess.non_modrs_mods.borrow() { if !span.allows_unstable() { let cx = &self.context; diff --git a/src/test/compile-fail/impl-trait/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs index a9fe1e04664e9..52c5471681df3 100644 --- a/src/test/compile-fail/impl-trait/where-allowed.rs +++ b/src/test/compile-fail/impl-trait/where-allowed.rs @@ -10,7 +10,7 @@ //! A simple test for testing many permutations of allowedness of //! impl Trait -#![feature(conservative_impl_trait, nested_impl_trait, universal_impl_trait, dyn_trait)] +#![feature(conservative_impl_trait, universal_impl_trait, dyn_trait)] use std::fmt::Debug; // Allowed @@ -60,6 +60,7 @@ fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } // Disallowed fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +//~^^ ERROR nested `impl Trait` is not allowed // Disallowed fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } @@ -68,6 +69,7 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } // Disallowed fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +//~^^ ERROR nested `impl Trait` is not allowed // Disallowed fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs index 1f2d76f289472..4d40e707ddcb9 100644 --- a/src/test/run-pass/impl-trait/lifetimes.rs +++ b/src/test/run-pass/impl-trait/lifetimes.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, underscore_lifetimes, universal_impl_trait, nested_impl_trait)] +#![feature(conservative_impl_trait, underscore_lifetimes, universal_impl_trait)] #![allow(warnings)] use std::fmt::Debug; @@ -55,12 +55,11 @@ fn pass_through_elision_with_fn_ptr(x: &fn(&u32) -> &u32) -> impl Into<&fn(&u32) fn pass_through_elision_with_fn_path &u32>( x: &T -) -> impl Into<&impl Fn(&u32) -> &u32> { x } +) -> &impl Fn(&u32) -> &u32 { x } -fn foo(x: &impl Debug) -> impl Into<&impl Debug> { x } -fn foo_explicit_lifetime<'a>(x: &'a impl Debug) -> impl Into<&'a impl Debug> { x } -fn foo_no_outer_impl(x: &impl Debug) -> &impl Debug { x } -fn foo_explicit_arg(x: &T) -> impl Into<&impl Debug> { x } +fn foo(x: &impl Debug) -> &impl Debug { x } +fn foo_explicit_lifetime<'a>(x: &'a impl Debug) -> &'a impl Debug { x } +fn foo_explicit_arg(x: &T) -> &impl Debug { x } fn mixed_lifetimes<'a>() -> impl for<'b: 'a> Fn(&'b u32) { |_| () } fn mixed_as_static() -> impl Fn(&'static u32) { mixed_lifetimes() } diff --git a/src/test/ui/error-codes/E0657.rs b/src/test/ui/error-codes/E0657.rs index 4595e413081a5..31b3acd86ef55 100644 --- a/src/test/ui/error-codes/E0657.rs +++ b/src/test/ui/error-codes/E0657.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(warnings)] -#![feature(conservative_impl_trait, nested_impl_trait)] +#![feature(conservative_impl_trait)] trait Id {} trait Lt<'a> {} @@ -17,7 +17,7 @@ impl<'a> Lt<'a> for () {} impl Id for T {} fn free_fn_capture_hrtb_in_impl_trait() - -> impl for<'a> Id> + -> Box Id>> //~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level [E0657] { () @@ -26,7 +26,7 @@ fn free_fn_capture_hrtb_in_impl_trait() struct Foo; impl Foo { fn impl_fn_capture_hrtb_in_impl_trait() - -> impl for<'a> Id> + -> Box Id>> //~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level { () diff --git a/src/test/compile-fail/feature-gate-nested_impl_trait.rs b/src/test/ui/nested_impl_trait.rs similarity index 80% rename from src/test/compile-fail/feature-gate-nested_impl_trait.rs rename to src/test/ui/nested_impl_trait.rs index 7c35263d05dd7..f6302c0f3b3e2 100644 --- a/src/test/compile-fail/feature-gate-nested_impl_trait.rs +++ b/src/test/ui/nested_impl_trait.rs @@ -14,18 +14,19 @@ use std::fmt::Debug; fn fine(x: impl Into) -> impl Into { x } fn bad_in_ret_position(x: impl Into) -> impl Into { x } -//~^ ERROR nested `impl Trait` is experimental +//~^ ERROR nested `impl Trait` is not allowed fn bad_in_fn_syntax(x: fn() -> impl Into) {} -//~^ ERROR nested `impl Trait` is experimental +//~^ ERROR nested `impl Trait` is not allowed +//~^^ `impl Trait` not allowed fn bad_in_arg_position(_: impl Into) { } -//~^ ERROR nested `impl Trait` is experimental +//~^ ERROR nested `impl Trait` is not allowed struct X; impl X { fn bad(x: impl Into) -> impl Into { x } - //~^ ERROR nested `impl Trait` is experimental + //~^ ERROR nested `impl Trait` is not allowed } fn allowed_in_assoc_type() -> impl Iterator { @@ -33,6 +34,7 @@ fn allowed_in_assoc_type() -> impl Iterator { } fn allowed_in_ret_type() -> impl Fn() -> impl Into { +//~^ `impl Trait` not allowed || 5 } diff --git a/src/test/ui/nested_impl_trait.stderr b/src/test/ui/nested_impl_trait.stderr new file mode 100644 index 0000000000000..6649f9ab99cc1 --- /dev/null +++ b/src/test/ui/nested_impl_trait.stderr @@ -0,0 +1,50 @@ +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:16:56 + | +16 | fn bad_in_ret_position(x: impl Into) -> impl Into { x } + | ----------^^^^^^^^^^- + | | | + | | devilishly nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:19:42 + | +19 | fn bad_in_fn_syntax(x: fn() -> impl Into) {} + | ----------^^^^^^^^^^- + | | | + | | devilishly nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:23:37 + | +23 | fn bad_in_arg_position(_: impl Into) { } + | ----------^^^^^^^^^^- + | | | + | | devilishly nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:28:44 + | +28 | fn bad(x: impl Into) -> impl Into { x } + | ----------^^^^^^^^^^- + | | | + | | devilishly nested `impl Trait` here + | outer `impl Trait` + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/nested_impl_trait.rs:19:32 + | +19 | fn bad_in_fn_syntax(x: fn() -> impl Into) {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/nested_impl_trait.rs:36:42 + | +36 | fn allowed_in_ret_type() -> impl Fn() -> impl Into { + | ^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + From 70e1f4fc6d951dfc0547ff5acb3d8780d16635e6 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Thu, 8 Feb 2018 16:50:14 -0800 Subject: [PATCH 05/35] Disallow projections from impl Trait types --- src/librustc_passes/ast_validation.rs | 68 ++++++++++++++++++++++- src/librustc_passes/diagnostics.rs | 1 + src/test/ui/impl_trait_projections.rs | 43 ++++++++++++++ src/test/ui/impl_trait_projections.stderr | 28 ++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/impl_trait_projections.rs create mode 100644 src/test/ui/impl_trait_projections.stderr diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 826f27c2ddbf4..14ea5c0ce7982 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -447,7 +447,7 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { struct_span_err!(self.session, t.span, E0666, "nested `impl Trait` is not allowed") .span_label(outer_impl_trait, "outer `impl Trait`") - .span_label(t.span, "devilishly nested `impl Trait` here") + .span_label(t.span, "nested `impl Trait` here") .emit(); } @@ -482,6 +482,66 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { } } +// Bans `impl Trait` in path projections like `::Item` or `Foo::Bar`. +struct ImplTraitProjectionVisitor<'a> { + session: &'a Session, + is_banned: bool, +} + +impl<'a> ImplTraitProjectionVisitor<'a> { + fn with_ban(&mut self, f: F) + where F: FnOnce(&mut ImplTraitProjectionVisitor<'a>) + { + let old_is_banned = self.is_banned; + self.is_banned = true; + f(self); + self.is_banned = old_is_banned; + } +} + +impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> { + fn visit_ty(&mut self, t: &'a Ty) { + match t.node { + TyKind::ImplTrait(_) => { + if self.is_banned { + struct_span_err!(self.session, t.span, E0667, + "`impl Trait` is not allowed in path parameters") + .emit(); + } + } + TyKind::Path(ref qself, ref path) => { + // We allow these: + // - `Option` + // - `option::Option` + // - `option::Option::Foo + // + // But not these: + // - `::Foo` + // - `option::Option::Foo`. + // + // To implement this, we disallow `impl Trait` from `qself` + // (for cases like `::Foo>`) + // but we allow `impl Trait` in `PathParameters` + // iff there are no more PathSegments. + if let Some(ref qself) = *qself { + // `impl Trait` in `qself` is always illegal + self.with_ban(|this| this.visit_ty(&qself.ty)); + } + + for (i, segment) in path.segments.iter().enumerate() { + // Allow `impl Trait` iff we're on the final path segment + if i == (path.segments.len() - 1) { + visit::walk_path_segment(self, path.span, segment); + } else { + self.with_ban(|this| + visit::walk_path_segment(this, path.span, segment)); + } + } + } + _ => visit::walk_ty(self, t), + } + } +} pub fn check_crate(session: &Session, krate: &Crate) { visit::walk_crate( @@ -490,5 +550,11 @@ pub fn check_crate(session: &Session, krate: &Crate) { outer_impl_trait: None, }, krate); + visit::walk_crate( + &mut ImplTraitProjectionVisitor { + session, + is_banned: false, + }, krate); + visit::walk_crate(&mut AstValidator { session: session }, krate) } diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 6dfc52f842e16..980808a6905c1 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -321,4 +321,5 @@ register_diagnostics! { E0568, // auto traits can not have super traits E0642, // patterns aren't allowed in methods without bodies E0666, // nested `impl Trait` is illegal + E0667, // `impl Trait` in projections } diff --git a/src/test/ui/impl_trait_projections.rs b/src/test/ui/impl_trait_projections.rs new file mode 100644 index 0000000000000..e34b7799fb724 --- /dev/null +++ b/src/test/ui/impl_trait_projections.rs @@ -0,0 +1,43 @@ +// Copyright 2018 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(conservative_impl_trait, universal_impl_trait)] + +use std::fmt::Debug; +use std::option; + +fn parametrized_type_is_allowed() -> Option { + Some(5i32) +} + +fn path_parametrized_type_is_allowed() -> option::Option { + Some(5i32) +} + +fn projection_is_disallowed(x: impl Iterator) -> ::Item { +//~^ ERROR `impl Trait` is not allowed in path parameters +//~^^ ERROR ambiguous associated type + x.next().unwrap() +} + +fn projection_with_named_trait_is_disallowed(x: impl Iterator) + -> ::Item +//~^ ERROR `impl Trait` is not allowed in path parameters +{ + x.next().unwrap() +} + +fn projection_with_named_trait_inside_path_is_disallowed() + -> <::std::ops::Range as Iterator>::Item +//~^ ERROR `impl Trait` is not allowed in path parameters +{ + (1i32..100).next().unwrap() +} + +fn main() {} diff --git a/src/test/ui/impl_trait_projections.stderr b/src/test/ui/impl_trait_projections.stderr new file mode 100644 index 0000000000000..2e8bfc931f82e --- /dev/null +++ b/src/test/ui/impl_trait_projections.stderr @@ -0,0 +1,28 @@ +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:23:51 + | +23 | fn projection_is_disallowed(x: impl Iterator) -> ::Item { + | ^^^^^^^^^^^^^ + +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:30:9 + | +30 | -> ::Item + | ^^^^^^^^^^^^^ + +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:37:27 + | +37 | -> <::std::ops::Range as Iterator>::Item + | ^^^^^^^^^^ + +error[E0223]: ambiguous associated type + --> $DIR/impl_trait_projections.rs:23:50 + | +23 | fn projection_is_disallowed(x: impl Iterator) -> ::Item { + | ^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type + | + = note: specify the type using the syntax `::Item` + +error: aborting due to 4 previous errors + From f1fbf79223aca762c42c6674d125c4c5223f9949 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 13 Feb 2018 17:46:33 -0800 Subject: [PATCH 06/35] Amend nested impl Trait error message --- src/test/ui/nested_impl_trait.stderr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/ui/nested_impl_trait.stderr b/src/test/ui/nested_impl_trait.stderr index 6649f9ab99cc1..094926120cdee 100644 --- a/src/test/ui/nested_impl_trait.stderr +++ b/src/test/ui/nested_impl_trait.stderr @@ -4,7 +4,7 @@ error[E0666]: nested `impl Trait` is not allowed 16 | fn bad_in_ret_position(x: impl Into) -> impl Into { x } | ----------^^^^^^^^^^- | | | - | | devilishly nested `impl Trait` here + | | nested `impl Trait` here | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed @@ -13,7 +13,7 @@ error[E0666]: nested `impl Trait` is not allowed 19 | fn bad_in_fn_syntax(x: fn() -> impl Into) {} | ----------^^^^^^^^^^- | | | - | | devilishly nested `impl Trait` here + | | nested `impl Trait` here | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed @@ -22,7 +22,7 @@ error[E0666]: nested `impl Trait` is not allowed 23 | fn bad_in_arg_position(_: impl Into) { } | ----------^^^^^^^^^^- | | | - | | devilishly nested `impl Trait` here + | | nested `impl Trait` here | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed @@ -31,7 +31,7 @@ error[E0666]: nested `impl Trait` is not allowed 28 | fn bad(x: impl Into) -> impl Into { x } | ----------^^^^^^^^^^- | | | - | | devilishly nested `impl Trait` here + | | nested `impl Trait` here | outer `impl Trait` error[E0562]: `impl Trait` not allowed outside of function and inherent method return types From dbacf0c56ba2bd5ed38fc2a2e4bc20150271e7f2 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 13 Feb 2018 17:52:22 -0800 Subject: [PATCH 07/35] Test err on impl Trait projection within dyn Trait --- src/test/ui/impl_trait_projections.rs | 9 ++++++++- src/test/ui/impl_trait_projections.stderr | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/test/ui/impl_trait_projections.rs b/src/test/ui/impl_trait_projections.rs index e34b7799fb724..f69a78b1450f1 100644 --- a/src/test/ui/impl_trait_projections.rs +++ b/src/test/ui/impl_trait_projections.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, universal_impl_trait)] +#![feature(dyn_trait, conservative_impl_trait, universal_impl_trait)] use std::fmt::Debug; use std::option; @@ -40,4 +40,11 @@ fn projection_with_named_trait_inside_path_is_disallowed() (1i32..100).next().unwrap() } +fn projection_from_impl_trait_inside_dyn_trait_is_disallowed() + -> as Iterator>::Item +//~^ ERROR `impl Trait` is not allowed in path parameters +{ + panic!() +} + fn main() {} diff --git a/src/test/ui/impl_trait_projections.stderr b/src/test/ui/impl_trait_projections.stderr index 2e8bfc931f82e..08de0eb99a307 100644 --- a/src/test/ui/impl_trait_projections.stderr +++ b/src/test/ui/impl_trait_projections.stderr @@ -16,6 +16,12 @@ error[E0667]: `impl Trait` is not allowed in path parameters 37 | -> <::std::ops::Range as Iterator>::Item | ^^^^^^^^^^ +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:44:29 + | +44 | -> as Iterator>::Item + | ^^^^^^^^^^ + error[E0223]: ambiguous associated type --> $DIR/impl_trait_projections.rs:23:50 | @@ -24,5 +30,5 @@ error[E0223]: ambiguous associated type | = note: specify the type using the syntax `::Item` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors From 20dcc72127b53e1b7388f430f7ed26144fe5dcf4 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Wed, 14 Feb 2018 11:06:08 +0800 Subject: [PATCH 08/35] inform type annotations --- src/librustc_typeck/check/mod.rs | 4 +--- src/librustc_typeck/diagnostics.rs | 3 ++- .../epoch-raw-pointer-method-2015.rs | 2 +- src/test/compile-fail/issue-15965.rs | 2 +- src/test/compile-fail/issue-2151.rs | 2 +- src/test/compile-fail/match-vec-mismatch.rs | 2 +- src/test/compile-fail/pat-tuple-bad-type.rs | 2 +- .../unboxed-closures-failed-recursive-fn-2.rs | 2 +- src/test/ui/error-codes/E0619.rs | 19 ------------------- src/test/ui/error-codes/E0619.stderr | 8 -------- ...ference-variable-behind-raw-pointer.stderr | 2 +- .../span/issue-42234-unknown-receiver-type.rs | 4 ++-- .../issue-42234-unknown-receiver-type.stderr | 6 +++--- 13 files changed, 15 insertions(+), 43 deletions(-) delete mode 100644 src/test/ui/error-codes/E0619.rs delete mode 100644 src/test/ui/error-codes/E0619.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 165b499cc62aa..e760636230d18 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5086,9 +5086,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If not, error. if alternative.is_ty_var() || alternative.references_error() { if !self.is_tainted_by_errors() { - type_error_struct!(self.tcx.sess, sp, ty, E0619, - "the type of this value must be known in this context") - .emit(); + self.need_type_info((**self).body_id, sp, ty); } self.demand_suptype(sp, self.tcx.types.err, ty); ty = self.tcx.types.err; diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index f59948e9fc42f..1c0e084832ebc 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4368,12 +4368,13 @@ i_am_a_function(); "##, E0619: r##" +#### Note: this error code is no longer emitted by the compiler. The type-checker needed to know the type of an expression, but that type had not yet been inferred. Erroneous code example: -```compile_fail,E0619 +```compile_fail let mut x = vec![]; match x.pop() { Some(v) => { diff --git a/src/test/compile-fail/epoch-raw-pointer-method-2015.rs b/src/test/compile-fail/epoch-raw-pointer-method-2015.rs index a71db040b50e7..6aa83a38b7ee9 100644 --- a/src/test/compile-fail/epoch-raw-pointer-method-2015.rs +++ b/src/test/compile-fail/epoch-raw-pointer-method-2015.rs @@ -18,6 +18,6 @@ fn main() { let x = 0; let y = &x as *const _; let _ = y.is_null(); - //~^ error: the type of this value must be known in this context [tyvar_behind_raw_pointer] + //~^ error: type annotations needed [tyvar_behind_raw_pointer] //~^^ warning: this was previously accepted } diff --git a/src/test/compile-fail/issue-15965.rs b/src/test/compile-fail/issue-15965.rs index 08b896f387bbe..76ba5a0f4b371 100644 --- a/src/test/compile-fail/issue-15965.rs +++ b/src/test/compile-fail/issue-15965.rs @@ -11,7 +11,7 @@ fn main() { return { return () } -//~^ ERROR the type of this value must be known in this context +//~^ ERROR type annotations needed [E0282] () ; } diff --git a/src/test/compile-fail/issue-2151.rs b/src/test/compile-fail/issue-2151.rs index fbd8f9163b5df..3cf971f3f8dfb 100644 --- a/src/test/compile-fail/issue-2151.rs +++ b/src/test/compile-fail/issue-2151.rs @@ -10,5 +10,5 @@ fn main() { let x = panic!(); - x.clone(); //~ ERROR the type of this value must be known in this context + x.clone(); //~ ERROR type annotations needed } diff --git a/src/test/compile-fail/match-vec-mismatch.rs b/src/test/compile-fail/match-vec-mismatch.rs index fed68da006889..998c11979953c 100644 --- a/src/test/compile-fail/match-vec-mismatch.rs +++ b/src/test/compile-fail/match-vec-mismatch.rs @@ -43,6 +43,6 @@ fn main() { fn another_fn_to_avoid_suppression() { match Default::default() { - [] => {} //~ ERROR the type of this value + [] => {} //~ ERROR type annotations needed }; } diff --git a/src/test/compile-fail/pat-tuple-bad-type.rs b/src/test/compile-fail/pat-tuple-bad-type.rs index fd4ab5d253158..251e7b47dcc99 100644 --- a/src/test/compile-fail/pat-tuple-bad-type.rs +++ b/src/test/compile-fail/pat-tuple-bad-type.rs @@ -12,7 +12,7 @@ fn main() { let x; match x { - (..) => {} //~ ERROR the type of this value must be known in this context + (..) => {} //~ ERROR type annotations needed _ => {} } diff --git a/src/test/compile-fail/unboxed-closures-failed-recursive-fn-2.rs b/src/test/compile-fail/unboxed-closures-failed-recursive-fn-2.rs index 12b48b2a6c8aa..8f5bf827fcf1a 100644 --- a/src/test/compile-fail/unboxed-closures-failed-recursive-fn-2.rs +++ b/src/test/compile-fail/unboxed-closures-failed-recursive-fn-2.rs @@ -24,7 +24,7 @@ fn a() { match closure0.take() { Some(c) => { return c(); - //~^ ERROR the type of this value must be known in this context + //~^ ERROR type annotations needed } None => { } } diff --git a/src/test/ui/error-codes/E0619.rs b/src/test/ui/error-codes/E0619.rs deleted file mode 100644 index a5a5ff7218dcf..0000000000000 --- a/src/test/ui/error-codes/E0619.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017 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 x; - - match x { - (..) => {} //~ ERROR E0619 - _ => {} - } -} - diff --git a/src/test/ui/error-codes/E0619.stderr b/src/test/ui/error-codes/E0619.stderr deleted file mode 100644 index cec336cfcec66..0000000000000 --- a/src/test/ui/error-codes/E0619.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error[E0619]: the type of this value must be known in this context - --> $DIR/E0619.rs:15:9 - | -15 | (..) => {} //~ ERROR E0619 - | ^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/inference-variable-behind-raw-pointer.stderr b/src/test/ui/inference-variable-behind-raw-pointer.stderr index d0ee55c092b28..bb1d921f1c61c 100644 --- a/src/test/ui/inference-variable-behind-raw-pointer.stderr +++ b/src/test/ui/inference-variable-behind-raw-pointer.stderr @@ -1,4 +1,4 @@ -warning: the type of this value must be known in this context +warning: type annotations needed --> $DIR/inference-variable-behind-raw-pointer.rs:18:13 | 18 | if data.is_null() {} diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.rs b/src/test/ui/span/issue-42234-unknown-receiver-type.rs index d9cdd99c245e6..975c81955e0b3 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.rs +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.rs @@ -15,11 +15,11 @@ fn shines_a_beacon_through_the_darkness() { let x: Option<_> = None; x.unwrap().method_that_could_exist_on_some_type(); - //~^ ERROR 17:5: 17:15: the type of this value must be known in this context + //~^ ERROR 17:5: 17:15: type annotations needed } fn courier_to_des_moines_and_points_west(data: &[u32]) -> String { - data.iter() //~ ERROR 22:5: 23:20: the type of this value must be known in this context + data.iter() //~ ERROR 22:5: 23:20: type annotations needed .sum::<_>() .to_string() } diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr index ed756cdc553ce..2a85e1f1c45ba 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr @@ -1,13 +1,13 @@ -error[E0619]: the type of this value must be known in this context +error[E0282]: type annotations needed --> $DIR/issue-42234-unknown-receiver-type.rs:17:5 | 17 | x.unwrap().method_that_could_exist_on_some_type(); | ^^^^^^^^^^ -error[E0619]: the type of this value must be known in this context +error[E0282]: type annotations needed --> $DIR/issue-42234-unknown-receiver-type.rs:22:5 | -22 | / data.iter() //~ ERROR 22:5: 23:20: the type of this value must be known in this context +22 | / data.iter() //~ ERROR 22:5: 23:20: type annotations needed 23 | | .sum::<_>() | |___________________^ From d4b847504c2ecf32637486987ac299f91a3d1c54 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Feb 2018 17:40:46 +0100 Subject: [PATCH 09/35] incr.comp.: Store DepNode colors in a dense array instead of a hashmap. --- src/librustc/dep_graph/graph.rs | 148 ++++++++++++++++++++++--------- src/librustc/dep_graph/prev.rs | 5 ++ src/librustc/ty/maps/plumbing.rs | 6 +- 3 files changed, 112 insertions(+), 47 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 55ec8adb5fbf3..b77431e806a6d 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -74,7 +74,7 @@ struct DepGraphData { /// nodes and edges as well as all fingerprints of nodes that have them. previous: PreviousDepGraph, - colors: RefCell>, + colors: RefCell, /// When we load, there may be `.o` files, cached mir, or other such /// things available to us. If we find that they are not dirty, we @@ -97,8 +97,10 @@ impl DepGraph { // Pre-allocate the fingerprints array. We over-allocate a little so // that we hopefully don't have to re-allocate during this compilation // session. + let prev_graph_node_count = prev_graph.node_count(); + let fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, - (prev_graph.node_count() * 115) / 100); + (prev_graph_node_count * 115) / 100); DepGraph { data: Some(Rc::new(DepGraphData { previous_work_products: RefCell::new(FxHashMap()), @@ -106,7 +108,7 @@ impl DepGraph { dep_node_debug: RefCell::new(FxHashMap()), current: RefCell::new(CurrentDepGraph::new()), previous: prev_graph, - colors: RefCell::new(FxHashMap()), + colors: RefCell::new(DepNodeColorMap::new(prev_graph_node_count)), loaded_from_cache: RefCell::new(FxHashMap()), })), fingerprints: Rc::new(RefCell::new(fingerprints)), @@ -213,8 +215,6 @@ impl DepGraph { R: HashStable, { if let Some(ref data) = self.data { - debug_assert!(!data.colors.borrow().contains_key(&key)); - push(&data.current, key); if cfg!(debug_assertions) { profq_msg(ProfileQueriesMsg::TaskBegin(key.clone())) @@ -254,19 +254,21 @@ impl DepGraph { } // Determine the color of the new DepNode. - { - let prev_fingerprint = data.previous.fingerprint_of(&key); + if let Some(prev_index) = data.previous.node_to_index_opt(&key) { + let prev_fingerprint = data.previous.fingerprint_by_index(prev_index); - let color = if Some(current_fingerprint) == prev_fingerprint { + let color = if current_fingerprint == prev_fingerprint { DepNodeColor::Green(dep_node_index) } else { DepNodeColor::Red }; - let old_value = data.colors.borrow_mut().insert(key, color); - debug_assert!(old_value.is_none(), + let mut colors = data.colors.borrow_mut(); + debug_assert!(colors.get(prev_index).is_none(), "DepGraph::with_task() - Duplicate DepNodeColor \ insertion for {:?}", key); + + colors.insert(prev_index, color); } (result, dep_node_index) @@ -281,9 +283,11 @@ impl DepGraph { let mut fingerprints = self.fingerprints.borrow_mut(); let dep_node_index = DepNodeIndex::new(fingerprints.len()); fingerprints.push(fingerprint); + debug_assert!(fingerprints[dep_node_index] == fingerprint, "DepGraph::with_task() - Assigned fingerprint to \ unexpected index for {:?}", key); + (result, dep_node_index) } else { (task(cx, arg), DepNodeIndex::INVALID) @@ -356,6 +360,15 @@ impl DepGraph { .unwrap() } + #[inline] + pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { + if let Some(ref data) = self.data { + data.current.borrow_mut().node_to_node_index.contains_key(dep_node) + } else { + false + } + } + #[inline] pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint { match self.fingerprints.borrow().get(dep_node_index) { @@ -495,7 +508,17 @@ impl DepGraph { } pub fn node_color(&self, dep_node: &DepNode) -> Option { - self.data.as_ref().and_then(|data| data.colors.borrow().get(dep_node).cloned()) + if let Some(ref data) = self.data { + if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { + return data.colors.borrow().get(prev_index) + } else { + // This is a node that did not exist in the previous compilation + // session, so we consider it to be red. + return Some(DepNodeColor::Red) + } + } + + None } pub fn try_mark_green<'tcx>(&self, @@ -505,7 +528,6 @@ impl DepGraph { debug!("try_mark_green({:?}) - BEGIN", dep_node); let data = self.data.as_ref().unwrap(); - debug_assert!(!data.colors.borrow().contains_key(dep_node)); debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node)); if dep_node.kind.is_input() { @@ -535,19 +557,22 @@ impl DepGraph { } }; + debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none()); + let mut current_deps = Vec::new(); for &dep_dep_node_index in prev_deps { - let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); + let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); - let dep_dep_node_color = data.colors.borrow().get(dep_dep_node).cloned(); match dep_dep_node_color { Some(DepNodeColor::Green(node_index)) => { // This dependency has been marked as green before, we are // still fine and can continue with checking the other // dependencies. debug!("try_mark_green({:?}) --- found dependency {:?} to \ - be immediately green", dep_node, dep_dep_node); + be immediately green", + dep_node, + data.previous.index_to_node(dep_dep_node_index)); current_deps.push(node_index); } Some(DepNodeColor::Red) => { @@ -556,10 +581,14 @@ impl DepGraph { // mark the DepNode as green and also don't need to bother // with checking any of the other dependencies. debug!("try_mark_green({:?}) - END - dependency {:?} was \ - immediately red", dep_node, dep_dep_node); + immediately red", + dep_node, + data.previous.index_to_node(dep_dep_node_index)); return None } None => { + let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); + // We don't know the state of this dependency. If it isn't // an input node, let's try to mark it green recursively. if !dep_dep_node.kind.is_input() { @@ -601,10 +630,8 @@ impl DepGraph { debug!("try_mark_green({:?}) --- trying to force \ dependency {:?}", dep_node, dep_dep_node); if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) { - let dep_dep_node_color = data.colors - .borrow() - .get(dep_dep_node) - .cloned(); + let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); + match dep_dep_node_color { Some(DepNodeColor::Green(node_index)) => { debug!("try_mark_green({:?}) --- managed to \ @@ -681,26 +708,21 @@ impl DepGraph { } // ... and finally storing a "Green" entry in the color map. - let old_color = data.colors - .borrow_mut() - .insert(*dep_node, DepNodeColor::Green(dep_node_index)); - debug_assert!(old_color.is_none(), + let mut colors = data.colors.borrow_mut(); + debug_assert!(colors.get(prev_dep_node_index).is_none(), "DepGraph::try_mark_green() - Duplicate DepNodeColor \ insertion for {:?}", dep_node); + colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); + debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node); Some(dep_node_index) } - // Used in various assertions - pub fn is_green(&self, dep_node_index: DepNodeIndex) -> bool { - let dep_node = self.data.as_ref().unwrap().current.borrow().nodes[dep_node_index]; - self.data.as_ref().unwrap().colors.borrow().get(&dep_node).map(|&color| { - match color { - DepNodeColor::Red => false, - DepNodeColor::Green(_) => true, - } - }).unwrap_or(false) + // Returns true if the given node has been marked as green during the + // current compilation session. Used in various assertions + pub fn is_green(&self, dep_node: &DepNode) -> bool { + self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false) } // This method loads all on-disk cacheable query results into memory, so @@ -714,20 +736,25 @@ impl DepGraph { pub fn exec_cache_promotions<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { let green_nodes: Vec = { let data = self.data.as_ref().unwrap(); - data.colors.borrow().iter().filter_map(|(dep_node, color)| match color { - DepNodeColor::Green(_) => { - if dep_node.cache_on_disk(tcx) { - Some(*dep_node) - } else { + let colors = data.colors.borrow(); + colors.values.indices().filter_map(|prev_index| { + match colors.get(prev_index) { + Some(DepNodeColor::Green(_)) => { + let dep_node = data.previous.index_to_node(prev_index); + if dep_node.cache_on_disk(tcx) { + Some(dep_node) + } else { + None + } + } + None | + Some(DepNodeColor::Red) => { + // We can skip red nodes because a node can only be marked + // as red if the query result was recomputed and thus is + // already in memory. None } } - DepNodeColor::Red => { - // We can skip red nodes because a node can only be marked - // as red if the query result was recomputed and thus is - // already in memory. - None - } }).collect() }; @@ -1052,3 +1079,36 @@ enum OpenTask { node: DepNode, }, } + +// A data structure that stores Option values as a contiguous +// array, using one u32 per entry. +struct DepNodeColorMap { + values: IndexVec, +} + +const COMPRESSED_NONE: u32 = 0; +const COMPRESSED_RED: u32 = 1; +const COMPRESSED_FIRST_GREEN: u32 = 2; + +impl DepNodeColorMap { + fn new(size: usize) -> DepNodeColorMap { + DepNodeColorMap { + values: IndexVec::from_elem_n(COMPRESSED_NONE, size) + } + } + + fn get(&self, index: SerializedDepNodeIndex) -> Option { + match self.values[index] { + COMPRESSED_NONE => None, + COMPRESSED_RED => Some(DepNodeColor::Red), + value => Some(DepNodeColor::Green(DepNodeIndex(value - COMPRESSED_FIRST_GREEN))) + } + } + + fn insert(&mut self, index: SerializedDepNodeIndex, color: DepNodeColor) { + self.values[index] = match color { + DepNodeColor::Red => COMPRESSED_RED, + DepNodeColor::Green(index) => index.0 + COMPRESSED_FIRST_GREEN, + } + } +} diff --git a/src/librustc/dep_graph/prev.rs b/src/librustc/dep_graph/prev.rs index 50e1ee88a4614..504b60e763e23 100644 --- a/src/librustc/dep_graph/prev.rs +++ b/src/librustc/dep_graph/prev.rs @@ -49,6 +49,11 @@ impl PreviousDepGraph { self.index[dep_node] } + #[inline] + pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { + self.index.get(dep_node).cloned() + } + #[inline] pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option { self.index diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 0ab6ee1a54a9b..956348edcce65 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -147,7 +147,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } match self.dep_graph.try_mark_green(self.global_tcx(), &dep_node) { Some(dep_node_index) => { - debug_assert!(self.dep_graph.is_green(dep_node_index)); + debug_assert!(self.dep_graph.is_green(&dep_node)); self.dep_graph.read_index(dep_node_index); Some(dep_node_index) } @@ -390,7 +390,7 @@ macro_rules! define_maps { dep_node: &DepNode) -> Result<$V, CycleError<'a, $tcx>> { - debug_assert!(tcx.dep_graph.is_green(dep_node_index)); + debug_assert!(tcx.dep_graph.is_green(dep_node)); // First we try to load the result from the on-disk cache let result = if Self::cache_on_disk(key) && @@ -478,7 +478,7 @@ macro_rules! define_maps { span: Span, dep_node: DepNode) -> Result<($V, DepNodeIndex), CycleError<'a, $tcx>> { - debug_assert!(tcx.dep_graph.node_color(&dep_node).is_none()); + debug_assert!(!tcx.dep_graph.dep_node_exists(&dep_node)); profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin); let res = tcx.cycle_check(span, Query::$name(key), || { From 9e9c55f8fd064335cadc28bd9a0152538dcc9fa0 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 14 Feb 2018 10:22:12 -0800 Subject: [PATCH 10/35] Update E0657 stderr to match changed test --- src/test/ui/error-codes/E0657.stderr | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/ui/error-codes/E0657.stderr b/src/test/ui/error-codes/E0657.stderr index d3b53d37a30a0..e039d645fa6db 100644 --- a/src/test/ui/error-codes/E0657.stderr +++ b/src/test/ui/error-codes/E0657.stderr @@ -1,14 +1,14 @@ error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level - --> $DIR/E0657.rs:20:32 + --> $DIR/E0657.rs:20:31 | -20 | -> impl for<'a> Id> - | ^^ +20 | -> Box Id>> + | ^^ error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level - --> $DIR/E0657.rs:29:36 + --> $DIR/E0657.rs:29:35 | -29 | -> impl for<'a> Id> - | ^^ +29 | -> Box Id>> + | ^^ error: aborting due to 2 previous errors From 7062955ad9186c3a8cd785ecf90bc10f1949b16a Mon Sep 17 00:00:00 2001 From: bobtwinkles Date: Thu, 15 Feb 2018 01:25:29 -0500 Subject: [PATCH 11/35] Fix arguments specified by lxl in two-phase-bin-ops test --- src/test/run-pass/borrowck/two-phase-bin-ops.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/run-pass/borrowck/two-phase-bin-ops.rs b/src/test/run-pass/borrowck/two-phase-bin-ops.rs index 9bded41e1f933..1b2529d7875ab 100644 --- a/src/test/run-pass/borrowck/two-phase-bin-ops.rs +++ b/src/test/run-pass/borrowck/two-phase-bin-ops.rs @@ -9,7 +9,6 @@ // except according to those terms. // revisions: lxl nll -//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows #![cfg_attr(nll, feature(nll))] From f787bddcff700a139a0acdc815b4e5b0d641fad9 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 14 Feb 2018 16:11:02 +0100 Subject: [PATCH 12/35] Turn features() into a query. --- src/librustc/dep_graph/dep_node.rs | 10 +-- src/librustc/hir/lowering.rs | 6 +- src/librustc/ich/impls_syntax.rs | 19 ++++++ src/librustc/infer/error_reporting/mod.rs | 4 +- src/librustc/middle/stability.rs | 14 ++-- src/librustc/session/mod.rs | 66 ++++++------------- src/librustc/traits/specialize/mod.rs | 2 +- src/librustc/ty/context.rs | 64 ++++++++++++++++-- src/librustc/ty/maps/config.rs | 6 ++ src/librustc/ty/maps/mod.rs | 8 +++ src/librustc/ty/maps/plumbing.rs | 1 + src/librustc/ty/mod.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_const_eval/_match.rs | 4 +- src/librustc_const_eval/check_match.rs | 2 +- src/librustc_const_eval/eval.rs | 2 +- src/librustc_driver/driver.rs | 10 +-- src/librustc_incremental/assert_dep_graph.rs | 2 +- .../persist/dirty_clean.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/unused.rs | 2 +- src/librustc_metadata/native_libs.rs | 4 +- src/librustc_mir/borrow_check/mod.rs | 10 +-- src/librustc_mir/build/cfg.rs | 2 +- src/librustc_mir/build/matches/simplify.rs | 2 +- .../transform/clean_end_regions.rs | 2 +- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/util/borrowck_errors.rs | 2 +- src/librustc_plugin/load.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/lib.rs | 6 +- src/librustc_resolve/macros.rs | 4 +- src/librustc_resolve/resolve_imports.rs | 2 +- src/librustc_trans_utils/symbol_names_test.rs | 2 +- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/collect.rs | 6 +- src/librustc_typeck/lib.rs | 2 +- src/librustdoc/test.rs | 2 +- src/libsyntax/ext/tt/macro_rules.rs | 17 +++-- src/libsyntax/ext/tt/quoted.rs | 15 ++--- src/libsyntax/feature_gate.rs | 7 ++ 47 files changed, 202 insertions(+), 135 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 4034055d04155..d1734e214d561 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -436,6 +436,9 @@ impl DepKind { } define_dep_nodes!( <'tcx> + // We use this for most things when incr. comp. is turned off. + [] Null, + // Represents the `Krate` as a whole (the `hir::Krate` value) (as // distinct from the krate module). This is basically a hash of // the entire krate, so if you read from `Krate` (e.g., by calling @@ -605,8 +608,8 @@ define_dep_nodes!( <'tcx> [input] MissingExternCrateItem(CrateNum), [input] UsedCrateSource(CrateNum), [input] PostorderCnums, - [input] HasCloneClosures(CrateNum), - [input] HasCopyClosures(CrateNum), + [] HasCloneClosures(CrateNum), + [] HasCopyClosures(CrateNum), // This query is not expected to have inputs -- as a result, it's // not a good candidate for "replay" because it's essentially a @@ -630,8 +633,6 @@ define_dep_nodes!( <'tcx> [] CompileCodegenUnit(InternedString), [input] OutputFilenames, [anon] NormalizeTy, - // We use this for most things when incr. comp. is turned off. - [] Null, [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) }, @@ -642,6 +643,7 @@ define_dep_nodes!( <'tcx> [] GetSymbolExportLevel(DefId), + [input] Features, ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 55dcb16c3c95f..974ee99efabbe 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -550,7 +550,7 @@ impl<'a> LoweringContext<'a> { { assert!(!self.is_collecting_in_band_lifetimes); assert!(self.lifetimes_to_define.is_empty()); - self.is_collecting_in_band_lifetimes = self.sess.features.borrow().in_band_lifetimes; + self.is_collecting_in_band_lifetimes = self.sess.features_untracked().in_band_lifetimes; assert!(self.in_band_ty_params.is_empty()); @@ -957,7 +957,7 @@ impl<'a> LoweringContext<'a> { let span = t.span; match itctx { ImplTraitContext::Existential => { - let has_feature = self.sess.features.borrow().conservative_impl_trait; + let has_feature = self.sess.features_untracked().conservative_impl_trait; if !t.span.allows_unstable() && !has_feature { emit_feature_err(&self.sess.parse_sess, "conservative_impl_trait", t.span, GateIssue::Language, @@ -981,7 +981,7 @@ impl<'a> LoweringContext<'a> { }, lifetimes) }, ImplTraitContext::Universal(def_id) => { - let has_feature = self.sess.features.borrow().universal_impl_trait; + let has_feature = self.sess.features_untracked().universal_impl_trait; if !t.span.allows_unstable() && !has_feature { emit_feature_err(&self.sess.parse_sess, "universal_impl_trait", t.span, GateIssue::Language, diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index c31a5c9d86d77..f935cbfcde992 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -17,6 +17,7 @@ use std::hash as std_hash; use std::mem; use syntax::ast; +use syntax::feature_gate; use syntax::parse::token; use syntax::symbol::InternedString; use syntax::tokenstream; @@ -460,3 +461,21 @@ fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar, (pos.0 - filemap_start.0, width as u32) } + + + +impl<'gcx> HashStable> for feature_gate::Features { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + // Unfortunately we cannot exhaustively list fields here, since the + // struct is macro generated. + self.declared_stable_lang_features.hash_stable(hcx, hasher); + self.declared_lib_features.hash_stable(hcx, hasher); + + self.walk_feature_fields(|feature_name, value| { + feature_name.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + }); + } +} diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 03fc40b2e39fc..ae740707da5d6 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -262,11 +262,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { will_later_be_reported_by_nll: bool) { debug!("report_region_errors(): {} errors to start", errors.len()); - if will_later_be_reported_by_nll && self.tcx.sess.nll() { + if will_later_be_reported_by_nll && self.tcx.nll() { // With `#![feature(nll)]`, we want to present a nice user // experience, so don't even mention the errors from the // AST checker. - if self.tcx.sess.features.borrow().nll { + if self.tcx.features().nll { return; } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index e80ea16f565ab..16c33d6bd837d 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -131,7 +131,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { item_sp: Span, kind: AnnotationKind, visit_children: F) where F: FnOnce(&mut Self) { - if self.tcx.sess.features.borrow().staged_api { + if self.tcx.features().staged_api { // This crate explicitly wants staged API. debug!("annotate(id = {:?}, attrs = {:?})", id, attrs); if let Some(..) = attr::find_deprecation(self.tcx.sess.diagnostic(), attrs, item_sp) { @@ -398,7 +398,7 @@ impl<'a, 'tcx> Index<'tcx> { pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Index<'tcx> { let is_staged_api = tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || - tcx.sess.features.borrow().staged_api; + tcx.features().staged_api; let mut staged_api = FxHashMap(); staged_api.insert(LOCAL_CRATE, is_staged_api); let mut index = Index { @@ -408,7 +408,7 @@ impl<'a, 'tcx> Index<'tcx> { active_features: FxHashSet(), }; - let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features; + let ref active_lib_features = tcx.features().declared_lib_features; // Put the active features into a map for quick lookup index.active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect(); @@ -677,7 +677,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // There's no good place to insert stability check for non-Copy unions, // so semi-randomly perform it here in stability.rs - hir::ItemUnion(..) if !self.tcx.sess.features.borrow().untagged_unions => { + hir::ItemUnion(..) if !self.tcx.features().untagged_unions => { let def_id = self.tcx.hir.local_def_id(item.id); let adt_def = self.tcx.adt_def(def_id); let ty = self.tcx.type_of(def_id); @@ -721,8 +721,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let sess = &tcx.sess; - let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); if tcx.stability().staged_api[&LOCAL_CRATE] { @@ -736,12 +734,12 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { krate.visit_all_item_likes(&mut missing.as_deep_visitor()); } - let ref declared_lib_features = sess.features.borrow().declared_lib_features; + let ref declared_lib_features = tcx.features().declared_lib_features; let mut remaining_lib_features: FxHashMap = declared_lib_features.clone().into_iter().collect(); remaining_lib_features.remove(&Symbol::intern("proc_macro")); - for &(ref stable_lang_feature, span) in &sess.features.borrow().declared_stable_lang_features { + for &(ref stable_lang_feature, span) in &tcx.features().declared_stable_lang_features { let version = find_lang_feature_accepted_version(&stable_lang_feature.as_str()) .expect("unexpectedly couldn't find version feature was stabilized"); tcx.lint_node(lint::builtin::STABLE_FEATURES, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 9d7a9acc3d533..bcffce80911f7 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -19,7 +19,7 @@ use lint; use middle::allocator::AllocatorKind; use middle::dependency_format; use session::search_paths::PathKind; -use session::config::{BorrowckMode, DebugInfoLevel, OutputType, Epoch}; +use session::config::{DebugInfoLevel, OutputType, Epoch}; use ty::tls; use util::nodemap::{FxHashMap, FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; @@ -91,7 +91,8 @@ pub struct Session { /// multiple crates with the same name to coexist. See the /// trans::back::symbol_names module for more information. pub crate_disambiguator: RefCell>, - pub features: RefCell, + + features: RefCell>, /// The maximum recursion limit for potentially infinitely recursive /// operations such as auto-dereference and monomorphization. @@ -192,6 +193,7 @@ impl Session { None => bug!("accessing disambiguator before initialization"), } } + pub fn struct_span_warn<'a, S: Into>(&'a self, sp: S, msg: &str) @@ -443,16 +445,22 @@ impl Session { self.opts.debugging_opts.print_llvm_passes } - /// If true, we should use NLL-style region checking instead of - /// lexical style. - pub fn nll(&self) -> bool { - self.features.borrow().nll || self.opts.debugging_opts.nll + /// Get the features enabled for the current compilation session. Do not use + /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents + /// dependency tracking. Use tcx.features() instead. + #[inline] + pub fn features_untracked(&self) -> cell::Ref { + let features = self.features.borrow(); + + if features.is_none() { + bug!("Access to Session::features before it is initialized"); + } + + cell::Ref::map(features, |r| r.as_ref().unwrap()) } - /// If true, we should use the MIR-based borrowck (we may *also* use - /// the AST-based borrowck). - pub fn use_mir(&self) -> bool { - self.borrowck_mode().use_mir() + pub fn init_features(&self, features: feature_gate::Features) { + *(self.features.borrow_mut()) = Some(features); } /// If true, we should gather causal information during NLL @@ -462,42 +470,6 @@ impl Session { self.opts.debugging_opts.nll_dump_cause } - /// If true, we should enable two-phase borrows checks. This is - /// done with either `-Ztwo-phase-borrows` or with - /// `#![feature(nll)]`. - pub fn two_phase_borrows(&self) -> bool { - self.features.borrow().nll || self.opts.debugging_opts.two_phase_borrows - } - - /// What mode(s) of borrowck should we run? AST? MIR? both? - /// (Also considers the `#![feature(nll)]` setting.) - pub fn borrowck_mode(&self) -> BorrowckMode { - match self.opts.borrowck_mode { - mode @ BorrowckMode::Mir | - mode @ BorrowckMode::Compare => mode, - - mode @ BorrowckMode::Ast => { - if self.nll() { - BorrowckMode::Mir - } else { - mode - } - } - - } - } - - /// Should we emit EndRegion MIR statements? These are consumed by - /// MIR borrowck, but not when NLL is used. They are also consumed - /// by the validation stuff. - pub fn emit_end_regions(&self) -> bool { - // FIXME(#46875) -- we should not emit end regions when NLL is enabled, - // but for now we can't stop doing so because it causes false positives - self.opts.debugging_opts.emit_end_regions || - self.opts.debugging_opts.mir_emit_validate > 0 || - self.use_mir() - } - /// Calculates the flavor of LTO to use for this compilation. pub fn lto(&self) -> config::Lto { // If our target has codegen requirements ignore the command line @@ -1009,7 +981,7 @@ pub fn build_session_(sopts: config::Options, crate_types: RefCell::new(Vec::new()), dependency_formats: RefCell::new(FxHashMap()), crate_disambiguator: RefCell::new(None), - features: RefCell::new(feature_gate::Features::new()), + features: RefCell::new(None), recursion_limit: Cell::new(64), type_length_limit: Cell::new(1048576), next_node_id: Cell::new(NodeId::new(1)), diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index afe29cc0e7baf..1d0b40f44c05d 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -162,7 +162,7 @@ pub(super) fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // The feature gate should prevent introducing new specializations, but not // taking advantage of upstream ones. - if !tcx.sess.features.borrow().specialization && + if !tcx.features().specialization && (impl1_def_id.is_local() || impl2_def_id.is_local()) { return false; } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e4e07454c97ac..d01bfcefbb7f1 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -14,7 +14,7 @@ use dep_graph::DepGraph; use dep_graph::{DepNode, DepConstructor}; use errors::DiagnosticBuilder; use session::Session; -use session::config::OutputFilenames; +use session::config::{BorrowckMode, OutputFilenames}; use middle; use hir::{TraitCandidate, HirId, ItemLocalId}; use hir::def::{Def, Export}; @@ -71,6 +71,7 @@ use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::codemap::MultiSpan; +use syntax::feature_gate; use syntax::symbol::{Symbol, keywords}; use syntax_pos::Span; @@ -1251,6 +1252,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.stability_index(LOCAL_CRATE) } + pub fn features(self) -> Rc { + self.features_query(LOCAL_CRATE) + } + pub fn crates(self) -> Rc> { self.all_crate_nums(LOCAL_CRATE) } @@ -1362,6 +1367,53 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.on_disk_query_result_cache.serialize(self.global_tcx(), encoder) } + /// If true, we should use NLL-style region checking instead of + /// lexical style. + pub fn nll(self) -> bool { + self.features().nll || self.sess.opts.debugging_opts.nll + } + + /// If true, we should use the MIR-based borrowck (we may *also* use + /// the AST-based borrowck). + pub fn use_mir(self) -> bool { + self.borrowck_mode().use_mir() + } + + /// If true, we should enable two-phase borrows checks. This is + /// done with either `-Ztwo-phase-borrows` or with + /// `#![feature(nll)]`. + pub fn two_phase_borrows(self) -> bool { + self.features().nll || self.sess.opts.debugging_opts.two_phase_borrows + } + + /// What mode(s) of borrowck should we run? AST? MIR? both? + /// (Also considers the `#![feature(nll)]` setting.) + pub fn borrowck_mode(&self) -> BorrowckMode { + match self.sess.opts.borrowck_mode { + mode @ BorrowckMode::Mir | + mode @ BorrowckMode::Compare => mode, + + mode @ BorrowckMode::Ast => { + if self.nll() { + BorrowckMode::Mir + } else { + mode + } + } + + } + } + + /// Should we emit EndRegion MIR statements? These are consumed by + /// MIR borrowck, but not when NLL is used. They are also consumed + /// by the validation stuff. + pub fn emit_end_regions(self) -> bool { + // FIXME(#46875) -- we should not emit end regions when NLL is enabled, + // but for now we can't stop doing so because it causes false positives + self.sess.opts.debugging_opts.emit_end_regions || + self.sess.opts.debugging_opts.mir_emit_validate > 0 || + self.use_mir() + } } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { @@ -2020,7 +2072,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_diverging_default(self) -> Ty<'tcx> { - if self.sess.features.borrow().never_type { + if self.features().never_type { self.types.never } else { self.intern_tup(&[], true) @@ -2395,13 +2447,17 @@ pub fn provide(providers: &mut ty::maps::Providers) { }; providers.has_copy_closures = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.features.borrow().copy_closures + tcx.features().copy_closures }; providers.has_clone_closures = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.features.borrow().clone_closures + tcx.features().clone_closures }; providers.fully_normalize_monormophic_ty = |tcx, ty| { tcx.fully_normalize_associated_types_in(&ty) }; + providers.features_query = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + Rc::new(tcx.sess.features_untracked().clone()) + }; } diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index eb07876b05f26..c91b30440e5e3 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -593,6 +593,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::fully_normalize_monormophic_ty<'t } } +impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up enabled feature gates") + } +} + impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { #[inline] fn cache_on_disk(def_id: Self::Key) -> bool { diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 85fca68187fe6..887b51113b502 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -52,6 +52,7 @@ use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::symbol::InternedString; use syntax::attr; use syntax::ast; +use syntax::feature_gate; use syntax::symbol::Symbol; #[macro_use] @@ -369,12 +370,19 @@ define_maps! { <'tcx> // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. [] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>) -> usize, + + [] fn features_query: features_node(CrateNum) -> Rc, } ////////////////////////////////////////////////////////////////////// // These functions are little shims used to find the dep-node for a // given query when there is not a *direct* mapping: + +fn features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::Features +} + fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> { DepConstructor::EraseRegionsTy { ty } } diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 0ab6ee1a54a9b..ffc51c28f0b63 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -923,6 +923,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::TargetFeaturesEnabled => { force!(target_features_enabled, def_id!()); } DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); } + DepKind::Features => { force!(features_query, LOCAL_CRATE); } } true diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f52f2ea0f9fc8..07d886edb2059 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2270,7 +2270,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns true if the impls are the same polarity and are implementing /// a trait which contains no items pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { - if !self.sess.features.borrow().overlapping_marker_traits { + if !self.features().overlapping_marker_traits { return false; } let trait1_is_empty = self.impl_trait_ref(def_id1) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 738c0d82ee1b5..d07686960d0b7 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -275,7 +275,7 @@ impl<'b, 'tcx: 'b> BorrowckErrors for BorrowckCtxt<'b, 'tcx> { o: Origin) -> DiagnosticBuilder<'a> { - if !o.should_emit_errors(self.tcx.sess.borrowck_mode()) { + if !o.should_emit_errors(self.tcx.borrowck_mode()) { self.tcx.sess.diagnostic().cancel(&mut diag); } diag diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index a7c382eba5091..4db460f43c508 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -201,7 +201,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { - if self.tcx.sess.features.borrow().never_type { + if self.tcx.features().never_type { self.tcx.is_ty_uninhabited_from(self.module, ty) } else { false @@ -227,7 +227,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { substs: &'tcx ty::subst::Substs<'tcx>) -> bool { - if self.tcx.sess.features.borrow().never_type { + if self.tcx.features().never_type { self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs) } else { false diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index ae53ed0e1140d..6f7143c185cb3 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -212,7 +212,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let pat_ty = self.tables.node_id_to_type(scrut.hir_id); let module = self.tcx.hir.get_module_parent(scrut.id); if inlined_arms.is_empty() { - let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type { + let scrutinee_is_uninhabited = if self.tcx.features().never_type { self.tcx.is_ty_uninhabited_from(module, pat_ty) } else { self.conservative_is_uninhabited(pat_ty) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 8e4ec93c14bae..2a571fa82643b 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -398,7 +398,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, }).collect::, _>>()?)))) } hir::ExprIndex(ref arr, ref idx) => { - if !tcx.sess.features.borrow().const_indexing { + if !tcx.features().const_indexing { signal!(e, IndexOpFeatureGated); } let arr = cx.eval(arr)?; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index f344624666a6c..9d358c439db6b 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -648,7 +648,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess, sess.opts.test); // these need to be set "early" so that expansion sees `quote` if enabled. - *sess.features.borrow_mut() = features; + sess.init_features(features); *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); @@ -688,7 +688,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let mut registry = registry.unwrap_or(Registry::new(sess, krate.span)); time(time_passes, "plugin registration", || { - if sess.features.borrow().rustc_diagnostic_macros { + if sess.features_untracked().rustc_diagnostic_macros { registry.register_macro("__diagnostic_used", diagnostics::plugin::expand_diagnostic_used); registry.register_macro("__register_diagnostic", @@ -738,7 +738,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, crate_loader, &resolver_arenas); resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives; - syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote); + syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features_untracked().quote); krate = time(time_passes, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their @@ -769,7 +769,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, .filter(|p| env::join_paths(iter::once(p)).is_ok())) .unwrap()); } - let features = sess.features.borrow(); + let features = sess.features_untracked(); let cfg = syntax::ext::expand::ExpansionConfig { features: Some(&features), recursion_limit: sess.recursion_limit.get(), @@ -874,7 +874,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, sess.track_errors(|| { syntax::feature_gate::check_crate(&krate, &sess.parse_sess, - &sess.features.borrow(), + &sess.features_untracked(), &attributes, sess.opts.unstable_features); }) diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 5976b80d90f87..17a6176b79e95 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -69,7 +69,7 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - if !tcx.sess.features.borrow().rustc_attrs { + if !tcx.features().rustc_attrs { return; } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index c3e283535ec82..e114606a63115 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -219,7 +219,7 @@ impl Assertion { pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // can't add `#[rustc_dirty]` etc without opting in to this feature - if !tcx.sess.features.borrow().rustc_attrs { + if !tcx.features().rustc_attrs { return; } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index de55710bdf3d0..ea136475dba4f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1355,7 +1355,7 @@ impl UnreachablePub { // visibility is token at start of declaration (can be macro // variable rather than literal `pub`) let pub_span = cx.tcx.sess.codemap().span_until_char(def_span, ' '); - let replacement = if cx.tcx.sess.features.borrow().crate_visibility_modifier { + let replacement = if cx.tcx.features().crate_visibility_modifier { "crate" } else { "pub(crate)" diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 439533fae49d9..6ab3172c4fefa 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -72,7 +72,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let mut fn_warned = false; let mut op_warned = false; - if cx.tcx.sess.features.borrow().fn_must_use { + if cx.tcx.features().fn_must_use { let maybe_def = match expr.node { hir::ExprCall(ref callee, _) => { match callee.node { diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index c0ce32cc97068..2504f8dc251f9 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { None => self.tcx.sess.err(msg), } } - if lib.cfg.is_some() && !self.tcx.sess.features.borrow().link_cfg { + if lib.cfg.is_some() && !self.tcx.features().link_cfg { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, "link_cfg", span.unwrap(), @@ -154,7 +154,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { "is feature gated"); } if lib.kind == cstore::NativeStaticNobundle && - !self.tcx.sess.features.borrow().static_nobundle { + !self.tcx.features().static_nobundle { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, "static_nobundle", span.unwrap(), diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index c4df7349391e2..622cf04c71a9e 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -72,7 +72,7 @@ fn mir_borrowck<'a, 'tcx>( let input_mir = tcx.mir_validated(def_id); debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id)); - if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.sess.use_mir() { + if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir() { return None; } @@ -101,7 +101,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( // contain non-lexical lifetimes. It will have a lifetime tied // to the inference context. let mut mir: Mir<'tcx> = input_mir.clone(); - let free_regions = if !tcx.sess.nll() { + let free_regions = if !tcx.nll() { None } else { let mir = &mut mir; @@ -204,7 +204,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( ); (Some(Rc::new(regioncx)), opt_closure_req) } else { - assert!(!tcx.sess.nll()); + assert!(!tcx.nll()); (None, None) }; let flow_inits = flow_inits; // remove mut @@ -712,7 +712,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// allowed to be split into separate Reservation and /// Activation phases. fn allow_two_phase_borrow(&self, kind: BorrowKind) -> bool { - self.tcx.sess.two_phase_borrows() && + self.tcx.two_phase_borrows() && (kind.allows_two_phase_borrow() || self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) } @@ -1187,7 +1187,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { span: Span, flow_state: &Flows<'cx, 'gcx, 'tcx>, ) { - if !self.tcx.sess.two_phase_borrows() { + if !self.tcx.two_phase_borrows() { return; } diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 932aad0bb1d84..1ed8289d44184 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -50,7 +50,7 @@ impl<'tcx> CFG<'tcx> { block: BasicBlock, source_info: SourceInfo, region_scope: region::Scope) { - if tcx.sess.emit_end_regions() { + if tcx.emit_end_regions() { if let region::ScopeData::CallSite(_) = region_scope.data() { // The CallSite scope (aka the root scope) is sort of weird, in that it is // supposed to "separate" the "interior" and "exterior" of a closure. Being diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index b16d7ed236509..abea55835466f 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -113,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { i == variant_index || { - self.hir.tcx().sess.features.borrow().never_type && + self.hir.tcx().features().never_type && self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs) } }); diff --git a/src/librustc_mir/transform/clean_end_regions.rs b/src/librustc_mir/transform/clean_end_regions.rs index 7986313aa8134..6e8985d99d287 100644 --- a/src/librustc_mir/transform/clean_end_regions.rs +++ b/src/librustc_mir/transform/clean_end_regions.rs @@ -42,7 +42,7 @@ impl MirPass for CleanEndRegions { tcx: TyCtxt<'a, 'tcx, 'tcx>, _source: MirSource, mir: &mut Mir<'tcx>) { - if !tcx.sess.emit_end_regions() { return; } + if !tcx.emit_end_regions() { return; } let mut gather = GatherBorrowedRegions { seen_regions: FxHashSet() diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 2b9ee223b01a4..bb2dc9a7494f9 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -904,7 +904,7 @@ This does not pose a problem by itself because they can't be accessed directly." if self.mode != Mode::Fn && // feature-gate is not enabled, - !self.tcx.sess.features.borrow() + !self.tcx.features() .declared_lib_features .iter() .any(|&(ref sym, _)| sym == feature_name) && diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 4a7ee397aec00..89242ca32bcbf 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -514,7 +514,7 @@ impl<'b, 'gcx, 'tcx> BorrowckErrors for TyCtxt<'b, 'gcx, 'tcx> { o: Origin) -> DiagnosticBuilder<'a> { - if !o.should_emit_errors(self.sess.borrowck_mode()) { + if !o.should_emit_errors(self.borrowck_mode()) { self.sess.diagnostic().cancel(&mut diag); } diag diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index a46b85d93cbb8..bf59165a9c461 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -52,7 +52,7 @@ pub fn load_plugins(sess: &Session, // do not report any error now. since crate attributes are // not touched by expansion, every use of plugin without // the feature enabled will result in an error later... - if sess.features.borrow().plugin { + if sess.features_untracked().plugin { for attr in &krate.attrs { if !attr.check_name("plugin") { continue; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index c55bf395d71b3..7377adba6c14b 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -590,7 +590,7 @@ impl<'a> Resolver<'a> { }; let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, - &self.session.features, + &self.session.features_untracked(), ¯o_def)); self.macro_map.insert(def_id, ext.clone()); ext diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2da4bfedd3a17..ec0239272a677 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1523,7 +1523,7 @@ impl<'a> Resolver<'a> { invocations.insert(Mark::root(), arenas.alloc_invocation_data(InvocationData::root(graph_root))); - let features = session.features.borrow(); + let features = session.features_untracked(); let mut macro_defs = FxHashMap(); macro_defs.insert(Mark::root(), root_def_id); @@ -2994,7 +2994,7 @@ impl<'a> Resolver<'a> { let prim = self.primitive_type_table.primitive_types[&path[0].node.name]; match prim { TyUint(UintTy::U128) | TyInt(IntTy::I128) => { - if !self.session.features.borrow().i128_type { + if !self.session.features_untracked().i128_type { emit_feature_err(&self.session.parse_sess, "i128_type", span, GateIssue::Language, "128-bit type is unstable"); @@ -3085,7 +3085,7 @@ impl<'a> Resolver<'a> { let prev_name = path[0].node.name; if prev_name == keywords::Extern.name() || prev_name == keywords::CrateRoot.name() && - self.session.features.borrow().extern_absolute_paths { + self.session.features_untracked().extern_absolute_paths { // `::extern_crate::a::b` let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span); let crate_root = diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 080ef3252a633..69078d40045b6 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -744,7 +744,7 @@ impl<'a> Resolver<'a> { let def_id = self.definitions.local_def_id(item.id); let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, - &self.session.features, + &self.session.features_untracked(), item)); self.macro_map.insert(def_id, ext); @@ -838,7 +838,7 @@ impl<'a> Resolver<'a> { } fn gate_legacy_custom_derive(&mut self, name: Symbol, span: Span) { - if !self.session.features.borrow().custom_derive { + if !self.session.features_untracked().custom_derive { let sess = &self.session.parse_sess; let explain = feature_gate::EXPLAIN_CUSTOM_DERIVE; emit_feature_err(sess, "custom_derive", span, GateIssue::Language, explain); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 8cb25f449b667..d60638c0ee7ec 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -609,7 +609,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if module_path.len() == 1 && (module_path[0].node.name == keywords::CrateRoot.name() || module_path[0].node.name == keywords::Extern.name()) { let is_extern = module_path[0].node.name == keywords::Extern.name() || - self.session.features.borrow().extern_absolute_paths; + self.session.features_untracked().extern_absolute_paths; match directive.subclass { GlobImport { .. } if is_extern => { return Some((directive.span, diff --git a/src/librustc_trans_utils/symbol_names_test.rs b/src/librustc_trans_utils/symbol_names_test.rs index 5d7d4f3055bad..267c8d2bd03c8 100644 --- a/src/librustc_trans_utils/symbol_names_test.rs +++ b/src/librustc_trans_utils/symbol_names_test.rs @@ -28,7 +28,7 @@ pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - if !tcx.sess.features.borrow().rustc_attrs { + if !tcx.features().rustc_attrs { return; } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1139ea5fbd364..b94917ae04dc8 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -417,7 +417,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_def = self.tcx().trait_def(trait_def_id); - if !self.tcx().sess.features.borrow().unboxed_closures && + if !self.tcx().features().unboxed_closures && trait_segment.with_parameters(|p| p.parenthesized) != trait_def.paren_sugar { // For now, require that parenthetical notation be used only with `Fn()` etc. let msg = if trait_def.paren_sugar { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index bf253a88d27c2..bb6ed89433562 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -114,7 +114,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; if pat_adjustments.len() > 0 { - if tcx.sess.features.borrow().match_default_bindings { + if tcx.features().match_default_bindings { debug!("default binding mode is now {:?}", def_bm); self.inh.tables.borrow_mut() .pat_adjustments_mut() diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 47e4b0272bed4..3a153bafe8f50 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -585,7 +585,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } - if has_unsized_tuple_coercion && !self.tcx.sess.features.borrow().unsized_tuple_coercion { + if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, "unsized_tuple_coercion", self.cause.span, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index e8c3966f23f08..f3850da0ba557 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -324,7 +324,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // possible that there will be multiple applicable methods. if !is_suggestion.0 { if reached_raw_pointer - && !self.tcx.sess.features.borrow().arbitrary_self_types { + && !self.tcx.features().arbitrary_self_types { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 epoch // (see https://github.com/rust-lang/rust/issues/46906) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 165b499cc62aa..73e24ff5252df 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1089,7 +1089,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } fcx.demand_suptype(span, ret_ty, actual_return_ty); - if fcx.tcx.sess.features.borrow().termination_trait { + if fcx.tcx.features().termination_trait { // If the termination trait language item is activated, check that the main return type // implements the termination trait. if let Some(term_id) = fcx.tcx.lang_items().termination() { @@ -1600,7 +1600,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let repr_type_ty = def.repr.discr_type().to_ty(tcx); if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { - if !tcx.sess.features.borrow().repr128 { + if !tcx.features().repr128 { emit_feature_err(&tcx.sess.parse_sess, "repr128", sp, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 3668fc46ddc27..e2d640fd67e6b 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -471,7 +471,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty); - if !fcx.tcx.sess.features.borrow().arbitrary_self_types { + if !fcx.tcx.features().arbitrary_self_types { match self_kind { ExplicitSelf::ByValue | ExplicitSelf::ByReference(_, _) | diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index f65d627781f0f..d3de31d630a97 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -74,7 +74,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d return; } - if tcx.sess.features.borrow().unboxed_closures { + if tcx.features().unboxed_closures { // the feature gate allows all Fn traits return; } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d5328a18c2240..8234dc95c7996 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -711,7 +711,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar"); - if paren_sugar && !tcx.sess.features.borrow().unboxed_closures { + if paren_sugar && !tcx.features().unboxed_closures { let mut err = tcx.sess.struct_span_err( item.span, "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ @@ -953,7 +953,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } if !allow_defaults && p.default.is_some() { - if !tcx.sess.features.borrow().default_type_parameter_fallback { + if !tcx.features().default_type_parameter_fallback { tcx.lint_node( lint::builtin::INVALID_TYPE_PARAM_DEFAULT, p.id, @@ -1674,7 +1674,7 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>( // feature gate SIMD types in FFI, since I (huonw) am not sure the // ABIs are handled at all correctly. if abi != abi::Abi::RustIntrinsic && abi != abi::Abi::PlatformIntrinsic - && !tcx.sess.features.borrow().simd_ffi { + && !tcx.features().simd_ffi { let check = |ast_ty: &hir::Ty, ty: Ty| { if ty.is_simd() { tcx.sess.struct_span_err(ast_ty.span, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index bd7e200d620e6..01ceb8eb29151 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -207,7 +207,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let actual = tcx.fn_sig(main_def_id); let expected_return_type = if tcx.lang_items().termination().is_some() - && tcx.sess.features.borrow().termination_trait { + && tcx.features().termination_trait { // we take the return type of the given main function, the real check is done // in `check_fn` actual.output().skip_binder() diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 087d88419bc84..b1dd3db9d861d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -665,7 +665,7 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { nested: F) { let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs); if let Some(ref cfg) = attrs.cfg { - if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features.borrow())) { + if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) { return; } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 5254c751e6b62..f8c95ae17bf31 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -26,7 +26,6 @@ use parse::token::Token::*; use symbol::Symbol; use tokenstream::{TokenStream, TokenTree}; -use std::cell::RefCell; use std::collections::HashMap; use std::collections::hash_map::Entry; use std::rc::Rc; @@ -183,7 +182,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, // Holy self-referential! /// Converts a `macro_rules!` invocation into a syntax extension. -pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) -> SyntaxExtension { +pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> SyntaxExtension { let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs")); let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs")); @@ -295,7 +294,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) } fn check_lhs_nt_follows(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], lhs: "ed::TokenTree) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the @@ -352,7 +351,7 @@ fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool { } fn check_matcher(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], matcher: &[quoted::TokenTree]) -> bool { let first_sets = FirstSets::new(matcher); @@ -600,7 +599,7 @@ impl TokenSet { // Requires that `first_sets` is pre-computed for `matcher`; // see `FirstSets::new`. fn check_matcher_core(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], first_sets: &FirstSets, matcher: &[quoted::TokenTree], @@ -868,7 +867,7 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result, + features: &Features, attrs: &[ast::Attribute], tok: "ed::TokenTree) -> Result<(), String> { debug!("has_legal_fragment_specifier({:?})", tok); @@ -883,7 +882,7 @@ fn has_legal_fragment_specifier(sess: &ParseSess, } fn is_legal_fragment_specifier(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], frag_name: &str, frag_span: Span) -> bool { @@ -891,7 +890,7 @@ fn is_legal_fragment_specifier(sess: &ParseSess, "item" | "block" | "stmt" | "expr" | "pat" | "path" | "ty" | "ident" | "meta" | "tt" | "" => true, "lifetime" => { - if !features.borrow().macro_lifetime_matcher && + if !features.macro_lifetime_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_LIFETIME_MATCHER; emit_feature_err(sess, @@ -903,7 +902,7 @@ fn is_legal_fragment_specifier(sess: &ParseSess, true }, "vis" => { - if !features.borrow().macro_vis_matcher && + if !features.macro_vis_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_VIS_MATCHER; emit_feature_err(sess, diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index 982b60b81e47e..c6484e9a7706a 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -17,7 +17,6 @@ use symbol::keywords; use syntax_pos::{BytePos, Span, DUMMY_SP}; use tokenstream; -use std::cell::RefCell; use std::iter::Peekable; use std::rc::Rc; @@ -183,7 +182,7 @@ pub fn parse( input: tokenstream::TokenStream, expect_matchers: bool, sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], ) -> Vec { // Will contain the final collection of `self::TokenTree` @@ -251,7 +250,7 @@ fn parse_tree( trees: &mut Peekable, expect_matchers: bool, sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], ) -> TokenTree where @@ -382,7 +381,7 @@ fn parse_sep_and_kleene_op( input: &mut Peekable, span: Span, sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], ) -> (Option, KleeneOp) where @@ -415,7 +414,7 @@ where match parse_kleene_op(input, span) { // #2 is a KleeneOp (this is the only valid option) :) Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; @@ -438,7 +437,7 @@ where Err(span) => span, } } else { - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; @@ -460,7 +459,7 @@ where Ok(Err((tok, span))) => match parse_kleene_op(input, span) { // #2 is a KleeneOp :D Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; @@ -487,7 +486,7 @@ where Err(span) => span, }; - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { sess.span_diagnostic diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ea916d5168c33..8369520d0d6e5 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -62,6 +62,7 @@ macro_rules! declare_features { &[$((stringify!($feature), $ver, $issue, set!($feature))),+]; /// A set of features to be used by later passes. + #[derive(Clone)] pub struct Features { /// `#![feature]` attrs for stable language features, for error reporting pub declared_stable_lang_features: Vec<(Symbol, Span)>, @@ -78,6 +79,12 @@ macro_rules! declare_features { $($feature: false),+ } } + + pub fn walk_feature_fields(&self, mut f: F) + where F: FnMut(&str, bool) + { + $(f(stringify!($feature), self.$feature);)+ + } } }; From c0517a38aced792365af440e9140d91518b9bb45 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 14 Feb 2018 16:26:56 +0100 Subject: [PATCH 13/35] incr.comp.: Add regression test for detecting feature gate changes. --- src/test/incremental/feature_gate.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/incremental/feature_gate.rs diff --git a/src/test/incremental/feature_gate.rs b/src/test/incremental/feature_gate.rs new file mode 100644 index 0000000000000..de2f9ab52f60b --- /dev/null +++ b/src/test/incremental/feature_gate.rs @@ -0,0 +1,23 @@ +// Copyright 2018 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. + +// This test makes sure that we detect changed feature gates. + +// revisions:rpass1 cfail2 +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] +#![cfg_attr(rpass1, feature(nll))] + +fn main() { + let mut v = vec![1]; + v.push(v[0]); + //[cfail2]~^ ERROR cannot borrow +} From d691c463f6248e20e0dbf57745fee07a5b1eb5a8 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 15 Feb 2018 15:53:26 +0100 Subject: [PATCH 14/35] Fix procedural_mbe_matching test case after libsyntax change. --- src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs index 9ebc438ad5a00..fd8f7b9e384f3 100644 --- a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs +++ b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs @@ -41,7 +41,7 @@ fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree]) let mbe_matcher = quoted::parse(mbe_matcher.into_iter().collect(), true, cx.parse_sess, - &RefCell::new(Features::new()), + &Features::new(), &[]); let map = match TokenTree::parse(cx, &mbe_matcher, args.iter().cloned().collect()) { Success(map) => map, From 1f0e1a043959461afd061be7ff92362492b2c85d Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Thu, 15 Feb 2018 00:06:14 +0100 Subject: [PATCH 15/35] Convert compile-fail/lint-ctypes.rs to ui test --- src/test/{compile-fail => ui}/lint-ctypes.rs | 0 src/test/ui/lint-ctypes.stderr | 128 +++++++++++++++++++ 2 files changed, 128 insertions(+) rename src/test/{compile-fail => ui}/lint-ctypes.rs (100%) create mode 100644 src/test/ui/lint-ctypes.stderr diff --git a/src/test/compile-fail/lint-ctypes.rs b/src/test/ui/lint-ctypes.rs similarity index 100% rename from src/test/compile-fail/lint-ctypes.rs rename to src/test/ui/lint-ctypes.rs diff --git a/src/test/ui/lint-ctypes.stderr b/src/test/ui/lint-ctypes.stderr new file mode 100644 index 0000000000000..21aadde8ac87c --- /dev/null +++ b/src/test/ui/lint-ctypes.stderr @@ -0,0 +1,128 @@ +error: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type + --> $DIR/lint-ctypes.rs:54:28 + | +54 | pub fn ptr_type1(size: *const Foo); //~ ERROR: found struct without + | ^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-ctypes.rs:11:9 + | +11 | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + +error: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type + --> $DIR/lint-ctypes.rs:55:28 + | +55 | pub fn ptr_type2(size: *const Foo); //~ ERROR: found struct without + | ^^^^^^^^^^ + +error: found Rust slice type in foreign module, consider using a raw pointer instead + --> $DIR/lint-ctypes.rs:56:26 + | +56 | pub fn slice_type(p: &[u32]); //~ ERROR: found Rust slice type + | ^^^^^^ + +error: found Rust type `str` in foreign module; consider using a `*const libc::c_char` + --> $DIR/lint-ctypes.rs:57:24 + | +57 | pub fn str_type(p: &str); //~ ERROR: found Rust type + | ^^^^ + +error: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type + --> $DIR/lint-ctypes.rs:58:24 + | +58 | pub fn box_type(p: Box); //~ ERROR found struct without + | ^^^^^^^^ + +error: found Rust type `char` in foreign module, while `u32` or `libc::wchar_t` should be used + --> $DIR/lint-ctypes.rs:59:25 + | +59 | pub fn char_type(p: char); //~ ERROR found Rust type + | ^^^^ + +error: found Rust type `i128` in foreign module, but 128-bit integers don't currently have a known stable ABI + --> $DIR/lint-ctypes.rs:60:25 + | +60 | pub fn i128_type(p: i128); //~ ERROR found Rust type + | ^^^^ + +error: found Rust type `u128` in foreign module, but 128-bit integers don't currently have a known stable ABI + --> $DIR/lint-ctypes.rs:61:25 + | +61 | pub fn u128_type(p: u128); //~ ERROR found Rust type + | ^^^^ + +error: found Rust trait type in foreign module, consider using a raw pointer instead + --> $DIR/lint-ctypes.rs:62:26 + | +62 | pub fn trait_type(p: &Clone); //~ ERROR found Rust trait type + | ^^^^^^ + +error: found Rust tuple type in foreign module; consider using a struct instead + --> $DIR/lint-ctypes.rs:63:26 + | +63 | pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type + | ^^^^^^^^^^ + +error: found Rust tuple type in foreign module; consider using a struct instead + --> $DIR/lint-ctypes.rs:64:27 + | +64 | pub fn tuple_type2(p: I32Pair); //~ ERROR found Rust tuple type + | ^^^^^^^ + +error: found zero-size struct in foreign module, consider adding a member to this struct + --> $DIR/lint-ctypes.rs:65:25 + | +65 | pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct + | ^^^^^^^^ + +error: found zero-sized type composed only of phantom-data in a foreign-function. + --> $DIR/lint-ctypes.rs:66:33 + | +66 | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR found zero-sized type + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: found zero-sized type composed only of phantom-data in a foreign-function. + --> $DIR/lint-ctypes.rs:68:12 + | +68 | -> ::std::marker::PhantomData; //~ ERROR: found zero-sized type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: found function pointer with Rust calling convention in foreign module; consider using an `extern` function pointer + --> $DIR/lint-ctypes.rs:69:23 + | +69 | pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust + | ^^^^^^ + +error: found function pointer with Rust calling convention in foreign module; consider using an `extern` function pointer + --> $DIR/lint-ctypes.rs:70:24 + | +70 | pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust + | ^^^^ + +error: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type + --> $DIR/lint-ctypes.rs:71:28 + | +71 | pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without + | ^^^^^^^^^^ + +error: found non-foreign-function-safe member in struct marked #[repr(C)]: found Rust type `i128` in foreign module, but 128-bit integers don't currently have a known stable ABI + --> $DIR/lint-ctypes.rs:72:32 + | +72 | pub fn transparent_i128(p: TransparentI128); //~ ERROR: found Rust type `i128` + | ^^^^^^^^^^^^^^^ + +error: found non-foreign-function-safe member in struct marked #[repr(C)]: found Rust type `str` in foreign module; consider using a `*const libc::c_char` + --> $DIR/lint-ctypes.rs:73:31 + | +73 | pub fn transparent_str(p: TransparentStr); //~ ERROR: found Rust type `str` + | ^^^^^^^^^^^^^^ + +error: found non-foreign-function-safe member in struct marked #[repr(C)]: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type + --> $DIR/lint-ctypes.rs:74:30 + | +74 | pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: found struct without + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 20 previous errors + From 7ac5e96f4af8efe4a7f09a873d81006329cb5133 Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Sun, 11 Feb 2018 21:31:42 +0100 Subject: [PATCH 16/35] [improper_ctypes] Use a 'help:' line for possible fixes --- src/librustc_lint/types.rs | 177 +++++++++++++++++++++------------ src/test/ui/lint-ctypes.stderr | 59 ++++++++--- 2 files changed, 156 insertions(+), 80 deletions(-) diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index f734f3182a931..b6e8ae9694269 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -353,13 +353,18 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, } +struct FfiError { + message: &'static str, + help: Option<&'static str>, +} + enum FfiResult { FfiSafe, FfiPhantom, - FfiUnsafe(&'static str), - FfiBadStruct(DefId, &'static str), - FfiBadUnion(DefId, &'static str), - FfiBadEnum(DefId, &'static str), + FfiUnsafe(FfiError), + FfiBadStruct(DefId, FfiError), + FfiBadUnion(DefId, FfiError), + FfiBadEnum(DefId, FfiError), } /// Check if this enum can be safely exported based on the @@ -434,14 +439,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match def.adt_kind() { AdtKind::Struct => { if !def.repr.c() && !def.repr.transparent() { - return FfiUnsafe("found struct without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(C)] attribute to the type"); + return FfiUnsafe(FfiError { + message: "found struct without foreign-function-safe \ + representation annotation in foreign module", + help: Some("consider adding a #[repr(C)] attribute to the type"), + }); } if def.non_enum_variant().fields.is_empty() { - return FfiUnsafe("found zero-size struct in foreign module, consider \ - adding a member to this struct"); + return FfiUnsafe(FfiError { + message: "found zero-size struct in foreign module", + help: Some("consider adding a member to this struct"), + }); } // We can't completely trust repr(C) and repr(transparent) markings; @@ -471,8 +480,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { - return FfiBadStruct(def.did, s); + FfiUnsafe(err) => { + return FfiBadStruct(def.did, err); } } } @@ -481,14 +490,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } AdtKind::Union => { if !def.repr.c() { - return FfiUnsafe("found union without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(C)] attribute to the type"); + return FfiUnsafe(FfiError { + message: "found union without foreign-function-safe \ + representation annotation in foreign module", + help: Some("consider adding a #[repr(C)] attribute to the type"), + }); } if def.non_enum_variant().fields.is_empty() { - return FfiUnsafe("found zero-size union in foreign module, consider \ - adding a member to this union"); + return FfiUnsafe(FfiError { + message: "found zero-size union in foreign module", + help: Some("consider adding a member to this union"), + }); } let mut all_phantom = true; @@ -505,8 +518,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { - return FfiBadUnion(def.did, s); + FfiUnsafe(err) => { + return FfiBadUnion(def.did, err); } } } @@ -524,10 +537,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if !def.repr.c() && def.repr.int.is_none() { // Special-case types like `Option`. if !is_repr_nullable_ptr(cx, def, substs) { - return FfiUnsafe("found enum without foreign-function-safe \ - representation annotation in foreign \ - module, consider adding a #[repr(...)] \ - attribute to the type"); + return FfiUnsafe(FfiError { + message: "found enum without foreign-function-safe \ + representation annotation in foreign module", + help: Some("consider adding a #[repr(...)] attribute \ + to the type"), + }); } } @@ -535,7 +550,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if !is_ffi_safe(int_ty) { // FIXME: This shouldn't be reachable: we should check // this earlier. - return FfiUnsafe("enum has unexpected #[repr(...)] attribute"); + return FfiUnsafe(FfiError { + message: "enum has unexpected #[repr(...)] attribute", + help: None, + }); } // Enum with an explicitly sized discriminant; either @@ -558,11 +576,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return r; } FfiPhantom => { - return FfiBadEnum(def.did, - "Found phantom data in enum variant"); + return FfiBadEnum(def.did, FfiError { + message: "Found phantom data in enum variant", + help: None, + }); } - FfiUnsafe(s) => { - return FfiBadEnum(def.did, s); + FfiUnsafe(err) => { + return FfiBadEnum(def.did, err); } } } @@ -573,43 +593,57 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } ty::TyChar => { - FfiUnsafe("found Rust type `char` in foreign module, while \ - `u32` or `libc::wchar_t` should be used") + FfiUnsafe(FfiError { + message: "found Rust type `char` in foreign module", + help: Some("consider using `u32` or `libc::wchar_t`"), + }) } ty::TyInt(ast::IntTy::I128) => { - FfiUnsafe("found Rust type `i128` in foreign module, but \ - 128-bit integers don't currently have a known \ - stable ABI") + FfiUnsafe(FfiError { + message: "found Rust type `i128` in foreign module, but 128-bit \ + integers don't currently have a known stable ABI", + help: None, + }) } ty::TyUint(ast::UintTy::U128) => { - FfiUnsafe("found Rust type `u128` in foreign module, but \ - 128-bit integers don't currently have a known \ - stable ABI") + FfiUnsafe(FfiError { + message: "found Rust type `u128` in foreign module, but 128-bit \ + integers don't currently have a known stable ABI", + help: None, + }) } // Primitive types with a stable representation. ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe, ty::TySlice(_) => { - FfiUnsafe("found Rust slice type in foreign module, \ - consider using a raw pointer instead") + FfiUnsafe(FfiError { + message: "found Rust slice type in foreign module", + help: Some("consider using a raw pointer instead"), + }) } ty::TyDynamic(..) => { - FfiUnsafe("found Rust trait type in foreign module, \ - consider using a raw pointer instead") + FfiUnsafe(FfiError { + message: "found Rust trait type in foreign module", + help: Some("consider using a raw pointer instead"), + }) } ty::TyStr => { - FfiUnsafe("found Rust type `str` in foreign module; \ - consider using a `*const libc::c_char`") + FfiUnsafe(FfiError { + message: "found Rust type `str` in foreign module", + help: Some("consider using a `*const libc::c_char`"), + }) } ty::TyTuple(..) => { - FfiUnsafe("found Rust tuple type in foreign module; \ - consider using a struct instead") + FfiUnsafe(FfiError { + message: "found Rust tuple type in foreign module", + help: Some("consider using a struct instead"), + }) } ty::TyRawPtr(ref m) | @@ -620,9 +654,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::TyFnPtr(sig) => { match sig.abi() { Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => { - return FfiUnsafe("found function pointer with Rust calling convention in \ - foreign module; consider using an `extern` function \ - pointer") + return FfiUnsafe(FfiError { + message: "found function pointer with Rust calling convention in \ + foreign module", + help: Some("consider using an `extern` function pointer"), + }) } _ => {} } @@ -676,34 +712,45 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { &format!("found zero-sized type composed only \ of phantom-data in a foreign-function.")); } - FfiResult::FfiUnsafe(s) => { - self.cx.span_lint(IMPROPER_CTYPES, sp, s); + FfiResult::FfiUnsafe(err) => { + let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, err.message); + if let Some(s) = err.help { + diag.help(s); + } + diag.emit(); } - FfiResult::FfiBadStruct(_, s) => { + FfiResult::FfiBadStruct(_, err) => { // FIXME: This diagnostic is difficult to read, and doesn't // point at the relevant field. - self.cx.span_lint(IMPROPER_CTYPES, - sp, - &format!("found non-foreign-function-safe member in struct \ - marked #[repr(C)]: {}", - s)); + let msg = format!("found non-foreign-function-safe member in struct \ + marked #[repr(C)]: {}", err.message); + let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg); + if let Some(s) = err.help { + diag.help(s); + } + diag.emit(); } - FfiResult::FfiBadUnion(_, s) => { + FfiResult::FfiBadUnion(_, err) => { // FIXME: This diagnostic is difficult to read, and doesn't // point at the relevant field. - self.cx.span_lint(IMPROPER_CTYPES, - sp, - &format!("found non-foreign-function-safe member in union \ - marked #[repr(C)]: {}", - s)); + let msg = format!("found non-foreign-function-safe member in union \ + marked #[repr(C)]: {}", err.message); + let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg); + if let Some(s) = err.help { + diag.help(s); + } + diag.emit(); } - FfiResult::FfiBadEnum(_, s) => { + FfiResult::FfiBadEnum(_, err) => { // FIXME: This diagnostic is difficult to read, and doesn't // point at the relevant variant. - self.cx.span_lint(IMPROPER_CTYPES, - sp, - &format!("found non-foreign-function-safe member in enum: {}", - s)); + let msg = format!("found non-foreign-function-safe member in enum: {}", + err.message); + let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg); + if let Some(s) = err.help { + diag.help(s); + } + diag.emit(); } } } diff --git a/src/test/ui/lint-ctypes.stderr b/src/test/ui/lint-ctypes.stderr index 21aadde8ac87c..0f7f7e048e3ab 100644 --- a/src/test/ui/lint-ctypes.stderr +++ b/src/test/ui/lint-ctypes.stderr @@ -1,4 +1,4 @@ -error: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type +error: found struct without foreign-function-safe representation annotation in foreign module --> $DIR/lint-ctypes.rs:54:28 | 54 | pub fn ptr_type1(size: *const Foo); //~ ERROR: found struct without @@ -9,36 +9,47 @@ note: lint level defined here | 11 | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ + = help: consider adding a #[repr(C)] attribute to the type -error: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type +error: found struct without foreign-function-safe representation annotation in foreign module --> $DIR/lint-ctypes.rs:55:28 | 55 | pub fn ptr_type2(size: *const Foo); //~ ERROR: found struct without | ^^^^^^^^^^ + | + = help: consider adding a #[repr(C)] attribute to the type -error: found Rust slice type in foreign module, consider using a raw pointer instead +error: found Rust slice type in foreign module --> $DIR/lint-ctypes.rs:56:26 | 56 | pub fn slice_type(p: &[u32]); //~ ERROR: found Rust slice type | ^^^^^^ + | + = help: consider using a raw pointer instead -error: found Rust type `str` in foreign module; consider using a `*const libc::c_char` +error: found Rust type `str` in foreign module --> $DIR/lint-ctypes.rs:57:24 | 57 | pub fn str_type(p: &str); //~ ERROR: found Rust type | ^^^^ + | + = help: consider using a `*const libc::c_char` -error: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type +error: found struct without foreign-function-safe representation annotation in foreign module --> $DIR/lint-ctypes.rs:58:24 | 58 | pub fn box_type(p: Box); //~ ERROR found struct without | ^^^^^^^^ + | + = help: consider adding a #[repr(C)] attribute to the type -error: found Rust type `char` in foreign module, while `u32` or `libc::wchar_t` should be used +error: found Rust type `char` in foreign module --> $DIR/lint-ctypes.rs:59:25 | 59 | pub fn char_type(p: char); //~ ERROR found Rust type | ^^^^ + | + = help: consider using `u32` or `libc::wchar_t` error: found Rust type `i128` in foreign module, but 128-bit integers don't currently have a known stable ABI --> $DIR/lint-ctypes.rs:60:25 @@ -52,29 +63,37 @@ error: found Rust type `u128` in foreign module, but 128-bit integers don't curr 61 | pub fn u128_type(p: u128); //~ ERROR found Rust type | ^^^^ -error: found Rust trait type in foreign module, consider using a raw pointer instead +error: found Rust trait type in foreign module --> $DIR/lint-ctypes.rs:62:26 | 62 | pub fn trait_type(p: &Clone); //~ ERROR found Rust trait type | ^^^^^^ + | + = help: consider using a raw pointer instead -error: found Rust tuple type in foreign module; consider using a struct instead +error: found Rust tuple type in foreign module --> $DIR/lint-ctypes.rs:63:26 | 63 | pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type | ^^^^^^^^^^ + | + = help: consider using a struct instead -error: found Rust tuple type in foreign module; consider using a struct instead +error: found Rust tuple type in foreign module --> $DIR/lint-ctypes.rs:64:27 | 64 | pub fn tuple_type2(p: I32Pair); //~ ERROR found Rust tuple type | ^^^^^^^ + | + = help: consider using a struct instead -error: found zero-size struct in foreign module, consider adding a member to this struct +error: found zero-size struct in foreign module --> $DIR/lint-ctypes.rs:65:25 | 65 | pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct | ^^^^^^^^ + | + = help: consider adding a member to this struct error: found zero-sized type composed only of phantom-data in a foreign-function. --> $DIR/lint-ctypes.rs:66:33 @@ -88,23 +107,29 @@ error: found zero-sized type composed only of phantom-data in a foreign-function 68 | -> ::std::marker::PhantomData; //~ ERROR: found zero-sized type | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: found function pointer with Rust calling convention in foreign module; consider using an `extern` function pointer +error: found function pointer with Rust calling convention in foreign module --> $DIR/lint-ctypes.rs:69:23 | 69 | pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust | ^^^^^^ + | + = help: consider using an `extern` function pointer -error: found function pointer with Rust calling convention in foreign module; consider using an `extern` function pointer +error: found function pointer with Rust calling convention in foreign module --> $DIR/lint-ctypes.rs:70:24 | 70 | pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust | ^^^^ + | + = help: consider using an `extern` function pointer -error: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type +error: found struct without foreign-function-safe representation annotation in foreign module --> $DIR/lint-ctypes.rs:71:28 | 71 | pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without | ^^^^^^^^^^ + | + = help: consider adding a #[repr(C)] attribute to the type error: found non-foreign-function-safe member in struct marked #[repr(C)]: found Rust type `i128` in foreign module, but 128-bit integers don't currently have a known stable ABI --> $DIR/lint-ctypes.rs:72:32 @@ -112,17 +137,21 @@ error: found non-foreign-function-safe member in struct marked #[repr(C)]: found 72 | pub fn transparent_i128(p: TransparentI128); //~ ERROR: found Rust type `i128` | ^^^^^^^^^^^^^^^ -error: found non-foreign-function-safe member in struct marked #[repr(C)]: found Rust type `str` in foreign module; consider using a `*const libc::c_char` +error: found non-foreign-function-safe member in struct marked #[repr(C)]: found Rust type `str` in foreign module --> $DIR/lint-ctypes.rs:73:31 | 73 | pub fn transparent_str(p: TransparentStr); //~ ERROR: found Rust type `str` | ^^^^^^^^^^^^^^ + | + = help: consider using a `*const libc::c_char` -error: found non-foreign-function-safe member in struct marked #[repr(C)]: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type +error: found non-foreign-function-safe member in struct marked #[repr(C)]: found struct without foreign-function-safe representation annotation in foreign module --> $DIR/lint-ctypes.rs:74:30 | 74 | pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: found struct without | ^^^^^^^^^^^^^^^^ + | + = help: consider adding a #[repr(C)] attribute to the type error: aborting due to 20 previous errors From ae92dfac5019643b8fb310de9e92f0889b0106ca Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Sun, 11 Feb 2018 21:54:56 +0100 Subject: [PATCH 17/35] [improper_ctypes] Stop complaining about repr(usize) and repr(isize) enums This dates back to at least #26583. At the time, usize and isize were considered ffi-unsafe to nudge people away from them, but this changed in the aforementioned PR, making it inconsistent to complain about it in enum discriminants. In fact, repr(usize) is probably the best way to interface with `enum Foo : size_t { ... }`. --- src/librustc_lint/types.rs | 29 ----------------------- src/test/compile-fail/lint-ctypes-enum.rs | 12 ++++++++++ 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index b6e8ae9694269..f17fa9c7ca1d2 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -26,7 +26,6 @@ use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; use syntax::ast; use syntax::abi::Abi; -use syntax::attr; use syntax_pos::Span; use syntax::codemap; @@ -402,17 +401,6 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, false } -fn is_ffi_safe(ty: attr::IntType) -> bool { - match ty { - attr::SignedInt(ast::IntTy::I8) | attr::UnsignedInt(ast::UintTy::U8) | - attr::SignedInt(ast::IntTy::I16) | attr::UnsignedInt(ast::UintTy::U16) | - attr::SignedInt(ast::IntTy::I32) | attr::UnsignedInt(ast::UintTy::U32) | - attr::SignedInt(ast::IntTy::I64) | attr::UnsignedInt(ast::UintTy::U64) | - attr::SignedInt(ast::IntTy::I128) | attr::UnsignedInt(ast::UintTy::U128) => true, - attr::SignedInt(ast::IntTy::Isize) | attr::UnsignedInt(ast::UintTy::Usize) => false - } -} - impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Check if the given type is "ffi-safe" (has a stable, well-defined /// representation which can be exported to C code). @@ -546,23 +534,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - if let Some(int_ty) = def.repr.int { - if !is_ffi_safe(int_ty) { - // FIXME: This shouldn't be reachable: we should check - // this earlier. - return FfiUnsafe(FfiError { - message: "enum has unexpected #[repr(...)] attribute", - help: None, - }); - } - - // Enum with an explicitly sized discriminant; either - // a C-style enum or a discriminated union. - - // The layout of enum variants is implicitly repr(C). - // FIXME: Is that correct? - } - // Check the contained variants. for variant in &def.variants { for field in &variant.fields { diff --git a/src/test/compile-fail/lint-ctypes-enum.rs b/src/test/compile-fail/lint-ctypes-enum.rs index e35dadbea9d4d..ce6afe1d219ea 100644 --- a/src/test/compile-fail/lint-ctypes-enum.rs +++ b/src/test/compile-fail/lint-ctypes-enum.rs @@ -16,11 +16,23 @@ enum U { A } enum B { C, D } enum T { E, F, G } +#[repr(C)] +enum ReprC { A, B, C } + +#[repr(u8)] +enum U8 { A, B, C } + +#[repr(isize)] +enum Isize { A, B, C } + extern { fn zf(x: Z); fn uf(x: U); //~ ERROR found enum without foreign-function-safe fn bf(x: B); //~ ERROR found enum without foreign-function-safe fn tf(x: T); //~ ERROR found enum without foreign-function-safe + fn reprc(x: ReprC); + fn u8(x: U8); + fn isize(x: Isize); } pub fn main() { } From 9b5f47ec48e8c12b68cff7cc64afe166358183ef Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Mon, 12 Feb 2018 01:08:48 +0100 Subject: [PATCH 18/35] [improper_ctypes] Overhaul primary label - Always name the non-FFI-safe - Explain *why* the type is not FFI-safe - Stop vaguely gesturing at structs/enums/unions if the non-FFI-safe types occured in a field. The last part is arguably a regression, but it's minor now that the non-FFI-safe type is actually named. Removing it avoids some code duplication. --- src/librustc_lint/types.rs | 238 ++++++++------------ src/test/compile-fail/issue-14309.rs | 10 +- src/test/compile-fail/issue-16250.rs | 2 +- src/test/compile-fail/lint-ctypes-enum.rs | 6 +- src/test/compile-fail/union/union-repr-c.rs | 2 +- src/test/ui/lint-ctypes.rs | 40 ++-- src/test/ui/lint-ctypes.stderr | 100 ++++---- 7 files changed, 171 insertions(+), 227 deletions(-) diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index f17fa9c7ca1d2..7203b1b1e7dae 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -10,7 +10,6 @@ #![allow(non_snake_case)] -use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; @@ -352,18 +351,14 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, } -struct FfiError { - message: &'static str, - help: Option<&'static str>, -} - -enum FfiResult { +enum FfiResult<'tcx> { FfiSafe, - FfiPhantom, - FfiUnsafe(FfiError), - FfiBadStruct(DefId, FfiError), - FfiBadUnion(DefId, FfiError), - FfiBadEnum(DefId, FfiError), + FfiPhantom(Ty<'tcx>), + FfiUnsafe { + ty: Ty<'tcx>, + reason: &'static str, + help: Option<&'static str>, + }, } /// Check if this enum can be safely exported based on the @@ -406,7 +401,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// representation which can be exported to C code). fn check_type_for_ffi(&self, cache: &mut FxHashSet>, - ty: Ty<'tcx>) -> FfiResult { + ty: Ty<'tcx>) -> FfiResult<'tcx> { use self::FfiResult::*; let cx = self.cx.tcx; @@ -422,23 +417,24 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match ty.sty { ty::TyAdt(def, substs) => { if def.is_phantom_data() { - return FfiPhantom; + return FfiPhantom(ty); } match def.adt_kind() { AdtKind::Struct => { if !def.repr.c() && !def.repr.transparent() { - return FfiUnsafe(FfiError { - message: "found struct without foreign-function-safe \ - representation annotation in foreign module", - help: Some("consider adding a #[repr(C)] attribute to the type"), - }); + return FfiUnsafe { + ty: ty, + reason: "this struct has unspecified layout", + help: Some("consider adding a #[repr(C)] attribute to this struct"), + }; } if def.non_enum_variant().fields.is_empty() { - return FfiUnsafe(FfiError { - message: "found zero-size struct in foreign module", + return FfiUnsafe { + ty: ty, + reason: "this struct has no fields", help: Some("consider adding a member to this struct"), - }); + }; } // We can't completely trust repr(C) and repr(transparent) markings; @@ -464,32 +460,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiSafe => { all_phantom = false; } - FfiPhantom => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { + FfiPhantom(..) => {} + FfiUnsafe { .. } => { return r; } - FfiUnsafe(err) => { - return FfiBadStruct(def.did, err); - } } } - if all_phantom { FfiPhantom } else { FfiSafe } + if all_phantom { FfiPhantom(ty) } else { FfiSafe } } AdtKind::Union => { if !def.repr.c() { - return FfiUnsafe(FfiError { - message: "found union without foreign-function-safe \ - representation annotation in foreign module", - help: Some("consider adding a #[repr(C)] attribute to the type"), - }); + return FfiUnsafe { + ty: ty, + reason: "this union has unspecified layout", + help: Some("consider adding a #[repr(C)] attribute to this union"), + }; } if def.non_enum_variant().fields.is_empty() { - return FfiUnsafe(FfiError { - message: "found zero-size union in foreign module", - help: Some("consider adding a member to this union"), - }); + return FfiUnsafe { + ty: ty, + reason: "this union has no fields", + help: Some("consider adding a field to this union"), + }; } let mut all_phantom = true; @@ -502,17 +496,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiSafe => { all_phantom = false; } - FfiPhantom => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { + FfiPhantom(..) => {} + FfiUnsafe { .. } => { return r; } - FfiUnsafe(err) => { - return FfiBadUnion(def.did, err); - } } } - if all_phantom { FfiPhantom } else { FfiSafe } + if all_phantom { FfiPhantom(ty) } else { FfiSafe } } AdtKind::Enum => { if def.variants.is_empty() { @@ -525,12 +516,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if !def.repr.c() && def.repr.int.is_none() { // Special-case types like `Option`. if !is_repr_nullable_ptr(cx, def, substs) { - return FfiUnsafe(FfiError { - message: "found enum without foreign-function-safe \ - representation annotation in foreign module", + return FfiUnsafe { + ty: ty, + reason: "enum has no representation hint", help: Some("consider adding a #[repr(...)] attribute \ - to the type"), - }); + to this enum"), + }; } } @@ -543,17 +534,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let r = self.check_type_for_ffi(cache, arg); match r { FfiSafe => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { + FfiUnsafe { .. } => { return r; } - FfiPhantom => { - return FfiBadEnum(def.did, FfiError { - message: "Found phantom data in enum variant", + FfiPhantom(..) => { + return FfiUnsafe { + ty: ty, + reason: "this enum contains a PhantomData field", help: None, - }); - } - FfiUnsafe(err) => { - return FfiBadEnum(def.did, err); + }; } } } @@ -563,59 +552,44 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - ty::TyChar => { - FfiUnsafe(FfiError { - message: "found Rust type `char` in foreign module", - help: Some("consider using `u32` or `libc::wchar_t`"), - }) - } + ty::TyChar => FfiUnsafe { + ty: ty, + reason: "the `char` type has no C equivalent", + help: Some("consider using `u32` or `libc::wchar_t` instead"), + }, - ty::TyInt(ast::IntTy::I128) => { - FfiUnsafe(FfiError { - message: "found Rust type `i128` in foreign module, but 128-bit \ - integers don't currently have a known stable ABI", - help: None, - }) - } - - ty::TyUint(ast::UintTy::U128) => { - FfiUnsafe(FfiError { - message: "found Rust type `u128` in foreign module, but 128-bit \ - integers don't currently have a known stable ABI", - help: None, - }) - } + ty::TyInt(ast::IntTy::I128) | ty::TyUint(ast::UintTy::U128) => FfiUnsafe { + ty: ty, + reason: "128-bit integers don't currently have a known stable ABI", + help: None, + }, // Primitive types with a stable representation. ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe, - ty::TySlice(_) => { - FfiUnsafe(FfiError { - message: "found Rust slice type in foreign module", - help: Some("consider using a raw pointer instead"), - }) - } - - ty::TyDynamic(..) => { - FfiUnsafe(FfiError { - message: "found Rust trait type in foreign module", - help: Some("consider using a raw pointer instead"), - }) - } - - ty::TyStr => { - FfiUnsafe(FfiError { - message: "found Rust type `str` in foreign module", - help: Some("consider using a `*const libc::c_char`"), - }) - } - - ty::TyTuple(..) => { - FfiUnsafe(FfiError { - message: "found Rust tuple type in foreign module", - help: Some("consider using a struct instead"), - }) - } + ty::TySlice(_) => FfiUnsafe { + ty: ty, + reason: "slices have no C equivalent", + help: Some("consider using a raw pointer instead"), + }, + + ty::TyDynamic(..) => FfiUnsafe { + ty: ty, + reason: "trait objects have no C equivalent", + help: Some("consider using a raw pointer instead"), + }, + + ty::TyStr => FfiUnsafe { + ty: ty, + reason: "string slices have no C equivalent", + help: Some("consider using `*const u8` and a length instead"), + }, + + ty::TyTuple(..) => FfiUnsafe { + ty: ty, + reason: "tuples have unspecified layout", + help: Some("consider using a struct instead"), + }, ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => self.check_type_for_ffi(cache, m.ty), @@ -625,11 +599,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::TyFnPtr(sig) => { match sig.abi() { Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => { - return FfiUnsafe(FfiError { - message: "found function pointer with Rust calling convention in \ - foreign module", - help: Some("consider using an `extern` function pointer"), - }) + return FfiUnsafe { + ty: ty, + reason: "this function pointer has Rust-specific calling convention", + help: Some("consider using an `fn \"extern\"(...) -> ...` \ + function pointer instead"), + } } _ => {} } @@ -677,48 +652,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match self.check_type_for_ffi(&mut FxHashSet(), ty) { FfiResult::FfiSafe => {} - FfiResult::FfiPhantom => { + FfiResult::FfiPhantom(ty) => { self.cx.span_lint(IMPROPER_CTYPES, sp, - &format!("found zero-sized type composed only \ - of phantom-data in a foreign-function.")); - } - FfiResult::FfiUnsafe(err) => { - let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, err.message); - if let Some(s) = err.help { - diag.help(s); - } - diag.emit(); - } - FfiResult::FfiBadStruct(_, err) => { - // FIXME: This diagnostic is difficult to read, and doesn't - // point at the relevant field. - let msg = format!("found non-foreign-function-safe member in struct \ - marked #[repr(C)]: {}", err.message); - let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg); - if let Some(s) = err.help { - diag.help(s); - } - diag.emit(); - } - FfiResult::FfiBadUnion(_, err) => { - // FIXME: This diagnostic is difficult to read, and doesn't - // point at the relevant field. - let msg = format!("found non-foreign-function-safe member in union \ - marked #[repr(C)]: {}", err.message); - let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg); - if let Some(s) = err.help { - diag.help(s); - } - diag.emit(); + &format!("`extern` block uses type `{}` which is not FFI-safe: \ + composed only of PhantomData", ty)); } - FfiResult::FfiBadEnum(_, err) => { - // FIXME: This diagnostic is difficult to read, and doesn't - // point at the relevant variant. - let msg = format!("found non-foreign-function-safe member in enum: {}", - err.message); + FfiResult::FfiUnsafe { ty: unsafe_ty, reason, help } => { + let msg = format!("`extern` block uses type `{}` which is not FFI-safe: {}", + unsafe_ty, reason); let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg); - if let Some(s) = err.help { + if let Some(s) = help { diag.help(s); } diag.emit(); diff --git a/src/test/compile-fail/issue-14309.rs b/src/test/compile-fail/issue-14309.rs index 56261c34a0308..f76fa3e4a8ece 100644 --- a/src/test/compile-fail/issue-14309.rs +++ b/src/test/compile-fail/issue-14309.rs @@ -37,13 +37,13 @@ struct D { } extern "C" { - fn foo(x: A); //~ ERROR found struct without foreign-function-safe - fn bar(x: B); //~ ERROR foreign-function-safe + fn foo(x: A); //~ ERROR type `A` which is not FFI-safe + fn bar(x: B); //~ ERROR type `A` fn baz(x: C); - fn qux(x: A2); //~ ERROR foreign-function-safe - fn quux(x: B2); //~ ERROR foreign-function-safe + fn qux(x: A2); //~ ERROR type `A` + fn quux(x: B2); //~ ERROR type `A` fn corge(x: C2); - fn fred(x: D); //~ ERROR foreign-function-safe + fn fred(x: D); //~ ERROR type `A` } fn main() { } diff --git a/src/test/compile-fail/issue-16250.rs b/src/test/compile-fail/issue-16250.rs index 288fe4a9abb82..f9d01003005e4 100644 --- a/src/test/compile-fail/issue-16250.rs +++ b/src/test/compile-fail/issue-16250.rs @@ -13,7 +13,7 @@ pub struct Foo; extern { - pub fn foo(x: (Foo)); //~ ERROR found struct without + pub fn foo(x: (Foo)); //~ ERROR unspecified layout } fn main() { diff --git a/src/test/compile-fail/lint-ctypes-enum.rs b/src/test/compile-fail/lint-ctypes-enum.rs index ce6afe1d219ea..7b7ffd8fc107c 100644 --- a/src/test/compile-fail/lint-ctypes-enum.rs +++ b/src/test/compile-fail/lint-ctypes-enum.rs @@ -27,9 +27,9 @@ enum Isize { A, B, C } extern { fn zf(x: Z); - fn uf(x: U); //~ ERROR found enum without foreign-function-safe - fn bf(x: B); //~ ERROR found enum without foreign-function-safe - fn tf(x: T); //~ ERROR found enum without foreign-function-safe + fn uf(x: U); //~ ERROR enum has no representation hint + fn bf(x: B); //~ ERROR enum has no representation hint + fn tf(x: T); //~ ERROR enum has no representation hint fn reprc(x: ReprC); fn u8(x: U8); fn isize(x: Isize); diff --git a/src/test/compile-fail/union/union-repr-c.rs b/src/test/compile-fail/union/union-repr-c.rs index 15a4197fe94c9..36c42ce1104e0 100644 --- a/src/test/compile-fail/union/union-repr-c.rs +++ b/src/test/compile-fail/union/union-repr-c.rs @@ -22,7 +22,7 @@ union W { extern "C" { static FOREIGN1: U; // OK - static FOREIGN2: W; //~ ERROR found union without foreign-function-safe representation + static FOREIGN2: W; //~ ERROR union has unspecified layout } fn main() {} diff --git a/src/test/ui/lint-ctypes.rs b/src/test/ui/lint-ctypes.rs index c22239dee0a80..77cb1ef0f5130 100644 --- a/src/test/ui/lint-ctypes.rs +++ b/src/test/ui/lint-ctypes.rs @@ -51,27 +51,27 @@ pub struct TransparentCustomZst(i32, ZeroSize); pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData); extern { - pub fn ptr_type1(size: *const Foo); //~ ERROR: found struct without - pub fn ptr_type2(size: *const Foo); //~ ERROR: found struct without - pub fn slice_type(p: &[u32]); //~ ERROR: found Rust slice type - pub fn str_type(p: &str); //~ ERROR: found Rust type - pub fn box_type(p: Box); //~ ERROR found struct without - pub fn char_type(p: char); //~ ERROR found Rust type - pub fn i128_type(p: i128); //~ ERROR found Rust type - pub fn u128_type(p: u128); //~ ERROR found Rust type - pub fn trait_type(p: &Clone); //~ ERROR found Rust trait type - pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type - pub fn tuple_type2(p: I32Pair); //~ ERROR found Rust tuple type - pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct - pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR found zero-sized type + pub fn ptr_type1(size: *const Foo); //~ ERROR: uses type `Foo` + pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo` + pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]` + pub fn str_type(p: &str); //~ ERROR: uses type `str` + pub fn box_type(p: Box); //~ ERROR uses type `std::boxed::Box` + pub fn char_type(p: char); //~ ERROR uses type `char` + pub fn i128_type(p: i128); //~ ERROR uses type `i128` + pub fn u128_type(p: u128); //~ ERROR uses type `u128` + pub fn trait_type(p: &Clone); //~ ERROR uses type `std::clone::Clone` + pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)` + pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)` + pub fn zero_size(p: ZeroSize); //~ ERROR struct has no fields + pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR composed only of PhantomData pub fn zero_size_phantom_toplevel() - -> ::std::marker::PhantomData; //~ ERROR: found zero-sized type - pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust - pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust - pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without - pub fn transparent_i128(p: TransparentI128); //~ ERROR: found Rust type `i128` - pub fn transparent_str(p: TransparentStr); //~ ERROR: found Rust type `str` - pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: found struct without + -> ::std::marker::PhantomData; //~ ERROR: composed only of PhantomData + pub fn fn_type(p: RustFn); //~ ERROR function pointer has Rust-specific + pub fn fn_type2(p: fn()); //~ ERROR function pointer has Rust-specific + pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `std::boxed::Box` + pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128` + pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str` + pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `std::boxed::Box` pub fn good3(fptr: Option); pub fn good4(aptr: &[u8; 4 as usize]); diff --git a/src/test/ui/lint-ctypes.stderr b/src/test/ui/lint-ctypes.stderr index 0f7f7e048e3ab..8ecdae07a5329 100644 --- a/src/test/ui/lint-ctypes.stderr +++ b/src/test/ui/lint-ctypes.stderr @@ -1,7 +1,7 @@ -error: found struct without foreign-function-safe representation annotation in foreign module +error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout --> $DIR/lint-ctypes.rs:54:28 | -54 | pub fn ptr_type1(size: *const Foo); //~ ERROR: found struct without +54 | pub fn ptr_type1(size: *const Foo); //~ ERROR: uses type `Foo` | ^^^^^^^^^^ | note: lint level defined here @@ -9,149 +9,149 @@ note: lint level defined here | 11 | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ - = help: consider adding a #[repr(C)] attribute to the type + = help: consider adding a #[repr(C)] attribute to this struct -error: found struct without foreign-function-safe representation annotation in foreign module +error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout --> $DIR/lint-ctypes.rs:55:28 | -55 | pub fn ptr_type2(size: *const Foo); //~ ERROR: found struct without +55 | pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo` | ^^^^^^^^^^ | - = help: consider adding a #[repr(C)] attribute to the type + = help: consider adding a #[repr(C)] attribute to this struct -error: found Rust slice type in foreign module +error: `extern` block uses type `[u32]` which is not FFI-safe: slices have no C equivalent --> $DIR/lint-ctypes.rs:56:26 | -56 | pub fn slice_type(p: &[u32]); //~ ERROR: found Rust slice type +56 | pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]` | ^^^^^^ | = help: consider using a raw pointer instead -error: found Rust type `str` in foreign module +error: `extern` block uses type `str` which is not FFI-safe: string slices have no C equivalent --> $DIR/lint-ctypes.rs:57:24 | -57 | pub fn str_type(p: &str); //~ ERROR: found Rust type +57 | pub fn str_type(p: &str); //~ ERROR: uses type `str` | ^^^^ | - = help: consider using a `*const libc::c_char` + = help: consider using `*const u8` and a length instead -error: found struct without foreign-function-safe representation annotation in foreign module +error: `extern` block uses type `std::boxed::Box` which is not FFI-safe: this struct has unspecified layout --> $DIR/lint-ctypes.rs:58:24 | -58 | pub fn box_type(p: Box); //~ ERROR found struct without +58 | pub fn box_type(p: Box); //~ ERROR uses type `std::boxed::Box` | ^^^^^^^^ | - = help: consider adding a #[repr(C)] attribute to the type + = help: consider adding a #[repr(C)] attribute to this struct -error: found Rust type `char` in foreign module +error: `extern` block uses type `char` which is not FFI-safe: the `char` type has no C equivalent --> $DIR/lint-ctypes.rs:59:25 | -59 | pub fn char_type(p: char); //~ ERROR found Rust type +59 | pub fn char_type(p: char); //~ ERROR uses type `char` | ^^^^ | - = help: consider using `u32` or `libc::wchar_t` + = help: consider using `u32` or `libc::wchar_t` instead -error: found Rust type `i128` in foreign module, but 128-bit integers don't currently have a known stable ABI +error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI --> $DIR/lint-ctypes.rs:60:25 | -60 | pub fn i128_type(p: i128); //~ ERROR found Rust type +60 | pub fn i128_type(p: i128); //~ ERROR uses type `i128` | ^^^^ -error: found Rust type `u128` in foreign module, but 128-bit integers don't currently have a known stable ABI +error: `extern` block uses type `u128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI --> $DIR/lint-ctypes.rs:61:25 | -61 | pub fn u128_type(p: u128); //~ ERROR found Rust type +61 | pub fn u128_type(p: u128); //~ ERROR uses type `u128` | ^^^^ -error: found Rust trait type in foreign module +error: `extern` block uses type `std::clone::Clone` which is not FFI-safe: trait objects have no C equivalent --> $DIR/lint-ctypes.rs:62:26 | -62 | pub fn trait_type(p: &Clone); //~ ERROR found Rust trait type +62 | pub fn trait_type(p: &Clone); //~ ERROR uses type `std::clone::Clone` | ^^^^^^ | = help: consider using a raw pointer instead -error: found Rust tuple type in foreign module +error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout --> $DIR/lint-ctypes.rs:63:26 | -63 | pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type +63 | pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)` | ^^^^^^^^^^ | = help: consider using a struct instead -error: found Rust tuple type in foreign module +error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout --> $DIR/lint-ctypes.rs:64:27 | -64 | pub fn tuple_type2(p: I32Pair); //~ ERROR found Rust tuple type +64 | pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)` | ^^^^^^^ | = help: consider using a struct instead -error: found zero-size struct in foreign module +error: `extern` block uses type `ZeroSize` which is not FFI-safe: this struct has no fields --> $DIR/lint-ctypes.rs:65:25 | -65 | pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct +65 | pub fn zero_size(p: ZeroSize); //~ ERROR struct has no fields | ^^^^^^^^ | = help: consider adding a member to this struct -error: found zero-sized type composed only of phantom-data in a foreign-function. +error: `extern` block uses type `ZeroSizeWithPhantomData` which is not FFI-safe: composed only of PhantomData --> $DIR/lint-ctypes.rs:66:33 | -66 | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR found zero-sized type +66 | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR composed only of PhantomData | ^^^^^^^^^^^^^^^^^^^^^^^ -error: found zero-sized type composed only of phantom-data in a foreign-function. +error: `extern` block uses type `std::marker::PhantomData` which is not FFI-safe: composed only of PhantomData --> $DIR/lint-ctypes.rs:68:12 | -68 | -> ::std::marker::PhantomData; //~ ERROR: found zero-sized type +68 | -> ::std::marker::PhantomData; //~ ERROR: composed only of PhantomData | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: found function pointer with Rust calling convention in foreign module +error: `extern` block uses type `fn()` which is not FFI-safe: this function pointer has Rust-specific calling convention --> $DIR/lint-ctypes.rs:69:23 | -69 | pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust +69 | pub fn fn_type(p: RustFn); //~ ERROR function pointer has Rust-specific | ^^^^^^ | - = help: consider using an `extern` function pointer + = help: consider using an `fn "extern"(...) -> ...` function pointer instead -error: found function pointer with Rust calling convention in foreign module +error: `extern` block uses type `fn()` which is not FFI-safe: this function pointer has Rust-specific calling convention --> $DIR/lint-ctypes.rs:70:24 | -70 | pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust +70 | pub fn fn_type2(p: fn()); //~ ERROR function pointer has Rust-specific | ^^^^ | - = help: consider using an `extern` function pointer + = help: consider using an `fn "extern"(...) -> ...` function pointer instead -error: found struct without foreign-function-safe representation annotation in foreign module +error: `extern` block uses type `std::boxed::Box` which is not FFI-safe: this struct has unspecified layout --> $DIR/lint-ctypes.rs:71:28 | -71 | pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without +71 | pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `std::boxed::Box` | ^^^^^^^^^^ | - = help: consider adding a #[repr(C)] attribute to the type + = help: consider adding a #[repr(C)] attribute to this struct -error: found non-foreign-function-safe member in struct marked #[repr(C)]: found Rust type `i128` in foreign module, but 128-bit integers don't currently have a known stable ABI +error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI --> $DIR/lint-ctypes.rs:72:32 | -72 | pub fn transparent_i128(p: TransparentI128); //~ ERROR: found Rust type `i128` +72 | pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128` | ^^^^^^^^^^^^^^^ -error: found non-foreign-function-safe member in struct marked #[repr(C)]: found Rust type `str` in foreign module +error: `extern` block uses type `str` which is not FFI-safe: string slices have no C equivalent --> $DIR/lint-ctypes.rs:73:31 | -73 | pub fn transparent_str(p: TransparentStr); //~ ERROR: found Rust type `str` +73 | pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str` | ^^^^^^^^^^^^^^ | - = help: consider using a `*const libc::c_char` + = help: consider using `*const u8` and a length instead -error: found non-foreign-function-safe member in struct marked #[repr(C)]: found struct without foreign-function-safe representation annotation in foreign module +error: `extern` block uses type `std::boxed::Box` which is not FFI-safe: this struct has unspecified layout --> $DIR/lint-ctypes.rs:74:30 | -74 | pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: found struct without +74 | pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `std::boxed::Box` | ^^^^^^^^^^^^^^^^ | - = help: consider adding a #[repr(C)] attribute to the type + = help: consider adding a #[repr(C)] attribute to this struct error: aborting due to 20 previous errors From 22a171609bf555833b277a70420a24696dd8805d Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Wed, 14 Feb 2018 19:39:04 +0100 Subject: [PATCH 19/35] [improper_ctypes] Suggest repr(transparent) for structs The suggestion is unconditional, so following it could lead to further errors. This is already the case for the repr(C) suggestion, which makes this acceptable, though not *good*. Checking up-front whether the suggestion can help would be great but applies more broadly (and would require some refactoring to avoid duplicating the checks). --- src/librustc_lint/types.rs | 3 ++- src/test/ui/lint-ctypes.stderr | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 7203b1b1e7dae..378fe99bf3150 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -425,7 +425,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiUnsafe { ty: ty, reason: "this struct has unspecified layout", - help: Some("consider adding a #[repr(C)] attribute to this struct"), + help: Some("consider adding a #[repr(C)] or #[repr(transparent)] \ + attribute to this struct"), }; } diff --git a/src/test/ui/lint-ctypes.stderr b/src/test/ui/lint-ctypes.stderr index 8ecdae07a5329..a8628c8b3d2d9 100644 --- a/src/test/ui/lint-ctypes.stderr +++ b/src/test/ui/lint-ctypes.stderr @@ -9,7 +9,7 @@ note: lint level defined here | 11 | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ - = help: consider adding a #[repr(C)] attribute to this struct + = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout --> $DIR/lint-ctypes.rs:55:28 @@ -17,7 +17,7 @@ error: `extern` block uses type `Foo` which is not FFI-safe: this struct has uns 55 | pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo` | ^^^^^^^^^^ | - = help: consider adding a #[repr(C)] attribute to this struct + = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct error: `extern` block uses type `[u32]` which is not FFI-safe: slices have no C equivalent --> $DIR/lint-ctypes.rs:56:26 @@ -41,7 +41,7 @@ error: `extern` block uses type `std::boxed::Box` which is not FFI-safe: th 58 | pub fn box_type(p: Box); //~ ERROR uses type `std::boxed::Box` | ^^^^^^^^ | - = help: consider adding a #[repr(C)] attribute to this struct + = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct error: `extern` block uses type `char` which is not FFI-safe: the `char` type has no C equivalent --> $DIR/lint-ctypes.rs:59:25 @@ -129,7 +129,7 @@ error: `extern` block uses type `std::boxed::Box` which is not FFI-safe: th 71 | pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `std::boxed::Box` | ^^^^^^^^^^ | - = help: consider adding a #[repr(C)] attribute to this struct + = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI --> $DIR/lint-ctypes.rs:72:32 @@ -151,7 +151,7 @@ error: `extern` block uses type `std::boxed::Box` which is not FFI-safe: th 74 | pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `std::boxed::Box` | ^^^^^^^^^^^^^^^^ | - = help: consider adding a #[repr(C)] attribute to this struct + = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct error: aborting due to 20 previous errors From 9d493c897b4382dc145b9448b3fafdfbbaecf528 Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Wed, 14 Feb 2018 23:01:39 +0100 Subject: [PATCH 20/35] [improper_ctypes] Point at definition of non-FFI-safe type if possible --- src/librustc_lint/types.rs | 5 +++++ src/test/ui/lint-ctypes.stderr | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 378fe99bf3150..396d830d85be1 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -666,6 +666,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if let Some(s) = help { diag.help(s); } + if let ty::TyAdt(def, _) = unsafe_ty.sty { + if let Some(sp) = self.cx.tcx.hir.span_if_local(def.did) { + diag.span_note(sp, "type defined here"); + } + } diag.emit(); } } diff --git a/src/test/ui/lint-ctypes.stderr b/src/test/ui/lint-ctypes.stderr index a8628c8b3d2d9..2abf08d55f7b3 100644 --- a/src/test/ui/lint-ctypes.stderr +++ b/src/test/ui/lint-ctypes.stderr @@ -10,6 +10,11 @@ note: lint level defined here 11 | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct +note: type defined here + --> $DIR/lint-ctypes.rs:32:1 + | +32 | pub struct Foo; + | ^^^^^^^^^^^^^^^ error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout --> $DIR/lint-ctypes.rs:55:28 @@ -18,6 +23,11 @@ error: `extern` block uses type `Foo` which is not FFI-safe: this struct has uns | ^^^^^^^^^^ | = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct +note: type defined here + --> $DIR/lint-ctypes.rs:32:1 + | +32 | pub struct Foo; + | ^^^^^^^^^^^^^^^ error: `extern` block uses type `[u32]` which is not FFI-safe: slices have no C equivalent --> $DIR/lint-ctypes.rs:56:26 @@ -94,6 +104,11 @@ error: `extern` block uses type `ZeroSize` which is not FFI-safe: this struct ha | ^^^^^^^^ | = help: consider adding a member to this struct +note: type defined here + --> $DIR/lint-ctypes.rs:28:1 + | +28 | pub struct ZeroSize; + | ^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `ZeroSizeWithPhantomData` which is not FFI-safe: composed only of PhantomData --> $DIR/lint-ctypes.rs:66:33 From 051ea5cc9bac00c7f588b4eae72b8a382d8ceb68 Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Wed, 14 Feb 2018 23:11:29 +0100 Subject: [PATCH 21/35] [improper_ctypes] Don't suggest raw pointers when encountering trait objects It's unhelpful since raw pointers to trait objects are also FFI-unsafe and casting to a thin raw pointer loses the vtable. There are working solutions that _involve_ raw pointers but they're too complex to explain in one line and have serious trade offs. --- src/librustc_lint/types.rs | 2 +- src/test/ui/lint-ctypes.stderr | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 396d830d85be1..ef9b3d38c637c 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -577,7 +577,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::TyDynamic(..) => FfiUnsafe { ty: ty, reason: "trait objects have no C equivalent", - help: Some("consider using a raw pointer instead"), + help: None, }, ty::TyStr => FfiUnsafe { diff --git a/src/test/ui/lint-ctypes.stderr b/src/test/ui/lint-ctypes.stderr index 2abf08d55f7b3..748c311055fa9 100644 --- a/src/test/ui/lint-ctypes.stderr +++ b/src/test/ui/lint-ctypes.stderr @@ -78,8 +78,6 @@ error: `extern` block uses type `std::clone::Clone` which is not FFI-safe: trait | 62 | pub fn trait_type(p: &Clone); //~ ERROR uses type `std::clone::Clone` | ^^^^^^ - | - = help: consider using a raw pointer instead error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout --> $DIR/lint-ctypes.rs:63:26 From 0be2dc8d9b4765e59cf9bbf3d342de00fa1b9aec Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Sat, 17 Feb 2018 14:18:53 +0000 Subject: [PATCH 22/35] fix stderr --- src/test/ui/inference-variable-behind-raw-pointer.stderr | 2 +- src/test/ui/span/issue-42234-unknown-receiver-type.stderr | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/test/ui/inference-variable-behind-raw-pointer.stderr b/src/test/ui/inference-variable-behind-raw-pointer.stderr index bb1d921f1c61c..d0ee55c092b28 100644 --- a/src/test/ui/inference-variable-behind-raw-pointer.stderr +++ b/src/test/ui/inference-variable-behind-raw-pointer.stderr @@ -1,4 +1,4 @@ -warning: type annotations needed +warning: the type of this value must be known in this context --> $DIR/inference-variable-behind-raw-pointer.rs:18:13 | 18 | if data.is_null() {} diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr index 2a85e1f1c45ba..d87cec642f18e 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr @@ -1,15 +1,17 @@ error[E0282]: type annotations needed --> $DIR/issue-42234-unknown-receiver-type.rs:17:5 | +16 | let x: Option<_> = None; + | - consider giving `x` a type 17 | x.unwrap().method_that_could_exist_on_some_type(); - | ^^^^^^^^^^ + | ^^^^^^^^^^ cannot infer type for `T` error[E0282]: type annotations needed --> $DIR/issue-42234-unknown-receiver-type.rs:22:5 | 22 | / data.iter() //~ ERROR 22:5: 23:20: type annotations needed 23 | | .sum::<_>() - | |___________________^ + | |___________________^ cannot infer type for `_` error: aborting due to 2 previous errors From 01a70c65892eea8cdf9d6a5f72ea003897eb61c6 Mon Sep 17 00:00:00 2001 From: Seiichi Uchida Date: Sat, 27 Jan 2018 16:13:50 +0900 Subject: [PATCH 23/35] Add a closing parenthesis to the span of Visibility::Crate --- src/libsyntax/parse/parser.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ac582627f88fd..effc5f75f6ad6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5702,8 +5702,8 @@ impl<'a> Parser<'a> { // `pub(crate)` self.bump(); // `(` self.bump(); // `crate` - let vis = Visibility::Crate(self.prev_span, CrateSugar::PubCrate); self.expect(&token::CloseDelim(token::Paren))?; // `)` + let vis = Visibility::Crate(self.prev_span, CrateSugar::PubCrate); return Ok(vis) } else if self.look_ahead(1, |t| t.is_keyword(keywords::In)) { // `pub(in path)` @@ -5715,7 +5715,8 @@ impl<'a> Parser<'a> { return Ok(vis) } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && self.look_ahead(1, |t| t.is_keyword(keywords::Super) || - t.is_keyword(keywords::SelfValue)) { + t.is_keyword(keywords::SelfValue)) + { // `pub(self)` or `pub(super)` self.bump(); // `(` let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `super`/`self` From 0bddba9248674fe9fde68d3e31fcc9afee7b505c Mon Sep 17 00:00:00 2001 From: Seiichi Uchida Date: Sat, 27 Jan 2018 16:15:00 +0900 Subject: [PATCH 24/35] Add a span field to Visibility::Restricted This span covers the whole visibility expression: e.g. `pub (in path)`. --- src/librustc/hir/lowering.rs | 2 +- src/librustc_resolve/lib.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/fold.rs | 5 +++-- src/libsyntax/parse/parser.rs | 12 ++++++++++-- src/libsyntax/visit.rs | 2 +- 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 55dcb16c3c95f..e8969e7e3cb12 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3365,7 +3365,7 @@ impl<'a> LoweringContext<'a> { match *v { Visibility::Public => hir::Public, Visibility::Crate(..) => hir::Visibility::Crate, - Visibility::Restricted { ref path, id } => { + Visibility::Restricted { ref path, id, .. } => { hir::Visibility::Restricted { path: P(self.lower_path(id, path, ParamMode::Explicit, true)), id: if let Some(owner) = explicit_owner { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2da4bfedd3a17..37016ee9cf93b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3802,7 +3802,7 @@ impl<'a> Resolver<'a> { ast::Visibility::Inherited => { ty::Visibility::Restricted(self.current_module.normal_ancestor_id) } - ast::Visibility::Restricted { ref path, id } => { + ast::Visibility::Restricted { ref path, id, .. } => { let def = self.smart_resolve_path(id, None, path, PathSource::Visibility).base_def(); if def == Def::Err { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c7ab6158256ba..54b6e166e390f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1941,7 +1941,7 @@ pub enum CrateSugar { pub enum Visibility { Public, Crate(Span, CrateSugar), - Restricted { path: P, id: NodeId }, + Restricted { path: P, id: NodeId, span: Span }, Inherited, } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 921ed3565a471..9e51379a9ee5f 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1368,9 +1368,10 @@ pub fn noop_fold_stmt_kind(node: StmtKind, folder: &mut T) -> SmallVe pub fn noop_fold_vis(vis: Visibility, folder: &mut T) -> Visibility { match vis { - Visibility::Restricted { path, id } => Visibility::Restricted { + Visibility::Restricted { path, id, span } => Visibility::Restricted { path: path.map(|path| folder.fold_path(path)), - id: folder.new_id(id) + id: folder.new_id(id), + span: folder.new_span(span), }, _ => vis, } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index effc5f75f6ad6..230c0bff91764 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5710,8 +5710,12 @@ impl<'a> Parser<'a> { self.bump(); // `(` self.bump(); // `in` let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `path` - let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; self.expect(&token::CloseDelim(token::Paren))?; // `)` + let vis = Visibility::Restricted { + path: P(path), + id: ast::DUMMY_NODE_ID, + span: self.prev_span, + }; return Ok(vis) } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && self.look_ahead(1, |t| t.is_keyword(keywords::Super) || @@ -5720,8 +5724,12 @@ impl<'a> Parser<'a> { // `pub(self)` or `pub(super)` self.bump(); // `(` let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `super`/`self` - let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; self.expect(&token::CloseDelim(token::Paren))?; // `)` + let vis = Visibility::Restricted { + path: P(path), + id: ast::DUMMY_NODE_ID, + span: self.prev_span, + }; return Ok(vis) } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct // `pub(something) fn ...` or `struct X { pub(something) y: Z }` diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index bbb123dab2868..14679a9ebd141 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -811,7 +811,7 @@ pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { } pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { - if let Visibility::Restricted { ref path, id } = *vis { + if let Visibility::Restricted { ref path, id, .. } = *vis { visitor.visit_path(path, id); } } From d6bdf296a42caec8711adc075782e0b8c920aa1f Mon Sep 17 00:00:00 2001 From: Seiichi Uchida Date: Mon, 29 Jan 2018 14:12:09 +0900 Subject: [PATCH 25/35] Change ast::Visibility to Spanned type --- src/librustc/hir/lowering.rs | 10 ++--- src/librustc_allocator/expand.rs | 4 +- src/librustc_metadata/cstore_impl.rs | 3 +- src/librustc_passes/ast_validation.rs | 29 ++++++------- src/librustc_resolve/check_unused.rs | 2 +- src/librustc_resolve/lib.rs | 12 +++--- src/librustc_save_analysis/dump_visitor.rs | 36 +++++++--------- src/libsyntax/ast.rs | 8 ++-- src/libsyntax/diagnostics/plugin.rs | 3 +- src/libsyntax/ext/build.rs | 4 +- src/libsyntax/ext/expand.rs | 9 ++-- src/libsyntax/ext/placeholders.rs | 2 +- src/libsyntax/ext/quote.rs | 8 +++- src/libsyntax/feature_gate.rs | 4 +- src/libsyntax/fold.rs | 17 ++++---- src/libsyntax/parse/mod.rs | 2 +- src/libsyntax/parse/parser.rs | 50 ++++++++++++---------- src/libsyntax/print/pprust.rs | 30 ++++++++----- src/libsyntax/std_inject.rs | 6 +-- src/libsyntax/test.rs | 18 ++++---- src/libsyntax/visit.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 4 +- src/libsyntax_ext/global_asm.rs | 3 +- src/libsyntax_ext/proc_macro_registrar.rs | 14 +++--- 24 files changed, 153 insertions(+), 127 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e8969e7e3cb12..e3af285053805 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3362,10 +3362,10 @@ impl<'a> LoweringContext<'a> { v: &Visibility, explicit_owner: Option) -> hir::Visibility { - match *v { - Visibility::Public => hir::Public, - Visibility::Crate(..) => hir::Visibility::Crate, - Visibility::Restricted { ref path, id, .. } => { + match v.node { + VisibilityKind::Public => hir::Public, + VisibilityKind::Crate(..) => hir::Visibility::Crate, + VisibilityKind::Restricted { ref path, id, .. } => { hir::Visibility::Restricted { path: P(self.lower_path(id, path, ParamMode::Explicit, true)), id: if let Some(owner) = explicit_owner { @@ -3375,7 +3375,7 @@ impl<'a> LoweringContext<'a> { } } } - Visibility::Inherited => hir::Inherited, + VisibilityKind::Inherited => hir::Inherited, } } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 352184c1efa76..951c2280f76f9 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -13,7 +13,7 @@ use rustc_errors; use syntax::abi::Abi; use syntax::ast::{Crate, Attribute, LitKind, StrStyle, ExprKind}; use syntax::ast::{Unsafety, Constness, Generics, Mutability, Ty, Mac, Arg}; -use syntax::ast::{self, Ident, Item, ItemKind, TyKind, Visibility, Expr}; +use syntax::ast::{self, Ident, Item, ItemKind, TyKind, VisibilityKind, Expr}; use syntax::attr; use syntax::codemap::dummy_spanned; use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; @@ -97,7 +97,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { ]); let mut items = vec![ f.cx.item_extern_crate(f.span, f.alloc), - f.cx.item_use_simple(f.span, Visibility::Inherited, super_path), + f.cx.item_use_simple(f.span, dummy_spanned(VisibilityKind::Inherited), super_path), ]; for method in ALLOCATOR_METHODS { items.push(f.allocator_fn(method)); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index d73e968a82760..3e5ba4851cd00 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -34,6 +34,7 @@ use std::rc::Rc; use syntax::ast; use syntax::attr; +use syntax::codemap; use syntax::ext::base::SyntaxExtension; use syntax::parse::filemap_to_stream; use syntax::symbol::Symbol; @@ -496,7 +497,7 @@ impl CrateStore for cstore::CStore { tokens: body.into(), legacy: def.legacy, }), - vis: ast::Visibility::Inherited, + vis: codemap::dummy_spanned(ast::VisibilityKind::Inherited), tokens: None, }) } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 6971033c8994b..bb6dbe632e316 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -58,14 +58,14 @@ impl<'a> AstValidator<'a> { } } - fn invalid_visibility(&self, vis: &Visibility, span: Span, note: Option<&str>) { - if vis != &Visibility::Inherited { + fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) { + if vis.node != VisibilityKind::Inherited { let mut err = struct_span_err!(self.session, - span, + vis.span, E0449, "unnecessary visibility qualifier"); - if vis == &Visibility::Public { - err.span_label(span, "`pub` not needed here"); + if vis.node == VisibilityKind::Public { + err.span_label(vis.span, "`pub` not needed here"); } if let Some(note) = note { err.note(note); @@ -216,7 +216,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_item(&mut self, item: &'a Item) { match item.node { ItemKind::Impl(unsafety, polarity, _, _, Some(..), ref ty, ref impl_items) => { - self.invalid_visibility(&item.vis, item.span, None); + self.invalid_visibility(&item.vis, None); if ty.node == TyKind::Err { self.err_handler() .struct_span_err(item.span, "`impl Trait for .. {}` is an obsolete syntax") @@ -226,7 +226,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { span_err!(self.session, item.span, E0198, "negative impls cannot be unsafe"); } for impl_item in impl_items { - self.invalid_visibility(&impl_item.vis, impl_item.span, None); + self.invalid_visibility(&impl_item.vis, None); if let ImplItemKind::Method(ref sig, _) = impl_item.node { self.check_trait_fn_not_const(sig.constness); } @@ -234,7 +234,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Impl(unsafety, polarity, defaultness, _, None, _, _) => { self.invalid_visibility(&item.vis, - item.span, Some("place qualifiers on individual impl items instead")); if unsafety == Unsafety::Unsafe { span_err!(self.session, item.span, E0197, "inherent impls cannot be unsafe"); @@ -247,16 +246,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } ItemKind::ForeignMod(..) => { - self.invalid_visibility(&item.vis, - item.span, - Some("place qualifiers on individual foreign items \ - instead")); + self.invalid_visibility( + &item.vis, + Some("place qualifiers on individual foreign items instead"), + ); } ItemKind::Enum(ref def, _) => { for variant in &def.variants { self.invalid_non_exhaustive_attribute(variant); for field in variant.node.data.fields() { - self.invalid_visibility(&field.vis, field.span, None); + self.invalid_visibility(&field.vis, None); } } } @@ -359,8 +358,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_vis(&mut self, vis: &'a Visibility) { - match *vis { - Visibility::Restricted { ref path, .. } => { + match vis.node { + VisibilityKind::Restricted { ref path, .. } => { path.segments.iter().find(|segment| segment.parameters.is_some()).map(|segment| { self.err_handler().span_err(segment.parameters.as_ref().unwrap().span(), "generic arguments in visibility path"); diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 5a321053b7ae8..865c6b422f3d4 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -86,7 +86,7 @@ impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> { // because this means that they were generated in some fashion by the // compiler and we don't need to consider them. if let ast::ItemKind::Use(..) = item.node { - if item.vis == ast::Visibility::Public || item.span.source_equal(&DUMMY_SP) { + if item.vis.node == ast::VisibilityKind::Public || item.span.source_equal(&DUMMY_SP) { return; } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 37016ee9cf93b..facca445b9785 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3796,13 +3796,15 @@ impl<'a> Resolver<'a> { } fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility { - match *vis { - ast::Visibility::Public => ty::Visibility::Public, - ast::Visibility::Crate(..) => ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)), - ast::Visibility::Inherited => { + match vis.node { + ast::VisibilityKind::Public => ty::Visibility::Public, + ast::VisibilityKind::Crate(..) => { + ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)) + } + ast::VisibilityKind::Inherited => { ty::Visibility::Restricted(self.current_module.normal_ancestor_id) } - ast::Visibility::Restricted { ref path, id, .. } => { + ast::VisibilityKind::Restricted { ref path, id, .. } => { let def = self.smart_resolve_path(id, None, path, PathSource::Visibility).base_def(); if def == Def::Err { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 47530c4208520..c9c905723b2bb 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -43,7 +43,7 @@ use syntax::print::pprust::{ ty_to_string }; use syntax::ptr::P; -use syntax::codemap::{Spanned, DUMMY_SP}; +use syntax::codemap::{Spanned, DUMMY_SP, dummy_spanned}; use syntax_pos::*; use {escape, generated_code, lower_attributes, PathCollector, SaveContext}; @@ -65,12 +65,19 @@ macro_rules! down_cast_data { } macro_rules! access_from { + ($save_ctxt:expr, $vis:expr, $id:expr) => { + Access { + public: $vis.node == ast::VisibilityKind::Public, + reachable: $save_ctxt.analysis.access_levels.is_reachable($id), + } + }; + ($save_ctxt:expr, $item:expr) => { Access { - public: $item.vis == ast::Visibility::Public, + public: $item.vis.node == ast::VisibilityKind::Public, reachable: $save_ctxt.analysis.access_levels.is_reachable($item.id), } - } + }; } pub struct DumpVisitor<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> { @@ -405,12 +412,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { method_data.value = sig_str; method_data.sig = sig::method_signature(id, name, generics, sig, &self.save_ctxt); - self.dumper.dump_def( - &Access { - public: vis == ast::Visibility::Public, - reachable: self.save_ctxt.analysis.access_levels.is_reachable(id), - }, - method_data); + self.dumper.dump_def(&access_from!(self.save_ctxt, vis, id), method_data); } // walk arg and return types @@ -543,10 +545,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { let span = self.span_from_span(sub_span.expect("No span found for variable")); self.dumper.dump_def( - &Access { - public: vis == ast::Visibility::Public, - reachable: self.save_ctxt.analysis.access_levels.is_reachable(id), - }, + &access_from!(self.save_ctxt, vis, id), Def { kind: DefKind::Const, id: ::id_from_node_id(id, &self.save_ctxt), @@ -597,7 +596,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { .iter() .enumerate() .filter_map(|(i, f)| { - if include_priv_fields || f.vis == ast::Visibility::Public { + if include_priv_fields || f.vis.node == ast::VisibilityKind::Public { f.ident .map(|i| i.to_string()) .or_else(|| Some(i.to_string())) @@ -1144,7 +1143,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { &ty, expr.as_ref().map(|e| &**e), trait_id, - ast::Visibility::Public, + dummy_spanned(ast::VisibilityKind::Public), &trait_item.attrs, ); } @@ -1155,7 +1154,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { trait_item.id, trait_item.ident, &trait_item.generics, - ast::Visibility::Public, + dummy_spanned(ast::VisibilityKind::Public), trait_item.span, ); } @@ -1259,10 +1258,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { // The access is calculated using the current tree ID, but with the root tree's visibility // (since nested trees don't have their own visibility). - let access = Access { - public: root_item.vis == ast::Visibility::Public, - reachable: self.save_ctxt.analysis.access_levels.is_reachable(id), - }; + let access = access_from!(self.save_ctxt, root_item.vis, id); // The parent def id of a given use tree is always the enclosing item. let parent = self.save_ctxt.tcx.hir.opt_local_def_id(id) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 54b6e166e390f..c5a383bfa2ff5 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1937,11 +1937,13 @@ pub enum CrateSugar { JustCrate, } +pub type Visibility = Spanned; + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum Visibility { +pub enum VisibilityKind { Public, - Crate(Span, CrateSugar), - Restricted { path: P, id: NodeId, span: Span }, + Crate(CrateSugar), + Restricted { path: P, id: NodeId }, Inherited, } diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 5224f52c49629..6eaeec99b17ca 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -14,6 +14,7 @@ use std::env; use ast; use ast::{Ident, Name}; +use codemap; use syntax_pos::Span; use ext::base::{ExtCtxt, MacEager, MacResult}; use ext::build::AstBuilder; @@ -234,7 +235,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, ty, expr, ), - vis: ast::Visibility::Public, + vis: codemap::dummy_spanned(ast::VisibilityKind::Public), span, tokens: None, }) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 2e6de96d65a6d..2de4643aef927 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -987,7 +987,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { attrs, id: ast::DUMMY_NODE_ID, node, - vis: ast::Visibility::Inherited, + vis: dummy_spanned(ast::VisibilityKind::Inherited), span, tokens: None, }) @@ -1033,7 +1033,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { span: ty.span, ty, ident: None, - vis: ast::Visibility::Inherited, + vis: dummy_spanned(ast::VisibilityKind::Inherited), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 44a073545a730..9c0a7e9516615 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -11,7 +11,7 @@ use ast::{self, Block, Ident, NodeId, PatKind, Path}; use ast::{MacStmtStyle, StmtKind, ItemKind}; use attr::{self, HasAttrs}; -use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, dummy_spanned}; +use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, dummy_spanned, respan}; use config::{is_test_or_bench, StripUnconfigured}; use errors::FatalError; use ext::base::*; @@ -238,7 +238,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { node: ast::ItemKind::Mod(krate.module), ident: keywords::Invalid.ident(), id: ast::DUMMY_NODE_ID, - vis: ast::Visibility::Public, + vis: dummy_spanned(ast::VisibilityKind::Public), tokens: None, }))); @@ -1022,7 +1022,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { // Ensure that test functions are accessible from the test harness. ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => { if item.attrs.iter().any(|attr| is_test_or_bench(attr)) { - item = item.map(|mut item| { item.vis = ast::Visibility::Public; item }); + item = item.map(|mut item| { + item.vis = respan(item.vis.span, ast::VisibilityKind::Public); + item + }); } noop_fold_item(item, self) } diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 2f5b386346bc8..9c2c22476e9d9 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -33,7 +33,7 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { let ident = keywords::Invalid.ident(); let attrs = Vec::new(); let generics = ast::Generics::default(); - let vis = ast::Visibility::Inherited; + let vis = dummy_spanned(ast::VisibilityKind::Inherited); let span = DUMMY_SP; let expr_placeholder = || P(ast::Expr { id, span, diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 7fcd88c94ca6f..b4c005e77a355 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -9,6 +9,7 @@ // except according to those terms. use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Stmt, Ty}; +use codemap::dummy_spanned; use syntax_pos::Span; use ext::base::ExtCtxt; use ext::base; @@ -855,7 +856,12 @@ fn expand_wrapper(cx: &ExtCtxt, let mut stmts = imports.iter().map(|path| { // make item: `use ...;` let path = path.iter().map(|s| s.to_string()).collect(); - cx.stmt_item(sp, cx.item_use_glob(sp, ast::Visibility::Inherited, ids_ext(path))) + let use_item = cx.item_use_glob( + sp, + dummy_spanned(ast::VisibilityKind::Inherited), + ids_ext(path), + ); + cx.stmt_item(sp, use_item) }).chain(Some(stmt_let_ext_cx)).collect::>(); stmts.push(cx.stmt_expr(expr)); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 3b137f9570a39..c0fde71d086f4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1816,8 +1816,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_vis(&mut self, vis: &'a ast::Visibility) { - if let ast::Visibility::Crate(span, ast::CrateSugar::JustCrate) = *vis { - gate_feature_post!(&self, crate_visibility_modifier, span, + if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node { + gate_feature_post!(&self, crate_visibility_modifier, vis.span, "`crate` visibility modifier is experimental"); } visit::walk_vis(self, vis); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 9e51379a9ee5f..670492818a62b 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -21,7 +21,7 @@ use ast::*; use ast; use syntax_pos::Span; -use codemap::{Spanned, respan}; +use codemap::{Spanned, respan, dummy_spanned}; use parse::token::{self, Token}; use ptr::P; use symbol::keywords; @@ -1018,7 +1018,7 @@ pub fn noop_fold_crate(Crate {module, attrs, span}: Crate, ident: keywords::Invalid.ident(), attrs, id: ast::DUMMY_NODE_ID, - vis: ast::Visibility::Public, + vis: dummy_spanned(ast::VisibilityKind::Public), span, node: ast::ItemKind::Mod(module), tokens: None, @@ -1367,12 +1367,13 @@ pub fn noop_fold_stmt_kind(node: StmtKind, folder: &mut T) -> SmallVe } pub fn noop_fold_vis(vis: Visibility, folder: &mut T) -> Visibility { - match vis { - Visibility::Restricted { path, id, span } => Visibility::Restricted { - path: path.map(|path| folder.fold_path(path)), - id: folder.new_id(id), - span: folder.new_span(span), - }, + match vis.node { + VisibilityKind::Restricted { path, id } => { + respan(vis.span, VisibilityKind::Restricted { + path: path.map(|path| folder.fold_path(path)), + id: folder.new_id(id), + }) + } _ => vis, } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b671f81c2a84b..5ab9a484eb793 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -932,7 +932,7 @@ mod tests { span: sp(15,21), recovered: false, })), - vis: ast::Visibility::Inherited, + vis: codemap::dummy_spanned(ast::VisibilityKind::Inherited), span: sp(0,21)}))); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 230c0bff91764..573de215a5ec5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -36,7 +36,7 @@ use ast::StrStyle; use ast::SelfKind; use ast::{TraitItem, TraitRef, TraitObjectSyntax}; use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds}; -use ast::{Visibility, WhereClause, CrateSugar}; +use ast::{Visibility, VisibilityKind, WhereClause, CrateSugar}; use ast::{UseTree, UseTreeKind}; use ast::{BinOpKind, UnOp}; use ast::{RangeEnd, RangeSyntax}; @@ -4132,7 +4132,7 @@ impl<'a> Parser<'a> { token::Ident(ident) if ident.name == "macro_rules" && self.look_ahead(1, |t| *t == token::Not) => { let prev_span = self.prev_span; - self.complain_if_pub_macro(vis, prev_span); + self.complain_if_pub_macro(&vis.node, prev_span); self.bump(); self.bump(); @@ -4169,7 +4169,11 @@ impl<'a> Parser<'a> { node: StmtKind::Local(self.parse_local(attrs.into())?), span: lo.to(self.prev_span), } - } else if let Some(macro_def) = self.eat_macro_def(&attrs, &Visibility::Inherited, lo)? { + } else if let Some(macro_def) = self.eat_macro_def( + &attrs, + &codemap::respan(lo, VisibilityKind::Inherited), + lo, + )? { Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Item(macro_def), @@ -4296,7 +4300,7 @@ impl<'a> Parser<'a> { self.mk_item( span, id /*id is good here*/, ItemKind::Mac(respan(span, Mac_ { path: pth, tts: tts })), - Visibility::Inherited, + respan(lo, VisibilityKind::Inherited), attrs) }), } @@ -5213,15 +5217,15 @@ impl<'a> Parser<'a> { }) } - fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) { + fn complain_if_pub_macro(&mut self, vis: &VisibilityKind, sp: Span) { if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) { err.emit(); } } - fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> { + fn complain_if_pub_macro_diag(&mut self, vis: &VisibilityKind, sp: Span) -> PResult<'a, ()> { match *vis { - Visibility::Inherited => Ok(()), + VisibilityKind::Inherited => Ok(()), _ => { let is_macro_rules: bool = match self.token { token::Ident(sid) => sid.name == Symbol::intern("macro_rules"), @@ -5283,7 +5287,7 @@ impl<'a> Parser<'a> { self.expect(&token::Not)?; } - self.complain_if_pub_macro(vis, prev_span); + self.complain_if_pub_macro(&vis.node, prev_span); // eat a matched-delimiter token tree: *at_end = true; @@ -5686,12 +5690,13 @@ impl<'a> Parser<'a> { self.expected_tokens.push(TokenType::Keyword(keywords::Crate)); if self.is_crate_vis() { self.bump(); // `crate` - return Ok(Visibility::Crate(self.prev_span, CrateSugar::JustCrate)); + return Ok(respan(self.prev_span, VisibilityKind::Crate(CrateSugar::JustCrate))); } if !self.eat_keyword(keywords::Pub) { - return Ok(Visibility::Inherited) + return Ok(respan(self.prev_span, VisibilityKind::Inherited)) } + let lo = self.prev_span; if self.check(&token::OpenDelim(token::Paren)) { // We don't `self.bump()` the `(` yet because this might be a struct definition where @@ -5703,7 +5708,10 @@ impl<'a> Parser<'a> { self.bump(); // `(` self.bump(); // `crate` self.expect(&token::CloseDelim(token::Paren))?; // `)` - let vis = Visibility::Crate(self.prev_span, CrateSugar::PubCrate); + let vis = respan( + lo.to(self.prev_span), + VisibilityKind::Crate(CrateSugar::PubCrate), + ); return Ok(vis) } else if self.look_ahead(1, |t| t.is_keyword(keywords::In)) { // `pub(in path)` @@ -5711,11 +5719,10 @@ impl<'a> Parser<'a> { self.bump(); // `in` let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `path` self.expect(&token::CloseDelim(token::Paren))?; // `)` - let vis = Visibility::Restricted { + let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID, - span: self.prev_span, - }; + }); return Ok(vis) } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && self.look_ahead(1, |t| t.is_keyword(keywords::Super) || @@ -5725,11 +5732,10 @@ impl<'a> Parser<'a> { self.bump(); // `(` let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `super`/`self` self.expect(&token::CloseDelim(token::Paren))?; // `)` - let vis = Visibility::Restricted { + let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID, - span: self.prev_span, - }; + }); return Ok(vis) } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct // `pub(something) fn ...` or `struct X { pub(something) y: Z }` @@ -5749,7 +5755,7 @@ impl<'a> Parser<'a> { } } - Ok(Visibility::Public) + Ok(respan(lo, VisibilityKind::Public)) } /// Parse defaultness: `default` or nothing. @@ -6582,7 +6588,7 @@ impl<'a> Parser<'a> { // Verify wether we have encountered a struct or method definition where the user forgot to // add the `struct` or `fn` keyword after writing `pub`: `pub S {}` - if visibility == Visibility::Public && + if visibility.node == VisibilityKind::Public && self.check_ident() && self.look_ahead(1, |t| *t != token::Not) { @@ -6690,7 +6696,7 @@ impl<'a> Parser<'a> { // MACRO INVOCATION ITEM let prev_span = self.prev_span; - self.complain_if_pub_macro(&visibility, prev_span); + self.complain_if_pub_macro(&visibility.node, prev_span); let mac_lo = self.span; @@ -6724,8 +6730,8 @@ impl<'a> Parser<'a> { } // FAILURE TO PARSE ITEM - match visibility { - Visibility::Inherited => {} + match visibility.node { + VisibilityKind::Inherited => {} _ => { return Err(self.span_fatal(self.prev_span, "unmatched visibility `pub`")); } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ae459c668aae4..34499839fb031 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -377,7 +377,7 @@ pub fn fun_to_string(decl: &ast::FnDecl, to_string(|s| { s.head("")?; s.print_fn(decl, unsafety, constness, Abi::Rust, Some(name), - generics, &ast::Visibility::Inherited)?; + generics, &codemap::dummy_spanned(ast::VisibilityKind::Inherited))?; s.end()?; // Close the head box s.end() // Close the outer box }) @@ -1458,13 +1458,13 @@ impl<'a> State<'a> { } pub fn print_visibility(&mut self, vis: &ast::Visibility) -> io::Result<()> { - match *vis { - ast::Visibility::Public => self.word_nbsp("pub"), - ast::Visibility::Crate(_, sugar) => match sugar { + match vis.node { + ast::VisibilityKind::Public => self.word_nbsp("pub"), + ast::VisibilityKind::Crate(sugar) => match sugar { ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"), ast::CrateSugar::JustCrate => self.word_nbsp("crate") } - ast::Visibility::Restricted { ref path, .. } => { + ast::VisibilityKind::Restricted { ref path, .. } => { let path = to_string(|s| s.print_path(path, false, 0, true)); if path == "self" || path == "super" { self.word_nbsp(&format!("pub({})", path)) @@ -1472,7 +1472,7 @@ impl<'a> State<'a> { self.word_nbsp(&format!("pub(in {})", path)) } } - ast::Visibility::Inherited => Ok(()) + ast::VisibilityKind::Inherited => Ok(()) } } @@ -1569,15 +1569,23 @@ impl<'a> State<'a> { self.print_outer_attributes(&ti.attrs)?; match ti.node { ast::TraitItemKind::Const(ref ty, ref default) => { - self.print_associated_const(ti.ident, ty, - default.as_ref().map(|expr| &**expr), - &ast::Visibility::Inherited)?; + self.print_associated_const( + ti.ident, + ty, + default.as_ref().map(|expr| &**expr), + &codemap::dummy_spanned(ast::VisibilityKind::Inherited), + )?; } ast::TraitItemKind::Method(ref sig, ref body) => { if body.is_some() { self.head("")?; } - self.print_method_sig(ti.ident, &ti.generics, sig, &ast::Visibility::Inherited)?; + self.print_method_sig( + ti.ident, + &ti.generics, + sig, + &codemap::dummy_spanned(ast::VisibilityKind::Inherited), + )?; if let Some(ref body) = *body { self.nbsp()?; self.print_block_with_attrs(body, &ti.attrs)?; @@ -3055,7 +3063,7 @@ impl<'a> State<'a> { abi, name, &generics, - &ast::Visibility::Inherited)?; + &codemap::dummy_spanned(ast::VisibilityKind::Inherited))?; self.end() } diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 00546400bb542..ab42cfeb66bae 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -14,7 +14,7 @@ use std::cell::Cell; use ext::hygiene::{Mark, SyntaxContext}; use symbol::{Symbol, keywords}; use syntax_pos::{DUMMY_SP, Span}; -use codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; +use codemap::{ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned}; use ptr::P; use tokenstream::TokenStream; @@ -60,7 +60,7 @@ pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option P { prefix: path_node(vec![id_test]), kind: ast::UseTreeKind::Simple(id_test), })), - ast::Visibility::Public, keywords::Invalid.ident()) + ast::VisibilityKind::Public, keywords::Invalid.ident()) } else { - (ast::ItemKind::ExternCrate(None), ast::Visibility::Inherited, id_test) + (ast::ItemKind::ExternCrate(None), ast::VisibilityKind::Inherited, id_test) }; P(ast::Item { id: ast::DUMMY_NODE_ID, ident, node: vi, attrs: vec![], - vis, + vis: dummy_spanned(vis), span: sp, tokens: None, }) @@ -513,7 +513,7 @@ fn mk_main(cx: &mut TestCtxt) -> P { attrs: vec![main_attr], id: ast::DUMMY_NODE_ID, node: main, - vis: ast::Visibility::Public, + vis: dummy_spanned(ast::VisibilityKind::Public), span: sp, tokens: None, }) @@ -543,7 +543,7 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P, Option>) { ident: mod_ident, attrs: vec![], node: item_, - vis: ast::Visibility::Public, + vis: dummy_spanned(ast::VisibilityKind::Public), span: DUMMY_SP, tokens: None, })).pop().unwrap(); @@ -562,7 +562,7 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P, Option>) { ident: keywords::Invalid.ident(), attrs: vec![], node: ast::ItemKind::Use(P(use_path)), - vis: ast::Visibility::Inherited, + vis: dummy_spanned(ast::VisibilityKind::Inherited), span: DUMMY_SP, tokens: None, })).pop().unwrap() diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 14679a9ebd141..4691ddafa36e8 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -811,7 +811,7 @@ pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { } pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { - if let Visibility::Restricted { ref path, id, .. } = *vis { + if let VisibilityKind::Restricted { ref path, id } = vis.node { visitor.visit_path(path, id); } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 0dfe9cb970efb..6ba633eb87bc9 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -530,7 +530,7 @@ impl<'a> TraitDef<'a> { id: ast::DUMMY_NODE_ID, span: self.span, ident, - vis: ast::Visibility::Inherited, + vis: dummy_spanned(ast::VisibilityKind::Inherited), defaultness: ast::Defaultness::Final, attrs: Vec::new(), generics: Generics::default(), @@ -977,7 +977,7 @@ impl<'a> MethodDef<'a> { attrs: self.attributes.clone(), generics: fn_generics, span: trait_.span, - vis: ast::Visibility::Inherited, + vis: dummy_spanned(ast::VisibilityKind::Inherited), defaultness: ast::Defaultness::Final, ident: method_ident, node: ast::ImplItemKind::Method(ast::MethodSig { diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index 81226ba599ae6..dd882d7abdf91 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -19,6 +19,7 @@ /// therefore apply. use syntax::ast; +use syntax::codemap::dummy_spanned; use syntax::ext::base; use syntax::ext::base::*; use syntax::feature_gate; @@ -59,7 +60,7 @@ pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, asm, ctxt: cx.backtrace(), })), - vis: ast::Visibility::Inherited, + vis: dummy_spanned(ast::VisibilityKind::Inherited), span: sp, tokens: None, }))) diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 0ba21e6b366cf..e623779ce63ba 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -14,7 +14,7 @@ use errors; use syntax::ast::{self, Ident, NodeId}; use syntax::attr; -use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; +use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute, respan}; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; @@ -103,7 +103,7 @@ impl<'a> CollectProcMacros<'a> { fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) { if self.is_proc_macro_crate && self.in_root && - *vis == ast::Visibility::Public { + vis.node == ast::VisibilityKind::Public { self.handler.span_err(sp, "`proc-macro` crate types cannot \ export any items other than functions \ @@ -181,7 +181,7 @@ impl<'a> CollectProcMacros<'a> { Vec::new() }; - if self.in_root && item.vis == ast::Visibility::Public { + if self.in_root && item.vis.node == ast::VisibilityKind::Public { self.derives.push(ProcMacroDerive { span: item.span, trait_name, @@ -206,7 +206,7 @@ impl<'a> CollectProcMacros<'a> { return; } - if self.in_root && item.vis == ast::Visibility::Public { + if self.in_root && item.vis.node == ast::VisibilityKind::Public { self.attr_macros.push(ProcMacroDef { span: item.span, function_name: item.ident, @@ -229,7 +229,7 @@ impl<'a> CollectProcMacros<'a> { return; } - if self.in_root && item.vis == ast::Visibility::Public { + if self.in_root && item.vis.node == ast::VisibilityKind::Public { self.bang_macros.push(ProcMacroDef { span: item.span, function_name: item.ident, @@ -439,12 +439,12 @@ fn mk_registrar(cx: &mut ExtCtxt, let derive_registrar = cx.attribute(span, derive_registrar); let func = func.map(|mut i| { i.attrs.push(derive_registrar); - i.vis = ast::Visibility::Public; + i.vis = respan(span, ast::VisibilityKind::Public); i }); let ident = ast::Ident::with_empty_ctxt(Symbol::gensym("registrar")); let module = cx.item_mod(span, span, ident, Vec::new(), vec![krate, func]).map(|mut i| { - i.vis = ast::Visibility::Public; + i.vis = respan(span, ast::VisibilityKind::Public); i }); From b5099a708d67ed165c5ebcfc2c55b1cdf2ad86bc Mon Sep 17 00:00:00 2001 From: Seiichi Uchida Date: Sun, 4 Feb 2018 21:19:14 +0900 Subject: [PATCH 26/35] Replace dummy spans with empty spans --- src/liblibc | 2 +- src/librustc_allocator/expand.rs | 4 ++-- src/librustc_metadata/cstore_impl.rs | 2 +- src/librustc_save_analysis/dump_visitor.rs | 7 ++++--- src/libsyntax/diagnostics/plugin.rs | 2 +- src/libsyntax/ext/build.rs | 4 ++-- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/ext/quote.rs | 4 ++-- src/libsyntax/fold.rs | 4 ++-- src/libsyntax/parse/mod.rs | 2 +- src/libsyntax/print/pprust.rs | 4 ++-- src/libsyntax/std_inject.rs | 4 ++-- src/libsyntax_ext/deriving/generic/mod.rs | 4 ++-- src/libsyntax_ext/global_asm.rs | 4 ++-- src/libsyntax_pos/lib.rs | 6 ++++++ src/tools/cargo | 2 +- 16 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/liblibc b/src/liblibc index 56444a4545bd7..2b4cd1016bdba 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 56444a4545bd71430d64b86b8a71714cfdbe9f5d +Subproject commit 2b4cd1016bdba92becb4f982a4dcb18fe6653bc4 diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 951c2280f76f9..26a7f50b99798 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -15,7 +15,7 @@ use syntax::ast::{Crate, Attribute, LitKind, StrStyle, ExprKind}; use syntax::ast::{Unsafety, Constness, Generics, Mutability, Ty, Mac, Arg}; use syntax::ast::{self, Ident, Item, ItemKind, TyKind, VisibilityKind, Expr}; use syntax::attr; -use syntax::codemap::dummy_spanned; +use syntax::codemap::{dummy_spanned, respan}; use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; use syntax::ext::base::ExtCtxt; use syntax::ext::base::Resolver; @@ -97,7 +97,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { ]); let mut items = vec![ f.cx.item_extern_crate(f.span, f.alloc), - f.cx.item_use_simple(f.span, dummy_spanned(VisibilityKind::Inherited), super_path), + f.cx.item_use_simple(f.span, respan(f.span.empty(), VisibilityKind::Inherited), super_path), ]; for method in ALLOCATOR_METHODS { items.push(f.allocator_fn(method)); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 3e5ba4851cd00..c1340d0a28a44 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -497,7 +497,7 @@ impl CrateStore for cstore::CStore { tokens: body.into(), legacy: def.legacy, }), - vis: codemap::dummy_spanned(ast::VisibilityKind::Inherited), + vis: codemap::respan(local_span.empty(), ast::VisibilityKind::Inherited), tokens: None, }) } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index c9c905723b2bb..bf82b0774238b 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -43,7 +43,7 @@ use syntax::print::pprust::{ ty_to_string }; use syntax::ptr::P; -use syntax::codemap::{Spanned, DUMMY_SP, dummy_spanned}; +use syntax::codemap::{Spanned, DUMMY_SP, respan}; use syntax_pos::*; use {escape, generated_code, lower_attributes, PathCollector, SaveContext}; @@ -1134,6 +1134,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) { self.process_macro_use(trait_item.span); + let vis_span = trait_item.span.empty(); match trait_item.node { ast::TraitItemKind::Const(ref ty, ref expr) => { self.process_assoc_const( @@ -1143,7 +1144,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { &ty, expr.as_ref().map(|e| &**e), trait_id, - dummy_spanned(ast::VisibilityKind::Public), + respan(vis_span, ast::VisibilityKind::Public), &trait_item.attrs, ); } @@ -1154,7 +1155,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { trait_item.id, trait_item.ident, &trait_item.generics, - dummy_spanned(ast::VisibilityKind::Public), + respan(vis_span, ast::VisibilityKind::Public), trait_item.span, ); } diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 6eaeec99b17ca..dd27dea4f0d97 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -235,7 +235,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, ty, expr, ), - vis: codemap::dummy_spanned(ast::VisibilityKind::Public), + vis: codemap::respan(span.empty(), ast::VisibilityKind::Public), span, tokens: None, }) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 2de4643aef927..7681f55bd8ccb 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -987,7 +987,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { attrs, id: ast::DUMMY_NODE_ID, node, - vis: dummy_spanned(ast::VisibilityKind::Inherited), + vis: respan(span.empty(), ast::VisibilityKind::Inherited), span, tokens: None, }) @@ -1033,7 +1033,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { span: ty.span, ty, ident: None, - vis: dummy_spanned(ast::VisibilityKind::Inherited), + vis: respan(span.empty(), ast::VisibilityKind::Inherited), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 9c0a7e9516615..d4d9dfb01da2c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -238,7 +238,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { node: ast::ItemKind::Mod(krate.module), ident: keywords::Invalid.ident(), id: ast::DUMMY_NODE_ID, - vis: dummy_spanned(ast::VisibilityKind::Public), + vis: respan(krate.span.empty(), ast::VisibilityKind::Public), tokens: None, }))); diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index b4c005e77a355..7a024dbad8830 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -9,7 +9,7 @@ // except according to those terms. use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Stmt, Ty}; -use codemap::dummy_spanned; +use codemap::respan; use syntax_pos::Span; use ext::base::ExtCtxt; use ext::base; @@ -858,7 +858,7 @@ fn expand_wrapper(cx: &ExtCtxt, let path = path.iter().map(|s| s.to_string()).collect(); let use_item = cx.item_use_glob( sp, - dummy_spanned(ast::VisibilityKind::Inherited), + respan(sp.empty(), ast::VisibilityKind::Inherited), ids_ext(path), ); cx.stmt_item(sp, use_item) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 670492818a62b..1a2025b073b2b 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -21,7 +21,7 @@ use ast::*; use ast; use syntax_pos::Span; -use codemap::{Spanned, respan, dummy_spanned}; +use codemap::{Spanned, respan}; use parse::token::{self, Token}; use ptr::P; use symbol::keywords; @@ -1018,7 +1018,7 @@ pub fn noop_fold_crate(Crate {module, attrs, span}: Crate, ident: keywords::Invalid.ident(), attrs, id: ast::DUMMY_NODE_ID, - vis: dummy_spanned(ast::VisibilityKind::Public), + vis: respan(span.empty(), ast::VisibilityKind::Public), span, node: ast::ItemKind::Mod(module), tokens: None, diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 5ab9a484eb793..d2ae9904143d9 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -932,7 +932,7 @@ mod tests { span: sp(15,21), recovered: false, })), - vis: codemap::dummy_spanned(ast::VisibilityKind::Inherited), + vis: codemap::respan(sp(0, 0), ast::VisibilityKind::Inherited), span: sp(0,21)}))); } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 34499839fb031..3dfe3c9e5b990 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1573,7 +1573,7 @@ impl<'a> State<'a> { ti.ident, ty, default.as_ref().map(|expr| &**expr), - &codemap::dummy_spanned(ast::VisibilityKind::Inherited), + &codemap::respan(ti.span.empty(), ast::VisibilityKind::Inherited), )?; } ast::TraitItemKind::Method(ref sig, ref body) => { @@ -1584,7 +1584,7 @@ impl<'a> State<'a> { ti.ident, &ti.generics, sig, - &codemap::dummy_spanned(ast::VisibilityKind::Inherited), + &codemap::respan(ti.span.empty(), ast::VisibilityKind::Inherited), )?; if let Some(ref body) = *body { self.nbsp()?; diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index ab42cfeb66bae..da24107f4c33b 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -14,7 +14,7 @@ use std::cell::Cell; use ext::hygiene::{Mark, SyntaxContext}; use symbol::{Symbol, keywords}; use syntax_pos::{DUMMY_SP, Span}; -use codemap::{ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned}; +use codemap::{ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned, respan}; use ptr::P; use tokenstream::TokenStream; @@ -78,7 +78,7 @@ pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option TraitDef<'a> { id: ast::DUMMY_NODE_ID, span: self.span, ident, - vis: dummy_spanned(ast::VisibilityKind::Inherited), + vis: respan(self.span.empty(), ast::VisibilityKind::Inherited), defaultness: ast::Defaultness::Final, attrs: Vec::new(), generics: Generics::default(), @@ -977,7 +977,7 @@ impl<'a> MethodDef<'a> { attrs: self.attributes.clone(), generics: fn_generics, span: trait_.span, - vis: dummy_spanned(ast::VisibilityKind::Inherited), + vis: respan(trait_.span.empty(), ast::VisibilityKind::Inherited), defaultness: ast::Defaultness::Final, ident: method_ident, node: ast::ImplItemKind::Method(ast::MethodSig { diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index dd882d7abdf91..9605f6b5c5a9d 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -19,7 +19,7 @@ /// therefore apply. use syntax::ast; -use syntax::codemap::dummy_spanned; +use syntax::codemap::respan; use syntax::ext::base; use syntax::ext::base::*; use syntax::feature_gate; @@ -60,7 +60,7 @@ pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, asm, ctxt: cx.backtrace(), })), - vis: dummy_spanned(ast::VisibilityKind::Inherited), + vis: respan(sp.empty(), ast::VisibilityKind::Inherited), span: sp, tokens: None, }))) diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 294506625bc05..f9e01b630aebc 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -216,6 +216,12 @@ impl Span { self.data().with_ctxt(ctxt) } + /// Returns a new span representing an empty span at the beginning of this span + #[inline] + pub fn empty(self) -> Span { + span.with_hi(self.lo()) + } + /// Returns `self` if `self` is not the dummy span, and `other` otherwise. pub fn substitute_dummy(self, other: Span) -> Span { if self.source_equal(&DUMMY_SP) { other } else { self } diff --git a/src/tools/cargo b/src/tools/cargo index 1d6dfea44f971..91e36aa86c703 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 1d6dfea44f97199d5d5c177c7dadcde393eaff9a +Subproject commit 91e36aa86c7037de50642f2fec1cf47c3d18af02 From 291c51b9c8abe254216da4e954c5f6696a52da8f Mon Sep 17 00:00:00 2001 From: Seiichi Uchida Date: Wed, 14 Feb 2018 22:30:15 +0900 Subject: [PATCH 27/35] Fix up tests and typos --- src/librustc_allocator/expand.rs | 6 +++++- src/libsyntax/parse/mod.rs | 4 ++-- src/libsyntax_pos/lib.rs | 2 +- src/test/ui/error-codes/E0449.stderr | 10 ++++------ 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 26a7f50b99798..c088458c3557c 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -97,7 +97,11 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { ]); let mut items = vec![ f.cx.item_extern_crate(f.span, f.alloc), - f.cx.item_use_simple(f.span, respan(f.span.empty(), VisibilityKind::Inherited), super_path), + f.cx.item_use_simple( + f.span, + respan(f.span.empty(), VisibilityKind::Inherited), + super_path, + ), ]; for method in ALLOCATOR_METHODS { items.push(f.allocator_fn(method)); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index d2ae9904143d9..06eb64e157cd5 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -664,7 +664,7 @@ pub fn integer_lit(s: &str, suffix: Option, diag: Option<(Span, &Handler mod tests { use super::*; use syntax_pos::{self, Span, BytePos, Pos, NO_EXPANSION}; - use codemap::Spanned; + use codemap::{respan, Spanned}; use ast::{self, Ident, PatKind}; use abi::Abi; use attr::first_attr_value_str_by_name; @@ -932,7 +932,7 @@ mod tests { span: sp(15,21), recovered: false, })), - vis: codemap::respan(sp(0, 0), ast::VisibilityKind::Inherited), + vis: respan(sp(0, 0), ast::VisibilityKind::Inherited), span: sp(0,21)}))); } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index f9e01b630aebc..0f6dbc39e217a 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -219,7 +219,7 @@ impl Span { /// Returns a new span representing an empty span at the beginning of this span #[inline] pub fn empty(self) -> Span { - span.with_hi(self.lo()) + self.with_hi(self.lo()) } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. diff --git a/src/test/ui/error-codes/E0449.stderr b/src/test/ui/error-codes/E0449.stderr index 2270167303a80..3587319ed0cbc 100644 --- a/src/test/ui/error-codes/E0449.stderr +++ b/src/test/ui/error-codes/E0449.stderr @@ -2,23 +2,21 @@ error[E0449]: unnecessary visibility qualifier --> $DIR/E0449.rs:17:1 | 17 | pub impl Bar {} //~ ERROR E0449 - | ^^^^^^^^^^^^^^^ `pub` not needed here + | ^^^ `pub` not needed here | = note: place qualifiers on individual impl items instead error[E0449]: unnecessary visibility qualifier --> $DIR/E0449.rs:19:1 | -19 | / pub impl Foo for Bar { //~ ERROR E0449 -20 | | pub fn foo() {} //~ ERROR E0449 -21 | | } - | |_^ `pub` not needed here +19 | pub impl Foo for Bar { //~ ERROR E0449 + | ^^^ `pub` not needed here error[E0449]: unnecessary visibility qualifier --> $DIR/E0449.rs:20:5 | 20 | pub fn foo() {} //~ ERROR E0449 - | ^^^^^^^^^^^^^^^ `pub` not needed here + | ^^^ `pub` not needed here error: aborting due to 3 previous errors From 8e9fa57055a083ebc2378d855514166e3ec7a566 Mon Sep 17 00:00:00 2001 From: Seiichi Uchida Date: Sun, 18 Feb 2018 00:21:33 +0900 Subject: [PATCH 28/35] Revert unintentional submodule updates --- src/liblibc | 2 +- src/tools/cargo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/liblibc b/src/liblibc index 2b4cd1016bdba..56444a4545bd7 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 2b4cd1016bdba92becb4f982a4dcb18fe6653bc4 +Subproject commit 56444a4545bd71430d64b86b8a71714cfdbe9f5d diff --git a/src/tools/cargo b/src/tools/cargo index 91e36aa86c703..1d6dfea44f971 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 91e36aa86c7037de50642f2fec1cf47c3d18af02 +Subproject commit 1d6dfea44f97199d5d5c177c7dadcde393eaff9a From 472dcdb4ecb3fbea4b3e2b1d5952adc1d0f6cc76 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 17 Feb 2018 20:57:00 -0500 Subject: [PATCH 29/35] Fix broken documentation link. --- src/libstd/sys/unix/ext/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 86b0f35be924d..31bdc5ea1f565 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -415,7 +415,7 @@ impl UnixStream { /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`read`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples From 4370a5877c6c606dec106d200ccb36d5d78082a5 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Sun, 18 Feb 2018 11:07:52 +0800 Subject: [PATCH 30/35] fix tyvar_behind_raw_pointer error code --- src/librustc_typeck/check/method/probe.rs | 2 +- src/test/ui/inference-variable-behind-raw-pointer.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index e8c3966f23f08..9f3e44f56dae2 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -337,7 +337,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lint::builtin::TYVAR_BEHIND_RAW_POINTER, scope_expr_id, span, - &format!("the type of this value must be known in this context")); + &format!("type annotations needed")); } } else { let t = self.structurally_resolved_type(span, final_ty); diff --git a/src/test/ui/inference-variable-behind-raw-pointer.stderr b/src/test/ui/inference-variable-behind-raw-pointer.stderr index d0ee55c092b28..bb1d921f1c61c 100644 --- a/src/test/ui/inference-variable-behind-raw-pointer.stderr +++ b/src/test/ui/inference-variable-behind-raw-pointer.stderr @@ -1,4 +1,4 @@ -warning: the type of this value must be known in this context +warning: type annotations needed --> $DIR/inference-variable-behind-raw-pointer.rs:18:13 | 18 | if data.is_null() {} From 6818551c6f3a434752d0322fce03d594513b5ebd Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 18 Feb 2018 13:33:56 -0800 Subject: [PATCH 31/35] bump pulldown --- src/Cargo.lock | 8 ++++---- src/librustdoc/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index d8306c66daf84..7dc8374e3e8fd 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1086,7 +1086,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1383,7 +1383,7 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2104,7 +2104,7 @@ dependencies = [ name = "rustdoc" version = "0.0.0" dependencies = [ - "pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2886,7 +2886,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "378e941dbd392c101f2cb88097fa4d7167bc421d4b88de3ff7dbee503bc3233b" -"checksum pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a656fdb8b6848f896df5e478a0eb9083681663e37dcb77dd16981ff65329fe8b" +"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32" "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 09d0a0f610b7b..88b0f4486223c 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,5 +10,5 @@ path = "lib.rs" doctest = false [dependencies] -pulldown-cmark = { version = "0.1.0", default-features = false } +pulldown-cmark = { version = "0.1.2", default-features = false } tempdir = "0.3" From f60aeec5d564cf3ca0628db55abb8c62276e102f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 18 Feb 2018 13:37:52 -0800 Subject: [PATCH 32/35] Include shortcut links in markdown_links --- src/librustdoc/html/markdown.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index fedd802ce557f..bc7d1066ba45e 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -731,18 +731,30 @@ pub fn markdown_links(md: &str) -> Vec { opts.insert(OPTION_ENABLE_TABLES); opts.insert(OPTION_ENABLE_FOOTNOTES); - let p = Parser::new_ext(md, opts); - - let iter = Footnotes::new(HeadingLinks::new(p, None)); let mut links = vec![]; + let shortcut_links = RefCell::new(vec![]); + + { + let push = |_: &str, s: &str| { + shortcut_links.borrow_mut().push(s.to_owned()); + None + }; + let p = Parser::new_with_broken_link_callback(md, opts, + Some(&push)); - for ev in iter { - if let Event::Start(Tag::Link(dest, _)) = ev { - debug!("found link: {}", dest); - links.push(dest.into_owned()); + let iter = Footnotes::new(HeadingLinks::new(p, None)); + + for ev in iter { + if let Event::Start(Tag::Link(dest, _)) = ev { + debug!("found link: {}", dest); + links.push(dest.into_owned()); + } } } + let mut shortcut_links = shortcut_links.into_inner(); + links.extend(shortcut_links.drain(..)); + links } From 1d0ae9f174dd7fbefc268dc52fcac35627afa42d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 18 Feb 2018 14:32:34 -0800 Subject: [PATCH 33/35] Generate shortcut links --- src/librustdoc/html/markdown.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index bc7d1066ba45e..66fe2280aef7e 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -591,7 +591,15 @@ impl<'a> fmt::Display for Markdown<'a> { opts.insert(OPTION_ENABLE_TABLES); opts.insert(OPTION_ENABLE_FOOTNOTES); - let p = Parser::new_ext(md, opts); + let replacer = |_: &str, s: &str| { + if let Some(&(_, ref replace)) = links.into_iter().find(|link| &*link.0 == s) { + Some((replace.clone(), s.to_owned())) + } else { + None + } + }; + + let p = Parser::new_with_broken_link_callback(md, opts, Some(&replacer)); let mut s = String::with_capacity(md.len() * 3 / 2); @@ -662,7 +670,16 @@ impl<'a> fmt::Display for MarkdownSummaryLine<'a> { // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - let p = Parser::new(md); + let replacer = |_: &str, s: &str| { + if let Some(&(_, ref replace)) = links.into_iter().find(|link| &*link.0 == s) { + Some((replace.clone(), s.to_owned())) + } else { + None + } + }; + + let p = Parser::new_with_broken_link_callback(md, Options::empty(), + Some(&replacer)); let mut s = String::new(); From a04c124078ae9142588363e54877b9a151fb2043 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 18 Feb 2018 14:55:48 -0800 Subject: [PATCH 34/35] Add test --- src/test/rustdoc/intra-links.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/test/rustdoc/intra-links.rs b/src/test/rustdoc/intra-links.rs index 4726323e11cef..c822d0f8b21b8 100644 --- a/src/test/rustdoc/intra-links.rs +++ b/src/test/rustdoc/intra-links.rs @@ -77,3 +77,15 @@ pub trait SoAmbiguous {} #[allow(bad_style)] pub fn SoAmbiguous() {} + + +// @has - '//a/@href' '../intra_links/struct.ThisType.html' +// @has - '//a/@href' '../intra_links/struct.ThisType.html#method.this_method' +// @has - '//a/@href' '../intra_links/enum.ThisEnum.html' +// @has - '//a/@href' '../intra_links/enum.ThisEnum.html#ThisVariant.v' +/// Shortcut links for: +/// * [`ThisType`] +/// * [`ThisType::this_method`] +/// * [ThisEnum] +/// * [ThisEnum::ThisVariant] +pub struct SomeOtherType; From 5fdc10c68b3b5a42b17555be18baf5d7d60d55e6 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 18 Feb 2018 15:44:24 -0800 Subject: [PATCH 35/35] Filter out non-macros in resolve_macro Fixes https://github.com/rust-lang/rust/issues/48341 --- src/librustdoc/clean/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7f51b8f68ae49..6accda1d85179 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1008,7 +1008,7 @@ fn resolve(cx: &DocContext, path_str: &str, is_val: bool) -> Result<(Def, Option /// Resolve a string as a macro fn macro_resolve(cx: &DocContext, path_str: &str) -> Option { - use syntax::ext::base::MacroKind; + use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::hygiene::Mark; let segment = ast::PathSegment { identifier: ast::Ident::from_str(path_str), @@ -1025,7 +1025,11 @@ fn macro_resolve(cx: &DocContext, path_str: &str) -> Option { let res = resolver .resolve_macro_to_def_inner(mark, &path, MacroKind::Bang, false); if let Ok(def) = res { - Some(def) + if let SyntaxExtension::DeclMacro(..) = *resolver.get_macro(def) { + Some(def) + } else { + None + } } else if let Some(def) = resolver.all_macros.get(&path_str.into()) { Some(*def) } else {