about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs2
-rw-r--r--compiler/rustc_errors/src/lib.rs13
-rw-r--r--compiler/rustc_hir/src/hir.rs59
-rw-r--r--compiler/rustc_interface/src/tests.rs3
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs15
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/liveness.rs2
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/validation.rs23
-rw-r--r--compiler/rustc_mir/src/transform/simplify.rs3
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs2
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs2
-rw-r--r--compiler/rustc_session/src/config.rs2
-rw-r--r--compiler/rustc_session/src/options.rs9
-rw-r--r--compiler/rustc_span/src/symbol.rs6
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs24
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs2
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs16
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs4
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs39
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs100
20 files changed, 268 insertions, 59 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index fd0ff5b66e6..289629d9215 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -199,7 +199,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
             }
 
             self.visit_local(&place_ref.local, context, location);
-            self.visit_projection(place_ref.local, place_ref.projection, context, location);
+            self.visit_projection(*place_ref, context, location);
         }
     }
 }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 9800ed9bfa9..a0be7442d59 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -30,6 +30,7 @@ use rustc_span::{Loc, MultiSpan, Span};
 
 use std::borrow::Cow;
 use std::hash::{Hash, Hasher};
+use std::num::NonZeroUsize;
 use std::panic;
 use std::path::Path;
 use std::{error, fmt};
