about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-12-01 00:39:18 +0000
committerbors <bors@rust-lang.org>2019-12-01 00:39:18 +0000
commit135ccbaca86ed4b9c0efaf0cd31442eae57ffad7 (patch)
treef5d91a593d425871fff9e1b68ac2e9f982d6c8e1
parentd8bdb3fdcbd88eb16e1a6669236122c41ed2aed3 (diff)
parentb772b5b19d769e7062b032e6e73f6466b26d78bd (diff)
downloadrust-135ccbaca86ed4b9c0efaf0cd31442eae57ffad7.tar.gz
rust-135ccbaca86ed4b9c0efaf0cd31442eae57ffad7.zip
Auto merge of #66908 - Centril:rollup-26givp6, r=Centril
Rollup of 9 pull requests

Successful merges:

 - #66612 (Initial implementation of or-pattern usefulness checking)
 - #66705 (Atomic as_mut_ptr)
 - #66759 (impl TrustedLen for vec::Drain)
 - #66858 (Use LLVMAddAnalysisPasses instead of Rust's wrapper)
 - #66870 (SimplifyArmIdentity only for locals with the same type)
 - #66883 (rustc_typeck: gate AnonConst's generics on feature(const_generics).)
 - #66889 (Make python-generated source files compatible with rustfmt)
 - #66894 (Remove unneeded prelude imports in libcore tests)
 - #66895 (Feature gating *declarations* => new crate `rustc_feature`)

Failed merges:

 - #66905 (rustc_plugin: Remove some remaining plugin features)

r? @ghost
-rw-r--r--Cargo.lock18
-rwxr-xr-x[-rw-r--r--]src/etc/dec2flt_table.py15
-rw-r--r--src/liballoc/vec.rs3
-rw-r--r--src/libcore/num/dec2flt/table.rs2456
-rw-r--r--src/libcore/sync/atomic.rs74
-rw-r--r--src/libcore/tests/num/bignum.rs1
-rw-r--r--src/libcore/tests/num/flt2dec/mod.rs1
-rw-r--r--src/libcore/tests/num/flt2dec/strategy/dragon.rs1
-rwxr-xr-x[-rw-r--r--]src/libcore/unicode/printable.py6
-rw-r--r--src/libcore/unicode/printable.rs9
-rw-r--r--src/libcore/unicode/tables.rs29
-rwxr-xr-xsrc/libcore/unicode/unicode.py36
-rw-r--r--src/librustc/Cargo.toml1
-rw-r--r--src/librustc/arena.rs2
-rw-r--r--src/librustc/ich/impls_syntax.rs3
-rw-r--r--src/librustc/lint/levels.rs6
-rw-r--r--src/librustc/middle/stability.rs24
-rw-r--r--src/librustc/query/mod.rs2
-rw-r--r--src/librustc/session/config.rs6
-rw-r--r--src/librustc/session/mod.rs7
-rw-r--r--src/librustc/ty/context.rs3
-rw-r--r--src/librustc/ty/query/mod.rs1
-rw-r--r--src/librustc/ty/sty.rs49
-rw-r--r--src/librustc_codegen_llvm/back/lto.rs2
-rw-r--r--src/librustc_codegen_llvm/back/write.rs6
-rw-r--r--src/librustc_codegen_llvm/lib.rs1
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs3
-rw-r--r--src/librustc_codegen_llvm/llvm_util.rs2
-rw-r--r--src/librustc_driver/Cargo.toml1
-rw-r--r--src/librustc_driver/lib.rs24
-rw-r--r--src/librustc_feature/Cargo.toml15
-rw-r--r--src/librustc_feature/accepted.rs (renamed from src/libsyntax/feature_gate/accepted.rs)2
-rw-r--r--src/librustc_feature/active.rs (renamed from src/libsyntax/feature_gate/active.rs)19
-rw-r--r--src/librustc_feature/builtin_attrs.rs (renamed from src/libsyntax/feature_gate/builtin_attrs.rs)71
-rw-r--r--src/librustc_feature/lib.rs137
-rw-r--r--src/librustc_feature/removed.rs (renamed from src/libsyntax/feature_gate/removed.rs)2
-rw-r--r--src/librustc_lint/Cargo.toml1
-rw-r--r--src/librustc_lint/builtin.rs8
-rw-r--r--src/librustc_lint/unused.rs5
-rw-r--r--src/librustc_metadata/native_libs.rs36
-rw-r--r--src/librustc_mir/build/matches/test.rs8
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs60
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs48
-rw-r--r--src/librustc_mir/transform/simplify_try.rs8
-rw-r--r--src/librustc_parse/Cargo.toml1
-rw-r--r--src/librustc_parse/config.rs14
-rw-r--r--src/librustc_parse/validate_attr.rs18
-rw-r--r--src/librustc_passes/Cargo.toml1
-rw-r--r--src/librustc_passes/ast_validation.rs3
-rw-r--r--src/librustc_passes/check_const.rs11
-rw-r--r--src/librustc_resolve/Cargo.toml1
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs4
-rw-r--r--src/librustc_resolve/diagnostics.rs2
-rw-r--r--src/librustc_resolve/macros.rs15
-rw-r--r--src/librustc_typeck/astconv.rs5
-rw-r--r--src/librustc_typeck/check/coercion.rs12
-rw-r--r--src/librustc_typeck/check/mod.rs32
-rw-r--r--src/librustc_typeck/check/wfcheck.rs6
-rw-r--r--src/librustc_typeck/collect.rs26
-rw-r--r--src/librustdoc/clean/cfg.rs2
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/librustdoc/externalfiles.rs2
-rw-r--r--src/librustdoc/html/render.rs2
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/librustdoc/markdown.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/test.rs2
-rw-r--r--src/libstd/lib.rs1
-rw-r--r--src/libstd/sys/wasm/alloc.rs4
-rw-r--r--src/libstd/sys/wasm/condvar_atomics.rs2
-rw-r--r--src/libstd/sys/wasm/mutex_atomics.rs4
-rw-r--r--src/libsyntax/Cargo.toml1
-rw-r--r--src/libsyntax/attr/builtin.rs57
-rw-r--r--src/libsyntax/feature_gate/check.rs126
-rw-r--r--src/libsyntax/feature_gate/mod.rs71
-rw-r--r--src/libsyntax/lib.rs5
-rw-r--r--src/libsyntax/sess.rs4
-rw-r--r--src/libsyntax_expand/Cargo.toml1
-rw-r--r--src/libsyntax_expand/expand.rs33
-rw-r--r--src/libsyntax_expand/mbe/macro_rules.rs2
-rw-r--r--src/libsyntax_ext/Cargo.toml1
-rw-r--r--src/libsyntax_ext/test_harness.rs2
-rw-r--r--src/libsyntax_ext/util.rs2
-rw-r--r--src/rustllvm/PassWrapper.cpp11
-rw-r--r--src/test/mir-opt/simplify-arm-identity.rs75
-rw-r--r--src/test/ui/issues/issue-66851.rs20
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs26
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr33
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-pass.rs40
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-pass.stderr8
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs51
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr80
-rw-r--r--src/tools/tidy/src/features.rs2
93 files changed, 2255 insertions, 1785 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d27eec893b0..67259aed8eb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3199,6 +3199,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_error_codes",
  "rustc_errors",
+ "rustc_feature",
  "rustc_fs_util",
  "rustc_index",
  "rustc_macros",
@@ -3574,6 +3575,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_error_codes",
  "rustc_errors",
+ "rustc_feature",
  "rustc_interface",
  "rustc_lint",
  "rustc_metadata",
@@ -3608,6 +3610,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustc_feature"
+version = "0.0.0"
+dependencies = [
+ "lazy_static 1.3.0",
+ "rustc_data_structures",
+ "syntax_pos",
+]
+
+[[package]]
 name = "rustc_fs_util"
 version = "0.0.0"
 
