about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs10
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs7
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs10
-rw-r--r--compiler/rustc_ast_pretty/src/pprust.rs11
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs2
-rw-r--r--compiler/rustc_expand/src/config.rs2
-rw-r--r--compiler/rustc_expand/src/expand.rs27
-rw-r--r--compiler/rustc_expand/src/module.rs12
-rw-r--r--compiler/rustc_feature/src/active.rs6
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs22
-rw-r--r--compiler/rustc_mir/src/borrow_check/region_infer/values.rs4
-rw-r--r--compiler/rustc_mir/src/monomorphize/partitioning/mod.rs6
-rw-r--r--compiler/rustc_mir/src/transform/instrument_coverage.rs2
-rw-r--r--compiler/rustc_mir/src/transform/simplify_try.rs2
-rw-r--r--compiler/rustc_mir/src/transform/validate.rs28
-rw-r--r--compiler/rustc_mir/src/util/pretty.rs2
-rw-r--r--compiler/rustc_parse/src/lib.rs2
-rw-r--r--compiler/rustc_parse/src/parser/item.rs67
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_save_analysis/src/sig.rs2
-rw-r--r--compiler/rustc_session/src/config.rs4
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs47
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs118
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs90
-rw-r--r--compiler/rustc_typeck/src/collect.rs41
-rw-r--r--library/core/src/ops/arith.rs77
-rw-r--r--src/doc/rustc/src/lints/listing/allowed-by-default.md3
-rw-r--r--src/doc/rustdoc/src/what-is-rustdoc.md23
-rw-r--r--src/test/ui/ast-json/ast-json-noexpand-output.stdout2
-rw-r--r--src/test/ui/ast-json/ast-json-output.stdout2
-rw-r--r--src/test/ui/const-generics/auxiliary/const_generic_lib.rs4
-rw-r--r--src/test/ui/const-generics/auxiliary/impl-const.rs4
-rw-r--r--src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr (renamed from src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr)4
-rw-r--r--src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr15
-rw-r--r--src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs1
-rw-r--r--src/test/ui/const-generics/const-argument-cross-crate.rs1
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs14
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr10
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple.rs14
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs12
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr9
-rw-r--r--src/test/ui/const-generics/defaults/complex-unord-param.min.stderr8
-rw-r--r--src/test/ui/const-generics/defaults/complex-unord-param.rs10
-rw-r--r--src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr (renamed from src/test/ui/const-generics/defaults/intermixed-lifetime.stderr)4
-rw-r--r--src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr26
-rw-r--r--src/test/ui/const-generics/defaults/intermixed-lifetime.rs12
-rw-r--r--src/test/ui/const-generics/defaults/simple-defaults.min.stderr8
-rw-r--r--src/test/ui/const-generics/defaults/simple-defaults.rs9
-rw-r--r--src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs4
-rw-r--r--src/test/ui/const-generics/issues/issue-61935.full.stderr10
-rw-r--r--src/test/ui/const-generics/issues/issue-61935.min.stderr10
-rw-r--r--src/test/ui/const-generics/issues/issue-61935.rs9
-rw-r--r--src/test/ui/const-generics/issues/issue-61935.stderr19
-rw-r--r--src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs8
-rw-r--r--src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr19
-rw-r--r--src/test/ui/const-generics/issues/issue-62220.full.stderr (renamed from src/test/ui/const-generics/issues/issue-62220.stderr)2
-rw-r--r--src/test/ui/const-generics/issues/issue-62220.min.stderr10
-rw-r--r--src/test/ui/const-generics/issues/issue-62220.rs9
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.full.stderr10
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.min.stderr10
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.rs9
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.stderr19
-rw-r--r--src/test/ui/const-generics/issues/issue-62504.full.stderr (renamed from src/test/ui/const-generics/issues/issue-62504.stderr)2
-rw-r--r--src/test/ui/const-generics/issues/issue-62504.min.stderr10
-rw-r--r--src/test/ui/const-generics/issues/issue-62504.rs10
-rw-r--r--src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr11
-rw-r--r--src/test/ui/const-generics/issues/issue-62579-no-match.rs10
-rw-r--r--src/test/ui/const-generics/issues/issue-62579-no-match.stderr11
-rw-r--r--src/test/ui/const-generics/issues/issue-62878.full.stderr (renamed from src/test/ui/const-generics/issues/issue-62878.stderr)19
-rw-r--r--src/test/ui/const-generics/issues/issue-62878.min.stderr18
-rw-r--r--src/test/ui/const-generics/issues/issue-62878.rs12
-rw-r--r--src/test/ui/const-generics/issues/issue-67185-2.full.stderr (renamed from src/test/ui/const-generics/issues/issue-67185-2.stderr)23
-rw-r--r--src/test/ui/const-generics/issues/issue-67185-2.min.stderr103
-rw-r--r--src/test/ui/const-generics/issues/issue-67185-2.rs6
-rw-r--r--src/test/ui/const-generics/issues/issue-67739.full.stderr (renamed from src/test/ui/const-generics/issues/issue-67739.stderr)0
-rw-r--r--src/test/ui/const-generics/issues/issue-67739.min.stderr10
-rw-r--r--src/test/ui/const-generics/issues/issue-67739.rs11
-rw-r--r--src/test/ui/const-generics/issues/issue-68366.full.stderr (renamed from src/test/ui/const-generics/issues/issue-68366.stderr)4
-rw-r--r--src/test/ui/const-generics/issues/issue-68366.min.stderr29
-rw-r--r--src/test/ui/const-generics/issues/issue-68366.rs7
-rw-r--r--src/test/ui/const-generics/issues/issue-72787.full.stderr (renamed from src/test/ui/const-generics/issues/issue-72787.stderr)10
-rw-r--r--src/test/ui/const-generics/issues/issue-72787.min.stderr57
-rw-r--r--src/test/ui/const-generics/issues/issue-72787.rs22
-rw-r--r--src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr (renamed from src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr)2
-rw-r--r--src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr10
-rw-r--r--src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs9
-rw-r--r--src/test/ui/const-generics/issues/issue-73120.rs1
-rw-r--r--src/test/ui/issues/issue-76077-1.fixed18
-rw-r--r--src/test/ui/issues/issue-76077-1.rs18
-rw-r--r--src/test/ui/issues/issue-76077-1.stderr24
-rw-r--r--src/test/ui/issues/issue-76077.rs10
-rw-r--r--src/test/ui/issues/issue-76077.stderr8
-rw-r--r--src/test/ui/parser/unsafe-foreign-mod.rs9
-rw-r--r--src/test/ui/parser/unsafe-foreign-mod.stderr14
-rw-r--r--src/test/ui/parser/unsafe-mod.rs9
-rw-r--r--src/test/ui/parser/unsafe-mod.stderr23
-rw-r--r--src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs89
-rw-r--r--src/test/ui/proc-macro/unsafe-foreign-mod.rs14
-rw-r--r--src/test/ui/proc-macro/unsafe-mod.rs13
104 files changed, 1320 insertions, 301 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 49aa1fc1735..b9f380dc4e8 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2289,12 +2289,15 @@ impl FnRetTy {
 /// Module declaration.
 ///
 /// E.g., `mod foo;` or `mod foo { .. }`.
-#[derive(Clone, Encodable, Decodable, Debug, Default)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Mod {
     /// A span from the first token past `{` to the last token until `}`.
     /// For `mod foo;`, the inner span ranges from the first token
     /// to the last token in the external file.
     pub inner: Span,
+    /// `unsafe` keyword accepted syntactically for macro DSLs, but not
+    /// semantically by Rust.
+    pub unsafety: Unsafe,
     pub items: Vec<P<Item>>,
     /// `true` for `mod foo { .. }`; `false` for `mod foo;`.
     pub inline: bool,
@@ -2302,9 +2305,12 @@ pub struct Mod {
 
 /// Foreign module declaration.
 ///
-/// E.g., `extern { .. }` or `extern C { .. }`.
+/// E.g., `extern { .. }` or `extern "C" { .. }`.
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct ForeignMod {
+    /// `unsafe` keyword accepted syntactically for macro DSLs, but not
+    /// semantically by Rust.
+    pub unsafety: Unsafe,
     pub abi: Option<StrLit>,
     pub items: Vec<P<ForeignItem>>,
 }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 3ef83ef3fc9..3119c5e0a12 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -490,7 +490,7 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
 }
 
 pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
-    let ForeignMod { abi: _, items } = foreign_mod;
+    let ForeignMod { unsafety: _, abi: _, items } = foreign_mod;
     items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
 }
 
@@ -970,7 +970,8 @@ pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
     vis.visit_asyncness(asyncness);
 }
 
-pub fn noop_visit_mod<T: MutVisitor>(Mod { inner, items, inline: _ }: &mut Mod, vis: &mut T) {
+pub fn noop_visit_mod<T: MutVisitor>(module: &mut Mod, vis: &mut T) {
+    let Mod { inner, unsafety: _, items, inline: _ } = module;
     vis.visit_span(inner);
     items.flat_map_in_place(|item| vis.flat_map_item(item));
 }
@@ -990,7 +991,7 @@ pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
 
         let len = items.len();
         if len == 0 {
-            let module = Mod { inner: span, items: vec![], inline: true };
+            let module = Mod { inner: span, unsafety: Unsafe::No, items: vec![], inline: true };
             Crate { module, attrs: vec![], span, proc_macros }
         } else if len == 1 {
             let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index a01dd8c939c..998acf4fd10 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -990,12 +990,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     self.error_item_without_body(item.span, "function", msg, " { <body> }");
                 }
             }
