From 33910f9d86cf8c283c51800085c3e863261ec5ae Mon Sep 17 00:00:00 2001 From: wangxiangqing Date: Tue, 22 Oct 2019 00:08:14 +0800 Subject: [PATCH 01/32] Deprecated proc_macro doesn't trigger warning on build library Change-Id: Ib3a396e7334d209fe6c6ef425bbfc7b2ae471378 --- src/libsyntax_ext/proc_macro_harness.rs | 10 ++++++++++ .../ui/proc-macro/proc-macro-deprecated-attr.rs | 15 +++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/test/ui/proc-macro/proc-macro-deprecated-attr.rs diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index 96d0c3fcab1c5..bbf5b1255510f 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -416,6 +416,16 @@ fn mk_decls( ).map(|mut i| { let attr = cx.meta_word(span, sym::rustc_proc_macro_decls); i.attrs.push(cx.attribute(attr)); + + let deprecated_attr = attr::mk_nested_word_item( + Ident::new(sym::deprecated, span) + ); + let allow_deprecated_attr = attr::mk_list_item( + Ident::new(sym::allow, span), + vec![deprecated_attr] + ); + i.attrs.push(cx.attribute(allow_deprecated_attr)); + i }); diff --git a/src/test/ui/proc-macro/proc-macro-deprecated-attr.rs b/src/test/ui/proc-macro/proc-macro-deprecated-attr.rs new file mode 100644 index 0000000000000..32ccc24904283 --- /dev/null +++ b/src/test/ui/proc-macro/proc-macro-deprecated-attr.rs @@ -0,0 +1,15 @@ +// build-pass + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro] +#[deprecated(since = "1.0.0", note = "test")] +pub fn test_compile_without_warning_with_deprecated(_: TokenStream) -> TokenStream { + " + extern crate proc_macro; + fn foo() { } + ".parse().unwrap() +} From c027be0dd09a440927071dea69378d01322373cd Mon Sep 17 00:00:00 2001 From: wangxiangqing Date: Tue, 22 Oct 2019 00:08:14 +0800 Subject: [PATCH 02/32] Deprecated proc_macro doesn't trigger warning on build library Change-Id: Ib3a396e7334d209fe6c6ef425bbfc7b2ae471378 --- src/libsyntax_ext/proc_macro_harness.rs | 1 + src/test/ui/proc-macro/proc-macro-deprecated-attr.rs | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index bbf5b1255510f..c874f1ffb1175 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -337,6 +337,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { // use proc_macro::bridge::client::ProcMacro; // // #[rustc_proc_macro_decls] +// #[allow(deprecated)] // static DECLS: &[ProcMacro] = &[ // ProcMacro::custom_derive($name_trait1, &[], ::$name1); // ProcMacro::custom_derive($name_trait2, &["attribute_name"], ::$name2); diff --git a/src/test/ui/proc-macro/proc-macro-deprecated-attr.rs b/src/test/ui/proc-macro/proc-macro-deprecated-attr.rs index 32ccc24904283..25ce53b70a5bd 100644 --- a/src/test/ui/proc-macro/proc-macro-deprecated-attr.rs +++ b/src/test/ui/proc-macro/proc-macro-deprecated-attr.rs @@ -1,4 +1,6 @@ -// build-pass +// check-pass + +#![deny(deprecated)] #![crate_type = "proc-macro"] @@ -8,8 +10,5 @@ use proc_macro::*; #[proc_macro] #[deprecated(since = "1.0.0", note = "test")] pub fn test_compile_without_warning_with_deprecated(_: TokenStream) -> TokenStream { - " - extern crate proc_macro; - fn foo() { } - ".parse().unwrap() + TokenStream::new() } From aa733dacdf786039af1b2b95b85439db513f3fe6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 13 Oct 2019 22:07:02 +0200 Subject: [PATCH 03/32] Add long error explanation for E0576 --- src/librustc_resolve/error_codes.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index b82cba8c83dc4..c8ccd330b517e 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -1797,6 +1797,31 @@ let _: ::Empire; // ok! ``` "##, +E0576: r##" +An associated item wasn't found in the given type. + +Erroneous code example: + +```compile_fail,E0576 +trait Hello { + type Who; + + fn hello() -> ::You; // error! +} +``` + +In this example, we tried to use the non-existent associated type `You` of the +`Hello` trait. To fix this error, use an existing associated type: + +``` +trait Hello { + type Who; + + fn hello() -> ::Who; // ok! +} +``` +"##, + E0603: r##" A private item was used outside its scope. @@ -1924,7 +1949,6 @@ struct Foo> { // E0427, merged into 530 // E0467, removed // E0470, removed - E0576, E0577, E0578, } From 530d7098bf58aacea8fb703e065d755483dca516 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 13 Oct 2019 22:07:11 +0200 Subject: [PATCH 04/32] Update ui tests --- src/test/ui/issues/issue-19883.stderr | 1 + src/test/ui/issues/issue-22037.stderr | 1 + src/test/ui/issues/issue-22384.stderr | 1 + src/test/ui/type/type-path-err-node-types.stderr | 2 +- src/test/ui/ufcs/ufcs-partially-resolved.stderr | 2 +- 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/ui/issues/issue-19883.stderr b/src/test/ui/issues/issue-19883.stderr index 738add1684004..e370b2ec1cb42 100644 --- a/src/test/ui/issues/issue-19883.stderr +++ b/src/test/ui/issues/issue-19883.stderr @@ -6,3 +6,4 @@ LL | >::Dst error: aborting due to previous error +For more information about this error, try `rustc --explain E0576`. diff --git a/src/test/ui/issues/issue-22037.stderr b/src/test/ui/issues/issue-22037.stderr index 40d4a5e3bc0c5..615628558f08b 100644 --- a/src/test/ui/issues/issue-22037.stderr +++ b/src/test/ui/issues/issue-22037.stderr @@ -6,3 +6,4 @@ LL | fn a(&self) -> ::X; error: aborting due to previous error +For more information about this error, try `rustc --explain E0576`. diff --git a/src/test/ui/issues/issue-22384.stderr b/src/test/ui/issues/issue-22384.stderr index 130c3124b6f82..1f767a443d0f0 100644 --- a/src/test/ui/issues/issue-22384.stderr +++ b/src/test/ui/issues/issue-22384.stderr @@ -6,3 +6,4 @@ LL | <::foobar as Trait>::foo(); error: aborting due to previous error +For more information about this error, try `rustc --explain E0576`. diff --git a/src/test/ui/type/type-path-err-node-types.stderr b/src/test/ui/type/type-path-err-node-types.stderr index cd93525c76219..ea9cca2bfaab0 100644 --- a/src/test/ui/type/type-path-err-node-types.stderr +++ b/src/test/ui/type/type-path-err-node-types.stderr @@ -30,5 +30,5 @@ LL | let _ = |a, b: _| -> _ { 0 }; error: aborting due to 5 previous errors -Some errors have detailed explanations: E0282, E0412, E0425, E0433. +Some errors have detailed explanations: E0282, E0412, E0425, E0433, E0576. For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/ufcs/ufcs-partially-resolved.stderr b/src/test/ui/ufcs/ufcs-partially-resolved.stderr index 39752f66b9d65..dee990ec3d1cb 100644 --- a/src/test/ui/ufcs/ufcs-partially-resolved.stderr +++ b/src/test/ui/ufcs/ufcs-partially-resolved.stderr @@ -200,5 +200,5 @@ LL | ::X::N; error: aborting due to 32 previous errors -Some errors have detailed explanations: E0223, E0433, E0575, E0599. +Some errors have detailed explanations: E0223, E0433, E0575, E0576, E0599. For more information about an error, try `rustc --explain E0223`. From 7ffbd62445b9706325d01ec8be8e70c41404fe0d Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 14 Oct 2019 18:55:32 +0100 Subject: [PATCH 05/32] ignore uninhabited non-exhaustive variant fields This commit modifies the uninhabitedness checking so that the fields of a non-exhaustive variant (which is not local) are ignored if they are uninhabited. This is an improvement over the previous behaviour which considered all non-local non-exhaustive variants useful because unreachable patterns are now detected. Signed-off-by: David Wood --- src/librustc_mir/hair/pattern/_match.rs | 88 ++++++++----------- .../issue-65157-repeated-match-arm.rs | 22 +++++ .../issue-65157-repeated-match-arm.stderr | 14 +++ 3 files changed, 75 insertions(+), 49 deletions(-) create mode 100644 src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs create mode 100644 src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index dc6d4b27886e4..907c84b6f8cf0 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -394,16 +394,6 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } - fn is_non_exhaustive_variant<'p>(&self, pattern: &'p Pat<'tcx>) -> bool { - match *pattern.kind { - PatKind::Variant { adt_def, variant_index, .. } => { - let ref variant = adt_def.variants[variant_index]; - variant.is_field_list_non_exhaustive() - } - _ => false, - } - } - fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { match ty.kind { ty::Adt(adt_def, ..) => adt_def.is_variant_list_non_exhaustive(), @@ -1252,19 +1242,12 @@ pub fn is_useful<'p, 'a, 'tcx>( debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]); if let Some(constructors) = pat_constructors(cx, v[0], pcx) { - let is_declared_nonexhaustive = cx.is_non_exhaustive_variant(v[0]) && !cx.is_local(pcx.ty); - debug!("is_useful - expanding constructors: {:#?}, is_declared_nonexhaustive: {:?}", - constructors, is_declared_nonexhaustive); - - if is_declared_nonexhaustive { - Useful - } else { - split_grouped_constructors( - cx.tcx, cx.param_env, constructors, matrix, pcx.ty, pcx.span, Some(hir_id), - ).into_iter().map(|c| - is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id) - ).find(|result| result.is_useful()).unwrap_or(NotUseful) - } + debug!("is_useful - expanding constructors: {:#?}", constructors); + split_grouped_constructors( + cx.tcx, cx.param_env, constructors, matrix, pcx.ty, pcx.span, Some(hir_id), + ).into_iter().map(|c| + is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id) + ).find(|result| result.is_useful()).unwrap_or(NotUseful) } else { debug!("is_useful - expanding wildcard"); @@ -1548,27 +1531,30 @@ fn constructor_sub_pattern_tys<'a, 'tcx>( // Use T as the sub pattern type of Box. vec![substs.type_at(0)] } else { - adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.iter().map(|field| { + let variant = &adt.variants[ctor.variant_index_for_adt(cx, adt)]; + let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(ty); + variant.fields.iter().map(|field| { let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); - if is_visible { - let ty = field.ty(cx.tcx, substs); - match ty.kind { - // If the field type returned is an array of an unknown - // size return an TyErr. - ty::Array(_, len) - if len.try_eval_usize(cx.tcx, cx.param_env).is_none() => - cx.tcx.types.err, - _ => ty, - } - } else { - // Treat all non-visible fields as TyErr. They - // can't appear in any other pattern from - // this match (because they are private), - // so their type does not matter - but - // we don't want to know they are - // uninhabited. - cx.tcx.types.err + let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs)); + match (is_visible, is_non_exhaustive, is_uninhabited) { + // Treat all uninhabited types in non-exhaustive variants as `TyErr`. + (_, true, true) => cx.tcx.types.err, + // Treat all non-visible fields as `TyErr`. They can't appear in any + // other pattern from this match (because they are private), so their + // type does not matter - but we don't want to know they are uninhabited. + (false, ..) => cx.tcx.types.err, + (true, ..) => { + let ty = field.ty(cx.tcx, substs); + match ty.kind { + // If the field type returned is an array of an unknown + // size return an TyErr. + ty::Array(_, len) + if len.try_eval_usize(cx.tcx, cx.param_env).is_none() => + cx.tcx.types.err, + _ => ty, + } + }, } }).collect() } @@ -1874,15 +1860,18 @@ fn constructor_covered_by_range<'tcx>( } } -fn patterns_for_variant<'p, 'tcx>( +fn patterns_for_variant<'p, 'a: 'p, 'tcx>( + cx: &mut MatchCheckCtxt<'a, 'tcx>, subpatterns: &'p [FieldPat<'tcx>], - wild_patterns: &[&'p Pat<'tcx>]) - -> SmallVec<[&'p Pat<'tcx>; 2]> -{ + wild_patterns: &[&'p Pat<'tcx>], + is_non_exhaustive: bool, +) -> SmallVec<[&'p Pat<'tcx>; 2]> { let mut result = SmallVec::from_slice(wild_patterns); for subpat in subpatterns { - result[subpat.field.index()] = &subpat.pattern; + if !is_non_exhaustive || !cx.is_uninhabited(subpat.pattern.ty) { + result[subpat.field.index()] = &subpat.pattern; + } } debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result); @@ -1916,13 +1905,14 @@ fn specialize<'p, 'a: 'p, 'tcx>( PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { let ref variant = adt_def.variants[variant_index]; + let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(pat.ty); Some(Variant(variant.def_id)) .filter(|variant_constructor| variant_constructor == constructor) - .map(|_| patterns_for_variant(subpatterns, wild_patterns)) + .map(|_| patterns_for_variant(cx, subpatterns, wild_patterns, is_non_exhaustive)) } PatKind::Leaf { ref subpatterns } => { - Some(patterns_for_variant(subpatterns, wild_patterns)) + Some(patterns_for_variant(cx, subpatterns, wild_patterns, false)) } PatKind::Deref { ref subpattern } => { diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs new file mode 100644 index 0000000000000..0096e2963007a --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs @@ -0,0 +1,22 @@ +// aux-build:uninhabited.rs +#![deny(unreachable_patterns)] +#![feature(never_type)] +#![feature(non_exhaustive)] + +extern crate uninhabited; + +use uninhabited::PartiallyInhabitedVariants; + +// This test checks a redundant/useless pattern of a non-exhaustive enum/variant is still +// warned against. + +pub fn foo(x: PartiallyInhabitedVariants) { + match x { + PartiallyInhabitedVariants::Struct { .. } => {}, + PartiallyInhabitedVariants::Struct { .. } => {}, + //~^ ERROR unreachable pattern + _ => {}, + } +} + +fn main() { } diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr new file mode 100644 index 0000000000000..d46b1fd4c4202 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr @@ -0,0 +1,14 @@ +error: unreachable pattern + --> $DIR/issue-65157-repeated-match-arm.rs:16:9 + | +LL | PartiallyInhabitedVariants::Struct { .. } => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/issue-65157-repeated-match-arm.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 2e64bb2d37d5f15113e0a7199cd684504c6b8de7 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Sep 2019 17:18:08 +0200 Subject: [PATCH 06/32] syntax: reject `trait Foo: Bar = Baz;`. Add test for rejecting `trait A: B1 = B2;`. Also test rejection of `trait A: = B;`. --- src/libsyntax/parse/parser/item.rs | 28 +++++++++++++------ .../trait-alias/trait-alias-syntax-fail.rs | 3 ++ .../trait-alias-syntax-fail.stderr | 22 +++++++++++---- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 73bd80e2a21f7..01dc0c21d4d4e 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -211,7 +211,7 @@ impl<'a> Parser<'a> { { // UNSAFE TRAIT ITEM self.bump(); // `unsafe` - let info = self.parse_item_trait(Unsafety::Unsafe)?; + let info = self.parse_item_trait(lo, Unsafety::Unsafe)?; return self.mk_item_with_info(attrs, lo, vis, info); } @@ -289,7 +289,7 @@ impl<'a> Parser<'a> { && self.is_keyword_ahead(1, &[kw::Trait])) { // TRAIT ITEM - let info = self.parse_item_trait(Unsafety::Normal)?; + let info = self.parse_item_trait(lo, Unsafety::Normal)?; return self.mk_item_with_info(attrs, lo, vis, info); } @@ -780,7 +780,7 @@ impl<'a> Parser<'a> { } /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`. - fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> { + fn parse_item_trait(&mut self, lo: Span, unsafety: Unsafety) -> PResult<'a, ItemInfo> { // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes @@ -793,29 +793,41 @@ impl<'a> Parser<'a> { let mut tps = self.parse_generics()?; // Parse optional colon and supertrait bounds. - let bounds = if self.eat(&token::Colon) { + let had_colon = self.eat(&token::Colon); + let span_at_colon = self.prev_span; + let bounds = if had_colon { self.parse_generic_bounds(Some(self.prev_span))? } else { Vec::new() }; + let span_before_eq = self.prev_span; if self.eat(&token::Eq) { // It's a trait alias. + if had_colon { + let span = span_at_colon.to(span_before_eq); + self.struct_span_err(span, "bounds are not allowed on trait aliases") + .emit(); + } + let bounds = self.parse_generic_bounds(None)?; tps.where_clause = self.parse_where_clause()?; self.expect(&token::Semi)?; + + let whole_span = lo.to(self.prev_span); if is_auto == IsAuto::Yes { let msg = "trait aliases cannot be `auto`"; - self.struct_span_err(self.prev_span, msg) - .span_label(self.prev_span, msg) + self.struct_span_err(whole_span, msg) + .span_label(whole_span, msg) .emit(); } if unsafety != Unsafety::Normal { let msg = "trait aliases cannot be `unsafe`"; - self.struct_span_err(self.prev_span, msg) - .span_label(self.prev_span, msg) + self.struct_span_err(whole_span, msg) + .span_label(whole_span, msg) .emit(); } + Ok((ident, ItemKind::TraitAlias(tps, bounds), None)) } else { // It's a normal trait. diff --git a/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.rs b/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.rs index 5948d45b6987f..039bbce8c1ed0 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.rs +++ b/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.rs @@ -4,4 +4,7 @@ trait Foo {} auto trait A = Foo; //~ ERROR trait aliases cannot be `auto` unsafe trait B = Foo; //~ ERROR trait aliases cannot be `unsafe` +trait C: Ord = Eq; //~ ERROR bounds are not allowed on trait aliases +trait D: = Eq; //~ ERROR bounds are not allowed on trait aliases + fn main() {} diff --git a/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.stderr b/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.stderr index f456a2d778c25..18c22133bc780 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.stderr +++ b/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.stderr @@ -1,14 +1,26 @@ error: trait aliases cannot be `auto` - --> $DIR/trait-alias-syntax-fail.rs:4:19 + --> $DIR/trait-alias-syntax-fail.rs:4:1 | LL | auto trait A = Foo; - | ^ trait aliases cannot be `auto` + | ^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `auto` error: trait aliases cannot be `unsafe` - --> $DIR/trait-alias-syntax-fail.rs:5:21 + --> $DIR/trait-alias-syntax-fail.rs:5:1 | LL | unsafe trait B = Foo; - | ^ trait aliases cannot be `unsafe` + | ^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` -error: aborting due to 2 previous errors +error: bounds are not allowed on trait aliases + --> $DIR/trait-alias-syntax-fail.rs:7:8 + | +LL | trait C: Ord = Eq; + | ^^^^^ + +error: bounds are not allowed on trait aliases + --> $DIR/trait-alias-syntax-fail.rs:8:8 + | +LL | trait D: = Eq; + | ^ + +error: aborting due to 4 previous errors From 2d182b82ce5ecfe8090ba3d4e78f1cd72c072ef1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Sep 2019 17:40:50 +0200 Subject: [PATCH 07/32] pre-expansion gate trait_alias. --- src/libsyntax/feature_gate/check.rs | 10 +--------- src/libsyntax/parse/parser/item.rs | 2 ++ src/libsyntax/sess.rs | 2 ++ src/test/ui/feature-gates/feature-gate-trait-alias.rs | 9 +++++++++ .../ui/feature-gates/feature-gate-trait-alias.stderr | 11 ++++++++++- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 172511f0f099b..97172691a1114 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -423,15 +423,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "auto traits are experimental and possibly buggy"); } - ast::ItemKind::TraitAlias(..) => { - gate_feature_post!( - &self, - trait_alias, - i.span, - "trait aliases are experimental" - ); - } - ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { let msg = "`macro` is experimental"; gate_feature_post!(&self, decl_macro, i.span, msg); @@ -867,6 +858,7 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(yields, generators, "yield syntax is experimental"); gate_all!(or_patterns, "or-patterns syntax is experimental"); gate_all!(const_extern_fn, "`const extern fn` definitions are unstable"); + gate_all!(trait_alias, "trait aliases are experimental"); visit::walk_crate(&mut visitor, krate); } diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 01dc0c21d4d4e..c5498236da13f 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -828,6 +828,8 @@ impl<'a> Parser<'a> { .emit(); } + self.sess.gated_spans.trait_alias.borrow_mut().push(whole_span); + Ok((ident, ItemKind::TraitAlias(tps, bounds), None)) } else { // It's a normal trait. diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index e49d3954f8e69..b48b2b494c891 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -30,6 +30,8 @@ crate struct GatedSpans { crate or_patterns: Lock>, /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`. crate const_extern_fn: Lock>, + /// Spans collected for gating `trait_alias`, e.g. `trait Foo = Ord + Eq;`. + pub trait_alias: Lock>, } /// Info about a parsing session. diff --git a/src/test/ui/feature-gates/feature-gate-trait-alias.rs b/src/test/ui/feature-gates/feature-gate-trait-alias.rs index 819085adddade..4b94d7d6d3bda 100644 --- a/src/test/ui/feature-gates/feature-gate-trait-alias.rs +++ b/src/test/ui/feature-gates/feature-gate-trait-alias.rs @@ -1,4 +1,13 @@ trait Foo = Default; //~^ ERROR trait aliases are experimental +macro_rules! accept_item { + ($i:item) => {} +} + +accept_item! { + trait Foo = Ord + Eq; + //~^ ERROR trait aliases are experimental +} + fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-trait-alias.stderr b/src/test/ui/feature-gates/feature-gate-trait-alias.stderr index 9250e27d15807..b1bf6ad349129 100644 --- a/src/test/ui/feature-gates/feature-gate-trait-alias.stderr +++ b/src/test/ui/feature-gates/feature-gate-trait-alias.stderr @@ -7,6 +7,15 @@ LL | trait Foo = Default; = note: for more information, see https://github.com/rust-lang/rust/issues/41517 = help: add `#![feature(trait_alias)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: trait aliases are experimental + --> $DIR/feature-gate-trait-alias.rs:9:5 + | +LL | trait Foo = Ord + Eq; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/41517 + = help: add `#![feature(trait_alias)]` to the crate attributes to enable + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. From c17a1fd7d0ef0f1f546445d0c8bdb11be55e4be7 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Sep 2019 18:05:26 +0200 Subject: [PATCH 08/32] pre-expansion gate associated_type_bounds --- src/libsyntax/feature_gate/check.rs | 16 ++-------------- src/libsyntax/parse/parser/path.rs | 12 ++++++++++-- src/libsyntax/sess.rs | 2 ++ .../feature-gate-associated_type_bounds.rs | 4 ++++ .../feature-gate-associated_type_bounds.stderr | 11 ++++++++++- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 97172691a1114..43a3f45bb06a9 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -3,10 +3,7 @@ use super::accepted::ACCEPTED_FEATURES; use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}; -use crate::ast::{ - self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, - PatKind, RangeEnd, VariantData, -}; +use crate::ast::{self, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData}; use crate::attr::{self, check_builtin_attribute}; use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; @@ -584,16 +581,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_generic_param(self, param) } - fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { - match constraint.kind { - AssocTyConstraintKind::Bound { .. } => - gate_feature_post!(&self, associated_type_bounds, constraint.span, - "associated type bounds are unstable"), - _ => {} - } - visit::walk_assoc_ty_constraint(self, constraint) - } - fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) { match ti.kind { ast::TraitItemKind::Method(ref sig, ref block) => { @@ -859,6 +846,7 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(or_patterns, "or-patterns syntax is experimental"); gate_all!(const_extern_fn, "`const extern fn` definitions are unstable"); gate_all!(trait_alias, "trait aliases are experimental"); + gate_all!(associated_type_bounds, "associated type bounds are unstable"); visit::walk_crate(&mut visitor, krate); } diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs index 639d61a2b5cd4..77709a2295339 100644 --- a/src/libsyntax/parse/parser/path.rs +++ b/src/libsyntax/parse/parser/path.rs @@ -404,8 +404,9 @@ impl<'a> Parser<'a> { // Parse lifetime argument. args.push(GenericArg::Lifetime(self.expect_lifetime())); misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints); - } else if self.check_ident() && self.look_ahead(1, - |t| t == &token::Eq || t == &token::Colon) { + } else if self.check_ident() + && self.look_ahead(1, |t| t == &token::Eq || t == &token::Colon) + { // Parse associated type constraint. let lo = self.token.span; let ident = self.parse_ident()?; @@ -420,7 +421,14 @@ impl<'a> Parser<'a> { } else { unreachable!(); }; + let span = lo.to(self.prev_span); + + // Gate associated type bounds, e.g., `Iterator`. + if let AssocTyConstraintKind::Bound { .. } = kind { + self.sess.gated_spans.associated_type_bounds.borrow_mut().push(span); + } + constraints.push(AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index b48b2b494c891..13f89c3720bb5 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -32,6 +32,8 @@ crate struct GatedSpans { crate const_extern_fn: Lock>, /// Spans collected for gating `trait_alias`, e.g. `trait Foo = Ord + Eq;`. pub trait_alias: Lock>, + /// Spans collected for gating `associated_type_bounds`, e.g. `Iterator`. + pub associated_type_bounds: Lock>, } /// Info about a parsing session. diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs index 0faa9090f4ebc..00737d8428b3d 100644 --- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs +++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs @@ -70,3 +70,7 @@ fn main() { // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed. // let _: &dyn Tr1 = &S1; } + +macro_rules! accept_path { ($p:path) => {} } +accept_path!(Iterator); +//~^ ERROR associated type bounds are unstable diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr index 84af2a0163ae4..a7ab7614d7b78 100644 --- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr +++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr @@ -115,6 +115,15 @@ LL | let _: impl Tr1 = S1; = note: for more information, see https://github.com/rust-lang/rust/issues/52662 = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:75:23 + | +LL | accept_path!(Iterator); + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable + error[E0562]: `impl Trait` not allowed outside of function and inherent method return types --> $DIR/feature-gate-associated_type_bounds.rs:54:14 | @@ -139,7 +148,7 @@ LL | let _: impl Tr1 = S1; | = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable -error: aborting due to 16 previous errors +error: aborting due to 17 previous errors Some errors have detailed explanations: E0562, E0658. For more information about an error, try `rustc --explain E0562`. From 04c661ba021730bc13d33c6d55cb9aad05026f36 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Sep 2019 18:22:17 +0200 Subject: [PATCH 09/32] pre-expansion gate crate_visibility_modifier --- src/libsyntax/feature_gate/check.rs | 9 +-------- src/libsyntax/parse/parser.rs | 1 + src/libsyntax/sess.rs | 2 ++ .../feature-gate-crate_visibility_modifier.rs | 3 +++ .../feature-gate-crate_visibility_modifier.stderr | 11 ++++++++++- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 43a3f45bb06a9..58610d8db7e8d 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -652,14 +652,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } visit::walk_impl_item(self, ii) } - - fn visit_vis(&mut self, vis: &'a ast::Visibility) { - if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node { - gate_feature_post!(&self, crate_visibility_modifier, vis.span, - "`crate` visibility modifier is experimental"); - } - visit::walk_vis(self, vis) - } } pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], @@ -847,6 +839,7 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(const_extern_fn, "`const extern fn` definitions are unstable"); gate_all!(trait_alias, "trait aliases are experimental"); gate_all!(associated_type_bounds, "associated type bounds are unstable"); + gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental"); visit::walk_crate(&mut visitor, krate); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2ce0046ca276c..f25224d1e36f5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1122,6 +1122,7 @@ impl<'a> Parser<'a> { self.expected_tokens.push(TokenType::Keyword(kw::Crate)); if self.is_crate_vis() { self.bump(); // `crate` + self.sess.gated_spans.crate_visibility_modifier.borrow_mut().push(self.prev_span); return Ok(respan(self.prev_span, VisibilityKind::Crate(CrateSugar::JustCrate))); } diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index 13f89c3720bb5..58a2f89aca969 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -34,6 +34,8 @@ crate struct GatedSpans { pub trait_alias: Lock>, /// Spans collected for gating `associated_type_bounds`, e.g. `Iterator`. pub associated_type_bounds: Lock>, + /// Spans collected for gating `crate_visibility_modifier`, e.g. `crate fn`. + pub crate_visibility_modifier: Lock>, } /// Info about a parsing session. diff --git a/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.rs b/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.rs index 0e3f6b168be6b..7517fb280ea78 100644 --- a/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.rs +++ b/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.rs @@ -5,4 +5,7 @@ crate struct Bender { //~ ERROR `crate` visibility modifier is experimental water: bool, } +macro_rules! accept_vis { ($v:vis) => {} } +accept_vis!(crate); //~ ERROR `crate` visibility modifier is experimental + fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.stderr b/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.stderr index 1e061eced3660..b317872cea817 100644 --- a/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.stderr +++ b/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.stderr @@ -7,6 +7,15 @@ LL | crate struct Bender { = note: for more information, see https://github.com/rust-lang/rust/issues/53120 = help: add `#![feature(crate_visibility_modifier)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: `crate` visibility modifier is experimental + --> $DIR/feature-gate-crate_visibility_modifier.rs:9:13 + | +LL | accept_vis!(crate); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53120 + = help: add `#![feature(crate_visibility_modifier)]` to the crate attributes to enable + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. From 49cbfa1a6f6469ddbc0e88161e52104cc87aea9b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Sep 2019 18:58:17 +0200 Subject: [PATCH 10/32] pre-expansion gate const_generics --- src/libsyntax/feature_gate/check.rs | 13 ++----------- src/libsyntax/parse/parser/generics.rs | 4 ++++ src/libsyntax/sess.rs | 2 ++ .../const-param-in-trait-ungated.stderr | 4 ++-- ...-type-depends-on-type-param-ungated.stderr | 4 ++-- .../const-generics/issues/issue-60263.stderr | 4 ++-- .../feature-gate-const_generics-ptr.stderr | 8 ++++---- .../feature-gate-const_generics.rs | 5 +++++ .../feature-gate-const_generics.stderr | 19 ++++++++++++++----- 9 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 58610d8db7e8d..282b5ae219365 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -3,7 +3,7 @@ use super::accepted::ACCEPTED_FEATURES; use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}; -use crate::ast::{self, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData}; +use crate::ast::{self, NodeId, PatKind, RangeEnd, VariantData}; use crate::attr::{self, check_builtin_attribute}; use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; @@ -571,16 +571,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_fn(self, fn_kind, fn_decl, span) } - fn visit_generic_param(&mut self, param: &'a GenericParam) { - match param.kind { - GenericParamKind::Const { .. } => - gate_feature_post!(&self, const_generics, param.ident.span, - "const generics are unstable"), - _ => {} - } - visit::walk_generic_param(self, param) - } - fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) { match ti.kind { ast::TraitItemKind::Method(ref sig, ref block) => { @@ -840,6 +830,7 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(trait_alias, "trait aliases are experimental"); gate_all!(associated_type_bounds, "associated type bounds are unstable"); gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental"); + gate_all!(const_generics, "const generics are unstable"); visit::walk_crate(&mut visitor, krate); } diff --git a/src/libsyntax/parse/parser/generics.rs b/src/libsyntax/parse/parser/generics.rs index bfcb0042a75a3..51caae69c86a4 100644 --- a/src/libsyntax/parse/parser/generics.rs +++ b/src/libsyntax/parse/parser/generics.rs @@ -55,11 +55,15 @@ impl<'a> Parser<'a> { } fn parse_const_param(&mut self, preceding_attrs: Vec) -> PResult<'a, GenericParam> { + let lo = self.token.span; + self.expect_keyword(kw::Const)?; let ident = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; + self.sess.gated_spans.const_generics.borrow_mut().push(lo.to(self.prev_span)); + Ok(GenericParam { ident, id: ast::DUMMY_NODE_ID, diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index 58a2f89aca969..3d2051b4c78eb 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -36,6 +36,8 @@ crate struct GatedSpans { pub associated_type_bounds: Lock>, /// Spans collected for gating `crate_visibility_modifier`, e.g. `crate fn`. pub crate_visibility_modifier: Lock>, + /// Spans collected for gating `const_generics`, e.g. `const N: usize`. + pub const_generics: Lock>, } /// Info about a parsing session. diff --git a/src/test/ui/const-generics/const-param-in-trait-ungated.stderr b/src/test/ui/const-generics/const-param-in-trait-ungated.stderr index cfb1f8b581c85..330c93e83b5e7 100644 --- a/src/test/ui/const-generics/const-param-in-trait-ungated.stderr +++ b/src/test/ui/const-generics/const-param-in-trait-ungated.stderr @@ -1,8 +1,8 @@ error[E0658]: const generics are unstable - --> $DIR/const-param-in-trait-ungated.rs:1:19 + --> $DIR/const-param-in-trait-ungated.rs:1:13 | LL | trait Trait {} - | ^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/44580 = help: add `#![feature(const_generics)]` to the crate attributes to enable diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr index c659074a091c8..969f35bdaa306 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr @@ -5,10 +5,10 @@ LL | struct B(PhantomData<[T; N]>); | ^ const parameter depends on type parameter error[E0658]: const generics are unstable - --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19 + --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:13 | LL | struct B(PhantomData<[T; N]>); - | ^ + | ^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/44580 = help: add `#![feature(const_generics)]` to the crate attributes to enable diff --git a/src/test/ui/const-generics/issues/issue-60263.stderr b/src/test/ui/const-generics/issues/issue-60263.stderr index fe7b6fdb1904d..5223c8c5137ae 100644 --- a/src/test/ui/const-generics/issues/issue-60263.stderr +++ b/src/test/ui/const-generics/issues/issue-60263.stderr @@ -1,8 +1,8 @@ error[E0658]: const generics are unstable - --> $DIR/issue-60263.rs:1:16 + --> $DIR/issue-60263.rs:1:10 | LL | struct B; - | ^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/44580 = help: add `#![feature(const_generics)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr index 935f84b9163d3..790bc33e2683e 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr @@ -1,17 +1,17 @@ error[E0658]: const generics are unstable - --> $DIR/feature-gate-const_generics-ptr.rs:1:22 + --> $DIR/feature-gate-const_generics-ptr.rs:1:16 | LL | struct ConstFn; - | ^ + | ^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/44580 = help: add `#![feature(const_generics)]` to the crate attributes to enable error[E0658]: const generics are unstable - --> $DIR/feature-gate-const_generics-ptr.rs:5:23 + --> $DIR/feature-gate-const_generics-ptr.rs:5:17 | LL | struct ConstPtr; - | ^ + | ^^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/44580 = help: add `#![feature(const_generics)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-const_generics.rs b/src/test/ui/feature-gates/feature-gate-const_generics.rs index fe1ded1c4bbc4..0adc9902a6937 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics.rs +++ b/src/test/ui/feature-gates/feature-gate-const_generics.rs @@ -2,4 +2,9 @@ fn foo() {} //~ ERROR const generics are unstable struct Foo([(); X]); //~ ERROR const generics are unstable +macro_rules! accept_item { ($i:item) => {} } +accept_item! { + impl A {} //~ ERROR const generics are unstable +} + fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_generics.stderr b/src/test/ui/feature-gates/feature-gate-const_generics.stderr index 468e9c31d37e2..f0154ed289f14 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_generics.stderr @@ -1,21 +1,30 @@ error[E0658]: const generics are unstable - --> $DIR/feature-gate-const_generics.rs:1:14 + --> $DIR/feature-gate-const_generics.rs:1:8 | LL | fn foo() {} - | ^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/44580 = help: add `#![feature(const_generics)]` to the crate attributes to enable error[E0658]: const generics are unstable - --> $DIR/feature-gate-const_generics.rs:3:18 + --> $DIR/feature-gate-const_generics.rs:3:12 | LL | struct Foo([(); X]); - | ^ + | ^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/44580 = help: add `#![feature(const_generics)]` to the crate attributes to enable -error: aborting due to 2 previous errors +error[E0658]: const generics are unstable + --> $DIR/feature-gate-const_generics.rs:7:10 + | +LL | impl A {} + | ^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 + = help: add `#![feature(const_generics)]` to the crate attributes to enable + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. From 1f470ceac2202ecffe8a15acc1139edb9ad4a03b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Sep 2019 19:18:41 +0200 Subject: [PATCH 11/32] pre-expansion gate decl_macro --- src/libstd/lib.rs | 3 ++- src/libsyntax/feature_gate/check.rs | 6 +----- src/libsyntax/parse/parser/item.rs | 5 +++++ src/libsyntax/sess.rs | 2 ++ src/test/ui/feature-gates/feature-gate-decl_macro.rs | 4 ++++ .../ui/feature-gates/feature-gate-decl_macro.stderr | 11 ++++++++++- 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 93d3e4ea3df22..8fbb449d88c01 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -220,7 +220,7 @@ #![cfg_attr(test, feature(print_internals, set_stdio, update_panic_count))] #![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"), - feature(slice_index_methods, decl_macro, coerce_unsized, + feature(slice_index_methods, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))] #![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array, maybe_uninit_extra))] @@ -251,6 +251,7 @@ #![feature(container_error_extra)] #![feature(core_intrinsics)] #![feature(custom_test_frameworks)] +#![feature(decl_macro)] #![feature(doc_alias)] #![feature(doc_cfg)] #![feature(doc_keyword)] diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 282b5ae219365..9882db4e3f308 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -420,11 +420,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "auto traits are experimental and possibly buggy"); } - ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { - let msg = "`macro` is experimental"; - gate_feature_post!(&self, decl_macro, i.span, msg); - } - ast::ItemKind::OpaqueTy(..) => { gate_feature_post!( &self, @@ -831,6 +826,7 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(associated_type_bounds, "associated type bounds are unstable"); gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental"); gate_all!(const_generics, "const generics are unstable"); + gate_all!(decl_macro, "`macro` is experimental"); visit::walk_crate(&mut visitor, krate); } diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index c5498236da13f..95bddb5afdd08 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -1706,6 +1706,11 @@ impl<'a> Parser<'a> { }; let span = lo.to(self.prev_span); + + if !def.legacy { + self.sess.gated_spans.decl_macro.borrow_mut().push(span); + } + Ok(Some(self.mk_item(span, ident, ItemKind::MacroDef(def), vis.clone(), attrs.to_vec()))) } diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index 3d2051b4c78eb..30aeff752ec40 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -38,6 +38,8 @@ crate struct GatedSpans { pub crate_visibility_modifier: Lock>, /// Spans collected for gating `const_generics`, e.g. `const N: usize`. pub const_generics: Lock>, + /// Spans collected for gating `decl_macro`, e.g. `macro m() {}`. + pub decl_macro: Lock>, } /// Info about a parsing session. diff --git a/src/test/ui/feature-gates/feature-gate-decl_macro.rs b/src/test/ui/feature-gates/feature-gate-decl_macro.rs index d002c5dbbd2db..b208a047481a4 100644 --- a/src/test/ui/feature-gates/feature-gate-decl_macro.rs +++ b/src/test/ui/feature-gates/feature-gate-decl_macro.rs @@ -2,4 +2,8 @@ macro m() {} //~ ERROR `macro` is experimental +macro_rules! accept_item { ($i:item) => {} } +accept_item! { + macro m() {} //~ ERROR `macro` is experimental +} fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-decl_macro.stderr b/src/test/ui/feature-gates/feature-gate-decl_macro.stderr index 905a1b1531044..c6690ebd4d917 100644 --- a/src/test/ui/feature-gates/feature-gate-decl_macro.stderr +++ b/src/test/ui/feature-gates/feature-gate-decl_macro.stderr @@ -7,6 +7,15 @@ LL | macro m() {} = note: for more information, see https://github.com/rust-lang/rust/issues/39412 = help: add `#![feature(decl_macro)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: `macro` is experimental + --> $DIR/feature-gate-decl_macro.rs:7:5 + | +LL | macro m() {} + | ^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/39412 + = help: add `#![feature(decl_macro)]` to the crate attributes to enable + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. From 2aff6b36d7ed5c25700669a92b4a43200ee0fe6b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Sep 2019 19:49:54 +0200 Subject: [PATCH 12/32] pre-expansion gate box_patterns --- src/libsyntax/feature_gate/check.rs | 16 ++-------------- src/libsyntax/parse/parser/pat.rs | 4 +++- src/libsyntax/sess.rs | 2 ++ .../feature-gates/feature-gate-box_patterns.rs | 3 +++ .../feature-gate-box_patterns.stderr | 11 ++++++++++- .../ui/or-patterns/or-patterns-syntactic-pass.rs | 1 + src/test/ui/pattern/rest-pat-syntactic.rs | 2 ++ 7 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 9882db4e3f308..7c4668122a4c2 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -510,10 +510,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_expr(self, e) } - fn visit_arm(&mut self, arm: &'a ast::Arm) { - visit::walk_arm(self, arm) - } - fn visit_pat(&mut self, pattern: &'a ast::Pat) { match &pattern.kind { PatKind::Slice(pats) => { @@ -533,11 +529,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } } - PatKind::Box(..) => { - gate_feature_post!(&self, box_patterns, - pattern.span, - "box pattern syntax is experimental"); - } PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => { gate_feature_post!(&self, exclusive_range_pattern, pattern.span, "exclusive range pattern syntax is experimental"); @@ -547,11 +538,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_pat(self, pattern) } - fn visit_fn(&mut self, - fn_kind: FnKind<'a>, - fn_decl: &'a ast::FnDecl, - span: Span, - _node_id: NodeId) { + fn visit_fn(&mut self, fn_kind: FnKind<'a>, fn_decl: &'a ast::FnDecl, span: Span, _: NodeId) { if let Some(header) = fn_kind.header() { // Stability of const fn methods are covered in // `visit_trait_item` and `visit_impl_item` below; this is @@ -827,6 +814,7 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental"); gate_all!(const_generics, "const generics are unstable"); gate_all!(decl_macro, "`macro` is experimental"); + gate_all!(box_patterns, "box pattern syntax is experimental"); visit::walk_crate(&mut visitor, krate); } diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index af795e51792ff..5374671d4b895 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -324,7 +324,9 @@ impl<'a> Parser<'a> { self.parse_pat_ident(BindingMode::ByRef(mutbl))? } else if self.eat_keyword(kw::Box) { // Parse `box pat` - PatKind::Box(self.parse_pat_with_range_pat(false, None)?) + let pat = self.parse_pat_with_range_pat(false, None)?; + self.sess.gated_spans.box_patterns.borrow_mut().push(lo.to(self.prev_span)); + PatKind::Box(pat) } else if self.can_be_ident_pat() { // Parse `ident @ pat` // This can give false positives and parse nullary enums, diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index 30aeff752ec40..c8e60be1db948 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -40,6 +40,8 @@ crate struct GatedSpans { pub const_generics: Lock>, /// Spans collected for gating `decl_macro`, e.g. `macro m() {}`. pub decl_macro: Lock>, + /// Spans collected for gating `box_patterns`, e.g. `box 0`. + pub box_patterns: Lock>, } /// Info about a parsing session. diff --git a/src/test/ui/feature-gates/feature-gate-box_patterns.rs b/src/test/ui/feature-gates/feature-gate-box_patterns.rs index 8bec16a974e80..c5b926d5af28c 100644 --- a/src/test/ui/feature-gates/feature-gate-box_patterns.rs +++ b/src/test/ui/feature-gates/feature-gate-box_patterns.rs @@ -2,3 +2,6 @@ fn main() { let box x = Box::new('c'); //~ ERROR box pattern syntax is experimental println!("x: {}", x); } + +macro_rules! accept_pat { ($p:pat) => {} } +accept_pat!(box 0); //~ ERROR box pattern syntax is experimental diff --git a/src/test/ui/feature-gates/feature-gate-box_patterns.stderr b/src/test/ui/feature-gates/feature-gate-box_patterns.stderr index d2dafe93a862f..1e47bd41e8870 100644 --- a/src/test/ui/feature-gates/feature-gate-box_patterns.stderr +++ b/src/test/ui/feature-gates/feature-gate-box_patterns.stderr @@ -7,6 +7,15 @@ LL | let box x = Box::new('c'); = note: for more information, see https://github.com/rust-lang/rust/issues/29641 = help: add `#![feature(box_patterns)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: box pattern syntax is experimental + --> $DIR/feature-gate-box_patterns.rs:7:13 + | +LL | accept_pat!(box 0); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29641 + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs index 5fe72caf9c1ff..9667711242ce6 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs @@ -4,6 +4,7 @@ // check-pass #![feature(or_patterns)] +#![feature(box_patterns)] fn main() {} diff --git a/src/test/ui/pattern/rest-pat-syntactic.rs b/src/test/ui/pattern/rest-pat-syntactic.rs index 9656a0b5de9ce..45b31f6125374 100644 --- a/src/test/ui/pattern/rest-pat-syntactic.rs +++ b/src/test/ui/pattern/rest-pat-syntactic.rs @@ -3,6 +3,8 @@ // check-pass +#![feature(box_patterns)] + fn main() {} macro_rules! accept_pat { From 665a876e307933c6480a6c55a3e38e88937aff2c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Sep 2019 20:11:00 +0200 Subject: [PATCH 13/32] pre-expansion gate exclusive_range_pattern --- src/libsyntax/feature_gate/check.rs | 8 ++------ src/libsyntax/parse/parser/pat.rs | 9 +++++++-- src/libsyntax/sess.rs | 2 ++ .../feature-gate-exclusive-range-pattern.rs | 6 +++++- .../feature-gate-exclusive-range-pattern.stderr | 15 ++++++++++++--- src/test/ui/parser/pat-tuple-4.rs | 1 - src/test/ui/parser/pat-tuple-4.stderr | 16 +++------------- src/test/ui/parser/pat-tuple-5.stderr | 4 ++-- 8 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 7c4668122a4c2..0b4289b139fc1 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -3,9 +3,8 @@ use super::accepted::ACCEPTED_FEATURES; use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}; -use crate::ast::{self, NodeId, PatKind, RangeEnd, VariantData}; +use crate::ast::{self, NodeId, PatKind, VariantData}; use crate::attr::{self, check_builtin_attribute}; -use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; use crate::visit::{self, FnKind, Visitor}; use crate::parse::token; @@ -529,10 +528,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } } - PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => { - gate_feature_post!(&self, exclusive_range_pattern, pattern.span, - "exclusive range pattern syntax is experimental"); - } _ => {} } visit::walk_pat(self, pattern) @@ -815,6 +810,7 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(const_generics, "const generics are unstable"); gate_all!(decl_macro, "`macro` is experimental"); gate_all!(box_patterns, "box pattern syntax is experimental"); + gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental"); visit::walk_crate(&mut visitor, krate); } diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 5374671d4b895..969d5dd837480 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -611,6 +611,11 @@ impl<'a> Parser<'a> { Ok(PatKind::Mac(mac)) } + fn excluded_range_end(&self, span: Span) -> RangeEnd { + self.sess.gated_spans.exclusive_range_pattern.borrow_mut().push(span); + RangeEnd::Excluded + } + /// Parse a range pattern `$path $form $end?` where `$form = ".." | "..." | "..=" ;`. /// The `$path` has already been parsed and the next token is the `$form`. fn parse_pat_range_starting_with_path( @@ -620,7 +625,7 @@ impl<'a> Parser<'a> { path: Path ) -> PResult<'a, PatKind> { let (end_kind, form) = match self.token.kind { - token::DotDot => (RangeEnd::Excluded, ".."), + token::DotDot => (self.excluded_range_end(self.token.span), ".."), token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."), token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="), _ => panic!("can only parse `..`/`...`/`..=` for ranges (checked above)"), @@ -643,7 +648,7 @@ impl<'a> Parser<'a> { } else if self.eat(&token::DotDotEq) { (RangeEnd::Included(RangeSyntax::DotDotEq), "..=") } else if self.eat(&token::DotDot) { - (RangeEnd::Excluded, "..") + (self.excluded_range_end(op_span), "..") } else { panic!("impossible case: we already matched on a range-operator token") }; diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index c8e60be1db948..09331924c6021 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -42,6 +42,8 @@ crate struct GatedSpans { pub decl_macro: Lock>, /// Spans collected for gating `box_patterns`, e.g. `box 0`. pub box_patterns: Lock>, + /// Spans collected for gating `exclusive_range_pattern`, e.g. `0..2`. + pub exclusive_range_pattern: Lock>, } /// Info about a parsing session. diff --git a/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.rs b/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.rs index ded08b93fe81c..594ec73fe26f7 100644 --- a/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.rs +++ b/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.rs @@ -1,6 +1,10 @@ -pub fn main() { +#[cfg(FALSE)] +fn foo() { match 22 { 0 .. 3 => {} //~ ERROR exclusive range pattern syntax is experimental + PATH .. 3 => {} //~ ERROR exclusive range pattern syntax is experimental _ => {} } } + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr b/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr index ee20408d1781f..075fdbed90d6c 100644 --- a/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr +++ b/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr @@ -1,12 +1,21 @@ error[E0658]: exclusive range pattern syntax is experimental - --> $DIR/feature-gate-exclusive-range-pattern.rs:3:9 + --> $DIR/feature-gate-exclusive-range-pattern.rs:4:11 | LL | 0 .. 3 => {} - | ^^^^^^ + | ^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/37854 = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/feature-gate-exclusive-range-pattern.rs:5:14 + | +LL | PATH .. 3 => {} + | ^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/37854 + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/parser/pat-tuple-4.rs b/src/test/ui/parser/pat-tuple-4.rs index 2f03160430a22..6b8c146949aec 100644 --- a/src/test/ui/parser/pat-tuple-4.rs +++ b/src/test/ui/parser/pat-tuple-4.rs @@ -4,7 +4,6 @@ fn main() { match 0 { (.. PAT) => {} //~^ ERROR `..X` range patterns are not supported - //~| ERROR exclusive range pattern syntax is experimental } } diff --git a/src/test/ui/parser/pat-tuple-4.stderr b/src/test/ui/parser/pat-tuple-4.stderr index af3ecce184649..1962dc4ff20a8 100644 --- a/src/test/ui/parser/pat-tuple-4.stderr +++ b/src/test/ui/parser/pat-tuple-4.stderr @@ -4,17 +4,8 @@ error: `..X` range patterns are not supported LL | (.. PAT) => {} | ^^^^^^ help: try using the minimum value for the type: `MIN..PAT` -error[E0658]: exclusive range pattern syntax is experimental - --> $DIR/pat-tuple-4.rs:5:10 - | -LL | (.. PAT) => {} - | ^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/37854 - = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable - error[E0308]: mismatched types - --> $DIR/pat-tuple-4.rs:11:30 + --> $DIR/pat-tuple-4.rs:10:30 | LL | const RECOVERY_WITNESS: () = 0; | ^ expected (), found integer @@ -22,7 +13,6 @@ LL | const RECOVERY_WITNESS: () = 0; = note: expected type `()` found type `{integer}` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0308, E0658. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/pat-tuple-5.stderr b/src/test/ui/parser/pat-tuple-5.stderr index 09ebdc29a2161..17155b4dd4954 100644 --- a/src/test/ui/parser/pat-tuple-5.stderr +++ b/src/test/ui/parser/pat-tuple-5.stderr @@ -5,10 +5,10 @@ LL | (PAT ..) => {} | ^^^^^^ help: try using the maximum value for the type: `PAT..MAX` error[E0658]: exclusive range pattern syntax is experimental - --> $DIR/pat-tuple-5.rs:5:10 + --> $DIR/pat-tuple-5.rs:5:14 | LL | (PAT ..) => {} - | ^^^^^^ + | ^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/37854 = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable From 1935ba658c576f14397c2c7a26a6642cf08f26a6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Sep 2019 23:09:17 +0200 Subject: [PATCH 14/32] pre-expansion gate try_blocks --- src/libsyntax/feature_gate/check.rs | 4 +--- src/libsyntax/parse/parser/expr.rs | 4 +++- src/libsyntax/sess.rs | 2 ++ src/test/ui/feature-gates/feature-gate-try_blocks.rs | 7 +++++-- src/test/ui/feature-gates/feature-gate-try_blocks.stderr | 4 ++-- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 0b4289b139fc1..31fae7863fb63 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -495,9 +495,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "type ascription is experimental"); } } - ast::ExprKind::TryBlock(_) => { - gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); - } ast::ExprKind::Block(_, opt_label) => { if let Some(label) = opt_label { gate_feature_post!(&self, label_break_value, label.ident.span, @@ -811,6 +808,7 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(decl_macro, "`macro` is experimental"); gate_all!(box_patterns, "box pattern syntax is experimental"); gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental"); + gate_all!(try_blocks, "`try` blocks are unstable"); visit::walk_crate(&mut visitor, krate); } diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 67a530ec6831b..2e34422b91883 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1646,7 +1646,9 @@ impl<'a> Parser<'a> { error.emit(); Err(error) } else { - Ok(self.mk_expr(span_lo.to(body.span), ExprKind::TryBlock(body), attrs)) + let span = span_lo.to(body.span); + self.sess.gated_spans.try_blocks.borrow_mut().push(span); + Ok(self.mk_expr(span, ExprKind::TryBlock(body), attrs)) } } diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index 09331924c6021..3582d897272bb 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -44,6 +44,8 @@ crate struct GatedSpans { pub box_patterns: Lock>, /// Spans collected for gating `exclusive_range_pattern`, e.g. `0..2`. pub exclusive_range_pattern: Lock>, + /// Spans collected for gating `try_blocks`, e.g. `try { a? + b? }`. + pub try_blocks: Lock>, } /// Info about a parsing session. diff --git a/src/test/ui/feature-gates/feature-gate-try_blocks.rs b/src/test/ui/feature-gates/feature-gate-try_blocks.rs index 06cadd82c0731..b451ba84a1565 100644 --- a/src/test/ui/feature-gates/feature-gate-try_blocks.rs +++ b/src/test/ui/feature-gates/feature-gate-try_blocks.rs @@ -1,9 +1,12 @@ // compile-flags: --edition 2018 -pub fn main() { - let try_result: Option<_> = try { //~ ERROR `try` expression is experimental +#[cfg(FALSE)] +fn foo() { + let try_result: Option<_> = try { //~ ERROR `try` blocks are unstable let x = 5; x }; assert_eq!(try_result, Some(5)); } + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-try_blocks.stderr b/src/test/ui/feature-gates/feature-gate-try_blocks.stderr index 565f3610a2e21..44a7d9b9043fd 100644 --- a/src/test/ui/feature-gates/feature-gate-try_blocks.stderr +++ b/src/test/ui/feature-gates/feature-gate-try_blocks.stderr @@ -1,5 +1,5 @@ -error[E0658]: `try` expression is experimental - --> $DIR/feature-gate-try_blocks.rs:4:33 +error[E0658]: `try` blocks are unstable + --> $DIR/feature-gate-try_blocks.rs:5:33 | LL | let try_result: Option<_> = try { | _________________________________^ From 66995a6a71e2f5e194797cb846ce5866c4305f93 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Sep 2019 23:39:15 +0200 Subject: [PATCH 15/32] dedup GAT gate checks --- src/libsyntax/feature_gate/check.rs | 37 ++++++++++++++++------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 31fae7863fb63..ab8781feef07d 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -287,6 +287,25 @@ impl<'a> PostExpansionVisitor<'a> { err.emit(); } } + + fn check_gat(&self, generics: &ast::Generics, span: Span) { + if !generics.params.is_empty() { + gate_feature_post!( + &self, + generic_associated_types, + span, + "generic associated types are unstable" + ); + } + if !generics.where_clause.predicates.is_empty() { + gate_feature_post!( + &self, + generic_associated_types, + span, + "where clauses on associated types are unstable" + ); + } + } } impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { @@ -566,14 +585,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, associated_type_defaults, ti.span, "associated type defaults are unstable"); } - if !ti.generics.params.is_empty() { - gate_feature_post!(&self, generic_associated_types, ti.span, - "generic associated types are unstable"); - } - if !ti.generics.where_clause.predicates.is_empty() { - gate_feature_post!(&self, generic_associated_types, ti.span, - "where clauses on associated types are unstable"); - } + self.check_gat(&ti.generics, ti.span); } _ => {} } @@ -603,14 +615,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } ast::ImplItemKind::TyAlias(_) => { - if !ii.generics.params.is_empty() { - gate_feature_post!(&self, generic_associated_types, ii.span, - "generic associated types are unstable"); - } - if !ii.generics.where_clause.predicates.is_empty() { - gate_feature_post!(&self, generic_associated_types, ii.span, - "where clauses on associated types are unstable"); - } + self.check_gat(&ii.generics, ii.span); } _ => {} } From 137ded8ab1edf5112c45e0b6854272ae2e9d3a6d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Sep 2019 23:54:05 +0200 Subject: [PATCH 16/32] pre-expansion gate label_break_value --- src/libsyntax/feature_gate/check.rs | 7 +------ src/libsyntax/parse/parser/expr.rs | 4 ++++ src/libsyntax/sess.rs | 2 ++ .../ui/feature-gates/feature-gate-label_break_value.rs | 5 ++++- .../ui/feature-gates/feature-gate-label_break_value.stderr | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index ab8781feef07d..4e273fc9374fc 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -514,12 +514,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "type ascription is experimental"); } } - ast::ExprKind::Block(_, opt_label) => { - if let Some(label) = opt_label { - gate_feature_post!(&self, label_break_value, label.ident.span, - "labels on blocks are unstable"); - } - } _ => {} } visit::walk_expr(self, e) @@ -814,6 +808,7 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(box_patterns, "box pattern syntax is experimental"); gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental"); gate_all!(try_blocks, "`try` blocks are unstable"); + gate_all!(label_break_value, "labels on blocks are unstable"); visit::walk_crate(&mut visitor, krate); } diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 2e34422b91883..395f3a3a4dfe1 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1260,6 +1260,10 @@ impl<'a> Parser<'a> { blk_mode: BlockCheckMode, outer_attrs: ThinVec, ) -> PResult<'a, P> { + if let Some(label) = opt_label { + self.sess.gated_spans.label_break_value.borrow_mut().push(label.ident.span); + } + self.expect(&token::OpenDelim(token::Brace))?; let mut attrs = outer_attrs; diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index 3582d897272bb..ac6be3036ce64 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -46,6 +46,8 @@ crate struct GatedSpans { pub exclusive_range_pattern: Lock>, /// Spans collected for gating `try_blocks`, e.g. `try { a? + b? }`. pub try_blocks: Lock>, + /// Spans collected for gating `label_break_value`, e.g. `'label: { ... }`. + pub label_break_value: Lock>, } /// Info about a parsing session. diff --git a/src/test/ui/feature-gates/feature-gate-label_break_value.rs b/src/test/ui/feature-gates/feature-gate-label_break_value.rs index 6fc38f45517ef..8d7ecd27b450f 100644 --- a/src/test/ui/feature-gates/feature-gate-label_break_value.rs +++ b/src/test/ui/feature-gates/feature-gate-label_break_value.rs @@ -1,5 +1,8 @@ -pub fn main() { +#[cfg(FALSE)] +pub fn foo() { 'a: { //~ ERROR labels on blocks are unstable break 'a; } } + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-label_break_value.stderr b/src/test/ui/feature-gates/feature-gate-label_break_value.stderr index a417e0eec22f2..6a861d3e04f92 100644 --- a/src/test/ui/feature-gates/feature-gate-label_break_value.stderr +++ b/src/test/ui/feature-gates/feature-gate-label_break_value.stderr @@ -1,5 +1,5 @@ error[E0658]: labels on blocks are unstable - --> $DIR/feature-gate-label_break_value.rs:2:5 + --> $DIR/feature-gate-label_break_value.rs:3:5 | LL | 'a: { | ^^ From e4ed8865786a787a7b0c045f7674569b6be0e9bc Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 22 Sep 2019 00:06:51 +0200 Subject: [PATCH 17/32] pre-expansion gate box_syntax --- src/libsyntax/feature_gate/check.rs | 7 +------ src/libsyntax/parse/parser/expr.rs | 4 +++- src/libsyntax/sess.rs | 2 ++ src/test/ui/feature-gates/feature-gate-box_syntax.rs | 5 ++++- src/test/ui/feature-gates/feature-gate-box_syntax.stderr | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 4e273fc9374fc..7243f5c032016 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -153,9 +153,6 @@ fn leveled_feature_err<'a, S: Into>( } -const EXPLAIN_BOX_SYNTAX: &str = - "box expression syntax is experimental; you can call `Box::new` instead"; - pub const EXPLAIN_STMT_ATTR_SYNTAX: &str = "attributes on expressions are experimental"; @@ -503,9 +500,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_expr(&mut self, e: &'a ast::Expr) { match e.kind { - ast::ExprKind::Box(_) => { - gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); - } ast::ExprKind::Type(..) => { // To avoid noise about type ascription in common syntax errors, only emit if it // is the *only* error. @@ -809,6 +803,7 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental"); gate_all!(try_blocks, "`try` blocks are unstable"); gate_all!(label_break_value, "labels on blocks are unstable"); + gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead"); visit::walk_crate(&mut visitor, krate); } diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 395f3a3a4dfe1..e7dd15654d806 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -453,7 +453,9 @@ impl<'a> Parser<'a> { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - (lo.to(span), ExprKind::Box(e)) + let span = lo.to(span); + self.sess.gated_spans.box_syntax.borrow_mut().push(span); + (span, ExprKind::Box(e)) } token::Ident(..) if self.token.is_ident_named(sym::not) => { // `not` is just an ordinary identifier in Rust-the-language, diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index ac6be3036ce64..febaa71477509 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -48,6 +48,8 @@ crate struct GatedSpans { pub try_blocks: Lock>, /// Spans collected for gating `label_break_value`, e.g. `'label: { ... }`. pub label_break_value: Lock>, + /// Spans collected for gating `box_syntax`, e.g. `box $expr`. + pub box_syntax: Lock>, } /// Info about a parsing session. diff --git a/src/test/ui/feature-gates/feature-gate-box_syntax.rs b/src/test/ui/feature-gates/feature-gate-box_syntax.rs index 778660cc0b549..c23953a9e099e 100644 --- a/src/test/ui/feature-gates/feature-gate-box_syntax.rs +++ b/src/test/ui/feature-gates/feature-gate-box_syntax.rs @@ -1,6 +1,9 @@ // Test that the use of the box syntax is gated by `box_syntax` feature gate. -fn main() { +#[cfg(FALSE)] +fn foo() { let x = box 3; //~^ ERROR box expression syntax is experimental; you can call `Box::new` instead } + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-box_syntax.stderr b/src/test/ui/feature-gates/feature-gate-box_syntax.stderr index 61b0534d2dc3e..cbafa50257706 100644 --- a/src/test/ui/feature-gates/feature-gate-box_syntax.stderr +++ b/src/test/ui/feature-gates/feature-gate-box_syntax.stderr @@ -1,5 +1,5 @@ error[E0658]: box expression syntax is experimental; you can call `Box::new` instead - --> $DIR/feature-gate-box_syntax.rs:4:13 + --> $DIR/feature-gate-box_syntax.rs:5:13 | LL | let x = box 3; | ^^^^^ From 15a6c09b6e8a977f2c6f5a73de01a20d00b37930 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 22 Sep 2019 00:19:02 +0200 Subject: [PATCH 18/32] pre-expansion gate type_ascription --- src/libsyntax/feature_gate/check.rs | 21 ++++++------------- src/libsyntax/parse/parser/expr.rs | 1 + src/libsyntax/sess.rs | 2 ++ .../feature-gate-type_ascription.rs | 5 ++++- .../feature-gate-type_ascription.stderr | 2 +- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 7243f5c032016..502b1c0f74371 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -498,21 +498,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - fn visit_expr(&mut self, e: &'a ast::Expr) { - match e.kind { - ast::ExprKind::Type(..) => { - // To avoid noise about type ascription in common syntax errors, only emit if it - // is the *only* error. - if self.parse_sess.span_diagnostic.err_count() == 0 { - gate_feature_post!(&self, type_ascription, e.span, - "type ascription is experimental"); - } - } - _ => {} - } - visit::walk_expr(self, e) - } - fn visit_pat(&mut self, pattern: &'a ast::Pat) { match &pattern.kind { PatKind::Slice(pats) => { @@ -805,6 +790,12 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(label_break_value, "labels on blocks are unstable"); gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead"); + // To avoid noise about type ascription in common syntax errors, + // only emit if it is the *only* error. (Also check it last.) + if parse_sess.span_diagnostic.err_count() == 0 { + gate_all!(type_ascription, "type ascription is experimental"); + } + visit::walk_crate(&mut visitor, krate); } diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index e7dd15654d806..97b1092452aaf 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -252,6 +252,7 @@ impl<'a> Parser<'a> { self.last_type_ascription = Some((self.prev_span, maybe_path)); lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type)?; + self.sess.gated_spans.type_ascription.borrow_mut().push(lhs.span); continue } else if op == AssocOp::DotDot || op == AssocOp::DotDotEq { // If we didn’t have to handle `x..`/`x..=`, it would be pretty easy to diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index febaa71477509..28a0868d5dd1e 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -50,6 +50,8 @@ crate struct GatedSpans { pub label_break_value: Lock>, /// Spans collected for gating `box_syntax`, e.g. `box $expr`. pub box_syntax: Lock>, + /// Spans collected for gating `type_ascription`, e.g. `42: usize`. + pub type_ascription: Lock>, } /// Info about a parsing session. diff --git a/src/test/ui/feature-gates/feature-gate-type_ascription.rs b/src/test/ui/feature-gates/feature-gate-type_ascription.rs index 7a597157300ed..655891d802c1c 100644 --- a/src/test/ui/feature-gates/feature-gate-type_ascription.rs +++ b/src/test/ui/feature-gates/feature-gate-type_ascription.rs @@ -1,5 +1,8 @@ // Type ascription is unstable -fn main() { +#[cfg(FALSE)] +fn foo() { let a = 10: u8; //~ ERROR type ascription is experimental } + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-type_ascription.stderr b/src/test/ui/feature-gates/feature-gate-type_ascription.stderr index 83f95529f0d9d..d63d624c6c112 100644 --- a/src/test/ui/feature-gates/feature-gate-type_ascription.stderr +++ b/src/test/ui/feature-gates/feature-gate-type_ascription.stderr @@ -1,5 +1,5 @@ error[E0658]: type ascription is experimental - --> $DIR/feature-gate-type_ascription.rs:4:13 + --> $DIR/feature-gate-type_ascription.rs:5:13 | LL | let a = 10: u8; | ^^^^^^ From 822f787546f93e0319def3576ff7550e46fb3c1e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 24 Oct 2019 02:24:14 +0200 Subject: [PATCH 19/32] Adjust the tracking issue for `untagged_unions`. Also elaborate on some feature gates in `active.rs`. --- src/libsyntax/feature_gate/active.rs | 18 +++++++++++++----- .../feature-gate-untagged_unions.stderr | 6 +++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index 1386eac48dae2..4f92401d2bc57 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -330,8 +330,13 @@ declare_features! ( /// Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", Some(51085), None), - /// Allows untagged unions `union U { ... }`. - (active, untagged_unions, "1.13.0", Some(32836), None), + /// Allows `union`s to implement `Drop`. Moreover, `union`s may now include fields + /// that don't implement `Copy` as long as they don't have any drop glue. + /// This is checked recursively. On encountering type variable where no progress can be made, + /// `T: Copy` is used as a substitute for "no drop glue". + /// + /// NOTE: A limited form of `union U { ... }` was accepted in 1.19.0. + (active, untagged_unions, "1.13.0", Some(55149), None), /// Allows `#[link(..., cfg(..))]`. (active, link_cfg, "1.14.0", Some(37406), None), @@ -522,13 +527,16 @@ declare_features! ( /// Allows the definition of `const extern fn` and `const unsafe extern fn`. (active, const_extern_fn, "1.40.0", Some(64926), None), - // Allows the use of raw-dylibs (RFC 2627). + /// Allows the use of raw-dylibs (RFC 2627). (active, raw_dylib, "1.40.0", Some(58713), None), - /// Enable accurate caller location reporting during panic (RFC 2091). + /// Allows `#[track_caller]` to be used which provides + /// accurate caller location reporting during panic (RFC 2091). (active, track_caller, "1.40.0", Some(47809), None), - /// Non-object safe trait objects safe to use but cannot be created in safe rust + /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe. + /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and + /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. (active, object_safe_for_dispatch, "1.40.0", Some(43561), None), // ------------------------------------------------------------------------- diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr index 1885518a4585c..2182b3a313efb 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr @@ -6,7 +6,7 @@ LL | | a: String, LL | | } | |_^ | - = note: for more information, see https://github.com/rust-lang/rust/issues/32836 + = note: for more information, see https://github.com/rust-lang/rust/issues/55149 = help: add `#![feature(untagged_unions)]` to the crate attributes to enable error[E0658]: unions with non-`Copy` fields are unstable @@ -17,7 +17,7 @@ LL | | a: T, LL | | } | |_^ | - = note: for more information, see https://github.com/rust-lang/rust/issues/32836 + = note: for more information, see https://github.com/rust-lang/rust/issues/55149 = help: add `#![feature(untagged_unions)]` to the crate attributes to enable error[E0658]: unions with `Drop` implementations are unstable @@ -28,7 +28,7 @@ LL | | a: u8, LL | | } | |_^ | - = note: for more information, see https://github.com/rust-lang/rust/issues/32836 + = note: for more information, see https://github.com/rust-lang/rust/issues/55149 = help: add `#![feature(untagged_unions)]` to the crate attributes to enable error[E0740]: unions may not contain fields that need dropping From b1331563baa43819b2717a24d2cdc94e3b3a2eb5 Mon Sep 17 00:00:00 2001 From: wangxiangqing Date: Tue, 22 Oct 2019 00:08:14 +0800 Subject: [PATCH 20/32] Deprecated proc_macro doesn't trigger warning on build library Change-Id: Ib3a396e7334d209fe6c6ef425bbfc7b2ae471378 --- src/test/ui/proc-macro/proc-macro-deprecated-attr.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/ui/proc-macro/proc-macro-deprecated-attr.rs b/src/test/ui/proc-macro/proc-macro-deprecated-attr.rs index 25ce53b70a5bd..f1144a4a55b16 100644 --- a/src/test/ui/proc-macro/proc-macro-deprecated-attr.rs +++ b/src/test/ui/proc-macro/proc-macro-deprecated-attr.rs @@ -1,4 +1,6 @@ // check-pass +// force-host +// no-prefer-dynamic #![deny(deprecated)] From a2e94ca1ee21f46eb18cd4392fa8e621ebaea20a Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Thu, 25 Jul 2019 00:39:39 +0200 Subject: [PATCH 21/32] Add `array::IntoIter` as a consuming/by-value array iterator The iterator is implemented using const generics. It implements the traits `Iterator`, `DoubleEndedIterator`, `ExactSizeIterator`, `FusedIterator` and `TrustedLen`. It also contains a public method `new` to create it from an array. `IntoIterator` was not implemented for arrays yet, as there are still some open questions regarding backwards compatibility. This commit only adds the iterator impl and does not yet offer a convenient way to obtain that iterator. --- src/libcore/array/iter.rs | 266 +++++++++++++++++++++++++ src/libcore/{array.rs => array/mod.rs} | 7 + 2 files changed, 273 insertions(+) create mode 100644 src/libcore/array/iter.rs rename src/libcore/{array.rs => array/mod.rs} (98%) diff --git a/src/libcore/array/iter.rs b/src/libcore/array/iter.rs new file mode 100644 index 0000000000000..850a599c6599f --- /dev/null +++ b/src/libcore/array/iter.rs @@ -0,0 +1,266 @@ +//! Defines the `IntoIter` owned iterator for arrays. + +use crate::{ + fmt, + iter::{ExactSizeIterator, FusedIterator, TrustedLen}, + mem::{self, MaybeUninit}, + ops::Range, + ptr, +}; +use super::LengthAtMost32; + + +/// A by-value [array] iterator. +/// +/// [array]: ../../std/primitive.array.html +#[unstable(feature = "array_value_iter", issue = "0")] +pub struct IntoIter +where + [T; N]: LengthAtMost32, +{ + /// This is the array we are iterating over. + /// + /// Elements with index `i` where `alive.start <= i < alive.end` have not + /// been yielded yet and are valid array entries. Elements with indices `i + /// < alive.start` or `i >= alive.end` have been yielded already and must + /// not be accessed anymore! Those dead elements might even be in a + /// completely uninitialized state! + /// + /// So the invariants are: + /// - `data[alive]` is alive (i.e. contains valid elements) + /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the + /// elements were already read and must not be touched anymore!) + data: [MaybeUninit; N], + + /// The elements in `data` that have not been yielded yet. + /// + /// Invariants: + /// - `alive.start <= alive.end` + /// - `alive.end <= N` + alive: Range, +} + +impl IntoIter +where + [T; N]: LengthAtMost32, +{ + /// Creates a new iterator over the given `array`. + /// + /// *Note*: this method might never get stabilized and/or removed in the + /// future as there will likely be another, preferred way of obtaining this + /// iterator (either via `IntoIterator` for arrays or via another way). + #[unstable(feature = "array_value_iter", issue = "0")] + pub fn new(array: [T; N]) -> Self { + // The transmute here is actually safe. The docs of `MaybeUninit` + // promise: + // + // > `MaybeUninit` is guaranteed to have the same size and alignment + // > as `T`. + // + // The docs even show a transmute from an array of `MaybeUninit` to + // an array of `T`. + // + // With that, this initialization satisfies the invariants. + + // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it + // works with const generics: + // `mem::transmute::<[T; {N}], [MaybeUninit; {N}]>(array)` + // + // Until then, we do it manually here. We first create a bitwise copy + // but cast the pointer so that it is treated as a different type. Then + // we forget `array` so that it is not dropped. + let data = unsafe { + let data = ptr::read(&array as *const [T; N] as *const [MaybeUninit; N]); + mem::forget(array); + data + }; + + Self { + data, + alive: 0..N, + } + } + + /// Returns an immutable slice of all elements that have not been yielded + /// yet. + fn as_slice(&self) -> &[T] { + // This transmute is safe. As mentioned in `new`, `MaybeUninit` retains + // the size and alignment of `T`. Furthermore, we know that all + // elements within `alive` are properly initialized. + let slice = &self.data[self.alive.clone()]; + unsafe { + mem::transmute::<&[MaybeUninit], &[T]>(slice) + } + } +} + + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl Iterator for IntoIter +where + [T; N]: LengthAtMost32, +{ + type Item = T; + fn next(&mut self) -> Option { + if self.alive.start == self.alive.end { + return None; + } + + // Bump start index. + // + // From the check above we know that `alive.start != alive.end`. + // Combine this with the invariant `alive.start <= alive.end`, we know + // that `alive.start < alive.end`. Increasing `alive.start` by 1 + // maintains the invariant regarding `alive`. However, due to this + // change, for a short time, the alive zone is not `data[alive]` + // anymore, but `data[idx..alive.end]`. + let idx = self.alive.start; + self.alive.start += 1; + + // Read the element from the array. This is safe: `idx` is an index + // into the "alive" region of the array. Reading this element means + // that `data[idx]` is regarded as dead now (i.e. do not touch). As + // `idx` was the start of the alive-zone, the alive zone is now + // `data[alive]` again, restoring all invariants. + let out = unsafe { self.data.get_unchecked(idx).read() }; + + Some(out) + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } + + fn count(self) -> usize { + self.len() + } + + fn last(mut self) -> Option { + self.next_back() + } +} + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl DoubleEndedIterator for IntoIter +where + [T; N]: LengthAtMost32, +{ + fn next_back(&mut self) -> Option { + if self.alive.start == self.alive.end { + return None; + } + + // Decrease end index. + // + // From the check above we know that `alive.start != alive.end`. + // Combine this with the invariant `alive.start <= alive.end`, we know + // that `alive.start < alive.end`. As `alive.start` cannot be negative, + // `alive.end` is at least 1, meaning that we can safely decrement it + // by one. This also maintains the invariant `alive.start <= + // alive.end`. However, due to this change, for a short time, the alive + // zone is not `data[alive]` anymore, but `data[alive.start..alive.end + // + 1]`. + self.alive.end -= 1; + + // Read the element from the array. This is safe: `alive.end` is an + // index into the "alive" region of the array. Compare the previous + // comment that states that the alive region is + // `data[alive.start..alive.end + 1]`. Reading this element means that + // `data[alive.end]` is regarded as dead now (i.e. do not touch). As + // `alive.end` was the end of the alive-zone, the alive zone is now + // `data[alive]` again, restoring all invariants. + let out = unsafe { self.data.get_unchecked(self.alive.end).read() }; + + Some(out) + } +} + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl Drop for IntoIter +where + [T; N]: LengthAtMost32, +{ + fn drop(&mut self) { + // We simply drop each element via `for_each`. This should not incur + // any significant runtime overhead and avoids adding another `unsafe` + // block. + self.by_ref().for_each(drop); + } +} + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl ExactSizeIterator for IntoIter +where + [T; N]: LengthAtMost32, +{ + fn len(&self) -> usize { + // Will never underflow due to the invariant `alive.start <= + // alive.end`. + self.alive.end - self.alive.start + } + fn is_empty(&self) -> bool { + self.alive.is_empty() + } +} + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl FusedIterator for IntoIter +where + [T; N]: LengthAtMost32, +{} + +// The iterator indeed reports the correct length. The number of "alive" +// elements (that will still be yielded) is the length of the range `alive`. +// This range is decremented in length in either `next` or `next_back`. It is +// always decremented by 1 in those methods, but only if `Some(_)` is returned. +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +unsafe impl TrustedLen for IntoIter +where + [T; N]: LengthAtMost32, +{} + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl Clone for IntoIter +where + [T; N]: LengthAtMost32, +{ + fn clone(&self) -> Self { + unsafe { + // This creates a new uninitialized array. Note that the `assume_init` + // refers to the array, not the individual elements. And it is Ok if + // the array is in an uninitialized state as all elements may be + // uninitialized (all bit patterns are valid). Compare the + // `MaybeUninit` docs for more information. + let mut new_data: [MaybeUninit; N] = MaybeUninit::uninit().assume_init(); + + // Clone all alive elements. + for idx in self.alive.clone() { + // The element at `idx` in the old array is alive, so we can + // safely call `get_ref()`. We then clone it, and write the + // clone into the new array. + let clone = self.data.get_unchecked(idx).get_ref().clone(); + new_data.get_unchecked_mut(idx).write(clone); + } + + Self { + data: new_data, + alive: self.alive.clone(), + } + } + } +} + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl fmt::Debug for IntoIter +where + [T; N]: LengthAtMost32, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Only print the elements that were not yielded yet: we cannot + // access the yielded elements anymore. + f.debug_tuple("IntoIter") + .field(&self.as_slice()) + .finish() + } +} diff --git a/src/libcore/array.rs b/src/libcore/array/mod.rs similarity index 98% rename from src/libcore/array.rs rename to src/libcore/array/mod.rs index b5614010e5c2f..120658e9a4343 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array/mod.rs @@ -14,6 +14,13 @@ use crate::hash::{Hash, self}; use crate::marker::Unsize; use crate::slice::{Iter, IterMut}; +#[cfg(not(bootstrap))] +mod iter; + +#[cfg(not(bootstrap))] +#[unstable(feature = "array_value_iter", issue = "0")] +pub use iter::IntoIter; + /// Utility trait implemented only on arrays of fixed size /// /// This trait can be used to implement other traits on fixed-size arrays From 5334a307d551e5affaef253f1c83141495db46f0 Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Fri, 26 Jul 2019 13:27:13 +0200 Subject: [PATCH 22/32] Add unit tests for `array::IntoIter` Many tests are based on tests by Josh Stone --- src/libcore/tests/array.rs | 207 ++++++++++++++++++++++++++++++++++++- src/libcore/tests/lib.rs | 1 + 2 files changed, 207 insertions(+), 1 deletion(-) diff --git a/src/libcore/tests/array.rs b/src/libcore/tests/array.rs index 9e133ac568811..4f3b79c78b66c 100644 --- a/src/libcore/tests/array.rs +++ b/src/libcore/tests/array.rs @@ -1,4 +1,4 @@ -use core::array::FixedSizeArray; +use core::array::{FixedSizeArray, IntoIter}; use core::convert::TryFrom; #[test] @@ -40,3 +40,208 @@ fn array_try_from() { 30 31 32 } } + + +#[test] +fn iterator_collect() { + let arr = [0, 1, 2, 5, 9]; + let v: Vec<_> = IntoIter::new(arr.clone()).collect(); + assert_eq!(&arr[..], &v[..]); +} + +#[test] +fn iterator_rev_collect() { + let arr = [0, 1, 2, 5, 9]; + let v: Vec<_> = IntoIter::new(arr.clone()).rev().collect(); + assert_eq!(&v[..], &[9, 5, 2, 1, 0]); +} + +#[test] +fn iterator_nth() { + let v = [0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(IntoIter::new(v.clone()).nth(i).unwrap(), v[i]); + } + assert_eq!(IntoIter::new(v.clone()).nth(v.len()), None); + + let mut iter = IntoIter::new(v); + assert_eq!(iter.nth(2).unwrap(), v[2]); + assert_eq!(iter.nth(1).unwrap(), v[4]); +} + +#[test] +fn iterator_last() { + let v = [0, 1, 2, 3, 4]; + assert_eq!(IntoIter::new(v).last().unwrap(), 4); + assert_eq!(IntoIter::new([0]).last().unwrap(), 0); + + let mut it = IntoIter::new([0, 9, 2, 4]); + assert_eq!(it.next_back(), Some(4)); + assert_eq!(it.last(), Some(2)); +} + +#[test] +fn iterator_clone() { + let mut it = IntoIter::new([0, 2, 4, 6, 8]); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let mut clone = it.clone(); + assert_eq!(it.next_back(), Some(6)); + assert_eq!(clone.next_back(), Some(6)); + assert_eq!(it.next_back(), Some(4)); + assert_eq!(clone.next_back(), Some(4)); + assert_eq!(it.next(), Some(2)); + assert_eq!(clone.next(), Some(2)); +} + +#[test] +fn iterator_fused() { + let mut it = IntoIter::new([0, 9, 2]); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(9)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); +} + +#[test] +fn iterator_len() { + let mut it = IntoIter::new([0, 1, 2, 5, 9]); + assert_eq!(it.size_hint(), (5, Some(5))); + assert_eq!(it.len(), 5); + assert_eq!(it.is_empty(), false); + + assert_eq!(it.next(), Some(0)); + assert_eq!(it.size_hint(), (4, Some(4))); + assert_eq!(it.len(), 4); + assert_eq!(it.is_empty(), false); + + assert_eq!(it.next_back(), Some(9)); + assert_eq!(it.size_hint(), (3, Some(3))); + assert_eq!(it.len(), 3); + assert_eq!(it.is_empty(), false); + + // Empty + let it = IntoIter::new([] as [String; 0]); + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.len(), 0); + assert_eq!(it.is_empty(), true); +} + +#[test] +fn iterator_count() { + let v = [0, 1, 2, 3, 4]; + assert_eq!(IntoIter::new(v.clone()).count(), 5); + + let mut iter2 = IntoIter::new(v); + iter2.next(); + iter2.next(); + assert_eq!(iter2.count(), 3); +} + +#[test] +fn iterator_flat_map() { + assert!((0..5).flat_map(|i| IntoIter::new([2 * i, 2 * i + 1])).eq(0..10)); +} + +#[test] +fn iterator_debug() { + let arr = [0, 1, 2, 5, 9]; + assert_eq!( + format!("{:?}", IntoIter::new(arr)), + "IntoIter([0, 1, 2, 5, 9])", + ); +} + +#[test] +fn iterator_drops() { + use core::cell::Cell; + + // This test makes sure the correct number of elements are dropped. The `R` + // type is just a reference to a `Cell` that is incremented when an `R` is + // dropped. + + #[derive(Clone)] + struct Foo<'a>(&'a Cell); + + impl Drop for Foo<'_> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } + } + + fn five(i: &Cell) -> [Foo<'_>; 5] { + // This is somewhat verbose because `Foo` does not implement `Copy` + // since it implements `Drop`. Consequently, we cannot write + // `[Foo(i); 5]`. + [Foo(i), Foo(i), Foo(i), Foo(i), Foo(i)] + } + + // Simple: drop new iterator. + let i = Cell::new(0); + { + IntoIter::new(five(&i)); + } + assert_eq!(i.get(), 5); + + // Call `next()` once. + let i = Cell::new(0); + { + let mut iter = IntoIter::new(five(&i)); + let _x = iter.next(); + assert_eq!(i.get(), 0); + assert_eq!(iter.count(), 4); + assert_eq!(i.get(), 4); + } + assert_eq!(i.get(), 5); + + // Check `clone` and calling `next`/`next_back`. + let i = Cell::new(0); + { + let mut iter = IntoIter::new(five(&i)); + iter.next(); + assert_eq!(i.get(), 1); + iter.next_back(); + assert_eq!(i.get(), 2); + + let mut clone = iter.clone(); + assert_eq!(i.get(), 2); + + iter.next(); + assert_eq!(i.get(), 3); + + clone.next(); + assert_eq!(i.get(), 4); + + assert_eq!(clone.count(), 2); + assert_eq!(i.get(), 6); + } + assert_eq!(i.get(), 8); + + // Check via `nth`. + let i = Cell::new(0); + { + let mut iter = IntoIter::new(five(&i)); + let _x = iter.nth(2); + assert_eq!(i.get(), 2); + let _y = iter.last(); + assert_eq!(i.get(), 3); + } + assert_eq!(i.get(), 5); + + // Check every element. + let i = Cell::new(0); + for (index, _x) in IntoIter::new(five(&i)).enumerate() { + assert_eq!(i.get(), index); + } + assert_eq!(i.get(), 5); + + let i = Cell::new(0); + for (index, _x) in IntoIter::new(five(&i)).rev().enumerate() { + assert_eq!(i.get(), index); + } + assert_eq!(i.get(), 5); +} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 35661356028cb..b28ed2eaa0876 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -31,6 +31,7 @@ #![feature(slice_partition_dedup)] #![feature(int_error_matching)] #![feature(const_fn)] +#![feature(array_value_iter)] #![feature(iter_partition_in_place)] #![feature(iter_is_partitioned)] #![feature(iter_order_by)] From c36b9ddcb40b81642cef2d1dd17bcd45f54c70da Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Mon, 21 Oct 2019 13:47:02 +0200 Subject: [PATCH 23/32] Add UI tests for `array::IntoIter` impls This it to make sure traits are implemented for arrays with length 32 and below, while they are not implemented for >= 33. --- .../array-impls/into-iter-impls-length-32.rs | 41 ++++++ .../into-iter-no-impls-length-33.rs | 53 ++++++++ .../into-iter-no-impls-length-33.stderr | 122 ++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs create mode 100644 src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.rs create mode 100644 src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr diff --git a/src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs b/src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs new file mode 100644 index 0000000000000..0aeba8607e818 --- /dev/null +++ b/src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs @@ -0,0 +1,41 @@ +// check-pass + +#![feature(array_value_iter)] +#![feature(trusted_len)] + +use std::{ + array::IntoIter, + fmt::Debug, + iter::{ExactSizeIterator, FusedIterator, TrustedLen}, +}; + +pub fn yes_iterator() -> impl Iterator { + IntoIter::new([0i32; 32]) +} + +pub fn yes_double_ended_iterator() -> impl DoubleEndedIterator { + IntoIter::new([0i32; 32]) +} + +pub fn yes_exact_size_iterator() -> impl ExactSizeIterator { + IntoIter::new([0i32; 32]) +} + +pub fn yes_fused_iterator() -> impl FusedIterator { + IntoIter::new([0i32; 32]) +} + +pub fn yes_trusted_len() -> impl TrustedLen { + IntoIter::new([0i32; 32]) +} + +pub fn yes_clone() -> impl Clone { + IntoIter::new([0i32; 32]) +} + +pub fn yes_debug() -> impl Debug { + IntoIter::new([0i32; 32]) +} + + +fn main() {} diff --git a/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.rs b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.rs new file mode 100644 index 0000000000000..a0bbd2ce64add --- /dev/null +++ b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.rs @@ -0,0 +1,53 @@ +#![feature(array_value_iter)] +#![feature(trusted_len)] + +use std::{ + array::IntoIter, + fmt::Debug, + iter::{ExactSizeIterator, FusedIterator, TrustedLen}, +}; + +pub fn no_iterator() -> impl Iterator { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_double_ended_iterator() -> impl DoubleEndedIterator { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_exact_size_iterator() -> impl ExactSizeIterator { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_fused_iterator() -> impl FusedIterator { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_trusted_len() -> impl TrustedLen { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_clone() -> impl Clone { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_debug() -> impl Debug { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + + +fn main() {} diff --git a/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr new file mode 100644 index 0000000000000..bfdff8e3bbe61 --- /dev/null +++ b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr @@ -0,0 +1,122 @@ +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:12:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:10:25 + | +LL | pub fn no_iterator() -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:18:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:16:38 + | +LL | pub fn no_double_ended_iterator() -> impl DoubleEndedIterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:24:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:22:36 + | +LL | pub fn no_exact_size_iterator() -> impl ExactSizeIterator { + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::iter::ExactSizeIterator` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:30:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:28:31 + | +LL | pub fn no_fused_iterator() -> impl FusedIterator { + | ^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::iter::FusedIterator` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:36:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:34:28 + | +LL | pub fn no_trusted_len() -> impl TrustedLen { + | ^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::iter::TrustedLen` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:42:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:40:22 + | +LL | pub fn no_clone() -> impl Clone { + | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::clone::Clone` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:48:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:46:22 + | +LL | pub fn no_debug() -> impl Debug { + | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::fmt::Debug` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0277`. From 4cfcb770844333a6c7e1ebddc8d30770098bdfd7 Mon Sep 17 00:00:00 2001 From: Sydney Acksman Date: Thu, 24 Oct 2019 09:46:19 -0500 Subject: [PATCH 24/32] Changed APIT with explicit generic args span to specific arg spans --- src/librustc_typeck/astconv.rs | 21 +++++++++++++++---- .../issues/universal-issue-48703.stderr | 4 ++-- ...sal-turbofish-in-method-issue-50950.stderr | 6 ++++-- src/test/ui/synthetic-param.stderr | 12 +++++------ 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index a052ad95ed58a..97f7c6a2c8a73 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -215,7 +215,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Report error if there is an explicit type parameter when using `impl Trait`. fn check_impl_trait( tcx: TyCtxt<'_>, - span: Span, seg: &hir::PathSegment, generics: &ty::Generics, ) -> bool { @@ -228,14 +227,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }); if explicit && impl_trait { + let spans = + seg.generic_args().args + .iter() + .filter_map(|arg| + match arg { + GenericArg::Type(_) => Some(arg.span()), + _ => None + }) + .collect::>(); + let mut err = struct_span_err! { tcx.sess, - span, + spans.clone(), E0632, "cannot provide explicit generic arguments when `impl Trait` is \ - used in argument position" + used in argument position" }; + for span in spans { + err.span_label(span, "explicit generic argument not allowed"); + } + err.emit(); } @@ -254,7 +267,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let empty_args = P(hir::GenericArgs { args: HirVec::new(), bindings: HirVec::new(), parenthesized: false, }); - let suppress_mismatch = Self::check_impl_trait(tcx, span, seg, &def); + let suppress_mismatch = Self::check_impl_trait(tcx, seg, &def); Self::check_generic_arg_count( tcx, span, diff --git a/src/test/ui/impl-trait/issues/universal-issue-48703.stderr b/src/test/ui/impl-trait/issues/universal-issue-48703.stderr index a51302dce2966..8f05ab3c4940c 100644 --- a/src/test/ui/impl-trait/issues/universal-issue-48703.stderr +++ b/src/test/ui/impl-trait/issues/universal-issue-48703.stderr @@ -1,8 +1,8 @@ error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position - --> $DIR/universal-issue-48703.rs:8:5 + --> $DIR/universal-issue-48703.rs:8:11 | LL | foo::('a'); - | ^^^^^^^^^^^^^ + | ^^^^^^ explicit generic argument not allowed error: aborting due to previous error diff --git a/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr index f09aa166ef508..c980e9463e48a 100644 --- a/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr +++ b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr @@ -1,8 +1,10 @@ error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position - --> $DIR/universal-turbofish-in-method-issue-50950.rs:14:9 + --> $DIR/universal-turbofish-in-method-issue-50950.rs:14:24 | LL | evt.handle_event::(|_evt| { - | ^^^^^^^^^^^^ + | ^^^^^^^^^ ^^^^^^^^^^^^^ explicit generic argument not allowed + | | + | explicit generic argument not allowed error: aborting due to previous error diff --git a/src/test/ui/synthetic-param.stderr b/src/test/ui/synthetic-param.stderr index f8d14f26f32de..951d7edb7f523 100644 --- a/src/test/ui/synthetic-param.stderr +++ b/src/test/ui/synthetic-param.stderr @@ -1,20 +1,20 @@ error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position - --> $DIR/synthetic-param.rs:20:5 + --> $DIR/synthetic-param.rs:20:12 | LL | func::(42); - | ^^^^^^^^^^ + | ^^ explicit generic argument not allowed error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position - --> $DIR/synthetic-param.rs:23:5 + --> $DIR/synthetic-param.rs:23:17 | LL | Foo::func::(42); - | ^^^^^^^^^^^^^^^ + | ^^ explicit generic argument not allowed error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position - --> $DIR/synthetic-param.rs:26:5 + --> $DIR/synthetic-param.rs:26:23 | LL | Bar::::func::(42); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^ explicit generic argument not allowed error: aborting due to 3 previous errors From 9adea6177773b992fcdf7b1df26dd527cceba40d Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Thu, 24 Oct 2019 23:41:48 +0800 Subject: [PATCH 25/32] add a WARNING to rust.optimize option in config.toml.example --- config.toml.example | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/config.toml.example b/config.toml.example index 848147c2974c1..0124583e41ca3 100644 --- a/config.toml.example +++ b/config.toml.example @@ -258,10 +258,9 @@ [rust] # Whether or not to optimize the compiler and standard library. -# -# Note: the slowness of the non optimized compiler compiling itself usually -# outweighs the time gains in not doing optimizations, therefore a -# full bootstrap takes much more time with `optimize` set to false. +# WARNING: Building with optimize = false is NOT SUPPORTED. Due to bootstrapping, +# building without optimizations takes much longer than optimizing. Further, some platforms +# fail to build without this optimization (c.f. #65352). #optimize = true # Indicates that the build should be configured for debugging Rust. A From 2f7e3d55c96ef44463bb62f98ba25538fc2fffff Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Thu, 24 Oct 2019 23:43:06 +0800 Subject: [PATCH 26/32] add the missing rust.musl-root option in config.toml.example --- config.toml.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.toml.example b/config.toml.example index 0124583e41ca3..d6a5c5a3b92a4 100644 --- a/config.toml.example +++ b/config.toml.example @@ -340,6 +340,9 @@ # nightly features #channel = "dev" +# The root location of the MUSL installation directory. +#musl-root = "..." + # By default the `rustc` executable is built with `-Wl,-rpath` flags on Unix # platforms to ensure that the compiler is usable by default from the build # directory (as it links to a number of dynamic libraries). This may not be From a90954163b9cc80009ec3aeacf9974817b3b1892 Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Thu, 24 Oct 2019 23:46:05 +0800 Subject: [PATCH 27/32] reorder Llvm struct's fields based on the order in config.toml.example --- src/bootstrap/config.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 52b5cd888df9c..a97273ed2f8c6 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -243,14 +243,14 @@ struct Install { #[derive(Deserialize, Default)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Llvm { - ccache: Option, - ninja: Option, - assertions: Option, optimize: Option, thin_lto: Option, release_debuginfo: Option, + assertions: Option, + ccache: Option, version_check: Option, static_libstdcpp: Option, + ninja: Option, targets: Option, experimental_targets: Option, link_jobs: Option, From 945223128a1c390dd457480543ee68d4c89478ee Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Thu, 24 Oct 2019 23:50:03 +0800 Subject: [PATCH 28/32] reorder Build struct's fields based on the order in config.toml.example --- src/bootstrap/config.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index a97273ed2f8c6..d393990fdd222 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -200,16 +200,15 @@ struct Build { target: Vec, cargo: Option, rustc: Option, - low_priority: Option, - compiler_docs: Option, docs: Option, + compiler_docs: Option, submodules: Option, fast_submodules: Option, gdb: Option, - locked_deps: Option, - vendor: Option, nodejs: Option, python: Option, + locked_deps: Option, + vendor: Option, full_bootstrap: Option, extended: Option, tools: Option>, @@ -217,6 +216,7 @@ struct Build { sanitizers: Option, profiler: Option, cargo_native_static: Option, + low_priority: Option, configure_args: Option>, local_rebuild: Option, print_step_timings: Option, From e1e60c339a84e2263c6b728dc12596fb38035280 Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Thu, 24 Oct 2019 23:51:02 +0800 Subject: [PATCH 29/32] reorder Install struct's fields based on the order in config.toml.example --- src/bootstrap/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index d393990fdd222..1a27ad94e04dd 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -228,11 +228,11 @@ struct Build { struct Install { prefix: Option, sysconfdir: Option, - datadir: Option, docdir: Option, bindir: Option, libdir: Option, mandir: Option, + datadir: Option, // standard paths, currently unused infodir: Option, From 2c93fd2cb699a240dae93f2064000ce33d9f682d Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Thu, 24 Oct 2019 23:53:45 +0800 Subject: [PATCH 30/32] reorder Rust struct's fields based on the order in config.toml.example --- src/bootstrap/config.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 1a27ad94e04dd..d49c8080ebc81 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -293,6 +293,7 @@ impl Default for StringOrBool { #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Rust { optimize: Option, + debug: Option, codegen_units: Option, codegen_units_std: Option, debug_assertions: Option, @@ -301,25 +302,24 @@ struct Rust { debuginfo_level_std: Option, debuginfo_level_tools: Option, debuginfo_level_tests: Option, - parallel_compiler: Option, backtrace: Option, + incremental: Option, + parallel_compiler: Option, default_linker: Option, channel: Option, musl_root: Option, rpath: Option, + verbose_tests: Option, optimize_tests: Option, codegen_tests: Option, ignore_git: Option, - debug: Option, dist_src: Option, - verbose_tests: Option, - incremental: Option, save_toolstates: Option, codegen_backends: Option>, codegen_backends_dir: Option, lld: Option, - lldb: Option, llvm_tools: Option, + lldb: Option, deny_warnings: Option, backtrace_on_ice: Option, verify_llvm_ir: Option, From 5defe06f96f62807af0ac09d1896d1baba5d8054 Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Thu, 24 Oct 2019 23:54:31 +0800 Subject: [PATCH 31/32] reorder TomlTarget struct's fields based on the order in config.toml.example --- src/bootstrap/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index d49c8080ebc81..ef6253903e97c 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -333,13 +333,13 @@ struct Rust { #[derive(Deserialize, Default)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct TomlTarget { - llvm_config: Option, - llvm_filecheck: Option, cc: Option, cxx: Option, ar: Option, ranlib: Option, linker: Option, + llvm_config: Option, + llvm_filecheck: Option, android_ndk: Option, crt_static: Option, musl_root: Option, From d72417434682e1fcb6e447436f0664d7ea763468 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 20 Oct 2019 22:08:44 +0100 Subject: [PATCH 32/32] Fix more `ReEmpty` ICEs --- .../nll/type_check/constraint_conversion.rs | 6 ++++++ src/test/ui/nll/empty-type-predicate-2.rs | 18 ++++++++++++++++++ src/test/ui/nll/empty-type-predicate.rs | 4 ++-- 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/nll/empty-type-predicate-2.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index c88f1cac35040..34ac96beb5ca3 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -178,6 +178,9 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<' a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) { + if let ty::ReEmpty = a { + return; + } let b = self.to_region_vid(b); let a = self.to_region_vid(a); self.add_outlives(b, a); @@ -190,6 +193,9 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<' a: ty::Region<'tcx>, bound: VerifyBound<'tcx>, ) { + if let ty::ReEmpty = a { + return; + } let type_test = self.verify_to_type_test(kind, a, bound); self.add_type_test(type_test); } diff --git a/src/test/ui/nll/empty-type-predicate-2.rs b/src/test/ui/nll/empty-type-predicate-2.rs new file mode 100644 index 0000000000000..20d6e47f75300 --- /dev/null +++ b/src/test/ui/nll/empty-type-predicate-2.rs @@ -0,0 +1,18 @@ +// Regression test for #65553 +// +// `D::Error:` is lowered to `D::Error: ReEmpty` - check that we don't ICE in +// NLL for the unexpected region. + +// check-pass + +trait Deserializer { + type Error; +} + +fn d1() where D::Error: {} + +fn d2() { + d1::(); +} + +fn main() {} diff --git a/src/test/ui/nll/empty-type-predicate.rs b/src/test/ui/nll/empty-type-predicate.rs index 48073f8749e75..d126a455daeb2 100644 --- a/src/test/ui/nll/empty-type-predicate.rs +++ b/src/test/ui/nll/empty-type-predicate.rs @@ -3,9 +3,9 @@ // `dyn T:` is lowered to `dyn T: ReEmpty` - check that we don't ICE in NLL for // the unexpected region. -// build-pass (FIXME(62277): could be check-pass?) +// check-pass trait T {} fn f() where dyn T: {} -fn main() {} +fn main() { f(); }