@@ -3682,6 +3693,7 @@ dependencies = [
  "rustc",
  "rustc_data_structures",
  "rustc_error_codes",
+ "rustc_feature",
  "rustc_index",
  "rustc_target",
  "syntax",
@@ -3786,6 +3798,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_error_codes",
  "rustc_errors",
+ "rustc_feature",
  "rustc_lexer",
  "rustc_target",
  "smallvec 1.0.0",
@@ -3802,6 +3815,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_error_codes",
  "rustc_errors",
+ "rustc_feature",
  "rustc_index",
  "rustc_parse",
  "rustc_target",
@@ -3844,6 +3858,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_error_codes",
  "rustc_errors",
+ "rustc_feature",
  "rustc_metadata",
  "smallvec 1.0.0",
  "syntax",
@@ -4442,6 +4457,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_error_codes",
  "rustc_errors",
+ "rustc_feature",
  "rustc_index",
  "rustc_lexer",
  "rustc_macros",
@@ -4458,6 +4474,7 @@ dependencies = [
  "log",
  "rustc_data_structures",
  "rustc_errors",
+ "rustc_feature",
  "rustc_lexer",
  "rustc_parse",
  "serialize",
@@ -4475,6 +4492,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_error_codes",
  "rustc_errors",
+ "rustc_feature",
  "rustc_parse",
  "rustc_target",
  "smallvec 1.0.0",
diff --git a/src/etc/dec2flt_table.py b/src/etc/dec2flt_table.py
index 2ffaf13dc8f..85395d2ecdf 100644..100755
--- a/src/etc/dec2flt_table.py
+++ b/src/etc/dec2flt_table.py
@@ -111,14 +111,18 @@ def print_proper_powers():
     print("pub const MIN_E: i16 = {};".format(MIN_E))
     print("pub const MAX_E: i16 = {};".format(MAX_E))
     print()
+    print("#[rustfmt::skip]")
     typ = "([u64; {0}], [i16; {0}])".format(len(powers))
-    print("pub const POWERS: ", typ, " = ([", sep='')
+    print("pub const POWERS: ", typ, " = (", sep='')
+    print("    [")
     for z in powers:
-        print("    0x{:x},".format(z.sig))
-    print("], [")
+        print("        0x{:x},".format(z.sig))
+    print("    ],")
+    print("    [")
     for z in powers:
-        print("    {},".format(z.exp))
-    print("]);")
+        print("        {},".format(z.exp))
+    print("    ],")
+    print(");")
 
 
 def print_short_powers(num_bits, significand_size):
@@ -127,6 +131,7 @@ def print_short_powers(num_bits, significand_size):
     max_e = int(ceil(log(max_sig, 5)))
     e_range = range(max_e)
     typ = "[f{}; {}]".format(num_bits, len(e_range))
+    print("#[rustfmt::skip]")
     print("pub const F", num_bits, "_SHORT_POWERS: ", typ, " = [", sep='')
     for e in e_range:
         print("    1e{},".format(e))
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index 8892e186d0a..1a700b99056 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -2703,6 +2703,9 @@ impl<T> ExactSizeIterator for Drain<'_, T> {
     }
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for Drain<'_, T> {}
+
 #[stable(feature = "fused", since = "1.26.0")]
 impl<T> FusedIterator for Drain<'_, T> {}
 
diff --git a/src/libcore/num/dec2flt/table.rs b/src/libcore/num/dec2flt/table.rs
index 345ac830aaa..1bd94ffa04e 100644
--- a/src/libcore/num/dec2flt/table.rs
+++ b/src/libcore/num/dec2flt/table.rs
@@ -4,1232 +4,1237 @@
 pub const MIN_E: i16 = -305;
 pub const MAX_E: i16 = 305;
 
-pub const POWERS: ([u64; 611], [i16; 611]) = ([
-    0xe0b62e2929aba83c,
-    0x8c71dcd9ba0b4926,
-    0xaf8e5410288e1b6f,
-    0xdb71e91432b1a24b,
-    0x892731ac9faf056f,
-    0xab70fe17c79ac6ca,
-    0xd64d3d9db981787d,
-    0x85f0468293f0eb4e,
-    0xa76c582338ed2622,
-    0xd1476e2c07286faa,
-    0x82cca4db847945ca,
-    0xa37fce126597973d,
-    0xcc5fc196fefd7d0c,
-    0xff77b1fcbebcdc4f,
-    0x9faacf3df73609b1,
-    0xc795830d75038c1e,
-    0xf97ae3d0d2446f25,
-    0x9becce62836ac577,
-    0xc2e801fb244576d5,
-    0xf3a20279ed56d48a,
-    0x9845418c345644d7,
-    0xbe5691ef416bd60c,
-    0xedec366b11c6cb8f,
-    0x94b3a202eb1c3f39,
-    0xb9e08a83a5e34f08,
-    0xe858ad248f5c22ca,
-    0x91376c36d99995be,
-    0xb58547448ffffb2e,
-    0xe2e69915b3fff9f9,
-    0x8dd01fad907ffc3c,
-    0xb1442798f49ffb4b,
-    0xdd95317f31c7fa1d,
-    0x8a7d3eef7f1cfc52,
-    0xad1c8eab5ee43b67,
-    0xd863b256369d4a41,
-    0x873e4f75e2224e68,
-    0xa90de3535aaae202,
-    0xd3515c2831559a83,
-    0x8412d9991ed58092,
-    0xa5178fff668ae0b6,
-    0xce5d73ff402d98e4,
-    0x80fa687f881c7f8e,
-    0xa139029f6a239f72,
-    0xc987434744ac874f,
-    0xfbe9141915d7a922,
-    0x9d71ac8fada6c9b5,
-    0xc4ce17b399107c23,
-    0xf6019da07f549b2b,
-    0x99c102844f94e0fb,
-    0xc0314325637a193a,
-    0xf03d93eebc589f88,
-    0x96267c7535b763b5,
-    0xbbb01b9283253ca3,
-    0xea9c227723ee8bcb,
-    0x92a1958a7675175f,
-    0xb749faed14125d37,
-    0xe51c79a85916f485,
-    0x8f31cc0937ae58d3,
-    0xb2fe3f0b8599ef08,
-    0xdfbdcece67006ac9,
-    0x8bd6a141006042be,
-    0xaecc49914078536d,
-    0xda7f5bf590966849,
-    0x888f99797a5e012d,
-    0xaab37fd7d8f58179,
-    0xd5605fcdcf32e1d7,
-    0x855c3be0a17fcd26,
-    0xa6b34ad8c9dfc070,
-    0xd0601d8efc57b08c,
-    0x823c12795db6ce57,
-    0xa2cb1717b52481ed,
-    0xcb7ddcdda26da269,
-    0xfe5d54150b090b03,
-    0x9efa548d26e5a6e2,
-    0xc6b8e9b0709f109a,
-    0xf867241c8cc6d4c1,
-    0x9b407691d7fc44f8,
-    0xc21094364dfb5637,
-    0xf294b943e17a2bc4,
-    0x979cf3ca6cec5b5b,
-    0xbd8430bd08277231,
-    0xece53cec4a314ebe,
-    0x940f4613ae5ed137,
-    0xb913179899f68584,
-    0xe757dd7ec07426e5,
-    0x9096ea6f3848984f,
-    0xb4bca50b065abe63,
-    0xe1ebce4dc7f16dfc,
-    0x8d3360f09cf6e4bd,
-    0xb080392cc4349ded,
-    0xdca04777f541c568,
-    0x89e42caaf9491b61,
-    0xac5d37d5b79b6239,
-    0xd77485cb25823ac7,
-    0x86a8d39ef77164bd,
-    0xa8530886b54dbdec,
-    0xd267caa862a12d67,
-    0x8380dea93da4bc60,
-    0xa46116538d0deb78,
-    0xcd795be870516656,
-    0x806bd9714632dff6,
-    0xa086cfcd97bf97f4,
-    0xc8a883c0fdaf7df0,
-    0xfad2a4b13d1b5d6c,
-    0x9cc3a6eec6311a64,
-    0xc3f490aa77bd60fd,
-    0xf4f1b4d515acb93c,
-    0x991711052d8bf3c5,
-    0xbf5cd54678eef0b7,
-    0xef340a98172aace5,
-    0x9580869f0e7aac0f,
-    0xbae0a846d2195713,
-    0xe998d258869facd7,
-    0x91ff83775423cc06,
-    0xb67f6455292cbf08,
-    0xe41f3d6a7377eeca,
-    0x8e938662882af53e,
-    0xb23867fb2a35b28e,
-    0xdec681f9f4c31f31,
-    0x8b3c113c38f9f37f,
-    0xae0b158b4738705f,
-    0xd98ddaee19068c76,
-    0x87f8a8d4cfa417ca,
-    0xa9f6d30a038d1dbc,
-    0xd47487cc8470652b,
-    0x84c8d4dfd2c63f3b,
-    0xa5fb0a17c777cf0a,
-    0xcf79cc9db955c2cc,
-    0x81ac1fe293d599c0,
-    0xa21727db38cb0030,
-    0xca9cf1d206fdc03c,
-    0xfd442e4688bd304b,
-    0x9e4a9cec15763e2f,
-    0xc5dd44271ad3cdba,
-    0xf7549530e188c129,
-    0x9a94dd3e8cf578ba,
-    0xc13a148e3032d6e8,
-    0xf18899b1bc3f8ca2,
-    0x96f5600f15a7b7e5,
-    0xbcb2b812db11a5de,
-    0xebdf661791d60f56,
-    0x936b9fcebb25c996,
-    0xb84687c269ef3bfb,
-    0xe65829b3046b0afa,
-    0x8ff71a0fe2c2e6dc,
-    0xb3f4e093db73a093,
-    0xe0f218b8d25088b8,
-    0x8c974f7383725573,
-    0xafbd2350644eead0,
-    0xdbac6c247d62a584,
-    0x894bc396ce5da772,
-    0xab9eb47c81f5114f,
-    0xd686619ba27255a3,
-    0x8613fd0145877586,
-    0xa798fc4196e952e7,
-    0xd17f3b51fca3a7a1,
-    0x82ef85133de648c5,
-    0xa3ab66580d5fdaf6,
-    0xcc963fee10b7d1b3,
-    0xffbbcfe994e5c620,
-    0x9fd561f1fd0f9bd4,
-    0xc7caba6e7c5382c9,
-    0xf9bd690a1b68637b,
-    0x9c1661a651213e2d,
-    0xc31bfa0fe5698db8,
-    0xf3e2f893dec3f126,
-    0x986ddb5c6b3a76b8,
-    0xbe89523386091466,
-    0xee2ba6c0678b597f,
-    0x94db483840b717f0,
-    0xba121a4650e4ddec,
-    0xe896a0d7e51e1566,
-    0x915e2486ef32cd60,
-    0xb5b5ada8aaff80b8,
-    0xe3231912d5bf60e6,
-    0x8df5efabc5979c90,
-    0xb1736b96b6fd83b4,
-    0xddd0467c64bce4a1,
-    0x8aa22c0dbef60ee4,
-    0xad4ab7112eb3929e,
-    0xd89d64d57a607745,
-    0x87625f056c7c4a8b,
-    0xa93af6c6c79b5d2e,
-    0xd389b47879823479,
-    0x843610cb4bf160cc,
-    0xa54394fe1eedb8ff,
-    0xce947a3da6a9273e,
-    0x811ccc668829b887,
-    0xa163ff802a3426a9,
-    0xc9bcff6034c13053,
-    0xfc2c3f3841f17c68,
-    0x9d9ba7832936edc1,
-    0xc5029163f384a931,
-    0xf64335bcf065d37d,
-    0x99ea0196163fa42e,
-    0xc06481fb9bcf8d3a,
-    0xf07da27a82c37088,
-    0x964e858c91ba2655,
-    0xbbe226efb628afeb,
-    0xeadab0aba3b2dbe5,
-    0x92c8ae6b464fc96f,
-    0xb77ada0617e3bbcb,
-    0xe55990879ddcaabe,
-    0x8f57fa54c2a9eab7,
-    0xb32df8e9f3546564,
-    0xdff9772470297ebd,
-    0x8bfbea76c619ef36,
-    0xaefae51477a06b04,
-    0xdab99e59958885c5,
-    0x88b402f7fd75539b,
-    0xaae103b5fcd2a882,
-    0xd59944a37c0752a2,
-    0x857fcae62d8493a5,
-    0xa6dfbd9fb8e5b88f,
-    0xd097ad07a71f26b2,
-    0x825ecc24c8737830,
-    0xa2f67f2dfa90563b,
-    0xcbb41ef979346bca,
-    0xfea126b7d78186bd,
-    0x9f24b832e6b0f436,
-    0xc6ede63fa05d3144,
-    0xf8a95fcf88747d94,
-    0x9b69dbe1b548ce7d,
-    0xc24452da229b021c,
-    0xf2d56790ab41c2a3,
-    0x97c560ba6b0919a6,
-    0xbdb6b8e905cb600f,
-    0xed246723473e3813,
-    0x9436c0760c86e30c,
-    0xb94470938fa89bcf,
-    0xe7958cb87392c2c3,
-    0x90bd77f3483bb9ba,
-    0xb4ecd5f01a4aa828,
-    0xe2280b6c20dd5232,
-    0x8d590723948a535f,
-    0xb0af48ec79ace837,
-    0xdcdb1b2798182245,
-    0x8a08f0f8bf0f156b,
-    0xac8b2d36eed2dac6,
-    0xd7adf884aa879177,
-    0x86ccbb52ea94baeb,
-    0xa87fea27a539e9a5,
-    0xd29fe4b18e88640f,
-    0x83a3eeeef9153e89,
-    0xa48ceaaab75a8e2b,
-    0xcdb02555653131b6,
-    0x808e17555f3ebf12,
-    0xa0b19d2ab70e6ed6,
-    0xc8de047564d20a8c,
-    0xfb158592be068d2f,
-    0x9ced737bb6c4183d,
-    0xc428d05aa4751e4d,
-    0xf53304714d9265e0,
-    0x993fe2c6d07b7fac,
-    0xbf8fdb78849a5f97,
-    0xef73d256a5c0f77d,
-    0x95a8637627989aae,
-    0xbb127c53b17ec159,
-    0xe9d71b689dde71b0,
-    0x9226712162ab070e,
-    0xb6b00d69bb55c8d1,
-    0xe45c10c42a2b3b06,
-    0x8eb98a7a9a5b04e3,
-    0xb267ed1940f1c61c,
-    0xdf01e85f912e37a3,
-    0x8b61313bbabce2c6,
-    0xae397d8aa96c1b78,
-    0xd9c7dced53c72256,
-    0x881cea14545c7575,
-    0xaa242499697392d3,
-    0xd4ad2dbfc3d07788,
-    0x84ec3c97da624ab5,
-    0xa6274bbdd0fadd62,
-    0xcfb11ead453994ba,
-    0x81ceb32c4b43fcf5,
-    0xa2425ff75e14fc32,
-    0xcad2f7f5359a3b3e,
-    0xfd87b5f28300ca0e,
-    0x9e74d1b791e07e48,
-    0xc612062576589ddb,
-    0xf79687aed3eec551,
-    0x9abe14cd44753b53,
-    0xc16d9a0095928a27,
-    0xf1c90080baf72cb1,
-    0x971da05074da7bef,
-    0xbce5086492111aeb,
-    0xec1e4a7db69561a5,
-    0x9392ee8e921d5d07,
-    0xb877aa3236a4b449,
-    0xe69594bec44de15b,
-    0x901d7cf73ab0acd9,
-    0xb424dc35095cd80f,
-    0xe12e13424bb40e13,
-    0x8cbccc096f5088cc,
-    0xafebff0bcb24aaff,
-    0xdbe6fecebdedd5bf,
-    0x89705f4136b4a597,
-    0xabcc77118461cefd,
-    0xd6bf94d5e57a42bc,
-    0x8637bd05af6c69b6,
-    0xa7c5ac471b478423,
-    0xd1b71758e219652c,
-    0x83126e978d4fdf3b,
-    0xa3d70a3d70a3d70a,
-    0xcccccccccccccccd,
-    0x8000000000000000,
-    0xa000000000000000,
-    0xc800000000000000,
-    0xfa00000000000000,
-    0x9c40000000000000,
-    0xc350000000000000,
-    0xf424000000000000,
-    0x9896800000000000,
-    0xbebc200000000000,
-    0xee6b280000000000,
-    0x9502f90000000000,
-    0xba43b74000000000,
-    0xe8d4a51000000000,
-    0x9184e72a00000000,
-    0xb5e620f480000000,
-    0xe35fa931a0000000,
-    0x8e1bc9bf04000000,
-    0xb1a2bc2ec5000000,
-    0xde0b6b3a76400000,
-    0x8ac7230489e80000,
-    0xad78ebc5ac620000,
-    0xd8d726b7177a8000,
-    0x878678326eac9000,
-    0xa968163f0a57b400,
-    0xd3c21bcecceda100,
-    0x84595161401484a0,
-    0xa56fa5b99019a5c8,
-    0xcecb8f27f4200f3a,
-    0x813f3978f8940984,
-    0xa18f07d736b90be5,
-    0xc9f2c9cd04674edf,
-    0xfc6f7c4045812296,
-    0x9dc5ada82b70b59e,
-    0xc5371912364ce305,
-    0xf684df56c3e01bc7,
-    0x9a130b963a6c115c,
-    0xc097ce7bc90715b3,
-    0xf0bdc21abb48db20,
-    0x96769950b50d88f4,
-    0xbc143fa4e250eb31,
-    0xeb194f8e1ae525fd,
-    0x92efd1b8d0cf37be,
-    0xb7abc627050305ae,
-    0xe596b7b0c643c719,
-    0x8f7e32ce7bea5c70,
-    0xb35dbf821ae4f38c,
-    0xe0352f62a19e306f,
-    0x8c213d9da502de45,
-    0xaf298d050e4395d7,
-    0xdaf3f04651d47b4c,
-    0x88d8762bf324cd10,
-    0xab0e93b6efee0054,
-    0xd5d238a4abe98068,
-    0x85a36366eb71f041,
-    0xa70c3c40a64e6c52,
-    0xd0cf4b50cfe20766,
-    0x82818f1281ed44a0,
-    0xa321f2d7226895c8,
-    0xcbea6f8ceb02bb3a,
-    0xfee50b7025c36a08,
-    0x9f4f2726179a2245,
-    0xc722f0ef9d80aad6,
-    0xf8ebad2b84e0d58c,
-    0x9b934c3b330c8577,
-    0xc2781f49ffcfa6d5,
-    0xf316271c7fc3908b,
-    0x97edd871cfda3a57,
-    0xbde94e8e43d0c8ec,
-    0xed63a231d4c4fb27,
-    0x945e455f24fb1cf9,
-    0xb975d6b6ee39e437,
-    0xe7d34c64a9c85d44,
-    0x90e40fbeea1d3a4b,
-    0xb51d13aea4a488dd,
-    0xe264589a4dcdab15,
-    0x8d7eb76070a08aed,
-    0xb0de65388cc8ada8,
-    0xdd15fe86affad912,
-    0x8a2dbf142dfcc7ab,
-    0xacb92ed9397bf996,
-    0xd7e77a8f87daf7fc,
-    0x86f0ac99b4e8dafd,
-    0xa8acd7c0222311bd,
-    0xd2d80db02aabd62c,
-    0x83c7088e1aab65db,
-    0xa4b8cab1a1563f52,
-    0xcde6fd5e09abcf27,
-    0x80b05e5ac60b6178,
-    0xa0dc75f1778e39d6,
-    0xc913936dd571c84c,
-    0xfb5878494ace3a5f,
-    0x9d174b2dcec0e47b,
-    0xc45d1df942711d9a,
-    0xf5746577930d6501,
-    0x9968bf6abbe85f20,
-    0xbfc2ef456ae276e9,
-    0xefb3ab16c59b14a3,
-    0x95d04aee3b80ece6,
-    0xbb445da9ca61281f,
-    0xea1575143cf97227,
-    0x924d692ca61be758,
-    0xb6e0c377cfa2e12e,
-    0xe498f455c38b997a,
-    0x8edf98b59a373fec,
-    0xb2977ee300c50fe7,
-    0xdf3d5e9bc0f653e1,
-    0x8b865b215899f46d,
-    0xae67f1e9aec07188,
-    0xda01ee641a708dea,
-    0x884134fe908658b2,
-    0xaa51823e34a7eedf,
-    0xd4e5e2cdc1d1ea96,
-    0x850fadc09923329e,
-    0xa6539930bf6bff46,
-    0xcfe87f7cef46ff17,
-    0x81f14fae158c5f6e,
-    0xa26da3999aef774a,
-    0xcb090c8001ab551c,
-    0xfdcb4fa002162a63,
-    0x9e9f11c4014dda7e,
-    0xc646d63501a1511e,
-    0xf7d88bc24209a565,
-    0x9ae757596946075f,
-    0xc1a12d2fc3978937,
-    0xf209787bb47d6b85,
-    0x9745eb4d50ce6333,
-    0xbd176620a501fc00,
-    0xec5d3fa8ce427b00,
-    0x93ba47c980e98ce0,
-    0xb8a8d9bbe123f018,
-    0xe6d3102ad96cec1e,
-    0x9043ea1ac7e41393,
-    0xb454e4a179dd1877,
-    0xe16a1dc9d8545e95,
-    0x8ce2529e2734bb1d,
-    0xb01ae745b101e9e4,
-    0xdc21a1171d42645d,
-    0x899504ae72497eba,
-    0xabfa45da0edbde69,
-    0xd6f8d7509292d603,
-    0x865b86925b9bc5c2,
-    0xa7f26836f282b733,
-    0xd1ef0244af2364ff,
-    0x8335616aed761f1f,
-    0xa402b9c5a8d3a6e7,
-    0xcd036837130890a1,
-    0x802221226be55a65,
-    0xa02aa96b06deb0fe,
-    0xc83553c5c8965d3d,
-    0xfa42a8b73abbf48d,
-    0x9c69a97284b578d8,
-    0xc38413cf25e2d70e,
-    0xf46518c2ef5b8cd1,
-    0x98bf2f79d5993803,
-    0xbeeefb584aff8604,
-    0xeeaaba2e5dbf6785,
-    0x952ab45cfa97a0b3,
-    0xba756174393d88e0,
-    0xe912b9d1478ceb17,
-    0x91abb422ccb812ef,
-    0xb616a12b7fe617aa,
-    0xe39c49765fdf9d95,
-    0x8e41ade9fbebc27d,
-    0xb1d219647ae6b31c,
-    0xde469fbd99a05fe3,
-    0x8aec23d680043bee,
-    0xada72ccc20054aea,
-    0xd910f7ff28069da4,
-    0x87aa9aff79042287,
-    0xa99541bf57452b28,
-    0xd3fa922f2d1675f2,
-    0x847c9b5d7c2e09b7,
-    0xa59bc234db398c25,
-    0xcf02b2c21207ef2f,
-    0x8161afb94b44f57d,
-    0xa1ba1ba79e1632dc,
-    0xca28a291859bbf93,
-    0xfcb2cb35e702af78,
-    0x9defbf01b061adab,
-    0xc56baec21c7a1916,
-    0xf6c69a72a3989f5c,
-    0x9a3c2087a63f6399,
-    0xc0cb28a98fcf3c80,
-    0xf0fdf2d3f3c30b9f,
-    0x969eb7c47859e744,
-    0xbc4665b596706115,
-    0xeb57ff22fc0c795a,
-    0x9316ff75dd87cbd8,
-    0xb7dcbf5354e9bece,
-    0xe5d3ef282a242e82,
-    0x8fa475791a569d11,
-    0xb38d92d760ec4455,
-    0xe070f78d3927556b,
-    0x8c469ab843b89563,
-    0xaf58416654a6babb,
-    0xdb2e51bfe9d0696a,
-    0x88fcf317f22241e2,
-    0xab3c2fddeeaad25b,
-    0xd60b3bd56a5586f2,
-    0x85c7056562757457,
-    0xa738c6bebb12d16d,
-    0xd106f86e69d785c8,
-    0x82a45b450226b39d,
-    0xa34d721642b06084,
-    0xcc20ce9bd35c78a5,
-    0xff290242c83396ce,
-    0x9f79a169bd203e41,
-    0xc75809c42c684dd1,
-    0xf92e0c3537826146,
-    0x9bbcc7a142b17ccc,
-    0xc2abf989935ddbfe,
-    0xf356f7ebf83552fe,
-    0x98165af37b2153df,
-    0xbe1bf1b059e9a8d6,
-    0xeda2ee1c7064130c,
-    0x9485d4d1c63e8be8,
-    0xb9a74a0637ce2ee1,
-    0xe8111c87c5c1ba9a,
-    0x910ab1d4db9914a0,
-    0xb54d5e4a127f59c8,
-    0xe2a0b5dc971f303a,
-    0x8da471a9de737e24,
-    0xb10d8e1456105dad,
-    0xdd50f1996b947519,
-    0x8a5296ffe33cc930,
-    0xace73cbfdc0bfb7b,
-    0xd8210befd30efa5a,
-    0x8714a775e3e95c78,
-    0xa8d9d1535ce3b396,
-    0xd31045a8341ca07c,
-    0x83ea2b892091e44e,
-    0xa4e4b66b68b65d61,
-    0xce1de40642e3f4b9,
-    0x80d2ae83e9ce78f4,
-    0xa1075a24e4421731,
-    0xc94930ae1d529cfd,
-    0xfb9b7cd9a4a7443c,
-    0x9d412e0806e88aa6,
-    0xc491798a08a2ad4f,
-    0xf5b5d7ec8acb58a3,
-    0x9991a6f3d6bf1766,
-    0xbff610b0cc6edd3f,
-    0xeff394dcff8a948f,
-    0x95f83d0a1fb69cd9,
-    0xbb764c4ca7a44410,
-    0xea53df5fd18d5514,
-    0x92746b9be2f8552c,
-    0xb7118682dbb66a77,
-    0xe4d5e82392a40515,
-    0x8f05b1163ba6832d,
-    0xb2c71d5bca9023f8,
-    0xdf78e4b2bd342cf7,
-    0x8bab8eefb6409c1a,
-    0xae9672aba3d0c321,
-    0xda3c0f568cc4f3e9,
-    0x8865899617fb1871,
-    0xaa7eebfb9df9de8e,
-    0xd51ea6fa85785631,
-    0x8533285c936b35df,
-    0xa67ff273b8460357,
-    0xd01fef10a657842c,
-    0x8213f56a67f6b29c,
-    0xa298f2c501f45f43,
-    0xcb3f2f7642717713,
-    0xfe0efb53d30dd4d8,
-    0x9ec95d1463e8a507,
-    0xc67bb4597ce2ce49,
-    0xf81aa16fdc1b81db,
-    0x9b10a4e5e9913129,
-    0xc1d4ce1f63f57d73,
-    0xf24a01a73cf2dcd0,
-    0x976e41088617ca02,
-    0xbd49d14aa79dbc82,
-    0xec9c459d51852ba3,
-    0x93e1ab8252f33b46,
-    0xb8da1662e7b00a17,
-    0xe7109bfba19c0c9d,
-    0x906a617d450187e2,
-    0xb484f9dc9641e9db,
-    0xe1a63853bbd26451,
-    0x8d07e33455637eb3,
-    0xb049dc016abc5e60,
-    0xdc5c5301c56b75f7,
-    0x89b9b3e11b6329bb,
-    0xac2820d9623bf429,
-    0xd732290fbacaf134,
-    0x867f59a9d4bed6c0,
-    0xa81f301449ee8c70,
-    0xd226fc195c6a2f8c,
-    0x83585d8fd9c25db8,
-    0xa42e74f3d032f526,
-    0xcd3a1230c43fb26f,
-    0x80444b5e7aa7cf85,
-    0xa0555e361951c367,
-    0xc86ab5c39fa63441,
-    0xfa856334878fc151,
-    0x9c935e00d4b9d8d2,
-    0xc3b8358109e84f07,
-    0xf4a642e14c6262c9,
-    0x98e7e9cccfbd7dbe,
-    0xbf21e44003acdd2d,
-    0xeeea5d5004981478,
-    0x95527a5202df0ccb,
-    0xbaa718e68396cffe,
-    0xe950df20247c83fd,
-    0x91d28b7416cdd27e,
-], [
-    -1077,
-    -1073,
-    -1070,
-    -1067,
-    -1063,
-    -1060,
-    -1057,
-    -1053,
-    -1050,
-    -1047,
-    -1043,
-    -1040,
-    -1037,
-    -1034,
-    -1030,
-    -1027,
-    -1024,
-    -1020,
-    -1017,
-    -1014,
-    -1010,
-    -1007,
-    -1004,
-    -1000,
-    -997,
-    -994,
-    -990,
-    -987,
-    -984,
-    -980,
-    -977,
-    -974,
-    -970,
-    -967,
-    -964,
-    -960,
-    -957,
-    -954,
-    -950,
-    -947,
-    -944,
-    -940,
-    -937,
-    -934,
-    -931,
-    -927,
-    -924,
-    -921,
-    -917,
-    -914,
-    -911,
-    -907,
-    -904,
-    -901,
-    -897,
-    -894,
-    -891,
-    -887,
-    -884,
-    -881,
-    -877,
-    -874,
-    -871,
-    -867,
-    -864,
-    -861,
-    -857,
-    -854,
-    -851,
-    -847,
-    -844,
-    -841,
-    -838,
-    -834,
-    -831,
-    -828,
-    -824,
-    -821,
-    -818,
-    -814,
-    -811,
-    -808,
-    -804,
-    -801,
-    -798,
-    -794,
-    -791,
-    -788,
-    -784,
-    -781,
-    -778,
-    -774,
-    -771,
-    -768,
-    -764,
-    -761,
-    -758,
-    -754,
-    -751,
-    -748,
-    -744,
-    -741,
-    -738,
-    -735,
-    -731,
-    -728,
-    -725,
-    -721,
-    -718,
-    -715,
-    -711,
-    -708,
-    -705,
-    -701,
-    -698,
-    -695,
-    -691,
-    -688,
-    -685,
-    -681,
-    -678,
-    -675,
-    -671,
-    -668,
-    -665,
-    -661,
-    -658,
-    -655,
-    -651,
-    -648,
-    -645,
-    -642,
-    -638,
-    -635,
-    -632,
-    -628,
-    -625,
-    -622,
-    -618,
-    -615,
-    -612,
-    -608,
-    -605,
-    -602,
-    -598,
-    -595,
-    -592,
-    -588,
-    -585,
-    -582,
-    -578,
-    -575,
-    -572,
-    -568,
-    -565,
-    -562,
-    -558,
-    -555,
-    -552,
-    -549,
-    -545,
-    -542,
-    -539,
-    -535,
-    -532,
-    -529,
-    -525,
-    -522,
-    -519,
-    -515,
-    -512,
-    -509,
-    -505,
-    -502,
-    -499,
-    -495,
-    -492,
-    -489,
-    -485,
-    -482,
-    -479,
-    -475,
-    -472,
-    -469,
-    -465,
-    -462,
-    -459,
-    -455,
-    -452,
-    -449,
-    -446,
-    -442,
-    -439,
-    -436,
-    -432,
-    -429,
-    -426,
-    -422,
-    -419,
-    -416,
-    -412,
-    -409,
-    -406,
-    -402,
-    -399,
-    -396,
-    -392,
-    -389,
-    -386,
-    -382,
-    -379,
-    -376,
-    -372,
-    -369,
-    -366,
-    -362,
-    -359,
-    -356,
-    -353,
-    -349,
-    -346,
-    -343,
-    -339,
-    -336,
-    -333,
-    -329,
-    -326,
-    -323,
-    -319,
-    -316,
-    -313,
-    -309,
-    -306,
-    -303,
-    -299,
-    -296,
-    -293,
-    -289,
-    -286,
-    -283,
-    -279,
-    -276,
-    -273,
-    -269,
-    -266,
-    -263,
-    -259,
-    -256,
-    -253,
-    -250,
-    -246,
-    -243,
-    -240,
-    -236,
-    -233,
-    -230,
-    -226,
-    -223,
-    -220,
-    -216,
-    -213,
-    -210,
-    -206,
-    -203,
-    -200,
-    -196,
-    -193,
-    -190,
-    -186,
-    -183,
-    -180,
-    -176,
-    -173,
-    -170,
-    -166,
-    -163,
-    -160,
-    -157,
-    -153,
-    -150,
-    -147,
-    -143,
-    -140,
-    -137,
-    -133,
-    -130,
-    -127,
-    -123,
-    -120,
-    -117,
-    -113,
-    -110,
-    -107,
-    -103,
-    -100,
-    -97,
-    -93,
-    -90,
-    -87,
-    -83,
-    -80,
-    -77,
-    -73,
-    -70,
-    -67,
-    -63,
-    -60,
-    -57,
-    -54,
-    -50,
-    -47,
-    -44,
-    -40,
-    -37,
-    -34,
-    -30,
-    -27,
-    -24,
-    -20,
-    -17,
-    -14,
-    -10,
-    -7,
-    -4,
-    0,
-    3,
-    6,
-    10,
-    13,
-    16,
-    20,
-    23,
-    26,
-    30,
-    33,
-    36,
-    39,
-    43,
-    46,
-    49,
-    53,
-    56,
-    59,
-    63,
-    66,
-    69,
-    73,
-    76,
-    79,
-    83,
-    86,
-    89,
-    93,
-    96,
-    99,
-    103,
-    106,
-    109,
-    113,
-    116,
-    119,
-    123,
-    126,
-    129,
-    132,
-    136,
-    139,
-    142,
-    146,
-    149,
-    152,
-    156,
-    159,
-    162,
-    166,
-    169,
-    172,
-    176,
-    179,
-    182,
-    186,
-    189,
-    192,
-    196,
-    199,
-    202,
-    206,
-    209,
-    212,
-    216,
-    219,
-    222,
-    226,
-    229,
-    232,
-    235,
-    239,
-    242,
-    245,
-    249,
-    252,
-    255,
-    259,
-    262,
-    265,
-    269,
-    272,
-    275,
-    279,
-    282,
-    285,
-    289,
-    292,
-    295,
-    299,
-    302,
-    305,
-    309,
-    312,
-    315,
-    319,
-    322,
-    325,
-    328,
-    332,
-    335,
-    338,
-    342,
-    345,
-    348,
-    352,
-    355,
-    358,
-    362,
-    365,
-    368,
-    372,
-    375,
-    378,
-    382,
-    385,
-    388,
-    392,
-    395,
-    398,
-    402,
-    405,
-    408,
-    412,
-    415,
-    418,
-    422,
-    425,
-    428,
-    431,
-    435,
-    438,
-    441,
-    445,
-    448,
-    451,
-    455,
-    458,
-    461,
-    465,
-    468,
-    471,
-    475,
-    478,
-    481,
-    485,
-    488,
-    491,
-    495,
-    498,
-    501,
-    505,
-    508,
-    511,
-    515,
-    518,
-    521,
-    524,
-    528,
-    531,
-    534,
-    538,
-    541,
-    544,
-    548,
-    551,
-    554,
-    558,
-    561,
-    564,
-    568,
-    571,
-    574,
-    578,
-    581,
-    584,
-    588,
-    591,
-    594,
-    598,
-    601,
-    604,
-    608,
-    611,
-    614,
-    617,
-    621,
-    624,
-    627,
-    631,
-    634,
-    637,
-    641,
-    644,
-    647,
-    651,
-    654,
-    657,
-    661,
-    664,
-    667,
-    671,
-    674,
-    677,
-    681,
-    684,
-    687,
-    691,
-    694,
-    697,
-    701,
-    704,
-    707,
-    711,
-    714,
-    717,
-    720,
-    724,
-    727,
-    730,
-    734,
-    737,
-    740,
-    744,
-    747,
-    750,
-    754,
-    757,
-    760,
-    764,
-    767,
-    770,
-    774,
-    777,
-    780,
-    784,
-    787,
-    790,
-    794,
-    797,
-    800,
-    804,
-    807,
-    810,
-    813,
-    817,
-    820,
-    823,
-    827,
-    830,
-    833,
-    837,
-    840,
-    843,
-    847,
-    850,
-    853,
-    857,
-    860,
-    863,
-    867,
-    870,
-    873,
-    877,
-    880,
-    883,
-    887,
-    890,
-    893,
-    897,
-    900,
-    903,
-    907,
-    910,
-    913,
-    916,
-    920,
-    923,
-    926,
-    930,
-    933,
-    936,
-    940,
-    943,
-    946,
-    950,
-]);
+#[rustfmt::skip]
+pub const POWERS: ([u64; 611], [i16; 611]) = (
+    [
+        0xe0b62e2929aba83c,
+        0x8c71dcd9ba0b4926,
+        0xaf8e5410288e1b6f,
+        0xdb71e91432b1a24b,
+        0x892731ac9faf056f,
+        0xab70fe17c79ac6ca,
+        0xd64d3d9db981787d,
+        0x85f0468293f0eb4e,
+        0xa76c582338ed2622,
+        0xd1476e2c07286faa,
+        0x82cca4db847945ca,
+        0xa37fce126597973d,
+        0xcc5fc196fefd7d0c,
+        0xff77b1fcbebcdc4f,
+        0x9faacf3df73609b1,
+        0xc795830d75038c1e,
+        0xf97ae3d0d2446f25,
+        0x9becce62836ac577,
+        0xc2e801fb244576d5,
+        0xf3a20279ed56d48a,
+        0x9845418c345644d7,
+        0xbe5691ef416bd60c,
+        0xedec366b11c6cb8f,
+        0x94b3a202eb1c3f39,
+        0xb9e08a83a5e34f08,
+        0xe858ad248f5c22ca,
+        0x91376c36d99995be,
+        0xb58547448ffffb2e,
+        0xe2e69915b3fff9f9,
+        0x8dd01fad907ffc3c,
+        0xb1442798f49ffb4b,
+        0xdd95317f31c7fa1d,
+        0x8a7d3eef7f1cfc52,
+        0xad1c8eab5ee43b67,
+        0xd863b256369d4a41,
+        0x873e4f75e2224e68,
+        0xa90de3535aaae202,
+        0xd3515c2831559a83,
+        0x8412d9991ed58092,
+        0xa5178fff668ae0b6,
+        0xce5d73ff402d98e4,
+        0x80fa687f881c7f8e,
+        0xa139029f6a239f72,
+        0xc987434744ac874f,
+        0xfbe9141915d7a922,
+        0x9d71ac8fada6c9b5,
+        0xc4ce17b399107c23,
+        0xf6019da07f549b2b,
+        0x99c102844f94e0fb,
+        0xc0314325637a193a,
+        0xf03d93eebc589f88,
+        0x96267c7535b763b5,
+        0xbbb01b9283253ca3,
+        0xea9c227723ee8bcb,
+        0x92a1958a7675175f,
+        0xb749faed14125d37,
+        0xe51c79a85916f485,
+        0x8f31cc0937ae58d3,
+        0xb2fe3f0b8599ef08,
+        0xdfbdcece67006ac9,
+        0x8bd6a141006042be,
+        0xaecc49914078536d,
+        0xda7f5bf590966849,
+        0x888f99797a5e012d,
+        0xaab37fd7d8f58179,
+        0xd5605fcdcf32e1d7,
+        0x855c3be0a17fcd26,
+        0xa6b34ad8c9dfc070,
+        0xd0601d8efc57b08c,
+        0x823c12795db6ce57,
+        0xa2cb1717b52481ed,
+        0xcb7ddcdda26da269,
+        0xfe5d54150b090b03,
+        0x9efa548d26e5a6e2,
+        0xc6b8e9b0709f109a,
+        0xf867241c8cc6d4c1,
+        0x9b407691d7fc44f8,
+        0xc21094364dfb5637,
+        0xf294b943e17a2bc4,
+        0x979cf3ca6cec5b5b,
+        0xbd8430bd08277231,
+        0xece53cec4a314ebe,
+        0x940f4613ae5ed137,
+        0xb913179899f68584,
+        0xe757dd7ec07426e5,
+        0x9096ea6f3848984f,
+        0xb4bca50b065abe63,
+        0xe1ebce4dc7f16dfc,
+        0x8d3360f09cf6e4bd,
+        0xb080392cc4349ded,
+        0xdca04777f541c568,
+        0x89e42caaf9491b61,
+        0xac5d37d5b79b6239,
+        0xd77485cb25823ac7,
+        0x86a8d39ef77164bd,
+        0xa8530886b54dbdec,
+        0xd267caa862a12d67,
+        0x8380dea93da4bc60,
+        0xa46116538d0deb78,
+        0xcd795be870516656,
+        0x806bd9714632dff6,
+        0xa086cfcd97bf97f4,
+        0xc8a883c0fdaf7df0,
+        0xfad2a4b13d1b5d6c,
+        0x9cc3a6eec6311a64,
+        0xc3f490aa77bd60fd,
+        0xf4f1b4d515acb93c,
+        0x991711052d8bf3c5,
+        0xbf5cd54678eef0b7,
+        0xef340a98172aace5,
+        0x9580869f0e7aac0f,
+        0xbae0a846d2195713,
+        0xe998d258869facd7,
+        0x91ff83775423cc06,
+        0xb67f6455292cbf08,
+        0xe41f3d6a7377eeca,
+        0x8e938662882af53e,
+        0xb23867fb2a35b28e,
+        0xdec681f9f4c31f31,
+        0x8b3c113c38f9f37f,
+        0xae0b158b4738705f,
+        0xd98ddaee19068c76,
+        0x87f8a8d4cfa417ca,
+        0xa9f6d30a038d1dbc,
+        0xd47487cc8470652b,
+        0x84c8d4dfd2c63f3b,
+        0xa5fb0a17c777cf0a,
+        0xcf79cc9db955c2cc,
+        0x81ac1fe293d599c0,
+        0xa21727db38cb0030,
+        0xca9cf1d206fdc03c,
+        0xfd442e4688bd304b,
+        0x9e4a9cec15763e2f,
+        0xc5dd44271ad3cdba,
+        0xf7549530e188c129,
+        0x9a94dd3e8cf578ba,
+        0xc13a148e3032d6e8,
+        0xf18899b1bc3f8ca2,
+        0x96f5600f15a7b7e5,
+        0xbcb2b812db11a5de,
+        0xebdf661791d60f56,
+        0x936b9fcebb25c996,
+        0xb84687c269ef3bfb,
+        0xe65829b3046b0afa,
+        0x8ff71a0fe2c2e6dc,
+        0xb3f4e093db73a093,
+        0xe0f218b8d25088b8,
+        0x8c974f7383725573,
+        0xafbd2350644eead0,
+        0xdbac6c247d62a584,
+        0x894bc396ce5da772,
+        0xab9eb47c81f5114f,
+        0xd686619ba27255a3,
+        0x8613fd0145877586,
+        0xa798fc4196e952e7,
+        0xd17f3b51fca3a7a1,
+        0x82ef85133de648c5,
+        0xa3ab66580d5fdaf6,
+        0xcc963fee10b7d1b3,
+        0xffbbcfe994e5c620,
+        0x9fd561f1fd0f9bd4,
+        0xc7caba6e7c5382c9,
+        0xf9bd690a1b68637b,
+        0x9c1661a651213e2d,
+        0xc31bfa0fe5698db8,
+        0xf3e2f893dec3f126,
+        0x986ddb5c6b3a76b8,
+        0xbe89523386091466,
+        0xee2ba6c0678b597f,
+        0x94db483840b717f0,
+        0xba121a4650e4ddec,
+        0xe896a0d7e51e1566,
+        0x915e2486ef32cd60,
+        0xb5b5ada8aaff80b8,
+        0xe3231912d5bf60e6,
+        0x8df5efabc5979c90,
+        0xb1736b96b6fd83b4,
+        0xddd0467c64bce4a1,
+        0x8aa22c0dbef60ee4,
+        0xad4ab7112eb3929e,
+        0xd89d64d57a607745,
+        0x87625f056c7c4a8b,
+        0xa93af6c6c79b5d2e,
+        0xd389b47879823479,
+        0x843610cb4bf160cc,
+        0xa54394fe1eedb8ff,
+        0xce947a3da6a9273e,
+        0x811ccc668829b887,
+        0xa163ff802a3426a9,
+        0xc9bcff6034c13053,
+        0xfc2c3f3841f17c68,
+        0x9d9ba7832936edc1,
+        0xc5029163f384a931,
+        0xf64335bcf065d37d,
+        0x99ea0196163fa42e,
+        0xc06481fb9bcf8d3a,
+        0xf07da27a82c37088,
+        0x964e858c91ba2655,
+        0xbbe226efb628afeb,
+        0xeadab0aba3b2dbe5,
+        0x92c8ae6b464fc96f,
+        0xb77ada0617e3bbcb,
+        0xe55990879ddcaabe,
+        0x8f57fa54c2a9eab7,
+        0xb32df8e9f3546564,
+        0xdff9772470297ebd,
+        0x8bfbea76c619ef36,
+        0xaefae51477a06b04,
+        0xdab99e59958885c5,
+        0x88b402f7fd75539b,
+        0xaae103b5fcd2a882,
+        0xd59944a37c0752a2,
+        0x857fcae62d8493a5,
+        0xa6dfbd9fb8e5b88f,
+        0xd097ad07a71f26b2,
+        0x825ecc24c8737830,
+        0xa2f67f2dfa90563b,
+        0xcbb41ef979346bca,
+        0xfea126b7d78186bd,
+        0x9f24b832e6b0f436,
+        0xc6ede63fa05d3144,
+        0xf8a95fcf88747d94,
+        0x9b69dbe1b548ce7d,
+        0xc24452da229b021c,
+        0xf2d56790ab41c2a3,
+        0x97c560ba6b0919a6,
+        0xbdb6b8e905cb600f,
+        0xed246723473e3813,
+        0x9436c0760c86e30c,
+        0xb94470938fa89bcf,
+        0xe7958cb87392c2c3,
+        0x90bd77f3483bb9ba,
+        0xb4ecd5f01a4aa828,
+        0xe2280b6c20dd5232,
+        0x8d590723948a535f,
+        0xb0af48ec79ace837,
+        0xdcdb1b2798182245,
+        0x8a08f0f8bf0f156b,
+        0xac8b2d36eed2dac6,
+        0xd7adf884aa879177,
+        0x86ccbb52ea94baeb,
+        0xa87fea27a539e9a5,
+        0xd29fe4b18e88640f,
+        0x83a3eeeef9153e89,
+        0xa48ceaaab75a8e2b,
+        0xcdb02555653131b6,
+        0x808e17555f3ebf12,
+        0xa0b19d2ab70e6ed6,
+        0xc8de047564d20a8c,
+        0xfb158592be068d2f,
+        0x9ced737bb6c4183d,
+        0xc428d05aa4751e4d,
+        0xf53304714d9265e0,
+        0x993fe2c6d07b7fac,
+        0xbf8fdb78849a5f97,
+        0xef73d256a5c0f77d,
+        0x95a8637627989aae,
+        0xbb127c53b17ec159,
+        0xe9d71b689dde71b0,
+        0x9226712162ab070e,
+        0xb6b00d69bb55c8d1,
+        0xe45c10c42a2b3b06,
+        0x8eb98a7a9a5b04e3,
+        0xb267ed1940f1c61c,
+        0xdf01e85f912e37a3,
+        0x8b61313bbabce2c6,
+        0xae397d8aa96c1b78,
+        0xd9c7dced53c72256,
+        0x881cea14545c7575,
+        0xaa242499697392d3,
+        0xd4ad2dbfc3d07788,
+        0x84ec3c97da624ab5,
+        0xa6274bbdd0fadd62,
+        0xcfb11ead453994ba,
+        0x81ceb32c4b43fcf5,
+        0xa2425ff75e14fc32,
+        0xcad2f7f5359a3b3e,
+        0xfd87b5f28300ca0e,
+        0x9e74d1b791e07e48,
+        0xc612062576589ddb,
+        0xf79687aed3eec551,
+        0x9abe14cd44753b53,
+        0xc16d9a0095928a27,
+        0xf1c90080baf72cb1,
+        0x971da05074da7bef,
+        0xbce5086492111aeb,
+        0xec1e4a7db69561a5,
+        0x9392ee8e921d5d07,
+        0xb877aa3236a4b449,
+        0xe69594bec44de15b,
+        0x901d7cf73ab0acd9,
+        0xb424dc35095cd80f,
+        0xe12e13424bb40e13,
+        0x8cbccc096f5088cc,
+        0xafebff0bcb24aaff,
+        0xdbe6fecebdedd5bf,
+        0x89705f4136b4a597,
+        0xabcc77118461cefd,
+        0xd6bf94d5e57a42bc,
+        0x8637bd05af6c69b6,
+        0xa7c5ac471b478423,
+        0xd1b71758e219652c,
+        0x83126e978d4fdf3b,
+        0xa3d70a3d70a3d70a,
+        0xcccccccccccccccd,
+        0x8000000000000000,
+        0xa000000000000000,
+        0xc800000000000000,
+        0xfa00000000000000,
+        0x9c40000000000000,
+        0xc350000000000000,
+        0xf424000000000000,
+        0x9896800000000000,
+        0xbebc200000000000,
+        0xee6b280000000000,
+        0x9502f90000000000,
+        0xba43b74000000000,
+        0xe8d4a51000000000,
+        0x9184e72a00000000,
+        0xb5e620f480000000,
+        0xe35fa931a0000000,
+        0x8e1bc9bf04000000,
+        0xb1a2bc2ec5000000,
+        0xde0b6b3a76400000,
+        0x8ac7230489e80000,
+        0xad78ebc5ac620000,
+        0xd8d726b7177a8000,
+        0x878678326eac9000,
+        0xa968163f0a57b400,
+        0xd3c21bcecceda100,
+        0x84595161401484a0,
+        0xa56fa5b99019a5c8,
+        0xcecb8f27f4200f3a,
+        0x813f3978f8940984,
+        0xa18f07d736b90be5,
+        0xc9f2c9cd04674edf,
+        0xfc6f7c4045812296,
+        0x9dc5ada82b70b59e,
+        0xc5371912364ce305,
+        0xf684df56c3e01bc7,
+        0x9a130b963a6c115c,
+        0xc097ce7bc90715b3,
+        0xf0bdc21abb48db20,
+        0x96769950b50d88f4,
+        0xbc143fa4e250eb31,
+        0xeb194f8e1ae525fd,
+        0x92efd1b8d0cf37be,
+        0xb7abc627050305ae,
+        0xe596b7b0c643c719,
+        0x8f7e32ce7bea5c70,
+        0xb35dbf821ae4f38c,
+        0xe0352f62a19e306f,
+        0x8c213d9da502de45,
+        0xaf298d050e4395d7,
+        0xdaf3f04651d47b4c,
+        0x88d8762bf324cd10,
+        0xab0e93b6efee0054,
+        0xd5d238a4abe98068,
+        0x85a36366eb71f041,
+        0xa70c3c40a64e6c52,
+        0xd0cf4b50cfe20766,
+        0x82818f1281ed44a0,
+        0xa321f2d7226895c8,
+        0xcbea6f8ceb02bb3a,
+        0xfee50b7025c36a08,
+        0x9f4f2726179a2245,
+        0xc722f0ef9d80aad6,
+        0xf8ebad2b84e0d58c,
+        0x9b934c3b330c8577,
+        0xc2781f49ffcfa6d5,
+        0xf316271c7fc3908b,
+        0x97edd871cfda3a57,
+        0xbde94e8e43d0c8ec,
+        0xed63a231d4c4fb27,
+        0x945e455f24fb1cf9,
+        0xb975d6b6ee39e437,
+        0xe7d34c64a9c85d44,
+        0x90e40fbeea1d3a4b,
+        0xb51d13aea4a488dd,
+        0xe264589a4dcdab15,
+        0x8d7eb76070a08aed,
+        0xb0de65388cc8ada8,
+        0xdd15fe86affad912,
+        0x8a2dbf142dfcc7ab,
+        0xacb92ed9397bf996,
+        0xd7e77a8f87daf7fc,
+        0x86f0ac99b4e8dafd,
+        0xa8acd7c0222311bd,
+        0xd2d80db02aabd62c,
+        0x83c7088e1aab65db,
+        0xa4b8cab1a1563f52,
+        0xcde6fd5e09abcf27,
+        0x80b05e5ac60b6178,
+        0xa0dc75f1778e39d6,
+        0xc913936dd571c84c,
+        0xfb5878494ace3a5f,
+        0x9d174b2dcec0e47b,
+        0xc45d1df942711d9a,
+        0xf5746577930d6501,
+        0x9968bf6abbe85f20,
+        0xbfc2ef456ae276e9,
+        0xefb3ab16c59b14a3,
+        0x95d04aee3b80ece6,
+        0xbb445da9ca61281f,
+        0xea1575143cf97227,
+        0x924d692ca61be758,
+        0xb6e0c377cfa2e12e,
+        0xe498f455c38b997a,
+        0x8edf98b59a373fec,
+        0xb2977ee300c50fe7,
+        0xdf3d5e9bc0f653e1,
+        0x8b865b215899f46d,
+        0xae67f1e9aec07188,
+        0xda01ee641a708dea,
+        0x884134fe908658b2,
+        0xaa51823e34a7eedf,
+        0xd4e5e2cdc1d1ea96,
+        0x850fadc09923329e,
+        0xa6539930bf6bff46,
+        0xcfe87f7cef46ff17,
+        0x81f14fae158c5f6e,
+        0xa26da3999aef774a,
+        0xcb090c8001ab551c,
+        0xfdcb4fa002162a63,
+        0x9e9f11c4014dda7e,
+        0xc646d63501a1511e,
+        0xf7d88bc24209a565,
+        0x9ae757596946075f,
+        0xc1a12d2fc3978937,
+        0xf209787bb47d6b85,
+        0x9745eb4d50ce6333,
+        0xbd176620a501fc00,
+        0xec5d3fa8ce427b00,
+        0x93ba47c980e98ce0,
+        0xb8a8d9bbe123f018,
+        0xe6d3102ad96cec1e,
+        0x9043ea1ac7e41393,
+        0xb454e4a179dd1877,
+        0xe16a1dc9d8545e95,
+        0x8ce2529e2734bb1d,
+        0xb01ae745b101e9e4,
+        0xdc21a1171d42645d,
+        0x899504ae72497eba,
+        0xabfa45da0edbde69,
+        0xd6f8d7509292d603,
+        0x865b86925b9bc5c2,
+        0xa7f26836f282b733,
+        0xd1ef0244af2364ff,
+        0x8335616aed761f1f,
+        0xa402b9c5a8d3a6e7,
+        0xcd036837130890a1,
+        0x802221226be55a65,
+        0xa02aa96b06deb0fe,
+        0xc83553c5c8965d3d,
+        0xfa42a8b73abbf48d,
+        0x9c69a97284b578d8,
+        0xc38413cf25e2d70e,
+        0xf46518c2ef5b8cd1,
+        0x98bf2f79d5993803,
+        0xbeeefb584aff8604,
+        0xeeaaba2e5dbf6785,
+        0x952ab45cfa97a0b3,
+        0xba756174393d88e0,
+        0xe912b9d1478ceb17,
+        0x91abb422ccb812ef,
+        0xb616a12b7fe617aa,
+        0xe39c49765fdf9d95,
+        0x8e41ade9fbebc27d,
+        0xb1d219647ae6b31c,
+        0xde469fbd99a05fe3,
+        0x8aec23d680043bee,
+        0xada72ccc20054aea,
+        0xd910f7ff28069da4,
+        0x87aa9aff79042287,
+        0xa99541bf57452b28,
+        0xd3fa922f2d1675f2,
+        0x847c9b5d7c2e09b7,
+        0xa59bc234db398c25,
+        0xcf02b2c21207ef2f,
+        0x8161afb94b44f57d,
+        0xa1ba1ba79e1632dc,
+        0xca28a291859bbf93,
+        0xfcb2cb35e702af78,
+        0x9defbf01b061adab,
+        0xc56baec21c7a1916,
+        0xf6c69a72a3989f5c,
+        0x9a3c2087a63f6399,
+        0xc0cb28a98fcf3c80,
+        0xf0fdf2d3f3c30b9f,
+        0x969eb7c47859e744,
+        0xbc4665b596706115,
+        0xeb57ff22fc0c795a,
+        0x9316ff75dd87cbd8,
+        0xb7dcbf5354e9bece,
+        0xe5d3ef282a242e82,
+        0x8fa475791a569d11,
+        0xb38d92d760ec4455,
+        0xe070f78d3927556b,
+        0x8c469ab843b89563,
+        0xaf58416654a6babb,
+        0xdb2e51bfe9d0696a,
+        0x88fcf317f22241e2,
+        0xab3c2fddeeaad25b,
+        0xd60b3bd56a5586f2,
+        0x85c7056562757457,
+        0xa738c6bebb12d16d,
+        0xd106f86e69d785c8,
+        0x82a45b450226b39d,
+        0xa34d721642b06084,
+        0xcc20ce9bd35c78a5,
+        0xff290242c83396ce,
+        0x9f79a169bd203e41,
+        0xc75809c42c684dd1,
+        0xf92e0c3537826146,
+        0x9bbcc7a142b17ccc,
+        0xc2abf989935ddbfe,
+        0xf356f7ebf83552fe,
+        0x98165af37b2153df,
+        0xbe1bf1b059e9a8d6,
+        0xeda2ee1c7064130c,
+        0x9485d4d1c63e8be8,
+        0xb9a74a0637ce2ee1,
+        0xe8111c87c5c1ba9a,
+        0x910ab1d4db9914a0,
+        0xb54d5e4a127f59c8,
+        0xe2a0b5dc971f303a,
+        0x8da471a9de737e24,
+        0xb10d8e1456105dad,
+        0xdd50f1996b947519,
+        0x8a5296ffe33cc930,
+        0xace73cbfdc0bfb7b,
+        0xd8210befd30efa5a,
+        0x8714a775e3e95c78,
+        0xa8d9d1535ce3b396,
+        0xd31045a8341ca07c,
+        0x83ea2b892091e44e,
+        0xa4e4b66b68b65d61,
+        0xce1de40642e3f4b9,
+        0x80d2ae83e9ce78f4,
+        0xa1075a24e4421731,
+        0xc94930ae1d529cfd,
+        0xfb9b7cd9a4a7443c,
+        0x9d412e0806e88aa6,
+        0xc491798a08a2ad4f,
+        0xf5b5d7ec8acb58a3,
+        0x9991a6f3d6bf1766,
+        0xbff610b0cc6edd3f,
+        0xeff394dcff8a948f,
+        0x95f83d0a1fb69cd9,
+        0xbb764c4ca7a44410,
+        0xea53df5fd18d5514,
+        0x92746b9be2f8552c,
+        0xb7118682dbb66a77,
+        0xe4d5e82392a40515,
+        0x8f05b1163ba6832d,
+        0xb2c71d5bca9023f8,
+        0xdf78e4b2bd342cf7,
+        0x8bab8eefb6409c1a,
+        0xae9672aba3d0c321,
+        0xda3c0f568cc4f3e9,
+        0x8865899617fb1871,
+        0xaa7eebfb9df9de8e,
+        0xd51ea6fa85785631,
+        0x8533285c936b35df,
+        0xa67ff273b8460357,
+        0xd01fef10a657842c,
+        0x8213f56a67f6b29c,
+        0xa298f2c501f45f43,
+        0xcb3f2f7642717713,
+        0xfe0efb53d30dd4d8,
+        0x9ec95d1463e8a507,
+        0xc67bb4597ce2ce49,
+        0xf81aa16fdc1b81db,
+        0x9b10a4e5e9913129,
+        0xc1d4ce1f63f57d73,
+        0xf24a01a73cf2dcd0,
+        0x976e41088617ca02,
+        0xbd49d14aa79dbc82,
+        0xec9c459d51852ba3,
+        0x93e1ab8252f33b46,
+        0xb8da1662e7b00a17,
+        0xe7109bfba19c0c9d,
+        0x906a617d450187e2,
+        0xb484f9dc9641e9db,
+        0xe1a63853bbd26451,
+        0x8d07e33455637eb3,
+        0xb049dc016abc5e60,
+        0xdc5c5301c56b75f7,
+        0x89b9b3e11b6329bb,
+        0xac2820d9623bf429,
+        0xd732290fbacaf134,
+        0x867f59a9d4bed6c0,
+        0xa81f301449ee8c70,
+        0xd226fc195c6a2f8c,
+        0x83585d8fd9c25db8,
+        0xa42e74f3d032f526,
+        0xcd3a1230c43fb26f,
+        0x80444b5e7aa7cf85,
+        0xa0555e361951c367,
+        0xc86ab5c39fa63441,
+        0xfa856334878fc151,
+        0x9c935e00d4b9d8d2,
+        0xc3b8358109e84f07,
+        0xf4a642e14c6262c9,
+        0x98e7e9cccfbd7dbe,
+        0xbf21e44003acdd2d,
+        0xeeea5d5004981478,
+        0x95527a5202df0ccb,
+        0xbaa718e68396cffe,
+        0xe950df20247c83fd,
+        0x91d28b7416cdd27e,
+    ],
+    [
+        -1077,
+        -1073,
+        -1070,
+        -1067,
+        -1063,
+        -1060,
+        -1057,
+        -1053,
+        -1050,
+        -1047,
+        -1043,
+        -1040,
+        -1037,
+        -1034,
+        -1030,
+        -1027,
+        -1024,
+        -1020,
+        -1017,
+        -1014,
+        -1010,
+        -1007,
+        -1004,
+        -1000,
+        -997,
+        -994,
+        -990,
+        -987,
+        -984,
+        -980,
+        -977,
+        -974,
+        -970,
+        -967,
+        -964,
+        -960,
+        -957,
+        -954,
+        -950,
+        -947,
+        -944,
+        -940,
+        -937,
+        -934,
+        -931,
+        -927,
+        -924,
+        -921,
+        -917,
+        -914,
+        -911,
+        -907,
+        -904,
+        -901,
+        -897,
+        -894,
+        -891,
+        -887,
+        -884,
+        -881,
+        -877,
+        -874,
+        -871,
+        -867,
+        -864,
+        -861,
+        -857,
+        -854,
+        -851,
+        -847,
+        -844,
+        -841,
+        -838,
+        -834,
+        -831,
+        -828,
+        -824,
+        -821,
+        -818,
+        -814,
+        -811,
+        -808,
+        -804,
+        -801,
+        -798,
+        -794,
+        -791,
+        -788,
+        -784,
+        -781,
+        -778,
+        -774,
+        -771,
+        -768,
+        -764,
+        -761,
+        -758,
+        -754,
+        -751,
+        -748,
+        -744,
+        -741,
+        -738,
+        -735,
+        -731,
+        -728,
+        -725,
+        -721,
+        -718,
+        -715,
+        -711,
+        -708,
+        -705,
+        -701,
+        -698,
+        -695,
+        -691,
+        -688,
+        -685,
+        -681,
+        -678,
+        -675,
+        -671,
+        -668,
+        -665,
+        -661,
+        -658,
+        -655,
+        -651,
+        -648,
+        -645,
+        -642,
+        -638,
+        -635,
+        -632,
+        -628,
+        -625,
+        -622,
+        -618,
+        -615,
+        -612,
+        -608,
+        -605,
+        -602,
+        -598,
+        -595,
+        -592,
+        -588,
+        -585,
+        -582,
+        -578,
+        -575,
+        -572,
+        -568,
+        -565,
+        -562,
+        -558,
+        -555,
+        -552,
+        -549,
+        -545,
+        -542,
+        -539,
+        -535,
+        -532,
+        -529,
+        -525,
+        -522,
+        -519,
+        -515,
+        -512,
+        -509,
+        -505,
+        -502,
+        -499,
+        -495,
+        -492,
+        -489,
+        -485,
+        -482,
+        -479,
+        -475,
+        -472,
+        -469,
+        -465,
+        -462,
+        -459,
+        -455,
+        -452,
+        -449,
+        -446,
+        -442,
+        -439,
+        -436,
+        -432,
+        -429,
+        -426,
+        -422,
+        -419,
+        -416,
+        -412,
+        -409,
+        -406,
+        -402,
+        -399,
+        -396,
+        -392,
+        -389,
+        -386,
+        -382,
+        -379,
+        -376,
+        -372,
+        -369,
+        -366,
+        -362,
+        -359,
+        -356,
+        -353,
+        -349,
+        -346,
+        -343,
+        -339,
+        -336,
+        -333,
+        -329,
+        -326,
+        -323,
+        -319,
+        -316,
+        -313,
+        -309,
+        -306,
+        -303,
+        -299,
+        -296,
+        -293,
+        -289,
+        -286,
+        -283,
+        -279,
+        -276,
+        -273,
+        -269,
+        -266,
+        -263,
+        -259,
+        -256,
+        -253,
+        -250,
+        -246,
+        -243,
+        -240,
+        -236,
+        -233,
+        -230,
+        -226,
+        -223,
+        -220,
+        -216,
+        -213,
+        -210,
+        -206,
+        -203,
+        -200,
+        -196,
+        -193,
+        -190,
+        -186,
+        -183,
+        -180,
+        -176,
+        -173,
+        -170,
+        -166,
+        -163,
+        -160,
+        -157,
+        -153,
+        -150,
+        -147,
+        -143,
+        -140,
+        -137,
+        -133,
+        -130,
+        -127,
+        -123,
+        -120,
+        -117,
+        -113,
+        -110,
+        -107,
+        -103,
+        -100,
+        -97,
+        -93,
+        -90,
+        -87,
+        -83,
+        -80,
+        -77,
+        -73,
+        -70,
+        -67,
+        -63,
+        -60,
+        -57,
+        -54,
+        -50,
+        -47,
+        -44,
+        -40,
+        -37,
+        -34,
+        -30,
+        -27,
+        -24,
+        -20,
+        -17,
+        -14,
+        -10,
+        -7,
+        -4,
+        0,
+        3,
+        6,
+        10,
+        13,
+        16,
+        20,
+        23,
+        26,
+        30,
+        33,
+        36,
+        39,
+        43,
+        46,
+        49,
+        53,
+        56,
+        59,
+        63,
+        66,
+        69,
+        73,
+        76,
+        79,
+        83,
+        86,
+        89,
+        93,
+        96,
+        99,
+        103,
+        106,
+        109,
+        113,
+        116,
+        119,
+        123,
+        126,
+        129,
+        132,
+        136,
+        139,
+        142,
+        146,
+        149,
+        152,
+        156,
+        159,
+        162,
+        166,
+        169,
+        172,
+        176,
+        179,
+        182,
+        186,
+        189,
+        192,
+        196,
+        199,
+        202,
+        206,
+        209,
+        212,
+        216,
+        219,
+        222,
+        226,
+        229,
+        232,
+        235,
+        239,
+        242,
+        245,
+        249,
+        252,
+        255,
+        259,
+        262,
+        265,
+        269,
+        272,
+        275,
+        279,
+        282,
+        285,
+        289,
+        292,
+        295,
+        299,
+        302,
+        305,
+        309,
+        312,
+        315,
+        319,
+        322,
+        325,
+        328,
+        332,
+        335,
+        338,
+        342,
+        345,
+        348,
+        352,
+        355,
+        358,
+        362,
+        365,
+        368,
+        372,
+        375,
+        378,
+        382,
+        385,
+        388,
+        392,
+        395,
+        398,
+        402,
+        405,
+        408,
+        412,
+        415,
+        418,
+        422,
+        425,
+        428,
+        431,
+        435,
+        438,
+        441,
+        445,
+        448,
+        451,
+        455,
+        458,
+        461,
+        465,
+        468,
+        471,
+        475,
+        478,
+        481,
+        485,
+        488,
+        491,
+        495,
+        498,
+        501,
+        505,
+        508,
+        511,
+        515,
+        518,
+        521,
+        524,
+        528,
+        531,
+        534,
+        538,
+        541,
+        544,
+        548,
+        551,
+        554,
+        558,
+        561,
+        564,
+        568,
+        571,
+        574,
+        578,
+        581,
+        584,
+        588,
+        591,
+        594,
+        598,
+        601,
+        604,
+        608,
+        611,
+        614,
+        617,
+        621,
+        624,
+        627,
+        631,
+        634,
+        637,
+        641,
+        644,
+        647,
+        651,
+        654,
+        657,
+        661,
+        664,
+        667,
+        671,
+        674,
+        677,
+        681,
+        684,
+        687,
+        691,
+        694,
+        697,
+        701,
+        704,
+        707,
+        711,
+        714,
+        717,
+        720,
+        724,
+        727,
+        730,
+        734,
+        737,
+        740,
+        744,
+        747,
+        750,
+        754,
+        757,
+        760,
+        764,
+        767,
+        770,
+        774,
+        777,
+        780,
+        784,
+        787,
+        790,
+        794,
+        797,
+        800,
+        804,
+        807,
+        810,
+        813,
+        817,
+        820,
+        823,
+        827,
+        830,
+        833,
+        837,
+        840,
+        843,
+        847,
+        850,
+        853,
+        857,
+        860,
+        863,
+        867,
+        870,
+        873,
+        877,
+        880,
+        883,
+        887,
+        890,
+        893,
+        897,
+        900,
+        903,
+        907,
+        910,
+        913,
+        916,
+        920,
+        923,
+        926,
+        930,
+        933,
+        936,
+        940,
+        943,
+        946,
+        950,
+    ],
+);
 
+#[rustfmt::skip]
 pub const F32_SHORT_POWERS: [f32; 11] = [
     1e0,
     1e1,
@@ -1244,6 +1249,7 @@ pub const F32_SHORT_POWERS: [f32; 11] = [
     1e10,
 ];
 
+#[rustfmt::skip]
 pub const F64_SHORT_POWERS: [f64; 23] = [
     1e0,
     1e1,
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 820c1edf930..251d49db062 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -802,6 +802,43 @@ impl AtomicBool {
     pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
         unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 }
     }
+
+    /// Returns a mutable pointer to the underlying [`bool`].
+    ///
+    /// Doing non-atomic reads and writes on the resulting integer can be a data race.
+    /// This method is mostly useful for FFI, where the function signature may use
+    /// `*mut bool` instead of `&AtomicBool`.
+    ///
+    /// Returning an `*mut` pointer from a shared reference to this atomic is safe because the
+    /// atomic types work with interior mutability. All modifications of an atomic change the value
+    /// through a shared reference, and can do so safely as long as they use atomic operations. Any
+    /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
+    /// restriction: operations on it must be atomic.
+    ///
+    /// [`bool`]: ../../../std/primitive.bool.html
+    ///
+    /// # Examples
+    ///
+    /// ```ignore (extern-declaration)
+    /// # fn main() {
+    /// use std::sync::atomic::AtomicBool;
+    /// extern {
+    ///     fn my_atomic_op(arg: *mut bool);
+    /// }
+    ///
+    /// let mut atomic = AtomicBool::new(true);
+    /// unsafe {
+    ///     my_atomic_op(atomic.as_mut_ptr());
+    /// }
+    /// # }
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_mut_ptr",
+           reason = "recently added",
+           issue = "66893")]
+    pub fn as_mut_ptr(&self) -> *mut bool {
+        self.v.get() as *mut bool
+    }
 }
 
 #[cfg(target_has_atomic_load_store = "ptr")]
