From 0b713ae919705bfbc2ec5bf5eea74570f7ecc19a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 13 Aug 2019 23:54:20 +0200 Subject: [PATCH 01/12] typeck: extract ban_private_field_access --- src/librustc_typeck/check/expr.rs | 50 ++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 9680f61d69903..b4154c15d6739 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -24,6 +24,7 @@ use syntax::source_map::Span; use syntax::util::lev_distance::find_best_match_for_name; use rustc::hir; use rustc::hir::{ExprKind, QPath}; +use rustc::hir::def_id::DefId; use rustc::hir::def::{CtorKind, Res, DefKind}; use rustc::hir::ptr::P; use rustc::infer; @@ -1336,23 +1337,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { autoderef.unambiguous_final_ty(self); if let Some((did, field_ty)) = private_candidate { - let struct_path = self.tcx().def_path_str(did); - let mut err = struct_span_err!(self.tcx().sess, expr.span, E0616, - "field `{}` of struct `{}` is private", - field, struct_path); - // Also check if an accessible method exists, which is often what is meant. - if self.method_exists(field, expr_t, expr.hir_id, false) - && !self.expr_in_place(expr.hir_id) - { - self.suggest_method_call( - &mut err, - &format!("a method `{}` also exists, call it with parentheses", field), - field, - expr_t, - expr.hir_id, - ); - } - err.emit(); + self.ban_private_field_access(expr, expr_t, field, did); field_ty } else if field.name == kw::Invalid { self.tcx().types.err @@ -1446,6 +1431,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn ban_private_field_access( + &self, + expr: &'tcx hir::Expr, + expr_t: Ty<'tcx>, + field: ast::Ident, + def_id: DefId, + ) { + let struct_path = self.tcx().def_path_str(def_id); + let mut err = struct_span_err!( + self.tcx().sess, + expr.span, + E0616, + "field `{}` of struct `{}` is private", + field, + struct_path + ); + // Also check if an accessible method exists, which is often what is meant. + if self.method_exists(field, expr_t, expr.hir_id, false) + && !self.expr_in_place(expr.hir_id) + { + self.suggest_method_call( + &mut err, + &format!("a method `{}` also exists, call it with parentheses", field), + field, + expr_t, + expr.hir_id, + ); + } + err.emit(); + } + fn no_such_field_err(&self, span: Span, field: T, expr_t: &ty::TyS<'_>) -> DiagnosticBuilder<'_> { type_error_struct!(self.tcx().sess, span, expr_t, E0609, From 5e019def0d8c277ef7b82d9348350ed1fc8747db Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 13 Aug 2019 23:59:22 +0200 Subject: [PATCH 02/12] typeck: extract ban_take_value_of_method --- src/librustc_typeck/check/expr.rs | 48 +++++++++++++++++++------------ 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index b4154c15d6739..c25a60d065d6b 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1342,23 +1342,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if field.name == kw::Invalid { self.tcx().types.err } else if self.method_exists(field, expr_t, expr.hir_id, true) { - let mut err = type_error_struct!(self.tcx().sess, field.span, expr_t, E0615, - "attempted to take value of method `{}` on type `{}`", - field, expr_t); - - if !self.expr_in_place(expr.hir_id) { - self.suggest_method_call( - &mut err, - "use parentheses to call the method", - field, - expr_t, - expr.hir_id - ); - } else { - err.help("methods are immutable and cannot be assigned to"); - } - - err.emit(); + self.ban_take_value_of_method(expr, expr_t, field); self.tcx().types.err } else { if !expr_t.is_primitive_ty() { @@ -1436,9 +1420,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr, expr_t: Ty<'tcx>, field: ast::Ident, - def_id: DefId, + base_did: DefId, ) { - let struct_path = self.tcx().def_path_str(def_id); + let struct_path = self.tcx().def_path_str(base_did); let mut err = struct_span_err!( self.tcx().sess, expr.span, @@ -1462,6 +1446,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); } + fn ban_take_value_of_method(&self, expr: &'tcx hir::Expr, expr_t: Ty<'tcx>, field: ast::Ident) { + let mut err = type_error_struct!( + self.tcx().sess, + field.span, + expr_t, + E0615, + "attempted to take value of method `{}` on type `{}`", + field, + expr_t + ); + + if !self.expr_in_place(expr.hir_id) { + self.suggest_method_call( + &mut err, + "use parentheses to call the method", + field, + expr_t, + expr.hir_id + ); + } else { + err.help("methods are immutable and cannot be assigned to"); + } + + err.emit(); + } + fn no_such_field_err(&self, span: Span, field: T, expr_t: &ty::TyS<'_>) -> DiagnosticBuilder<'_> { type_error_struct!(self.tcx().sess, span, expr_t, E0609, From 98058468815a62be36875ed0e990bbcbcd4a42b4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 14 Aug 2019 00:30:06 +0200 Subject: [PATCH 03/12] typeck: extract maybe_suggest_array_indexing --- src/librustc_typeck/check/expr.rs | 50 ++++++++++++++++++------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index c25a60d065d6b..20a47441375ba 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1370,25 +1370,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; } ty::Array(_, len) => { - if let (Some(len), Ok(user_index)) = ( - len.try_eval_usize(self.tcx, self.param_env), - field.as_str().parse::() - ) { - let base = self.tcx.sess.source_map() - .span_to_snippet(base.span) - .unwrap_or_else(|_| - self.tcx.hir().hir_to_pretty_string(base.hir_id)); - let help = "instead of using tuple indexing, use array indexing"; - let suggestion = format!("{}[{}]", base, field); - let applicability = if len < user_index { - Applicability::MachineApplicable - } else { - Applicability::MaybeIncorrect - }; - err.span_suggestion( - expr.span, help, suggestion, applicability - ); - } + self.maybe_suggest_array_indexing(&mut err, expr, base, field, len); } ty::RawPtr(..) => { let base = self.tcx.sess.source_map() @@ -1417,7 +1399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn ban_private_field_access( &self, - expr: &'tcx hir::Expr, + expr: &hir::Expr, expr_t: Ty<'tcx>, field: ast::Ident, base_did: DefId, @@ -1446,7 +1428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); } - fn ban_take_value_of_method(&self, expr: &'tcx hir::Expr, expr_t: Ty<'tcx>, field: ast::Ident) { + fn ban_take_value_of_method(&self, expr: &hir::Expr, expr_t: Ty<'tcx>, field: ast::Ident) { let mut err = type_error_struct!( self.tcx().sess, field.span, @@ -1472,6 +1454,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); } + fn maybe_suggest_array_indexing( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr, + base: &hir::Expr, + field: ast::Ident, + len: &ty::Const<'tcx>, + ) { + if let (Some(len), Ok(user_index)) = ( + len.try_eval_usize(self.tcx, self.param_env), + field.as_str().parse::() + ) { + let base = self.tcx.sess.source_map() + .span_to_snippet(base.span) + .unwrap_or_else(|_| self.tcx.hir().hir_to_pretty_string(base.hir_id)); + let help = "instead of using tuple indexing, use array indexing"; + let suggestion = format!("{}[{}]", base, field); + let applicability = if len < user_index { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }; + err.span_suggestion(expr.span, help, suggestion, applicability); + } + } + fn no_such_field_err(&self, span: Span, field: T, expr_t: &ty::TyS<'_>) -> DiagnosticBuilder<'_> { type_error_struct!(self.tcx().sess, span, expr_t, E0609, From 039c78932564c38c79f08745ab6e02bceb1eb468 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 14 Aug 2019 00:31:08 +0200 Subject: [PATCH 04/12] typeck: extract suggest_first_deref_field --- src/librustc_typeck/check/expr.rs | 32 ++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 20a47441375ba..2b696613c8b55 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1373,17 +1373,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.maybe_suggest_array_indexing(&mut err, expr, base, field, len); } ty::RawPtr(..) => { - let base = self.tcx.sess.source_map() - .span_to_snippet(base.span) - .unwrap_or_else(|_| self.tcx.hir().hir_to_pretty_string(base.hir_id)); - let msg = format!("`{}` is a raw pointer; try dereferencing it", base); - let suggestion = format!("(*{}).{}", base, field); - err.span_suggestion( - expr.span, - &msg, - suggestion, - Applicability::MaybeIncorrect, - ); + self.suggest_first_deref_field(&mut err, expr, base, field); } _ => {} } @@ -1480,6 +1470,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn suggest_first_deref_field( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr, + base: &hir::Expr, + field: ast::Ident, + ) { + let base = self.tcx.sess.source_map() + .span_to_snippet(base.span) + .unwrap_or_else(|_| self.tcx.hir().hir_to_pretty_string(base.hir_id)); + let msg = format!("`{}` is a raw pointer; try dereferencing it", base); + let suggestion = format!("(*{}).{}", base, field); + err.span_suggestion( + expr.span, + &msg, + suggestion, + Applicability::MaybeIncorrect, + ); + } + fn no_such_field_err(&self, span: Span, field: T, expr_t: &ty::TyS<'_>) -> DiagnosticBuilder<'_> { type_error_struct!(self.tcx().sess, span, expr_t, E0609, From 01e96dc5832b85f87acb1a651e33d12ac9b37cc5 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 14 Aug 2019 00:40:44 +0200 Subject: [PATCH 05/12] typeck: extract suggest_fields_on_recordish --- src/librustc_typeck/check/expr.rs | 45 ++++++++++++++++++------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 2b696613c8b55..e4582424d0fca 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1350,24 +1350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match expr_t.sty { ty::Adt(def, _) if !def.is_enum() => { - if let Some(suggested_field_name) = - Self::suggest_field_name(def.non_enum_variant(), - &field.as_str(), vec![]) { - err.span_suggestion( - field.span, - "a field with a similar name exists", - suggested_field_name.to_string(), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label(field.span, "unknown field"); - let struct_variant_def = def.non_enum_variant(); - let field_names = self.available_field_names(struct_variant_def); - if !field_names.is_empty() { - err.note(&format!("available fields are: {}", - self.name_series_display(field_names))); - } - }; + self.suggest_fields_on_recordish(&mut err, def, field); } ty::Array(_, len) => { self.maybe_suggest_array_indexing(&mut err, expr, base, field, len); @@ -1444,6 +1427,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); } + fn suggest_fields_on_recordish( + &self, + err: &mut DiagnosticBuilder<'_>, + def: &'tcx ty::AdtDef, + field: ast::Ident, + ) { + if let Some(suggested_field_name) = + Self::suggest_field_name(def.non_enum_variant(), &field.as_str(), vec![]) + { + err.span_suggestion( + field.span, + "a field with a similar name exists", + suggested_field_name.to_string(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_label(field.span, "unknown field"); + let struct_variant_def = def.non_enum_variant(); + let field_names = self.available_field_names(struct_variant_def); + if !field_names.is_empty() { + err.note(&format!("available fields are: {}", + self.name_series_display(field_names))); + } + } + } + fn maybe_suggest_array_indexing( &self, err: &mut DiagnosticBuilder<'_>, From 07414417c58cf9e1ad1d75730007c683bd7dfae7 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 14 Aug 2019 00:50:39 +0200 Subject: [PATCH 06/12] typeck: restructure check_field a bit --- src/librustc_typeck/check/expr.rs | 56 +++++++++++++++++-------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index e4582424d0fca..57e82714150e8 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1338,36 +1338,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some((did, field_ty)) = private_candidate { self.ban_private_field_access(expr, expr_t, field, did); - field_ty - } else if field.name == kw::Invalid { - self.tcx().types.err + return field_ty; + } + + if field.name == kw::Invalid { } else if self.method_exists(field, expr_t, expr.hir_id, true) { self.ban_take_value_of_method(expr, expr_t, field); - self.tcx().types.err - } else { - if !expr_t.is_primitive_ty() { - let mut err = self.no_such_field_err(field.span, field, expr_t); + } else if !expr_t.is_primitive_ty() { + let mut err = self.no_such_field_err(field.span, field, expr_t); - match expr_t.sty { - ty::Adt(def, _) if !def.is_enum() => { - self.suggest_fields_on_recordish(&mut err, def, field); - } - ty::Array(_, len) => { - self.maybe_suggest_array_indexing(&mut err, expr, base, field, len); - } - ty::RawPtr(..) => { - self.suggest_first_deref_field(&mut err, expr, base, field); - } - _ => {} + match expr_t.sty { + ty::Adt(def, _) if !def.is_enum() => { + self.suggest_fields_on_recordish(&mut err, def, field); } - err - } else { - type_error_struct!(self.tcx().sess, field.span, expr_t, E0610, - "`{}` is a primitive type and therefore doesn't have fields", - expr_t) - }.emit(); - self.tcx().types.err + ty::Array(_, len) => { + self.maybe_suggest_array_indexing(&mut err, expr, base, field, len); + } + ty::RawPtr(..) => { + self.suggest_first_deref_field(&mut err, expr, base, field); + } + _ => {} + } + + err.emit(); + } else { + type_error_struct!( + self.tcx().sess, + field.span, + expr_t, + E0610, + "`{}` is a primitive type and therefore doesn't have fields", + expr_t + ) + .emit(); } + + self.tcx().types.err } fn ban_private_field_access( From 88398a429c04ac915fbd314da22c6dc813c275c9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 14 Aug 2019 01:51:41 +0200 Subject: [PATCH 07/12] typeck: on wrong .await suggest -> 2018 --- src/librustc_typeck/check/expr.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 57e82714150e8..d139cd4264c86 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1360,6 +1360,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } + if field.name == kw::Await { + // We know by construction that `.await` is either on Rust 2015 + // or results in `ExprKind::Await`. Suggest switching the edition to 2018. + err.note("to `.await` a `Future`, switch to Rust 2018"); + err.help("set `edition = \"2018\"` in `Cargo.toml`"); + err.note("for more on editions, read https://doc.rust-lang.org/edition-guide"); + } + err.emit(); } else { type_error_struct!( From 9287eb647f7168a65950965044bd5e22d1b05faf Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 14 Aug 2019 01:52:16 +0200 Subject: [PATCH 08/12] typeck: add tests for suggesting -> 2018 on wrong .await --- .../suggest-switching-edition-on-await.rs | 45 +++++++++++++++++++ .../suggest-switching-edition-on-await.stderr | 43 ++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 src/test/ui/async-await/suggest-switching-edition-on-await.rs create mode 100644 src/test/ui/async-await/suggest-switching-edition-on-await.stderr diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await.rs b/src/test/ui/async-await/suggest-switching-edition-on-await.rs new file mode 100644 index 0000000000000..1402f1ca92ba8 --- /dev/null +++ b/src/test/ui/async-await/suggest-switching-edition-on-await.rs @@ -0,0 +1,45 @@ +use std::pin::Pin; +use std::future::Future; + +fn main() {} + +fn await_on_struct_missing() { + struct S; + let x = S; + x.await; + //~^ ERROR no field `await` on type + //~| NOTE unknown field + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP set `edition = "2018"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} + +fn await_on_struct_similar() { + struct S { + awai: u8, + } + let x = S { awai: 42 }; + x.await; + //~^ ERROR no field `await` on type + //~| HELP a field with a similar name exists + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP set `edition = "2018"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} + +fn await_on_63533(x: Pin<&mut dyn Future>) { + x.await; + //~^ ERROR no field `await` on type + //~| NOTE unknown field + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP set `edition = "2018"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} + +fn await_on_apit(x: impl Future) { + x.await; + //~^ ERROR no field `await` on type + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP set `edition = "2018"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr new file mode 100644 index 0000000000000..f623511c0eb23 --- /dev/null +++ b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr @@ -0,0 +1,43 @@ +error[E0609]: no field `await` on type `await_on_struct_missing::S` + --> $DIR/suggest-switching-edition-on-await.rs:9:7 + | +LL | x.await; + | ^^^^^ unknown field + | + = note: to `.await` a `Future`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0609]: no field `await` on type `await_on_struct_similar::S` + --> $DIR/suggest-switching-edition-on-await.rs:22:7 + | +LL | x.await; + | ^^^^^ help: a field with a similar name exists: `awai` + | + = note: to `.await` a `Future`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0609]: no field `await` on type `std::pin::Pin<&mut dyn std::future::Future>` + --> $DIR/suggest-switching-edition-on-await.rs:31:7 + | +LL | x.await; + | ^^^^^ unknown field + | + = note: to `.await` a `Future`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0609]: no field `await` on type `impl Future` + --> $DIR/suggest-switching-edition-on-await.rs:40:7 + | +LL | x.await; + | ^^^^^ + | + = note: to `.await` a `Future`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0609`. From 42728642246154c3977cd58d378548dfffa881b3 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 14 Aug 2019 05:44:32 +0200 Subject: [PATCH 09/12] Feature gate 'yield ?' pre-expansion. --- src/libsyntax/feature_gate.rs | 12 ++++++----- src/libsyntax/parse/lexer/tests.rs | 1 + src/libsyntax/parse/mod.rs | 3 +++ src/libsyntax/parse/parser/expr.rs | 3 +++ .../feature-gates/feature-gate-generators.rs | 6 ++++++ .../feature-gate-generators.stderr | 20 ++++++++++++++++++- 6 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 08a113b53d032..d704c21c95884 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -2088,11 +2088,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "type ascription is experimental"); } } - ast::ExprKind::Yield(..) => { - gate_feature_post!(&self, generators, - e.span, - "yield syntax is experimental"); - } ast::ExprKind::TryBlock(_) => { gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); } @@ -2464,6 +2459,13 @@ pub fn check_crate(krate: &ast::Crate, "async closures are unstable" )); + for_each_in_lock(&sess.yield_spans, |span| gate_feature!( + &ctx, + generators, + *span, + "yield syntax is experimental" + )); + let visitor = &mut PostExpansionVisitor { context: &ctx, builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP, diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs index fc47e4f0b185a..7f66d012356a3 100644 --- a/src/libsyntax/parse/lexer/tests.rs +++ b/src/libsyntax/parse/lexer/tests.rs @@ -34,6 +34,7 @@ fn mk_sess(sm: Lrc) -> ParseSess { param_attr_spans: Lock::new(Vec::new()), let_chains_spans: Lock::new(Vec::new()), async_closure_spans: Lock::new(Vec::new()), + yield_spans: Lock::new(Vec::new()), injected_crate_name: Once::new(), } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 80aa7a35266eb..31757130df18b 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -62,6 +62,8 @@ pub struct ParseSess { pub let_chains_spans: Lock>, // Places where `async || ..` exprs were used and should be feature gated. pub async_closure_spans: Lock>, + // Places where `yield e?` exprs were used and should be feature gated. + pub yield_spans: Lock>, pub injected_crate_name: Once, } @@ -91,6 +93,7 @@ impl ParseSess { param_attr_spans: Lock::new(Vec::new()), let_chains_spans: Lock::new(Vec::new()), async_closure_spans: Lock::new(Vec::new()), + yield_spans: Lock::new(Vec::new()), injected_crate_name: Once::new(), } } diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 4432c1329cbfe..3101acd5dcb09 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -993,6 +993,9 @@ impl<'a> Parser<'a> { } else { ex = ExprKind::Yield(None); } + + let span = lo.to(hi); + self.sess.yield_spans.borrow_mut().push(span); } else if self.eat_keyword(kw::Let) { return self.parse_let_expr(attrs); } else if is_span_rust_2018 && self.eat_keyword(kw::Await) { diff --git a/src/test/ui/feature-gates/feature-gate-generators.rs b/src/test/ui/feature-gates/feature-gate-generators.rs index cee930fd785b9..382d891feed84 100644 --- a/src/test/ui/feature-gates/feature-gate-generators.rs +++ b/src/test/ui/feature-gates/feature-gate-generators.rs @@ -2,3 +2,9 @@ fn main() { yield true; //~ ERROR yield syntax is experimental //~^ ERROR yield statement outside of generator literal } + +#[cfg(FALSE)] +fn foo() { + yield; //~ ERROR yield syntax is experimental + yield 0; //~ ERROR yield syntax is experimental +} diff --git a/src/test/ui/feature-gates/feature-gate-generators.stderr b/src/test/ui/feature-gates/feature-gate-generators.stderr index cdb056012542b..24b814b410c9d 100644 --- a/src/test/ui/feature-gates/feature-gate-generators.stderr +++ b/src/test/ui/feature-gates/feature-gate-generators.stderr @@ -7,12 +7,30 @@ LL | yield true; = note: for more information, see https://github.com/rust-lang/rust/issues/43122 = help: add `#![feature(generators)]` to the crate attributes to enable +error[E0658]: yield syntax is experimental + --> $DIR/feature-gate-generators.rs:8:5 + | +LL | yield; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/43122 + = help: add `#![feature(generators)]` to the crate attributes to enable + +error[E0658]: yield syntax is experimental + --> $DIR/feature-gate-generators.rs:9:5 + | +LL | yield 0; + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/43122 + = help: add `#![feature(generators)]` to the crate attributes to enable + error[E0627]: yield statement outside of generator literal --> $DIR/feature-gate-generators.rs:2:5 | LL | yield true; | ^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0658`. From 4fe201cc117a30c19e41affd32f699d094d87718 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 14 Aug 2019 06:09:11 +0200 Subject: [PATCH 10/12] Simplify pre-expansion gating in general. --- src/libsyntax/feature_gate.rs | 42 +++++++++-------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d704c21c95884..d77baa9f8720e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -30,7 +30,6 @@ use crate::tokenstream::TokenTree; use errors::{Applicability, DiagnosticBuilder, Handler}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::Lock; use rustc_target::spec::abi::Abi; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use log::debug; @@ -2422,10 +2421,6 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], features } -fn for_each_in_lock(vec: &Lock>, f: impl Fn(&T)) { - vec.borrow().iter().for_each(f); -} - pub fn check_crate(krate: &ast::Crate, sess: &ParseSess, features: &Features, @@ -2438,33 +2433,16 @@ pub fn check_crate(krate: &ast::Crate, plugin_attributes, }; - for_each_in_lock(&sess.param_attr_spans, |span| gate_feature!( - &ctx, - param_attrs, - *span, - "attributes on function parameters are unstable" - )); - - for_each_in_lock(&sess.let_chains_spans, |span| gate_feature!( - &ctx, - let_chains, - *span, - "`let` expressions in this position are experimental" - )); - - for_each_in_lock(&sess.async_closure_spans, |span| gate_feature!( - &ctx, - async_closure, - *span, - "async closures are unstable" - )); - - for_each_in_lock(&sess.yield_spans, |span| gate_feature!( - &ctx, - generators, - *span, - "yield syntax is experimental" - )); + macro_rules! gate_all { + ($spans:ident, $gate:ident, $msg:literal) => { + for span in &*sess.$spans.borrow() { gate_feature!(&ctx, $gate, *span, $msg); } + } + } + + gate_all!(param_attr_spans, param_attrs, "attributes on function parameters are unstable"); + gate_all!(let_chains_spans, let_chains, "`let` expressions in this position are experimental"); + gate_all!(async_closure_spans, async_closure, "async closures are unstable"); + gate_all!(yield_spans, generators, "yield syntax is experimental"); let visitor = &mut PostExpansionVisitor { context: &ctx, From 1ab9e523f37bdc156bb9ab9d8b52749bc428437c Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 14 Aug 2019 10:35:24 +0300 Subject: [PATCH 11/12] Update rustc-demangle to 0.1.16. --- Cargo.lock | 8 ++++---- src/librustc_codegen_utils/Cargo.toml | 2 +- src/test/ui/symbol-names/issue-60925.legacy.stderr | 4 ++-- src/test/ui/symbol-names/issue-60925.rs | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab6731e4d433d..02a5876243be9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,7 +106,7 @@ dependencies = [ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -2736,7 +2736,7 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2894,7 +2894,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "punycode 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", "rustc_metadata 0.0.0", "rustc_target 0.0.0", @@ -4600,7 +4600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-ap-serialize 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61673783f2089e01033ffa82d1988f55175402071b31253a358292e1624d4602" "checksum rustc-ap-syntax 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28f3dd1346d5b0269c07a4a78855e309a298ab569c9c1302d4d4f57f8eee4e84" "checksum rustc-ap-syntax_pos 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45e67b526dbda3a0c7dab91c8947d43685e7697f52686a4949da3c179cd7c979" -"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" +"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2e07e19601f21c59aad953c2632172ba70cb27e685771514ea66e4062b3363" "checksum rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79d38ca7cbc22fa59f09d8534ea4b27f67b0facf0cbe274433aceea227a02543" diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index d93589ea84be0..89b50c5daccae 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -13,7 +13,7 @@ test = false flate2 = "1.0" log = "0.4" punycode = "0.4.0" -rustc-demangle = "0.1.15" +rustc-demangle = "0.1.16" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr index 7fcd2ede31b69..de8efdde737f0 100644 --- a/src/test/ui/symbol-names/issue-60925.legacy.stderr +++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr @@ -4,13 +4,13 @@ error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3f LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo::foo::h059a991a004536ad) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling-alt(issue_60925::foo::Foo::foo) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/issue-60925.rs b/src/test/ui/symbol-names/issue-60925.rs index 89de15cc0f3e4..02438351dbc6e 100644 --- a/src/test/ui/symbol-names/issue-60925.rs +++ b/src/test/ui/symbol-names/issue-60925.rs @@ -20,8 +20,8 @@ mod foo { impl Foo<::llvm::Foo> { #[rustc_symbol_name] //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo - //[legacy]~| ERROR demangling(issue_60925::foo::Foo::foo + //[legacy]~| ERROR demangling-alt(issue_60925::foo::Foo::foo) //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo) //[v0]~| ERROR demangling(>::foo) //[v0]~| ERROR demangling-alt(>::foo) From 5941acd80faaf9043cb48737c47d0b94023eddc3 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Tue, 30 Jul 2019 16:31:26 -0300 Subject: [PATCH 12/12] Use libunwind from llvm-project submodule for musl targets --- src/bootstrap/sanity.rs | 4 ---- src/ci/docker/scripts/musl-toolchain.sh | 26 ------------------------- src/ci/docker/scripts/musl.sh | 26 ++----------------------- src/libunwind/Cargo.toml | 4 ++-- src/libunwind/build.rs | 16 +++++++++++---- 5 files changed, 16 insertions(+), 60 deletions(-) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 4e3930c8da7fc..bffe748f37cc1 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -202,10 +202,6 @@ pub fn check(build: &mut Build) { panic!("couldn't find libc.a in musl dir: {}", root.join("lib").display()); } - if fs::metadata(root.join("lib/libunwind.a")).is_err() { - panic!("couldn't find libunwind.a in musl dir: {}", - root.join("lib").display()); - } } None => { panic!("when targeting MUSL either the rust.musl-root \ diff --git a/src/ci/docker/scripts/musl-toolchain.sh b/src/ci/docker/scripts/musl-toolchain.sh index 55899fa6c3e69..74ba2f0eadb25 100644 --- a/src/ci/docker/scripts/musl-toolchain.sh +++ b/src/ci/docker/scripts/musl-toolchain.sh @@ -54,29 +54,3 @@ if [ "$REPLACE_CC" = "1" ]; then ln -s $TARGET-g++ /usr/local/bin/$exec done fi - -export CC=$TARGET-gcc -export CXX=$TARGET-g++ - -LLVM=70 - -# may have been downloaded in a previous run -if [ ! -d libunwind-release_$LLVM ]; then - curl -L https://github.com/llvm-mirror/llvm/archive/release_$LLVM.tar.gz | tar xzf - - curl -L https://github.com/llvm-mirror/libunwind/archive/release_$LLVM.tar.gz | tar xzf - -fi - -# fixme(mati865): Replace it with https://github.com/rust-lang/rust/pull/59089 -mkdir libunwind-build -cd libunwind-build -cmake ../libunwind-release_$LLVM \ - -DLLVM_PATH=/build/llvm-release_$LLVM \ - -DLIBUNWIND_ENABLE_SHARED=0 \ - -DCMAKE_C_COMPILER=$CC \ - -DCMAKE_CXX_COMPILER=$CXX \ - -DCMAKE_C_FLAGS="$CFLAGS" \ - -DCMAKE_CXX_FLAGS="$CXXFLAGS" - -hide_output make -j$(nproc) -cp lib/libunwind.a $OUTPUT/$TARGET/lib -cd - && rm -rf libunwind-build diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh index c2cf77d56cb3b..d847c407aba67 100644 --- a/src/ci/docker/scripts/musl.sh +++ b/src/ci/docker/scripts/musl.sh @@ -20,6 +20,8 @@ exit 1 TAG=$1 shift +# Ancient binutils versions don't understand debug symbols produced by more recent tools. +# Apparently applying `-fPIC` everywhere allows them to link successfully. export CFLAGS="-fPIC $CFLAGS" MUSL=musl-1.1.22 @@ -38,27 +40,3 @@ else fi hide_output make install hide_output make clean - -cd .. - -LLVM=70 - -# may have been downloaded in a previous run -if [ ! -d libunwind-release_$LLVM ]; then - curl -L https://github.com/llvm-mirror/llvm/archive/release_$LLVM.tar.gz | tar xzf - - curl -L https://github.com/llvm-mirror/libunwind/archive/release_$LLVM.tar.gz | tar xzf - -fi - -mkdir libunwind-build -cd libunwind-build -cmake ../libunwind-release_$LLVM \ - -DLLVM_PATH=/build/llvm-release_$LLVM \ - -DLIBUNWIND_ENABLE_SHARED=0 \ - -DCMAKE_C_COMPILER=$CC \ - -DCMAKE_CXX_COMPILER=$CXX \ - -DCMAKE_C_FLAGS="$CFLAGS" \ - -DCMAKE_CXX_FLAGS="$CXXFLAGS" - -hide_output make -j$(nproc) -cp lib/libunwind.a /musl-$TAG/lib -cd ../ && rm -rf libunwind-build diff --git a/src/libunwind/Cargo.toml b/src/libunwind/Cargo.toml index f0f1bab425d7a..f10df8c85ba0a 100644 --- a/src/libunwind/Cargo.toml +++ b/src/libunwind/Cargo.toml @@ -22,7 +22,7 @@ compiler_builtins = "0.1.0" cfg-if = "0.1.8" [build-dependencies] -cc = { optional = true, version = "1.0.1" } +cc = { version = "1.0.1" } [features] -llvm-libunwind = ["cc"] +llvm-libunwind = [] diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index c1b0dbc0881d3..a266407c60294 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -5,14 +5,14 @@ fn main() { let target = env::var("TARGET").expect("TARGET was not set"); if cfg!(feature = "llvm-libunwind") && - (target.contains("linux") || + ((target.contains("linux") && !target.contains("musl")) || target.contains("fuchsia")) { // Build the unwinding from libunwind C/C++ source code. - #[cfg(feature = "llvm-libunwind")] llvm_libunwind::compile(); } else if target.contains("linux") { if target.contains("musl") { - // musl is handled in lib.rs + // linking for musl is handled in lib.rs + llvm_libunwind::compile(); } else if !target.contains("android") { println!("cargo:rustc-link-lib=gcc_s"); } @@ -44,7 +44,6 @@ fn main() { } } -#[cfg(feature = "llvm-libunwind")] mod llvm_libunwind { use std::env; use std::path::Path; @@ -96,6 +95,15 @@ mod llvm_libunwind { cfg.file(root.join("src").join(src)); } + if target_env == "musl" { + // use the same C compiler command to compile C++ code so we do not need to setup the + // C++ compiler env variables on the builders + cfg.cpp(false); + // linking for musl is handled in lib.rs + cfg.cargo_metadata(false); + println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap()); + } + cfg.compile("unwind"); } }