diff --git a/Cargo.lock b/Cargo.lock
index 80acf227698e9..cde73166babb7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -26,9 +26,9 @@ dependencies = [
 
 [[package]]
 name = "aho-corasick"
-version = "0.7.13"
+version = "0.7.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
 dependencies = [
  "memchr",
 ]
@@ -559,7 +559,7 @@ dependencies = [
  "cargo_metadata 0.12.0",
  "clippy_lints",
  "clippy_utils",
- "compiletest_rs 0.6.0",
+ "compiletest_rs",
  "derive-new",
  "filetime",
  "if_chain",
@@ -581,7 +581,7 @@ version = "0.0.1"
 dependencies = [
  "bytecount",
  "clap",
- "itertools 0.9.0",
+ "itertools 0.10.1",
  "opener",
  "regex",
  "shell-escape",
@@ -595,7 +595,7 @@ dependencies = [
  "cargo_metadata 0.12.0",
  "clippy_utils",
  "if_chain",
- "itertools 0.9.0",
+ "itertools 0.10.1",
  "pulldown-cmark 0.8.0",
  "quine-mc_cluskey",
  "regex-syntax",
@@ -687,29 +687,6 @@ dependencies = [
  "winapi",
 ]
 
-[[package]]
-name = "compiletest_rs"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0086d6ad78cf409c3061618cd98e2789d5c9ce598fc9651611cf62eae0a599cb"
-dependencies = [
- "diff",
- "filetime",
- "getopts",
- "lazy_static",
- "libc",
- "log",
- "miow",
- "regex",
- "rustfix 0.5.1",
- "serde",
- "serde_derive",
- "serde_json",
- "tempfile",
- "tester",
- "winapi",
-]
-
 [[package]]
 name = "compiletest_rs"
 version = "0.7.0"
@@ -2272,7 +2249,7 @@ name = "miri"
 version = "0.1.0"
 dependencies = [
  "colored",
- "compiletest_rs 0.7.0",
+ "compiletest_rs",
  "env_logger 0.8.1",
  "getrandom 0.2.0",
  "hex 0.4.2",
@@ -3005,9 +2982,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.4.6"
+version = "1.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759"
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
 dependencies = [
  "aho-corasick",
  "memchr",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index b92c5fa072786..c27ab810a4c60 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1902,10 +1902,6 @@ pub enum TyKind {
     Never,
     /// A tuple (`(A, B, C, D,...)`).
     Tup(Vec<P<Ty>>),
-    /// An anonymous struct type i.e. `struct { foo: Type }`
-    AnonymousStruct(Vec<FieldDef>, bool),
-    /// An anonymous union type i.e. `union { bar: Type }`
-    AnonymousUnion(Vec<FieldDef>, bool),
     /// A path (`module::module::...::Type`), optionally
     /// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
     ///
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 2ec941cbb2466..ba86036577ac5 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -484,9 +484,6 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
             visit_vec(bounds, |bound| vis.visit_param_bound(bound));
         }
         TyKind::MacCall(mac) => vis.visit_mac_call(mac),
-        TyKind::AnonymousStruct(fields, ..) | TyKind::AnonymousUnion(fields, ..) => {
-            fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
-        }
     }
     vis.visit_span(span);
     visit_lazy_tts(tokens, vis);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index c30f711b39707..b38031042e0f0 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -407,9 +407,6 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
         TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
         TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
         TyKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
-        TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => {
-            walk_list!(visitor, visit_field_def, fields)
-        }
         TyKind::Never | TyKind::CVarArgs => {}
     }
 }
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index b7497c713f3df..a77e3e1997fd6 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -748,10 +748,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         }
     }
 
-    pub(super) fn lower_field_def(
-        &mut self,
-        (index, f): (usize, &FieldDef),
-    ) -> hir::FieldDef<'hir> {
+    fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
         let ty = if let TyKind::Path(ref qself, ref path) = f.ty.kind {
             let t = self.lower_path_ty(
                 &f.ty,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 8d731d7a57895..4cf54b07dbef8 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1301,15 +1301,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let kind = match t.kind {
             TyKind::Infer => hir::TyKind::Infer,
             TyKind::Err => hir::TyKind::Err,
-            // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
-            TyKind::AnonymousStruct(ref _fields, _recovered) => {
-                self.sess.struct_span_err(t.span, "anonymous structs are unimplemented").emit();
-                hir::TyKind::Err
-            }
-            TyKind::AnonymousUnion(ref _fields, _recovered) => {
-                self.sess.struct_span_err(t.span, "anonymous unions are unimplemented").emit();
-                hir::TyKind::Err
-            }
             TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
             TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
             TyKind::Rptr(ref region, ref mt) => {
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index e9dce953c7388..6723cffc8e684 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -193,11 +193,6 @@ impl<'a> AstValidator<'a> {
                     }
                 }
             }
-            TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => {
-                self.with_banned_assoc_ty_bound(|this| {
-                    walk_list!(this, visit_struct_field_def, fields)
-                });
-            }
             _ => visit::walk_ty(self, t),
         }
     }
@@ -205,7 +200,6 @@ impl<'a> AstValidator<'a> {
     fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
         if let Some(ident) = field.ident {
             if ident.name == kw::Underscore {
-                self.check_anonymous_field(field);
                 self.visit_vis(&field.vis);
                 self.visit_ident(ident);
                 self.visit_ty_common(&field.ty);
@@ -251,66 +245,6 @@ impl<'a> AstValidator<'a> {
         err.emit();
     }
 
-    fn check_anonymous_field(&self, field: &FieldDef) {
-        let FieldDef { ty, .. } = field;
-        match &ty.kind {
-            TyKind::AnonymousStruct(..) | TyKind::AnonymousUnion(..) => {
-                // We already checked for `kw::Underscore` before calling this function,
-                // so skip the check
-            }
-            TyKind::Path(..) => {
-                // If the anonymous field contains a Path as type, we can't determine
-                // if the path is a valid struct or union, so skip the check
-            }
-            _ => {
-                let msg = "unnamed fields can only have struct or union types";
-                let label = "not a struct or union";
-                self.err_handler()
-                    .struct_span_err(field.span, msg)
-                    .span_label(ty.span, label)
-                    .emit();
-            }
-        }
-    }
-
-    fn deny_anonymous_struct(&self, ty: &Ty) {
-        match &ty.kind {
-            TyKind::AnonymousStruct(..) => {
-                self.err_handler()
-                    .struct_span_err(
-                        ty.span,
-                        "anonymous structs are not allowed outside of unnamed struct or union fields",
-                    )
-                    .span_label(ty.span, "anonymous struct declared here")
-                    .emit();
-            }
-            TyKind::AnonymousUnion(..) => {
-                self.err_handler()
-                    .struct_span_err(
-                        ty.span,
-                        "anonymous unions are not allowed outside of unnamed struct or union fields",
-                    )
-                    .span_label(ty.span, "anonymous union declared here")
-                    .emit();
-            }
-            _ => {}
-        }
-    }
-
-    fn deny_anonymous_field(&self, field: &FieldDef) {
-        if let Some(ident) = field.ident {
-            if ident.name == kw::Underscore {
-                self.err_handler()
-                    .struct_span_err(
-                        field.span,
-                        "anonymous fields are not allowed outside of structs or unions",
-                    )
-                    .span_label(ident.span, "anonymous field declared here")
-                    .emit()
-            }
-        }
-    }
-
     fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
         for Param { pat, .. } in &decl.inputs {
             match pat.kind {
@@ -1081,7 +1015,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
     fn visit_ty(&mut self, ty: &'a Ty) {
         self.visit_ty_common(ty);
-        self.deny_anonymous_struct(ty);
         self.walk_ty(ty)
     }
 
@@ -1096,7 +1029,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     }
 
     fn visit_field_def(&mut self, s: &'a FieldDef) {
-        self.deny_anonymous_field(s);
         visit::walk_field_def(self, s)
     }
 
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 1defb65ed8793..30bc4edd7e69c 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -668,7 +668,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
         // involved, so we only emit errors where there are no other parsing errors.
         gate_all!(destructuring_assignment, "destructuring assignments are unstable");
     }
-    gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
 
     // All uses of `gate_all!` below this point were added in #65742,
     // and subsequently disabled (with the non-early gating readded).
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 3cf04be160c64..c24882086e12d 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -985,14 +985,6 @@ impl<'a> State<'a> {
                 }
                 self.pclose();
             }
-            ast::TyKind::AnonymousStruct(ref fields, ..) => {
-                self.head("struct");
-                self.print_record_struct_body(&fields, ty.span);
-            }
-            ast::TyKind::AnonymousUnion(ref fields, ..) => {
-                self.head("union");
-                self.print_record_struct_body(&fields, ty.span);
-            }
             ast::TyKind::Paren(ref typ) => {
                 self.popen();
                 self.print_type(typ);
@@ -1413,7 +1405,12 @@ impl<'a> State<'a> {
         }
     }
 
-    crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
+    crate fn print_record_struct_body(
+        &mut self,
+        fields: &Vec<ast::FieldDef>,
+        span: rustc_span::Span,
+    ) {
+        self.nbsp();
         self.bopen();
         self.hardbreak_if_not_bol();
 
@@ -1462,7 +1459,6 @@ impl<'a> State<'a> {
             }
             ast::VariantData::Struct(ref fields, ..) => {
                 self.print_where_clause(&generics.where_clause);
-                self.nbsp();
                 self.print_record_struct_body(fields, span);
             }
         }
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 56b93f8346680..c180706c581a6 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -12,7 +12,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::OptLevel;
 use rustc_session::Session;
 use rustc_target::spec::abi::Abi;
-use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType};
+use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
 
 use crate::attributes;
 use crate::llvm::AttributePlace::Function;
@@ -161,6 +161,17 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     }
 }
 
+fn set_stackprotector(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+    let sspattr = match cx.sess().stack_protector() {
+        StackProtector::None => return,
+        StackProtector::All => Attribute::StackProtectReq,
+        StackProtector::Strong => Attribute::StackProtectStrong,
+        StackProtector::Basic => Attribute::StackProtect,
+    };
+
+    sspattr.apply_llfn(Function, llfn)
+}
+
 pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     let target_cpu = SmallCStr::new(llvm_util::target_cpu(cx.tcx.sess));
     llvm::AddFunctionAttrStringValue(
@@ -267,6 +278,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
     set_frame_pointer_type(cx, llfn);
     set_instrument_function(cx, llfn);
     set_probestack(cx, llfn);
+    set_stackprotector(cx, llfn);
 
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
         Attribute::Cold.apply_llfn(Function, llfn);
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 1da14344b1d26..5756e47590272 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -232,6 +232,29 @@ impl CodegenBackend for LlvmCodegenBackend {
                 }
                 println!();
             }