@@ -1891,6 +1928,43 @@ assert_eq!(min_foo, 12);
                 }
             }
 
+            doc_comment! {
+                concat!("Returns a mutable pointer to the underlying integer.
+
+Doing non-atomic reads and writes on the resulting integer can be a data race.
+This method is mostly useful for FFI, where the function signature may use
+`*mut ", stringify!($int_type), "` instead of `&", stringify!($atomic_type), "`.
+
+Returning an `*mut` pointer from a shared reference to this atomic is safe because the
+atomic types work with interior mutability. All modifications of an atomic change the value
+through a shared reference, and can do so safely as long as they use atomic operations. Any
+use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
+restriction: operations on it must be atomic.
+
+# Examples
+
+```ignore (extern-declaration)
+# fn main() {
+", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";
+
+extern {
+    fn my_atomic_op(arg: *mut ", stringify!($int_type), ");
+}
+
+let mut atomic = ", stringify!($atomic_type), "::new(1);
+unsafe {
+    my_atomic_op(atomic.as_mut_ptr());
+}
+# }
+```"),
+                #[inline]
+                #[unstable(feature = "atomic_mut_ptr",
+                       reason = "recently added",
+                       issue = "66893")]
+                pub fn as_mut_ptr(&self) -> *mut $int_type {
+                    self.v.get()
+                }
+            }
         }
     }
 }
