From 8b847ef734e2bf2d424cf111f671978505c04cf1 Mon Sep 17 00:00:00 2001
From: Moulins <arthur.heuillard@orange.fr>
Date: Fri, 23 Jun 2023 21:05:24 +0200
Subject: [PATCH] add crate-local `-Z reference_niches` unstable flag (does
 nothing for now)

---
 compiler/rustc_abi/src/lib.rs                 |  8 +++++
 compiler/rustc_interface/src/tests.rs         |  2 ++
 .../src/rmeta/decoder/cstore_impl.rs          |  1 +
 compiler/rustc_metadata/src/rmeta/encoder.rs  |  1 +
 compiler/rustc_metadata/src/rmeta/mod.rs      |  3 +-
 compiler/rustc_middle/src/query/erase.rs      |  1 +
 compiler/rustc_middle/src/query/mod.rs        |  5 ++++
 compiler/rustc_session/src/config.rs          |  2 ++
 compiler/rustc_session/src/options.rs         | 30 +++++++++++++++++++
 compiler/rustc_ty_utils/src/layout.rs         | 11 +++++--
 10 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index ef0c763ac20..29b3c44dcd6 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -49,6 +49,14 @@ bitflags! {
     }
 }
 
+/// Which niches (beyond the `null` niche) are available on references.
+#[derive(Default, Copy, Clone, Hash, Debug, Eq, PartialEq)]
+#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
+pub struct ReferenceNichePolicy {
+    pub size: bool,
+    pub align: bool,
+}
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
 pub enum IntegerType {
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 5c6c3491b38..49bd7b6aa9c 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -28,6 +28,7 @@ use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
 use rustc_span::FileName;
 use rustc_span::SourceFileHashAlgorithm;
+use rustc_target::abi::ReferenceNichePolicy;
 use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
 use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
 
@@ -819,6 +820,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(profile_emit, Some(PathBuf::from("abc")));
     tracked!(profile_sample_use, Some(PathBuf::from("abc")));
     tracked!(profiler_runtime, "abc".to_string());
+    tracked!(reference_niches, Some(ReferenceNichePolicy { size: true, align: false }));
     tracked!(relax_elf_relocations, Some(true));
     tracked!(relro_level, Some(RelroLevel::Full));
     tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index a8815ee0908..77c33336dff 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -301,6 +301,7 @@ provide! { tcx, def_id, other, cdata,
     is_profiler_runtime => { cdata.root.profiler_runtime }
     required_panic_strategy => { cdata.root.required_panic_strategy }
     panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy }
+    reference_niches_policy => { cdata.root.reference_niches_policy }
     extern_crate => {
         let r = *cdata.extern_crate.lock();
         r.map(|c| &*tcx.arena.alloc(c))
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index ac86110f2bd..46571e7796d 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -673,6 +673,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(),
                 required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE),
                 panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
+                reference_niches_policy: tcx.reference_niches_policy(LOCAL_CRATE),
                 edition: tcx.sess.edition(),
                 has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
                 has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE),
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 0bc16fc64ff..8bc2e0aa5a9 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -32,7 +32,7 @@ use rustc_span::edition::Edition;
 use rustc_span::hygiene::{ExpnIndex, MacroKind};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span};
-use rustc_target::abi::{FieldIdx, VariantIdx};
+use rustc_target::abi::{FieldIdx, ReferenceNichePolicy, VariantIdx};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
 
 use std::marker::PhantomData;