+            PrintRequest::StackProtectorStrategies => {
+                println!(
+                    r#"Available stack protector strategies:
+    all
+        Generate stack canaries in all functions.
+
+    strong
+        Generate stack canaries in a function if it either:
+        - has a local variable of `[T; N]` type, regardless of `T` and `N`
+        - takes the address of a local variable.
+
+          (Note that a local variable being borrowed is not equivalent to its
+          address being taken: e.g. some borrows may be removed by optimization,
+          while by-value argument passing may be implemented with reference to a
+          local stack variable in the ABI.)
+
+    basic
+        Generate stack canaries in functions with:
+        - local variables of `[T; N]` type, where `T` is byte-sized and `N` > 8.
+
+"#
+                );
+            }
             req => llvm_util::print(req, sess),
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 3f2ed02d90df3..3accd9785650d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -159,6 +159,9 @@ pub enum Attribute {
     InaccessibleMemOnly = 27,
     SanitizeHWAddress = 28,
     WillReturn = 29,
+    StackProtectReq = 30,
+    StackProtectStrong = 31,
+    StackProtect = 32,
 }
 
 /// LLVMIntPredicate
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 53053327d0dab..9edcf1dbb747d 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -736,7 +736,12 @@ impl RustcDefaultCalls {
                         println!("{}", cfg);
                     }
                 }
-                RelocationModels | CodeModels | TlsModels | TargetCPUs | TargetFeatures => {
+                RelocationModels
+                | CodeModels
+                | TlsModels
+                | TargetCPUs
+                | StackProtectorStrategies
+                | TargetFeatures => {
                     codegen_backend.print(*req, sess);
                 }
                 // Any output here interferes with Cargo's parsing of other printed output
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 366ed715434ed..efa93c186363a 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -638,9 +638,6 @@ declare_features! (
     /// Allows specifying the as-needed link modifier
     (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
 
-    /// Allows unnamed fields of struct and union type
-    (incomplete, unnamed_fields, "1.53.0", Some(49804), None),
-
     /// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns.
     (active, more_qualified_paths, "1.54.0", Some(86935), None),
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index afab919bc3c2c..4729c9e004261 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -18,7 +18,9 @@ use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
 use rustc_span::SourceFileHashAlgorithm;
 use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
-use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, TlsModel};
+use rustc_target::spec::{
+    RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel,
+};
 
 use std::collections::{BTreeMap, BTreeSet};
 use std::iter::FromIterator;
@@ -709,8 +711,8 @@ fn test_debugging_options_tracking_hash() {
     // This list is in alphabetical order.
     tracked!(allow_features, Some(vec![String::from("lang_items")]));
     tracked!(always_encode_mir, true);
-    tracked!(assume_incomplete_release, true);
     tracked!(asm_comments, true);
+    tracked!(assume_incomplete_release, true);
     tracked!(binary_dep_depinfo, true);
     tracked!(chalk, true);
     tracked!(codegen_backend, Some("abc".to_string()));
@@ -726,8 +728,8 @@ fn test_debugging_options_tracking_hash() {
     tracked!(human_readable_cgu_names, true);
     tracked!(inline_in_all_cgus, Some(true));
     tracked!(inline_mir, Some(true));
-    tracked!(inline_mir_threshold, Some(123));
     tracked!(inline_mir_hint_threshold, Some(123));
+    tracked!(inline_mir_threshold, Some(123));
     tracked!(instrument_coverage, Some(InstrumentCoverage::All));
     tracked!(instrument_mcount, true);
     tracked!(link_only, true);
@@ -753,7 +755,6 @@ fn test_debugging_options_tracking_hash() {
     tracked!(profiler_runtime, "abc".to_string());
     tracked!(relax_elf_relocations, Some(true));
     tracked!(relro_level, Some(RelroLevel::Full));
-    tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
     tracked!(report_delayed_bugs, true);
     tracked!(sanitizer, SanitizerSet::ADDRESS);
     tracked!(sanitizer_memory_track_origins, 2);
@@ -761,15 +762,17 @@ fn test_debugging_options_tracking_hash() {
     tracked!(saturating_float_casts, Some(true));
     tracked!(share_generics, Some(true));
     tracked!(show_span, Some(String::from("abc")));
+    tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
     tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1));
+    tracked!(stack_protector, StackProtector::All);
     tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
     tracked!(teach, true);
     tracked!(thinlto, Some(true));
     tracked!(thir_unsafeck, true);
-    tracked!(tune_cpu, Some(String::from("abc")));
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
     tracked!(trap_unreachable, Some(false));
     tracked!(treat_err_as_bug, NonZeroUsize::new(1));
+    tracked!(tune_cpu, Some(String::from("abc")));
     tracked!(unleash_the_miri_inside_of_you, true);
     tracked!(use_ctors_section, Some(true));
     tracked!(verify_llvm_ir, true);
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index 0b1b68d83b7b9..51c835245997e 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -80,6 +80,9 @@ enum LLVMRustAttribute {
   InaccessibleMemOnly = 27,
   SanitizeHWAddress = 28,
   WillReturn = 29,
+  StackProtectReq = 30,
+  StackProtectStrong = 31,
+  StackProtect = 32,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 9850f395a0f65..b86a9ac8265e2 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -199,6 +199,12 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::SanitizeHWAddress;
   case WillReturn:
     return Attribute::WillReturn;
+  case StackProtectReq:
+    return Attribute::StackProtectReq;
+  case StackProtectStrong:
+    return Attribute::StackProtectStrong;
+  case StackProtect:
+    return Attribute::StackProtect;
   }
   report_fatal_error("bad AttributeKind");
 }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 10c73fd64bc19..c5b961f12b2ab 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1234,7 +1234,7 @@ impl<'a> Parser<'a> {
         Ok((class_name, ItemKind::Union(vdata, generics)))
     }
 
-    pub(super) fn parse_record_struct_body(
+    fn parse_record_struct_body(
         &mut self,
         adt_ty: &str,
     ) -> PResult<'a, (Vec<FieldDef>, /* recovered */ bool)> {
@@ -1468,28 +1468,22 @@ impl<'a> Parser<'a> {
     fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
         let (ident, is_raw) = self.ident_or_err()?;
         if !is_raw && ident.is_reserved() {
-            if ident.name == kw::Underscore {
-                self.sess.gated_spans.gate(sym::unnamed_fields, lo);
+            let err = if self.check_fn_front_matter(false) {
+                // We use `parse_fn` to get a span for the function
+                if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) {
+                    db.delay_as_bug();
+                }
+                let mut err = self.struct_span_err(
+                    lo.to(self.prev_token.span),
+                    &format!("functions are not allowed in {} definitions", adt_ty),
+                );
+                err.help("unlike in C++, Java, and C#, functions are declared in `impl` blocks");
+                err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
+                err
             } else {
-                let err = if self.check_fn_front_matter(false) {
-                    // We use `parse_fn` to get a span for the function
-                    if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) {
-                        db.delay_as_bug();
-                    }
-                    let mut err = self.struct_span_err(
-                        lo.to(self.prev_token.span),
-                        &format!("functions are not allowed in {} definitions", adt_ty),
-                    );
-                    err.help(
-                        "unlike in C++, Java, and C#, functions are declared in `impl` blocks",
-                    );
-                    err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
-                    err
-                } else {
-                    self.expected_ident_found()
-                };
-                return Err(err);
-            }
+                self.expected_ident_found()
+            };
+            return Err(err);
         }
         self.bump();
         Ok(ident)
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 299fc916ac97f..98400372c36a6 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -226,19 +226,6 @@ impl<'a> Parser<'a> {
             }
         } else if self.eat_keyword(kw::Impl) {
             self.parse_impl_ty(&mut impl_dyn_multi)?
-        } else if self.token.is_keyword(kw::Union)
-            && self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
-        {
-            self.bump();
-            let (fields, recovered) = self.parse_record_struct_body("union")?;
-            let span = lo.to(self.prev_token.span);
-            self.sess.gated_spans.gate(sym::unnamed_fields, span);
-            TyKind::AnonymousUnion(fields, recovered)
-        } else if self.eat_keyword(kw::Struct) {
-            let (fields, recovered) = self.parse_record_struct_body("struct")?;
-            let span = lo.to(self.prev_token.span);
-            self.sess.gated_spans.gate(sym::unnamed_fields, span);
-            TyKind::AnonymousStruct(fields, recovered)
         } else if self.is_explicit_dyn_type() {
             self.parse_dyn_ty(&mut impl_dyn_multi)?
         } else if self.eat_lt() {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index fdedb7e6a4afe..062c424478c6b 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -512,6 +512,7 @@ pub enum PrintRequest {
     TlsModels,
     TargetSpec,
     NativeStaticLibs,
+    StackProtectorStrategies,
 }
 
 #[derive(Copy, Clone)]
@@ -1067,8 +1068,8 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
             "print",
             "Compiler information to print on stdout",
             "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
-             target-cpus|target-features|relocation-models|\
-             code-models|tls-models|target-spec-json|native-static-libs]",
+             target-cpus|target-features|relocation-models|code-models|\
+             tls-models|target-spec-json|native-static-libs|stack-protector-strategies]",
         ),
         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