@@ -359,7 +360,7 @@ pub struct HandlerFlags {
     pub can_emit_warnings: bool,
     /// If true, error-level diagnostics are upgraded to bug-level.
     /// (rustc: see `-Z treat-err-as-bug`)
-    pub treat_err_as_bug: Option<usize>,
+    pub treat_err_as_bug: Option<NonZeroUsize>,
     /// If true, immediately emit diagnostics that would otherwise be buffered.
     /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
     pub dont_buffer_diagnostics: bool,
@@ -396,7 +397,7 @@ impl Handler {
     pub fn with_tty_emitter(
         color_config: ColorConfig,
         can_emit_warnings: bool,
-        treat_err_as_bug: Option<usize>,
+        treat_err_as_bug: Option<NonZeroUsize>,
         sm: Option<Lrc<SourceMap>>,
     ) -> Self {
         Self::with_tty_emitter_and_flags(
@@ -424,7 +425,7 @@ impl Handler {
 
     pub fn with_emitter(
         can_emit_warnings: bool,
-        treat_err_as_bug: Option<usize>,
+        treat_err_as_bug: Option<NonZeroUsize>,
         emitter: Box<dyn Emitter + sync::Send>,
     ) -> Self {
         Handler::with_emitter_and_flags(
@@ -841,7 +842,7 @@ impl HandlerInner {
     }
 
     fn treat_err_as_bug(&self) -> bool {
-        self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c)
+        self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c.get())
     }
 
     fn print_error_count(&mut self, registry: &Registry) {
@@ -950,7 +951,7 @@ impl HandlerInner {
         // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
         // incrementing `err_count` by one, so we need to +1 the comparing.
         // FIXME: Would be nice to increment err_count in a more coherent way.
-        if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c) {
+        if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c.get()) {
             // FIXME: don't abort here if report_delayed_bugs is off
             self.span_bug(sp, msg);
         }
@@ -1023,7 +1024,7 @@ impl HandlerInner {
 
     fn panic_if_treat_err_as_bug(&self) {
         if self.treat_err_as_bug() {
-            match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) {
+            match (self.err_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0)) {
                 (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
                 (0, _) | (1, _) => {}
                 (count, as_bug) => panic!(
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 61586dd1a1c..2fef7c2cc08 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,5 +1,5 @@
 // ignore-tidy-filelength
-use crate::def::{DefKind, Namespace, Res};
+use crate::def::{CtorKind, DefKind, Namespace, Res};
 use crate::def_id::DefId;
 crate use crate::hir_id::HirId;
 use crate::{itemlikevisit, LangItem};
@@ -1576,6 +1576,63 @@ impl Expr<'_> {
         }
         expr
     }
+
+    pub fn can_have_side_effects(&self) -> bool {
+        match self.peel_drop_temps().kind {
+            ExprKind::Path(_) | ExprKind::Lit(_) => false,
+            ExprKind::Type(base, _)
+            | ExprKind::Unary(_, base)
+            | ExprKind::Field(base, _)
+            | ExprKind::Index(base, _)
+            | ExprKind::AddrOf(.., base)
+            | ExprKind::Cast(base, _) => {
+                // This isn't exactly true for `Index` and all `Unnary`, but we are using this
+                // method exclusively for diagnostics and there's a *cultural* pressure against
+                // them being used only for its side-effects.
+                base.can_have_side_effects()
+            }
+            ExprKind::Struct(_, fields, init) => fields
+                .iter()
+                .map(|field| field.expr)
+                .chain(init.into_iter())
+                .all(|e| e.can_have_side_effects()),
+
+            ExprKind::Array(args)
+            | ExprKind::Tup(args)
+            | ExprKind::Call(
+                Expr {
+                    kind:
+                        ExprKind::Path(QPath::Resolved(
+                            None,
+                            Path { res: Res::Def(DefKind::Ctor(_, CtorKind::Fn), _), .. },
+                        )),
+                    ..
+                },
+                args,
+            ) => args.iter().all(|arg| arg.can_have_side_effects()),
+            ExprKind::If(..)
+            | ExprKind::Match(..)
+            | ExprKind::MethodCall(..)
+            | ExprKind::Call(..)
+            | ExprKind::Closure(..)
+            | ExprKind::Block(..)
+            | ExprKind::Repeat(..)
+            | ExprKind::Break(..)
+            | ExprKind::Continue(..)
+            | ExprKind::Ret(..)
+            | ExprKind::Loop(..)
+            | ExprKind::Assign(..)
+            | ExprKind::InlineAsm(..)
+            | ExprKind::LlvmInlineAsm(..)
+            | ExprKind::AssignOp(..)
+            | ExprKind::ConstBlock(..)
+            | ExprKind::Box(..)
+            | ExprKind::Binary(..)
+            | ExprKind::Yield(..)
+            | ExprKind::DropTemps(..)
+            | ExprKind::Err => true,
+        }
+    }
 }
 
 /// Checks if the specified expression is a built-in range literal.
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index f9c3406d3b3..a2e96146568 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -20,6 +20,7 @@ use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy}
 use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TlsModel};
 use std::collections::{BTreeMap, BTreeSet};
 use std::iter::FromIterator;
+use std::num::NonZeroUsize;
 use std::path::{Path, PathBuf};
 
 type CfgSpecs = FxHashSet<(String, Option<String>)>;
@@ -595,7 +596,7 @@ fn test_debugging_options_tracking_hash() {
     tracked!(tune_cpu, Some(String::from("abc")));
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
     tracked!(trap_unreachable, Some(false));
-    tracked!(treat_err_as_bug, Some(1));
+    tracked!(treat_err_as_bug, NonZeroUsize::new(1));
     tracked!(unleash_the_miri_inside_of_you, true);
     tracked!(use_ctors_section, Some(true));
     tracked!(verify_llvm_ir, true);
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 023555d91cc..9530efaedbc 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -998,12 +998,11 @@ macro_rules! visit_place_fns {
     () => {
         fn visit_projection(
             &mut self,
-            local: Local,
-            projection: &[PlaceElem<'tcx>],
+            place_ref: PlaceRef<'tcx>,
             context: PlaceContext,
             location: Location,
         ) {
-            self.super_projection(local, projection, context, location);
+            self.super_projection(place_ref, context, location);
         }
 
         fn visit_projection_elem(
@@ -1033,20 +1032,20 @@ macro_rules! visit_place_fns {
 
             self.visit_local(&place.local, context, location);
 
-            self.visit_projection(place.local, &place.projection, context, location);
+            self.visit_projection(place.as_ref(), context, location);
         }
 
         fn super_projection(
             &mut self,
-            local: Local,
-            projection: &[PlaceElem<'tcx>],
+            place_ref: PlaceRef<'tcx>,
             context: PlaceContext,
             location: Location,
         ) {
-            let mut cursor = projection;
+            // FIXME: Use PlaceRef::iter_projections, once that exists.
+            let mut cursor = place_ref.projection;
             while let &[ref proj_base @ .., elem] = cursor {
                 cursor = proj_base;
-                self.visit_projection_elem(local, cursor, elem, context, location);
+                self.visit_projection_elem(place_ref.local, cursor, elem, context, location);
             }
         }
 
diff --git a/compiler/rustc_mir/src/dataflow/impls/liveness.rs b/compiler/rustc_mir/src/dataflow/impls/liveness.rs
index 85aaff5ab72..2d20f0d9547 100644
--- a/compiler/rustc_mir/src/dataflow/impls/liveness.rs
+++ b/compiler/rustc_mir/src/dataflow/impls/liveness.rs
@@ -95,7 +95,7 @@ where
 
         // We purposefully do not call `super_place` here to avoid calling `visit_local` for this
         // place with one of the `Projection` variants of `PlaceContext`.
-        self.visit_projection(local, projection, context, location);
+        self.visit_projection(place.as_ref(), context, location);
 
         match DefUse::for_place(context) {
             // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use.
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index 4973450ca83..a8263683712 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -515,7 +515,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
         // Special-case reborrows to be more like a copy of a reference.
         match *rvalue {
             Rvalue::Ref(_, kind, place) => {
-                if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, self.body, place) {
+                if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) {
                     let ctx = match kind {
                         BorrowKind::Shared => {
                             PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
@@ -530,21 +530,21 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                             PlaceContext::MutatingUse(MutatingUseContext::Borrow)
                         }
                     };
-                    self.visit_local(&place.local, ctx, location);
-                    self.visit_projection(place.local, reborrowed_proj, ctx, location);
+                    self.visit_local(&reborrowed_place_ref.local, ctx, location);
+                    self.visit_projection(reborrowed_place_ref, ctx, location);
                     return;
                 }
             }
             Rvalue::AddressOf(mutbl, place) => {
-                if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, self.body, place) {
+                if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) {
                     let ctx = match mutbl {
                         Mutability::Not => {
                             PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
                         }
                         Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf),
                     };
-                    self.visit_local(&place.local, ctx, location);
-                    self.visit_projection(place.local, reborrowed_proj, ctx, location);
+                    self.visit_local(&reborrowed_place_ref.local, ctx, location);
+                    self.visit_projection(reborrowed_place_ref, ctx, location);
                     return;
                 }
             }
@@ -1039,7 +1039,7 @@ fn place_as_reborrow(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     place: Place<'tcx>,
-) -> Option<&'a [PlaceElem<'tcx>]> {
+) -> Option<PlaceRef<'tcx>> {
     match place.as_ref().last_projection() {
         Some((place_base, ProjectionElem::Deref)) => {
             // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
@@ -1048,13 +1048,14 @@ fn place_as_reborrow(
                 None
             } else {
                 // Ensure the type being derefed is a reference and not a raw pointer.
-                //
                 // This is sufficient to prevent an access to a `static mut` from being marked as a
                 // reborrow, even if the check above were to disappear.
                 let inner_ty = place_base.ty(body, tcx).ty;
-                match inner_ty.kind() {
-                    ty::Ref(..) => Some(place_base.projection),
-                    _ => None,
+
+                if let ty::Ref(..) = inner_ty.kind() {
+                    return Some(place_base);
+                } else {
+                    return None;
                 }
             }
         }
diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs
index 11539d3ef30..ae4f15b3bbc 100644
--- a/compiler/rustc_mir/src/transform/simplify.rs
+++ b/compiler/rustc_mir/src/transform/simplify.rs
@@ -413,8 +413,7 @@ impl UsedLocals {
         } else {
             // A definition. Although, it still might use other locals for indexing.
             self.super_projection(
-                place.local,
-                &place.projection,
+                place.as_ref(),
                 PlaceContext::MutatingUse(MutatingUseContext::Projection),
                 location,
             );
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 1292286bc18..8a097bf481d 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -950,7 +950,7 @@ impl<'a> Parser<'a> {
             self.bump();
             Ok(Ident::new(symbol, self.prev_token.span))
         } else {
-            self.parse_ident_common(false)
+            self.parse_ident_common(true)
         }
     }
 
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 8874548da78..9e2e7359ca9 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1028,7 +1028,7 @@ impl<'a> Parser<'a> {
             let boxed_span = self.token.span;
             let is_ref = self.eat_keyword(kw::Ref);
             let is_mut = self.eat_keyword(kw::Mut);
-            let fieldname = self.parse_ident()?;
+            let fieldname = self.parse_field_name()?;
             hi = self.prev_token.span;
 
             let bind_type = match (is_ref, is_mut) {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 4533b37f10b..e4f7e140281 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -2313,6 +2313,7 @@ crate mod dep_tracking {
     use std::collections::hash_map::DefaultHasher;
     use std::collections::BTreeMap;
     use std::hash::Hash;
+    use std::num::NonZeroUsize;
     use std::path::PathBuf;
 
     pub trait DepTrackingHash {
@@ -2353,6 +2354,7 @@ crate mod dep_tracking {
     impl_dep_tracking_hash_via_hash!(lint::Level);
     impl_dep_tracking_hash_via_hash!(Option<bool>);
     impl_dep_tracking_hash_via_hash!(Option<usize>);
+    impl_dep_tracking_hash_via_hash!(Option<NonZeroUsize>);
     impl_dep_tracking_hash_via_hash!(Option<String>);
     impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
     impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index baa0502521d..d439753d042 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -16,6 +16,7 @@ use std::collections::BTreeMap;
 
 use std::collections::hash_map::DefaultHasher;
 use std::hash::Hasher;
+use std::num::NonZeroUsize;
 use std::path::PathBuf;
 use std::str;
 
@@ -591,10 +592,10 @@ macro_rules! options {
             true
         }
 
-        fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
+        fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
             match v {
-                Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
-                None => { *slot = Some(1); true }
+                Some(s) => { *slot = s.parse().ok(); slot.is_some() }
+                None => { *slot = NonZeroUsize::new(1); true }
             }
         }
 
@@ -1141,7 +1142,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "for every macro invocation, print its name and arguments (default: no)"),
     trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
-    treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
+    treat_err_as_bug: Option<NonZeroUsize> = (None, parse_treat_err_as_bug, [TRACKED],
         "treat error number `val` that occurs as bug"),
     trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
         "in diagnostics, use heuristics to shorten paths referring to items"),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 653d70b6cf2..4ed0262bf2c 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -169,10 +169,14 @@ symbols! {
         Option,
         Ord,
         Ordering,
+        OsStr,
+        OsString,
         Output,
         Param,
         PartialEq,
         PartialOrd,
+        Path,
+        PathBuf,
         Pending,
         Pin,
         Poll,
@@ -198,6 +202,8 @@ symbols! {
         StructuralPartialEq,
         Sync,
         Target,
+        ToOwned,
+        ToString,
         Try,
         Ty,
         TyCtxt,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index ae803dbdb31..6cf1112820d 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -641,6 +641,7 @@ supported_targets! {
     ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
     ("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl),
     ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
+    ("s390x-unknown-linux-musl", s390x_unknown_linux_musl),
     ("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu),
     ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
     ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs
new file mode 100644
index 00000000000..4f811ce98c1
--- /dev/null
+++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs
@@ -0,0 +1,24 @@
+use crate::abi::Endian;
+use crate::spec::Target;
+
+pub fn target() -> Target {
+    let mut base = super::linux_musl_base::opts();
+    base.endian = Endian::Big;
+    // z10 is the oldest CPU supported by LLVM
+    base.cpu = "z10".to_string();
+    // FIXME: The data_layout string below and the ABI implementation in
+    // cabi_s390x.rs are for now hard-coded to assume the no-vector ABI.
+    // Pass the -vector feature string to LLVM to respect this assumption.
+    base.features = "-vector".to_string();
+    base.max_atomic_width = Some(64);
+    base.min_global_align = Some(16);
+    base.static_position_independent_executables = true;
+
+    Target {
+        llvm_target: "s390x-unknown-linux-musl".to_string(),
+        pointer_width: 64,
+        data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64".to_string(),
+        arch: "s390x".to_string(),
+        options: base,
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index 4836418b3c2..f2fbb95fc02 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -346,7 +346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             if call_is_multiline {
                                 err.span_suggestion(
                                     callee.span.shrink_to_hi(),
-                                    "try adding a semicolon",
+                                    "consider using a semicolon here",
                                     ";".to_owned(),
                                     Applicability::MaybeIncorrect,
                                 );
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index b2395b7bb25..159c97d8bfa 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -1450,7 +1450,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             ) {
                 if cond_expr.span.desugaring_kind().is_none() {
                     err.span_label(cond_expr.span, "expected this to be `()`");
-                    fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
+                    if expr.can_have_side_effects() {
+                        fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
+                    }
                 }
             }
             fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
@@ -1458,7 +1460,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             fcx.get_fn_decl(parent_id)
         };
 
-        if let (Some((fn_decl, can_suggest)), _) = (fn_decl, pointing_at_return_type) {
+        if let Some((fn_decl, can_suggest)) = fn_decl {
             if expression.is_none() {
                 pointing_at_return_type |= fcx.suggest_missing_return_type(
                     &mut err,
@@ -1472,6 +1474,16 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 fn_output = Some(&fn_decl.output); // `impl Trait` return type
             }
         }
+
+        let parent_id = fcx.tcx.hir().get_parent_item(id);
+        let parent_item = fcx.tcx.hir().get(parent_id);
+
+        if let (Some((expr, _)), Some((fn_decl, _, _))) =
+            (expression, fcx.get_node_fn_decl(parent_item))
+        {
+            fcx.suggest_missing_return_expr(&mut err, expr, fn_decl, expected, found);
+        }
+
         if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {
             self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
         }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 3326be796ce..155c10e8916 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -561,7 +561,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             hir::StmtKind::Expr(ref expr) => {
                 // Check with expected type of `()`.
                 self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
-                    self.suggest_semicolon_at_end(expr.span, err);
+                    if expr.can_have_side_effects() {
+                        self.suggest_semicolon_at_end(expr.span, err);
+                    }
                 });
             }
             hir::StmtKind::Semi(ref expr) => {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index a0465ca6aef..416b75d9e2e 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -44,11 +44,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         blk_id: hir::HirId,
     ) -> bool {
         let expr = expr.peel_drop_temps();
-        self.suggest_missing_semicolon(err, expr, expected, cause_span);
+        if expr.can_have_side_effects() {
+            self.suggest_missing_semicolon(err, expr, expected, cause_span);
+        }
         let mut pointing_at_return_type = false;
         if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
             pointing_at_return_type =
                 self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
+            self.suggest_missing_return_expr(err, expr, &fn_decl, expected, found);
         }
         pointing_at_return_type
     }
@@ -392,10 +395,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 | ExprKind::Loop(..)
                 | ExprKind::If(..)
                 | ExprKind::Match(..)
-                | ExprKind::Block(..) => {
+                | ExprKind::Block(..)
+                    if expression.can_have_side_effects() =>
+                {
                     err.span_suggestion(
                         cause_span.shrink_to_hi(),
-                        "try adding a semicolon",
+                        "consider using a semicolon here",
                         ";".to_string(),
                         Applicability::MachineApplicable,
                     );
@@ -464,6 +469,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    pub(in super::super) fn suggest_missing_return_expr(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &'tcx hir::Expr<'tcx>,
+        fn_decl: &hir::FnDecl<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        if !expected.is_unit() {
+            return;
+        }
+        let found = self.resolve_vars_with_obligations(found);
+        if let hir::FnRetTy::Return(ty) = fn_decl.output {
+            let ty = AstConv::ast_ty_to_ty(self, ty);
+            let ty = self.normalize_associated_types_in(expr.span, ty);
+            if self.can_coerce(found, ty) {
+                err.multipart_suggestion(
+                    "you might have meant to return this value",
+                    vec![
+                        (expr.span.shrink_to_lo(), "return ".to_string()),
+                        (expr.span.shrink_to_hi(), ";".to_string()),
+                    ],
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+    }
+
     pub(in super::super) fn suggest_missing_parentheses(
         &self,
         err: &mut DiagnosticBuilder<'_>,
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 5df00ea1d75..897b1f01569 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -17,6 +17,7 @@ use rustc_span::source_map::{Span, Spanned};
 use rustc_span::symbol::Ident;
 use rustc_span::{BytePos, DUMMY_SP};
 use rustc_trait_selection::traits::{ObligationCause, Pattern};
+use ty::VariantDef;
 
 use std::cmp;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
@@ -1264,14 +1265,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     u.emit();
                 }
             }
-            (None, Some(mut err)) | (Some(mut err), None) => {
+            (None, Some(mut u)) => {
+                if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
+                    u.delay_as_bug();
+                    e.emit();
+                } else {
+                    u.emit();
+                }
+            }
+            (Some(mut err), None) => {
                 err.emit();
             }
-            (None, None) => {}
+            (None, None) => {
+                if let Some(mut err) =
+                    self.error_tuple_variant_index_shorthand(variant, pat, fields)
+                {
+                    err.emit();
+                }
+            }
         }
         no_field_errors
     }
 
+    fn error_tuple_variant_index_shorthand(
+        &self,
+        variant: &VariantDef,
+        pat: &'_ Pat<'_>,
+        fields: &[hir::FieldPat<'_>],
+    ) -> Option<DiagnosticBuilder<'_>> {
+        // if this is a tuple struct, then all field names will be numbers
+        // so if any fields in a struct pattern use shorthand syntax, they will
+        // be invalid identifiers (for example, Foo { 0, 1 }).
+        if let (CtorKind::Fn, PatKind::Struct(qpath, field_patterns, ..)) =
+            (variant.ctor_kind, &pat.kind)
+        {
+            let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
+            if has_shorthand_field_name {
+                let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
+                    s.print_qpath(qpath, false)
+                });
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    pat.span,
+                    E0769,
+                    "tuple variant `{}` written as struct variant",
+                    path
+                );
+                err.span_suggestion_verbose(
+                    qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
+                    "use the tuple variant pattern syntax instead",
+                    format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)),
+                    Applicability::MaybeIncorrect,
+                );
+                return Some(err);
+            }
+        }
+        None
+    }
+
     fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) {
         let sess = self.tcx.sess;
         let sm = sess.source_map();
@@ -1411,16 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
             let (sugg, appl) = if fields.len() == variant.fields.len() {
                 (
-                    fields
-                        .iter()
-                        .map(|f| match self.tcx.sess.source_map().span_to_snippet(f.pat.span) {
-                            Ok(f) => f,
-                            Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
-                                s.print_pat(f.pat)
-                            }),
-                        })
-                        .collect::<Vec<String>>()
-                        .join(", "),
+                    self.get_suggested_tuple_struct_pattern(fields, variant),
                     Applicability::MachineApplicable,
                 )
             } else {
@@ -1429,10 +1471,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     Applicability::MaybeIncorrect,
                 )
             };
-            err.span_suggestion(
-                pat.span,
+            err.span_suggestion_verbose(
+                qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
                 "use the tuple variant pattern syntax instead",
-                format!("{}({})", path, sugg),
+                format!("({})", sugg),
                 appl,
             );
             return Some(err);
@@ -1440,6 +1482,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         None
     }
 
+    fn get_suggested_tuple_struct_pattern(
+        &self,
+        fields: &[hir::FieldPat<'_>],
+        variant: &VariantDef,
+    ) -> String {
+        let variant_field_idents = variant.fields.iter().map(|f| f.ident).collect::<Vec<Ident>>();
+        fields
+            .iter()
+            .map(|field| {
+                match self.tcx.sess.source_map().span_to_snippet(field.pat.span) {
+                    Ok(f) => {
+                        // Field names are numbers, but numbers
+                        // are not valid identifiers
+                        if variant_field_idents.contains(&field.ident) {
+                            String::from("_")
+                        } else {
+                            f
+                        }
+                    }
+                    Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
+                        s.print_pat(field.pat)
+                    }),
+                }
+            })
+            .collect::<Vec<String>>()
+            .join(", ")
+    }
+
     /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to
     /// inaccessible fields.
     ///