diff --git a/src/libcore/tests/num/bignum.rs b/src/libcore/tests/num/bignum.rs
index b9e15ec5c07..50a3ec046ad 100644
--- a/src/libcore/tests/num/bignum.rs
+++ b/src/libcore/tests/num/bignum.rs
@@ -1,4 +1,3 @@
-use std::prelude::v1::*;
 use core::num::bignum::tests::Big8x3 as Big;
 
 #[test]
diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs
index a35897e9bc1..f85369ce40b 100644
--- a/src/libcore/tests/num/flt2dec/mod.rs
+++ b/src/libcore/tests/num/flt2dec/mod.rs
@@ -1,4 +1,3 @@
-use std::prelude::v1::*;
 use std::{str, i16, f32, f64, fmt};
 
 use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded};
diff --git a/src/libcore/tests/num/flt2dec/strategy/dragon.rs b/src/libcore/tests/num/flt2dec/strategy/dragon.rs
index dc4d78bfae1..0c545b4d887 100644
--- a/src/libcore/tests/num/flt2dec/strategy/dragon.rs
+++ b/src/libcore/tests/num/flt2dec/strategy/dragon.rs
@@ -1,4 +1,3 @@
-use std::prelude::v1::*;
 use super::super::*;
 use core::num::bignum::Big32x40 as Big;
 use core::num::flt2dec::strategy::dragon::*;
diff --git a/src/libcore/unicode/printable.py b/src/libcore/unicode/printable.py
index 4e8b4ecad02..91db6381c9b 100644..100755
--- a/src/libcore/unicode/printable.py
+++ b/src/libcore/unicode/printable.py
@@ -111,16 +111,19 @@ def compress_normal(normal):
     return compressed
 
 def print_singletons(uppers, lowers, uppersname, lowersname):
+    print("#[rustfmt::skip]")
     print("const {}: &[(u8, u8)] = &[".format(uppersname))
     for u, c in uppers:
         print("    ({:#04x}, {}),".format(u, c))
     print("];")