@@ -1484,6 +1485,7 @@ fn collect_print_requests(
         "code-models" => PrintRequest::CodeModels,
         "tls-models" => PrintRequest::TlsModels,
         "native-static-libs" => PrintRequest::NativeStaticLibs,
+        "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
         "target-spec-json" => {
             if dopts.unstable_options {
                 PrintRequest::TargetSpec
@@ -2414,7 +2416,9 @@ crate mod dep_tracking {
     use rustc_span::edition::Edition;
     use rustc_span::RealFileName;
     use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
-    use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
+    use rustc_target::spec::{
+        RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
+    };
     use std::collections::hash_map::DefaultHasher;
     use std::collections::BTreeMap;
     use std::hash::Hash;
@@ -2488,6 +2492,7 @@ crate mod dep_tracking {
         Edition,
         LinkerPluginLto,
         SplitDebuginfo,
+        StackProtector,
         SwitchWithOptPath,
         SymbolManglingVersion,
         SourceFileHashAlgorithm,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 447be84b5a70a..d57b438c6e4b0 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -6,7 +6,9 @@ use crate::search_paths::SearchPath;
 use crate::utils::NativeLib;
 
 use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet};
-use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
+use rustc_target::spec::{
+    RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
+};
 
 use rustc_feature::UnstableFeatures;
 use rustc_span::edition::Edition;
@@ -381,6 +383,8 @@ mod desc {
     pub const parse_split_debuginfo: &str =
         "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
     pub const parse_gcc_ld: &str = "one of: no value, `lld`";
+    pub const parse_stack_protector: &str =
+        "one of (`none` (default), `basic`, `strong`, or `all`)";
 }
 
 mod parse {
@@ -884,6 +888,14 @@ mod parse {
         }
         true
     }
+
+    crate fn parse_stack_protector(slot: &mut StackProtector, v: Option<&str>) -> bool {
+        match v.and_then(|s| StackProtector::from_str(s).ok()) {
+            Some(ssp) => *slot = ssp,
+            _ => return false,
+        }
+        true
+    }
 }
 
 options! {
@@ -1275,6 +1287,8 @@ options! {
         "exclude spans when debug-printing compiler state (default: no)"),
     src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
         "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
+    stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED],
+        "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
     strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
         "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
     split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 4471e1e0ae8b4..7eef8aba13c64 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -28,7 +28,9 @@ use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, S
 use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
 use rustc_target::asm::InlineAsmArch;
 use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
-use rustc_target::spec::{SanitizerSet, SplitDebuginfo, Target, TargetTriple, TlsModel};
+use rustc_target::spec::{
+    SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
+};
 
 use std::cell::{self, RefCell};
 use std::env;
@@ -747,6 +749,14 @@ impl Session {
         self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo)
     }
 
+    pub fn stack_protector(&self) -> StackProtector {
+        if self.target.options.supports_stack_protector {
+            self.opts.debugging_opts.stack_protector
+        } else {
+            StackProtector::None
+        }
+    }
+
     pub fn target_can_use_split_dwarf(&self) -> bool {
         !self.target.is_like_windows && !self.target.is_like_osx
     }
@@ -1391,6 +1401,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
                                 disable it using `-C target-feature=-crt-static`",
         );
     }
+
+    if sess.opts.debugging_opts.stack_protector != StackProtector::None {
+        if !sess.target.options.supports_stack_protector {
+            sess.warn(&format!(
+                "`-Z stack-protector={}` is not supported for target {} and will be ignored",
+                sess.opts.debugging_opts.stack_protector, sess.opts.target_triple
+            ))
+        }
+    }
 }
 
 /// Holds data on the current incremental compilation session, if there is one.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index c816d06045681..b1aea3c9ba00a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1359,7 +1359,6 @@ symbols! {
         unix,
         unlikely,
         unmarked_api,
-        unnamed_fields,
         unpin,
         unreachable,
         unreachable_code,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 273221360b8b5..0194521223ebe 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -705,6 +705,59 @@ impl ToJson for FramePointer {
     }
 }
 