-            ItemKind::ForeignMod(_) => {
+            ItemKind::ForeignMod(ForeignMod { unsafety, .. }) => {
                 let old_item = mem::replace(&mut self.extern_mod, Some(item));
                 self.invalid_visibility(
                     &item.vis,
                     Some("place qualifiers on individual foreign items instead"),
                 );
+                if let Unsafe::Yes(span) = unsafety {
+                    self.err_handler().span_err(span, "extern block cannot be declared unsafe");
+                }
                 visit::walk_item(self, item);
                 self.extern_mod = old_item;
                 return; // Avoid visiting again.
@@ -1029,7 +1032,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 walk_list!(self, visit_attribute, &item.attrs);
                 return;
             }
-            ItemKind::Mod(Mod { inline, .. }) => {
+            ItemKind::Mod(Mod { inline, unsafety, .. }) => {
+                if let Unsafe::Yes(span) = unsafety {
+                    self.err_handler().span_err(span, "module cannot be declared unsafe");
+                }
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
                 if !inline && !self.session.contains_name(&item.attrs, sym::path) {
                     self.check_mod_file_item_asciionly(item.ident);
diff --git a/compiler/rustc_ast_pretty/src/pprust.rs b/compiler/rustc_ast_pretty/src/pprust.rs
index 9743a000429..955d1677647 100644
--- a/compiler/rustc_ast_pretty/src/pprust.rs
+++ b/compiler/rustc_ast_pretty/src/pprust.rs
@@ -1139,7 +1139,11 @@ impl<'a> State<'a> {
                 self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
             }
             ast::ItemKind::Mod(ref _mod) => {
-                self.head(visibility_qualified(&item.vis, "mod"));
+                self.head(to_string(|s| {
+                    s.print_visibility(&item.vis);
+                    s.print_unsafety(_mod.unsafety);
+                    s.word("mod");
+                }));
                 self.print_ident(item.ident);
 
                 if _mod.inline || self.is_expanded {
@@ -1154,7 +1158,10 @@ impl<'a> State<'a> {
                 }
             }
             ast::ItemKind::ForeignMod(ref nmod) => {
-                self.head("extern");
+                self.head(to_string(|s| {
+                    s.print_unsafety(nmod.unsafety);
+                    s.word("extern");
+                }));
                 if let Some(abi) = nmod.abi {
                     self.print_literal(&abi.as_lit());
                     self.nbsp();
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index 85cf4c42e94..b39423b86e7 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -166,14 +166,14 @@ pub mod printf {
             let cap = self.span.len() + if has_options { 2 } else { 0 };
             let mut s = String::with_capacity(cap);
 
-            s.push_str("{");
+            s.push('{');
 
             if let Some(arg) = self.parameter {
                 write!(s, "{}", arg.checked_sub(1)?).ok()?;
             }
 
             if has_options {
-                s.push_str(":");
+                s.push(':');
 
                 let align = if let Some(fill) = fill {
                     s.push_str(fill);
@@ -191,11 +191,11 @@ pub mod printf {
                 }
 
                 if alt {
-                    s.push_str("#");
+                    s.push('#');
                 }
 
                 if zero_fill {
-                    s.push_str("0");
+                    s.push('0');
                 }
 
                 if let Some(width) = width {
@@ -203,7 +203,7 @@ pub mod printf {
                 }
 
                 if let Some(precision) = precision {
-                    s.push_str(".");
+                    s.push('.');
                     precision.translate(&mut s).ok()?;
                 }
 
@@ -212,7 +212,7 @@ pub mod printf {
                 }
             }
 
-            s.push_str("}");
+            s.push('}');
             Some(s)
         }
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index c044020d930..faeb727202c 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1076,7 +1076,7 @@ fn exec_linker(
             }
             .to_string(),
         );
-        args.push_str("\n");
+        args.push('\n');
     }
     let file = tmpdir.join("linker-arguments");
     let bytes = if sess.target.target.options.is_like_msvc {
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 54e5d4d00f6..0c0f1bc681c 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -37,7 +37,7 @@ pub fn push_debuginfo_type_name<'tcx>(
         ty::Bool => output.push_str("bool"),
         ty::Char => output.push_str("char"),
         ty::Str => output.push_str("str"),
-        ty::Never => output.push_str("!"),
+        ty::Never => output.push('!'),
         ty::Int(int_ty) => output.push_str(int_ty.name_str()),
         ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()),
         ty::Float(float_ty) => output.push_str(float_ty.name_str()),
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 97608a38903..dd087ab9150 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -399,7 +399,7 @@ impl<'a> StripUnconfigured<'a> {
     }
 
     pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) {
-        let ast::ForeignMod { abi: _, items } = foreign_mod;
+        let ast::ForeignMod { unsafety: _, abi: _, items } = foreign_mod;
         items.flat_map_in_place(|item| self.configure(item));
     }
 
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index ca6f7324ca4..241566a042a 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -13,7 +13,7 @@ use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::{self as ast, AttrItem, Block, LitKind, NodeId, PatKind, Path};
-use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind};
+use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind, Unsafe};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
 use rustc_data_structures::map_in_place::MapInPlace;
@@ -370,11 +370,21 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             None => {
                 // Resolution failed so we return an empty expansion
                 krate.attrs = vec![];
-                krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true };
+                krate.module = ast::Mod {
+                    inner: orig_mod_span,
+                    unsafety: Unsafe::No,
+                    items: vec![],
+                    inline: true,
+                };
             }
             Some(ast::Item { span, kind, .. }) => {
                 krate.attrs = vec![];
-                krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true };
+                krate.module = ast::Mod {
+                    inner: orig_mod_span,
+                    unsafety: Unsafe::No,
+                    items: vec![],
+                    inline: true,
+                };
                 self.cx.span_err(
                     span,
                     &format!(
@@ -1441,8 +1451,15 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                     push_directory(&self.cx.sess, ident, &item.attrs, dir)
                 } else {
                     // We have an outline `mod foo;` so we need to parse the file.
-                    let (new_mod, dir) =
-                        parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed);
+                    let (new_mod, dir) = parse_external_mod(
+                        &self.cx.sess,
+                        ident,
+                        span,
+                        old_mod.unsafety,
+                        dir,
+                        &mut attrs,
+                        pushed,
+                    );
 
                     let krate = ast::Crate {
                         span: new_mod.inner,
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index fefc0bdeb7c..171cb3fa8e6 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -1,4 +1,4 @@
-use rustc_ast::{token, Attribute, Mod};
+use rustc_ast::{token, Attribute, Mod, Unsafe};
 use rustc_errors::{struct_span_err, PResult};
 use rustc_parse::new_parser_from_file;
 use rustc_session::parse::ParseSess;
@@ -42,6 +42,7 @@ crate fn parse_external_mod(
     sess: &Session,
     id: Ident,
     span: Span, // The span to blame on errors.
+    unsafety: Unsafe,
     Directory { mut ownership, path }: Directory,
     attrs: &mut Vec<Attribute>,
     pop_mod_stack: &mut bool,
@@ -60,13 +61,16 @@ crate fn parse_external_mod(
         drop(included_mod_stack);
 
         // Actually parse the external file as a module.
-        let mut module =
-            new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)).parse_mod(&token::Eof)?;
+        let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span));
+        let mut module = parser.parse_mod(&token::Eof, unsafety)?;
         module.0.inline = false;
         module
     };
     // (1) ...instead, we return a dummy module.
-    let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_default();
+    let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_else(|_| {
+        let module = Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false };
+        (module, Vec::new())
+    });
     attrs.append(&mut new_attrs);
 
     // Extract the directory path for submodules of `module`.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 3d7b3da45cc..1aeb0bd5ad9 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -585,6 +585,9 @@ declare_features! (
     /// Allows `if let` guard in match arms.
     (active, if_let_guard, "1.47.0", Some(51114), None),
 
+    /// Allows non trivial generic constants which have to be manually propageted upwards.
+    (active, const_evaluatable_checked, "1.48.0", Some(76560), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -600,6 +603,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
     sym::const_generics,
     sym::let_chains,
     sym::raw_dylib,
+    sym::const_evaluatable_checked,
     sym::const_trait_impl,
     sym::const_trait_bound_opt_out,
     sym::lazy_normalization_consts,
@@ -607,6 +611,6 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
 ];
 
 /// Some features are not allowed to be used together at the same time, if
-/// the two are present, produce an error
+/// the two are present, produce an error.
 pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] =
     &[(sym::const_generics, sym::min_const_generics)];
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index b53605b0796..1225776db45 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2093,7 +2093,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 _ => String::new(),
             };
             if !s.is_empty() {
-                s.push_str(" ");
+                s.push(' ');
             }
             s
         };
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index 3e2ea3d0f8f..9f43fac0916 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -50,7 +50,7 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {
             ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
             ty::Covariant => self.relate(a, b),
             // FIXME(#41044) -- not correct, need test
-            ty::Bivariant => Ok(a.clone()),
+            ty::Bivariant => Ok(a),
             ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b),
         }
     }
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
index f51bf7730ea..3cee32834be 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
@@ -150,8 +150,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             Some(mut descr) => {
                 // Surround descr with `backticks`.
                 descr.reserve(2);
-                descr.insert_str(0, "`");
-                descr.push_str("`");
+                descr.insert(0, '`');
+                descr.push('`');
                 descr
             }
             None => "value".to_string(),
@@ -222,7 +222,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             if self.upvars[var_index].by_ref {
                                 buf.push_str(&name);
                             } else {
-                                buf.push_str(&format!("*{}", &name));
+                                buf.push('*');
+                                buf.push_str(&name);
                             }
                         } else {
                             if autoderef {
@@ -234,7 +235,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                     &including_downcast,
                                 )?;
                             } else {
-                                buf.push_str(&"*");
+                                buf.push('*');
                                 self.append_place_to_string(
                                     PlaceRef { local, projection: proj_base },
                                     buf,
@@ -272,7 +273,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                 autoderef,
                                 &including_downcast,
                             )?;
-                            buf.push_str(&format!(".{}", field_name));
+                            buf.push('.');
+                            buf.push_str(&field_name);
                         }
                     }
                     ProjectionElem::Index(index) => {
@@ -284,11 +286,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             autoderef,
                             &including_downcast,
                         )?;
-                        buf.push_str("[");
+                        buf.push('[');
                         if self.append_local_to_string(*index, buf).is_err() {
-                            buf.push_str("_");
+                            buf.push('_');
                         }
-                        buf.push_str("]");
+                        buf.push(']');
                     }
                     ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
                         autoderef = true;
@@ -301,7 +303,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             autoderef,
                             &including_downcast,
                         )?;
-                        buf.push_str(&"[..]");
+                        buf.push_str("[..]");
                     }
                 };
             }
@@ -648,7 +650,7 @@ impl UseSpans {
                     " in closure".to_string()
                 }
             }
-            _ => "".to_string(),
+            _ => String::new(),
         }
     }
 
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/values.rs b/compiler/rustc_mir/src/borrow_check/region_infer/values.rs
index 8a5a600cfdd..f247d07e1f0 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/values.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/values.rs
@@ -417,7 +417,7 @@ crate fn location_set_str(
 
 fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String {
     let mut result = String::new();
-    result.push_str("{");
+    result.push('{');
 
     // Set to Some(l1, l2) when we have observed all the locations
     // from l1..=l2 (inclusive) but not yet printed them. This
@@ -478,7 +478,7 @@ fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String
         push_location_range(&mut result, location1, location2);
     }
 
-    result.push_str("}");
+    result.push('}');
 
     return result;
 
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
index e96af77bbb8..0f6f078d968 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
+++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
@@ -382,7 +382,7 @@ fn collect_and_partition_mono_items<'tcx>(
                 cgus.sort_by_key(|(name, _)| *name);
                 cgus.dedup();
                 for &(ref cgu_name, (linkage, _)) in cgus.iter() {
-                    output.push_str(" ");
+                    output.push(' ');
                     output.push_str(&cgu_name.as_str());
 
                     let linkage_abbrev = match linkage {
@@ -399,9 +399,9 @@ fn collect_and_partition_mono_items<'tcx>(
                         Linkage::Common => "Common",
                     };
 
-                    output.push_str("[");
+                    output.push('[');
                     output.push_str(linkage_abbrev);
-                    output.push_str("]");
+                    output.push(']');
                 }
                 output
             })
diff --git a/compiler/rustc_mir/src/transform/instrument_coverage.rs b/compiler/rustc_mir/src/transform/instrument_coverage.rs
index 8f43df8a6cb..a5b30a25a9b 100644
--- a/compiler/rustc_mir/src/transform/instrument_coverage.rs
+++ b/compiler/rustc_mir/src/transform/instrument_coverage.rs
@@ -353,7 +353,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
                             if !INCLUDE_COVERAGE_STATEMENTS {
                                 continue;
                             }
-                            format!("unreachable")
+                            String::from("unreachable")
                         }
                     },
                     _ => format!("{:?}", statement),
diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs
index a7a3548189e..a320d00614d 100644
--- a/compiler/rustc_mir/src/transform/simplify_try.rs
+++ b/compiler/rustc_mir/src/transform/simplify_try.rs
@@ -674,7 +674,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
         y_bb_idx: BasicBlock,
     ) -> StatementEquality {
         let helper = |rhs: &Rvalue<'tcx>,
-                      place: &Box<Place<'tcx>>,
+                      place: &Place<'tcx>,
                       variant_index: &VariantIdx,
                       side_to_choose| {
             let place_type = place.ty(self.body, self.tcx).ty;
diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs
index 8f01e942801..d3ca14abdca 100644
--- a/compiler/rustc_mir/src/transform/validate.rs
+++ b/compiler/rustc_mir/src/transform/validate.rs
@@ -4,8 +4,8 @@ use super::{MirPass, MirSource};
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::{
     mir::{
-        AggregateKind, BasicBlock, Body, Location, MirPhase, Operand, Rvalue, Statement,
-        StatementKind, Terminator, TerminatorKind,
+        AggregateKind, BasicBlock, Body, BorrowKind, Location, MirPhase, Operand, Rvalue,
+        Statement, StatementKind, Terminator, TerminatorKind,
     },
     ty::{
         self,
@@ -274,9 +274,33 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             )
                         }
                     }
+                    Rvalue::Ref(_, BorrowKind::Shallow, _) => {
+                        if self.mir_phase > MirPhase::DropLowering {
+                            self.fail(
+                                location,
+                                "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase",
+                            );
+                        }
+                    }
                     _ => {}
                 }
             }
+            StatementKind::AscribeUserType(..) => {
+                if self.mir_phase > MirPhase::DropLowering {
+                    self.fail(
+                        location,
+                        "`AscribeUserType` should have been removed after drop lowering phase",
+                    );
+                }
+            }
+            StatementKind::FakeRead(..) => {
+                if self.mir_phase > MirPhase::DropLowering {
+                    self.fail(
+                        location,
+                        "`FakeRead` should have been removed after drop lowering phase",
+                    );
+                }
+            }
             _ => {}
         }
     }
diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs
index 54bc248bc5b..75567181b69 100644
--- a/compiler/rustc_mir/src/util/pretty.rs
+++ b/compiler/rustc_mir/src/util/pretty.rs
@@ -514,7 +514,7 @@ fn write_scope_tree(
                 write!(indented_decl, " as {:?}", user_ty).unwrap();
             }
         }