+    print("#[rustfmt::skip]")
     print("const {}: &[u8] = &[".format(lowersname))
     for i in range(0, len(lowers), 8):
         print("    {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8])))
     print("];")
 
 def print_normal(normal, normalname):
+    print("#[rustfmt::skip]")
     print("const {}: &[u8] = &[".format(normalname))
     for v in normal:
         print("    {}".format(" ".join("{:#04x},".format(i) for i in v)))
@@ -170,8 +173,7 @@ def main():
 // NOTE: The following code was generated by "src/libcore/unicode/printable.py",
 //       do not edit directly!
 
-fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8],
-         normal: &[u8]) -> bool {
+fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], normal: &[u8]) -> bool {
     let xupper = (x >> 8) as u8;
     let mut lowerstart = 0;
     for &(upper, lowercount) in singletonuppers {
diff --git a/src/libcore/unicode/printable.rs b/src/libcore/unicode/printable.rs
index d411dda7dc1..eee9ea52ef0 100644
--- a/src/libcore/unicode/printable.rs
+++ b/src/libcore/unicode/printable.rs
@@ -1,8 +1,7 @@
 // NOTE: The following code was generated by "src/libcore/unicode/printable.py",
 //       do not edit directly!
 
-fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8],
-         normal: &[u8]) -> bool {
+fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], normal: &[u8]) -> bool {
     let xupper = (x >> 8) as u8;
     let mut lowerstart = 0;
     for &(upper, lowercount) in singletonuppers {
@@ -70,6 +69,7 @@ pub(crate) fn is_printable(x: char) -> bool {
     }
 }
 
+#[rustfmt::skip]
 const SINGLETONS0U: &[(u8, u8)] = &[
     (0x00, 1),
     (0x03, 5),
@@ -113,6 +113,7 @@ const SINGLETONS0U: &[(u8, u8)] = &[
     (0xfe, 3),
     (0xff, 9),
 ];
+#[rustfmt::skip]
 const SINGLETONS0L: &[u8] = &[
     0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57,
     0x58, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, 0xdd, 0x0e,
@@ -152,6 +153,7 @@ const SINGLETONS0L: &[u8] = &[
     0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1,
     0xd8, 0xd9, 0xe7, 0xfe, 0xff,
 ];
+#[rustfmt::skip]
 const SINGLETONS1U: &[(u8, u8)] = &[
     (0x00, 6),
     (0x01, 1),
@@ -189,6 +191,7 @@ const SINGLETONS1U: &[(u8, u8)] = &[
     (0xf9, 6),
     (0xfa, 2),
 ];
+#[rustfmt::skip]
 const SINGLETONS1L: &[u8] = &[
     0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e,
     0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e,
@@ -212,6 +215,7 @@ const SINGLETONS1L: &[u8] = &[
     0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, 0x0c, 0x72,
     0xa3, 0xa4, 0xcb, 0xcc, 0x6e, 0x6f,
 ];
+#[rustfmt::skip]
 const NORMAL0: &[u8] = &[
     0x00, 0x20,
     0x5f, 0x22,
@@ -355,6 +359,7 @@ const NORMAL0: &[u8] = &[
     0x1b, 0x03,
     0x0f, 0x0d,
 ];
+#[rustfmt::skip]
 const NORMAL1: &[u8] = &[
     0x5e, 0x22,
     0x7b, 0x05,
diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs
index 5b5be485431..3fa125e8fea 100644
--- a/src/libcore/unicode/tables.rs
+++ b/src/libcore/unicode/tables.rs
@@ -2,19 +2,16 @@
 
 #![allow(missing_docs, non_upper_case_globals, non_snake_case, clippy::unreadable_literal)]
 
-use crate::unicode::version::UnicodeVersion;
 use crate::unicode::bool_trie::{BoolTrie, SmallBoolTrie};
+use crate::unicode::version::UnicodeVersion;
 
 /// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of
 /// `char` and `str` methods are based on.
 #[unstable(feature = "unicode_version", issue = "49726")]
-pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion {
-    major: 12,
-    minor: 1,
-    micro: 0,
-    _priv: (),
-};
+pub const UNICODE_VERSION: UnicodeVersion =
+    UnicodeVersion { major: 12, minor: 1, micro: 0, _priv: () };
 pub(crate) mod general_category {
+    #[rustfmt::skip]
     const Cc_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
         r1: &[
             0, 1, 0
@@ -28,6 +25,7 @@ pub(crate) mod general_category {
         Cc_table.lookup(c)
     }
 
+    #[rustfmt::skip]
     const N_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x03ff000000000000, 0x0000000000000000, 0x720c000000000000, 0x0000000000000000,
@@ -138,10 +136,10 @@ pub(crate) mod general_category {
     pub fn N(c: char) -> bool {
         N_table.lookup(c)
     }
-
 }
 
 pub(crate) mod derived_property {
+    #[rustfmt::skip]
     const Alphabetic_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff,
@@ -327,6 +325,7 @@ pub(crate) mod derived_property {
         Alphabetic_table.lookup(c)
     }
 
+    #[rustfmt::skip]
     const Case_Ignorable_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0400408000000000, 0x0000000140000000, 0x0190a10000000000, 0x0000000000000000,
@@ -464,6 +463,7 @@ pub(crate) mod derived_property {
         Case_Ignorable_table.lookup(c)
     }
 
+    #[rustfmt::skip]
     const Cased_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff,
@@ -565,6 +565,7 @@ pub(crate) mod derived_property {
         Cased_table.lookup(c)
     }
 
+    #[rustfmt::skip]
     const Grapheme_Extend_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
@@ -689,6 +690,7 @@ pub(crate) mod derived_property {
         Grapheme_Extend_table.lookup(c)
     }
 
+    #[rustfmt::skip]
     const Lowercase_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x07fffffe00000000, 0x0420040000000000, 0xff7fffff80000000,
@@ -789,6 +791,7 @@ pub(crate) mod derived_property {
         Lowercase_table.lookup(c)
     }
 
+    #[rustfmt::skip]
     const Uppercase_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x0000000007fffffe, 0x0000000000000000, 0x000000007f7fffff,
@@ -889,10 +892,10 @@ pub(crate) mod derived_property {
     pub fn Uppercase(c: char) -> bool {
         Uppercase_table.lookup(c)
     }
-
 }
 
 pub(crate) mod property {
+    #[rustfmt::skip]
     const White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
         r1: &[
             0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -912,20 +915,19 @@ pub(crate) mod property {
     pub fn White_Space(c: char) -> bool {
         White_Space_table.lookup(c)
     }
-
 }
 
 pub(crate) mod conversions {
     pub fn to_lower(c: char) -> [char; 3] {
         match bsearch_case_table(c, to_lowercase_table) {
-            None        => [c, '\0', '\0'],
+            None => [c, '\0', '\0'],
             Some(index) => to_lowercase_table[index].1,
         }
     }
 
     pub fn to_upper(c: char) -> [char; 3] {
         match bsearch_case_table(c, to_uppercase_table) {
-            None        => [c, '\0', '\0'],
+            None => [c, '\0', '\0'],
             Some(index) => to_uppercase_table[index].1,
         }
     }
@@ -934,6 +936,7 @@ pub(crate) mod conversions {
         table.binary_search_by(|&(key, _)| key.cmp(&c)).ok()
     }
 
+    #[rustfmt::skip]
     const to_lowercase_table: &[(char, [char; 3])] = &[
         ('\u{41}', ['\u{61}', '\0', '\0']), ('\u{42}', ['\u{62}', '\0', '\0']), ('\u{43}',
         ['\u{63}', '\0', '\0']), ('\u{44}', ['\u{64}', '\0', '\0']), ('\u{45}', ['\u{65}', '\0',
@@ -1558,6 +1561,7 @@ pub(crate) mod conversions {
         ('\u{1e920}', ['\u{1e942}', '\0', '\0']), ('\u{1e921}', ['\u{1e943}', '\0', '\0'])
     ];
 
+    #[rustfmt::skip]
     const to_uppercase_table: &[(char, [char; 3])] = &[
         ('\u{61}', ['\u{41}', '\0', '\0']), ('\u{62}', ['\u{42}', '\0', '\0']), ('\u{63}',
         ['\u{43}', '\0', '\0']), ('\u{64}', ['\u{44}', '\0', '\0']), ('\u{65}', ['\u{45}', '\0',
@@ -2228,5 +2232,4 @@ pub(crate) mod conversions {
         ('\u{1e940}', ['\u{1e91e}', '\0', '\0']), ('\u{1e941}', ['\u{1e91f}', '\0', '\0']),
         ('\u{1e942}', ['\u{1e920}', '\0', '\0']), ('\u{1e943}', ['\u{1e921}', '\0', '\0'])
     ];
-
 }
diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py
index 89894f7932d..97df92a56da 100755
--- a/src/libcore/unicode/unicode.py
+++ b/src/libcore/unicode/unicode.py
@@ -81,8 +81,8 @@ PREAMBLE = """\
 
 #![allow(missing_docs, non_upper_case_globals, non_snake_case, clippy::unreadable_literal)]
 
-use crate::unicode::version::UnicodeVersion;
 use crate::unicode::bool_trie::{{BoolTrie, SmallBoolTrie}};
+use crate::unicode::version::UnicodeVersion;
 """.format(year=datetime.datetime.now().year)
 
 # Mapping taken from Table 12 from:
@@ -555,6 +555,8 @@ def generate_table(
     if is_pub:
         pub_string = "pub "
 
+    yield "\n"
+    yield "    #[rustfmt::skip]\n"
     yield "    %sconst %s: %s = &[\n" % (pub_string, name, decl_type)
 
     data = []
@@ -568,7 +570,7 @@ def generate_table(
     for table_line in generate_table_lines("".join(data).split(","), 8):
         yield table_line
 
-    yield "\n    ];\n\n"
+    yield "\n    ];\n"
 
 
 def compute_trie(raw_data, chunk_size):
@@ -634,6 +636,9 @@ def generate_bool_trie(name, codepoint_ranges, is_pub=False):
     pub_string = ""
     if is_pub:
         pub_string = "pub "
+
+    yield "\n"
+    yield "    #[rustfmt::skip]\n"
     yield "    %sconst %s: &super::BoolTrie = &super::BoolTrie {\n" % (pub_string, name)
     yield "        r1: [\n"
     data = ("0x%016x" % chunk for chunk in chunks[:0x800 // chunk_size])
@@ -678,7 +683,7 @@ def generate_bool_trie(name, codepoint_ranges, is_pub=False):
         yield fragment
     yield "\n        ],\n"
 
-    yield "    };\n\n"
+    yield "    };\n"
 
 
 def generate_small_bool_trie(name, codepoint_ranges, is_pub=False):
@@ -700,6 +705,8 @@ def generate_small_bool_trie(name, codepoint_ranges, is_pub=False):
     if is_pub:
         pub_string = "pub "
 
+    yield "\n"
+    yield "    #[rustfmt::skip]\n"
     yield ("    %sconst %s: &super::SmallBoolTrie = &super::SmallBoolTrie {\n"
            % (pub_string, name))
 
@@ -717,7 +724,7 @@ def generate_small_bool_trie(name, codepoint_ranges, is_pub=False):
         yield fragment
     yield "\n        ],\n"
 
-    yield "    };\n\n"
+    yield "    };\n"
 
 
 def generate_property_module(mod, grouped_categories, category_subset):
@@ -726,7 +733,7 @@ def generate_property_module(mod, grouped_categories, category_subset):
     Generate Rust code for module defining properties.
     """
 
-    yield "pub(crate) mod %s {\n" % mod
+    yield "pub(crate) mod %s {" % mod
     for cat in sorted(category_subset):
         if cat in ("Cc", "White_Space"):
             generator = generate_small_bool_trie("%s_table" % cat, grouped_categories[cat])
@@ -736,9 +743,10 @@ def generate_property_module(mod, grouped_categories, category_subset):
         for fragment in generator:
             yield fragment
 
+        yield "\n"
         yield "    pub fn %s(c: char) -> bool {\n" % cat
         yield "        %s_table.lookup(c)\n" % cat
-        yield "    }\n\n"
+        yield "    }\n"
 
     yield "}\n\n"
 
@@ -753,21 +761,21 @@ def generate_conversions_module(unicode_data):
     yield """
     pub fn to_lower(c: char) -> [char; 3] {
         match bsearch_case_table(c, to_lowercase_table) {
-            None        => [c, '\\0', '\\0'],
+            None => [c, '\\0', '\\0'],
             Some(index) => to_lowercase_table[index].1,
         }
     }
 
     pub fn to_upper(c: char) -> [char; 3] {
         match bsearch_case_table(c, to_uppercase_table) {
-            None        => [c, '\\0', '\\0'],
+            None => [c, '\\0', '\\0'],
             Some(index) => to_uppercase_table[index].1,
         }
     }
 
     fn bsearch_case_table(c: char, table: &[(char, [char; 3])]) -> Option<usize> {
         table.binary_search_by(|&(key, _)| key.cmp(&c)).ok()
-    }\n\n"""
+    }\n"""
 
     decl_type = "&[(char, [char; 3])]"
     format_conversion = lambda x: "({},[{},{},{}])".format(*(
@@ -827,13 +835,9 @@ def main():
     /// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of
     /// `char` and `str` methods are based on.
     #[unstable(feature = "unicode_version", issue = "49726")]
-    pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion {{
-        major: {version.major},
-        minor: {version.minor},
-        micro: {version.micro},
-        _priv: (),
-    }};
-    """).format(version=unicode_version)
+    pub const UNICODE_VERSION: UnicodeVersion =
+        UnicodeVersion {{ major: {v.major}, minor: {v.minor}, micro: {v.micro}, _priv: () }};
+    """).format(v=unicode_version)
     buf.write(unicode_version_notice)
 
     get_path = lambda f: get_unicode_file_path(unicode_version, f)
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index 6c1695a4eac..fb30d6c519c 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -22,6 +22,7 @@ rustc-rayon = "0.3.0"
 rustc-rayon-core = "0.3.0"
 polonius-engine  = "0.10.0"
 rustc_apfloat = { path = "../librustc_apfloat" }
+rustc_feature = { path = "../librustc_feature" }
 rustc_target = { path = "../librustc_target" }
 rustc_macros = { path = "../librustc_macros" }
 rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs
index 193b04eabb3..1d6a3420ed9 100644
--- a/src/librustc/arena.rs
+++ b/src/librustc/arena.rs
@@ -101,7 +101,7 @@ macro_rules! arena_types {
             [few] resolve_lifetimes: rustc::middle::resolve_lifetime::ResolveLifetimes,
             [few] lint_levels: rustc::lint::LintLevelMap,
             [few] stability_index: rustc::middle::stability::Index<'tcx>,
-            [few] features: syntax::feature_gate::Features,
+            [few] features: rustc_feature::Features,
             [few] all_traits: Vec<rustc::hir::def_id::DefId>,
             [few] privacy_access_levels: rustc::middle::privacy::AccessLevels,
             [few] target_features_whitelist: rustc_data_structures::fx::FxHashMap<
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index 144980c53eb..6499e56325a 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -4,7 +4,6 @@
 use crate::ich::StableHashingContext;
 
 use syntax::ast;
-use syntax::feature_gate;
 use syntax_pos::SourceFile;
 
 use crate::hir::def_id::{DefId, CrateNum, CRATE_DEF_INDEX};
@@ -156,7 +155,7 @@ fn stable_normalized_pos(np: ::syntax_pos::NormalizedPos,
 }
 
 
-impl<'tcx> HashStable<StableHashingContext<'tcx>> for feature_gate::Features {
+impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
         // Unfortunately we cannot exhaustively list fields here, since the
         // struct is macro generated.
diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs
index 27bf9649324..619ca724214 100644
--- a/src/librustc/lint/levels.rs
+++ b/src/librustc/lint/levels.rs
@@ -232,13 +232,13 @@ impl<'a> LintLevelsBuilder<'a> {
                             // don't have any lint names (`#[level(reason = "foo")]`)
                             if let ast::LitKind::Str(rationale, _) = name_value.kind {
                                 if !self.sess.features_untracked().lint_reasons {
-                                    feature_gate::emit_feature_err(
+                                    feature_gate::feature_err(
                                         &self.sess.parse_sess,
                                         sym::lint_reasons,
                                         item.span,
-                                        feature_gate::GateIssue::Language,
                                         "lint reasons are experimental"
-                                    );
+                                    )
+                                    .emit();
                                 }
                                 reason = Some(rationale);
                             } else {
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 411a47423c5..54aafe2114d 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -13,11 +13,12 @@ use crate::ty::query::Providers;
 use crate::middle::privacy::AccessLevels;
 use crate::session::{DiagnosticMessageId, Session};
 use errors::DiagnosticBuilder;
+use rustc_feature::GateIssue;
 use syntax::symbol::{Symbol, sym};
 use syntax_pos::{Span, MultiSpan};
 use syntax::ast::{Attribute, CRATE_NODE_ID};
 use syntax::errors::Applicability;
-use syntax::feature_gate::{GateIssue, emit_feature_err};
+use syntax::feature_gate::{feature_err, feature_err_issue};
 use syntax::attr::{self, Stability, Deprecation, RustcDeprecation};
 use crate::ty::{self, TyCtxt};
 use crate::util::nodemap::{FxHashSet, FxHashMap};
@@ -512,9 +513,8 @@ pub fn report_unstable(
         if is_soft {
             soft_handler(lint::builtin::SOFT_UNSTABLE, span, &msg)
         } else {
-            emit_feature_err(
-                &sess.parse_sess, feature, span, GateIssue::Library(issue), &msg
-            );
+            feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg)
+                .emit();
         }
     }
 }
@@ -842,15 +842,19 @@ impl Visitor<'tcx> for Checker<'tcx> {
                 let ty = self.tcx.type_of(def_id);
 
                 if adt_def.has_dtor(self.tcx) {
-                    emit_feature_err(&self.tcx.sess.parse_sess,
-                                     sym::untagged_unions, item.span, GateIssue::Language,
-                                     "unions with `Drop` implementations are unstable");
+                    feature_err(
+                        &self.tcx.sess.parse_sess, sym::untagged_unions, item.span,
+                        "unions with `Drop` implementations are unstable"
+                    )
+                    .emit();
                 } else {
                     let param_env = self.tcx.param_env(def_id);
                     if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
-                        emit_feature_err(&self.tcx.sess.parse_sess,
-                                         sym::untagged_unions, item.span, GateIssue::Language,
-                                         "unions with non-`Copy` fields are unstable");
+                        feature_err(
+                            &self.tcx.sess.parse_sess, sym::untagged_unions, item.span,
+                            "unions with non-`Copy` fields are unstable"
+                        )
+                        .emit();
                     }
                 }
             }
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index cd93fed8e1e..d715ddb1b81 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -1130,7 +1130,7 @@ rustc_queries! {
             desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) }
         }
 
-        query features_query(_: CrateNum) -> &'tcx feature_gate::Features {
+        query features_query(_: CrateNum) -> &'tcx rustc_feature::Features {
             eval_always
             desc { "looking up enabled feature gates" }
         }
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 6733250e1e8..fbfae721bbe 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -7,6 +7,7 @@ use crate::session::{early_error, early_warn, Session};
 use crate::session::search_paths::SearchPath;
 
 use rustc_data_structures::fx::FxHashSet;
+use rustc_feature::UnstableFeatures;
 
 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
 use rustc_target::spec::{Target, TargetTriple};
@@ -16,7 +17,6 @@ use syntax::ast;
 use syntax::source_map::{FileName, FilePathMapping};
 use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
 use syntax::symbol::{sym, Symbol};
-use syntax::feature_gate::UnstableFeatures;
 
 use errors::emitter::HumanReadableErrorType;
 use errors::{ColorConfig, FatalError, Handler};
@@ -2701,7 +2701,7 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
 
 pub mod nightly_options {
     use getopts;
-    use syntax::feature_gate::UnstableFeatures;
+    use rustc_feature::UnstableFeatures;
     use super::{ErrorOutputType, OptionStability, RustcOptGroup};
     use crate::session::early_error;
 
@@ -2850,9 +2850,9 @@ mod dep_tracking {
     use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
                 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
                 SymbolManglingVersion};
+    use rustc_feature::UnstableFeatures;
     use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
     use syntax::edition::Edition;
-    use syntax::feature_gate::UnstableFeatures;
 
     pub trait DepTrackingHash {
         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 0b9d04ca6a3..87c7e5a82a3 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -21,7 +21,6 @@ use errors::emitter::{Emitter, EmitterWriter};
 use errors::emitter::HumanReadableErrorType;
 use errors::annotate_snippet_emitter_writer::{AnnotateSnippetEmitterWriter};
 use syntax::edition::Edition;
-use syntax::feature_gate;
 use errors::json::JsonEmitter;
 use syntax::source_map;
 use syntax::sess::ParseSess;
@@ -86,7 +85,7 @@ pub struct Session {
     /// `rustc_codegen_llvm::back::symbol_names` module for more information.
     pub crate_disambiguator: Once<CrateDisambiguator>,
 
-    features: Once<feature_gate::Features>,
+    features: Once<rustc_feature::Features>,
 
     /// The maximum recursion limit for potentially infinitely recursive
     /// operations such as auto-dereference and monomorphization.
@@ -470,11 +469,11 @@ impl Session {
     /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents
     /// dependency tracking. Use tcx.features() instead.
     #[inline]
-    pub fn features_untracked(&self) -> &feature_gate::Features {
+    pub fn features_untracked(&self) -> &rustc_feature::Features {
         self.features.get()
     }
 
-    pub fn init_features(&self, features: feature_gate::Features) {
+    pub fn init_features(&self, features: rustc_feature::Features) {
         self.features.set(features);
     }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 0b6937975aa..776ae7dc141 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -72,7 +72,6 @@ use rustc_macros::HashStable;
 use syntax::ast;
 use syntax::attr;
 use syntax::source_map::MultiSpan;
-use syntax::feature_gate;
 use syntax::symbol::{Symbol, kw, sym};
 use syntax_pos::Span;
 use syntax::expand::allocator::AllocatorKind;
@@ -1312,7 +1311,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self.cstore.allocator_kind()
     }
 
-    pub fn features(self) -> &'tcx feature_gate::Features {
+    pub fn features(self) -> &'tcx rustc_feature::Features {
         self.features_query(LOCAL_CRATE)
     }
 
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index a1eb1c43335..5b4a6ac8a2d 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -56,7 +56,6 @@ use std::any::type_name;
 use syntax_pos::{Span, DUMMY_SP};
 use syntax::attr;
 use syntax::ast;
-use syntax::feature_gate;
 use syntax::symbol::Symbol;
 
 #[macro_use]
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index b72468a6ff9..aa5b1c7315a 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -2330,22 +2330,43 @@ impl<'tcx> Const<'tcx> {
         tcx: TyCtxt<'tcx>,
         param_env: ParamEnv<'tcx>,
     ) -> &Const<'tcx> {
-        // FIXME(const_generics): this doesn't work right now,
-        // because it tries to relate an `Infer` to a `Param`.
+        let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs| {
+            let param_env_and_substs = param_env.with_reveal_all().and(substs);
+
+            // Avoid querying `tcx.const_eval(...)` with any e.g. inference vars.
+            if param_env_and_substs.has_local_value() {
+                return None;
+            }
+
+            let (param_env, substs) = param_env_and_substs.into_parts();
+
+            // try to resolve e.g. associated constants to their definition on an impl
+            let instance = ty::Instance::resolve(tcx, param_env, did, substs)?;
+            let gid = GlobalId {
+                instance,
+                promoted: None,
+            };
+            tcx.const_eval(param_env.and(gid)).ok()
+        };
+
         match self.val {
             ConstKind::Unevaluated(did, substs) => {
-                // if `substs` has no unresolved components, use and empty param_env
-                let (param_env, substs) = param_env.with_reveal_all().and(substs).into_parts();
-                // try to resolve e.g. associated constants to their definition on an impl
-                let instance = match ty::Instance::resolve(tcx, param_env, did, substs) {
-                    Some(instance) => instance,
-                    None => return self,
-                };
-                let gid = GlobalId {
-                    instance,
-                    promoted: None,
-                };
-                tcx.const_eval(param_env.and(gid)).unwrap_or(self)
+                // HACK(eddyb) when substs contain e.g. inference variables,
+                // attempt using identity substs instead, that will succeed
+                // when the expression doesn't depend on any parameters.
+                // FIXME(eddyb) make `const_eval` a canonical query instead,
+                // that would properly handle inference variables in `substs`.
+                if substs.has_local_value() {
+                    let identity_substs = InternalSubsts::identity_for_item(tcx, did);
+                    // The `ParamEnv` needs to match the `identity_substs`.
+                    let identity_param_env = tcx.param_env(did);
+                    match try_const_eval(did, identity_param_env, identity_substs) {
+                        Some(ct) => ct.subst(tcx, substs),
+                        None => self,
+                    }
+                } else {
+                    try_const_eval(did, param_env, substs).unwrap_or(self)
+                }
             },
             _ => self,
         }
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index b3be3d09f17..d0b065ccc84 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -541,7 +541,7 @@ pub(crate) fn run_pass_manager(cgcx: &CodegenContext<LlvmCodegenBackend>,
     debug!("running the pass manager");
     unsafe {
         let pm = llvm::LLVMCreatePassManager();
-        llvm::LLVMRustAddAnalysisPasses(module.module_llvm.tm, pm, module.module_llvm.llmod());
+        llvm::LLVMAddAnalysisPasses(module.module_llvm.tm, pm);
 
         if config.verify_llvm_ir {
             let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr().cast());
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index 6cc7b0b4b1e..5dfb04a4436 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -384,8 +384,8 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
             // we'll get errors in LLVM.
             let using_thin_buffers = config.bitcode_needed();
             if !config.no_prepopulate_passes {
-                llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
-                llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
+                llvm::LLVMAddAnalysisPasses(tm, fpm);
+                llvm::LLVMAddAnalysisPasses(tm, mpm);
                 let opt_level = to_llvm_opt_settings(opt_level).0;
                 let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal ||
                     (cgcx.lto != Lto::Fat && cgcx.opts.cg.linker_plugin_lto.enabled());
@@ -509,7 +509,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
             where F: FnOnce(&'ll mut PassManager<'ll>) -> R,
         {
             let cpm = llvm::LLVMCreatePassManager();
-            llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
+            llvm::LLVMAddAnalysisPasses(tm, cpm);
             llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
             f(cpm)
         }
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index e7562c399b2..acc221f0657 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -30,6 +30,7 @@ extern crate libc;
 #[macro_use] extern crate rustc;
 extern crate rustc_target;
 #[macro_use] extern crate rustc_data_structures;
+extern crate rustc_feature;
 extern crate rustc_index;
 extern crate rustc_incremental;
 extern crate rustc_codegen_utils;
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 241ca695e5f..a49e863fa21 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -1341,6 +1341,8 @@ extern "C" {
 
     pub fn LLVMInitializePasses();
 
+    pub fn LLVMAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>);
+
     pub fn LLVMPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;
     pub fn LLVMPassManagerBuilderDispose(PMB: &'static mut PassManagerBuilder);
     pub fn LLVMPassManagerBuilderSetSizeLevel(PMB: &PassManagerBuilder, Value: Bool);
@@ -1703,7 +1705,6 @@ extern "C" {
                                        EmitStackSizeSection: bool)
                                        -> Option<&'static mut TargetMachine>;
     pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
-    pub fn LLVMRustAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>, M: &'a Module);
     pub fn LLVMRustAddBuilderLibraryInfo(PMB: &'a PassManagerBuilder,
                                          M: &'a Module,
                                          DisableSimplifyLibCalls: bool);
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index 290ca409261..7bff9e69dd5 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -6,7 +6,7 @@ use rustc::session::config::PrintRequest;
 use rustc_target::spec::{MergeFunctions, PanicStrategy};
 use libc::c_int;
 use std::ffi::CString;
-use syntax::feature_gate::UnstableFeatures;
+use rustc_feature::UnstableFeatures;
 use syntax::symbol::sym;
 
 use std::str;
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index 2b7e4d35248..d1cb4cbeb9b 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -19,6 +19,7 @@ rustc_target = { path = "../librustc_target" }
 rustc_lint = { path = "../librustc_lint" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
+rustc_feature = { path = "../librustc_feature" }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_mir = { path = "../librustc_mir" }
 rustc_parse = { path = "../librustc_parse" }
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index c945de8f1e1..8b04d3d46d0 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -44,7 +44,7 @@ use errors::{PResult, registry::Registry};
 use rustc_interface::interface;
 use rustc_interface::util::get_codegen_sysroot;
 use rustc_data_structures::sync::SeqCst;
-
+use rustc_feature::{find_gated_cfg, UnstableFeatures};
 use rustc_serialize::json::ToJson;
 
 use std::borrow::Cow;
@@ -61,10 +61,9 @@ use std::str;
 use std::time::Instant;
 
 use syntax::ast;
-use syntax::source_map::FileLoader;
-use syntax::feature_gate::{GatedCfg, UnstableFeatures};
-use syntax::symbol::sym;
-use syntax_pos::{DUMMY_SP, FileName};
+use syntax_pos::source_map::FileLoader;
+use syntax_pos::symbol::sym;
+use syntax_pos::FileName;
 
 pub mod pretty;
 mod args;
@@ -684,12 +683,6 @@ impl RustcDefaultCalls {
                         .is_nightly_build();
 
                     let mut cfgs = sess.parse_sess.config.iter().filter_map(|&(name, ref value)| {
-                        let gated_cfg = GatedCfg::gate(&ast::MetaItem {
-                            path: ast::Path::from_ident(ast::Ident::with_dummy_span(name)),
-                            kind: ast::MetaItemKind::Word,
-                            span: DUMMY_SP,
-                        });
-
                         // Note that crt-static is a specially recognized cfg
                         // directive that's printed out here as part of
                         // rust-lang/rust#37406, but in general the
@@ -700,10 +693,11 @@ impl RustcDefaultCalls {
                         // through to build scripts.
                         let value = value.as_ref().map(|s| s.as_str());
                         let value = value.as_ref().map(|s| s.as_ref());
-                        if name != sym::target_feature || value != Some("crt-static") {
-                            if !allow_unstable_cfg && gated_cfg.is_some() {
-                                return None
-                            }
+                        if (name != sym::target_feature || value != Some("crt-static"))
+                            && !allow_unstable_cfg
+                            && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
+                        {
+                            return None;
                         }
 
                         if let Some(value) = value {
diff --git a/src/librustc_feature/Cargo.toml b/src/librustc_feature/Cargo.toml
new file mode 100644
index 00000000000..40ce922947b
--- /dev/null
+++ b/src/librustc_feature/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_feature"
+version = "0.0.0"
+edition = "2018"
+
+[lib]
+name = "rustc_feature"
+path = "lib.rs"
+doctest = false
+
+[dependencies]
+rustc_data_structures = { path = "../librustc_data_structures" }
+lazy_static = "1.0.0"
+syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/librustc_feature/accepted.rs
index dab83f48a03..fec5a7f1a45 100644
--- a/src/libsyntax/feature_gate/accepted.rs
+++ b/src/librustc_feature/accepted.rs
@@ -1,7 +1,7 @@
 //! List of the accepted feature gates.
 
-use crate::symbol::sym;
 use super::{State, Feature};
+use syntax_pos::symbol::sym;
 
 macro_rules! declare_features {
     ($(
diff --git a/src/libsyntax/feature_gate/active.rs b/src/librustc_feature/active.rs
index b04b30aa6bc..7c0d39965fc 100644
--- a/src/libsyntax/feature_gate/active.rs
+++ b/src/librustc_feature/active.rs
@@ -2,10 +2,9 @@
 
 use super::{State, Feature};
 
-use crate::edition::Edition;
-use crate::symbol::{Symbol, sym};
-
+use syntax_pos::edition::Edition;
 use syntax_pos::Span;
+use syntax_pos::symbol::{Symbol, sym};
 
 macro_rules! set {
     ($field: ident) => {{
@@ -37,7 +36,7 @@ macro_rules! declare_features {
             ),+];
 
         /// A set of features to be used by later passes.
-        #[derive(Clone)]
+        #[derive(Clone, Default)]
         pub struct Features {
             /// `#![feature]` attrs for language features, for error reporting.
             pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
@@ -50,17 +49,7 @@ macro_rules! declare_features {
         }
 
         impl Features {
-            pub fn new() -> Features {
-                Features {
-                    declared_lang_features: Vec::new(),
-                    declared_lib_features: Vec::new(),
-                    $($feature: false),+
-                }
-            }
-
-            pub fn walk_feature_fields<F>(&self, mut f: F)
-                where F: FnMut(&str, bool)
-            {
+            pub fn walk_feature_fields(&self, mut f: impl FnMut(&str, bool)) {
                 $(f(stringify!($feature), self.$feature);)+
             }
         }
diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs
index a9f41633f30..f72df00a8e8 100644
--- a/src/libsyntax/feature_gate/builtin_attrs.rs
+++ b/src/librustc_feature/builtin_attrs.rs
@@ -3,17 +3,10 @@
 use AttributeType::*;
 use AttributeGate::*;
 
-use super::check::{emit_feature_err, GateIssue};
-use super::check::{Stability, EXPLAIN_ALLOW_INTERNAL_UNSAFE, EXPLAIN_ALLOW_INTERNAL_UNSTABLE};
-use super::active::Features;
+use crate::{Features, Stability};
 
-use crate::ast;
-use crate::attr::AttributeTemplate;
-use crate::sess::ParseSess;
-use crate::symbol::{Symbol, sym};
-
-use syntax_pos::Span;
 use rustc_data_structures::fx::FxHashMap;
+use syntax_pos::symbol::{Symbol, sym};
 use lazy_static::lazy_static;
 
 type GateFn = fn(&Features) -> bool;
@@ -24,39 +17,19 @@ macro_rules! cfg_fn {
     }
 }
 
+pub type GatedCfg = (Symbol, Symbol, GateFn);
+
 /// `cfg(...)`'s that are feature gated.
-const GATED_CFGS: &[(Symbol, Symbol, GateFn)] = &[
+const GATED_CFGS: &[GatedCfg] = &[
     // (name in cfg, feature, function to check if the feature is enabled)
     (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)),
     (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
     (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
 ];
 
-#[derive(Debug)]
-pub struct GatedCfg {
-    span: Span,
-    index: usize,
-}
-
-impl GatedCfg {
-    pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
-        GATED_CFGS.iter()
-                  .position(|info| cfg.check_name(info.0))
-                  .map(|idx| {
-                      GatedCfg {
-                          span: cfg.span,
-                          index: idx
-                      }
-                  })
-    }
-
-    pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
-        let (cfg, feature, has_feature) = GATED_CFGS[self.index];
-        if !has_feature(features) && !self.span.allows_unstable(feature) {
-            let explain = format!("`cfg({})` is experimental and subject to change", cfg);
-            emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
-        }
-    }
+/// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
+pub fn find_gated_cfg(pred: impl Fn(Symbol) -> bool) -> Option<&'static GatedCfg> {
+    GATED_CFGS.iter().find(|(cfg_sym, ..)| pred(*cfg_sym))
 }
 
 // If you change this, please modify `src/doc/unstable-book` as well. You must
@@ -108,6 +81,21 @@ impl AttributeGate {
     }
 }
 
+/// A template that the attribute input must match.
+/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
+#[derive(Clone, Copy)]
+pub struct AttributeTemplate {
+    pub word: bool,
+    pub list: Option<&'static str>,
+    pub name_value_str: Option<&'static str>,
+}
+
+impl AttributeTemplate {
+    pub fn only_word() -> Self {
+        Self { word: true, list: None, name_value_str: None }
+    }
+}
+
 /// A convenience macro for constructing attribute templates.
 /// E.g., `template!(Word, List: "description")` means that the attribute
 /// supports forms `#[attr]` and `#[attr(description)]`.
@@ -361,9 +349,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     gated!(
         allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
-        EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
+        "allow_internal_unstable side-steps feature gating and stability checks",
+    ),
+    gated!(
+        allow_internal_unsafe, Normal, template!(Word),
+        "allow_internal_unsafe side-steps the unsafe_code lint",
     ),
-    gated!(allow_internal_unsafe, Normal, template!(Word), EXPLAIN_ALLOW_INTERNAL_UNSAFE),
 
     // ==========================================================================
     // Internal attributes: Type system related:
@@ -587,14 +578,10 @@ pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> {
     BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect()
 }
 
-pub fn is_builtin_attr_name(name: ast::Name) -> bool {
+pub fn is_builtin_attr_name(name: Symbol) -> bool {
     BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
 }
 
-pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
-    attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).is_some()
-}
-
 lazy_static! {
     pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap<Symbol, &'static BuiltinAttribute> = {
         let mut map = FxHashMap::default();
diff --git a/src/librustc_feature/lib.rs b/src/librustc_feature/lib.rs
new file mode 100644
index 00000000000..c38bb3740af
--- /dev/null
+++ b/src/librustc_feature/lib.rs
@@ -0,0 +1,137 @@
+//! # Feature gates
+//!
+//! This crate declares the set of past and present unstable features in the compiler.
+//! Feature gate checking itself is done in `libsyntax/feature_gate/check.rs` at the moment.
+//!
+//! Features are enabled in programs via the crate-level attributes of
+//! `#![feature(...)]` with a comma-separated list of features.
+//!
+//! For the purpose of future feature-tracking, once a feature gate is added,
+//! even if it is stabilized or removed, *do not remove it*. Instead, move the
+//! symbol to the `accepted` or `removed` modules respectively.
+
+mod accepted;
+mod removed;
+mod active;
+mod builtin_attrs;
+
+use std::fmt;
+use std::num::NonZeroU32;
+use syntax_pos::{Span, edition::Edition, symbol::Symbol};
+
+#[derive(Clone, Copy)]
+pub enum State {
+    Accepted,
+    Active { set: fn(&mut Features, Span) },
+    Removed { reason: Option<&'static str> },
+    Stabilized { reason: Option<&'static str> },
+}
+
+impl fmt::Debug for State {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            State::Accepted { .. } => write!(f, "accepted"),
+            State::Active { .. } => write!(f, "active"),
+            State::Removed { .. } => write!(f, "removed"),
+            State::Stabilized { .. } => write!(f, "stabilized"),
+        }
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct Feature {
+    pub state: State,
+    pub name: Symbol,
+    pub since: &'static str,
+    issue: Option<u32>,  // FIXME: once #58732 is done make this an Option<NonZeroU32>
+    pub edition: Option<Edition>,
+    description: &'static str,
+}
+
+impl Feature {
+    fn issue(&self) -> Option<NonZeroU32> {
+        self.issue.and_then(|i| NonZeroU32::new(i))
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum Stability {
+    Unstable,
+    // First argument is tracking issue link; second argument is an optional
+    // help message, which defaults to "remove this attribute".
+    Deprecated(&'static str, Option<&'static str>),
+}
+
+#[derive(Clone, Copy, Hash)]
+pub enum UnstableFeatures {
+    /// Hard errors for unstable features are active, as on beta/stable channels.
+    Disallow,
+    /// Allow features to be activated, as on nightly.
+    Allow,
+    /// Errors are bypassed for bootstrapping. This is required any time
+    /// during the build that feature-related lints are set to warn or above
+    /// because the build turns on warnings-as-errors and uses lots of unstable
+    /// features. As a result, this is always required for building Rust itself.
+    Cheat
+}
+
+impl UnstableFeatures {
+    pub fn from_environment() -> UnstableFeatures {
+        // `true` if this is a feature-staged build, i.e., on the beta or stable channel.
+        let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
+        // `true` if we should enable unstable features for bootstrapping.
+        let bootstrap = std::env::var("RUSTC_BOOTSTRAP").is_ok();
+        match (disable_unstable_features, bootstrap) {
+            (_, true) => UnstableFeatures::Cheat,
+            (true, _) => UnstableFeatures::Disallow,
+            (false, _) => UnstableFeatures::Allow
+        }
+    }
+
+    pub fn is_nightly_build(&self) -> bool {
+        match *self {
+            UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
+            UnstableFeatures::Disallow => false,
+        }
+    }
+}
+
+fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
+    if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
+        // FIXME (#28244): enforce that active features have issue numbers
+        // assert!(info.issue().is_some())
+        info.issue()
+    } else {
+        // search in Accepted, Removed, or Stable Removed features
+        let found = ACCEPTED_FEATURES
+            .iter()
+            .chain(REMOVED_FEATURES)
+            .chain(STABLE_REMOVED_FEATURES)
+            .find(|t| t.name == feature);
+        match found {
+            Some(found) => found.issue(),
+            None => panic!("feature `{}` is not declared anywhere", feature),
+        }
+    }
+}
+
+pub enum GateIssue {
+    Language,
+    Library(Option<NonZeroU32>)
+}
+
+pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZeroU32> {
+    match issue {
+        GateIssue::Language => find_lang_feature_issue(feature),
+        GateIssue::Library(lib) => lib,
+    }
+}
+
+pub use accepted::ACCEPTED_FEATURES;
+pub use active::{ACTIVE_FEATURES, Features, INCOMPLETE_FEATURES};
+pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
+pub use builtin_attrs::{
+    AttributeGate, AttributeTemplate, AttributeType, find_gated_cfg, GatedCfg,
+    BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
+    deprecated_attributes, is_builtin_attr_name,
+};
diff --git a/src/libsyntax/feature_gate/removed.rs b/src/librustc_feature/removed.rs
index f0aa74c65df..340bd32fb8a 100644
--- a/src/libsyntax/feature_gate/removed.rs
+++ b/src/librustc_feature/removed.rs
@@ -1,7 +1,7 @@
 //! List of the removed feature gates.
 
-use crate::symbol::sym;
 use super::{State, Feature};
+use syntax_pos::symbol::sym;
 
 macro_rules! declare_features {
     ($(
diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml
index d26d8791f66..ed38243581b 100644
--- a/src/librustc_lint/Cargo.toml
+++ b/src/librustc_lint/Cargo.toml
@@ -15,5 +15,6 @@ rustc_target = { path = "../librustc_target" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_feature = { path = "../librustc_feature" }
 rustc_index = { path = "../librustc_index" }
 rustc_error_codes = { path = "../librustc_error_codes" }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 38624034022..5d3a6cccc4e 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -34,15 +34,15 @@ use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext};
 
 use rustc::util::nodemap::FxHashSet;
+use rustc_feature::{AttributeGate, AttributeTemplate, AttributeType, deprecated_attributes};
+use rustc_feature::Stability;
 
 use syntax::tokenstream::{TokenTree, TokenStream};
 use syntax::ast::{self, Expr};
 use syntax::ptr::P;
-use syntax::attr::{self, HasAttrs, AttributeTemplate};
+use syntax::attr::{self, HasAttrs};
 use syntax::source_map::Spanned;
 use syntax::edition::Edition;
-use syntax::feature_gate::{self, AttributeGate, AttributeType};
-use syntax::feature_gate::{Stability, deprecated_attributes};
 use syntax_pos::{BytePos, Span};
 use syntax::symbol::{Symbol, kw, sym};
 use syntax::errors::{Applicability, DiagnosticBuilder};
@@ -1850,7 +1850,7 @@ impl EarlyLintPass for IncompleteFeatures {
         features.declared_lang_features
             .iter().map(|(name, span, _)| (name, span))
             .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
-            .filter(|(name, _)| feature_gate::INCOMPLETE_FEATURES.iter().any(|f| name == &f))
+            .filter(|(name, _)| rustc_feature::INCOMPLETE_FEATURES.iter().any(|f| name == &f))
             .for_each(|(name, &span)| {
                 cx.struct_span_lint(
                     INCOMPLETE_FEATURES,
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 9f293bdaa10..f7de7ec7e18 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -1,3 +1,4 @@
+use rustc::hir;
 use rustc::hir::def::{Res, DefKind};
 use rustc::hir::def_id::DefId;
 use rustc::lint;
@@ -7,19 +8,17 @@ use rustc::ty::adjustment;
 use rustc_data_structures::fx::FxHashMap;
 use lint::{LateContext, EarlyContext, LintContext, LintArray};
 use lint::{LintPass, EarlyLintPass, LateLintPass};
+use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 
 use syntax::ast;
 use syntax::attr;
 use syntax::errors::{Applicability, pluralize};
-use syntax::feature_gate::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use syntax::print::pprust;
 use syntax::symbol::{kw, sym};
 use syntax::symbol::Symbol;
 use syntax::util::parser;
 use syntax_pos::{Span, BytePos};
 
-use rustc::hir;
-
 use log::debug;
 
 declare_lint! {
diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs
index e577b238c86..425e5d1d821 100644
--- a/src/librustc_metadata/native_libs.rs
+++ b/src/librustc_metadata/native_libs.rs
@@ -7,7 +7,7 @@ use rustc::util::nodemap::FxHashSet;
 use rustc_target::spec::abi::Abi;
 use syntax::attr;
 use syntax::source_map::Span;
-use syntax::feature_gate::{self, GateIssue};
+use syntax::feature_gate::feature_err;
 use syntax::symbol::{kw, sym, Symbol};
 use syntax::{span_err, struct_span_err};
 
@@ -158,27 +158,29 @@ impl Collector<'tcx> {
             }
         }
         if lib.cfg.is_some() && !self.tcx.features().link_cfg {
-            feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
-                                           sym::link_cfg,
-                                           span.unwrap(),
-                                           GateIssue::Language,
-                                           "is unstable");
+            feature_err(&self.tcx.sess.parse_sess, sym::link_cfg, span.unwrap(), "is unstable")
+                .emit();
         }
         if lib.kind == cstore::NativeStaticNobundle &&
-           !self.tcx.features().static_nobundle {
-            feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
-                                           sym::static_nobundle,
-                                           span.unwrap_or_else(|| syntax_pos::DUMMY_SP),
-                                           GateIssue::Language,
-                                           "kind=\"static-nobundle\" is unstable");
+           !self.tcx.features().static_nobundle
+        {
+            feature_err(
+                &self.tcx.sess.parse_sess,
+                sym::static_nobundle,
+                span.unwrap_or_else(|| syntax_pos::DUMMY_SP),
+                "kind=\"static-nobundle\" is unstable"
+            )
+            .emit();
         }
         if lib.kind == cstore::NativeRawDylib &&
            !self.tcx.features().raw_dylib {
-            feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
-                                           sym::raw_dylib,
-                                           span.unwrap_or_else(|| syntax_pos::DUMMY_SP),
-                                           GateIssue::Language,
-                                           "kind=\"raw-dylib\" is unstable");
+            feature_err(
+                &self.tcx.sess.parse_sess,
+                sym::raw_dylib,
+                span.unwrap_or_else(|| syntax_pos::DUMMY_SP),
+                "kind=\"raw-dylib\" is unstable"
+            )
+            .emit();
         }
         self.libs.push(lib);
     }
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 07c5d640a32..c893d6f4856 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -84,10 +84,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
             }
 
+            PatKind::Or { .. } => {
+                self.hir.tcx().sess.span_fatal(
+                    match_pair.pattern.span,
+                    "or-patterns are not fully implemented yet"
+                )
+            }
+
             PatKind::AscribeUserType { .. } |
             PatKind::Array { .. } |
             PatKind::Wild |
-            PatKind::Or { .. } |
             PatKind::Binding { .. } |
             PatKind::Leaf { .. } |
             PatKind::Deref { .. } => {
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 5db567dae29..f2c5bf1bf6d 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -400,6 +400,25 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
         self.0.iter().map(|p| *p)
     }
 
+    // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
+    fn expand_or_pat(&self) -> Option<Vec<Self>> {
+        if self.is_empty() {
+            None
+        } else if let PatKind::Or { pats } = &*self.head().kind {
+            Some(
+                pats.iter()
+                    .map(|pat| {
+                        let mut new_patstack = PatStack::from_pattern(pat);
+                        new_patstack.0.extend_from_slice(&self.0[1..]);
+                        new_patstack
+                    })
+                    .collect(),
+            )
+        } else {
+            None
+        }
+    }
+
     /// This computes `D(self)`. See top of the file for explanations.
     fn specialize_wildcard(&self) -> Option<Self> {
         if self.head().is_wildcard() { Some(self.to_tail()) } else { None }
@@ -447,8 +466,13 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
         Matrix(vec![])
     }
 
+    /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
     pub fn push(&mut self, row: PatStack<'p, 'tcx>) {
-        self.0.push(row)
+        if let Some(rows) = row.expand_or_pat() {
+            self.0.extend(rows);
+        } else {
+            self.0.push(row);
+        }
     }
 
     /// Iterate over the first component of each row
@@ -472,12 +496,10 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
         'a: 'q,
         'p: 'q,
     {
-        Matrix(
-            self.0
-                .iter()
-                .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
-                .collect(),
-        )
+        self.0
+            .iter()
+            .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
+            .collect()
     }
 }
 
@@ -529,7 +551,12 @@ impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
     where
         T: IntoIterator<Item = PatStack<'p, 'tcx>>,
     {
-        Matrix(iter.into_iter().collect())
+        let mut matrix = Matrix::empty();
+        for x in iter {
+            // Using `push` ensures we correctly expand or-patterns.
+            matrix.push(x);
+        }
+        matrix
     }
 }
 
@@ -1602,6 +1629,15 @@ pub fn is_useful<'p, 'a, 'tcx>(
 
     assert!(rows.iter().all(|r| r.len() == v.len()));
 
+    // If the first pattern is an or-pattern, expand it.
+    if let Some(vs) = v.expand_or_pat() {
+        return vs
+            .into_iter()
+            .map(|v| is_useful(cx, matrix, &v, witness_preference, hir_id))
+            .find(|result| result.is_useful())
+            .unwrap_or(NotUseful);
+    }
+
     let (ty, span) = matrix
         .heads()
         .map(|r| (r.ty, r.span))
@@ -1813,9 +1849,7 @@ fn pat_constructor<'tcx>(
                 if slice.is_some() { VarLen(prefix, suffix) } else { FixedLen(prefix + suffix) };
             Some(Slice(Slice { array_len, kind }))
         }
-        PatKind::Or { .. } => {
-            bug!("support for or-patterns has not been fully implemented yet.");
-        }
+        PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
     }
 }
 
@@ -2404,9 +2438,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
             _ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
         },
 
-        PatKind::Or { .. } => {
-            bug!("support for or-patterns has not been fully implemented yet.");
-        }
+        PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
     };
     debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result);
 
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index acad56be604..a4f12a4e54f 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -4,7 +4,7 @@ use rustc::hir::def_id::DefId;
 use rustc::mir::BorrowKind;
 use rustc::session::config::nightly_options;
 use rustc::ty::TyCtxt;
-use syntax::feature_gate::{emit_feature_err, GateIssue};
+use syntax::feature_gate::feature_err;
 use syntax::symbol::sym;
 use syntax_pos::{Span, Symbol};
 
@@ -222,13 +222,13 @@ impl NonConstOp for Panic {
     }
 
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
-        emit_feature_err(
+        feature_err(
             &item.tcx.sess.parse_sess,
             sym::const_panic,
             span,
-            GateIssue::Language,
             &format!("panicking in {}s is unstable", item.const_kind()),
-        );
+        )
+        .emit();
     }
 }
 
@@ -240,13 +240,13 @@ impl NonConstOp for RawPtrComparison {
     }
 
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
-        emit_feature_err(
+        feature_err(
             &item.tcx.sess.parse_sess,
             sym::const_compare_raw_pointers,
             span,
-            GateIssue::Language,
             &format!("comparing raw pointers inside {}", item.const_kind()),
-        );
+        )
+        .emit();
     }
 }
 
@@ -258,14 +258,14 @@ impl NonConstOp for RawPtrDeref {
     }
 
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
-        emit_feature_err(
-            &item.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
-            span, GateIssue::Language,
+        feature_err(
+            &item.tcx.sess.parse_sess, sym::const_raw_ptr_deref, span,
             &format!(
                 "dereferencing raw pointers in {}s is unstable",
                 item.const_kind(),
             ),
-        );
+        )
+        .emit();
     }
 }
 
@@ -277,14 +277,14 @@ impl NonConstOp for RawPtrToIntCast {
     }
 
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
-        emit_feature_err(
-            &item.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast,
-            span, GateIssue::Language,
+        feature_err(
+            &item.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast, span,
             &format!(
                 "casting pointers to integers in {}s is unstable",
                 item.const_kind(),
             ),
-        );
+        )
+        .emit();
     }
 }
 
@@ -334,11 +334,11 @@ impl NonConstOp for Transmute {
     }
 
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
-        emit_feature_err(
-            &item.tcx.sess.parse_sess, sym::const_transmute,
-            span, GateIssue::Language,
-            &format!("The use of std::mem::transmute() \
-            is gated in {}s", item.const_kind()));
+        feature_err(
+            &item.tcx.sess.parse_sess, sym::const_transmute, span,
+            &format!("The use of std::mem::transmute() is gated in {}s", item.const_kind())
+        )
+        .emit();
     }
 }
 
@@ -355,10 +355,10 @@ impl NonConstOp for UnionAccess {
     }
 
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
-        emit_feature_err(
-            &item.tcx.sess.parse_sess, sym::const_fn_union,
-            span, GateIssue::Language,
+        feature_err(
+            &item.tcx.sess.parse_sess, sym::const_fn_union, span,
             "unions in const fn are unstable",
-        );
+        )
+        .emit();
     }
 }
diff --git a/src/librustc_mir/transform/simplify_try.rs b/src/librustc_mir/transform/simplify_try.rs
index de5c2ebb571..9dc5daa9b07 100644
--- a/src/librustc_mir/transform/simplify_try.rs
+++ b/src/librustc_mir/transform/simplify_try.rs
@@ -34,7 +34,8 @@ pub struct SimplifyArmIdentity;
 
 impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
     fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        for bb in body.basic_blocks_mut() {
+        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
+        for bb in basic_blocks {
             // Need 3 statements:
             let (s0, s1, s2) = match &mut *bb.statements {
                 [s0, s1, s2] => (s0, s1, s2),
@@ -51,7 +52,12 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
                 Some(x) => x,
             };
             if local_tmp_s0 != local_tmp_s1
+                // The field-and-variant information match up.
                 || vf_s0 != vf_s1
+                // Source and target locals have the same type.
+                // FIXME(Centril | oli-obk): possibly relax to same layout?
+                || local_decls[local_0].ty != local_decls[local_1].ty
+                // We're setting the discriminant of `local_0` to this variant.
                 || Some((local_0, vf_s0.var_idx)) != match_set_discr(s2)
             {
                 continue;
diff --git a/src/librustc_parse/Cargo.toml b/src/librustc_parse/Cargo.toml
index a9175487a75..95b3256f53a 100644
--- a/src/librustc_parse/Cargo.toml
+++ b/src/librustc_parse/Cargo.toml
@@ -16,6 +16,7 @@ syntax_pos = { path = "../libsyntax_pos" }
 syntax = { path = "../libsyntax" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_feature = { path = "../librustc_feature" }
 rustc_lexer = { path = "../librustc_lexer" }
 rustc_target = { path = "../librustc_target" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs
index 7ce555ed57a..26e51e83d62 100644
--- a/src/librustc_parse/config.rs
+++ b/src/librustc_parse/config.rs
@@ -9,14 +9,9 @@
 //! [#64197]: https://github.com/rust-lang/rust/issues/64197
 
 use crate::validate_attr;
+use rustc_feature::Features;
 use syntax::attr::HasAttrs;
-use syntax::feature_gate::{
-    feature_err,
-    EXPLAIN_STMT_ATTR_SYNTAX,
-    Features,
-    get_features,
-    GateIssue,
-};
+use syntax::feature_gate::{feature_err, get_features};
 use syntax::attr;
 use syntax::ast;
 use syntax::edition::Edition;
@@ -52,7 +47,7 @@ pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition,
         } else { // the entire crate is unconfigured
             krate.attrs = Vec::new();
             krate.module.items = Vec::new();
-            return (krate, Features::new());
+            return (krate, Features::default());
         }
 
         features = get_features(&sess.span_diagnostic, &krate.attrs, edition, allow_features);
@@ -217,8 +212,7 @@ impl<'a> StripUnconfigured<'a> {
             let mut err = feature_err(self.sess,
                                       sym::stmt_expr_attributes,
                                       attr.span,
-                                      GateIssue::Language,
-                                      EXPLAIN_STMT_ATTR_SYNTAX);
+                                      "attributes on expressions are experimental");
 
             if attr.is_doc_comment() {
                 err.help("`///` is for documentation comments. For a plain comment, use `//`.");
diff --git a/src/librustc_parse/validate_attr.rs b/src/librustc_parse/validate_attr.rs
index bbe0dc1c35f..a3c9e266593 100644
--- a/src/librustc_parse/validate_attr.rs
+++ b/src/librustc_parse/validate_attr.rs
@@ -1,10 +1,10 @@
 //! Meta-syntax validation logic of attributes for post-expansion.
 
 use errors::{PResult, Applicability};
-use syntax::ast::{self, Attribute, AttrKind, Ident, MetaItem};
-use syntax::attr::{AttributeTemplate, mk_name_value_item_str};
+use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
+use syntax::ast::{self, Attribute, AttrKind, Ident, MetaItem, MetaItemKind};
+use syntax::attr::mk_name_value_item_str;
 use syntax::early_buffered_lints::BufferedEarlyLintId;
-use syntax::feature_gate::BUILTIN_ATTRIBUTE_MAP;
 use syntax::token;
 use syntax::tokenstream::TokenTree;
 use syntax::sess::ParseSess;
@@ -41,6 +41,16 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
     })
 }
 
+/// Checks that the given meta-item is compatible with this `AttributeTemplate`.
+fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool {
+    match meta {
+        MetaItemKind::Word => template.word,
+        MetaItemKind::List(..) => template.list.is_some(),
+        MetaItemKind::NameValue(lit) if lit.kind.is_str() => template.name_value_str.is_some(),
+        MetaItemKind::NameValue(..) => false,
+    }
+}
+
 pub fn check_builtin_attribute(
     sess: &ParseSess,
     attr: &Attribute,
@@ -57,7 +67,7 @@ pub fn check_builtin_attribute(
                              name == sym::test || name == sym::bench;
 
     match parse_meta(sess, attr) {
-        Ok(meta) => if !should_skip(name) && !template.compatible(&meta.kind) {
+        Ok(meta) => if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) {
             let error_msg = format!("malformed `{}` attribute input", name);
             let mut msg = "attribute must be of the form ".to_owned();
             let mut suggestions = vec![];
diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml
index 7a98734bdbe..bb2f7c67418 100644
--- a/src/librustc_passes/Cargo.toml
+++ b/src/librustc_passes/Cargo.toml
@@ -12,6 +12,7 @@ path = "lib.rs"
 log = "0.4"
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_feature = { path = "../librustc_feature" }
 rustc_index = { path = "../librustc_index" }
 rustc_parse = { path = "../librustc_parse" }
 rustc_target = { path = "../librustc_target" }
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index e189b7175f9..5a29a56ad54 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -14,7 +14,6 @@ use rustc_parse::validate_attr;
 use syntax::ast::*;
 use syntax::attr;
 use syntax::expand::is_proc_macro_attr;
-use syntax::feature_gate::is_builtin_attr;
 use syntax::print::pprust;
 use syntax::source_map::Spanned;
 use syntax::symbol::{kw, sym};
@@ -257,7 +256,7 @@ impl<'a> AstValidator<'a> {
             .flat_map(|i| i.attrs.as_ref())
             .filter(|attr| {
                 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
-                !arr.contains(&attr.name_or_empty()) && is_builtin_attr(attr)
+                !arr.contains(&attr.name_or_empty()) && attr::is_builtin_attr(attr)
             })
             .for_each(|attr| if attr.is_doc_comment() {
                 let mut err = self.err_handler().struct_span_err(
diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs
index 24bc088e24a..63c6e60de79 100644
--- a/src/librustc_passes/check_const.rs
+++ b/src/librustc_passes/check_const.rs
@@ -13,8 +13,9 @@ use rustc::hir::map::Map;
 use rustc::hir;
 use rustc::ty::TyCtxt;
 use rustc::ty::query::Providers;
+use rustc_feature::Features;
 use syntax::ast::Mutability;
-use syntax::feature_gate::{emit_feature_err, Features, GateIssue};
+use syntax::feature_gate::feature_err;
 use syntax::span_err;
 use syntax_pos::{sym, Span};
 use rustc_error_codes::*;
@@ -140,13 +141,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
             | NonConstExpr::Match(hir::MatchSource::Normal)
             | NonConstExpr::Match(hir::MatchSource::IfDesugar { .. })
             | NonConstExpr::Match(hir::MatchSource::IfLetDesugar { .. })
-            => emit_feature_err(
-                &self.tcx.sess.parse_sess,
-                sym::const_if_match,
-                span,
-                GateIssue::Language,
-                &msg
-            ),
+            => feature_err(&self.tcx.sess.parse_sess, sym::const_if_match, span, &msg).emit(),
 
             _ => span_err!(self.tcx.sess, span, E0744, "{}", msg),
         }
diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml
index 6cce893f8ec..caca20e4221 100644
--- a/src/librustc_resolve/Cargo.toml
+++ b/src/librustc_resolve/Cargo.toml
@@ -20,6 +20,7 @@ arena = { path = "../libarena" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 syntax_pos = { path = "../libsyntax_pos" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_feature = { path = "../librustc_feature" }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_error_codes = { path = "../librustc_error_codes" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index eb7265cb9cc..04e233c5973 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -29,10 +29,8 @@ use errors::Applicability;
 
 use syntax::ast::{Name, Ident};
 use syntax::attr;
-
 use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
 use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind};
-use syntax::feature_gate::is_builtin_attr;
 use syntax::token::{self, Token};
 use syntax::print::pprust;
 use syntax::{span_err, struct_span_err};
@@ -1231,7 +1229,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
     }
 
     fn visit_attribute(&mut self, attr: &'b ast::Attribute) {
-        if !attr.is_doc_comment() && is_builtin_attr(attr) {
+        if !attr.is_doc_comment() && attr::is_builtin_attr(attr) {
             self.r.builtin_attrs.push(
                 (attr.get_normal_item().path.segments[0].ident, self.parent_scope)
             );
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index e134b8b92ac..4dcafb6d279 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -9,8 +9,8 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::session::Session;
 use rustc::ty::{self, DefIdTree};
 use rustc::util::nodemap::FxHashSet;
+use rustc_feature::BUILTIN_ATTRIBUTES;
 use syntax::ast::{self, Ident, Path};
-use syntax::feature_gate::BUILTIN_ATTRIBUTES;
 use syntax::source_map::SourceMap;
 use syntax::struct_span_err;
 use syntax::symbol::{Symbol, kw};
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 21c24f9da1c..9e7098da49f 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -12,18 +12,18 @@ use rustc::middle::stability;
 use rustc::session::Session;
 use rustc::util::nodemap::FxHashSet;
 use rustc::{ty, lint, span_bug};
+use rustc_feature::is_builtin_attr_name;
 use syntax::ast::{self, NodeId, Ident};
 use syntax::attr::{self, StabilityLevel};
 use syntax::edition::Edition;
-use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
-use syntax::feature_gate::GateIssue;
+use syntax::feature_gate::feature_err;
 use syntax::print::pprust;
-use syntax::symbol::{Symbol, kw, sym};
 use syntax_expand::base::{self, InvocationRes, Indeterminate};
 use syntax_expand::base::SyntaxExtension;
 use syntax_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
 use syntax_expand::compile_declarative_macro;
 use syntax_pos::hygiene::{self, ExpnId, ExpnData, ExpnKind};
+use syntax_pos::symbol::{Symbol, kw, sym};
 use syntax_pos::{Span, DUMMY_SP};
 
 use std::{mem, ptr};
@@ -346,13 +346,8 @@ impl<'a> Resolver<'a> {
                segment.ident.as_str().starts_with("rustc") {
                 let msg =
                     "attributes starting with `rustc` are reserved for use by the `rustc` compiler";
-                emit_feature_err(
-                    &self.session.parse_sess,
-                    sym::rustc_attrs,
-                    segment.ident.span,
-                    GateIssue::Language,
-                    msg,
-                );
+                feature_err(&self.session.parse_sess, sym::rustc_attrs, segment.ident.span, msg)
+                    .emit();
             }
         }
 
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index fdbf729a773..af978d5095e 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -23,7 +23,7 @@ use crate::require_c_abi_if_c_variadic;
 use smallvec::SmallVec;
 use syntax::ast;
 use syntax::errors::pluralize;
-use syntax::feature_gate::{GateIssue, emit_feature_err};
+use syntax::feature_gate::feature_err;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax::symbol::sym;
 use syntax_pos::{DUMMY_SP, Span, MultiSpan};
@@ -914,8 +914,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             } else {
                 "parenthetical notation is only stable when used with `Fn`-family traits"
             };
-            emit_feature_err(&self.tcx().sess.parse_sess, sym::unboxed_closures,
-                             span, GateIssue::Language, msg);
+            feature_err(&self.tcx().sess.parse_sess, sym::unboxed_closures, span, msg).emit();
         }
 
         self.create_substs_for_ast_path(span,
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 871acb2726a..901a2192e20 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -644,11 +644,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         }
 
         if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
-            feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
-                                           sym::unsized_tuple_coercion,
-                                           self.cause.span,
-                                           feature_gate::GateIssue::Language,
-                                           feature_gate::EXPLAIN_UNSIZED_TUPLE_COERCION);
+            feature_gate::feature_err(
+                &self.tcx.sess.parse_sess,
+                sym::unsized_tuple_coercion,
+                self.cause.span,
+                "unsized tuple coercion is not stable enough for use and is subject to change",
+            )
+            .emit();
         }
 
         Ok(coercion)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3a4a4a50bf2..c7a0190a1d1 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -125,7 +125,7 @@ use syntax_pos::{self, BytePos, Span, MultiSpan};
 use syntax_pos::hygiene::DesugaringKind;
 use syntax::ast;
 use syntax::attr;
-use syntax::feature_gate::{GateIssue, emit_feature_err};
+use syntax::feature_gate::feature_err;
 use syntax::source_map::{DUMMY_SP, original_sp};
 use syntax::symbol::{kw, sym, Ident};
 use syntax::util::parser::ExprPrecedence;
@@ -2373,13 +2373,13 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
 
     if adt.is_enum() {
         if !tcx.features().transparent_enums {
-            emit_feature_err(
+            feature_err(
                 &tcx.sess.parse_sess,
                 sym::transparent_enums,
                 sp,
-                GateIssue::Language,
                 "transparent enums are unstable",
-            );
+            )
+            .emit();
         }
         if adt.variants.len() != 1 {
             bad_variant_count(tcx, adt, sp, def_id);
@@ -2391,11 +2391,13 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
     }
 
     if adt.is_union() && !tcx.features().transparent_unions {
-        emit_feature_err(&tcx.sess.parse_sess,
-                         sym::transparent_unions,
-                         sp,
-                         GateIssue::Language,
-                         "transparent unions are unstable");
+        feature_err(
+            &tcx.sess.parse_sess,
+            sym::transparent_unions,
+            sp,
+            "transparent unions are unstable",
+        )
+        .emit();
     }
 
     // For each field, figure out if it's known to be a ZST and align(1)
@@ -2452,11 +2454,13 @@ pub fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, vs: &'tcx [hir::Variant], i
     let repr_type_ty = def.repr.discr_type().to_ty(tcx);
     if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
         if !tcx.features().repr128 {
-            emit_feature_err(&tcx.sess.parse_sess,
-                             sym::repr128,
-                             sp,
-                             GateIssue::Language,
-                             "repr with 128-bit type is unstable");
+            feature_err(
+                &tcx.sess.parse_sess,
+                sym::repr128,
+                sp,
+                "repr with 128-bit type is unstable",
+            )
+            .emit();
         }
     }
 
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index b491b103313..20b6b01de57 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -10,7 +10,7 @@ use rustc::middle::lang_items;
 use rustc::infer::opaque_types::may_define_opaque_type;
 
 use syntax::ast;
-use syntax::feature_gate::{self, GateIssue};
+use syntax::feature_gate;
 use syntax_pos::Span;
 use syntax::symbol::sym;
 use errors::DiagnosticBuilder;
@@ -830,13 +830,13 @@ fn check_method_receiver<'fcx, 'tcx>(
                     &fcx.tcx.sess.parse_sess,
                     sym::arbitrary_self_types,
                     span,
-                    GateIssue::Language,
                     &format!(
                         "`{}` cannot be used as the type of `self` without \
                             the `arbitrary_self_types` feature",
                         receiver_ty,
                     ),
-                ).help(HELP_FOR_SELF_TYPE)
+                )
+                .help(HELP_FOR_SELF_TYPE)
                 .emit();
             } else {
                 // Report error; would not have worked with `arbitrary_self_types`.
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 652f081e176..6d6e7685fa0 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -909,14 +909,12 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
             let parent_id = tcx.hir().get_parent_item(hir_id);
             Some(tcx.hir().local_def_id(parent_id))
         }
-        // FIXME(#43408) enable this in all cases when we get lazy normalization.
-        Node::AnonConst(&anon_const) => {
-            // HACK(eddyb) this provides the correct generics when the workaround
-            // for a const parameter `AnonConst` is being used elsewhere, as then
-            // there won't be the kind of cyclic dependency blocking #43408.
-            let expr = &tcx.hir().body(anon_const.body).value;
-            let icx = ItemCtxt::new(tcx, def_id);
-            if AstConv::const_param_def_id(&icx, expr).is_some() {
+        // FIXME(#43408) enable this always when we get lazy normalization.
+        Node::AnonConst(_) => {
+            // HACK(eddyb) this provides the correct generics when
+            // `feature(const_generics)` is enabled, so that const expressions
+            // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
+            if tcx.features().const_generics {
                 let parent_id = tcx.hir().get_parent_item(hir_id);
                 Some(tcx.hir().local_def_id(parent_id))
             } else {
@@ -1494,16 +1492,16 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                         _ => None,
                     };
                     if let Some(unsupported_type) = err {
-                        feature_gate::emit_feature_err(
+                        feature_gate::feature_err(
                             &tcx.sess.parse_sess,
                             sym::const_compare_raw_pointers,
                             hir_ty.span,
-                            feature_gate::GateIssue::Language,
                             &format!(
                                 "using {} as const generic parameters is unstable",
                                 unsupported_type
                             ),
-                        );
+                        )
+                        .emit();
                     };
                 }
                 if ty::search_for_structural_match_violation(
@@ -2522,13 +2520,13 @@ fn from_target_feature(
                 None => true,
             };
             if !allowed && id.is_local() {
-                feature_gate::emit_feature_err(
+                feature_gate::feature_err(
                     &tcx.sess.parse_sess,
                     feature_gate.unwrap(),
                     item.span(),
-                    feature_gate::GateIssue::Language,
                     &format!("the target feature `{}` is currently unstable", feature),
-                );
+                )
+                .emit();
             }
             Some(Symbol::intern(feature))
         }));
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 09f4873967e..078948cc63b 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -7,10 +7,10 @@ use std::mem;
 use std::fmt::{self, Write};
 use std::ops;
 
+use rustc_feature::Features;
 use syntax::symbol::{Symbol, sym};
 use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, LitKind};
 use syntax::sess::ParseSess;
-use syntax::feature_gate::Features;
 
 use syntax_pos::Span;
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 7d1f89079f8..b77b1c720cf 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -12,12 +12,12 @@ use rustc::session::DiagnosticOutput;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use rustc_interface::interface;
 use rustc_driver::abort_on_err;
+use rustc_feature::UnstableFeatures;
 use rustc_resolve as resolve;
 
 use syntax::ast::CRATE_NODE_ID;
 use syntax::source_map;
 use syntax::attr;
-use syntax::feature_gate::UnstableFeatures;
 use errors::json::JsonEmitter;
 use syntax::symbol::sym;
 use syntax_pos::DUMMY_SP;
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index 56f1191feed..7945850ef08 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -2,7 +2,7 @@ use std::fs;
 use std::path::Path;
 use std::str;
 use errors;
-use crate::syntax::feature_gate::UnstableFeatures;
+use rustc_feature::UnstableFeatures;
 use crate::syntax::edition::Edition;
 use crate::html::markdown::{IdMap, ErrorCodes, Markdown, Playground};
 
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index ba94cb82c00..b5c1a77a387 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -45,7 +45,6 @@ use errors;
 use serialize::json::{ToJson, Json, as_json};
 use syntax::ast;
 use syntax::edition::Edition;
-use syntax::feature_gate::UnstableFeatures;
 use syntax::print::pprust;
 use syntax::source_map::FileName;
 use syntax::symbol::{Symbol, sym};
@@ -56,6 +55,7 @@ use rustc::middle::stability;
 use rustc::hir;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::flock;
+use rustc_feature::UnstableFeatures;
 
 use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, Mutability};
 use crate::config::RenderOptions;
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 69d9748bb88..be3644ecf96 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -24,6 +24,7 @@ extern crate env_logger;
 extern crate rustc;
 extern crate rustc_data_structures;
 extern crate rustc_driver;
+extern crate rustc_feature;
 extern crate rustc_error_codes;
 extern crate rustc_index;
 extern crate rustc_resolve;
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 8431271e62d..7dc3df23a6d 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -6,7 +6,7 @@ use errors;
 use testing;
 use syntax::edition::Edition;
 use syntax::source_map::DUMMY_SP;
-use syntax::feature_gate::UnstableFeatures;
+use rustc_feature::UnstableFeatures;
 
 use crate::externalfiles::{LoadStringError, load_string};
 use crate::config::{Options, RenderOptions};
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index d8f2dbca835..3c021ae7465 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -5,10 +5,10 @@ use rustc::hir;
 use rustc::lint as lint;
 use rustc::ty;
 use rustc_resolve::ParentScope;
+use rustc_feature::UnstableFeatures;
 use syntax;
 use syntax::ast::{self, Ident};
 use syntax_expand::base::SyntaxExtensionKind;
-use syntax::feature_gate::UnstableFeatures;
 use syntax::symbol::Symbol;
 use syntax_pos::DUMMY_SP;
 
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index d09eb0b2fc2..5fd7ab03224 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -1,4 +1,5 @@
 use rustc_data_structures::sync::Lrc;
+use rustc_feature::UnstableFeatures;
 use rustc_interface::interface;
 use rustc_target::spec::TargetTriple;
 use rustc::hir;
@@ -9,7 +10,6 @@ use syntax::ast;
 use syntax::with_globals;
 use syntax::source_map::SourceMap;
 use syntax::edition::Edition;
-use syntax::feature_gate::UnstableFeatures;
 use std::env;
 use std::io::{self, Write};
 use std::panic;
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index acf53f7f003..1dbb0c6ec83 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -234,6 +234,7 @@
 #![feature(allocator_internals)]
 #![feature(allow_internal_unsafe)]
 #![feature(allow_internal_unstable)]
+#![feature(atomic_mut_ptr)]
 #![feature(arbitrary_self_types)]
 #![feature(array_error_internals)]
 #![feature(asm)]
diff --git a/src/libstd/sys/wasm/alloc.rs b/src/libstd/sys/wasm/alloc.rs
index c1af6ec1262..05e55334ac0 100644
--- a/src/libstd/sys/wasm/alloc.rs
+++ b/src/libstd/sys/wasm/alloc.rs
@@ -67,7 +67,7 @@ mod lock {
             //
             //     unsafe {
             //         let r = core::arch::wasm32::i32_atomic_wait(
-            //             &LOCKED as *const AtomicI32 as *mut i32,
+            //             LOCKED.as_mut_ptr(),
             //             1,  //     expected value
             //             -1, //     timeout
             //         );
@@ -143,7 +143,7 @@ mod lock {
             //
             //     unsafe {
             //         core::arch::wasm32::atomic_notify(
-            //             &LOCKED as *const AtomicI32 as *mut i32,
+            //             LOCKED.as_mut_ptr(),
             //             1, //     only one thread
             //         );
             //     }
diff --git a/src/libstd/sys/wasm/condvar_atomics.rs b/src/libstd/sys/wasm/condvar_atomics.rs
index 580d2121844..f452bbd3487 100644
--- a/src/libstd/sys/wasm/condvar_atomics.rs
+++ b/src/libstd/sys/wasm/condvar_atomics.rs
@@ -89,6 +89,6 @@ impl Condvar {
     #[inline]
     fn ptr(&self) -> *mut i32 {
         assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
-        &self.cnt as *const AtomicUsize as *mut i32
+        self.cnt.as_mut_ptr() as *mut i32
     }
 }
diff --git a/src/libstd/sys/wasm/mutex_atomics.rs b/src/libstd/sys/wasm/mutex_atomics.rs
index 0e4f3d80aa9..cddd584dd22 100644
--- a/src/libstd/sys/wasm/mutex_atomics.rs
+++ b/src/libstd/sys/wasm/mutex_atomics.rs
@@ -56,7 +56,7 @@ impl Mutex {
     #[inline]
     fn ptr(&self) -> *mut i32 {
         assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
-        &self.locked as *const AtomicUsize as *mut isize as *mut i32
+        self.locked.as_mut_ptr() as *mut i32
     }
 }
 
@@ -145,6 +145,6 @@ impl ReentrantMutex {
 
     #[inline]
     fn ptr(&self) -> *mut i32 {
-        &self.owner as *const AtomicU32 as *mut i32
+        self.owner.as_mut_ptr() as *mut i32
     }
 }
diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml
index dff23076c82..085c1760c80 100644
--- a/src/libsyntax/Cargo.toml
+++ b/src/libsyntax/Cargo.toml
@@ -18,6 +18,7 @@ lazy_static = "1.0.0"
 syntax_pos = { path = "../libsyntax_pos" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_feature = { path = "../librustc_feature" }
 rustc_index = { path = "../librustc_index" }
 rustc_lexer = { path = "../librustc_lexer" }
 rustc_macros = { path = "../librustc_macros" }
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index c10541c8c7e..3c10f27b60a 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -1,7 +1,8 @@
 //! Parsing and validation of builtin attributes
 
+use super::{mark_used, MetaItemKind};
 use crate::ast::{self, Attribute, MetaItem, NestedMetaItem};
-use crate::feature_gate::{Features, GatedCfg};
+use crate::feature_gate::feature_err;
 use crate::print::pprust;
 use crate::sess::ParseSess;
 
@@ -9,12 +10,15 @@ use errors::{Applicability, Handler};
 use std::num::NonZeroU32;
 use syntax_pos::hygiene::Transparency;
 use syntax_pos::{symbol::Symbol, symbol::sym, Span};
+use rustc_feature::{Features, find_gated_cfg, GatedCfg, is_builtin_attr_name};
 use rustc_macros::HashStable_Generic;
 
-use super::{mark_used, MetaItemKind};
-
 use rustc_error_codes::*;
 
+pub fn is_builtin_attr(attr: &Attribute) -> bool {
+    attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
+}
+
 enum AttrError {
     MultipleItem(String),
     UnknownMetaItem(String, &'static [&'static str]),
@@ -24,31 +28,6 @@ enum AttrError {
     UnsupportedLiteral(&'static str, /* is_bytestr */ bool),
 }
 
-/// A template that the attribute input must match.
-/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
-#[derive(Clone, Copy)]
-pub struct AttributeTemplate {
-    pub word: bool,
-    pub list: Option<&'static str>,
-    pub name_value_str: Option<&'static str>,
-}
-
-impl AttributeTemplate {
-    pub fn only_word() -> Self {
-        Self { word: true, list: None, name_value_str: None }
-    }
-
-    /// Checks that the given meta-item is compatible with this template.
-    pub fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool {
-        match meta_item_kind {
-            ast::MetaItemKind::Word => self.word,
-            ast::MetaItemKind::List(..) => self.list.is_some(),
-            ast::MetaItemKind::NameValue(lit) if lit.kind.is_str() => self.name_value_str.is_some(),
-            ast::MetaItemKind::NameValue(..) => false,
-        }
-    }
-}
-
 fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
     let diag = &sess.span_diagnostic;
     match error {
@@ -555,8 +534,9 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
 /// Tests if a cfg-pattern matches the cfg set
 pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool {
     eval_condition(cfg, sess, &mut |cfg| {
-        if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) {
-            gated_cfg.check_and_emit(sess, feats);
+        let gate = find_gated_cfg(|sym| cfg.check_name(sym));
+        if let (Some(feats), Some(gated_cfg)) = (features, gate) {
+            gate_cfg(&gated_cfg, cfg.span, sess, feats);
         }
         let error = |span, msg| { sess.span_diagnostic.span_err(span, msg); true };
         if cfg.path.segments.len() != 1 {
@@ -585,12 +565,21 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
     })
 }
 
+fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) {
+    let (cfg, feature, has_feature) = gated_cfg;
+    if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
+        let explain = format!("`cfg({})` is experimental and subject to change", cfg);
+        feature_err(sess, *feature, cfg_span, &explain).emit()
+    }
+}
+
 /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
 /// evaluate individual items.
-pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
-                         -> bool
-    where F: FnMut(&ast::MetaItem) -> bool
-{
+pub fn eval_condition(
+    cfg: &ast::MetaItem,
+    sess: &ParseSess,
+    eval: &mut impl FnMut(&ast::MetaItem) -> bool,
+) -> bool {
     match cfg.kind {
         ast::MetaItemKind::List(ref mis) => {
             for mi in mis.iter() {
diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs
index ec0eaa56812..3d2c3b1d4f9 100644
--- a/src/libsyntax/feature_gate/check.rs
+++ b/src/libsyntax/feature_gate/check.rs
@@ -1,7 +1,7 @@
-use super::{active::{ACTIVE_FEATURES, Features}, Feature, State as FeatureState};
-use super::accepted::ACCEPTED_FEATURES;
-use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
-use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
+use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{Features, Feature, State as FeatureState, UnstableFeatures};
+use rustc_feature::{find_feature_issue, GateIssue};
 
 use crate::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
 use crate::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
@@ -19,18 +19,6 @@ use log::debug;
 
 use rustc_error_codes::*;
 
-
-use std::env;
-use std::num::NonZeroU32;
-
-#[derive(Copy, Clone, Debug)]
-pub enum Stability {
-    Unstable,
-    // First argument is tracking issue link; second argument is an optional
-    // help message, which defaults to "remove this attribute"
-    Deprecated(&'static str, Option<&'static str>),
-}
-
 macro_rules! gate_feature_fn {
     ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
         let (cx, has_feature, span,
@@ -59,30 +47,6 @@ pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features:
     PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
 }
 
-fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
-    if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
-        // FIXME (#28244): enforce that active features have issue numbers
-        // assert!(info.issue().is_some())
-        info.issue()
-    } else {
-        // search in Accepted, Removed, or Stable Removed features
-        let found = ACCEPTED_FEATURES
-            .iter()
-            .chain(REMOVED_FEATURES)
-            .chain(STABLE_REMOVED_FEATURES)
-            .find(|t| t.name == feature);
-        match found {
-            Some(found) => found.issue(),
-            None => panic!("feature `{}` is not declared anywhere", feature),
-        }
-    }
-}
-
-pub enum GateIssue {
-    Language,
-    Library(Option<NonZeroU32>)
-}
-
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub enum GateStrength {
     /// A hard error. (Most feature gates should use this.)
@@ -91,41 +55,35 @@ pub enum GateStrength {
     Soft,
 }
 
-pub fn emit_feature_err(
-    sess: &ParseSess,
+pub fn feature_err<'a>(
+    sess: &'a ParseSess,
     feature: Symbol,
-    span: Span,
-    issue: GateIssue,
+    span: impl Into<MultiSpan>,
     explain: &str,
-) {
-    feature_err(sess, feature, span, issue, explain).emit();
+) -> DiagnosticBuilder<'a> {
+    feature_err_issue(sess, feature, span, GateIssue::Language, explain)
 }
 
-pub fn feature_err<'a, S: Into<MultiSpan>>(
+pub fn feature_err_issue<'a>(
     sess: &'a ParseSess,
     feature: Symbol,
-    span: S,
+    span: impl Into<MultiSpan>,
     issue: GateIssue,
     explain: &str,
 ) -> DiagnosticBuilder<'a> {
     leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
 }
 
-fn leveled_feature_err<'a, S: Into<MultiSpan>>(
+fn leveled_feature_err<'a>(
     sess: &'a ParseSess,
     feature: Symbol,
-    span: S,
+    span: impl Into<MultiSpan>,
     issue: GateIssue,
     explain: &str,
     level: GateStrength,
 ) -> DiagnosticBuilder<'a> {
     let diag = &sess.span_diagnostic;
 
-    let issue = match issue {
-        GateIssue::Language => find_lang_feature_issue(feature),
-        GateIssue::Library(lib) => lib,
-    };
-
     let mut err = match level {
         GateStrength::Hard => {
             diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658))
@@ -133,7 +91,7 @@ fn leveled_feature_err<'a, S: Into<MultiSpan>>(
         GateStrength::Soft => diag.struct_span_warn(span, explain),
     };
 
-    if let Some(n) = issue {
+    if let Some(n) = find_feature_issue(feature, issue) {
         err.note(&format!(
             "for more information, see https://github.com/rust-lang/rust/issues/{}",
             n,
@@ -156,20 +114,6 @@ fn leveled_feature_err<'a, S: Into<MultiSpan>>(
 
 }
 
-const EXPLAIN_BOX_SYNTAX: &str =
-    "box expression syntax is experimental; you can call `Box::new` instead";
-
-pub const EXPLAIN_STMT_ATTR_SYNTAX: &str =
-    "attributes on expressions are experimental";
-
-pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &str =
-    "allow_internal_unstable side-steps feature gating and stability checks";
-pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &str =
-    "allow_internal_unsafe side-steps the unsafe_code lint";
-
-pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str =
-    "unsized tuple coercion is not stable enough for use and is subject to change";
-
 struct PostExpansionVisitor<'a> {
     parse_sess: &'a ParseSess,
     features: &'a Features,
@@ -282,7 +226,6 @@ impl<'a> PostExpansionVisitor<'a> {
                 self.parse_sess,
                 sym::arbitrary_enum_discriminant,
                 discriminant_spans.clone(),
-                crate::feature_gate::GateIssue::Language,
                 "custom discriminant values are not allowed in enums with tuple or struct variants",
             );
             for sp in discriminant_spans {
@@ -529,7 +472,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_expr(&mut self, e: &'a ast::Expr) {
         match e.kind {
             ast::ExprKind::Box(_) => {
-                gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
+                gate_feature_post!(
+                    &self, box_syntax, e.span,
+                    "box expression syntax is experimental; you can call `Box::new` instead"
+                );
             }
             ast::ExprKind::Type(..) => {
                 // To avoid noise about type ascription in common syntax errors, only emit if it
@@ -695,7 +641,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
         err.emit();
     }
 
-    let mut features = Features::new();
+    let mut features = Features::default();
     let mut edition_enabled_features = FxHashMap::default();
 
     for &edition in ALL_EDITIONS {
@@ -900,40 +846,6 @@ pub fn check_crate(krate: &ast::Crate,
     visit::walk_crate(&mut visitor, krate);
 }
 
-#[derive(Clone, Copy, Hash)]
-pub enum UnstableFeatures {
-    /// Hard errors for unstable features are active, as on beta/stable channels.
-    Disallow,
-    /// Allow features to be activated, as on nightly.
-    Allow,
-    /// Errors are bypassed for bootstrapping. This is required any time
-    /// during the build that feature-related lints are set to warn or above
-    /// because the build turns on warnings-as-errors and uses lots of unstable
-    /// features. As a result, this is always required for building Rust itself.
-    Cheat
-}
-
-impl UnstableFeatures {
-    pub fn from_environment() -> UnstableFeatures {
-        // `true` if this is a feature-staged build, i.e., on the beta or stable channel.
-        let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
-        // `true` if we should enable unstable features for bootstrapping.
-        let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
-        match (disable_unstable_features, bootstrap) {
-            (_, true) => UnstableFeatures::Cheat,
-            (true, _) => UnstableFeatures::Disallow,
-            (false, _) => UnstableFeatures::Allow
-        }
-    }
-
-    pub fn is_nightly_build(&self) -> bool {
-        match *self {
-            UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
-            UnstableFeatures::Disallow => false,
-        }
-    }
-}
-
 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) {
     if !unstable.is_nightly_build() {
         for attr in krate.attrs.iter().filter(|attr| attr.check_name(sym::feature)) {
diff --git a/src/libsyntax/feature_gate/mod.rs b/src/libsyntax/feature_gate/mod.rs
deleted file mode 100644
index c4418c0f0f6..00000000000
--- a/src/libsyntax/feature_gate/mod.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-//! # Feature gating
-//!
-//! This module implements the gating necessary for preventing certain compiler
-//! features from being used by default. This module will crawl a pre-expanded
-//! AST to ensure that there are no features which are used that are not
-//! enabled.
-//!
-//! Features are enabled in programs via the crate-level attributes of
-//! `#![feature(...)]` with a comma-separated list of features.
-//!
-//! For the purpose of future feature-tracking, once code for detection of feature
-//! gate usage is added, *do not remove it again* even once the feature
-//! becomes stable.
-
-mod accepted;
-mod removed;
-mod active;
-mod builtin_attrs;
-mod check;
-
-use crate::{edition::Edition, symbol::Symbol};
-use std::fmt;
-use std::num::NonZeroU32;
-use syntax_pos::Span;
-
-#[derive(Clone, Copy)]
-pub enum State {
-    Accepted,
-    Active { set: fn(&mut Features, Span) },
-    Removed { reason: Option<&'static str> },
-    Stabilized { reason: Option<&'static str> },
-}
-
-impl fmt::Debug for State {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            State::Accepted { .. } => write!(f, "accepted"),
-            State::Active { .. } => write!(f, "active"),
-            State::Removed { .. } => write!(f, "removed"),
-            State::Stabilized { .. } => write!(f, "stabilized"),
-        }
-    }
-}
-
-#[derive(Debug, Clone)]
-pub struct Feature {
-    state: State,
-    name: Symbol,
-    since: &'static str,
-    issue: Option<u32>,  // FIXME: once #58732 is done make this an Option<NonZeroU32>
-    edition: Option<Edition>,
-    description: &'static str,
-}
-
-impl Feature {
-    fn issue(&self) -> Option<NonZeroU32> {
-        self.issue.and_then(|i| NonZeroU32::new(i))
-    }
-}
-
-pub use active::{Features, INCOMPLETE_FEATURES};
-pub use builtin_attrs::{
-    AttributeGate, AttributeType, GatedCfg,
-    BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
-    deprecated_attributes, is_builtin_attr,  is_builtin_attr_name,
-};
-pub use check::{
-    check_crate, check_attribute, get_features, feature_err, emit_feature_err,
-    Stability, GateIssue, UnstableFeatures,
-    EXPLAIN_STMT_ATTR_SYNTAX, EXPLAIN_UNSIZED_TUPLE_COERCION,
-};
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 22b49862f49..3d4a5d624c1 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -92,7 +92,10 @@ pub mod attr;
 pub mod expand;
 pub use syntax_pos::source_map;
 pub mod entry;
-pub mod feature_gate;
+pub mod feature_gate {
+    mod check;
+    pub use check::{check_crate, check_attribute, get_features, feature_err, feature_err_issue};
+}
 pub mod mut_visit;
 pub mod ptr;
 pub mod show_span;
diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs
index 740e9dfe459..aa9217c1b69 100644
--- a/src/libsyntax/sess.rs
+++ b/src/libsyntax/sess.rs
@@ -3,15 +3,15 @@
 
 use crate::ast::{CrateConfig, NodeId};
 use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId};
-use crate::source_map::{SourceMap, FilePathMapping};
-use crate::feature_gate::UnstableFeatures;
 
 use errors::{Applicability, emitter::SilentEmitter, Handler, ColorConfig, DiagnosticBuilder};
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
 use rustc_data_structures::sync::{Lrc, Lock, Once};
+use rustc_feature::UnstableFeatures;
 use syntax_pos::{Symbol, Span, MultiSpan};
 use syntax_pos::edition::Edition;
 use syntax_pos::hygiene::ExpnId;
+use syntax_pos::source_map::{SourceMap, FilePathMapping};
 
 use std::path::PathBuf;
 use std::str;
diff --git a/src/libsyntax_expand/Cargo.toml b/src/libsyntax_expand/Cargo.toml
index 653b87f0d82..897d5a65ba3 100644
--- a/src/libsyntax_expand/Cargo.toml
+++ b/src/libsyntax_expand/Cargo.toml
@@ -16,6 +16,7 @@ log = "0.4"
 syntax_pos = { path = "../libsyntax_pos" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_feature = { path = "../librustc_feature" }
 rustc_lexer = { path = "../librustc_lexer" }
 rustc_parse = { path = "../librustc_parse" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs
index 4f05b0147bf..a6ced1439c5 100644
--- a/src/libsyntax_expand/expand.rs
+++ b/src/libsyntax_expand/expand.rs
@@ -4,16 +4,17 @@ use crate::hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind};
 use crate::mbe::macro_rules::annotate_err_with_kind;
 use crate::placeholders::{placeholder, PlaceholderExpander};
 use crate::config::StripUnconfigured;
-use rustc_parse::configure;
 
+use rustc_feature::Features;
+use rustc_parse::configure;
 use rustc_parse::DirectoryOwnership;
 use rustc_parse::parser::Parser;
 use rustc_parse::validate_attr;
 use syntax::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path};
 use syntax::ast::{MacStmtStyle, StmtKind, ItemKind};
-use syntax::attr::{self, HasAttrs};
+use syntax::attr::{self, HasAttrs, is_builtin_attr};
 use syntax::source_map::respan;
-use syntax::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
+use syntax::feature_gate::{self, feature_err};
 use syntax::mut_visit::*;
 use syntax::print::pprust;
 use syntax::ptr::P;
@@ -726,13 +727,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         if self.cx.ecfg.proc_macro_hygiene() {
             return
         }
-        emit_feature_err(
+        feature_err(
             self.cx.parse_sess,
             sym::proc_macro_hygiene,
             span,
-            GateIssue::Language,
             &format!("custom attributes cannot be applied to {}", kind),
-        );
+        )
+        .emit();
     }
 
     fn gate_proc_macro_input(&self, annotatable: &Annotatable) {
@@ -744,13 +745,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             fn visit_item(&mut self, item: &'ast ast::Item) {
                 match &item.kind {
                     ast::ItemKind::Mod(module) if !module.inline => {
-                        emit_feature_err(
+                        feature_err(
                             self.parse_sess,
                             sym::proc_macro_hygiene,
                             item.span,
-                            GateIssue::Language,
                             "non-inline modules in proc macro input are unstable",
-                        );
+                        )
+                        .emit();
                     }
                     _ => {}
                 }
@@ -789,13 +790,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         if self.cx.ecfg.proc_macro_hygiene() {
             return
         }
-        emit_feature_err(
+        feature_err(
             self.cx.parse_sess,
             sym::proc_macro_hygiene,
             span,
-            GateIssue::Language,
             &format!("procedural macros cannot be expanded to {}", kind),
-        );
+        )
+        .emit();
     }
 
     fn parse_ast_fragment(
@@ -991,9 +992,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         if let Some(attr) = &attr {
             if !self.cx.ecfg.custom_inner_attributes() &&
                attr.style == ast::AttrStyle::Inner && !attr.has_name(sym::test) {
-                emit_feature_err(&self.cx.parse_sess, sym::custom_inner_attributes,
-                                 attr.span, GateIssue::Language,
-                                 "non-builtin inner attributes are unstable");
+                feature_err(
+                    &self.cx.parse_sess, sym::custom_inner_attributes, attr.span,
+                    "non-builtin inner attributes are unstable"
+                )
+                .emit();
             }
         }
         attr
diff --git a/src/libsyntax_expand/mbe/macro_rules.rs b/src/libsyntax_expand/mbe/macro_rules.rs
index a1d8b5a5338..b191527df19 100644
--- a/src/libsyntax_expand/mbe/macro_rules.rs
+++ b/src/libsyntax_expand/mbe/macro_rules.rs
@@ -8,12 +8,12 @@ use crate::mbe::macro_parser::{Error, Failure, Success};
 use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult};
 use crate::mbe::transcribe::transcribe;
 
+use rustc_feature::Features;
 use rustc_parse::parser::Parser;
 use rustc_parse::Directory;
 use syntax::ast;
 use syntax::attr::{self, TransparencyError};
 use syntax::edition::Edition;
-use syntax::feature_gate::Features;
 use syntax::print::pprust;
 use syntax::sess::ParseSess;
 use syntax::symbol::{kw, sym, Symbol};
diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml
index 2ebdac8ef7c..d73a9ea6cdb 100644
--- a/src/libsyntax_ext/Cargo.toml
+++ b/src/libsyntax_ext/Cargo.toml
@@ -14,6 +14,7 @@ errors = { path = "../librustc_errors", package = "rustc_errors" }
 fmt_macros = { path = "../libfmt_macros" }
 log = "0.4"
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_feature = { path = "../librustc_feature" }
 rustc_parse = { path = "../librustc_parse" }
 rustc_target = { path = "../librustc_target" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs
index 659780d7a43..4c1eec38c6e 100644
--- a/src/libsyntax_ext/test_harness.rs
+++ b/src/libsyntax_ext/test_harness.rs
@@ -2,13 +2,13 @@
 
 use log::debug;
 use smallvec::{smallvec, SmallVec};
+use rustc_feature::Features;
 use rustc_target::spec::PanicStrategy;
 use syntax::ast::{self, Ident};
 use syntax::attr;
 use syntax::entry::{self, EntryPointType};
 use syntax_expand::base::{ExtCtxt, Resolver};
 use syntax_expand::expand::{AstFragment, ExpansionConfig};
-use syntax::feature_gate::Features;
 use syntax::mut_visit::{*, ExpectOne};
 use syntax::ptr::P;
 use syntax::sess::ParseSess;
diff --git a/src/libsyntax_ext/util.rs b/src/libsyntax_ext/util.rs
index e59daab1770..f7bd9a05604 100644
--- a/src/libsyntax_ext/util.rs
+++ b/src/libsyntax_ext/util.rs
@@ -1,7 +1,7 @@
 use rustc_parse::validate_attr;
+use rustc_feature::AttributeTemplate;
 use syntax_pos::Symbol;
 use syntax::ast::MetaItem;
-use syntax::attr::AttributeTemplate;
 use syntax_expand::base::ExtCtxt;
 
 pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index e2bb49699e9..a116ed282ac 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -445,17 +445,6 @@ extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
   delete unwrap(TM);
 }
 
-// Unfortunately, LLVM doesn't expose a C API to add the corresponding analysis
-// passes for a target to a pass manager. We export that functionality through
-// this function.
-extern "C" void LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM,
-                                          LLVMPassManagerRef PMR,
-                                          LLVMModuleRef M) {
-  PassManagerBase *PM = unwrap(PMR);
-  PM->add(
-      createTargetTransformInfoWrapperPass(unwrap(TM)->getTargetIRAnalysis()));
-}
-
 extern "C" void LLVMRustConfigurePassManagerBuilder(
     LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
     bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
diff --git a/src/test/mir-opt/simplify-arm-identity.rs b/src/test/mir-opt/simplify-arm-identity.rs
new file mode 100644
index 00000000000..a8fa64255fb
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm-identity.rs
@@ -0,0 +1,75 @@
+// Checks that `SimplifyArmIdentity` is not applied if enums have incompatible layouts.
+// Regression test for issue #66856.
+//
+// compile-flags: -Zmir-opt-level=2
+
+enum Src {
+    Foo(u8),
+    Bar,
+}
+
+enum Dst {
+    Foo(u8),
+}
+
+fn main() {
+    let e: Src = Src::Foo(0);
+    let _: Dst = match e {
+        Src::Foo(x) => Dst::Foo(x),
+        Src::Bar => Dst::Foo(0),
+    };
+}
+
+// END RUST SOURCE
+// START rustc.main.SimplifyArmIdentity.before.mir
+// fn main() -> () {
+//     ...
+//     bb0: {
+//         StorageLive(_1);
+//         ((_1 as Foo).0: u8) = const 0u8;
+//         discriminant(_1) = 0;
+//         StorageLive(_2);
+//         _3 = discriminant(_1);
+//         switchInt(move _3) -> [0isize: bb3, 1isize: bb1, otherwise: bb2];
+//     }
+//     bb1: {
+//         ((_2 as Foo).0: u8) = const 0u8;
+//         discriminant(_2) = 0;
+//         goto -> bb4;
+//     }
+//     ...
+//     bb3: {
+//         _4 = ((_1 as Foo).0: u8);
+//         ((_2 as Foo).0: u8) = move _4;
+//         discriminant(_2) = 0;
+//         goto -> bb4;
+//     }
+//     ...
+// }
+// END rustc.main.SimplifyArmIdentity.before.mir
+// START rustc.main.SimplifyArmIdentity.after.mir
+// fn main() -> () {
+//     ...
+//     bb0: {
+//         StorageLive(_1);
+//         ((_1 as Foo).0: u8) = const 0u8;
+//         discriminant(_1) = 0;
+//         StorageLive(_2);
+//         _3 = discriminant(_1);
+//         switchInt(move _3) -> [0isize: bb3, 1isize: bb1, otherwise: bb2];
+//     }
+//     bb1: {
+//         ((_2 as Foo).0: u8) = const 0u8;
+//         discriminant(_2) = 0;
+//         goto -> bb4;
+//     }
+//     ...
+//     bb3: {
+//         _4 = ((_1 as Foo).0: u8);
+//         ((_2 as Foo).0: u8) = move _4;
+//         discriminant(_2) = 0;
+//         goto -> bb4;
+//     }
+//     ...
+// }
+// END rustc.main.SimplifyArmIdentity.after.mir
diff --git a/src/test/ui/issues/issue-66851.rs b/src/test/ui/issues/issue-66851.rs
new file mode 100644
index 00000000000..72d62a30a33
--- /dev/null
+++ b/src/test/ui/issues/issue-66851.rs
@@ -0,0 +1,20 @@
+// This used to mis-compile because the mir-opt `SimplifyArmIdentity`
+// did not check that the types matched up in the `Ok(r)` branch.
+//
+// run-pass
+// compile-flags: -Zmir-opt-level=2
+
+#[derive(Debug, PartialEq, Eq)]
+enum SpecialsRes { Res(u64) }
+
+fn e103() -> SpecialsRes {
+    if let Ok(r) = "1".parse() {
+        SpecialsRes::Res(r)
+    } else {
+        SpecialsRes::Res(42)
+    }
+}
+
+fn main() {
+    assert_eq!(e103(), SpecialsRes::Res(1));
+}
diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs
new file mode 100644
index 00000000000..d7c191bb5a2
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs
@@ -0,0 +1,26 @@
+#![feature(or_patterns)]
+#![feature(slice_patterns)]
+#![allow(incomplete_features)]
+#![deny(unreachable_patterns)]
+
+// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
+fn main() {
+    // Get the fatal error out of the way
+    match (0u8,) {
+        (0 | _,) => {}
+        //~^ ERROR or-patterns are not fully implemented yet
+    }
+
+    match (0u8, 0u8) {
+        //~^ ERROR non-exhaustive patterns: `(2u8..=std::u8::MAX, _)`
+        (0 | 1, 2 | 3) => {}
+    }
+    match ((0u8,),) {
+        //~^ ERROR non-exhaustive patterns: `((4u8..=std::u8::MAX))`
+        ((0 | 1,) | (2 | 3,),) => {},
+    }
+    match (Some(0u8),) {
+        //~^ ERROR non-exhaustive patterns: `(Some(2u8..=std::u8::MAX))`
+        (None | Some(0 | 1),) => {}
+    }
+}
diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
new file mode 100644
index 00000000000..e6aa157d278
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
@@ -0,0 +1,33 @@
+error[E0004]: non-exhaustive patterns: `(2u8..=std::u8::MAX, _)` not covered
+  --> $DIR/exhaustiveness-non-exhaustive.rs:14:11
+   |
+LL |     match (0u8, 0u8) {
+   |           ^^^^^^^^^^ pattern `(2u8..=std::u8::MAX, _)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `((4u8..=std::u8::MAX))` not covered
+  --> $DIR/exhaustiveness-non-exhaustive.rs:18:11
+   |
+LL |     match ((0u8,),) {
+   |           ^^^^^^^^^ pattern `((4u8..=std::u8::MAX))` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `(Some(2u8..=std::u8::MAX))` not covered
+  --> $DIR/exhaustiveness-non-exhaustive.rs:22:11
+   |
+LL |     match (Some(0u8),) {
+   |           ^^^^^^^^^^^^ pattern `(Some(2u8..=std::u8::MAX))` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: or-patterns are not fully implemented yet
+  --> $DIR/exhaustiveness-non-exhaustive.rs:10:10
+   |
+LL |         (0 | _,) => {}
+   |          ^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/or-patterns/exhaustiveness-pass.rs b/src/test/ui/or-patterns/exhaustiveness-pass.rs
new file mode 100644
index 00000000000..62a851719f9
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-pass.rs
@@ -0,0 +1,40 @@
+#![feature(or_patterns)]
+#![feature(slice_patterns)]
+#![allow(incomplete_features)]
+#![deny(unreachable_patterns)]
+
+// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
+fn main() {
+    // Get the fatal error out of the way
+    match (0u8,) {
+        (0 | _,) => {}
+        //~^ ERROR or-patterns are not fully implemented yet
+    }
+
+    match (0u8,) {
+        (1 | 2,) => {}
+        _ => {}
+    }
+
+    match (0u8,) {
+        (1 | 1,) => {} // FIXME(or_patterns): redundancy not detected for now.
+        _ => {}
+    }
+    match (0u8, 0u8) {
+        (1 | 2, 3 | 4) => {}
+        (1, 2) => {}
+        (2, 1) => {}
+        _ => {}
+    }
+    match (Some(0u8),) {
+        (None | Some(0 | 1),) => {}
+        (Some(2..=255),) => {}
+    }
+    match ((0u8,),) {
+        ((0 | 1,) | (2 | 3,),) => {},
+        ((_,),) => {},
+    }
+    match (&[0u8][..],) {
+        ([] | [0 | 1..=255] | [_, ..],) => {},
+    }
+}
diff --git a/src/test/ui/or-patterns/exhaustiveness-pass.stderr b/src/test/ui/or-patterns/exhaustiveness-pass.stderr
new file mode 100644
index 00000000000..1f4278c4b80
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-pass.stderr
@@ -0,0 +1,8 @@
+error: or-patterns are not fully implemented yet
+  --> $DIR/exhaustiveness-pass.rs:10:10
+   |
+LL |         (0 | _,) => {}
+   |          ^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
new file mode 100644
index 00000000000..2cd8ca2dbac
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
@@ -0,0 +1,51 @@
+#![feature(or_patterns)]
+#![feature(slice_patterns)]
+#![allow(incomplete_features)]
+#![deny(unreachable_patterns)]
+
+// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
+fn main() {
+    // Get the fatal error out of the way
+    match (0u8,) {
+        (0 | _,) => {}
+        //~^ ERROR or-patterns are not fully implemented yet
+    }
+
+    match (0u8,) {
+        (1 | 2,) => {}
+        (1,) => {} //~ ERROR unreachable pattern
+        _ => {}
+    }
+    match (0u8,) {
+        (1 | 2,) => {}
+        (2,) => {} //~ ERROR unreachable pattern
+        _ => {}
+    }
+    match (0u8,) {
+        (1,) => {}
+        (2,) => {}
+        (1 | 2,) => {} //~ ERROR unreachable pattern
+        _ => {}
+    }
+    match (0u8, 0u8) {
+        (1 | 2, 3 | 4) => {}
+        (1, 3) => {} //~ ERROR unreachable pattern
+        (1, 4) => {} //~ ERROR unreachable pattern
+        (2, 4) => {} //~ ERROR unreachable pattern
+        (2 | 1, 4) => {} //~ ERROR unreachable pattern
+        (1, 5 | 6) => {}
+        (1, 4 | 5) => {} //~ ERROR unreachable pattern
+        _ => {}
+    }
+    match (Some(0u8),) {
+        (None | Some(1 | 2),) => {}
+        (Some(1),) => {} //~ ERROR unreachable pattern
+        (None,) => {} //~ ERROR unreachable pattern
+        _ => {}
+    }
+    match ((0u8,),) {
+        ((1 | 2,) | (3 | 4,),) => {},
+        ((1..=4,),) => {}, //~ ERROR unreachable pattern
+        _ => {},
+    }
+}
diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
new file mode 100644
index 00000000000..a4d55d805c3
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
@@ -0,0 +1,80 @@
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:16:9
+   |
+LL |         (1,) => {}
+   |         ^^^^
+   |
+note: lint level defined here
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:4:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:21:9
+   |
+LL |         (2,) => {}
+   |         ^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:27:9
+   |
+LL |         (1 | 2,) => {}
+   |         ^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:32:9
+   |
+LL |         (1, 3) => {}
+   |         ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:33:9
+   |
+LL |         (1, 4) => {}
+   |         ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:34:9
+   |
+LL |         (2, 4) => {}
+   |         ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:35:9
+   |
+LL |         (2 | 1, 4) => {}
+   |         ^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
+   |
+LL |         (1, 4 | 5) => {}
+   |         ^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:42:9
+   |
+LL |         (Some(1),) => {}
+   |         ^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:43:9
+   |
+LL |         (None,) => {}
+   |         ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:48:9
+   |
+LL |         ((1..=4,),) => {},
+   |         ^^^^^^^^^^^
+
+error: or-patterns are not fully implemented yet
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:10:10
+   |
+LL |         (0 | _,) => {}
+   |          ^^^^^
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index defe85ef46a..4ea101296b7 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -231,7 +231,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
 }
 
 fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features {
-    let path = base.join("libsyntax/feature_gate").join(file);
+    let path = base.join("librustc_feature").join(file);
     let contents = t!(fs::read_to_string(&path));
 
     // We allow rustc-internal features to omit a tracking issue.