+/// Controls use of stack canaries.
+#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)]
+pub enum StackProtector {
+    /// Disable stack canary generation.
+    None,
+
+    /// On LLVM, mark all generated LLVM functions with the `ssp` attribute (see
+    /// llvm/docs/LangRef.rst). This triggers stack canary generation in
+    /// functions which contain an array of a byte-sized type with more than
+    /// eight elements.
+    Basic,
+
+    /// On LLVM, mark all generated LLVM functions with the `sspstrong`
+    /// attribute (see llvm/docs/LangRef.rst). This triggers stack canary
+    /// generation in functions which either contain an array, or which take
+    /// the address of a local variable.
+    Strong,
+
+    /// Generate stack canaries in all functions.
+    All,
+}
+
+impl StackProtector {
+    fn as_str(&self) -> &'static str {
+        match self {
+            StackProtector::None => "none",
+            StackProtector::Basic => "basic",
+            StackProtector::Strong => "strong",
+            StackProtector::All => "all",
+        }
+    }
+}
+
+impl FromStr for StackProtector {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<StackProtector, ()> {
+        Ok(match s {
+            "none" => StackProtector::None,
+            "basic" => StackProtector::Basic,
+            "strong" => StackProtector::Strong,
+            "all" => StackProtector::All,
+            _ => return Err(()),
+        })
+    }
+}
+
+impl fmt::Display for StackProtector {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(self.as_str())
+    }
+}
+
 macro_rules! supported_targets {
     ( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
         $(mod $module;)+
@@ -1339,6 +1392,10 @@ pub struct TargetOptions {
 
     /// Minimum number of bits in #[repr(C)] enum. Defaults to 32.
     pub c_enum_min_bits: u64,
+
+    /// Whether the target supports stack canary checks. `true` by default,
+    /// since this is most common among tier 1 and tier 2 targets.
+    pub supports_stack_protector: bool,
 }
 
 impl Default for TargetOptions {
@@ -1444,6 +1501,7 @@ impl Default for TargetOptions {
             supported_sanitizers: SanitizerSet::empty(),
             default_adjusted_cabi: None,
             c_enum_min_bits: 32,
+            supports_stack_protector: true,
         }
     }
 }
@@ -2029,6 +2087,7 @@ impl Target {
         key!(supported_sanitizers, SanitizerSet)?;
         key!(default_adjusted_cabi, Option<Abi>)?;
         key!(c_enum_min_bits, u64);
+        key!(supports_stack_protector, bool);
 
         if base.is_builtin {
             // This can cause unfortunate ICEs later down the line.
@@ -2268,6 +2327,7 @@ impl ToJson for Target {
         target_option_val!(split_debuginfo);
         target_option_val!(supported_sanitizers);
         target_option_val!(c_enum_min_bits);
+        target_option_val!(supports_stack_protector);
 
         if let Some(abi) = self.default_adjusted_cabi {
             d.insert("default-adjusted-cabi".to_string(), Abi::name(abi).to_json());
diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
index 083262cf3514c..ba32a312910d8 100644
--- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
@@ -44,6 +44,10 @@ pub fn target() -> Target {
             // produce kernel functions that call other kernel functions.
             // This behavior is not supported by PTX ISA.
             merge_functions: MergeFunctions::Disabled,
+
+            // The LLVM backend does not support stack canaries for this target
+            supports_stack_protector: false,
+
             ..Default::default()
         },
     }
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 2adf6a549e641..e56b631dbaf8d 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1916,7 +1916,8 @@ impl<T: ?Sized> UnsafeCell<T> {
     /// ```
     #[inline(always)]
     #[stable(feature = "unsafe_cell_get_mut", since = "1.50.0")]
-    pub fn get_mut(&mut self) -> &mut T {
+    #[rustc_const_unstable(feature = "const_unsafecell_get_mut", issue = "88836")]
+    pub const fn get_mut(&mut self) -> &mut T {
         &mut self.value
     }
 
diff --git a/src/test/assembly/stack-protector/stack-protector-heuristics-effect.rs b/src/test/assembly/stack-protector/stack-protector-heuristics-effect.rs
new file mode 100644
index 0000000000000..c688006abc329
--- /dev/null
+++ b/src/test/assembly/stack-protector/stack-protector-heuristics-effect.rs
@@ -0,0 +1,395 @@
+// revisions: all strong basic none missing
+// assembly-output: emit-asm
+// ignore-windows stack check code uses different function names
+// ignore-nvptx stack protector is not supported
+// [all] compile-flags: -Z stack-protector=all
+// [strong] compile-flags: -Z stack-protector=strong
+// [basic] compile-flags: -Z stack-protector=basic
+// [none] compile-flags: -Z stack-protector=none
+// compile-flags: -C opt-level=2 -Z merge-functions=disabled
+
+#![crate_type = "lib"]
+
+#![allow(incomplete_features)]
+
+#![feature(unsized_locals, unsized_fn_params)]
+
+
+// CHECK-LABEL: emptyfn:
+#[no_mangle]
+pub fn emptyfn() {
+    // all: __stack_chk_fail
+    // strong-NOT: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: array_char
+#[no_mangle]
+pub fn array_char(f: fn(*const char)) {
+    let a = ['c'; 1];
+    let b = ['d'; 3];
+    let c = ['e'; 15];
+
+    f(&a as *const _);
+    f(&b as *const _);
+    f(&c as *const _);
+
+    // Any type of local array variable leads to stack protection with the
+    // "strong" heuristic. The 'basic' heuristic only adds stack protection to
+    // functions with local array variables of a byte-sized type, however. Since
+    // 'char' is 4 bytes in Rust, this function is not protected by the 'basic'
+    // heuristic
+    //
+    // (This test *also* takes the address of the local stack variables. We
+    // cannot know that this isn't what triggers the `strong` heuristic.
+    // However, the test strategy of passing the address of a stack array to an
+    // external function is sufficient to trigger the `basic` heuristic (see
+    // test `array_u8_large()`). Since the `basic` heuristic only checks for the
+    // presence of stack-local array variables, we can be confident that this
+    // test also captures this part of the `strong` heuristic specification.)
+
+    // all: __stack_chk_fail
+    // strong: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: array_u8_1
+#[no_mangle]
+pub fn array_u8_1(f: fn(*const u8)) {
+    let a = [0u8; 1];
+    f(&a as *const _);
+
+    // The 'strong' heuristic adds stack protection to functions with local
+    // array variables regardless of their size.
+
+    // all: __stack_chk_fail
+    // strong: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: array_u8_small:
+#[no_mangle]
+pub fn array_u8_small(f: fn(*const u8)) {
+    let a = [0u8; 2];
+    let b = [0u8; 8];
+    f(&a as *const _);
+    f(&b as *const _);
+
+    // Small arrays do not lead to stack protection by the 'basic' heuristic.
+
+    // all: __stack_chk_fail
+    // strong: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: array_u8_large:
+#[no_mangle]
+pub fn array_u8_large(f: fn(*const u8)) {
+    let a = [0u8; 9];
+    f(&a as *const _);
+
+    // Since `a` is a byte array with size greater than 8, the basic heuristic
+    // will also protect this function.
+
+    // all: __stack_chk_fail
+    // strong: __stack_chk_fail
+    // basic: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+#[derive(Copy, Clone)]
+pub struct ByteSizedNewtype(u8);
+
+// CHECK-LABEL: array_bytesizednewtype_9:
+#[no_mangle]
+pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) {
+    let a = [ByteSizedNewtype(0); 9];
+    f(&a as *const _);
+
+    // Since `a` is a byte array in the LLVM output, the basic heuristic will
+    // also protect this function.
+
+    // all: __stack_chk_fail
+    // strong: __stack_chk_fail
+    // basic: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: local_var_addr_used_indirectly
+#[no_mangle]
+pub fn local_var_addr_used_indirectly(f: fn(bool)) {
+    let a = 5;
+    let a_addr = &a as *const _ as usize;
+    f(a_addr & 0x10 == 0);
+
+    // This function takes the address of a local variable taken. Although this
+    // address is never used as a way to refer to stack memory, the `strong`
+    // heuristic adds stack smash protection. This is also the case in C++:
+    // ```
+    // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk
+    // #include <cstdint>
+    // void f(void (*g)(bool)) {
+    //     int32_t x;
+    //     g((reinterpret_cast<uintptr_t>(&x) & 0x10U) == 0);
+    // }
+    // EOF
+    // ```
+
+    // all: __stack_chk_fail
+    // strong: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+
+// CHECK-LABEL: local_string_addr_taken
+#[no_mangle]
+pub fn local_string_addr_taken(f: fn(&String)) {
+    let x = String::new();
+    f(&x);
+
+    // Taking the address of the local variable `x` leads to stack smash
+    // protection with the `strong` heuristic, but not with the `basic`
+    // heuristic. It does not matter that the reference is not mut.
+    //
+    // An interesting note is that a similar function in C++ *would* be
+    // protected by the `basic` heuristic, because `std::string` has a char
+    // array internally as a small object optimization:
+    // ```
+    // cat <<EOF | clang++ -O2 -fstack-protector -S -x c++ - -o - | grep stack_chk
+    // #include <string>
+    // void f(void (*g)(const std::string&)) {
+    //     std::string x;
+    //     g(x);
+    // }
+    // EOF
+    // ```
+    //
+
+    // all: __stack_chk_fail
+    // strong: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+pub trait SelfByRef {
+    fn f(&self) -> i32;
+}
+
+impl SelfByRef for i32 {
+    fn f(&self) -> i32 {
+        return self + 1;
+    }
+}
+
+// CHECK-LABEL: local_var_addr_taken_used_locally_only
+#[no_mangle]
+pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) {
+    let x = factory();
+    let g = x.f();
+    sink(g);
+
+    // Even though the local variable conceptually has its address taken, as
+    // it's passed by reference to the trait function, the use of the reference
+    // is easily inlined. There is therefore no stack smash protection even with
+    // the `strong` heuristic.
+
+    // all: __stack_chk_fail
+    // strong-NOT: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+pub struct Gigastruct {
+    does: u64,
+    not: u64,
+    have: u64,
+    array: u64,
+    members: u64
+}
+
+// CHECK-LABEL: local_large_var_moved
+#[no_mangle]
+pub fn local_large_var_moved(f: fn(Gigastruct)) {
+    let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 };
+    f(x);
+
+    // Even though the local variable conceptually doesn't have its address
+    // taken, it's so large that the "move" is implemented with a reference to a
+    // stack-local variable in the ABI. Consequently, this function *is*
+    // protected by the `strong` heuristic. This is also the case for
+    // rvalue-references in C++, regardless of struct size:
+    // ```
+    // cat <<EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk
+    // #include <cstdint>
+    // #include <utility>
+    // void f(void (*g)(uint64_t&&)) {
+    //     uint64_t x;
+    //     g(std::move(x));
+    // }
+    // EOF
+    // ```
+
+    // all: __stack_chk_fail
+    // strong: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: local_large_var_cloned
+#[no_mangle]
+pub fn local_large_var_cloned(f: fn(Gigastruct)) {
+    f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 });
+
+    // A new instance of `Gigastruct` is passed to `f()`, without any apparent
+    // connection to this stack frame. Still, since instances of `Gigastruct`
+    // are sufficiently large, it is allocated in the caller stack frame and
+    // passed as a pointer. As such, this function is *also* protected by the
+    // `strong` heuristic, just like `local_large_var_moved`. This is also the
+    // case for pass-by-value of sufficiently large structs in C++:
+    // ```
+    // cat <<EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk
+    // #include <cstdint>
+    // #include <utility>
+    // struct Gigastruct { uint64_t a, b, c, d, e; };
+    // void f(void (*g)(Gigastruct)) {
+    //     g(Gigastruct{});
+    // }
+    // EOF
+    // ```
+
+
+    // all: __stack_chk_fail
+    // strong: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+
+extern "C" {
+    // A call to an external `alloca` function is *not* recognized as an
+    // `alloca(3)` operation. This function is a compiler built-in, as the
+    // man page explains. Clang translates it to an LLVM `alloca`
+    // instruction with a count argument, which is also what the LLVM stack
+    // protector heuristics looks for. The man page for `alloca(3)` details
+    // a way to avoid using the compiler built-in: pass a -std=c11
+    // argument, *and* don't include <alloca.h>. Though this leads to an
+    // external alloca() function being called, it doesn't lead to stack
+    // protection being included. It even fails with a linker error
+    // "undefined reference to `alloca'". Example:
+    // ```
+    // cat<<EOF | clang -fstack-protector-strong -x c -std=c11 - -o /dev/null
+    // #include <stdlib.h>
+    // void * alloca(size_t);
+    // void f(void (*g)(void*)) {
+    //     void * p = alloca(10);
+    //     g(p);
+    // }
+    // int main() { return 0; }
+    // EOF
+    // ```
+    // The following tests demonstrate that calls to an external `alloca`
+    // function in Rust also doesn't trigger stack protection.
+
+    fn alloca(size: usize) -> *mut ();
+}
+
+// CHECK-LABEL: alloca_small_compile_time_constant_arg
+#[no_mangle]
+pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) {
+    f(unsafe { alloca(8) });
+
+    // all: __stack_chk_fail
+    // strong-NOT: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: alloca_large_compile_time_constant_arg
+#[no_mangle]
+pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) {
+    f(unsafe { alloca(9) });
+
+    // all: __stack_chk_fail
+    // strong-NOT: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+
+// CHECK-LABEL: alloca_dynamic_arg
+#[no_mangle]
+pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) {
+    f(unsafe { alloca(n) });
+
+    // all: __stack_chk_fail
+    // strong-NOT: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+// The question then is: in what ways can Rust code generate array-`alloca`
+// LLVM instructions? This appears to only be generated by
+// rustc_codegen_ssa::traits::Builder::array_alloca() through
+// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT
+// this is support for the "unsized locals" unstable feature:
+// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html.
+
+
+// CHECK-LABEL: unsized_fn_param
+#[no_mangle]
+pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
+    let n = if l { 1 } else { 2 };
+    f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from
+
+    // Even though slices are conceptually passed by-value both into this
+    // function and into `f()`, this is implemented with pass-by-reference
+    // using a suitably constructed fat-pointer (as if the functions
+    // accepted &[u8]). This function therefore doesn't need dynamic array
+    // alloca, and is therefore not protected by the `strong` or `basic`
+    // heuristics.
+
+
+    // all: __stack_chk_fail
+    // strong-NOT: __stack_chk_fail
+    // basic-NOT: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: unsized_local
+#[no_mangle]
+pub fn unsized_local(s: &[u8], l: bool, f: fn(&mut [u8])) {
+    let n = if l { 1 } else { 2 };
+    let mut a: [u8] = *Box::<[u8]>::from(&s[0..n]); // slice-copy with Box::from
+    f(&mut a);
+
+    // This function allocates a slice as a local variable in its stack
+    // frame. Since the size is not a compile-time constant, an array
+    // alloca is required, and the function is protected by both the
+    // `strong` and `basic` heuristic.
+
+    // all: __stack_chk_fail
+    // strong: __stack_chk_fail
+    // basic: __stack_chk_fail
+    // none-NOT: __stack_chk_fail
+    // missing-NOT: __stack_chk_fail
+}
diff --git a/src/test/assembly/stack-protector/stack-protector-target-support.rs b/src/test/assembly/stack-protector/stack-protector-target-support.rs
new file mode 100644
index 0000000000000..5ba46d082e157
--- /dev/null
+++ b/src/test/assembly/stack-protector/stack-protector-target-support.rs
@@ -0,0 +1,286 @@
+// Test that stack smash protection code is emitted for all tier1 and tier2
+// targets, with the exception of nvptx64-nvidia-cuda
+//
+// revisions: r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23
+// revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33 r34 r35 r36 r37 r38 r39 r40 r41 r42 r43 r44
+// revisions: r45 r46 r47 r48 r49 r50 r51 r52 r53 r54 r55 r56 r57 r58 r59 r60 r61 r62 r63 r64 r65
+// revisions: r66 r67 r68 r69 r70 r71 r72 r73 r74 r75 r76 r77 r78 r79 r80 r81 r82 r83 r84
+// assembly-output: emit-asm
+// [r1] compile-flags: --target aarch64-unknown-linux-gnu
+// [r1] needs-llvm-components: aarch64
+// [r2] compile-flags: --target i686-pc-windows-gnu
+// [r2] needs-llvm-components: x86
+// [r3] compile-flags: --target i686-pc-windows-msvc
+// [r3] needs-llvm-components: x86
+// [r4] compile-flags: --target i686-unknown-linux-gnu
+// [r4] needs-llvm-components: x86
+// [r5] compile-flags: --target x86_64-apple-darwin
+// [r5] needs-llvm-components: x86
+// [r6] compile-flags: --target x86_64-pc-windows-gnu
+// [r6] needs-llvm-components: x86
+// [r7] compile-flags: --target x86_64-pc-windows-msvc
+// [r7] needs-llvm-components: x86
+// [r8] compile-flags: --target x86_64-unknown-linux-gnu
+// [r8] needs-llvm-components: x86
+// [r9] compile-flags: --target aarch64-apple-darwin
+// [r9] needs-llvm-components: aarch64
+// [r10] compile-flags: --target aarch64-apple-ios
+// [r10] needs-llvm-components: aarch64
+// [r11] compile-flags: --target aarch64-fuchsia
+// [r11] needs-llvm-components: aarch64
+// [r12] compile-flags: --target aarch64-linux-android
+// [r12] needs-llvm-components: aarch64
+// [r13] compile-flags: --target aarch64-pc-windows-msvc
+// [r13] needs-llvm-components: aarch64
+// [r14] compile-flags: --target aarch64-unknown-linux-musl
+// [r14] needs-llvm-components: aarch64
+// [r15] compile-flags: --target aarch64-unknown-none
+// [r15] needs-llvm-components: aarch64
+// [r16] compile-flags: --target aarch64-unknown-none-softfloat
+// [r16] needs-llvm-components: aarch64
+// [r17] compile-flags: --target arm-linux-androideabi
+// [r17] needs-llvm-components: arm
+// [r18] compile-flags: --target arm-unknown-linux-gnueabi
+// [r18] needs-llvm-components: arm
+// [r19] compile-flags: --target arm-unknown-linux-gnueabihf
+// [r19] needs-llvm-components: arm
+// [r20] compile-flags: --target arm-unknown-linux-musleabi
+// [r20] needs-llvm-components: arm
+// [r21] compile-flags: --target arm-unknown-linux-musleabihf
+// [r21] needs-llvm-components: arm
+// [r22] compile-flags: --target armebv7r-none-eabi
+// [r22] needs-llvm-components: arm
+// [r23] compile-flags: --target armebv7r-none-eabihf
+// [r23] needs-llvm-components: arm
+// [r24] compile-flags: --target armv5te-unknown-linux-gnueabi
+// [r24] needs-llvm-components: arm
+// [r25] compile-flags: --target armv5te-unknown-linux-musleabi
+// [r25] needs-llvm-components: arm
+// [r26] compile-flags: --target armv7-linux-androideabi
+// [r26] needs-llvm-components: arm
+// [r27] compile-flags: --target armv7a-none-eabi
+// [r27] needs-llvm-components: arm
+// [r28] compile-flags: --target armv7r-none-eabi
+// [r28] needs-llvm-components: arm
+// [r29] compile-flags: --target armv7r-none-eabihf
+// [r29] needs-llvm-components: arm
+// [r30] compile-flags: --target armv7-unknown-linux-gnueabi
+// [r30] needs-llvm-components: arm
+// [r31] compile-flags: --target armv7-unknown-linux-gnueabihf
+// [r31] needs-llvm-components: arm
+// [r32] compile-flags: --target armv7-unknown-linux-musleabi
+// [r32] needs-llvm-components: arm
+// [r33] compile-flags: --target armv7-unknown-linux-musleabihf
+// [r33] needs-llvm-components: arm
+// [r34] compile-flags: --target asmjs-unknown-emscripten
+// [r34] needs-llvm-components: webassembly
+// [r35] compile-flags: --target i586-pc-windows-msvc
+// [r35] needs-llvm-components: x86
+// [r36] compile-flags: --target i586-unknown-linux-gnu
+// [r36] needs-llvm-components: x86
+// [r37] compile-flags: --target i586-unknown-linux-musl
+// [r37] needs-llvm-components: x86
+// [r38] compile-flags: --target i686-linux-android
+// [r38] needs-llvm-components: x86
+// [r39] compile-flags: --target i686-unknown-freebsd
+// [r39] needs-llvm-components: x86
+// [r40] compile-flags: --target i686-unknown-linux-musl
+// [r40] needs-llvm-components: x86
+// [r41] compile-flags: --target mips-unknown-linux-gnu
+// [r41] needs-llvm-components: mips
+// [r42] compile-flags: --target mips-unknown-linux-musl
+// [r42] needs-llvm-components: mips
+// [r43] compile-flags: --target mips64-unknown-linux-gnuabi64
+// [r43] needs-llvm-components: mips
+// [r44] compile-flags: --target mips64-unknown-linux-muslabi64
+// [r44] needs-llvm-components: mips
+// [r45] compile-flags: --target mips64el-unknown-linux-gnuabi64
+// [r45] needs-llvm-components: mips
+// [r46] compile-flags: --target mips64el-unknown-linux-muslabi64
+// [r46] needs-llvm-components: mips
+// [r47] compile-flags: --target mipsel-unknown-linux-gnu
+// [r47] needs-llvm-components: mips
+// [r48] compile-flags: --target mipsel-unknown-linux-musl
+// [r48] needs-llvm-components: mips
+// [r49] compile-flags: --target nvptx64-nvidia-cuda
+// [r49] needs-llvm-components: nvptx
+// [r50] compile-flags: --target powerpc-unknown-linux-gnu
+// [r50] needs-llvm-components: powerpc
+// [r51] compile-flags: --target powerpc64-unknown-linux-gnu
+// [r51] needs-llvm-components: powerpc
+// [r52] compile-flags: --target powerpc64le-unknown-linux-gnu
+// [r52] needs-llvm-components: powerpc
+// [r53] compile-flags: --target riscv32i-unknown-none-elf
+// [r53] needs-llvm-components: riscv
+// [r54] compile-flags: --target riscv32imac-unknown-none-elf
+// [r54] needs-llvm-components: riscv
+// [r55] compile-flags:--target riscv32imc-unknown-none-elf
+// [r55] needs-llvm-components: riscv
+// [r56] compile-flags:--target riscv64gc-unknown-linux-gnu
+// [r56] needs-llvm-components: riscv
+// [r57] compile-flags:--target riscv64gc-unknown-none-elf
+// [r57] needs-llvm-components: riscv
+// [r58] compile-flags:--target riscv64imac-unknown-none-elf
+// [r58] needs-llvm-components: riscv
+// [r59] compile-flags:--target s390x-unknown-linux-gnu
+// [r59] needs-llvm-components: systemz
+// [r60] compile-flags:--target sparc64-unknown-linux-gnu
+// [r60] needs-llvm-components: sparc
+// [r61] compile-flags:--target sparcv9-sun-solaris
+// [r61] needs-llvm-components: sparc
+// [r62] compile-flags:--target thumbv6m-none-eabi
+// [r62] needs-llvm-components: arm
+// [r63] compile-flags:--target thumbv7em-none-eabi
+// [r63] needs-llvm-components: arm
+// [r64] compile-flags:--target thumbv7em-none-eabihf
+// [r64] needs-llvm-components: arm
+// [r65] compile-flags:--target thumbv7m-none-eabi
+// [r65] needs-llvm-components: arm
+// [r66] compile-flags:--target thumbv7neon-linux-androideabi
+// [r66] needs-llvm-components: arm
+// [r67] compile-flags:--target thumbv7neon-unknown-linux-gnueabihf
+// [r67] needs-llvm-components: arm
+// [r68] compile-flags:--target thumbv8m.base-none-eabi
+// [r68] needs-llvm-components: arm
+// [r69] compile-flags:--target thumbv8m.main-none-eabi
+// [r69] needs-llvm-components: arm
+// [r70] compile-flags:--target thumbv8m.main-none-eabihf
+// [r70] needs-llvm-components: arm
+// [r71] compile-flags:--target wasm32-unknown-emscripten
+// [r71] needs-llvm-components: webassembly
+// [r72] compile-flags:--target wasm32-unknown-unknown
+// [r72] needs-llvm-components: webassembly
+// [r73] compile-flags:--target wasm32-wasi
+// [r73] needs-llvm-components: webassembly
+// [r74] compile-flags:--target x86_64-apple-ios
+// [r74] needs-llvm-components: x86
+// [r75] compile-flags:--target x86_64-fortanix-unknown-sgx
+// [r75] needs-llvm-components: x86
+// [r75] min-llvm-version: 11.0.0
+// [r76] compile-flags:--target x86_64-fuchsia
+// [r76] needs-llvm-components: x86
+// [r77] compile-flags:--target x86_64-linux-android
+// [r77] needs-llvm-components: x86
+// [r78] compile-flags:--target x86_64-sun-solaris
+// [r78] needs-llvm-components: x86
+// [r79] compile-flags:--target x86_64-unknown-freebsd
+// [r79] needs-llvm-components: x86
+// [r80] compile-flags:--target x86_64-unknown-illumos
+// [r80] needs-llvm-components: x86
+// [r81] compile-flags:--target x86_64-unknown-linux-gnux32
+// [r81] needs-llvm-components: x86
+// [r82] compile-flags:--target x86_64-unknown-linux-musl
+// [r82] needs-llvm-components: x86
+// [r83] compile-flags:--target x86_64-unknown-netbsd
+// [r83] needs-llvm-components: x86
+// [r84] compile-flags: --target x86_64-unknown-redox
+// [r84] needs-llvm-components: x86
+// compile-flags: -Z stack-protector=all
+// compile-flags: -C opt-level=2
+
+#![crate_type = "lib"]
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: foo{{:|()}}
+
+    // MSVC does the stack checking within a stack-check function:
+    // r3: calll @__security_check_cookie
+    // r7: callq __security_check_cookie
+    // r13: bl __security_check_cookie
+    // r35: calll @__security_check_cookie
+
+    // cuda doesn't support stack-smash protection
+    // r49-NOT: __security_check_cookie
+    // r49-NOT: __stack_chk_fail
+
+    // Other targets do stack checking within the function, and call a failure function on error
+    // r1: __stack_chk_fail
+    // r2: __stack_chk_fail
+    // r4: __stack_chk_fail
+    // r5: __stack_chk_fail
+    // r6: __stack_chk_fail
+    // r8: __stack_chk_fail
+    // r9: __stack_chk_fail
+    // r10: __stack_chk_fail
+    // r11: __stack_chk_fail
+    // r12: __stack_chk_fail
+    // r14: __stack_chk_fail
+    // r15: __stack_chk_fail
+    // r16: __stack_chk_fail
+    // r17: __stack_chk_fail
+    // r18: __stack_chk_fail
+    // r19: __stack_chk_fail
+    // r20: __stack_chk_fail
+    // r21: __stack_chk_fail
+    // r22: __stack_chk_fail
+    // r23: __stack_chk_fail
+    // r24: __stack_chk_fail
+    // r25: __stack_chk_fail
+    // r26: __stack_chk_fail
+    // r27: __stack_chk_fail
+    // r28: __stack_chk_fail
+    // r29: __stack_chk_fail
+    // r30: __stack_chk_fail
+    // r31: __stack_chk_fail
+    // r32: __stack_chk_fail
+    // r33: __stack_chk_fail
+    // r34: __stack_chk_fail
+    // r36: __stack_chk_fail
+    // r37: __stack_chk_fail
+    // r38: __stack_chk_fail
+    // r39: __stack_chk_fail
+    // r40: __stack_chk_fail
+    // r41: __stack_chk_fail
+    // r42: __stack_chk_fail
+    // r43: __stack_chk_fail
+    // r44: __stack_chk_fail
+    // r45: __stack_chk_fail
+    // r46: __stack_chk_fail
+    // r47: __stack_chk_fail
+    // r48: __stack_chk_fail
+    // r50: __stack_chk_fail
+    // r51: __stack_chk_fail
+    // r52: __stack_chk_fail
+    // r53: __stack_chk_fail
+    // r54: __stack_chk_fail
+    // r55: __stack_chk_fail
+    // r56: __stack_chk_fail
+    // r57: __stack_chk_fail
+    // r58: __stack_chk_fail
+    // r59: __stack_chk_fail
+    // r60: __stack_chk_fail
+    // r61: __stack_chk_fail
+    // r62: __stack_chk_fail
+    // r63: __stack_chk_fail
+    // r64: __stack_chk_fail
+    // r65: __stack_chk_fail
+    // r66: __stack_chk_fail
+    // r67: __stack_chk_fail
+    // r68: __stack_chk_fail
+    // r69: __stack_chk_fail
+    // r70: __stack_chk_fail
+    // r71: __stack_chk_fail
+    // r72: __stack_chk_fail
+    // r73: __stack_chk_fail
+    // r74: __stack_chk_fail
+    // r75: __stack_chk_fail
+    // r76: __stack_chk_fail
+    // r77: __stack_chk_fail
+    // r78: __stack_chk_fail
+    // r79: __stack_chk_fail
+    // r80: __stack_chk_fail
+    // r81: __stack_chk_fail
+    // r82: __stack_chk_fail
+    // r83: __stack_chk_fail
+    // r84: __stack_chk_fail
+}
diff --git a/src/test/codegen/stack-protector.rs b/src/test/codegen/stack-protector.rs
new file mode 100644
index 0000000000000..2198593eb57ae
--- /dev/null
+++ b/src/test/codegen/stack-protector.rs
@@ -0,0 +1,33 @@
+// revisions: all strong basic none
+// [all] compile-flags: -Z stack-protector=all
+// [strong] compile-flags: -Z stack-protector=strong
+// [basic] compile-flags: -Z stack-protector=basic
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: @foo() unnamed_addr #0
+
+    // all-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} }
+    // all-NOT: attributes #0 = { {{.*}} ssp {{.*}} }
+    // all: attributes #0 = { {{.*}} sspreq {{.*}} }
+    // all-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} }
+    // all-NOT: attributes #0 = { {{.*}} ssp {{.*}} }
+
+    // strong-NOT: attributes #0 = { {{.*}} sspreq {{.*}} }
+    // strong-NOT: attributes #0 = { {{.*}} ssp {{.*}} }
+    // strong: attributes #0 = { {{.*}} sspstrong {{.*}} }
+    // strong-NOT: attributes #0 = { {{.*}} sspreq {{.*}} }
+    // strong-NOT: attributes #0 = { {{.*}} ssp {{.*}} }
+
+    // basic-NOT: attributes #0 = { {{.*}} sspreq {{.*}} }
+    // basic-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} }
+    // basic: attributes #0 = { {{.*}} ssp {{.*}} }
+    // basic-NOT: attributes #0 = { {{.*}} sspreq {{.*}} }
+    // basic-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} }
+
+    // none-NOT: attributes #0 = { {{.*}} sspreq {{.*}} }
+    // none-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} }
+    // none-NOT: attributes #0 = { {{.*}} ssp {{.*}} }
+}
diff --git a/src/test/pretty/anonymous-types.rs b/src/test/pretty/anonymous-types.rs
deleted file mode 100644
index 5ff452e8e43c4..0000000000000
--- a/src/test/pretty/anonymous-types.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Test for issue 85480
-// Pretty print anonymous struct and union types
-
-// pp-exact
-// pretty-compare-only
-
-struct Foo {
-    _: union {
-           _: struct {
-                  a: u8,
-                  b: u16,
-              },
-           c: u32,
-       },
-    d: u64,
-    e: f32,
-}
-
-type A =
- struct {
-     field: u8,
- };
-
-fn main() { }
diff --git a/src/test/ui/abi/stack-protector.rs b/src/test/ui/abi/stack-protector.rs
new file mode 100644
index 0000000000000..24bd2e2194313
--- /dev/null
+++ b/src/test/ui/abi/stack-protector.rs
@@ -0,0 +1,99 @@
+// run-pass
+// only-x86_64-unknown-linux-gnu
+// revisions: ssp no-ssp
+// [ssp] compile-flags: -Z stack-protector=all
+// compile-flags: -C opt-level=2
+// compile-flags: -g
+
+use std::env;
+use std::process::{Command, ExitStatus};
+
+fn main() {
+    if env::args().len() == 1 {
+        // The test is initially run without arguments. Start the process again,
+        // this time *with* an argument; in this configuration, the test program
+        // will deliberately smash the stack.
+        let cur_argv0 = env::current_exe().unwrap();
+        let mut child = Command::new(&cur_argv0);
+        child.arg("stacksmash");
+
+        if cfg!(ssp) {
+            assert_stack_smash_prevented(&mut child);
+        } else {
+            assert_stack_smashed(&mut child);
+        }
+    } else {
+        vulnerable_function();
+        // If we return here the test is broken: it should either have called
+        // malicious_code() which terminates the process, or be caught by the
+        // stack check which also terminates the process.
+        panic!("TEST BUG: stack smash unsuccessful");
+    }
+}
+
+// Avoid inlining to make sure the return address is pushed to stack.
+#[inline(never)]
+fn vulnerable_function() {
+    let mut x = 5usize;
+    let stackaddr = &mut x as *mut usize;
+    let bad_code_ptr = malicious_code as usize;
+    // Overwrite the on-stack return address with the address of `malicious_code()`,
+    // thereby jumping to that function when returning from `vulnerable_function()`.
+    unsafe { fill(stackaddr, bad_code_ptr, 20); }
+}
+
+// Use an uninlined function with its own stack frame to make sure that we don't
+// clobber e.g. the counter or address local variable.
+#[inline(never)]
+unsafe fn fill(addr: *mut usize, val: usize, count: usize) {
+    let mut addr = addr;
+    for _ in 0..count {
+        *addr = val;
+        addr = addr.add(1);
+    }
+}
+
+// We jump to malicious_code() having wreaked havoc with the previous stack
+// frame and not setting up a new one. This function is therefore constrained,
+// e.g. both println!() and std::process::exit() segfaults if called. We
+// therefore keep the amount of work to a minimum by calling POSIX functions
+// directly.
+// The function is un-inlined just to make it possible to set a breakpoint here.
+#[inline(never)]
+fn malicious_code() {
+    let msg = [112u8, 119u8, 110u8, 101u8, 100u8, 33u8, 0u8]; // "pwned!\0" ascii
+    unsafe {
+        write(1, &msg as *const u8, msg.len());
+        _exit(0);
+    }
+}
+extern "C" {
+    fn write(fd: i32, buf: *const u8, count: usize) -> isize;
+    fn _exit(status: i32) -> !;
+}
+
+
+fn assert_stack_smash_prevented(cmd: &mut Command) {
+    let (status, stdout, stderr) = run(cmd);
+    assert!(!status.success());
+    assert!(stdout.is_empty());
+    assert!(stderr.contains("stack smashing detected"));
+}
+
+fn assert_stack_smashed(cmd: &mut Command) {
+    let (status, stdout, stderr) = run(cmd);
+    assert!(status.success());
+    assert!(stdout.contains("pwned!"));
+    assert!(stderr.is_empty());
+}
+
+
+fn run(cmd: &mut Command) -> (ExitStatus, String, String) {
+    let output = cmd.output().unwrap();
+    let stdout = String::from_utf8_lossy(&output.stdout);
+    let stderr = String::from_utf8_lossy(&output.stderr);
+    println!("status: {}", output.status);
+    println!("stdout: {}", stdout);
+    println!("stderr: {}", stderr);
+    (output.status, stdout.to_string(), stderr.to_string())
+}
diff --git a/src/test/ui/feature-gates/feature-gate-unnamed_fields.rs b/src/test/ui/feature-gates/feature-gate-unnamed_fields.rs
deleted file mode 100644
index bd815dbcc9242..0000000000000
--- a/src/test/ui/feature-gates/feature-gate-unnamed_fields.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-struct Foo {
-    foo: u8,
-    _: union { //~ ERROR unnamed fields are not yet fully implemented [E0658]
-    //~^ ERROR unnamed fields are not yet fully implemented [E0658]
-    //~| ERROR anonymous unions are unimplemented
-        bar: u8,
-        baz: u16
-    }
-}
-
-union Bar {
-    foobar: u8,
-    _: struct { //~ ERROR unnamed fields are not yet fully implemented [E0658]
-    //~^ ERROR unnamed fields are not yet fully implemented [E0658]
-    //~| ERROR anonymous structs are unimplemented
-    //~| ERROR unions may not contain fields that need dropping [E0740]
-        foobaz: u8,
-        barbaz: u16
-    }
-}
-
-struct S;
-struct Baz {
-    _: S //~ ERROR unnamed fields are not yet fully implemented [E0658]
-}
-
-fn main(){}
diff --git a/src/test/ui/feature-gates/feature-gate-unnamed_fields.stderr b/src/test/ui/feature-gates/feature-gate-unnamed_fields.stderr
deleted file mode 100644
index 4f3ab85c98792..0000000000000
--- a/src/test/ui/feature-gates/feature-gate-unnamed_fields.stderr
+++ /dev/null
@@ -1,111 +0,0 @@
-error[E0658]: unnamed fields are not yet fully implemented
-  --> $DIR/feature-gate-unnamed_fields.rs:3:5
-   |
-LL |     _: union {
-   |     ^
-   |
-   = note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information
-   = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
-
-error[E0658]: unnamed fields are not yet fully implemented
-  --> $DIR/feature-gate-unnamed_fields.rs:3:8
-   |
-LL |       _: union {
-   |  ________^
-LL | |
-LL | |
-LL | |         bar: u8,
-LL | |         baz: u16
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information
-   = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
-
-error[E0658]: unnamed fields are not yet fully implemented
-  --> $DIR/feature-gate-unnamed_fields.rs:13:5
-   |
-LL |     _: struct {
-   |     ^
-   |
-   = note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information
-   = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
-
-error[E0658]: unnamed fields are not yet fully implemented
-  --> $DIR/feature-gate-unnamed_fields.rs:13:8
-   |
-LL |       _: struct {
-   |  ________^
-LL | |
-LL | |
-LL | |
-LL | |         foobaz: u8,
-LL | |         barbaz: u16
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information
-   = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
-
-error[E0658]: unnamed fields are not yet fully implemented
-  --> $DIR/feature-gate-unnamed_fields.rs:24:5
-   |
-LL |     _: S
-   |     ^
-   |
-   = note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information
-   = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
-
-error: anonymous unions are unimplemented
-  --> $DIR/feature-gate-unnamed_fields.rs:3:8
-   |
-LL |       _: union {
-   |  ________^
-LL | |
-LL | |
-LL | |         bar: u8,
-LL | |         baz: u16
-LL | |     }
-   | |_____^
-
-error: anonymous structs are unimplemented
-  --> $DIR/feature-gate-unnamed_fields.rs:13:8
-   |
-LL |       _: struct {
-   |  ________^
-LL | |
-LL | |
-LL | |
-LL | |         foobaz: u8,
-LL | |         barbaz: u16
-LL | |     }
-   | |_____^
-
-error[E0740]: unions may not contain fields that need dropping
-  --> $DIR/feature-gate-unnamed_fields.rs:13:5
-   |
-LL | /     _: struct {
-LL | |
-LL | |
-LL | |
-LL | |         foobaz: u8,
-LL | |         barbaz: u16
-LL | |     }
-   | |_____^
-   |
-note: `std::mem::ManuallyDrop` can be used to wrap the type
-  --> $DIR/feature-gate-unnamed_fields.rs:13:5
-   |
-LL | /     _: struct {
-LL | |
-LL | |
-LL | |
-LL | |         foobaz: u8,
-LL | |         barbaz: u16
-LL | |     }
-   | |_____^
-
-error: aborting due to 8 previous errors
-
-Some errors have detailed explanations: E0658, E0740.
-For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/parser/issue-88583-union-as-ident.rs b/src/test/ui/parser/issue-88583-union-as-ident.rs
new file mode 100644
index 0000000000000..b3d66d46b1d4b
--- /dev/null
+++ b/src/test/ui/parser/issue-88583-union-as-ident.rs
@@ -0,0 +1,15 @@
+// check-pass
+
+#![allow(non_camel_case_types)]
+
+struct union;
+
+impl union {
+    pub fn new() -> Self {
+        union { }
+    }
+}
+
+fn main() {
+    let _u = union::new();
+}
diff --git a/src/test/ui/stack-protector/warn-stack-protector-unsupported.all.stderr b/src/test/ui/stack-protector/warn-stack-protector-unsupported.all.stderr
new file mode 100644
index 0000000000000..54887715523c1
--- /dev/null
+++ b/src/test/ui/stack-protector/warn-stack-protector-unsupported.all.stderr
@@ -0,0 +1,4 @@
+warning: `-Z stack-protector=all` is not supported for target nvptx64-nvidia-cuda and will be ignored
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr b/src/test/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr
new file mode 100644
index 0000000000000..f7a1ee39fb9af
--- /dev/null
+++ b/src/test/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr
@@ -0,0 +1,4 @@
+warning: `-Z stack-protector=basic` is not supported for target nvptx64-nvidia-cuda and will be ignored
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/stack-protector/warn-stack-protector-unsupported.rs b/src/test/ui/stack-protector/warn-stack-protector-unsupported.rs
new file mode 100644
index 0000000000000..6df5d3cd5ae1b
--- /dev/null
+++ b/src/test/ui/stack-protector/warn-stack-protector-unsupported.rs
@@ -0,0 +1,19 @@
+// build-pass
+// revisions: all strong basic
+// compile-flags: --target nvptx64-nvidia-cuda
+// needs-llvm-components: nvptx
+// [all] compile-flags: -Z stack-protector=all
+// [strong] compile-flags: -Z stack-protector=strong
+// [basic] compile-flags: -Z stack-protector=basic
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+pub fn main(){}
diff --git a/src/test/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr b/src/test/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr
new file mode 100644
index 0000000000000..ccc2f9f2cc5b8
--- /dev/null
+++ b/src/test/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr
@@ -0,0 +1,4 @@
+warning: `-Z stack-protector=strong` is not supported for target nvptx64-nvidia-cuda and will be ignored
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/unnamed_fields/restrict_anonymous.rs b/src/test/ui/unnamed_fields/restrict_anonymous.rs
deleted file mode 100644
index 99637d1105301..0000000000000
--- a/src/test/ui/unnamed_fields/restrict_anonymous.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-#![allow(incomplete_features)]
-#![feature(unnamed_fields)]
-
-fn f() -> struct { field: u8 } {} //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
-//~^ ERROR anonymous structs are unimplemented
-
-fn f2(a: struct { field: u8 } ) {} //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
-//~^ ERROR anonymous structs are unimplemented
-
-union G {
-    field: struct { field: u8 } //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
-    //~^ ERROR anonymous structs are unimplemented
-}
-//~| ERROR unions may not contain fields that need dropping [E0740]
-
-struct H { _: u8 } // Should error after hir checks
-
-struct I(struct { field: u8 }, u8); //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
-//~^ ERROR anonymous structs are unimplemented
-
-enum J {
-    K(struct { field: u8 }), //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
-    //~^ ERROR anonymous structs are unimplemented
-    L {
-        _ : struct { field: u8 } //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
-        //~^ ERROR anonymous fields are not allowed outside of structs or unions
-        //~| ERROR anonymous structs are unimplemented
-    },
-    M {
-        _ : u8 //~ ERROR anonymous fields are not allowed outside of structs or unions
-    }
-}
-
-static M: union { field: u8 } = 0; //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
-//~^ ERROR anonymous unions are unimplemented
-
-type N = union { field: u8 }; //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
-//~^ ERROR anonymous unions are unimplemented
-
-fn main() {
-    const O: struct { field: u8 } = 0; //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
-    //~^ ERROR anonymous structs are unimplemented
-
-    let p: [struct { field: u8 }; 1]; //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
-    //~^ ERROR anonymous structs are unimplemented
-
-    let q: (struct { field: u8 }, u8); //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
-    //~^ ERROR anonymous structs are unimplemented
-
-    let cl = || -> struct { field: u8 } {}; //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
-    //~^ ERROR anonymous structs are unimplemented
-}
diff --git a/src/test/ui/unnamed_fields/restrict_anonymous.stderr b/src/test/ui/unnamed_fields/restrict_anonymous.stderr
deleted file mode 100644
index efcf544fde4dc..0000000000000
--- a/src/test/ui/unnamed_fields/restrict_anonymous.stderr
+++ /dev/null
@@ -1,175 +0,0 @@
-error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous.rs:4:11
-   |
-LL | fn f() -> struct { field: u8 } {}
-   |           ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
-
-error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous.rs:7:10
-   |
-LL | fn f2(a: struct { field: u8 } ) {}
-   |          ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
-
-error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous.rs:11:12
-   |
-LL |     field: struct { field: u8 }
-   |            ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
-
-error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous.rs:18:10
-   |
-LL | struct I(struct { field: u8 }, u8);
-   |          ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
-
-error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous.rs:22:7
-   |
-LL |     K(struct { field: u8 }),
-   |       ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
-
-error: anonymous fields are not allowed outside of structs or unions
-  --> $DIR/restrict_anonymous.rs:25:9
-   |
-LL |         _ : struct { field: u8 }
-   |         -^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         anonymous field declared here
-
-error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous.rs:25:13
-   |
-LL |         _ : struct { field: u8 }
-   |             ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
-
-error: anonymous fields are not allowed outside of structs or unions
-  --> $DIR/restrict_anonymous.rs:30:9
-   |
-LL |         _ : u8
-   |         -^^^^^
-   |         |
-   |         anonymous field declared here
-
-error: anonymous unions are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous.rs:34:11
-   |
-LL | static M: union { field: u8 } = 0;
-   |           ^^^^^^^^^^^^^^^^^^^ anonymous union declared here
-
-error: anonymous unions are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous.rs:37:10
-   |
-LL | type N = union { field: u8 };
-   |          ^^^^^^^^^^^^^^^^^^^ anonymous union declared here
-
-error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous.rs:41:14
-   |
-LL |     const O: struct { field: u8 } = 0;
-   |              ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
-
-error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous.rs:44:13
-   |
-LL |     let p: [struct { field: u8 }; 1];
-   |             ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
-
-error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous.rs:47:13
-   |
-LL |     let q: (struct { field: u8 }, u8);
-   |             ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
-
-error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous.rs:50:20
-   |
-LL |     let cl = || -> struct { field: u8 } {};
-   |                    ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous.rs:4:11
-   |
-LL | fn f() -> struct { field: u8 } {}
-   |           ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous.rs:7:10
-   |
-LL | fn f2(a: struct { field: u8 } ) {}
-   |          ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous.rs:11:12
-   |
-LL |     field: struct { field: u8 }
-   |            ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous.rs:18:10
-   |
-LL | struct I(struct { field: u8 }, u8);
-   |          ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous.rs:22:7
-   |
-LL |     K(struct { field: u8 }),
-   |       ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous.rs:25:13
-   |
-LL |         _ : struct { field: u8 }
-   |             ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous unions are unimplemented
-  --> $DIR/restrict_anonymous.rs:34:11
-   |
-LL | static M: union { field: u8 } = 0;
-   |           ^^^^^^^^^^^^^^^^^^^
-
-error: anonymous unions are unimplemented
-  --> $DIR/restrict_anonymous.rs:37:10
-   |
-LL | type N = union { field: u8 };
-   |          ^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous.rs:44:13
-   |
-LL |     let p: [struct { field: u8 }; 1];
-   |             ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous.rs:47:13
-   |
-LL |     let q: (struct { field: u8 }, u8);
-   |             ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous.rs:50:20
-   |
-LL |     let cl = || -> struct { field: u8 } {};
-   |                    ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous.rs:41:14
-   |
-LL |     const O: struct { field: u8 } = 0;
-   |              ^^^^^^^^^^^^^^^^^^^^
-
-error[E0740]: unions may not contain fields that need dropping
-  --> $DIR/restrict_anonymous.rs:11:5
-   |
-LL |     field: struct { field: u8 }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: `std::mem::ManuallyDrop` can be used to wrap the type
-  --> $DIR/restrict_anonymous.rs:11:5
-   |
-LL |     field: struct { field: u8 }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 27 previous errors
-
-For more information about this error, try `rustc --explain E0740`.
diff --git a/src/tools/cargo b/src/tools/cargo
index 18751dd3f238d..e515c3277bf06 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 18751dd3f238d94d384a7fe967abfac06cbfe0b9
+Subproject commit e515c3277bf0681bfc79a9e763861bfe26bb05db
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 2310370fb9fbe..40aaa5924df5b 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -21,37 +21,35 @@ name = "clippy-driver"
 path = "src/driver.rs"
 
 [dependencies]
-# begin automatic update
-clippy_lints = { version = "0.1.50", path = "clippy_lints" }
-# end automatic update
+clippy_lints = { version = "0.1", path = "clippy_lints" }
 semver = "0.11"
-rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" }
-tempfile = { version = "3.1.0", optional = true }
+rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
+tempfile = { version = "3.2", optional = true }
 
 [dev-dependencies]
 cargo_metadata = "0.12"
-compiletest_rs = { version = "0.6.0", features = ["tmp"] }
+compiletest_rs = { version = "0.7", features = ["tmp"] }
 tester = "0.9"
-regex = "1.4"
+regex = "1.5"
 # This is used by the `collect-metadata` alias.
 filetime = "0.2"
 
 # A noop dependency that changes in the Rust repository, it's a bit of a hack.
 # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
 # for more information.
-rustc-workspace-hack = "1.0.0"
+rustc-workspace-hack = "1.0"
 
 # UI test dependencies
 clippy_utils = { path = "clippy_utils" }
 derive-new = "0.5"
 if_chain = "1.0"
-itertools = "0.10.1"
-quote = "1"
+itertools = "0.10"
+quote = "1.0"
 serde = { version = "1.0", features = ["derive"] }
-syn = { version = "1", features = ["full"] }
+syn = { version = "1.0", features = ["full"] }
 
 [build-dependencies]
-rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" }
+rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
 
 [features]
 deny-warnings = ["clippy_lints/deny-warnings"]
diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml
index 0fae8c7b9afcf..d7d2655026b4b 100644
--- a/src/tools/clippy/clippy_dev/Cargo.toml
+++ b/src/tools/clippy/clippy_dev/Cargo.toml
@@ -6,11 +6,11 @@ edition = "2018"
 [dependencies]
 bytecount = "0.6"
 clap = "2.33"
-itertools = "0.9"
+itertools = "0.10"
 opener = "0.5"
-regex = "1"
+regex = "1.5"
 shell-escape = "0.1"
-walkdir = "2"
+walkdir = "2.3"
 
 [features]
 deny-warnings = []
diff --git a/src/tools/clippy/clippy_dummy/Cargo.toml b/src/tools/clippy/clippy_dummy/Cargo.toml
index a1707bad5c268..c206a1eb07b50 100644
--- a/src/tools/clippy/clippy_dummy/Cargo.toml
+++ b/src/tools/clippy/clippy_dummy/Cargo.toml
@@ -13,4 +13,4 @@ keywords = ["clippy", "lint", "plugin"]
 categories = ["development-tools", "development-tools::cargo-plugins"]
 
 [build-dependencies]
-term = "0.6"
+term = "0.7"
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 3c28024bf926a..e59175a55e184 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -11,21 +11,21 @@ edition = "2018"
 [dependencies]
 cargo_metadata = "0.12"
 clippy_utils = { path = "../clippy_utils" }
-if_chain = "1.0.0"
-itertools = "0.9"
+if_chain = "1.0"
+itertools = "0.10"
 pulldown-cmark = { version = "0.8", default-features = false }
-quine-mc_cluskey = "0.2.2"
+quine-mc_cluskey = "0.2"
 regex-syntax = "0.6"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = { version = "1.0", optional = true }
-toml = "0.5.3"
+toml = "0.5"
 unicode-normalization = "0.1"
-unicode-script = { version = "0.5.3", default-features = false }
+unicode-script = { version = "0.5", default-features = false }
 semver = "0.11"
-rustc-semver = "1.1.0"
+rustc-semver = "1.1"
 # NOTE: cargo requires serde feat in its url dep
 # see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864>
-url = { version = "2.1.0", features = ["serde"] }
+url = { version = "2.2", features = ["serde"] }
 
 [features]
 deny-warnings = ["clippy_utils/deny-warnings"]
diff --git a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs
index bd5426ba707a8..162911b77d615 100644
--- a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs
@@ -1,7 +1,5 @@
 //! lint on missing cargo common metadata
 
-use std::path::PathBuf;
-
 use clippy_utils::{diagnostics::span_lint, is_lint_allowed};
 use rustc_hir::{hir_id::CRATE_HIR_ID, Crate};
 use rustc_lint::{LateContext, LateLintPass};
@@ -69,12 +67,8 @@ fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, fiel
     span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message);
 }
 
-fn is_empty_str(value: &Option<String>) -> bool {
-    value.as_ref().map_or(true, String::is_empty)
-}
-
-fn is_empty_path(value: &Option<PathBuf>) -> bool {
-    value.as_ref().and_then(|x| x.to_str()).map_or(true, str::is_empty)
+fn is_empty_str<T: AsRef<std::ffi::OsStr>>(value: &Option<T>) -> bool {
+    value.as_ref().map_or(true, |s| s.as_ref().is_empty())
 }
 
 fn is_empty_vec(value: &[String]) -> bool {
@@ -98,7 +92,7 @@ impl LateLintPass<'_> for CargoCommonMetadata {
                     missing_warning(cx, &package, "package.description");
                 }
 
-                if is_empty_str(&package.license) && is_empty_path(&package.license_file) {
+                if is_empty_str(&package.license) && is_empty_str(&package.license_file) {
                     missing_warning(cx, &package, "either package.license or package.license_file");
                 }
 
@@ -106,7 +100,7 @@ impl LateLintPass<'_> for CargoCommonMetadata {
                     missing_warning(cx, &package, "package.repository");
                 }
 
-                if is_empty_path(&package.readme) {
+                if is_empty_str(&package.readme) {
                     missing_warning(cx, &package, "package.readme");
                 }
 
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 4c038a997952a..7c24e830e71dc 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -5,8 +5,8 @@ edition = "2018"
 publish = false
 
 [dependencies]
-if_chain = "1.0.0"
-rustc-semver="1.1.0"
+if_chain = "1.0"
+rustc-semver = "1.1"
 
 [features]
 deny-warnings = []
diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index ada033de6e3ab..f33f1b65eabdb 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -11,15 +11,15 @@ publish = false
 
 [dependencies]
 clap = "2.33"
-flate2 = {version = "1.0.19"}
-fs_extra = {version = "1.2.0"}
-rayon = {version = "1.5.0"}
-serde = {version = "1.0", features = ["derive"]}
-serde_json = {version = "1.0"}
-tar = {version = "0.4.30"}
-toml = {version = "0.5"}
-ureq = {version = "2.0.0-rc3"}
-walkdir = {version = "2.3.2"}
+flate2 = "1.0"
+fs_extra = "1.2"
+rayon = "1.5"
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
+tar = "0.4"
+toml = "0.5"
+ureq = "2.2"
+walkdir = "2.3"
 
 [features]
 deny-warnings = []
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 2483d0570d9ea..14041539b9dfd 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -6,7 +6,7 @@ use std::cmp::{max, min, Ordering};
 use regex::Regex;
 use rustc_ast::visit;
 use rustc_ast::{ast, ptr};
-use rustc_span::{symbol, BytePos, Span};
+use rustc_span::{symbol, BytePos, Span, DUMMY_SP};
 
 use crate::attr::filter_inline_attrs;
 use crate::comment::{
@@ -31,7 +31,12 @@ use crate::stmt::Stmt;
 use crate::utils::*;
 use crate::vertical::rewrite_with_alignment;
 use crate::visitor::FmtVisitor;
-use crate::DEFAULT_VISIBILITY;
+
+const DEFAULT_VISIBILITY: ast::Visibility = ast::Visibility {
+    kind: ast::VisibilityKind::Inherited,
+    span: DUMMY_SP,
+    tokens: None,
+};
 
 fn type_annotation_separator(config: &Config) -> &str {
     colon_spaces(config)
@@ -972,7 +977,7 @@ impl<'a> StructParts<'a> {
         format_header(context, self.prefix, self.ident, self.vis, offset)
     }
 
-    pub(crate) fn from_variant(variant: &'a ast::Variant) -> Self {
+    fn from_variant(variant: &'a ast::Variant) -> Self {
         StructParts {
             prefix: "",
             ident: variant.ident,
diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs
index 206d2f782909c..47a7b9d4dbe3c 100644
--- a/src/tools/rustfmt/src/lib.rs
+++ b/src/tools/rustfmt/src/lib.rs
@@ -32,7 +32,7 @@ use std::path::PathBuf;
 use std::rc::Rc;
 
 use rustc_ast::ast;
-use rustc_span::{symbol, DUMMY_SP};
+use rustc_span::symbol;
 use thiserror::Error;
 
 use crate::comment::LineClasses;
@@ -96,11 +96,6 @@ mod types;
 mod vertical;
 pub(crate) mod visitor;
 
-const DEFAULT_VISIBILITY: ast::Visibility = ast::Visibility {
-    kind: ast::VisibilityKind::Inherited,
-    span: DUMMY_SP,
-    tokens: None,
-};
 /// The various errors that can occur during formatting. Note that not all of
 /// these can currently be propagated to clients.
 #[derive(Error, Debug)]
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 640d127e86098..76bf58e875b1f 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -1,15 +1,15 @@
 use std::iter::ExactSizeIterator;
 use std::ops::Deref;
 
-use rustc_ast::ast::{self, AttrVec, FnRetTy, Mutability};
-use rustc_span::{symbol::kw, symbol::Ident, BytePos, Pos, Span};
+use rustc_ast::ast::{self, FnRetTy, Mutability};
+use rustc_span::{symbol::kw, BytePos, Pos, Span};
 
+use crate::comment::{combine_strs_with_missing_comments, contains_comment};
 use crate::config::lists::*;
 use crate::config::{IndentStyle, TypeDensity, Version};
 use crate::expr::{
     format_expr, rewrite_assign_rhs, rewrite_call, rewrite_tuple, rewrite_unary_prefix, ExprType,
 };
-use crate::items::StructParts;
 use crate::lists::{
     definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator,
 };
@@ -24,11 +24,6 @@ use crate::utils::{
     colon_spaces, extra_offset, first_line_width, format_extern, format_mutability,
     last_line_extendable, last_line_width, mk_sp, rewrite_ident,
 };
-use crate::DEFAULT_VISIBILITY;
-use crate::{
-    comment::{combine_strs_with_missing_comments, contains_comment},
-    items::format_struct_struct,
-};
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub(crate) enum PathContext {
@@ -769,54 +764,6 @@ impl Rewrite for ast::Ty {
             ast::TyKind::Tup(ref items) => {
                 rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1)
             }
-            ast::TyKind::AnonymousStruct(ref fields, recovered) => {
-                let ident = Ident::new(
-                    kw::Struct,
-                    mk_sp(self.span.lo(), self.span.lo() + BytePos(6)),
-                );
-                let data = ast::VariantData::Struct(fields.clone(), recovered);
-                let variant = ast::Variant {
-                    attrs: AttrVec::new(),
-                    id: self.id,
-                    span: self.span,
-                    vis: DEFAULT_VISIBILITY,
-                    ident,
-                    data,
-                    disr_expr: None,
-                    is_placeholder: false,
-                };
-                format_struct_struct(
-                    &context,
-                    &StructParts::from_variant(&variant),
-                    fields,
-                    shape.indent,
-                    None,
-                )
-            }
-            ast::TyKind::AnonymousUnion(ref fields, recovered) => {
-                let ident = Ident::new(
-                    kw::Union,
-                    mk_sp(self.span.lo(), self.span.lo() + BytePos(5)),
-                );
-                let data = ast::VariantData::Struct(fields.clone(), recovered);
-                let variant = ast::Variant {
-                    attrs: AttrVec::new(),
-                    id: self.id,
-                    span: self.span,
-                    vis: DEFAULT_VISIBILITY,
-                    ident,
-                    data,
-                    disr_expr: None,
-                    is_placeholder: false,
-                };
-                format_struct_struct(
-                    &context,
-                    &StructParts::from_variant(&variant),
-                    fields,
-                    shape.indent,
-                    None,
-                )
-            }
             ast::TyKind::Path(ref q_self, ref path) => {
                 rewrite_path(context, PathContext::Type, q_self.as_ref(), path, shape)
             }