From 2bd28d9d58abb9e71c1ad725ec246839cfca0b0a Mon Sep 17 00:00:00 2001 From: Tommaso Bianchi Date: Sun, 24 Nov 2019 15:47:02 -0500 Subject: [PATCH 01/38] Add regression tests --- src/test/ui/dropck/dropck_fn_type.rs | 20 ++++++++ src/test/ui/dropck/dropck_traits.rs | 68 ++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 src/test/ui/dropck/dropck_fn_type.rs create mode 100644 src/test/ui/dropck/dropck_traits.rs diff --git a/src/test/ui/dropck/dropck_fn_type.rs b/src/test/ui/dropck/dropck_fn_type.rs new file mode 100644 index 0000000000000..2934217df346e --- /dev/null +++ b/src/test/ui/dropck/dropck_fn_type.rs @@ -0,0 +1,20 @@ +// run-pass +//! Regression test for #58311, regarding the usage of Fn types in drop impls + +// All of this Drop impls should compile. + +#[allow(dead_code)] +struct S [u8; 1]>(F); + +impl [u8; 1]> Drop for S { + fn drop(&mut self) {} +} + +#[allow(dead_code)] +struct P [A; 10]>(F); + +impl [A; 10]> Drop for P { + fn drop(&mut self) {} +} + +fn main() {} diff --git a/src/test/ui/dropck/dropck_traits.rs b/src/test/ui/dropck/dropck_traits.rs new file mode 100644 index 0000000000000..98e8e88a25995 --- /dev/null +++ b/src/test/ui/dropck/dropck_traits.rs @@ -0,0 +1,68 @@ +// run-pass +//! Regression test for #34426, regarding HRTB in drop impls + +// All of this Drop impls should compile. + +pub trait Lifetime<'a> {} +impl<'a> Lifetime<'a> for i32 {} + +#[allow(dead_code)] +struct Foo +where + for<'a> L: Lifetime<'a>, +{ + l: L, +} + +impl Drop for Foo +where + for<'a> L: Lifetime<'a>, +{ + fn drop(&mut self) {} +} + +#[allow(dead_code)] +struct Foo2 +where + for<'a> L: Lifetime<'a>, +{ + l: L, +} + +impl Lifetime<'a>> Drop for Foo2 +where + for<'x> T: Lifetime<'x>, +{ + fn drop(&mut self) {} +} + +pub trait Lifetime2<'a, 'b> {} +impl<'a, 'b> Lifetime2<'a, 'b> for i32 {} + +#[allow(dead_code)] +struct Bar +where + for<'a, 'b> L: Lifetime2<'a, 'b>, +{ + l: L, +} + +impl Drop for Bar +where + for<'a, 'b> L: Lifetime2<'a, 'b>, +{ + fn drop(&mut self) {} +} + +#[allow(dead_code)] +struct FnHolder Fn(&'a T, dyn for<'b> Lifetime2<'a, 'b>) -> u8>(T); + +impl Fn(&'a T, dyn for<'b> Lifetime2<'a, 'b>) -> u8> Drop for FnHolder { + fn drop(&mut self) {} +} + +fn main() { + let _foo = Foo { l: 0 }; + + let _bar = Bar { l: 0 }; +} From 042d8553a1626597a01ce66b70015a834791c990 Mon Sep 17 00:00:00 2001 From: Tommaso Bianchi Date: Mon, 16 Dec 2019 11:27:28 -0500 Subject: [PATCH 02/38] Fix too restrictive checks on Drop impls --- src/librustc_typeck/check/dropck.rs | 135 ++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 0c8df9bad448f..6fcb839fa0b89 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -2,13 +2,15 @@ use crate::check::regionck::RegionCtxt; use crate::hir; use crate::hir::def_id::DefId; +use crate::util::common::ErrorReported; use rustc::infer::outlives::env::OutlivesEnvironment; use rustc::infer::{InferOk, SuppressRegionErrors}; use rustc::middle::region; use rustc::traits::{ObligationCause, TraitEngine, TraitEngineExt}; +use rustc::ty::error::TypeError; +use rustc::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc::ty::subst::{Subst, SubstsRef}; -use rustc::ty::{self, Ty, TyCtxt}; -use crate::util::common::ErrorReported; +use rustc::ty::{self, Predicate, Ty, TyCtxt}; use syntax_pos::Span; @@ -192,6 +194,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); let assumptions_in_impl_context = assumptions_in_impl_context.predicates; + let self_param_env = tcx.param_env(self_type_did); + // An earlier version of this code attempted to do this checking // via the traits::fulfill machinery. However, it ran into trouble // since the fulfill machinery merely turns outlives-predicates @@ -205,14 +209,35 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // to take on a structure that is roughly an alpha-renaming of // the generic parameters of the item definition.) - // This path now just checks *all* predicates via the direct - // lookup, rather than using fulfill machinery. + // This path now just checks *all* predicates via an instantiation of + // the `SimpleEqRelation`, which simply forwards to the `relate` machinery + // after taking care of anonymizing late bound regions. // // However, it may be more efficient in the future to batch - // the analysis together via the fulfill , rather than the - // repeated `contains` calls. + // the analysis together via the fulfill (see comment above regarding + // the usage of the fulfill machinery), rather than the + // repeated `.iter().any(..)` calls. + + // This closure is a more robust way to check `Predicate` equality + // than simple `==` checks (which were the previous implementation). + // It relies on `ty::relate` for `TraitPredicate` and `ProjectionPredicate` + // (which implement the Relate trait), while delegating on simple equality + // for the other `Predicate`. + // This implementation solves (Issue #59497) and (Issue #58311). + // It is unclear to me at the moment whether the approach based on `relate` + // could be extended easily also to the other `Predicate`. + let predicate_matches_closure = |p: &'_ Predicate<'tcx>| { + let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env); + match (predicate, p) { + (Predicate::Trait(a), Predicate::Trait(b)) => relator.relate(a, b).is_ok(), + (Predicate::Projection(a), Predicate::Projection(b)) => { + relator.relate(a, b).is_ok() + } + _ => predicate == p, + } + }; - if !assumptions_in_impl_context.contains(&predicate) { + if !assumptions_in_impl_context.iter().any(predicate_matches_closure) { let item_span = tcx.hir().span(self_type_hir_id); struct_span_err!( tcx.sess, @@ -251,3 +276,99 @@ crate fn check_drop_obligations<'a, 'tcx>( Ok(()) } + +// This is an implementation of the TypeRelation trait with the +// aim of simply comparing for equality (without side-effects). +// It is not intended to be used anywhere else other than here. +crate struct SimpleEqRelation<'tcx> { + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, +} + +impl<'tcx> SimpleEqRelation<'tcx> { + fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> SimpleEqRelation<'tcx> { + SimpleEqRelation { tcx, param_env } + } +} + +impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } + + fn tag(&self) -> &'static str { + "dropck::SimpleEqRelation" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_with_variance>( + &mut self, + _: ty::Variance, + a: &T, + b: &T, + ) -> RelateResult<'tcx, T> { + // Here we ignore variance because we require drop impl's types + // to be *exactly* the same as to the ones in the struct definition. + self.relate(a, b) + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("SimpleEqRelation::tys(a={:?}, b={:?})", a, b); + ty::relate::super_relate_tys(self, a, b) + } + + fn regions( + &mut self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + debug!("SimpleEqRelation::regions(a={:?}, b={:?})", a, b); + + // We can just equate the regions because LBRs have been + // already anonymized. + if a == b { + Ok(a) + } else { + // I'm not sure is this `TypeError` is the right one, but + // it should not matter as it won't be checked (the dropck + // will emit its own, more informative and higher-level errors + // in case anything goes wrong). + Err(TypeError::RegionsPlaceholderMismatch) + } + } + + fn consts( + &mut self, + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + debug!("SimpleEqRelation::consts(a={:?}, b={:?})", a, b); + ty::relate::super_relate_consts(self, a, b) + } + + fn binders( + &mut self, + a: &ty::Binder, + b: &ty::Binder, + ) -> RelateResult<'tcx, ty::Binder> + where + T: Relate<'tcx>, + { + debug!("SimpleEqRelation::binders({:?}: {:?}", a, b); + + // Anonymizing the LBRs is necessary to solve (Issue #59497). + // After we do so, it should be totally fine to skip the binders. + let anon_a = self.tcx.anonymize_late_bound_regions(a); + let anon_b = self.tcx.anonymize_late_bound_regions(b); + self.relate(anon_a.skip_binder(), anon_b.skip_binder())?; + + Ok(a.clone()) + } +} From b08d697236b236e96b0e8e6894e05aefe5a11b39 Mon Sep 17 00:00:00 2001 From: Tommaso Bianchi Date: Mon, 16 Dec 2019 11:28:28 -0500 Subject: [PATCH 03/38] Formatting fixes --- src/librustc_typeck/check/dropck.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 6fcb839fa0b89..59df88f8c70c5 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -56,8 +56,10 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro // already checked by coherence, but compilation may // not have been terminated. let span = tcx.def_span(drop_impl_did); - tcx.sess.delay_span_bug(span, - &format!("should have been rejected by coherence check: {}", dtor_self_type)); + tcx.sess.delay_span_bug( + span, + &format!("should have been rejected by coherence check: {}", dtor_self_type), + ); Err(ErrorReported) } } @@ -85,10 +87,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs); let cause = &ObligationCause::misc(drop_impl_span, drop_impl_hir_id); - match infcx - .at(cause, impl_param_env) - .eq(named_type, fresh_impl_self_ty) - { + match infcx.at(cause, impl_param_env).eq(named_type, fresh_impl_self_ty) { Ok(InferOk { obligations, .. }) => { fulfillment_cx.register_predicate_obligations(infcx, obligations); } @@ -99,12 +98,13 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( drop_impl_span, E0366, "Implementations of Drop cannot be specialized" - ).span_note( + ) + .span_note( item_span, "Use same sequence of generic type and region \ parameters that is on the struct/enum definition", ) - .emit(); + .emit(); return Err(ErrorReported); } } @@ -245,12 +245,13 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( E0367, "The requirement `{}` is added only by the Drop impl.", predicate - ).span_note( + ) + .span_note( item_span, "The same requirement must be part of \ the struct/enum definition", ) - .emit(); + .emit(); result = Err(ErrorReported); } } From 020be74f6bc5131b79a46d94a1111c35b187469a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Dec 2019 13:45:28 +0100 Subject: [PATCH 04/38] Clean up E0120 long explanation --- src/librustc_error_codes/error_codes/E0120.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0120.md b/src/librustc_error_codes/error_codes/E0120.md index 99c2a493a46b9..4861ed8e89718 100644 --- a/src/librustc_error_codes/error_codes/E0120.md +++ b/src/librustc_error_codes/error_codes/E0120.md @@ -1,5 +1,7 @@ -An attempt was made to implement Drop on a trait, which is not allowed: only -structs and enums can implement Drop. An example causing this error: +The Drop was implemented on a trait, which is not allowed: only structs and +enums can implement Drop. + +Erroneous code example: ```compile_fail,E0120 trait MyTrait {} @@ -10,7 +12,7 @@ impl Drop for MyTrait { ``` A workaround for this problem is to wrap the trait up in a struct, and implement -Drop on that. An example is shown below: +Drop on that: ``` trait MyTrait {} @@ -22,7 +24,7 @@ impl Drop for MyWrapper { ``` -Alternatively, wrapping trait objects requires something like the following: +Alternatively, wrapping trait objects requires something: ``` trait MyTrait {} From 94d207f4b27ba45b8d33e7e73d0829074a02117d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Dec 2019 13:45:36 +0100 Subject: [PATCH 05/38] Clean up E0121 long explanation --- src/librustc_error_codes/error_codes/E0121.md | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0121.md b/src/librustc_error_codes/error_codes/E0121.md index 069d0fc48fb0f..6c20b2803cbe3 100644 --- a/src/librustc_error_codes/error_codes/E0121.md +++ b/src/librustc_error_codes/error_codes/E0121.md @@ -1,10 +1,24 @@ -In order to be consistent with Rust's lack of global type inference, -type and const placeholders are disallowed by design in item signatures. +The type placeholder `_` was used withing a type on an item's signature. -Examples of this error include: +Erroneous code example: ```compile_fail,E0121 -fn foo() -> _ { 5 } // error, explicitly write out the return type instead +fn foo() -> _ { 5 } // error -static BAR: _ = "test"; // error, explicitly write out the type instead +static BAR: _ = "test"; // error +``` + +In those cases, you need to provide the type explicitly: + +``` +fn foo() -> i32 { 5 } // ok! + +static BAR: &str = "test"; // ok! +``` + +The type placeholder `_` can be used outside item's signature as follows: + +``` +let x = "a4a".split('4') + .collect::>(); // No need to precise the Vec's generic type. ``` From 7f0741db9e521355ab732601f4ab53d586748ad1 Mon Sep 17 00:00:00 2001 From: Dylan DPC Date: Fri, 20 Dec 2019 16:50:20 +0530 Subject: [PATCH 06/38] Update E0120.md --- src/librustc_error_codes/error_codes/E0120.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0120.md b/src/librustc_error_codes/error_codes/E0120.md index 4861ed8e89718..dc7258d87317f 100644 --- a/src/librustc_error_codes/error_codes/E0120.md +++ b/src/librustc_error_codes/error_codes/E0120.md @@ -1,4 +1,4 @@ -The Drop was implemented on a trait, which is not allowed: only structs and +Drop was implemented on a trait, which is not allowed: only structs and enums can implement Drop. Erroneous code example: From dce0f06f953d4f0f46cc7ca108c55f326febc790 Mon Sep 17 00:00:00 2001 From: Dylan DPC Date: Fri, 20 Dec 2019 17:02:39 +0530 Subject: [PATCH 07/38] Update E0121.md --- src/librustc_error_codes/error_codes/E0121.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0121.md b/src/librustc_error_codes/error_codes/E0121.md index 6c20b2803cbe3..06fe396d50d3b 100644 --- a/src/librustc_error_codes/error_codes/E0121.md +++ b/src/librustc_error_codes/error_codes/E0121.md @@ -1,4 +1,4 @@ -The type placeholder `_` was used withing a type on an item's signature. +The type placeholder `_` was used within a type on an item's signature. Erroneous code example: From 963f20db1a4276093545bd1d79969ee1d6b2c959 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 18 Dec 2019 14:19:03 +0100 Subject: [PATCH 08/38] Allow -Cllvm-args to override rustc's default LLVM args. --- src/librustc_codegen_llvm/llvm_util.rs | 46 ++++++++++++++++++-------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 40739387b00c4..6f9bb6d1ac551 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -3,6 +3,7 @@ use crate::llvm; use syntax_pos::symbol::Symbol; use rustc::session::Session; use rustc::session::config::PrintRequest; +use rustc_data_structures::fx::FxHashSet; use rustc_target::spec::{MergeFunctions, PanicStrategy}; use libc::c_int; use std::ffi::CString; @@ -51,20 +52,39 @@ unsafe fn configure_llvm(sess: &Session) { llvm::LLVMRustInstallFatalErrorHandler(); + fn llvm_arg_to_arg_name(full_arg: &str) -> &str { + full_arg.trim().split(|c: char| { + c == '=' || c.is_whitespace() + }).next().unwrap_or("") + } + + let user_specified_args: FxHashSet<_> = sess + .opts + .cg + .llvm_args + .iter() + .map(|s| llvm_arg_to_arg_name(s)) + .filter(|s| s.len() > 0) + .collect(); + { - let mut add = |arg: &str| { - let s = CString::new(arg).unwrap(); - llvm_args.push(s.as_ptr()); - llvm_c_strs.push(s); + // This adds the given argument to LLVM. Unless `force` is true + // user specified arguments are *not* overridden. + let mut add = |arg: &str, force: bool| { + if force || !user_specified_args.contains(llvm_arg_to_arg_name(arg)) { + let s = CString::new(arg).unwrap(); + llvm_args.push(s.as_ptr()); + llvm_c_strs.push(s); + } }; - add("rustc"); // fake program name - if sess.time_llvm_passes() { add("-time-passes"); } - if sess.print_llvm_passes() { add("-debug-pass=Structure"); } + add("rustc", true); // fake program name + if sess.time_llvm_passes() { add("-time-passes", false); } + if sess.print_llvm_passes() { add("-debug-pass=Structure", false); } if sess.opts.debugging_opts.disable_instrumentation_preinliner { - add("-disable-preinline"); + add("-disable-preinline", false); } if sess.opts.debugging_opts.generate_arange_section { - add("-generate-arange-section"); + add("-generate-arange-section", false); } if get_major_version() >= 8 { match sess.opts.debugging_opts.merge_functions @@ -72,22 +92,22 @@ unsafe fn configure_llvm(sess: &Session) { MergeFunctions::Disabled | MergeFunctions::Trampolines => {} MergeFunctions::Aliases => { - add("-mergefunc-use-aliases"); + add("-mergefunc-use-aliases", false); } } } if sess.target.target.target_os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind { - add("-enable-emscripten-cxx-exceptions"); + add("-enable-emscripten-cxx-exceptions", false); } // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes // during inlining. Unfortunately these may block other optimizations. - add("-preserve-alignment-assumptions-during-inlining=false"); + add("-preserve-alignment-assumptions-during-inlining=false", false); for arg in &sess.opts.cg.llvm_args { - add(&(*arg)); + add(&(*arg), true); } } From 1ca145c3b5b7bc8907ff6f176df2b5687a8ea85f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 18 Dec 2019 14:28:06 +0100 Subject: [PATCH 09/38] Remove rarely used -Zdisable_instrumentation_preinliner flag. The same effect can be achieved by `-Cllvm-args=-disable-preinline`. --- src/librustc_codegen_llvm/llvm_util.rs | 4 +--- src/librustc_session/options.rs | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 6f9bb6d1ac551..3145b0df63b8a 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -80,9 +80,7 @@ unsafe fn configure_llvm(sess: &Session) { add("rustc", true); // fake program name if sess.time_llvm_passes() { add("-time-passes", false); } if sess.print_llvm_passes() { add("-debug-pass=Structure", false); } - if sess.opts.debugging_opts.disable_instrumentation_preinliner { - add("-disable-preinline", false); - } + if sess.opts.debugging_opts.generate_arange_section { add("-generate-arange-section", false); } diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 9ddc9c0d602af..2f2d03fc596e4 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -866,8 +866,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "extra arguments to prepend to the linker invocation (space separated)"), profile: bool = (false, parse_bool, [TRACKED], "insert profiling code"), - disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED], - "Disable the instrumentation pre-inliner, useful for profiling / PGO."), relro_level: Option = (None, parse_relro_level, [TRACKED], "choose which RELRO level to use"), nll_facts: bool = (false, parse_bool, [UNTRACKED], From 382d370c4f5750900ec8896b3659d7624fe048a0 Mon Sep 17 00:00:00 2001 From: Dodo Date: Fri, 20 Dec 2019 21:42:03 +0100 Subject: [PATCH 10/38] Make ptr::slice_from_raw_parts a const fn available under a feature flag --- src/libcore/ptr/mod.rs | 6 ++++-- src/libcore/tests/lib.rs | 3 +++ src/libcore/tests/ptr.rs | 11 +++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 776165e7bd70c..67a64b53b0be6 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -257,7 +257,8 @@ pub(crate) struct FatPtr { /// ``` #[inline] #[unstable(feature = "slice_from_raw_parts", reason = "recently added", issue = "36925")] -pub fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { +#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")] +pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { unsafe { Repr { raw: FatPtr { data, len } }.rust } } @@ -273,7 +274,8 @@ pub fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { /// [`from_raw_parts_mut`]: ../../std/slice/fn.from_raw_parts_mut.html #[inline] #[unstable(feature = "slice_from_raw_parts", reason = "recently added", issue = "36925")] -pub fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { +#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")] +pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { unsafe { Repr { raw: FatPtr { data, len } }.rust_mut } } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index b28ed2eaa0876..1f20ebc01e993 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -36,6 +36,9 @@ #![feature(iter_is_partitioned)] #![feature(iter_order_by)] #![feature(cmp_min_max_by)] +#![feature(slice_from_raw_parts)] +#![feature(const_slice_from_raw_parts)] +#![feature(const_raw_ptr_deref)] extern crate test; diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs index eea736bc88f01..473bc881d2932 100644 --- a/src/libcore/tests/ptr.rs +++ b/src/libcore/tests/ptr.rs @@ -1,6 +1,17 @@ use core::cell::RefCell; use core::ptr::*; +#[test] +fn test_const_from_raw_parts() { + const SLICE: &[u8] = &[1, 2, 3, 4]; + const FROM_RAW: &[u8] = unsafe { &*slice_from_raw_parts(SLICE.as_ptr(), SLICE.len()) }; + assert_eq!(SLICE, FROM_RAW); + + let slice = &[1, 2, 3, 4, 5]; + let from_raw = unsafe { &*slice_from_raw_parts(slice.as_ptr(), 2) } ; + assert_eq!(&slice[..2], from_raw); +} + #[test] fn test() { unsafe { From c59588f17bd7d7b8844b6c3a5b4a7fe73178d014 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 06:44:24 +0100 Subject: [PATCH 11/38] extract parse_ty_tuple_or_parens --- src/librustc_parse/parser/ty.rs | 82 ++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 6f7ab0542d5fa..ae660432923e5 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -74,44 +74,7 @@ impl<'a> Parser<'a> { let lo = self.token.span; let mut impl_dyn_multi = false; let kind = if self.eat(&token::OpenDelim(token::Paren)) { - // `(TYPE)` is a parenthesized type. - // `(TYPE,)` is a tuple with a single field of type TYPE. - let mut ts = vec![]; - let mut last_comma = false; - while self.token != token::CloseDelim(token::Paren) { - ts.push(self.parse_ty()?); - if self.eat(&token::Comma) { - last_comma = true; - } else { - last_comma = false; - break; - } - } - let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; - self.expect(&token::CloseDelim(token::Paren))?; - - if ts.len() == 1 && !last_comma { - let ty = ts.into_iter().nth(0).unwrap().into_inner(); - let maybe_bounds = allow_plus && self.token.is_like_plus(); - match ty.kind { - // `(TY_BOUND_NOPAREN) + BOUND + ...`. - TyKind::Path(None, ref path) if maybe_bounds => { - self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)? - } - TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) - if maybe_bounds && bounds.len() == 1 && !trailing_plus => { - let path = match bounds[0] { - GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(), - GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"), - }; - self.parse_remaining_bounds(Vec::new(), path, lo, true)? - } - // `(TYPE)` - _ => TyKind::Paren(P(ty)) - } - } else { - TyKind::Tup(ts) - } + self.parse_ty_tuple_or_parens(allow_plus)? } else if self.eat(&token::Not) { // Never type `!` TyKind::Never @@ -242,6 +205,49 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery) } + /// Parses either: + /// - `(TYPE)`, a parenthesized type. + /// - `(TYPE,)`, a tuple with a single field of type TYPE. + fn parse_ty_tuple_or_parens(&mut self, allow_plus: bool) -> PResult<'a, TyKind> { + let lo = self.token.span; + let mut ts = vec![]; + let mut last_comma = false; + while self.token != token::CloseDelim(token::Paren) { + ts.push(self.parse_ty()?); + if self.eat(&token::Comma) { + last_comma = true; + } else { + last_comma = false; + break; + } + } + let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; + self.expect(&token::CloseDelim(token::Paren))?; + + if ts.len() == 1 && !last_comma { + let ty = ts.into_iter().nth(0).unwrap().into_inner(); + let maybe_bounds = allow_plus && self.token.is_like_plus(); + match ty.kind { + // `(TY_BOUND_NOPAREN) + BOUND + ...`. + TyKind::Path(None, ref path) if maybe_bounds => { + self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true) + } + TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) + if maybe_bounds && bounds.len() == 1 && !trailing_plus => { + let path = match bounds[0] { + GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(), + GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"), + }; + self.parse_remaining_bounds(Vec::new(), path, lo, true) + } + // `(TYPE)` + _ => Ok(TyKind::Paren(P(ty))) + } + } else { + Ok(TyKind::Tup(ts)) + } + } + fn parse_remaining_bounds(&mut self, generic_params: Vec, path: ast::Path, lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); From e68db0acca48f99d1d1555e00c464daa7ea461f1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 07:55:38 +0100 Subject: [PATCH 12/38] refactor parse_ty_tuple_or_parens --- src/librustc_parse/parser/ty.rs | 40 +++++++++++++-------------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index ae660432923e5..716bdf7bb1259 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -73,8 +73,8 @@ impl<'a> Parser<'a> { let lo = self.token.span; let mut impl_dyn_multi = false; - let kind = if self.eat(&token::OpenDelim(token::Paren)) { - self.parse_ty_tuple_or_parens(allow_plus)? + let kind = if self.check(&token::OpenDelim(token::Paren)) { + self.parse_ty_tuple_or_parens(lo, allow_plus)? } else if self.eat(&token::Not) { // Never type `!` TyKind::Never @@ -208,34 +208,26 @@ impl<'a> Parser<'a> { /// Parses either: /// - `(TYPE)`, a parenthesized type. /// - `(TYPE,)`, a tuple with a single field of type TYPE. - fn parse_ty_tuple_or_parens(&mut self, allow_plus: bool) -> PResult<'a, TyKind> { - let lo = self.token.span; - let mut ts = vec![]; - let mut last_comma = false; - while self.token != token::CloseDelim(token::Paren) { - ts.push(self.parse_ty()?); - if self.eat(&token::Comma) { - last_comma = true; - } else { - last_comma = false; - break; - } - } - let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; - self.expect(&token::CloseDelim(token::Paren))?; + fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: bool) -> PResult<'a, TyKind> { + let mut trailing_plus = false; + let (ts, trailing) = self.parse_paren_comma_seq(|p| { + let ty = p.parse_ty()?; + trailing_plus = p.prev_token_kind == PrevTokenKind::Plus; + Ok(ty) + })?; - if ts.len() == 1 && !last_comma { + if ts.len() == 1 && !trailing { let ty = ts.into_iter().nth(0).unwrap().into_inner(); let maybe_bounds = allow_plus && self.token.is_like_plus(); match ty.kind { // `(TY_BOUND_NOPAREN) + BOUND + ...`. - TyKind::Path(None, ref path) if maybe_bounds => { - self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true) + TyKind::Path(None, path) if maybe_bounds => { + self.parse_remaining_bounds(Vec::new(), path, lo, true) } - TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) - if maybe_bounds && bounds.len() == 1 && !trailing_plus => { - let path = match bounds[0] { - GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(), + TyKind::TraitObject(mut bounds, TraitObjectSyntax::None) + if maybe_bounds && bounds.len() == 1 && !trailing_plus => { + let path = match bounds.remove(0) { + GenericBound::Trait(pt, ..) => pt.trait_ref.path, GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"), }; self.parse_remaining_bounds(Vec::new(), path, lo, true) From 6d678b1fc74a3cd8d3105b90a740109f9e397b58 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 07:58:45 +0100 Subject: [PATCH 13/38] parse_ptr -> parse_ty_ptr & refactor --- src/librustc_parse/parser/ty.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 716bdf7bb1259..9ea5a88ddadf9 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -79,8 +79,7 @@ impl<'a> Parser<'a> { // Never type `!` TyKind::Never } else if self.eat(&token::BinOp(token::Star)) { - // Raw pointer - TyKind::Ptr(self.parse_ptr()?) + self.parse_ty_ptr()? } else if self.eat(&token::OpenDelim(token::Bracket)) { // Array or slice let t = self.parse_ty()?; @@ -251,7 +250,8 @@ impl<'a> Parser<'a> { Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } - fn parse_ptr(&mut self) -> PResult<'a, MutTy> { + /// Parses a raw pointer type: `*[const | mut] $type`. + fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> { let mutbl = self.parse_const_or_mut().unwrap_or_else(|| { let span = self.prev_span; let msg = "expected mut or const in raw pointer type"; @@ -261,8 +261,8 @@ impl<'a> Parser<'a> { .emit(); Mutability::Immutable }); - let t = self.parse_ty_no_plus()?; - Ok(MutTy { ty: t, mutbl }) + let ty = self.parse_ty_no_plus()?; + Ok(TyKind::Ptr(MutTy { ty, mutbl })) } fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option>> { From f08563727aeab1f47ea3d18f674b13e6a2cdcf5c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 08:19:53 +0100 Subject: [PATCH 14/38] extract parse_array_or_slice_ty --- src/librustc_parse/parser/expr.rs | 9 ++++---- src/librustc_parse/parser/item.rs | 7 ++---- src/librustc_parse/parser/ty.rs | 37 ++++++++++++------------------- 3 files changed, 21 insertions(+), 32 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index e4dff07e92cb8..0b4a59eb236d6 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -91,6 +91,10 @@ impl<'a> Parser<'a> { self.parse_expr_res(Restrictions::empty(), None) } + pub(super) fn parse_anon_const_expr(&mut self) -> PResult<'a, AnonConst> { + self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value }) + } + fn parse_paren_expr_seq(&mut self) -> PResult<'a, Vec>> { self.parse_paren_comma_seq(|p| { match p.parse_expr() { @@ -883,10 +887,7 @@ impl<'a> Parser<'a> { let first_expr = self.parse_expr()?; if self.eat(&token::Semi) { // Repeating array syntax: `[ 0; 512 ]` - let count = AnonConst { - id: DUMMY_NODE_ID, - value: self.parse_expr()?, - }; + let count = self.parse_anon_const_expr()?; self.expect(&token::CloseDelim(token::Bracket))?; ex = ExprKind::Repeat(first_expr, count); } else if self.eat(&token::Comma) { diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 0840a1551dbf4..691dbf67ca843 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -5,7 +5,7 @@ use crate::maybe_whole; use rustc_errors::{PResult, Applicability, DiagnosticBuilder, StashKey}; use rustc_error_codes::*; -use syntax::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item}; +use syntax::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, Item}; use syntax::ast::{AssocItem, AssocItemKind, ItemKind, UseTree, UseTreeKind}; use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit}; use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind}; @@ -1318,10 +1318,7 @@ impl<'a> Parser<'a> { }; let disr_expr = if self.eat(&token::Eq) { - Some(AnonConst { - id: DUMMY_NODE_ID, - value: self.parse_expr()?, - }) + Some(self.parse_anon_const_expr()?) } else { None }; diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 9ea5a88ddadf9..c3d934d350327 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -8,7 +8,7 @@ use rustc_error_codes::*; use syntax::ptr::P; use syntax::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam, Lifetime, Ident}; use syntax::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef}; -use syntax::ast::{Mutability, AnonConst, Mac}; +use syntax::ast::{Mutability, Mac}; use syntax::token::{self, Token}; use syntax::struct_span_err; use syntax_pos::source_map::Span; @@ -81,18 +81,7 @@ impl<'a> Parser<'a> { } else if self.eat(&token::BinOp(token::Star)) { self.parse_ty_ptr()? } else if self.eat(&token::OpenDelim(token::Bracket)) { - // Array or slice - let t = self.parse_ty()?; - // Parse optional `; EXPR` in `[TYPE; EXPR]` - let t = match self.maybe_parse_fixed_length_of_vec()? { - None => TyKind::Slice(t), - Some(length) => TyKind::Array(t, AnonConst { - id: ast::DUMMY_NODE_ID, - value: length, - }), - }; - self.expect(&token::CloseDelim(token::Bracket))?; - t + self.parse_array_or_slice_ty()? } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) { // Reference self.expect_and()?; @@ -101,12 +90,9 @@ impl<'a> Parser<'a> { // `typeof(EXPR)` // In order to not be ambiguous, the type must be surrounded by parens. self.expect(&token::OpenDelim(token::Paren))?; - let e = AnonConst { - id: ast::DUMMY_NODE_ID, - value: self.parse_expr()?, - }; + let expr = self.parse_anon_const_expr()?; self.expect(&token::CloseDelim(token::Paren))?; - TyKind::Typeof(e) + TyKind::Typeof(expr) } else if self.eat_keyword(kw::Underscore) { // A type to be inferred `_` TyKind::Infer @@ -265,12 +251,17 @@ impl<'a> Parser<'a> { Ok(TyKind::Ptr(MutTy { ty, mutbl })) } - fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option>> { - if self.eat(&token::Semi) { - Ok(Some(self.parse_expr()?)) + /// Parses an array (`[TYPE; EXPR]`) or slice (`[TYPE]`) type. + /// The opening `[` bracket is already eaten. + fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> { + let elt_ty = self.parse_ty()?; + let ty = if self.eat(&token::Semi) { + TyKind::Array(elt_ty, self.parse_anon_const_expr()?) } else { - Ok(None) - } + TyKind::Slice(elt_ty) + }; + self.expect(&token::CloseDelim(token::Bracket))?; + Ok(ty) } fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { From b42b85f3cf32306a0115ef334f09fb397f122053 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 08:23:10 +0100 Subject: [PATCH 15/38] extract parse_typeof_ty --- src/librustc_parse/parser/ty.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index c3d934d350327..624719d6ca53b 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -87,12 +87,7 @@ impl<'a> Parser<'a> { self.expect_and()?; self.parse_borrowed_pointee()? } else if self.eat_keyword_noexpect(kw::Typeof) { - // `typeof(EXPR)` - // In order to not be ambiguous, the type must be surrounded by parens. - self.expect(&token::OpenDelim(token::Paren))?; - let expr = self.parse_anon_const_expr()?; - self.expect(&token::CloseDelim(token::Paren))?; - TyKind::Typeof(expr) + self.parse_typeof_ty()? } else if self.eat_keyword(kw::Underscore) { // A type to be inferred `_` TyKind::Infer @@ -268,7 +263,16 @@ impl<'a> Parser<'a> { let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; let mutbl = self.parse_mutability(); let ty = self.parse_ty_no_plus()?; - return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl })); + Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl })) + } + + // Parses the `typeof(EXPR)`. + // To avoid ambiguity, the type is surrounded by parenthesis. + fn parse_typeof_ty(&mut self) -> PResult<'a, TyKind> { + self.expect(&token::OpenDelim(token::Paren))?; + let expr = self.parse_anon_const_expr()?; + self.expect(&token::CloseDelim(token::Paren))?; + Ok(TyKind::Typeof(expr)) } /// Is the current token one of the keywords that signals a bare function type? From d47de3ee981b1cda68f8be7071d192c6b60f6859 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 08:29:12 +0100 Subject: [PATCH 16/38] extract parse_impl_ty --- src/librustc_parse/parser/ty.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 624719d6ca53b..c3fc16e0725ba 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -98,7 +98,6 @@ impl<'a> Parser<'a> { // Function pointer type or bound list (trait object type) starting with a poly-trait. // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> Trait1<'lt> + Trait2 + 'a` - let lo = self.token.span; let lifetime_defs = self.parse_late_bound_lifetime_defs()?; if self.token_is_bare_fn_keyword() { self.parse_ty_bare_fn(lifetime_defs)? @@ -108,10 +107,7 @@ impl<'a> Parser<'a> { self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? } } else if self.eat_keyword(kw::Impl) { - // Always parse bounds greedily for better error recovery. - let bounds = self.parse_generic_bounds(None)?; - impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; - TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) + self.parse_impl_ty(&mut impl_dyn_multi)? } else if self.check_keyword(kw::Dyn) && (self.token.span.rust_2018() || self.look_ahead(1, |t| t.can_begin_bound() && @@ -312,6 +308,14 @@ impl<'a> Parser<'a> { }))) } + /// Parses an `impl B0 + ... + Bn` type. + fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { + // Always parse bounds greedily for better error recovery. + let bounds = self.parse_generic_bounds(None)?; + *impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; + Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)) + } + pub(super) fn parse_generic_bounds(&mut self, colon_span: Option) -> PResult<'a, GenericBounds> { self.parse_generic_bounds_common(true, colon_span) From 1fa8f70ed0b412449402a0326e04f6302848a4d4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 08:38:23 +0100 Subject: [PATCH 17/38] extract parse_dyn_ty --- src/librustc_parse/parser/ty.rs | 40 ++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index c3fc16e0725ba..e88bfc17dd6eb 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -108,20 +108,14 @@ impl<'a> Parser<'a> { } } else if self.eat_keyword(kw::Impl) { self.parse_impl_ty(&mut impl_dyn_multi)? - } else if self.check_keyword(kw::Dyn) && - (self.token.span.rust_2018() || - self.look_ahead(1, |t| t.can_begin_bound() && - !can_continue_type_after_non_fn_ident(t))) { - self.bump(); // `dyn` - // Always parse bounds greedily for better error recovery. - let bounds = self.parse_generic_bounds(None)?; - impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; - TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) - } else if self.check(&token::Question) || - self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) { + } else if self.is_explicit_dyn_type() { + self.parse_dyn_ty(&mut impl_dyn_multi)? + } else if self.check(&token::Question) + || self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) + { // Bound list (trait object type) - TyKind::TraitObject(self.parse_generic_bounds_common(allow_plus, None)?, - TraitObjectSyntax::None) + let bounds = self.parse_generic_bounds_common(allow_plus, None)?; + TyKind::TraitObject(bounds, TraitObjectSyntax::None) } else if self.eat_lt() { // Qualified path let (qself, path) = self.parse_qpath(PathStyle::Type)?; @@ -316,6 +310,26 @@ impl<'a> Parser<'a> { Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)) } + /// Is a `dyn B0 + ... + Bn` type allowed here? + fn is_explicit_dyn_type(&mut self) -> bool { + self.check_keyword(kw::Dyn) + && (self.token.span.rust_2018() + || self.look_ahead(1, |t| { + t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t) + })) + } + + /// Parses a `dyn B0 + ... + Bn` type. + /// + /// Note that this does *not* parse bare trait objects. + fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { + self.bump(); // `dyn` + // Always parse bounds greedily for better error recovery. + let bounds = self.parse_generic_bounds(None)?; + *impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; + Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)) + } + pub(super) fn parse_generic_bounds(&mut self, colon_span: Option) -> PResult<'a, GenericBounds> { self.parse_generic_bounds_common(true, colon_span) From c0561cf6217d6147591c8d7799bc92307fc9b0c6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 08:49:20 +0100 Subject: [PATCH 18/38] extract parse_path_start_ty --- src/librustc_parse/parser/ty.rs | 47 ++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index e88bfc17dd6eb..ddbb9afa02b32 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -121,27 +121,7 @@ impl<'a> Parser<'a> { let (qself, path) = self.parse_qpath(PathStyle::Type)?; TyKind::Path(Some(qself), path) } else if self.token.is_path_start() { - // Simple path - let path = self.parse_path(PathStyle::Type)?; - if self.eat(&token::Not) { - // Macro invocation in type position - let args = self.parse_mac_args()?; - let mac = Mac { - path, - args, - prior_type_ascription: self.last_type_ascription, - }; - TyKind::Mac(mac) - } else { - // Just a type path or bound list (trait object type) starting with a trait. - // `Type` - // `Trait1 + Trait2 + 'a` - if allow_plus && self.check_plus() { - self.parse_remaining_bounds(Vec::new(), path, lo, true)? - } else { - TyKind::Path(None, path) - } - } + self.parse_path_start_ty(lo, allow_plus)? } else if self.eat(&token::DotDotDot) { if allow_c_variadic { TyKind::CVarArgs @@ -330,6 +310,31 @@ impl<'a> Parser<'a> { Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)) } + /// Parses a type starting with a path. + /// + /// This can be: + /// 1. a type macro, `mac!(...)`, + /// 2. a bare trait object, `B0 + ... + Bn`, + /// 3. or a path, `path::to::MyType`. + fn parse_path_start_ty(&mut self, lo: Span, allow_plus: bool) -> PResult<'a, TyKind> { + // Simple path + let path = self.parse_path(PathStyle::Type)?; + if self.eat(&token::Not) { + // Macro invocation in type position + Ok(TyKind::Mac(Mac { + path, + args: self.parse_mac_args()?, + prior_type_ascription: self.last_type_ascription, + })) + } else if allow_plus && self.check_plus() { + // `Trait1 + Trait2 + 'a` + self.parse_remaining_bounds(Vec::new(), path, lo, true) + } else { + // Just a type path. + Ok(TyKind::Path(None, path)) + } + } + pub(super) fn parse_generic_bounds(&mut self, colon_span: Option) -> PResult<'a, GenericBounds> { self.parse_generic_bounds_common(true, colon_span) From 6b92be20d10d55862f825a7e94b67e350b1efa6e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 09:01:26 +0100 Subject: [PATCH 19/38] extract error_illegal_c_variadic_ty --- src/librustc_parse/parser/ty.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index ddbb9afa02b32..840461d75be01 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -128,14 +128,7 @@ impl<'a> Parser<'a> { } else { // FIXME(Centril): Should we just allow `...` syntactically // anywhere in a type and use semantic restrictions instead? - struct_span_err!( - self.sess.span_diagnostic, - lo.to(self.prev_span), - E0743, - "C-variadic type `...` may not be nested inside another type", - ) - .emit(); - + self.error_illegal_c_varadic_ty(lo); TyKind::Err } } else { @@ -335,6 +328,16 @@ impl<'a> Parser<'a> { } } + fn error_illegal_c_varadic_ty(&self, lo: Span) { + struct_span_err!( + self.sess.span_diagnostic, + lo.to(self.prev_span), + E0743, + "C-variadic type `...` may not be nested inside another type", + ) + .emit(); + } + pub(super) fn parse_generic_bounds(&mut self, colon_span: Option) -> PResult<'a, GenericBounds> { self.parse_generic_bounds_common(true, colon_span) From 0e740223722724be520208161eef3dd41ec6dca6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 09:08:19 +0100 Subject: [PATCH 20/38] parse_ty_common: .fatal -> .struct_span_err --- src/librustc_parse/parser/ty.rs | 2 +- src/test/ui/type/ascription/issue-47666.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 840461d75be01..d9938a81240dc 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -133,7 +133,7 @@ impl<'a> Parser<'a> { } } else { let msg = format!("expected type, found {}", self.this_token_descr()); - let mut err = self.fatal(&msg); + let mut err = self.struct_span_err(self.token.span, &msg); err.span_label(self.token.span, "expected type"); self.maybe_annotate_with_ascription(&mut err, true); return Err(err); diff --git a/src/test/ui/type/ascription/issue-47666.stderr b/src/test/ui/type/ascription/issue-47666.stderr index 2f052341faead..648635f0c32fa 100644 --- a/src/test/ui/type/ascription/issue-47666.stderr +++ b/src/test/ui/type/ascription/issue-47666.stderr @@ -11,7 +11,7 @@ LL | let _ = Option:Some(vec![0, 1]); | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` = note: for more information, see https://github.com/rust-lang/rust/issues/23416 - = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error From 3b63465f546a7e8c66055595442dc3dc47341a8c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 09:10:17 +0100 Subject: [PATCH 21/38] parser/ty.rs: minor formatting tweaks --- src/librustc_parse/parser/ty.rs | 35 ++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index d9938a81240dc..a4c1f530ef8f2 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -183,8 +183,13 @@ impl<'a> Parser<'a> { } } - fn parse_remaining_bounds(&mut self, generic_params: Vec, path: ast::Path, - lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { + fn parse_remaining_bounds( + &mut self, + generic_params: Vec, + path: ast::Path, + lo: Span, + parse_plus: bool, + ) -> PResult<'a, TyKind> { let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; if parse_plus { @@ -338,8 +343,10 @@ impl<'a> Parser<'a> { .emit(); } - pub(super) fn parse_generic_bounds(&mut self, - colon_span: Option) -> PResult<'a, GenericBounds> { + pub(super) fn parse_generic_bounds( + &mut self, + colon_span: Option, + ) -> PResult<'a, GenericBounds> { self.parse_generic_bounds_common(true, colon_span) } @@ -351,20 +358,24 @@ impl<'a> Parser<'a> { /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) /// TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`) /// ``` - fn parse_generic_bounds_common(&mut self, - allow_plus: bool, - colon_span: Option) -> PResult<'a, GenericBounds> { + fn parse_generic_bounds_common( + &mut self, + allow_plus: bool, + colon_span: Option, + ) -> PResult<'a, GenericBounds> { let mut bounds = Vec::new(); let mut negative_bounds = Vec::new(); let mut last_plus_span = None; let mut was_negative = false; loop { // This needs to be synchronized with `TokenKind::can_begin_bound`. - let is_bound_start = self.check_path() || self.check_lifetime() || - self.check(&token::Not) || // used for error reporting only - self.check(&token::Question) || - self.check_keyword(kw::For) || - self.check(&token::OpenDelim(token::Paren)); + let is_bound_start = self.check_path() + || self.check_lifetime() + || self.check(&token::Not) // Used for error reporting only. + || self.check(&token::Question) + || self.check_keyword(kw::For) + || self.check(&token::OpenDelim(token::Paren)); + if is_bound_start { let lo = self.token.span; let has_parens = self.eat(&token::OpenDelim(token::Paren)); From 8e8ac0253958604c4e2077d6f035051f2b22a5d4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 09:18:34 +0100 Subject: [PATCH 22/38] extract error_opt_out_lifetime --- src/librustc_parse/parser/ty.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index a4c1f530ef8f2..b9537100ce174 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -383,10 +383,7 @@ impl<'a> Parser<'a> { let is_negative = self.eat(&token::Not); let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; if self.token.is_lifetime() { - if let Some(question_span) = question { - self.span_err(question_span, - "`?` may only modify trait bounds, not lifetime bounds"); - } + self.error_opt_out_lifetime(question); bounds.push(GenericBound::Outlives(self.expect_lifetime())); if has_parens { let inner_span = inner_lo.to(self.prev_span); @@ -473,6 +470,13 @@ impl<'a> Parser<'a> { return Ok(bounds); } + fn error_opt_out_lifetime(&self, question: Option) { + if let Some(span) = question { + self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds") + .emit(); + } + } + pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(kw::For) { self.expect_lt()?; From 56b54fb465887981cdb5325de776db7e6173a172 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 09:29:17 +0100 Subject: [PATCH 23/38] extract recover_paren_lifetime --- src/librustc_parse/parser/ty.rs | 36 +++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index b9537100ce174..2b642ad2de7a3 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -386,21 +386,7 @@ impl<'a> Parser<'a> { self.error_opt_out_lifetime(question); bounds.push(GenericBound::Outlives(self.expect_lifetime())); if has_parens { - let inner_span = inner_lo.to(self.prev_span); - self.expect(&token::CloseDelim(token::Paren))?; - let mut err = self.struct_span_err( - lo.to(self.prev_span), - "parenthesized lifetime bounds are not supported" - ); - if let Ok(snippet) = self.span_to_snippet(inner_span) { - err.span_suggestion_short( - lo.to(self.prev_span), - "remove the parentheses", - snippet.to_owned(), - Applicability::MachineApplicable - ); - } - err.emit(); + self.recover_paren_lifetime(lo, inner_lo)?; } } else { let lifetime_defs = self.parse_late_bound_lifetime_defs()?; @@ -477,6 +463,26 @@ impl<'a> Parser<'a> { } } + /// Recover on `('lifetime)` with `(` already eaten. + fn recover_paren_lifetime(&mut self, lo: Span, inner_lo: Span) -> PResult<'a, ()> { + let inner_span = inner_lo.to(self.prev_span); + self.expect(&token::CloseDelim(token::Paren))?; + let mut err = self.struct_span_err( + lo.to(self.prev_span), + "parenthesized lifetime bounds are not supported" + ); + if let Ok(snippet) = self.span_to_snippet(inner_span) { + err.span_suggestion_short( + lo.to(self.prev_span), + "remove the parentheses", + snippet.to_owned(), + Applicability::MachineApplicable + ); + } + err.emit(); + Ok(()) + } + pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(kw::For) { self.expect_lt()?; From e8b6769c04c732c3d91e5f55fc5b0350b872a747 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 09:42:32 +0100 Subject: [PATCH 24/38] parse_generic_bounds_common: dedent --- src/librustc_parse/parser/ty.rs | 64 ++++++++++++++++----------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 2b642ad2de7a3..b58c16c78e66a 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -376,42 +376,42 @@ impl<'a> Parser<'a> { || self.check_keyword(kw::For) || self.check(&token::OpenDelim(token::Paren)); - if is_bound_start { - let lo = self.token.span; - let has_parens = self.eat(&token::OpenDelim(token::Paren)); - let inner_lo = self.token.span; - let is_negative = self.eat(&token::Not); - let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; - if self.token.is_lifetime() { - self.error_opt_out_lifetime(question); - bounds.push(GenericBound::Outlives(self.expect_lifetime())); - if has_parens { - self.recover_paren_lifetime(lo, inner_lo)?; + if !is_bound_start { + break; + } + + let lo = self.token.span; + let has_parens = self.eat(&token::OpenDelim(token::Paren)); + let inner_lo = self.token.span; + let is_negative = self.eat(&token::Not); + let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + if self.token.is_lifetime() { + self.error_opt_out_lifetime(question); + bounds.push(GenericBound::Outlives(self.expect_lifetime())); + if has_parens { + self.recover_paren_lifetime(lo, inner_lo)?; + } + } else { + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + } + let poly_span = lo.to(self.prev_span); + if is_negative { + was_negative = true; + if let Some(sp) = last_plus_span.or(colon_span) { + negative_bounds.push(sp.to(poly_span)); } } else { - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - let path = self.parse_path(PathStyle::Type)?; - if has_parens { - self.expect(&token::CloseDelim(token::Paren))?; - } - let poly_span = lo.to(self.prev_span); - if is_negative { - was_negative = true; - if let Some(sp) = last_plus_span.or(colon_span) { - negative_bounds.push(sp.to(poly_span)); - } + let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); + let modifier = if question.is_some() { + TraitBoundModifier::Maybe } else { - let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); - let modifier = if question.is_some() { - TraitBoundModifier::Maybe - } else { - TraitBoundModifier::None - }; - bounds.push(GenericBound::Trait(poly_trait, modifier)); - } + TraitBoundModifier::None + }; + bounds.push(GenericBound::Trait(poly_trait, modifier)); } - } else { - break } if !allow_plus || !self.eat_plus() { From 7294804c409e35ac2e0c273d651aa2ba212f7d42 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 10:04:31 +0100 Subject: [PATCH 25/38] extract can_begin_bound --- src/librustc_parse/parser/ty.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index b58c16c78e66a..ca8dd62cc6a02 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -367,19 +367,7 @@ impl<'a> Parser<'a> { let mut negative_bounds = Vec::new(); let mut last_plus_span = None; let mut was_negative = false; - loop { - // This needs to be synchronized with `TokenKind::can_begin_bound`. - let is_bound_start = self.check_path() - || self.check_lifetime() - || self.check(&token::Not) // Used for error reporting only. - || self.check(&token::Question) - || self.check_keyword(kw::For) - || self.check(&token::OpenDelim(token::Paren)); - - if !is_bound_start { - break; - } - + while self.can_begin_bound() { let lo = self.token.span; let has_parens = self.eat(&token::OpenDelim(token::Paren)); let inner_lo = self.token.span; @@ -456,6 +444,17 @@ impl<'a> Parser<'a> { return Ok(bounds); } + /// Can the current token begin a bound? + fn can_begin_bound(&mut self) -> bool { + // This needs to be synchronized with `TokenKind::can_begin_bound`. + self.check_path() + || self.check_lifetime() + || self.check(&token::Not) // Used for error reporting only. + || self.check(&token::Question) + || self.check_keyword(kw::For) + || self.check(&token::OpenDelim(token::Paren)) + } + fn error_opt_out_lifetime(&self, question: Option) { if let Some(span) = question { self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds") From 229560ba1fbb0955aa94f91778c091cf189d280b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 10:32:38 +0100 Subject: [PATCH 26/38] extract parse_generic_bound --- src/librustc_parse/parser/ty.rs | 101 +++++++++++++++++++------------- 1 file changed, 61 insertions(+), 40 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index ca8dd62cc6a02..f0a1b36bc3624 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -352,12 +352,7 @@ impl<'a> Parser<'a> { /// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`. /// - /// ``` - /// BOUND = TY_BOUND | LT_BOUND - /// LT_BOUND = LIFETIME (e.g., `'a`) - /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) - /// TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`) - /// ``` + /// See `parse_generic_bound` for the `BOUND` grammar. fn parse_generic_bounds_common( &mut self, allow_plus: bool, @@ -368,39 +363,13 @@ impl<'a> Parser<'a> { let mut last_plus_span = None; let mut was_negative = false; while self.can_begin_bound() { - let lo = self.token.span; - let has_parens = self.eat(&token::OpenDelim(token::Paren)); - let inner_lo = self.token.span; - let is_negative = self.eat(&token::Not); - let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; - if self.token.is_lifetime() { - self.error_opt_out_lifetime(question); - bounds.push(GenericBound::Outlives(self.expect_lifetime())); - if has_parens { - self.recover_paren_lifetime(lo, inner_lo)?; - } - } else { - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - let path = self.parse_path(PathStyle::Type)?; - if has_parens { - self.expect(&token::CloseDelim(token::Paren))?; - } - let poly_span = lo.to(self.prev_span); - if is_negative { - was_negative = true; - if let Some(sp) = last_plus_span.or(colon_span) { - negative_bounds.push(sp.to(poly_span)); - } - } else { - let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); - let modifier = if question.is_some() { - TraitBoundModifier::Maybe - } else { - TraitBoundModifier::None - }; - bounds.push(GenericBound::Trait(poly_trait, modifier)); - } - } + self.parse_generic_bound( + colon_span, + last_plus_span, + &mut bounds, + &mut negative_bounds, + &mut was_negative, + )?; if !allow_plus || !self.eat_plus() { break @@ -441,7 +410,7 @@ impl<'a> Parser<'a> { err.emit(); } - return Ok(bounds); + Ok(bounds) } /// Can the current token begin a bound? @@ -455,6 +424,58 @@ impl<'a> Parser<'a> { || self.check(&token::OpenDelim(token::Paren)) } + /// Parses a bound according to the grammar: + /// + /// ``` + /// BOUND = TY_BOUND | LT_BOUND + /// LT_BOUND = LIFETIME (e.g., `'a`) + /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) + /// TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`) + /// ``` + fn parse_generic_bound( + &mut self, + colon_span: Option, + last_plus_span: Option, + bounds: &mut Vec, + negative_bounds: &mut Vec, + was_negative: &mut bool, + ) -> PResult<'a, ()> { + let lo = self.token.span; + let has_parens = self.eat(&token::OpenDelim(token::Paren)); + let inner_lo = self.token.span; + let is_negative = self.eat(&token::Not); + let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + if self.token.is_lifetime() { + self.error_opt_out_lifetime(question); + bounds.push(GenericBound::Outlives(self.expect_lifetime())); + if has_parens { + self.recover_paren_lifetime(lo, inner_lo)?; + } + } else { + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + } + let poly_span = lo.to(self.prev_span); + if is_negative { + *was_negative = true; + if let Some(sp) = last_plus_span.or(colon_span) { + negative_bounds.push(sp.to(poly_span)); + } + } else { + let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); + let modifier = if question.is_some() { + TraitBoundModifier::Maybe + } else { + TraitBoundModifier::None + }; + bounds.push(GenericBound::Trait(poly_trait, modifier)); + } + } + Ok(()) + } + fn error_opt_out_lifetime(&self, question: Option) { if let Some(span) = question { self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds") From 2ca618130aecb2b4446b4c4b6f128f603fccb1a7 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 11:04:26 +0100 Subject: [PATCH 27/38] functionalize parse_generic_bound --- src/librustc_parse/parser/ty.rs | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index f0a1b36bc3624..72f831aab0678 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -363,13 +363,15 @@ impl<'a> Parser<'a> { let mut last_plus_span = None; let mut was_negative = false; while self.can_begin_bound() { - self.parse_generic_bound( - colon_span, - last_plus_span, - &mut bounds, - &mut negative_bounds, - &mut was_negative, - )?; + match self.parse_generic_bound(colon_span, last_plus_span)? { + Ok(bound) => bounds.push(bound), + Err(neg_sp) => { + was_negative = true; + if let Some(neg_sp) = neg_sp { + negative_bounds.push(neg_sp); + } + } + } if !allow_plus || !self.eat_plus() { break @@ -436,10 +438,7 @@ impl<'a> Parser<'a> { &mut self, colon_span: Option, last_plus_span: Option, - bounds: &mut Vec, - negative_bounds: &mut Vec, - was_negative: &mut bool, - ) -> PResult<'a, ()> { + ) -> PResult<'a, Result>> { let lo = self.token.span; let has_parens = self.eat(&token::OpenDelim(token::Paren)); let inner_lo = self.token.span; @@ -447,10 +446,11 @@ impl<'a> Parser<'a> { let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; if self.token.is_lifetime() { self.error_opt_out_lifetime(question); - bounds.push(GenericBound::Outlives(self.expect_lifetime())); + let bound = GenericBound::Outlives(self.expect_lifetime()); if has_parens { self.recover_paren_lifetime(lo, inner_lo)?; } + Ok(Ok(bound)) } else { let lifetime_defs = self.parse_late_bound_lifetime_defs()?; let path = self.parse_path(PathStyle::Type)?; @@ -459,10 +459,7 @@ impl<'a> Parser<'a> { } let poly_span = lo.to(self.prev_span); if is_negative { - *was_negative = true; - if let Some(sp) = last_plus_span.or(colon_span) { - negative_bounds.push(sp.to(poly_span)); - } + Ok(Err(last_plus_span.or(colon_span).map(|sp| sp.to(poly_span)))) } else { let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); let modifier = if question.is_some() { @@ -470,10 +467,9 @@ impl<'a> Parser<'a> { } else { TraitBoundModifier::None }; - bounds.push(GenericBound::Trait(poly_trait, modifier)); + Ok(Ok(GenericBound::Trait(poly_trait, modifier))) } } - Ok(()) } fn error_opt_out_lifetime(&self, question: Option) { From f87ff0f0b788bfcb8f559dfb75ad3c10186635fd Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 11:08:04 +0100 Subject: [PATCH 28/38] parse_generic_bound: leave a FIXME --- src/librustc_parse/parser/ty.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 72f831aab0678..2c362294ad0c9 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -448,6 +448,8 @@ impl<'a> Parser<'a> { self.error_opt_out_lifetime(question); let bound = GenericBound::Outlives(self.expect_lifetime()); if has_parens { + // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, + // possibly introducing `GenericBound::Paren(P)`? self.recover_paren_lifetime(lo, inner_lo)?; } Ok(Ok(bound)) From 8f33bdca752668ab1e3419e192b37f557ba57f0d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 11:19:24 +0100 Subject: [PATCH 29/38] extract parse_generic_ty_bound --- src/librustc_parse/parser/ty.rs | 39 ++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 2c362294ad0c9..a5ce46e9700f9 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -431,8 +431,6 @@ impl<'a> Parser<'a> { /// ``` /// BOUND = TY_BOUND | LT_BOUND /// LT_BOUND = LIFETIME (e.g., `'a`) - /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) - /// TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`) /// ``` fn parse_generic_bound( &mut self, @@ -454,22 +452,11 @@ impl<'a> Parser<'a> { } Ok(Ok(bound)) } else { - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - let path = self.parse_path(PathStyle::Type)?; - if has_parens { - self.expect(&token::CloseDelim(token::Paren))?; - } - let poly_span = lo.to(self.prev_span); + let (poly_span, bound) = self.parse_generic_ty_bound(lo, has_parens, question)?; if is_negative { Ok(Err(last_plus_span.or(colon_span).map(|sp| sp.to(poly_span)))) } else { - let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); - let modifier = if question.is_some() { - TraitBoundModifier::Maybe - } else { - TraitBoundModifier::None - }; - Ok(Ok(GenericBound::Trait(poly_trait, modifier))) + Ok(Ok(bound)) } } } @@ -501,6 +488,28 @@ impl<'a> Parser<'a> { Ok(()) } + /// Parses a type bound according to: + /// ``` + /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) + /// TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`) + /// ``` + fn parse_generic_ty_bound( + &mut self, + lo: Span, + has_parens: bool, + question: Option, + ) -> PResult<'a, (Span, GenericBound)> { + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + } + let poly_span = lo.to(self.prev_span); + let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); + let modifier = question.map_or(TraitBoundModifier::None, |_| TraitBoundModifier::Maybe); + Ok((poly_span, GenericBound::Trait(poly_trait, modifier))) + } + pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(kw::For) { self.expect_lt()?; From 81232118b3c88340a54b309c3e0019faf45d470f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 11:28:57 +0100 Subject: [PATCH 30/38] extract parse_generic_lt_bound --- src/librustc_parse/parser/ty.rs | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index a5ce46e9700f9..905bc204b5156 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -427,10 +427,8 @@ impl<'a> Parser<'a> { } /// Parses a bound according to the grammar: - /// /// ``` /// BOUND = TY_BOUND | LT_BOUND - /// LT_BOUND = LIFETIME (e.g., `'a`) /// ``` fn parse_generic_bound( &mut self, @@ -443,14 +441,7 @@ impl<'a> Parser<'a> { let is_negative = self.eat(&token::Not); let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; if self.token.is_lifetime() { - self.error_opt_out_lifetime(question); - let bound = GenericBound::Outlives(self.expect_lifetime()); - if has_parens { - // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, - // possibly introducing `GenericBound::Paren(P)`? - self.recover_paren_lifetime(lo, inner_lo)?; - } - Ok(Ok(bound)) + Ok(Ok(self.parse_generic_lt_bound(lo, inner_lo, has_parens, question)?)) } else { let (poly_span, bound) = self.parse_generic_ty_bound(lo, has_parens, question)?; if is_negative { @@ -461,6 +452,27 @@ impl<'a> Parser<'a> { } } + /// Parses a lifetime ("outlives") bound, e.g. `'a`, according to: + /// ``` + /// LT_BOUND = LIFETIME + /// ``` + fn parse_generic_lt_bound( + &mut self, + lo: Span, + inner_lo: Span, + has_parens: bool, + question: Option, + ) -> PResult<'a, GenericBound> { + self.error_opt_out_lifetime(question); + let bound = GenericBound::Outlives(self.expect_lifetime()); + if has_parens { + // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, + // possibly introducing `GenericBound::Paren(P)`? + self.recover_paren_lifetime(lo, inner_lo)?; + } + Ok(bound) + } + fn error_opt_out_lifetime(&self, question: Option) { if let Some(span) = question { self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds") From 90f7d8b37870632d1d65caa6c3c2872377d8e615 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 11:49:25 +0100 Subject: [PATCH 31/38] simplify negative bound diagnostic --- src/librustc_parse/parser/ty.rs | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 905bc204b5156..eadaf8ad716d3 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -360,36 +360,24 @@ impl<'a> Parser<'a> { ) -> PResult<'a, GenericBounds> { let mut bounds = Vec::new(); let mut negative_bounds = Vec::new(); - let mut last_plus_span = None; - let mut was_negative = false; while self.can_begin_bound() { - match self.parse_generic_bound(colon_span, last_plus_span)? { + match self.parse_generic_bound()? { Ok(bound) => bounds.push(bound), - Err(neg_sp) => { - was_negative = true; - if let Some(neg_sp) = neg_sp { - negative_bounds.push(neg_sp); - } - } + Err(neg_sp) => negative_bounds.push(neg_sp), } - if !allow_plus || !self.eat_plus() { break - } else { - last_plus_span = Some(self.prev_span); } } - if !negative_bounds.is_empty() || was_negative { + if !negative_bounds.is_empty() { let negative_bounds_len = negative_bounds.len(); - let last_span = negative_bounds.last().map(|sp| *sp); + let last_span = *negative_bounds.last().unwrap(); let mut err = self.struct_span_err( negative_bounds, "negative trait bounds are not supported", ); - if let Some(sp) = last_span { - err.span_label(sp, "negative trait bounds are not supported"); - } + err.span_label(last_span, "negative trait bounds are not supported"); if let Some(bound_list) = colon_span { let bound_list = bound_list.to(self.prev_span); let mut new_bound_list = String::new(); @@ -432,9 +420,8 @@ impl<'a> Parser<'a> { /// ``` fn parse_generic_bound( &mut self, - colon_span: Option, - last_plus_span: Option, - ) -> PResult<'a, Result>> { + ) -> PResult<'a, Result> { + let anchor_lo = self.prev_span; let lo = self.token.span; let has_parens = self.eat(&token::OpenDelim(token::Paren)); let inner_lo = self.token.span; @@ -445,7 +432,7 @@ impl<'a> Parser<'a> { } else { let (poly_span, bound) = self.parse_generic_ty_bound(lo, has_parens, question)?; if is_negative { - Ok(Err(last_plus_span.or(colon_span).map(|sp| sp.to(poly_span)))) + Ok(Err(anchor_lo.to(poly_span))) } else { Ok(Ok(bound)) } From 765df3aaff42ac60973983132d18b30fdc9f787d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 11:57:18 +0100 Subject: [PATCH 32/38] simplify 'let question = ...;' --- src/librustc_parse/parser/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index eadaf8ad716d3..c972204587574 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -426,7 +426,7 @@ impl<'a> Parser<'a> { let has_parens = self.eat(&token::OpenDelim(token::Paren)); let inner_lo = self.token.span; let is_negative = self.eat(&token::Not); - let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + let question = self.eat(&token::Question).then_some(self.prev_span); if self.token.is_lifetime() { Ok(Ok(self.parse_generic_lt_bound(lo, inner_lo, has_parens, question)?)) } else { From 51bbdeb58871c7aa6324724598d583fbb7a3d4ba Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 12:19:53 +0100 Subject: [PATCH 33/38] parse_generic_bounds: account for negative lifetime bounds --- src/librustc_parse/parser/ty.rs | 35 +++++++++---------- src/test/ui/issues/issue-58857.rs | 2 +- src/test/ui/issues/issue-58857.stderr | 6 ++-- src/test/ui/parser/issue-33418.fixed | 10 +++--- src/test/ui/parser/issue-33418.rs | 10 +++--- src/test/ui/parser/issue-33418.stderr | 30 ++++++++-------- ...-negative-outlives-bound-syntactic-fail.rs | 12 +++++++ ...ative-outlives-bound-syntactic-fail.stderr | 26 ++++++++++++++ 8 files changed, 83 insertions(+), 48 deletions(-) create mode 100644 src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.rs create mode 100644 src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index c972204587574..db9a0ada525b1 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -375,9 +375,9 @@ impl<'a> Parser<'a> { let last_span = *negative_bounds.last().unwrap(); let mut err = self.struct_span_err( negative_bounds, - "negative trait bounds are not supported", + "negative bounds are not supported", ); - err.span_label(last_span, "negative trait bounds are not supported"); + err.span_label(last_span, "negative bounds are not supported"); if let Some(bound_list) = colon_span { let bound_list = bound_list.to(self.prev_span); let mut new_bound_list = String::new(); @@ -392,7 +392,7 @@ impl<'a> Parser<'a> { } err.span_suggestion_hidden( bound_list, - &format!("remove the trait bound{}", pluralize!(negative_bounds_len)), + &format!("remove the bound{}", pluralize!(negative_bounds_len)), new_bound_list, Applicability::MachineApplicable, ); @@ -418,25 +418,23 @@ impl<'a> Parser<'a> { /// ``` /// BOUND = TY_BOUND | LT_BOUND /// ``` - fn parse_generic_bound( - &mut self, - ) -> PResult<'a, Result> { + fn parse_generic_bound(&mut self) -> PResult<'a, Result> { let anchor_lo = self.prev_span; let lo = self.token.span; let has_parens = self.eat(&token::OpenDelim(token::Paren)); let inner_lo = self.token.span; let is_negative = self.eat(&token::Not); let question = self.eat(&token::Question).then_some(self.prev_span); - if self.token.is_lifetime() { - Ok(Ok(self.parse_generic_lt_bound(lo, inner_lo, has_parens, question)?)) + let bound = if self.token.is_lifetime() { + self.parse_generic_lt_bound(lo, inner_lo, has_parens, question)? } else { - let (poly_span, bound) = self.parse_generic_ty_bound(lo, has_parens, question)?; - if is_negative { - Ok(Err(anchor_lo.to(poly_span))) - } else { - Ok(Ok(bound)) - } - } + self.parse_generic_ty_bound(lo, has_parens, question)? + }; + Ok(if is_negative { + Err(anchor_lo.to(self.prev_span)) + } else { + Ok(bound) + }) } /// Parses a lifetime ("outlives") bound, e.g. `'a`, according to: @@ -497,16 +495,15 @@ impl<'a> Parser<'a> { lo: Span, has_parens: bool, question: Option, - ) -> PResult<'a, (Span, GenericBound)> { + ) -> PResult<'a, GenericBound> { let lifetime_defs = self.parse_late_bound_lifetime_defs()?; let path = self.parse_path(PathStyle::Type)?; if has_parens { self.expect(&token::CloseDelim(token::Paren))?; } - let poly_span = lo.to(self.prev_span); - let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); let modifier = question.map_or(TraitBoundModifier::None, |_| TraitBoundModifier::Maybe); - Ok((poly_span, GenericBound::Trait(poly_trait, modifier))) + Ok(GenericBound::Trait(poly_trait, modifier)) } pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { diff --git a/src/test/ui/issues/issue-58857.rs b/src/test/ui/issues/issue-58857.rs index 392e4ea0c2ecc..4350d7e5b403b 100644 --- a/src/test/ui/issues/issue-58857.rs +++ b/src/test/ui/issues/issue-58857.rs @@ -2,6 +2,6 @@ struct Conj {a : A} trait Valid {} impl Conj{} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported fn main() {} diff --git a/src/test/ui/issues/issue-58857.stderr b/src/test/ui/issues/issue-58857.stderr index ab9a0130c00b0..9bc80cc270b0f 100644 --- a/src/test/ui/issues/issue-58857.stderr +++ b/src/test/ui/issues/issue-58857.stderr @@ -1,10 +1,10 @@ -error: negative trait bounds are not supported +error: negative bounds are not supported --> $DIR/issue-58857.rs:4:7 | LL | impl Conj{} - | ^^^^^^^^ negative trait bounds are not supported + | ^^^^^^^^ negative bounds are not supported | - = help: remove the trait bound + = help: remove the bound error: aborting due to previous error diff --git a/src/test/ui/parser/issue-33418.fixed b/src/test/ui/parser/issue-33418.fixed index 2aaa3b5b1ea50..ed885ae143566 100644 --- a/src/test/ui/parser/issue-33418.fixed +++ b/src/test/ui/parser/issue-33418.fixed @@ -1,15 +1,15 @@ // run-rustfix trait Tr {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr2: SuperA {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr3: SuperB {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr4: SuperB + SuperD {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr5 {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait SuperA {} trait SuperB {} diff --git a/src/test/ui/parser/issue-33418.rs b/src/test/ui/parser/issue-33418.rs index 5533152092719..9934284abfbbe 100644 --- a/src/test/ui/parser/issue-33418.rs +++ b/src/test/ui/parser/issue-33418.rs @@ -1,17 +1,17 @@ // run-rustfix trait Tr: !SuperA {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr2: SuperA + !SuperB {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr3: !SuperA + SuperB {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr4: !SuperA + SuperB + !SuperC + SuperD {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr5: !SuperA + !SuperB {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait SuperA {} trait SuperB {} diff --git a/src/test/ui/parser/issue-33418.stderr b/src/test/ui/parser/issue-33418.stderr index 479e7bed1016a..7f361dbe2718f 100644 --- a/src/test/ui/parser/issue-33418.stderr +++ b/src/test/ui/parser/issue-33418.stderr @@ -1,46 +1,46 @@ -error: negative trait bounds are not supported +error: negative bounds are not supported --> $DIR/issue-33418.rs:3:9 | LL | trait Tr: !SuperA {} - | ^^^^^^^^^ negative trait bounds are not supported + | ^^^^^^^^^ negative bounds are not supported | - = help: remove the trait bound + = help: remove the bound -error: negative trait bounds are not supported +error: negative bounds are not supported --> $DIR/issue-33418.rs:5:19 | LL | trait Tr2: SuperA + !SuperB {} - | ^^^^^^^^^ negative trait bounds are not supported + | ^^^^^^^^^ negative bounds are not supported | - = help: remove the trait bound + = help: remove the bound -error: negative trait bounds are not supported +error: negative bounds are not supported --> $DIR/issue-33418.rs:7:10 | LL | trait Tr3: !SuperA + SuperB {} - | ^^^^^^^^^ negative trait bounds are not supported + | ^^^^^^^^^ negative bounds are not supported | - = help: remove the trait bound + = help: remove the bound -error: negative trait bounds are not supported +error: negative bounds are not supported --> $DIR/issue-33418.rs:9:10 | LL | trait Tr4: !SuperA + SuperB | ^^^^^^^^^ LL | + !SuperC + SuperD {} - | ^^^^^^^^^ negative trait bounds are not supported + | ^^^^^^^^^ negative bounds are not supported | - = help: remove the trait bounds + = help: remove the bounds -error: negative trait bounds are not supported +error: negative bounds are not supported --> $DIR/issue-33418.rs:12:10 | LL | trait Tr5: !SuperA | ^^^^^^^^^ LL | + !SuperB {} - | ^^^^^^^^^ negative trait bounds are not supported + | ^^^^^^^^^ negative bounds are not supported | - = help: remove the trait bounds + = help: remove the bounds error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.rs b/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.rs new file mode 100644 index 0000000000000..5a109ba7c6894 --- /dev/null +++ b/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.rs @@ -0,0 +1,12 @@ +// In this regression test for #67146, we check that the +// negative outlives bound `!'a` is rejected by the parser. +// This regression was first introduced in PR #57364. + +fn main() {} + +fn f1() {} +//~^ ERROR negative bounds are not supported +fn f2<'a, T: Ord + !'a>() {} +//~^ ERROR negative bounds are not supported +fn f3<'a, T: !'a + Ord>() {} +//~^ ERROR negative bounds are not supported diff --git a/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr b/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr new file mode 100644 index 0000000000000..74437c1a0081a --- /dev/null +++ b/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr @@ -0,0 +1,26 @@ +error: negative bounds are not supported + --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:7:8 + | +LL | fn f1() {} + | ^^^^^^^^^^ negative bounds are not supported + | + = help: remove the bound + +error: negative bounds are not supported + --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:9:18 + | +LL | fn f2<'a, T: Ord + !'a>() {} + | ^^^^^ negative bounds are not supported + | + = help: remove the bound + +error: negative bounds are not supported + --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:11:12 + | +LL | fn f3<'a, T: !'a + Ord>() {} + | ^^^^^ negative bounds are not supported + | + = help: remove the bound + +error: aborting due to 3 previous errors + From f02fd503d041dcf9cd87af8da43ac445f99d027e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 12:29:05 +0100 Subject: [PATCH 34/38] extract error_negative_bounds --- src/librustc_parse/parser/ty.rs | 62 +++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index db9a0ada525b1..3877f3f9a62f6 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -371,33 +371,7 @@ impl<'a> Parser<'a> { } if !negative_bounds.is_empty() { - let negative_bounds_len = negative_bounds.len(); - let last_span = *negative_bounds.last().unwrap(); - let mut err = self.struct_span_err( - negative_bounds, - "negative bounds are not supported", - ); - err.span_label(last_span, "negative bounds are not supported"); - if let Some(bound_list) = colon_span { - let bound_list = bound_list.to(self.prev_span); - let mut new_bound_list = String::new(); - if !bounds.is_empty() { - let mut snippets = bounds.iter().map(|bound| bound.span()) - .map(|span| self.span_to_snippet(span)); - while let Some(Ok(snippet)) = snippets.next() { - new_bound_list.push_str(" + "); - new_bound_list.push_str(&snippet); - } - new_bound_list = new_bound_list.replacen(" +", ":", 1); - } - err.span_suggestion_hidden( - bound_list, - &format!("remove the bound{}", pluralize!(negative_bounds_len)), - new_bound_list, - Applicability::MachineApplicable, - ); - } - err.emit(); + self.error_negative_bounds(colon_span, &bounds, negative_bounds); } Ok(bounds) @@ -414,6 +388,40 @@ impl<'a> Parser<'a> { || self.check(&token::OpenDelim(token::Paren)) } + fn error_negative_bounds( + &self, + colon_span: Option, + bounds: &[GenericBound], + negative_bounds: Vec, + ) { + let negative_bounds_len = negative_bounds.len(); + let last_span = *negative_bounds.last().unwrap(); + let mut err = self.struct_span_err( + negative_bounds, + "negative bounds are not supported", + ); + err.span_label(last_span, "negative bounds are not supported"); + if let Some(bound_list) = colon_span { + let bound_list = bound_list.to(self.prev_span); + let mut new_bound_list = String::new(); + if !bounds.is_empty() { + let mut snippets = bounds.iter().map(|bound| self.span_to_snippet(bound.span())); + while let Some(Ok(snippet)) = snippets.next() { + new_bound_list.push_str(" + "); + new_bound_list.push_str(&snippet); + } + new_bound_list = new_bound_list.replacen(" +", ":", 1); + } + err.span_suggestion_hidden( + bound_list, + &format!("remove the bound{}", pluralize!(negative_bounds_len)), + new_bound_list, + Applicability::MachineApplicable, + ); + } + err.emit(); + } + /// Parses a bound according to the grammar: /// ``` /// BOUND = TY_BOUND | LT_BOUND From 0ebd421fd6a0140ec33c222e58daf05931d99a35 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 12:29:55 +0100 Subject: [PATCH 35/38] document parse_late_bound_lifetime_defs --- src/librustc_parse/parser/ty.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 3877f3f9a62f6..09697c01a54b1 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -514,6 +514,7 @@ impl<'a> Parser<'a> { Ok(GenericBound::Trait(poly_trait, modifier)) } + /// Optionally parses `for<$generic_params>`. pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(kw::For) { self.expect_lt()?; From d977e5be07604514b7c00667b7f09240bcae6e12 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 12:40:20 +0100 Subject: [PATCH 36/38] parse_ty_bare_fn: improve docs --- src/librustc_parse/parser/ty.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 09697c01a54b1..15e0d54bb0171 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -250,20 +250,15 @@ impl<'a> Parser<'a> { self.check_keyword(kw::Extern) } - /// Parses a `TyKind::BareFn` type. + /// Parses a function pointer type (`TyKind::BareFn`). + /// ``` + /// [unsafe] [extern "ABI"] fn (S) -> T + /// ^~~~~^ ^~~~^ ^~^ ^ + /// | | | | + /// | | | Return type + /// Function Style ABI Parameter types + /// ``` fn parse_ty_bare_fn(&mut self, generic_params: Vec) -> PResult<'a, TyKind> { - /* - - [unsafe] [extern "ABI"] fn (S) -> T - ^~~~^ ^~~~^ ^~^ ^ - | | | | - | | | Return type - | | Argument types - | | - | ABI - Function Style - */ - let unsafety = self.parse_unsafety(); let ext = self.parse_extern()?; self.expect_keyword(kw::Fn)?; From cabe665fca55bb5d43744c10434bed12d10ad603 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Dec 2019 03:28:22 +0100 Subject: [PATCH 37/38] unwrap -> expect --- src/librustc_parse/parser/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 15e0d54bb0171..b83ec71124def 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -390,7 +390,7 @@ impl<'a> Parser<'a> { negative_bounds: Vec, ) { let negative_bounds_len = negative_bounds.len(); - let last_span = *negative_bounds.last().unwrap(); + let last_span = *negative_bounds.last().expect("no negative bounds, but still error?"); let mut err = self.struct_span_err( negative_bounds, "negative bounds are not supported", From 690b0b39a947c67d8a8998234c3cd083c679ee49 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Dec 2019 03:32:54 +0100 Subject: [PATCH 38/38] span_suggestion_hidden -> tool_only_span_suggestion --- src/librustc_parse/parser/ty.rs | 2 +- src/test/ui/issues/issue-58857.stderr | 2 -- src/test/ui/parser/issue-33418.stderr | 10 ---------- ...67146-negative-outlives-bound-syntactic-fail.stderr | 6 ------ 4 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index b83ec71124def..9f5fd6d0a36eb 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -407,7 +407,7 @@ impl<'a> Parser<'a> { } new_bound_list = new_bound_list.replacen(" +", ":", 1); } - err.span_suggestion_hidden( + err.tool_only_span_suggestion( bound_list, &format!("remove the bound{}", pluralize!(negative_bounds_len)), new_bound_list, diff --git a/src/test/ui/issues/issue-58857.stderr b/src/test/ui/issues/issue-58857.stderr index 9bc80cc270b0f..e2acec47e5abf 100644 --- a/src/test/ui/issues/issue-58857.stderr +++ b/src/test/ui/issues/issue-58857.stderr @@ -3,8 +3,6 @@ error: negative bounds are not supported | LL | impl Conj{} | ^^^^^^^^ negative bounds are not supported - | - = help: remove the bound error: aborting due to previous error diff --git a/src/test/ui/parser/issue-33418.stderr b/src/test/ui/parser/issue-33418.stderr index 7f361dbe2718f..9a8733e89292e 100644 --- a/src/test/ui/parser/issue-33418.stderr +++ b/src/test/ui/parser/issue-33418.stderr @@ -3,24 +3,18 @@ error: negative bounds are not supported | LL | trait Tr: !SuperA {} | ^^^^^^^^^ negative bounds are not supported - | - = help: remove the bound error: negative bounds are not supported --> $DIR/issue-33418.rs:5:19 | LL | trait Tr2: SuperA + !SuperB {} | ^^^^^^^^^ negative bounds are not supported - | - = help: remove the bound error: negative bounds are not supported --> $DIR/issue-33418.rs:7:10 | LL | trait Tr3: !SuperA + SuperB {} | ^^^^^^^^^ negative bounds are not supported - | - = help: remove the bound error: negative bounds are not supported --> $DIR/issue-33418.rs:9:10 @@ -29,8 +23,6 @@ LL | trait Tr4: !SuperA + SuperB | ^^^^^^^^^ LL | + !SuperC + SuperD {} | ^^^^^^^^^ negative bounds are not supported - | - = help: remove the bounds error: negative bounds are not supported --> $DIR/issue-33418.rs:12:10 @@ -39,8 +31,6 @@ LL | trait Tr5: !SuperA | ^^^^^^^^^ LL | + !SuperB {} | ^^^^^^^^^ negative bounds are not supported - | - = help: remove the bounds error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr b/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr index 74437c1a0081a..4dc0634730442 100644 --- a/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr +++ b/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr @@ -3,24 +3,18 @@ error: negative bounds are not supported | LL | fn f1() {} | ^^^^^^^^^^ negative bounds are not supported - | - = help: remove the bound error: negative bounds are not supported --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:9:18 | LL | fn f2<'a, T: Ord + !'a>() {} | ^^^^^ negative bounds are not supported - | - = help: remove the bound error: negative bounds are not supported --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:11:12 | LL | fn f3<'a, T: !'a + Ord>() {} | ^^^^^ negative bounds are not supported - | - = help: remove the bound error: aborting due to 3 previous errors