-        indented_decl.push_str(";");
+        indented_decl.push(';');
 
         let local_name =
             if local == RETURN_PLACE { " return place".to_string() } else { String::new() };
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index e7fd74f551a..12afc48356c 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -109,7 +109,7 @@ pub fn maybe_new_parser_from_source_str(
 }
 
 /// Creates a new parser, handling errors as appropriate if the file doesn't exist.
-/// If a span is given, that is used on an error as the as the source of the problem.
+/// If a span is given, that is used on an error as the source of the problem.
 pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, sp: Option<Span>) -> Parser<'a> {
     source_file_to_parser(sess, file_to_source_file(sess, path, sp))
 }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 9143af651df..1a428f8bb0a 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -28,7 +28,7 @@ impl<'a> Parser<'a> {
     /// Parses a source module as a crate. This is the main entry point for the parser.
     pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
         let lo = self.token.span;
-        let (module, attrs) = self.parse_mod(&token::Eof)?;
+        let (module, attrs) = self.parse_mod(&token::Eof, Unsafe::No)?;
         let span = lo.to(self.token.span);
         let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
         Ok(ast::Crate { attrs, module, span, proc_macros })
@@ -36,27 +36,38 @@ impl<'a> Parser<'a> {
 
     /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
     fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
+        let unsafety = self.parse_unsafety();
+        self.expect_keyword(kw::Mod)?;
         let id = self.parse_ident()?;
         let (module, mut inner_attrs) = if self.eat(&token::Semi) {
-            Default::default()
+            (Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }, Vec::new())
         } else {
             self.expect(&token::OpenDelim(token::Brace))?;
-            self.parse_mod(&token::CloseDelim(token::Brace))?
+            self.parse_mod(&token::CloseDelim(token::Brace), unsafety)?
         };
         attrs.append(&mut inner_attrs);
         Ok((id, ItemKind::Mod(module)))
     }
 
     /// Parses the contents of a module (inner attributes followed by module items).
-    pub fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec<Attribute>)> {
+    pub fn parse_mod(
+        &mut self,
+        term: &TokenKind,
+        unsafety: Unsafe,
+    ) -> PResult<'a, (Mod, Vec<Attribute>)> {
         let lo = self.token.span;
         let attrs = self.parse_inner_attributes()?;
-        let module = self.parse_mod_items(term, lo)?;
+        let module = self.parse_mod_items(term, lo, unsafety)?;
         Ok((module, attrs))
     }
 
     /// Given a termination token, parses all of the items in a module.
-    fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
+    fn parse_mod_items(
+        &mut self,
+        term: &TokenKind,
+        inner_lo: Span,
+        unsafety: Unsafe,
+    ) -> PResult<'a, Mod> {
         let mut items = vec![];
         while let Some(item) = self.parse_item()? {
             items.push(item);
@@ -75,7 +86,7 @@ impl<'a> Parser<'a> {
 
         let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };
 
-        Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
+        Ok(Mod { inner: inner_lo.to(hi), unsafety, items, inline: true })
     }
 }
 
@@ -235,8 +246,13 @@ impl<'a> Parser<'a> {
                 self.parse_item_extern_crate()?
             } else {
                 // EXTERN BLOCK
-                self.parse_item_foreign_mod(attrs)?
+                self.parse_item_foreign_mod(attrs, Unsafe::No)?
             }
+        } else if self.is_unsafe_foreign_mod() {
+            // EXTERN BLOCK
+            let unsafety = self.parse_unsafety();
+            self.expect_keyword(kw::Extern)?;
+            self.parse_item_foreign_mod(attrs, unsafety)?
         } else if self.is_static_global() {
             // STATIC ITEM
             self.bump(); // `static`
@@ -256,7 +272,9 @@ impl<'a> Parser<'a> {
         {
             // IMPL ITEM
             self.parse_item_impl(attrs, def())?
-        } else if self.eat_keyword(kw::Mod) {
+        } else if self.check_keyword(kw::Mod)
+            || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Mod])
+        {
             // MODULE ITEM
             self.parse_item_mod(attrs)?
         } else if self.eat_keyword(kw::Type) {
@@ -893,10 +911,14 @@ impl<'a> Parser<'a> {
     /// extern "C" {}
     /// extern {}
     /// ```
-    fn parse_item_foreign_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
+    fn parse_item_foreign_mod(
+        &mut self,
+        attrs: &mut Vec<Attribute>,
+        unsafety: Unsafe,
+    ) -> PResult<'a, ItemInfo> {
         let abi = self.parse_abi(); // ABI?
         let items = self.parse_item_list(attrs, |p| p.parse_foreign_item())?;
-        let module = ast::ForeignMod { abi, items };
+        let module = ast::ForeignMod { unsafety, abi, items };
         Ok((Ident::invalid(), ItemKind::ForeignMod(module)))
     }
 
@@ -938,6 +960,15 @@ impl<'a> Parser<'a> {
             .emit();
     }
 
+    fn is_unsafe_foreign_mod(&self) -> bool {
+        self.token.is_keyword(kw::Unsafe)
+            && self.is_keyword_ahead(1, &[kw::Extern])
+            && self.look_ahead(
+                2 + self.look_ahead(2, |t| t.can_begin_literal_maybe_minus() as usize),
+                |t| t.kind == token::OpenDelim(token::Brace),
+            )
+    }
+
     fn is_static_global(&mut self) -> bool {
         if self.check_keyword(kw::Static) {
             // Check if this could be a closure.
@@ -1552,10 +1583,14 @@ impl<'a> Parser<'a> {
             // `$qual fn` or `$qual $qual`:
             || QUALS.iter().any(|&kw| self.check_keyword(kw))
                 && self.look_ahead(1, |t| {
-                    // ...qualified and then `fn`, e.g. `const fn`.
+                    // `$qual fn`, e.g. `const fn` or `async fn`.
                     t.is_keyword(kw::Fn)
-                    // Two qualifiers. This is enough. Due `async` we need to check that it's reserved.
-                    || t.is_non_raw_ident_where(|i| QUALS.contains(&i.name) && i.is_reserved())
+                    // Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`.
+                    || t.is_non_raw_ident_where(|i| QUALS.contains(&i.name)
+                        // Rule out 2015 `const async: T = val`.
+                        && i.is_reserved()
+                        // Rule out unsafe extern block.
+                        && !self.is_unsafe_foreign_mod())
                 })
             // `extern ABI fn`
             || self.check_keyword(kw::Extern)
@@ -1567,9 +1602,9 @@ impl<'a> Parser<'a> {
     /// up to and including the `fn` keyword. The formal grammar is:
     ///
     /// ```
-    /// Extern = "extern" StringLit ;
+    /// Extern = "extern" StringLit? ;
     /// FnQual = "const"? "async"? "unsafe"? Extern? ;
-    /// FnFrontMatter = FnQual? "fn" ;
+    /// FnFrontMatter = FnQual "fn" ;
     /// ```
     pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
         let constness = self.parse_constness();
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index c95e7e193be..032d7cb3ed6 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -438,7 +438,7 @@ impl<'tcx> SaveContext<'tcx> {
                                     .next()
                                     .map(|item| item.def_id);
                             }
-                            qualname.push_str(">");
+                            qualname.push('>');
 
                             (qualname, trait_id, decl_id, docs, attrs)
                         }
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index 6dd7f89d594..747e198cd93 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -497,7 +497,7 @@ impl<'hir> Sig for hir::Item<'hir> {
                     sig.text.push_str(&bounds_to_string(bounds));
                 }
                 // FIXME where clause
-                sig.text.push_str(";");
+                sig.text.push(';');
 
                 Ok(sig)
             }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 19cd2385992..4aecb35294a 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -581,9 +581,9 @@ impl OutputFilenames {
 
         if !ext.is_empty() {
             if !extension.is_empty() {
-                extension.push_str(".");
+                extension.push('.');
                 extension.push_str(RUST_CGU_EXT);
-                extension.push_str(".");
+                extension.push('.');
             }
 
             extension.push_str(ext);
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 5092b945f72..407663e5757 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -348,6 +348,7 @@ symbols! {
         const_compare_raw_pointers,
         const_constructor,
         const_eval_limit,
+        const_evaluatable_checked,
         const_extern_fn,
         const_fn,
         const_fn_transmute,
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 013cd71ea30..fdb87c085b5 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -14,6 +14,24 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     span: Span,
 ) -> Result<(), ErrorHandled> {
+    debug!("is_const_evaluatable({:?}, {:?})", def, substs);
+    if infcx.tcx.features().const_evaluatable_checked {
+        // FIXME(const_evaluatable_checked): Actually look into generic constants to
+        // implement const equality.
+        for pred in param_env.caller_bounds() {
+            match pred.skip_binders() {
+                ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => {
+                    debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs);
+                    if b_def == def && b_substs == substs {
+                        debug!("is_const_evaluatable: caller_bound ~~> ok");
+                        return Ok(());
+                    }
+                }
+                _ => {} // don't care
+            }
+        }
+    }
+
     let future_compat_lint = || {
         if let Some(local_def_id) = def.did.as_local() {
             infcx.tcx.struct_span_lint_hir(
@@ -38,24 +56,23 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
     // See #74595 for more details about this.
     let concrete = infcx.const_eval_resolve(param_env, def, substs, None, Some(span));
 
-    let def_kind = infcx.tcx.def_kind(def.did);
-    match def_kind {
-        DefKind::AnonConst => {
-            let mir_body = if let Some(def) = def.as_const_arg() {
-                infcx.tcx.optimized_mir_of_const_arg(def)
-            } else {
-                infcx.tcx.optimized_mir(def.did)
-            };
-            if mir_body.is_polymorphic && concrete.is_ok() {
-                future_compat_lint();
-            }
-        }
-        _ => {
-            if substs.has_param_types_or_consts() && concrete.is_ok() {
-                future_compat_lint();
+    if concrete.is_ok() && substs.has_param_types_or_consts() {
+        match infcx.tcx.def_kind(def.did) {
+            DefKind::AnonConst => {
+                let mir_body = if let Some(def) = def.as_const_arg() {
+                    infcx.tcx.optimized_mir_of_const_arg(def)
+                } else {
+                    infcx.tcx.optimized_mir(def.did)
+                };
+
+                if mir_body.is_polymorphic {
+                    future_compat_lint();
+                }
             }
+            _ => future_compat_lint(),
         }
     }
 
+    debug!(?concrete, "is_const_evaluatable");
     concrete.map(drop)
 }
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index fa8b8dbd9f8..dba46f35dca 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1241,42 +1241,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 tcx.sess.span_err(span, "union expressions should have exactly one field");
             }
         } else if check_completeness && !error_happened && !remaining_fields.is_empty() {
-            let len = remaining_fields.len();
-
-            let mut displayable_field_names =
-                remaining_fields.keys().map(|ident| ident.as_str()).collect::<Vec<_>>();
-
-            displayable_field_names.sort();
+            let no_accessible_remaining_fields = remaining_fields
+                .iter()
+                .filter(|(_, (_, field))| {
+                    field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
+                })
+                .next()
+                .is_none();
 
-            let truncated_fields_error = if len <= 3 {
-                String::new()
+            if no_accessible_remaining_fields {
+                self.report_no_accessible_fields(adt_ty, span);
             } else {
-                format!(" and {} other field{}", (len - 3), if len - 3 == 1 { "" } else { "s" })
-            };
-
-            let remaining_fields_names = displayable_field_names
-                .iter()
-                .take(3)
-                .map(|n| format!("`{}`", n))
-                .collect::<Vec<_>>()
-                .join(", ");
-
-            struct_span_err!(
-                tcx.sess,
-                span,
-                E0063,
-                "missing field{} {}{} in initializer of `{}`",
-                pluralize!(remaining_fields.len()),
-                remaining_fields_names,
-                truncated_fields_error,
-                adt_ty
-            )
-            .span_label(
-                span,
-                format!("missing {}{}", remaining_fields_names, truncated_fields_error),
-            )
-            .emit();
+                self.report_missing_field(adt_ty, span, remaining_fields);
+            }
         }
+
         error_happened
     }
 
@@ -1293,6 +1272,79 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    /// Report an error for a struct field expression when there are fields which aren't provided.
+    ///
+    /// ```ignore (diagnostic)
+    /// error: missing field `you_can_use_this_field` in initializer of `foo::Foo`
+    ///  --> src/main.rs:8:5
+    ///   |
+    /// 8 |     foo::Foo {};
+    ///   |     ^^^^^^^^ missing `you_can_use_this_field`
+    ///
+    /// error: aborting due to previous error
+    /// ```
+    fn report_missing_field(
+        &self,
+        adt_ty: Ty<'tcx>,
+        span: Span,
+        remaining_fields: FxHashMap<Ident, (usize, &ty::FieldDef)>,
+    ) {
+        let tcx = self.tcx;
+        let len = remaining_fields.len();
+
+        let mut displayable_field_names =
+            remaining_fields.keys().map(|ident| ident.as_str()).collect::<Vec<_>>();
+
+        displayable_field_names.sort();
+
+        let truncated_fields_error = if len <= 3 {
+            String::new()
+        } else {
+            format!(" and {} other field{}", (len - 3), if len - 3 == 1 { "" } else { "s" })
+        };
+
+        let remaining_fields_names = displayable_field_names
+            .iter()
+            .take(3)
+            .map(|n| format!("`{}`", n))
+            .collect::<Vec<_>>()
+            .join(", ");
+
+        struct_span_err!(
+            tcx.sess,
+            span,
+            E0063,
+            "missing field{} {}{} in initializer of `{}`",
+            pluralize!(remaining_fields.len()),
+            remaining_fields_names,
+            truncated_fields_error,
+            adt_ty
+        )
+        .span_label(span, format!("missing {}{}", remaining_fields_names, truncated_fields_error))
+        .emit();
+    }
+
+    /// Report an error for a struct field expression when there are no visible fields.
+    ///
+    /// ```ignore (diagnostic)
+    /// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
+    ///  --> src/main.rs:8:5
+    ///   |
+    /// 8 |     foo::Foo {};
+    ///   |     ^^^^^^^^
+    ///
+    /// error: aborting due to previous error
+    /// ```
+    fn report_no_accessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) {
+        self.tcx.sess.span_err(
+            span,
+            &format!(
+                "cannot construct `{}` with struct literal syntax due to inaccessible fields",
+                adt_ty,
+            ),
+        );
+    }
+
     fn report_unknown_field(
         &self,
         ty: Ty<'tcx>,
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index f06929aa98f..1896155e327 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -1078,8 +1078,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut unmentioned_fields = variant
             .fields
             .iter()
-            .map(|field| field.ident.normalize_to_macros_2_0())
-            .filter(|ident| !used_fields.contains_key(&ident))
+            .map(|field| (field, field.ident.normalize_to_macros_2_0()))
+            .filter(|(_, ident)| !used_fields.contains_key(&ident))
             .collect::<Vec<_>>();
 
         let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered()) {
@@ -1110,7 +1110,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
             }
         } else if !etc && !unmentioned_fields.is_empty() {
-            unmentioned_err = Some(self.error_unmentioned_fields(pat, &unmentioned_fields));
+            let no_accessible_unmentioned_fields = unmentioned_fields
+                .iter()
+                .filter(|(field, _)| {
+                    field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
+                })
+                .next()
+                .is_none();
+
+            if no_accessible_unmentioned_fields {
+                unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields));
+            } else {
+                unmentioned_err = Some(self.error_unmentioned_fields(pat, &unmentioned_fields));
+            }
         }
         match (inexistent_fields_err, unmentioned_err) {
             (Some(mut i), Some(mut u)) => {
@@ -1173,7 +1185,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         kind_name: &str,
         inexistent_fields: &[Ident],
-        unmentioned_fields: &mut Vec<Ident>,
+        unmentioned_fields: &mut Vec<(&ty::FieldDef, Ident)>,
         variant: &ty::VariantDef,
     ) -> DiagnosticBuilder<'tcx> {
         let tcx = self.tcx;
@@ -1215,7 +1227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ),
             );
             if plural == "" {
-                let input = unmentioned_fields.iter().map(|field| &field.name);
+                let input = unmentioned_fields.iter().map(|(_, field)| &field.name);
                 let suggested_name = find_best_match_for_name(input, ident.name, None);
                 if let Some(suggested_name) = suggested_name {
                     err.span_suggestion(
@@ -1232,7 +1244,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // `smart_resolve_context_dependent_help`.
                     if suggested_name.to_ident_string().parse::<usize>().is_err() {
                         // We don't want to throw `E0027` in case we have thrown `E0026` for them.
-                        unmentioned_fields.retain(|&x| x.name != suggested_name);
+                        unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
                     }
                 }
             }
@@ -1300,17 +1312,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         None
     }
 
+    /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to
+    /// inaccessible fields.
+    ///
+    /// ```ignore (diagnostic)
+    /// error: pattern requires `..` due to inaccessible fields
+    ///   --> src/main.rs:10:9
+    ///    |
+    /// LL |     let foo::Foo {} = foo::Foo::default();
+    ///    |         ^^^^^^^^^^^
+    ///    |
+    /// help: add a `..`
+    ///    |
+    /// LL |     let foo::Foo { .. } = foo::Foo::default();
+    ///    |                  ^^^^^^
+    /// ```
+    fn error_no_accessible_fields(
+        &self,
+        pat: &Pat<'_>,
+        fields: &'tcx [hir::FieldPat<'tcx>],
+    ) -> DiagnosticBuilder<'tcx> {
+        let mut err = self
+            .tcx
+            .sess
+            .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields");
+
+        if let Some(field) = fields.last() {
+            err.span_suggestion_verbose(
+                field.span.shrink_to_hi(),
+                "ignore the inaccessible and unused fields",
+                ", ..".to_string(),
+                Applicability::MachineApplicable,
+            );
+        } else {
+            let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind {
+                qpath.span()
+            } else {
+                bug!("`error_no_accessible_fields` called on non-struct pattern");
+            };
+
+            // Shrink the span to exclude the `foo:Foo` in `foo::Foo { }`.
+            let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi());
+            err.span_suggestion_verbose(
+                span,
+                "ignore the inaccessible and unused fields",
+                " { .. }".to_string(),
+                Applicability::MachineApplicable,
+            );
+        }
+        err
+    }
+
+    /// Returns a diagnostic reporting a struct pattern which does not mention some fields.
+    ///
+    /// ```ignore (diagnostic)
+    /// error[E0027]: pattern does not mention field `you_cant_use_this_field`
+    ///   --> src/main.rs:15:9
+    ///    |
+    /// LL |     let foo::Foo {} = foo::Foo::new();
+    ///    |         ^^^^^^^^^^^ missing field `you_cant_use_this_field`
+    /// ```
     fn error_unmentioned_fields(
         &self,
         pat: &Pat<'_>,
-        unmentioned_fields: &[Ident],
+        unmentioned_fields: &[(&ty::FieldDef, Ident)],
     ) -> DiagnosticBuilder<'tcx> {
         let field_names = if unmentioned_fields.len() == 1 {
-            format!("field `{}`", unmentioned_fields[0])
+            format!("field `{}`", unmentioned_fields[0].1)
         } else {
             let fields = unmentioned_fields
                 .iter()
-                .map(|name| format!("`{}`", name))
+                .map(|(_, name)| format!("`{}`", name))
                 .collect::<Vec<String>>()
                 .join(", ");
             format!("fields {}", fields)
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index ea59375bad7..7d6b3df03b0 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -37,11 +37,12 @@ use rustc_middle::hir::map::Map;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::mono::Linkage;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::util::Discr;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
 use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
+use rustc_middle::ty::{TypeFoldable, TypeVisitor};
 use rustc_session::config::SanitizerSet;
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
@@ -50,6 +51,8 @@ use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
 
+use smallvec::SmallVec;
+
 mod type_of;
 
 struct OnlySelfBounds(bool);
@@ -1672,10 +1675,46 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate
                 .alloc_from_iter(result.predicates.iter().chain(inferred_outlives).copied());
         }
     }