@@ -251,6 +251,7 @@ pub(crate) struct CrateRoot {
     stable_crate_id: StableCrateId,
     required_panic_strategy: Option<PanicStrategy>,
     panic_in_drop_strategy: PanicStrategy,
+    reference_niches_policy: ReferenceNichePolicy,
     edition: Edition,
     has_global_allocator: bool,
     has_alloc_error_handler: bool,
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index a0cb23b5a4c..9bf02267005 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -296,6 +296,7 @@ trivial! {
     rustc_span::Symbol,
     rustc_span::symbol::Ident,
     rustc_target::spec::PanicStrategy,
+    rustc_target::abi::ReferenceNichePolicy,
     rustc_type_ir::Variance,
     u32,
     usize,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index c728cc0b39f..51409f90843 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1480,6 +1480,11 @@ rustc_queries! {
         desc { "getting a crate's configured panic-in-drop strategy" }
         separate_provide_extern
     }
+    query reference_niches_policy(_: CrateNum) -> abi::ReferenceNichePolicy {
+        fatal_cycle
+        desc { "getting a crate's policy for size and alignment niches of references" }
+        separate_provide_extern
+    }
     query is_no_builtins(_: CrateNum) -> bool {
         fatal_cycle
         desc { "getting whether a crate has `#![no_builtins]`" }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 593983f117d..43dae9e8de2 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3076,6 +3076,7 @@ pub(crate) mod dep_tracking {
     use rustc_feature::UnstableFeatures;
     use rustc_span::edition::Edition;
     use rustc_span::RealFileName;
+    use rustc_target::abi::ReferenceNichePolicy;
     use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
     use rustc_target::spec::{
         RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
@@ -3171,6 +3172,7 @@ pub(crate) mod dep_tracking {
         OomStrategy,
         LanguageIdentifier,
         TraitSolver,
+        ReferenceNichePolicy,
     );
 
     impl<T1, T2> DepTrackingHash for (T1, T2)
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 87d67c099ce..0d63db2bfef 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -6,6 +6,7 @@ use crate::{lint, EarlyErrorHandler};
 use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::ColorConfig;
 use rustc_errors::{LanguageIdentifier, TerminalUrl};
+use rustc_target::abi::ReferenceNichePolicy;
 use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
 use rustc_target::spec::{
     RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
@@ -421,6 +422,8 @@ mod desc {
     pub const parse_proc_macro_execution_strategy: &str =
         "one of supported execution strategies (`same-thread`, or `cross-thread`)";
     pub const parse_dump_solver_proof_tree: &str = "one of: `always`, `on-request`, `on-error`";
+    pub const parse_opt_reference_niches: &str =
+        "`null`, or a `,` separated combination of `size` or `align`";
 }
 
 mod parse {
@@ -1253,6 +1256,31 @@ mod parse {
         };
         true
     }
+
+    pub(crate) fn parse_opt_reference_niches(
+        slot: &mut Option<ReferenceNichePolicy>,
+        v: Option<&str>,
+    ) -> bool {
+        let Some(s) = v else {
+            return false;
+        };
+
+        let slot = slot.get_or_insert_default();
+
+        if s == "null" {
+            return true;
+        }
+
+        for opt in s.split(",") {
+            match opt {
+                "size" => slot.size = true,
+                "align" => slot.align = true,
+                _ => return false,
+            }
+        }
+
+        true
+    }
 }
 
 options! {
@@ -1698,6 +1726,8 @@ options! {
         "enable queries of the dependency graph for regression testing (default: no)"),
     randomize_layout: bool = (false, parse_bool, [TRACKED],
         "randomize the layout of types (default: no)"),
+    reference_niches: Option<ReferenceNichePolicy> = (None, parse_opt_reference_niches, [TRACKED],
+        "override the set of discriminant niches that may be exposed by references"),
     relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "whether ELF relocations can be relaxed"),
     relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 2afe1cb37bb..19545a1b135 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -3,7 +3,7 @@ use rustc_hir as hir;
 use rustc_index::bit_set::BitSet;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::mir::{GeneratorLayout, GeneratorSavedLocal};
-use rustc_middle::query::Providers;
+use rustc_middle::query::{LocalCrate, Providers};
 use rustc_middle::ty::layout::{
     IntegerExt, LayoutCx, LayoutError, LayoutOf, NaiveLayout, TyAndLayout, TyAndNaiveLayout,
     MAX_SIMD_LANES,
@@ -25,7 +25,14 @@ use crate::errors::{
 use crate::layout_sanity_check::sanity_check_layout;
 
 pub fn provide(providers: &mut Providers) {
-    *providers = Providers { layout_of, naive_layout_of, ..*providers };
+    *providers = Providers { layout_of, naive_layout_of, reference_niches_policy, ..*providers };
+}
+
+#[instrument(skip(tcx), level = "debug")]
+fn reference_niches_policy<'tcx>(tcx: TyCtxt<'tcx>, _: LocalCrate) -> ReferenceNichePolicy {
+    const DEFAULT: ReferenceNichePolicy = ReferenceNichePolicy { size: false, align: false };
+
+    tcx.sess.opts.unstable_opts.reference_niches.unwrap_or(DEFAULT)
 }
 
 #[instrument(skip(tcx, query), level = "debug")]