+
+    if tcx.features().const_evaluatable_checked {
+        let const_evaluatable = const_evaluatable_predicates_of(tcx, def_id, &result);
+        result.predicates =
+            tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable));
+    }
+
     debug!("predicates_defined_on({:?}) = {:?}", def_id, result);
     result
 }
 
+pub fn const_evaluatable_predicates_of<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    predicates: &ty::GenericPredicates<'tcx>,
+) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> {
+    #[derive(Default)]
+    struct ConstCollector<'tcx> {
+        ct: SmallVec<[(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>); 4]>,
+    }
+
+    impl<'tcx> TypeVisitor<'tcx> for ConstCollector<'tcx> {
+        fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool {
+            if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
+                self.ct.push((def, substs));
+            }
+            false
+        }
+    }
+
+    let mut collector = ConstCollector::default();
+    for (pred, _span) in predicates.predicates.iter() {
+        pred.visit_with(&mut collector);
+    }
+    warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.ct);
+    collector.ct.into_iter().map(move |(def_id, subst)| {
+        (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), DUMMY_SP)
+    })
+}
+
 /// Returns a list of all type predicates (explicit and implicit) for the definition with
 /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
 /// `Self: Trait` predicates for traits.
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index 622a138abe9..bdf93baa1b8 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -78,6 +78,12 @@ pub trait Add<Rhs = Self> {
     type Output;
 
     /// Performs the `+` operation.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// assert_eq!(12 + 1, 13);
+    /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn add(self, rhs: Rhs) -> Self::Output;
@@ -178,6 +184,12 @@ pub trait Sub<Rhs = Self> {
     type Output;
 
     /// Performs the `-` operation.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// assert_eq!(12 - 1, 11);
+    /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn sub(self, rhs: Rhs) -> Self::Output;
@@ -300,6 +312,12 @@ pub trait Mul<Rhs = Self> {
     type Output;
 
     /// Performs the `*` operation.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// assert_eq!(12 * 2, 24);
+    /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn mul(self, rhs: Rhs) -> Self::Output;
@@ -426,6 +444,12 @@ pub trait Div<Rhs = Self> {
     type Output;
 
     /// Performs the `/` operation.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// assert_eq!(12 / 2, 6);
+    /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn div(self, rhs: Rhs) -> Self::Output;
@@ -513,6 +537,12 @@ pub trait Rem<Rhs = Self> {
     type Output;
 
     /// Performs the `%` operation.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// assert_eq!(12 % 10, 2);
+    /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn rem(self, rhs: Rhs) -> Self::Output;
@@ -612,6 +642,13 @@ pub trait Neg {
     type Output;
 
     /// Performs the unary `-` operation.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// let x: i32 = 12;
+    /// assert_eq!(-x, -12);
+    /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn neg(self) -> Self::Output;
@@ -673,6 +710,14 @@ neg_impl! { isize i8 i16 i32 i64 i128 f32 f64 }
 #[doc(alias = "+=")]
 pub trait AddAssign<Rhs = Self> {
     /// Performs the `+=` operation.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// let mut x: u32 = 12;
+    /// x += 1;
+    /// assert_eq!(x, 13);
+    /// ```
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
     fn add_assign(&mut self, rhs: Rhs);
 }
@@ -731,6 +776,14 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 #[doc(alias = "-=")]
 pub trait SubAssign<Rhs = Self> {
     /// Performs the `-=` operation.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// let mut x: u32 = 12;
+    /// x -= 1;
+    /// assert_eq!(x, 11);
+    /// ```
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
     fn sub_assign(&mut self, rhs: Rhs);
 }
@@ -780,6 +833,14 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 #[doc(alias = "*=")]
 pub trait MulAssign<Rhs = Self> {
     /// Performs the `*=` operation.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// let mut x: u32 = 12;
+    /// x *= 2;
+    /// assert_eq!(x, 24);
+    /// ```
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
     fn mul_assign(&mut self, rhs: Rhs);
 }
@@ -829,6 +890,14 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 #[doc(alias = "/=")]
 pub trait DivAssign<Rhs = Self> {
     /// Performs the `/=` operation.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// let mut x: u32 = 12;
+    /// x /= 2;
+    /// assert_eq!(x, 6);
+    /// ```
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
     fn div_assign(&mut self, rhs: Rhs);
 }
@@ -881,6 +950,14 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 #[doc(alias = "%=")]
 pub trait RemAssign<Rhs = Self> {
     /// Performs the `%=` operation.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// let mut x: u32 = 12;
+    /// x %= 10;
+    /// assert_eq!(x, 2);
+    /// ```
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
     fn rem_assign(&mut self, rhs: Rhs);
 }
diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md
index d3dfc3197e2..d2d8c471efc 100644
--- a/src/doc/rustc/src/lints/listing/allowed-by-default.md
+++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md
@@ -232,7 +232,8 @@ error: lifetime name `'x` only used once
 
 ## trivial-casts
 
-This lint detects trivial casts which could be removed. Some example code
+This lint detects trivial casts which could be replaced with coercion, which may require
+type ascription or a temporary variable. Some example code
 that triggers this lint:
 
 ```rust
diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md
index adcebc832bc..7a38c96d714 100644
--- a/src/doc/rustdoc/src/what-is-rustdoc.md
+++ b/src/doc/rustdoc/src/what-is-rustdoc.md
@@ -93,6 +93,29 @@ passes `-L`, a flag that helps rustdoc find the dependencies
 your code relies on. If our project used dependencies, we'd get
 documentation for them as well!
 
+## Outer and inner documentation
+
+The `///` syntax is used to document the item present after it.
+That's why it is called an outer documentation.
+There is another syntax: `//!`, which is used to document the 
+item it is present inside. It is called an inner documentation.
+It is often used when documenting the entire crate,
+because nothing comes before it: it is the root of the crate.
+So in order to document an entire crate, you need to use `//!` syntax.
+For example:
+
+``` rust
+//! This is my first rust crate
+```
+
+When used in the crate root, it documents the item it is inside,
+which is the crate itself.
+
+For more information about the `//!` syntax, see [the Book].
+
+[the Book]: https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#commenting-contained-items
+
+
 ## Using standalone Markdown files
 
 `rustdoc` can also generate HTML from standalone Markdown files. Let's
diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout
index 031c0d0cae5..0e5a3a14ac7 100644
--- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout
+++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout
@@ -1 +1 @@
-{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
+{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout
index 9b3b6870cbe..8752ed2ae99 100644
--- a/src/test/ui/ast-json/ast-json-output.stdout
+++ b/src/test/ui/ast-json/ast-json-output.stdout
@@ -1 +1 @@
-{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
+{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
diff --git a/src/test/ui/const-generics/auxiliary/const_generic_lib.rs b/src/test/ui/const-generics/auxiliary/const_generic_lib.rs
index 901fb5dd054..899a5a1836c 100644
--- a/src/test/ui/const-generics/auxiliary/const_generic_lib.rs
+++ b/src/test/ui/const-generics/auxiliary/const_generic_lib.rs
@@ -1,4 +1,6 @@
-#![feature(const_generics)]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct Struct<const N: usize>(pub [u8; N]);
 
diff --git a/src/test/ui/const-generics/auxiliary/impl-const.rs b/src/test/ui/const-generics/auxiliary/impl-const.rs
index fc993d63927..2e25dadf119 100644
--- a/src/test/ui/const-generics/auxiliary/impl-const.rs
+++ b/src/test/ui/const-generics/auxiliary/impl-const.rs
@@ -1,4 +1,6 @@
-#![feature(const_generics)]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct Num<const N: usize>;
 
diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr
index aefd514f7a6..a35c3abc113 100644
--- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr
+++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr
@@ -1,11 +1,11 @@
 error[E0308]: mismatched types
-  --> $DIR/const-argument-cross-crate-mismatch.rs:6:67
+  --> $DIR/const-argument-cross-crate-mismatch.rs:7:67
    |
 LL |     let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8]));
    |                                                                   ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
 
 error[E0308]: mismatched types
-  --> $DIR/const-argument-cross-crate-mismatch.rs:8:65
+  --> $DIR/const-argument-cross-crate-mismatch.rs:9:65
    |
 LL |     let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]);
    |                                                                 ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements
diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr
new file mode 100644
index 00000000000..a35c3abc113
--- /dev/null
+++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/const-argument-cross-crate-mismatch.rs:7:67
+   |
+LL |     let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8]));
+   |                                                                   ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
+
+error[E0308]: mismatched types
+  --> $DIR/const-argument-cross-crate-mismatch.rs:9:65
+   |
+LL |     let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]);
+   |                                                                 ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs
index d863d097d5c..9ae2ae50ba0 100644
--- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs
+++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs
@@ -1,4 +1,5 @@
 // aux-build:const_generic_lib.rs
+// revisions: full min
 
 extern crate const_generic_lib;
 
diff --git a/src/test/ui/const-generics/const-argument-cross-crate.rs b/src/test/ui/const-generics/const-argument-cross-crate.rs
index 98cf39a7ee1..fda3ec3eef7 100644
--- a/src/test/ui/const-generics/const-argument-cross-crate.rs
+++ b/src/test/ui/const-generics/const-argument-cross-crate.rs
@@ -1,4 +1,5 @@
 // run-pass
+// revisions: full min
 // aux-build:const_generic_lib.rs
 
 extern crate const_generic_lib;
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs
new file mode 100644
index 00000000000..941bd5e9e5d
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs
@@ -0,0 +1,14 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+type Arr<const N: usize> = [u8; N - 1];
+
+fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
+    //~^ ERROR constant expression depends
+    Default::default()
+}
+
+fn main() {
+    let x = test::<33>();
+    assert_eq!(x, [0; 32]);
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr
new file mode 100644
index 00000000000..6e4a22a38b1
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr
@@ -0,0 +1,10 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/feature-gate-const_evaluatable_checked.rs:6:30
+   |
+LL | fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
+   |                              ^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs
new file mode 100644
index 00000000000..a7ead78b97b
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+type Arr<const N: usize> = [u8; N - 1];
+
+fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
+    Default::default()
+}
+
+fn main() {
+    let x = test::<33>();
+    assert_eq!(x, [0; 32]);
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
new file mode 100644
index 00000000000..1edf1885dd2
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
@@ -0,0 +1,12 @@
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+type Arr<const N: usize> = [u8; N - 1]; //~ ERROR evaluation of constant
+
+fn test<const N: usize>() -> Arr<N> where Arr<N>: Sized {
+    todo!()
+}
+
+fn main() {
+    test::<0>();
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr
new file mode 100644
index 00000000000..1ac5e1d9553
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr
@@ -0,0 +1,9 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/simple_fail.rs:4:33
+   |
+LL | type Arr<const N: usize> = [u8; N - 1];
+   |                                 ^^^^^ attempt to compute `0_usize - 1_usize` which would overflow
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr b/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr
new file mode 100644
index 00000000000..0574ddfb255
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr
@@ -0,0 +1,8 @@
+error: type parameters must be declared prior to const parameters
+  --> $DIR/complex-unord-param.rs:9:41
+   |
+LL | struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> {
+   |                    ---------------------^----------------------^--------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, A: 'a, T: 'a, const N: usize, const M: usize>`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.rs b/src/test/ui/const-generics/defaults/complex-unord-param.rs
index 72967640a8e..e83a96388c1 100644
--- a/src/test/ui/const-generics/defaults/complex-unord-param.rs
+++ b/src/test/ui/const-generics/defaults/complex-unord-param.rs
@@ -1,11 +1,13 @@
-// run-pass
+// [full] run-pass
+// revisions: full min
 // Checks a complicated usage of unordered params
-
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 #![allow(dead_code)]
 
 struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> {
+  //[min]~^ ERROR type parameters must be declared prior to const parameters
   args: &'a [&'a [T; M]; N],
   specifier: A,
 }
diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr
index 0f6d7f1065a..9cc3e9c0da6 100644
--- a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr
+++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr
@@ -1,11 +1,11 @@
 error: lifetime parameters must be declared prior to const parameters
-  --> $DIR/intermixed-lifetime.rs:6:28
+  --> $DIR/intermixed-lifetime.rs:7:28
    |
 LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
    |           -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>`
 
 error: lifetime parameters must be declared prior to type parameters
-  --> $DIR/intermixed-lifetime.rs:9:37
+  --> $DIR/intermixed-lifetime.rs:11:37
    |
 LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
    |           --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>`
diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr
new file mode 100644
index 00000000000..4d80fdb5bcb
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr
@@ -0,0 +1,26 @@
+error: lifetime parameters must be declared prior to const parameters
+  --> $DIR/intermixed-lifetime.rs:7:28
+   |
+LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
+   |           -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
+
+error: type parameters must be declared prior to const parameters
+  --> $DIR/intermixed-lifetime.rs:7:32
+   |
+LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
+   |           ---------------------^------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
+
+error: lifetime parameters must be declared prior to const parameters
+  --> $DIR/intermixed-lifetime.rs:11:37
+   |
+LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
+   |           --------------------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
+
+error: type parameters must be declared prior to const parameters
+  --> $DIR/intermixed-lifetime.rs:11:28
+   |
+LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
+   |           -----------------^----------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
index ea3a8c14b98..cc0d1c6c0c9 100644
--- a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
+++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
@@ -1,12 +1,16 @@
+// revisions: full min
 // Checks that lifetimes cannot be interspersed between consts and types.
-
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
 //~^ Error lifetime parameters must be declared prior to const parameters
+//[min]~^^ Error type parameters must be declared prior to const parameters
 
 struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
-//~^ Error lifetime parameters must be declared prior to type parameters
+//[full]~^ Error lifetime parameters must be declared prior to type parameters
+//[min]~^^ Error type parameters must be declared prior to const parameters
+//[min]~| Error lifetime parameters must be declared prior to const parameters
 
 fn main() {}
diff --git a/src/test/ui/const-generics/defaults/simple-defaults.min.stderr b/src/test/ui/const-generics/defaults/simple-defaults.min.stderr
new file mode 100644
index 00000000000..59cc6f28af8
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/simple-defaults.min.stderr
@@ -0,0 +1,8 @@
+error: type parameters must be declared prior to const parameters
+  --> $DIR/simple-defaults.rs:9:40
+   |
+LL | struct FixedOutput<'a, const N: usize, T=u32> {
+   |                   ---------------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/defaults/simple-defaults.rs b/src/test/ui/const-generics/defaults/simple-defaults.rs
index b282dfd37cc..78abe351998 100644
--- a/src/test/ui/const-generics/defaults/simple-defaults.rs
+++ b/src/test/ui/const-generics/defaults/simple-defaults.rs
@@ -1,10 +1,13 @@
-// run-pass
+// [full] run-pass
+// revisions: min full
 // Checks some basic test cases for defaults.
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 #![allow(dead_code)]
 
 struct FixedOutput<'a, const N: usize, T=u32> {
+  //[min]~^ ERROR type parameters must be declared prior to const parameters
   out: &'a [T; N],
 }
 
diff --git a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs
index 59a4d345cbc..7ea8d936d61 100644
--- a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs
+++ b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs
@@ -1,4 +1,6 @@
-#![feature(const_generics)]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 // All of these three items must be in `lib2` to reproduce the error
 
diff --git a/src/test/ui/const-generics/issues/issue-61935.full.stderr b/src/test/ui/const-generics/issues/issue-61935.full.stderr
new file mode 100644
index 00000000000..b805bc0db7e
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-61935.full.stderr
@@ -0,0 +1,10 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-61935.rs:10:14
+   |
+LL |         Self:FooImpl<{N==0}>
+   |              ^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-61935.min.stderr b/src/test/ui/const-generics/issues/issue-61935.min.stderr
new file mode 100644
index 00000000000..e5715ec658c
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-61935.min.stderr
@@ -0,0 +1,10 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-61935.rs:10:23
+   |
+LL |         Self:FooImpl<{N==0}>
+   |                       ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs
index 0d42ff1895c..64257da0309 100644
--- a/src/test/ui/const-generics/issues/issue-61935.rs
+++ b/src/test/ui/const-generics/issues/issue-61935.rs
@@ -1,12 +1,15 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 trait Foo {}
 
 impl<const N: usize> Foo for [(); N]
     where
         Self:FooImpl<{N==0}>
-//~^ERROR constant expression depends on a generic parameter
+//[full]~^ERROR constant expression depends on a generic parameter
+//[min]~^^ERROR generic parameters must not be used inside of non trivial constant values
 {}
 
 trait FooImpl<const IS_ZERO: bool>{}
diff --git a/src/test/ui/const-generics/issues/issue-61935.stderr b/src/test/ui/const-generics/issues/issue-61935.stderr
deleted file mode 100644
index a785af5f008..00000000000
--- a/src/test/ui/const-generics/issues/issue-61935.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-61935.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: constant expression depends on a generic parameter
-  --> $DIR/issue-61935.rs:8:14
-   |
-LL |         Self:FooImpl<{N==0}>
-   |              ^^^^^^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: aborting due to previous error; 1 warning emitted
-
diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs
index 2f3b5c5dc5b..a8fa3780356 100644
--- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs
+++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs
@@ -1,7 +1,9 @@
 // run-pass
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub trait BitLen: Sized {
     const BIT_LEN: usize;
@@ -12,5 +14,5 @@ impl<const L: usize> BitLen for [u8; L] {
 }
 
 fn main() {
-    let foo = <[u8; 2]>::BIT_LEN; //~ WARN unused variable
+    let _foo = <[u8; 2]>::BIT_LEN;
 }
diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr
deleted file mode 100644
index a9abb877c09..00000000000
--- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-62187-encountered-polymorphic-const.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: unused variable: `foo`
-  --> $DIR/issue-62187-encountered-polymorphic-const.rs:15:9
-   |
-LL |     let foo = <[u8; 2]>::BIT_LEN;
-   |         ^^^ help: if this is intentional, prefix it with an underscore: `_foo`
-   |
-   = note: `#[warn(unused_variables)]` on by default
-
-warning: 2 warnings emitted
-
diff --git a/src/test/ui/const-generics/issues/issue-62220.stderr b/src/test/ui/const-generics/issues/issue-62220.full.stderr
index d91d2bb326f..120aa8e4af5 100644
--- a/src/test/ui/const-generics/issues/issue-62220.stderr
+++ b/src/test/ui/const-generics/issues/issue-62220.full.stderr
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-62220.rs:10:27
+  --> $DIR/issue-62220.rs:13:27
    |
 LL |     pub fn trunc(self) -> (TruncatedVector<T, { N }>, T) {
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/const-generics/issues/issue-62220.min.stderr b/src/test/ui/const-generics/issues/issue-62220.min.stderr
new file mode 100644
index 00000000000..943b689bf61
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-62220.min.stderr
@@ -0,0 +1,10 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-62220.rs:8:59
+   |
+LL | pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
+   |                                                           ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs
index 5c4a0d31a89..acb13ad1170 100644
--- a/src/test/ui/const-generics/issues/issue-62220.rs
+++ b/src/test/ui/const-generics/issues/issue-62220.rs
@@ -1,14 +1,17 @@
-#![allow(incomplete_features)]
-#![feature(const_generics)]
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct Vector<T, const N: usize>([T; N]);
 
 pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
+//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
 
 impl<T, const N: usize> Vector<T, { N }> {
     /// Drop the last component and return the vector with one fewer dimension.
     pub fn trunc(self) -> (TruncatedVector<T, { N }>, T) {
-        //~^ ERROR constant expression depends on a generic parameter
+        //[full]~^ ERROR constant expression depends on a generic parameter
         unimplemented!()
     }
 }
diff --git a/src/test/ui/const-generics/issues/issue-62456.full.stderr b/src/test/ui/const-generics/issues/issue-62456.full.stderr
new file mode 100644
index 00000000000..a8d44074db9
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-62456.full.stderr
@@ -0,0 +1,10 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-62456.rs:7:20
+   |
+LL |     let _ = [0u64; N + 1];
+   |                    ^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-62456.min.stderr b/src/test/ui/const-generics/issues/issue-62456.min.stderr
new file mode 100644
index 00000000000..335f0ead278
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-62456.min.stderr
@@ -0,0 +1,10 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-62456.rs:7:20
+   |
+LL |     let _ = [0u64; N + 1];
+   |                    ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs
index 37947ad1b33..c96868c00a3 100644
--- a/src/test/ui/const-generics/issues/issue-62456.rs
+++ b/src/test/ui/const-generics/issues/issue-62456.rs
@@ -1,9 +1,12 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn foo<const N: usize>() {
     let _ = [0u64; N + 1];
-    //~^ ERROR constant expression depends on a generic parameter
+    //[full]~^ ERROR constant expression depends on a generic parameter
+    //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-62456.stderr b/src/test/ui/const-generics/issues/issue-62456.stderr
deleted file mode 100644
index 0454fed6705..00000000000
--- a/src/test/ui/const-generics/issues/issue-62456.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-62456.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: constant expression depends on a generic parameter
-  --> $DIR/issue-62456.rs:5:20
-   |
-LL |     let _ = [0u64; N + 1];
-   |                    ^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: aborting due to previous error; 1 warning emitted
-
diff --git a/src/test/ui/const-generics/issues/issue-62504.stderr b/src/test/ui/const-generics/issues/issue-62504.full.stderr
index f09af76325e..9c84f06ce9f 100644
--- a/src/test/ui/const-generics/issues/issue-62504.stderr
+++ b/src/test/ui/const-generics/issues/issue-62504.full.stderr
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-62504.rs:18:25
+  --> $DIR/issue-62504.rs:19:25
    |
 LL |         ArrayHolder([0; Self::SIZE])
    |                         ^^^^^^^^^^
diff --git a/src/test/ui/const-generics/issues/issue-62504.min.stderr b/src/test/ui/const-generics/issues/issue-62504.min.stderr
new file mode 100644
index 00000000000..752df17aad6
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-62504.min.stderr
@@ -0,0 +1,10 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-62504.rs:19:25
+   |
+LL |         ArrayHolder([0; Self::SIZE])
+   |                         ^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
+   |
+   = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs
index 4e05aadd393..b520dbe4e80 100644
--- a/src/test/ui/const-generics/issues/issue-62504.rs
+++ b/src/test/ui/const-generics/issues/issue-62504.rs
@@ -1,7 +1,8 @@
-// Regression test for #62504
-
-#![feature(const_generics)]
+// revisions: full min
 #![allow(incomplete_features)]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 trait HasSize {
     const SIZE: usize;
@@ -16,7 +17,8 @@ struct ArrayHolder<const X: usize>([u32; X]);
 impl<const X: usize> ArrayHolder<X> {
     pub const fn new() -> Self {
         ArrayHolder([0; Self::SIZE])
-        //~^ ERROR constant expression depends on a generic parameter
+        //[full]~^ ERROR constant expression depends on a generic parameter
+        //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
     }
 }
 
diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr
new file mode 100644
index 00000000000..6903b20fad6
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr
@@ -0,0 +1,11 @@
+error: `NoMatch` is forbidden as the type of a const generic parameter
+  --> $DIR/issue-62579-no-match.rs:10:17
+   |
+LL | fn foo<const T: NoMatch>() -> bool {
+   |                 ^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.rs b/src/test/ui/const-generics/issues/issue-62579-no-match.rs
index 7eaf5eea078..c9853aa9162 100644
--- a/src/test/ui/const-generics/issues/issue-62579-no-match.rs
+++ b/src/test/ui/const-generics/issues/issue-62579-no-match.rs
@@ -1,12 +1,14 @@
-// run-pass
-
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// [full] run-pass
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 #[derive(PartialEq, Eq)]
 struct NoMatch;
 
 fn foo<const T: NoMatch>() -> bool {
+    //[min]~^ ERROR `NoMatch` is forbidden as the type of a const generic parameter
     true
 }
 
diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.stderr
deleted file mode 100644
index 9fb9b5b13d8..00000000000
--- a/src/test/ui/const-generics/issues/issue-62579-no-match.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-62579-no-match.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/issues/issue-62878.stderr b/src/test/ui/const-generics/issues/issue-62878.full.stderr
index fe0990d8241..c8b9db89410 100644
--- a/src/test/ui/const-generics/issues/issue-62878.stderr
+++ b/src/test/ui/const-generics/issues/issue-62878.full.stderr
@@ -1,37 +1,28 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/issue-62878.rs:3:38
+  --> $DIR/issue-62878.rs:6:38
    |
 LL | fn foo<const N: usize, const A: [u8; N]>() {}
    |                                      ^ the type must not depend on the parameter `N`
 
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-62878.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
 error[E0107]: wrong number of const arguments: expected 2, found 1
-  --> $DIR/issue-62878.rs:7:5
+  --> $DIR/issue-62878.rs:11:5
    |
 LL |     foo::<_, {[1]}>();
    |     ^^^^^^^^^^^^^^^ expected 2 const arguments
 
 error[E0107]: wrong number of type arguments: expected 0, found 1
-  --> $DIR/issue-62878.rs:7:11
+  --> $DIR/issue-62878.rs:11:11
    |
 LL |     foo::<_, {[1]}>();
    |           ^ unexpected type argument
 
 error[E0308]: mismatched types
-  --> $DIR/issue-62878.rs:7:15
+  --> $DIR/issue-62878.rs:11:15
    |
 LL |     foo::<_, {[1]}>();
    |               ^^^ expected `usize`, found array `[{integer}; 1]`
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0107, E0308, E0770.
 For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/const-generics/issues/issue-62878.min.stderr b/src/test/ui/const-generics/issues/issue-62878.min.stderr
new file mode 100644
index 00000000000..34edd09b515
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-62878.min.stderr
@@ -0,0 +1,18 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/issue-62878.rs:6:38
+   |
+LL | fn foo<const N: usize, const A: [u8; N]>() {}
+   |                                      ^ the type must not depend on the parameter `N`
+
+error: `[u8; _]` is forbidden as the type of a const generic parameter
+  --> $DIR/issue-62878.rs:6:33
+   |
+LL | fn foo<const N: usize, const A: [u8; N]>() {}
+   |                                 ^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0770`.
diff --git a/src/test/ui/const-generics/issues/issue-62878.rs b/src/test/ui/const-generics/issues/issue-62878.rs
index ccc05fdf100..0487dda2fe8 100644
--- a/src/test/ui/const-generics/issues/issue-62878.rs
+++ b/src/test/ui/const-generics/issues/issue-62878.rs
@@ -1,11 +1,15 @@
-#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn foo<const N: usize, const A: [u8; N]>() {}
 //~^ ERROR the type of const parameters must not
+//[min]~| ERROR `[u8; _]` is forbidden as the type of a const generic parameter
 
 fn main() {
     foo::<_, {[1]}>();
-    //~^ ERROR wrong number of const arguments
-    //~| ERROR wrong number of type arguments
-    //~| ERROR mismatched types
+    //[full]~^ ERROR wrong number of const arguments
+    //[full]~| ERROR wrong number of type arguments
+    //[full]~| ERROR mismatched types
 }
diff --git a/src/test/ui/const-generics/issues/issue-67185-2.stderr b/src/test/ui/const-generics/issues/issue-67185-2.full.stderr
index 7d947a907a0..78c7ebff059 100644
--- a/src/test/ui/const-generics/issues/issue-67185-2.stderr
+++ b/src/test/ui/const-generics/issues/issue-67185-2.full.stderr
@@ -1,14 +1,5 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-67185-2.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
 error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:15:1
+  --> $DIR/issue-67185-2.rs:17:1
    |
 LL | / trait Foo
 LL | |
@@ -26,7 +17,7 @@ LL | | }
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
 
 error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:15:1
+  --> $DIR/issue-67185-2.rs:17:1
    |
 LL | / trait Foo
 LL | |
@@ -44,7 +35,7 @@ LL | | }
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
 
 error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:25:6
+  --> $DIR/issue-67185-2.rs:27:6
    |
 LL | trait Foo
    |       --- required by a bound in this
@@ -60,7 +51,7 @@ LL | impl Foo for FooImpl {}
              <[u16; 4] as Bar>
 
 error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:25:6
+  --> $DIR/issue-67185-2.rs:27:6
    |
 LL | trait Foo
    |       --- required by a bound in this
@@ -76,7 +67,7 @@ LL | impl Foo for FooImpl {}
              <[u16; 4] as Bar>
 
 error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:29:14
+  --> $DIR/issue-67185-2.rs:31:14
    |
 LL | trait Foo
    |       --- required by a bound in this
@@ -92,7 +83,7 @@ LL | fn f(_: impl Foo) {}
              <[u16; 4] as Bar>
 
 error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:29:14
+  --> $DIR/issue-67185-2.rs:31:14
    |
 LL | trait Foo
    |       --- required by a bound in this
@@ -107,6 +98,6 @@ LL | fn f(_: impl Foo) {}
              <[[u16; 3]; 3] as Bar>
              <[u16; 4] as Bar>
 
-error: aborting due to 6 previous errors; 1 warning emitted
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/issues/issue-67185-2.min.stderr b/src/test/ui/const-generics/issues/issue-67185-2.min.stderr
new file mode 100644
index 00000000000..78c7ebff059
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-67185-2.min.stderr
@@ -0,0 +1,103 @@
+error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
+  --> $DIR/issue-67185-2.rs:17:1
+   |
+LL | / trait Foo
+LL | |
+LL | |     where
+LL | |         [<u8 as Baz>::Quaks; 2]: Bar,
+LL | |         <u8 as Baz>::Quaks: Bar,
+LL | | {
+LL | | }
+   | |_^ the trait `Bar` is not implemented for `[u16; 3]`
+   |
+   = help: the following implementations were found:
+             <[[u16; 3]; 3] as Bar>
+             <[u16; 4] as Bar>
+   = help: see issue #48214
+   = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+
+error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
+  --> $DIR/issue-67185-2.rs:17:1
+   |
+LL | / trait Foo
+LL | |
+LL | |     where
+LL | |         [<u8 as Baz>::Quaks; 2]: Bar,
+LL | |         <u8 as Baz>::Quaks: Bar,
+LL | | {
+LL | | }
+   | |_^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`
+   |
+   = help: the following implementations were found:
+             <[[u16; 3]; 3] as Bar>
+             <[u16; 4] as Bar>
+   = help: see issue #48214
+   = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+
+error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
+  --> $DIR/issue-67185-2.rs:27:6
+   |
+LL | trait Foo
+   |       --- required by a bound in this
+...
+LL |         <u8 as Baz>::Quaks: Bar,
+   |                             --- required by this bound in `Foo`
+...
+LL | impl Foo for FooImpl {}
+   |      ^^^ the trait `Bar` is not implemented for `[u16; 3]`
+   |
+   = help: the following implementations were found:
+             <[[u16; 3]; 3] as Bar>
+             <[u16; 4] as Bar>
+
+error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
+  --> $DIR/issue-67185-2.rs:27:6
+   |
+LL | trait Foo
+   |       --- required by a bound in this
+...
+LL |         [<u8 as Baz>::Quaks; 2]: Bar,
+   |                                  --- required by this bound in `Foo`
+...
+LL | impl Foo for FooImpl {}
+   |      ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`
+   |
+   = help: the following implementations were found:
+             <[[u16; 3]; 3] as Bar>
+             <[u16; 4] as Bar>
+
+error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
+  --> $DIR/issue-67185-2.rs:31:14
+   |
+LL | trait Foo
+   |       --- required by a bound in this
+...
+LL |         [<u8 as Baz>::Quaks; 2]: Bar,
+   |                                  --- required by this bound in `Foo`
+...
+LL | fn f(_: impl Foo) {}
+   |              ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`
+   |
+   = help: the following implementations were found:
+             <[[u16; 3]; 3] as Bar>
+             <[u16; 4] as Bar>
+
+error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
+  --> $DIR/issue-67185-2.rs:31:14
+   |
+LL | trait Foo
+   |       --- required by a bound in this
+...
+LL |         <u8 as Baz>::Quaks: Bar,
+   |                             --- required by this bound in `Foo`
+...
+LL | fn f(_: impl Foo) {}
+   |              ^^^ the trait `Bar` is not implemented for `[u16; 3]`
+   |
+   = help: the following implementations were found:
+             <[[u16; 3]; 3] as Bar>
+             <[u16; 4] as Bar>
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/issues/issue-67185-2.rs b/src/test/ui/const-generics/issues/issue-67185-2.rs
index 111b718dd5e..1176d0c6904 100644
--- a/src/test/ui/const-generics/issues/issue-67185-2.rs
+++ b/src/test/ui/const-generics/issues/issue-67185-2.rs
@@ -1,5 +1,7 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 trait Baz {
     type Quaks;
diff --git a/src/test/ui/const-generics/issues/issue-67739.stderr b/src/test/ui/const-generics/issues/issue-67739.full.stderr
index 27a56b8eb02..27a56b8eb02 100644
--- a/src/test/ui/const-generics/issues/issue-67739.stderr
+++ b/src/test/ui/const-generics/issues/issue-67739.full.stderr
diff --git a/src/test/ui/const-generics/issues/issue-67739.min.stderr b/src/test/ui/const-generics/issues/issue-67739.min.stderr
new file mode 100644
index 00000000000..1254ee7239d
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-67739.min.stderr
@@ -0,0 +1,10 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-67739.rs:12:30
+   |
+LL |         [0u8; mem::size_of::<Self::Associated>()];
+   |                              ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
+   |
+   = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs
index c8ee1821239..72bf3ee9602 100644
--- a/src/test/ui/const-generics/issues/issue-67739.rs
+++ b/src/test/ui/const-generics/issues/issue-67739.rs
@@ -1,7 +1,7 @@
-// Regression test for #67739
-
-#![allow(incomplete_features)]
-#![feature(const_generics)]
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 use std::mem;
 
@@ -10,7 +10,8 @@ pub trait Trait {
 
     fn associated_size(&self) -> usize {
         [0u8; mem::size_of::<Self::Associated>()];
-        //~^ ERROR constant expression depends on a generic parameter
+        //[full]~^ ERROR constant expression depends on a generic parameter
+        //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
         0
     }
 }
diff --git a/src/test/ui/const-generics/issues/issue-68366.stderr b/src/test/ui/const-generics/issues/issue-68366.full.stderr
index bba16f42153..ac774f50c74 100644
--- a/src/test/ui/const-generics/issues/issue-68366.stderr
+++ b/src/test/ui/const-generics/issues/issue-68366.full.stderr
@@ -1,5 +1,5 @@
 error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-68366.rs:10:13
+  --> $DIR/issue-68366.rs:12:13
    |
 LL | impl <const N: usize> Collatz<{Some(N)}> {}
    |             ^ unconstrained const parameter
@@ -8,7 +8,7 @@ LL | impl <const N: usize> Collatz<{Some(N)}> {}
    = note: proving the result of expressions other than the parameter are unique is not supported
 
 error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-68366.rs:15:12
+  --> $DIR/issue-68366.rs:18:12
    |
 LL | impl<const N: usize> Foo {}
    |            ^ unconstrained const parameter
diff --git a/src/test/ui/const-generics/issues/issue-68366.min.stderr b/src/test/ui/const-generics/issues/issue-68366.min.stderr
new file mode 100644
index 00000000000..8d34bdc6ea0
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-68366.min.stderr
@@ -0,0 +1,29 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-68366.rs:12:37
+   |
+LL | impl <const N: usize> Collatz<{Some(N)}> {}
+   |                                     ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/issue-68366.rs:12:13
+   |
+LL | impl <const N: usize> Collatz<{Some(N)}> {}
+   |             ^ unconstrained const parameter
+   |
+   = note: expressions using a const parameter must map each value to a distinct output value
+   = note: proving the result of expressions other than the parameter are unique is not supported
+
+error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/issue-68366.rs:18:12
+   |
+LL | impl<const N: usize> Foo {}
+   |            ^ unconstrained const parameter
+   |
+   = note: expressions using a const parameter must map each value to a distinct output value
+   = note: proving the result of expressions other than the parameter are unique is not supported
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/const-generics/issues/issue-68366.rs b/src/test/ui/const-generics/issues/issue-68366.rs
index a06b99d6645..819fcaffea1 100644
--- a/src/test/ui/const-generics/issues/issue-68366.rs
+++ b/src/test/ui/const-generics/issues/issue-68366.rs
@@ -2,13 +2,16 @@
 // The note should relate to the fact that it cannot be shown forall N that it maps 1-1 to a new
 // type.
 
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct Collatz<const N: Option<usize>>;
 
 impl <const N: usize> Collatz<{Some(N)}> {}
 //~^ ERROR the const parameter
+//[min]~^^ generic parameters must not be used inside of non trivial constant values
 
 struct Foo;
 
diff --git a/src/test/ui/const-generics/issues/issue-72787.stderr b/src/test/ui/const-generics/issues/issue-72787.full.stderr
index ed892e46bbb..b4c79d4171b 100644
--- a/src/test/ui/const-generics/issues/issue-72787.stderr
+++ b/src/test/ui/const-generics/issues/issue-72787.full.stderr
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-72787.rs:9:32
+  --> $DIR/issue-72787.rs:11:32
    |
 LL |     Condition<{ LHS <= RHS }>: True
    |                                ^^^^
@@ -7,7 +7,7 @@ LL |     Condition<{ LHS <= RHS }>: True
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-72787.rs:20:42
+  --> $DIR/issue-72787.rs:26:42
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                                          ^^^^
@@ -15,7 +15,7 @@ LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-72787.rs:20:42
+  --> $DIR/issue-72787.rs:26:42
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                                          ^^^^
@@ -23,7 +23,7 @@ LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-72787.rs:20:42
+  --> $DIR/issue-72787.rs:26:42
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                                          ^^^^
@@ -31,7 +31,7 @@ LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-72787.rs:20:42
+  --> $DIR/issue-72787.rs:26:42
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                                          ^^^^
diff --git a/src/test/ui/const-generics/issues/issue-72787.min.stderr b/src/test/ui/const-generics/issues/issue-72787.min.stderr
new file mode 100644
index 00000000000..d3e9887fe20
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-72787.min.stderr
@@ -0,0 +1,57 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-72787.rs:11:17
+   |
+LL |     Condition<{ LHS <= RHS }>: True
+   |                 ^^^ non-trivial anonymous constants must not depend on the parameter `LHS`
+   |
+   = help: it is currently only allowed to use either `LHS` or `{ LHS }` as generic constants
+
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-72787.rs:11:24
+   |
+LL |     Condition<{ LHS <= RHS }>: True
+   |                        ^^^ non-trivial anonymous constants must not depend on the parameter `RHS`
+   |
+   = help: it is currently only allowed to use either `RHS` or `{ RHS }` as generic constants
+
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-72787.rs:26:25
+   |
+LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
+   |                         ^ non-trivial anonymous constants must not depend on the parameter `I`
+   |
+   = help: it is currently only allowed to use either `I` or `{ I }` as generic constants
+
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-72787.rs:26:36
+   |
+LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
+   |                                    ^ non-trivial anonymous constants must not depend on the parameter `J`
+   |
+   = help: it is currently only allowed to use either `J` or `{ J }` as generic constants
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-72787.rs:22:26
+   |
+LL | pub trait True {}
+   | -------------- required by this bound in `True`
+...
+LL |     IsLessOrEqual<I, 8>: True,
+   |                          ^^^^ cannot infer type for struct `IsLessOrEqual<I, 8_u32>`
+   |
+   = note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-72787.rs:22:26
+   |
+LL | pub trait True {}
+   | -------------- required by this bound in `True`
+...
+LL |     IsLessOrEqual<I, 8>: True,
+   |                          ^^^^ cannot infer type for struct `IsLessOrEqual<I, 8_u32>`
+   |
+   = note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/const-generics/issues/issue-72787.rs b/src/test/ui/const-generics/issues/issue-72787.rs
index a368c226ec3..45c20191c88 100644
--- a/src/test/ui/const-generics/issues/issue-72787.rs
+++ b/src/test/ui/const-generics/issues/issue-72787.rs
@@ -1,5 +1,7 @@
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct IsLessOrEqual<const LHS: u32, const RHS: u32>;
 pub struct Condition<const CONDITION: bool>;
@@ -7,7 +9,9 @@ pub trait True {}
 
 impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
     Condition<{ LHS <= RHS }>: True
-//~^ Error constant expression depends on a generic parameter
+//[full]~^ Error constant expression depends on a generic parameter
+//[min]~^^ Error generic parameters must not be used inside of non trivial constant values
+//[min]~| Error generic parameters must not be used inside of non trivial constant values
 {
 }
 impl True for Condition<true> {}
@@ -16,12 +20,16 @@ struct S<const I: u32, const J: u32>;
 impl<const I: u32, const J: u32> S<I, J>
 where
     IsLessOrEqual<I, 8>: True,
+//[min]~^ Error type annotations needed [E0283]
+//[min]~| Error type annotations needed [E0283]
     IsLessOrEqual<J, 8>: True,
     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
-//~^ Error constant expression depends on a generic parameter
-//~| Error constant expression depends on a generic parameter
-//~| Error constant expression depends on a generic parameter
-//~| Error constant expression depends on a generic parameter
+//[full]~^ constant expression depends on a generic parameter
+//[full]~| constant expression depends on a generic parameter
+//[full]~| constant expression depends on a generic parameter
+//[full]~| constant expression depends on a generic parameter
+//[min]~^^^^^ Error generic parameters must not be used inside of non trivial constant values
+//[min]~| Error generic parameters must not be used inside of non trivial constant values
     // Condition<{ 8 - I <= 8 - J }>: True,
 {
     fn print() {
diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr
index a9f664d0ac8..e4105a3df1c 100644
--- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr
+++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-72819-generic-in-const-eval.rs:7:47
+  --> $DIR/issue-72819-generic-in-const-eval.rs:9:47
    |
 LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue,
    |                                               ^^^^^^
diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr
new file mode 100644
index 00000000000..48a1f0bd19c
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr
@@ -0,0 +1,10 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-72819-generic-in-const-eval.rs:9:17
+   |
+LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue,
+   |                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs
index 225593c3178..b653b91d99d 100644
--- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs
+++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs
@@ -1,11 +1,14 @@
 // Regression test for #72819: ICE due to failure in resolving the const generic in `Arr`'s type
 // bounds.
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
-#![feature(const_generics)]
-#![allow(incomplete_features)]
 struct Arr<const N: usize>
 where Assert::<{N < usize::max_value() / 2}>: IsTrue,
-//~^ ERROR constant expression depends on a generic parameter
+//[full]~^ ERROR constant expression depends on a generic parameter
+//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
 {
 }
 
diff --git a/src/test/ui/const-generics/issues/issue-73120.rs b/src/test/ui/const-generics/issues/issue-73120.rs
index aea4de39f79..c153a93cdef 100644
--- a/src/test/ui/const-generics/issues/issue-73120.rs
+++ b/src/test/ui/const-generics/issues/issue-73120.rs
@@ -1,3 +1,4 @@
+// revisions: full min
 // check-pass
 // aux-build:const_generic_issues_lib.rs
 extern crate const_generic_issues_lib as lib2;
diff --git a/src/test/ui/issues/issue-76077-1.fixed b/src/test/ui/issues/issue-76077-1.fixed
new file mode 100644
index 00000000000..8103a7ca47d
--- /dev/null
+++ b/src/test/ui/issues/issue-76077-1.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+
+pub mod foo {
+    #[derive(Default)]
+    pub struct Foo { invisible: bool, }
+
+    #[derive(Default)]
+    pub struct Bar { pub visible: bool, invisible: bool, }
+}
+
+fn main() {
+    let foo::Foo { .. } = foo::Foo::default();
+    //~^ ERROR pattern requires `..` due to inaccessible fields
+
+    let foo::Bar { visible, .. } = foo::Bar::default();
+    //~^ ERROR pattern requires `..` due to inaccessible fields
+}
diff --git a/src/test/ui/issues/issue-76077-1.rs b/src/test/ui/issues/issue-76077-1.rs
new file mode 100644
index 00000000000..730332853c1
--- /dev/null
+++ b/src/test/ui/issues/issue-76077-1.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+
+pub mod foo {
+    #[derive(Default)]
+    pub struct Foo { invisible: bool, }
+
+    #[derive(Default)]
+    pub struct Bar { pub visible: bool, invisible: bool, }
+}
+
+fn main() {
+    let foo::Foo {} = foo::Foo::default();
+    //~^ ERROR pattern requires `..` due to inaccessible fields
+
+    let foo::Bar { visible } = foo::Bar::default();
+    //~^ ERROR pattern requires `..` due to inaccessible fields
+}
diff --git a/src/test/ui/issues/issue-76077-1.stderr b/src/test/ui/issues/issue-76077-1.stderr
new file mode 100644
index 00000000000..4557595529f
--- /dev/null
+++ b/src/test/ui/issues/issue-76077-1.stderr
@@ -0,0 +1,24 @@
+error: pattern requires `..` due to inaccessible fields
+  --> $DIR/issue-76077-1.rs:13:9
+   |
+LL |     let foo::Foo {} = foo::Foo::default();
+   |         ^^^^^^^^^^^
+   |
+help: ignore the inaccessible and unused fields
+   |
+LL |     let foo::Foo { .. } = foo::Foo::default();
+   |                  ^^^^^^
+
+error: pattern requires `..` due to inaccessible fields
+  --> $DIR/issue-76077-1.rs:16:9
+   |
+LL |     let foo::Bar { visible } = foo::Bar::default();
+   |         ^^^^^^^^^^^^^^^^^^^^
+   |
+help: ignore the inaccessible and unused fields
+   |
+LL |     let foo::Bar { visible, .. } = foo::Bar::default();
+   |                           ^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/issues/issue-76077.rs b/src/test/ui/issues/issue-76077.rs
new file mode 100644
index 00000000000..1ecd37de2e1
--- /dev/null
+++ b/src/test/ui/issues/issue-76077.rs
@@ -0,0 +1,10 @@
+pub mod foo {
+    pub struct Foo {
+        you_cant_use_this_field: bool,
+    }
+}
+
+fn main() {
+    foo::Foo {};
+    //~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields
+}
diff --git a/src/test/ui/issues/issue-76077.stderr b/src/test/ui/issues/issue-76077.stderr
new file mode 100644
index 00000000000..d834ec5e0ed
--- /dev/null
+++ b/src/test/ui/issues/issue-76077.stderr
@@ -0,0 +1,8 @@
+error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
+  --> $DIR/issue-76077.rs:8:5
+   |
+LL |     foo::Foo {};
+   |     ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/unsafe-foreign-mod.rs b/src/test/ui/parser/unsafe-foreign-mod.rs
new file mode 100644
index 00000000000..872af95bd22
--- /dev/null
+++ b/src/test/ui/parser/unsafe-foreign-mod.rs
@@ -0,0 +1,9 @@
+unsafe extern {
+    //~^ ERROR extern block cannot be declared unsafe
+}
+
+unsafe extern "C" {
+    //~^ ERROR extern block cannot be declared unsafe
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/unsafe-foreign-mod.stderr b/src/test/ui/parser/unsafe-foreign-mod.stderr
new file mode 100644
index 00000000000..5e10988051e
--- /dev/null
+++ b/src/test/ui/parser/unsafe-foreign-mod.stderr
@@ -0,0 +1,14 @@
+error: extern block cannot be declared unsafe
+  --> $DIR/unsafe-foreign-mod.rs:1:1
+   |
+LL | unsafe extern {
+   | ^^^^^^
+
+error: extern block cannot be declared unsafe
+  --> $DIR/unsafe-foreign-mod.rs:5:1
+   |
+LL | unsafe extern "C" {
+   | ^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/unsafe-mod.rs b/src/test/ui/parser/unsafe-mod.rs
new file mode 100644
index 00000000000..7916d878ea5
--- /dev/null
+++ b/src/test/ui/parser/unsafe-mod.rs
@@ -0,0 +1,9 @@
+unsafe mod m {
+    //~^ ERROR module cannot be declared unsafe
+}
+
+unsafe mod n;
+//~^ ERROR module cannot be declared unsafe
+//~^^ ERROR file not found for module `n`
+
+fn main() {}
diff --git a/src/test/ui/parser/unsafe-mod.stderr b/src/test/ui/parser/unsafe-mod.stderr
new file mode 100644
index 00000000000..259b2c1d61e
--- /dev/null
+++ b/src/test/ui/parser/unsafe-mod.stderr
@@ -0,0 +1,23 @@
+error[E0583]: file not found for module `n`
+  --> $DIR/unsafe-mod.rs:5:1
+   |
+LL | unsafe mod n;
+   | ^^^^^^^^^^^^^
+   |
+   = help: to create the module `n`, create file "$DIR/n.rs"
+
+error: module cannot be declared unsafe
+  --> $DIR/unsafe-mod.rs:1:1
+   |
+LL | unsafe mod m {
+   | ^^^^^^
+
+error: module cannot be declared unsafe
+  --> $DIR/unsafe-mod.rs:5:1
+   |
+LL | unsafe mod n;
+   | ^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0583`.
diff --git a/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs b/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs
new file mode 100644
index 00000000000..c72306c3d50
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs
@@ -0,0 +1,89 @@
+// force-host
+// no-prefer-dynamic
+
+// These are tests for syntax that is accepted by the Rust parser but
+// unconditionally rejected semantically after macro expansion. Attribute macros
+// are permitted to accept such syntax as long as they replace it with something
+// that makes sense to Rust.
+//
+// We also inspect some of the spans to verify the syntax is not triggering the
+// lossy string reparse hack (https://github.com/rust-lang/rust/issues/43081).
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_span)]
+
+extern crate proc_macro;
+use proc_macro::{token_stream, Delimiter, TokenStream, TokenTree};
+use std::path::Component;
+
+// unsafe mod m {
+//     pub unsafe mod inner;
+// }
+#[proc_macro_attribute]
+pub fn expect_unsafe_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream {
+    let tokens = &mut input.into_iter();
+    expect(tokens, "unsafe");
+    expect(tokens, "mod");
+    expect(tokens, "m");
+    let tokens = &mut expect_brace(tokens);
+    expect(tokens, "pub");
+    expect(tokens, "unsafe");
+    expect(tokens, "mod");
+    let ident = expect(tokens, "inner");
+    expect(tokens, ";");
+    check_useful_span(ident, "unsafe-mod.rs");
+    TokenStream::new()
+}
+
+// unsafe extern {
+//     type T;
+// }
+#[proc_macro_attribute]
+pub fn expect_unsafe_foreign_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream {
+    let tokens = &mut input.into_iter();
+    expect(tokens, "unsafe");
+    expect(tokens, "extern");
+    let tokens = &mut expect_brace(tokens);
+    expect(tokens, "type");
+    let ident = expect(tokens, "T");
+    expect(tokens, ";");
+    check_useful_span(ident, "unsafe-foreign-mod.rs");
+    TokenStream::new()
+}
+
+// unsafe extern "C++" {}
+#[proc_macro_attribute]
+pub fn expect_unsafe_extern_cpp_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream {
+    let tokens = &mut input.into_iter();
+    expect(tokens, "unsafe");
+    expect(tokens, "extern");
+    let abi = expect(tokens, "\"C++\"");
+    expect_brace(tokens);
+    check_useful_span(abi, "unsafe-foreign-mod.rs");
+    TokenStream::new()
+}
+
+fn expect(tokens: &mut token_stream::IntoIter, expected: &str) -> TokenTree {
+    match tokens.next() {
+        Some(token) if token.to_string() == expected => token,
+        wrong => panic!("unexpected token: {:?}, expected `{}`", wrong, expected),
+    }
+}
+
+fn expect_brace(tokens: &mut token_stream::IntoIter) -> token_stream::IntoIter {
+    match tokens.next() {
+        Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => {
+            group.stream().into_iter()
+        }
+        wrong => panic!("unexpected token: {:?}, expected `{{`", wrong),
+    }
+}
+
+fn check_useful_span(token: TokenTree, expected_filename: &str) {
+    let span = token.span();
+    assert!(span.start().column < span.end().column);
+
+    let source_path = span.source_file().path();
+    let filename = source_path.components().last().unwrap();
+    assert_eq!(filename, Component::Normal(expected_filename.as_ref()));
+}
diff --git a/src/test/ui/proc-macro/unsafe-foreign-mod.rs b/src/test/ui/proc-macro/unsafe-foreign-mod.rs
new file mode 100644
index 00000000000..7bdfa93c21f
--- /dev/null
+++ b/src/test/ui/proc-macro/unsafe-foreign-mod.rs
@@ -0,0 +1,14 @@
+// run-pass
+// aux-build:macro-only-syntax.rs
+
+extern crate macro_only_syntax;
+
+#[macro_only_syntax::expect_unsafe_foreign_mod]
+unsafe extern {
+    type T;
+}
+
+#[macro_only_syntax::expect_unsafe_extern_cpp_mod]
+unsafe extern "C++" {}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/unsafe-mod.rs b/src/test/ui/proc-macro/unsafe-mod.rs
new file mode 100644
index 00000000000..8ff6e352c53
--- /dev/null
+++ b/src/test/ui/proc-macro/unsafe-mod.rs
@@ -0,0 +1,13 @@
+// run-pass
+// aux-build:macro-only-syntax.rs
+
+#![feature(proc_macro_hygiene)]
+
+extern crate macro_only_syntax;
+
+#[macro_only_syntax::expect_unsafe_mod]
+unsafe mod m {
+    pub unsafe mod inner;
+}
+
+fn main() {}