about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-12-21 19:38:51 +0000
committerbors <bors@rust-lang.org>2022-12-21 19:38:51 +0000
commitc2840c809ac129e1358ab93189405e682695dd65 (patch)
tree0d6e8bdb94b2d82f91308e15d711d23bfb8d40c0
parent3c00b19b0a424b2f42cbce8f8ae84b51b2429572 (diff)
parenta694c342fa5b121de7562e4bd8beca3f7a8b8d97 (diff)
downloadrust-c2840c809ac129e1358ab93189405e682695dd65.tar.gz
rust-c2840c809ac129e1358ab93189405e682695dd65.zip
Auto merge of #13814 - Veykril:layout, r=Veykril
Calculate the TargetDataLayout correctly for the selected target

This fails the tests still since those don't call into rustc yet
-rw-r--r--crates/base-db/src/fixture.rs8
-rw-r--r--crates/base-db/src/input.rs13
-rw-r--r--crates/hir-def/src/layout.rs2
-rw-r--r--crates/hir-ty/src/db.rs4
-rw-r--r--crates/hir-ty/src/layout.rs22
-rw-r--r--crates/hir-ty/src/layout/adt.rs8
-rw-r--r--crates/hir-ty/src/layout/target.rs155
-rw-r--r--crates/hir-ty/src/layout/tests.rs44
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/ide/src/lib.rs1
-rw-r--r--crates/ide/src/shuffle_crate_graph.rs1
-rw-r--r--crates/project-model/src/lib.rs1
-rw-r--r--crates/project-model/src/rustc_cfg.rs2
-rw-r--r--crates/project-model/src/target_data_layout.rs40
-rw-r--r--crates/project-model/src/tests.rs27
-rw-r--r--crates/project-model/src/workspace.rs60
-rw-r--r--crates/rust-analyzer/src/reload.rs1
-rw-r--r--crates/test-utils/src/fixture.rs4
18 files changed, 318 insertions, 77 deletions
diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs
index 5b7828a2699..83286cf6b77 100644
--- a/crates/base-db/src/fixture.rs
+++ b/crates/base-db/src/fixture.rs
@@ -162,6 +162,7 @@ impl ChangeFixture {
                     Ok(Vec::new()),
                     false,
                     origin,
+                    meta.target_data_layout.as_deref().map(Arc::from),
                 );
                 let prev = crates.insert(crate_name.clone(), crate_id);
                 assert!(prev.is_none());
@@ -197,6 +198,7 @@ impl ChangeFixture {
                 Ok(Vec::new()),
                 false,
                 CrateOrigin::CratesIo { repo: None, name: None },
+                None,
             );
         } else {
             for (from, to, prelude) in crate_deps {
@@ -210,6 +212,8 @@ impl ChangeFixture {
                     .unwrap();
             }
         }
+        let target_layout =
+            crate_graph.iter().next().and_then(|it| crate_graph[it].target_layout.clone());
 
         if let Some(mini_core) = mini_core {
             let core_file = file_id;
@@ -234,6 +238,7 @@ impl ChangeFixture {
                 Ok(Vec::new()),
                 false,
                 CrateOrigin::Lang(LangCrateOrigin::Core),
+                target_layout.clone(),
             );
 
             for krate in all_crates {
@@ -271,6 +276,7 @@ impl ChangeFixture {
                 Ok(proc_macro),
                 true,
                 CrateOrigin::CratesIo { repo: None, name: None },
+                target_layout,
             );
 
             for krate in all_crates {
@@ -391,6 +397,7 @@ struct FileMeta {
     edition: Edition,
     env: Env,
     introduce_new_source_root: Option<SourceRootKind>,
+    target_data_layout: Option<String>,
 }
 
 fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option<String>) {
@@ -434,6 +441,7 @@ impl From<Fixture> for FileMeta {
                 "library" => SourceRootKind::Library,
                 invalid => panic!("invalid source root kind '{}'", invalid),
             }),
+            target_data_layout: f.target_data_layout,
         }
     }
 }
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index e7f0c4ec29b..7aff9b1ae84 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -270,6 +270,7 @@ pub struct CrateData {
     pub display_name: Option<CrateDisplayName>,
     pub cfg_options: CfgOptions,
     pub potential_cfg_options: CfgOptions,
+    pub target_layout: Option<Arc<str>>,
     pub env: Env,
     pub dependencies: Vec<Dependency>,
     pub proc_macro: ProcMacroLoadResult,
@@ -328,6 +329,7 @@ impl CrateGraph {
         proc_macro: ProcMacroLoadResult,
         is_proc_macro: bool,
         origin: CrateOrigin,
+        target_layout: Option<Arc<str>>,
     ) -> CrateId {
         let data = CrateData {
             root_file_id,
@@ -340,6 +342,7 @@ impl CrateGraph {
             proc_macro,
             dependencies: Vec::new(),
             origin,
+            target_layout,
             is_proc_macro,
         };
         let crate_id = CrateId(self.arena.len() as u32);
@@ -649,6 +652,7 @@ mod tests {
             Ok(Vec::new()),
             false,
             CrateOrigin::CratesIo { repo: None, name: None },
+            None,
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -661,6 +665,7 @@ mod tests {
             Ok(Vec::new()),
             false,
             CrateOrigin::CratesIo { repo: None, name: None },
+            None,
         );
         let crate3 = graph.add_crate_root(
             FileId(3u32),
@@ -673,6 +678,7 @@ mod tests {
             Ok(Vec::new()),
             false,
             CrateOrigin::CratesIo { repo: None, name: None },
+            None,
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -699,6 +705,7 @@ mod tests {
             Ok(Vec::new()),
             false,
             CrateOrigin::CratesIo { repo: None, name: None },
+            None,
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -711,6 +718,7 @@ mod tests {
             Ok(Vec::new()),
             false,
             CrateOrigin::CratesIo { repo: None, name: None },
+            None,
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -734,6 +742,7 @@ mod tests {
             Ok(Vec::new()),
             false,
             CrateOrigin::CratesIo { repo: None, name: None },
+            None,
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -746,6 +755,7 @@ mod tests {
             Ok(Vec::new()),
             false,
             CrateOrigin::CratesIo { repo: None, name: None },
+            None,
         );
         let crate3 = graph.add_crate_root(
             FileId(3u32),
@@ -758,6 +768,7 @@ mod tests {
             Ok(Vec::new()),
             false,
             CrateOrigin::CratesIo { repo: None, name: None },
+            None,
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -781,6 +792,7 @@ mod tests {
             Ok(Vec::new()),
             false,
             CrateOrigin::CratesIo { repo: None, name: None },
+            None,
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -793,6 +805,7 @@ mod tests {
             Ok(Vec::new()),
             false,
             CrateOrigin::CratesIo { repo: None, name: None },
+            None,
         );
         assert!(graph
             .add_dep(
diff --git a/crates/hir-def/src/layout.rs b/crates/hir-def/src/layout.rs
index a427c464bc0..6bb4cd94f8a 100644
--- a/crates/hir-def/src/layout.rs
+++ b/crates/hir-def/src/layout.rs
@@ -6,7 +6,7 @@ use la_arena::{Idx, RawIdx};
 pub use rustc_abi::{
     Abi, AbiAndPrefAlign, AddressSpace, Align, Endian, FieldsShape, Integer, IntegerType,
     LayoutCalculator, Niche, Primitive, ReprFlags, ReprOptions, Scalar, Size, StructKind,
-    TargetDataLayout, WrappingRange,
+    TargetDataLayout, TargetDataLayoutErrors, WrappingRange,
 };
 
 use crate::LocalEnumVariantId;
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 23ad335aac7..54b244620fb 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -64,8 +64,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::cycle(crate::layout::layout_of_adt_recover)]
     fn layout_of_adt(&self, def: AdtId, subst: Substitution) -> Result<Layout, LayoutError>;
 
-    #[salsa::invoke(crate::layout::current_target_data_layout_query)]
-    fn current_target_data_layout(&self) -> Arc<TargetDataLayout>;
+    #[salsa::invoke(crate::layout::target_data_layout_query)]
+    fn target_data_layout(&self, krate: CrateId) -> Arc<TargetDataLayout>;
 
     #[salsa::invoke(crate::lower::callable_item_sig)]
     fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs
index f4f3c723ab7..209072176c4 100644
--- a/crates/hir-ty/src/layout.rs
+++ b/crates/hir-ty/src/layout.rs
@@ -2,6 +2,7 @@
 
 use std::sync::Arc;
 
+use base_db::CrateId;
 use chalk_ir::{AdtId, TyKind};
 use hir_def::{
     layout::{
@@ -17,7 +18,7 @@ use crate::{db::HirDatabase, Interner, Substitution, Ty};
 use self::adt::struct_variant_idx;
 pub use self::{
     adt::{layout_of_adt_query, layout_of_adt_recover},
-    target::current_target_data_layout_query,
+    target::target_data_layout_query,
 };
 
 macro_rules! user_error {
@@ -31,6 +32,7 @@ mod target;
 
 struct LayoutCx<'a> {
     db: &'a dyn HirDatabase,
+    krate: CrateId,
 }
 
 impl LayoutCalculator for LayoutCx<'_> {
@@ -41,7 +43,7 @@ impl LayoutCalculator for LayoutCx<'_> {
     }
 
     fn current_data_layout(&self) -> Arc<TargetDataLayout> {
-        self.db.current_target_data_layout()
+        self.db.target_data_layout(self.krate)
     }
 }
 
@@ -53,9 +55,9 @@ fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout {
     Layout::scalar(dl, scalar_unit(dl, value))
 }
 
-pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError> {
-    let dl = &*db.current_target_data_layout();
-    let cx = LayoutCx { db };
+pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Layout, LayoutError> {
+    let cx = LayoutCx { db, krate };
+    let dl = &*cx.current_data_layout();
     Ok(match ty.kind(Interner) {
         TyKind::Adt(AdtId(def), subst) => db.layout_of_adt(*def, subst.clone())?,
         TyKind::Scalar(s) => match s {
@@ -84,7 +86,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError
                         chalk_ir::IntTy::I64 => Integer::I64,
                         chalk_ir::IntTy::I128 => Integer::I128,
                     },
-                    false,
+                    true,
                 ),
             ),
             chalk_ir::Scalar::Uint(i) => scalar(
@@ -98,7 +100,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError
                         chalk_ir::UintTy::U64 => Integer::I64,
                         chalk_ir::UintTy::U128 => Integer::I128,
                     },
-                    true,
+                    false,
                 ),
             ),
             chalk_ir::Scalar::Float(f) => scalar(
@@ -114,7 +116,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError
 
             let fields = tys
                 .iter(Interner)
-                .map(|k| layout_of_ty(db, k.assert_ty_ref(Interner)))
+                .map(|k| layout_of_ty(db, k.assert_ty_ref(Interner), krate))
                 .collect::<Result<Vec<_>, _>>()?;
             let fields = fields.iter().collect::<Vec<_>>();
             let fields = fields.iter().collect::<Vec<_>>();
@@ -132,7 +134,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError
                 },
                 _ => return Err(LayoutError::HasPlaceholder),
             };
-            let element = layout_of_ty(db, element)?;
+            let element = layout_of_ty(db, element, krate)?;
             let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?;
 
             let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) {
@@ -153,7 +155,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError
             }
         }
         TyKind::Slice(element) => {
-            let element = layout_of_ty(db, element)?;
+            let element = layout_of_ty(db, element, krate)?;
             Layout {
                 variants: Variants::Single { index: struct_variant_idx() },
                 fields: FieldsShape::Array { stride: element.size, count: 0 },
diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs
index e9382955356..23166a5a522 100644
--- a/crates/hir-ty/src/layout/adt.rs
+++ b/crates/hir-ty/src/layout/adt.rs
@@ -5,7 +5,7 @@ use std::ops::Bound;
 use hir_def::{
     adt::VariantData,
     layout::{Integer, IntegerExt, Layout, LayoutCalculator, LayoutError, RustcEnumVariantIdx},
-    AdtId, EnumVariantId, LocalEnumVariantId, VariantId,
+    AdtId, EnumVariantId, HasModule, LocalEnumVariantId, VariantId,
 };
 use la_arena::RawIdx;
 use smallvec::SmallVec;
@@ -23,12 +23,12 @@ pub fn layout_of_adt_query(
     def: AdtId,
     subst: Substitution,
 ) -> Result<Layout, LayoutError> {
-    let dl = db.current_target_data_layout();
-    let cx = LayoutCx { db };
+    let cx = LayoutCx { db, krate: def.module(db.upcast()).krate() };
+    let dl = cx.current_data_layout();
     let handle_variant = |def: VariantId, var: &VariantData| {
         var.fields()
             .iter()
-            .map(|(fd, _)| layout_of_ty(db, &field_ty(db, def, fd, &subst)))
+            .map(|(fd, _)| layout_of_ty(db, &field_ty(db, def, fd, &subst), cx.krate))
             .collect::<Result<Vec<_>, _>>()
     };
     let (variants, is_enum, is_union, repr) = match def {
diff --git a/crates/hir-ty/src/layout/target.rs b/crates/hir-ty/src/layout/target.rs
index b248031f152..54fa0fd9ea5 100644
--- a/crates/hir-ty/src/layout/target.rs
+++ b/crates/hir-ty/src/layout/target.rs
@@ -2,45 +2,130 @@
 
 use std::sync::Arc;
 
-use hir_def::layout::TargetDataLayout;
+use base_db::CrateId;
+use hir_def::layout::{TargetDataLayout, TargetDataLayoutErrors};
 
 use crate::db::HirDatabase;
 
-use hir_def::layout::{AbiAndPrefAlign, AddressSpace, Align, Endian, Integer, Size};
+use hir_def::layout::{AbiAndPrefAlign, AddressSpace, Align, Endian, Size};
 
-pub fn current_target_data_layout_query(db: &dyn HirDatabase) -> Arc<TargetDataLayout> {
+pub fn target_data_layout_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<TargetDataLayout> {
     let crate_graph = db.crate_graph();
-    let cfg_options = &crate_graph[crate_graph.iter().next().unwrap()].cfg_options;
-    let endian = match cfg_options.get_cfg_values("target_endian").next() {
-        Some(x) if x.as_str() == "big" => Endian::Big,
-        _ => Endian::Little,
+    let target_layout = &crate_graph[krate].target_layout;
+    let cfg_options = &crate_graph[krate].cfg_options;
+    Arc::new(
+        target_layout
+            .as_ref()
+            .and_then(|it| parse_from_llvm_datalayout_string(it).ok())
+            .unwrap_or_else(|| {
+                let endian = match cfg_options.get_cfg_values("target_endian").next() {
+                    Some(x) if x.as_str() == "big" => Endian::Big,
+                    _ => Endian::Little,
+                };
+                let pointer_size = Size::from_bytes(
+                    match cfg_options.get_cfg_values("target_pointer_width").next() {
+                        Some(x) => match x.as_str() {
+                            "16" => 2,
+                            "32" => 4,
+                            _ => 8,
+                        },
+                        _ => 8,
+                    },
+                );
+                TargetDataLayout { endian, pointer_size, ..TargetDataLayout::default() }
+            }),
+    )
+}
+
+/// copied from rustc as it is not exposed yet
+fn parse_from_llvm_datalayout_string<'a>(
+    input: &'a str,
+) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
+    // Parse an address space index from a string.
+    let parse_address_space = |s: &'a str, cause: &'a str| {
+        s.parse::<u32>().map(AddressSpace).map_err(|err| {
+            TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err }
+        })
     };
-    let pointer_size =
-        Size::from_bytes(match cfg_options.get_cfg_values("target_pointer_width").next() {
-            Some(x) => match x.as_str() {
-                "16" => 2,
-                "32" => 4,
-                _ => 8,
-            },
-            _ => 8,
-        });
-    // FIXME: These values are incorrect for many architectures, at least for aarch64 and riscv64,
-    // use `rustc +nightly -Z unstable-options --print target-spec-json` or something similar instead.
-    Arc::new(TargetDataLayout {
-        endian,
-        i1_align: AbiAndPrefAlign::new(Align::from_bytes(1).unwrap()),
-        i8_align: AbiAndPrefAlign::new(Align::from_bytes(1).unwrap()),
-        i16_align: AbiAndPrefAlign::new(Align::from_bytes(2).unwrap()),
-        i32_align: AbiAndPrefAlign::new(Align::from_bytes(4).unwrap()),
-        i64_align: AbiAndPrefAlign::new(Align::from_bytes(8).unwrap()),
-        i128_align: AbiAndPrefAlign::new(Align::from_bytes(8).unwrap()),
-        f32_align: AbiAndPrefAlign::new(Align::from_bytes(4).unwrap()),
-        f64_align: AbiAndPrefAlign::new(Align::from_bytes(8).unwrap()),
-        pointer_size,
-        pointer_align: AbiAndPrefAlign::new(Align::from_bytes(pointer_size.bytes()).unwrap()),
-        aggregate_align: AbiAndPrefAlign::new(Align::from_bytes(1).unwrap()),
-        vector_align: vec![],
-        instruction_address_space: AddressSpace(0),
-        c_enum_min_size: Integer::I32,
-    })
+
+    // Parse a bit count from a string.
+    let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| {
+        s.parse::<u64>().map_err(|err| TargetDataLayoutErrors::InvalidBits {
+            kind,
+            bit: s,
+            cause,
+            err,
+        })
+    };
+
+    // Parse a size string.
+    let size = |s: &'a str, cause: &'a str| parse_bits(s, "size", cause).map(Size::from_bits);
+
+    // Parse an alignment string.
+    let align = |s: &[&'a str], cause: &'a str| {
+        if s.is_empty() {
+            return Err(TargetDataLayoutErrors::MissingAlignment { cause });
+        }
+        let align_from_bits = |bits| {
+            Align::from_bits(bits)
+                .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err })
+        };
+        let abi = parse_bits(s[0], "alignment", cause)?;
+        let pref = s.get(1).map_or(Ok(abi), |pref| parse_bits(pref, "alignment", cause))?;
+        Ok(AbiAndPrefAlign { abi: align_from_bits(abi)?, pref: align_from_bits(pref)? })
+    };
+
+    let mut dl = TargetDataLayout::default();
+    let mut i128_align_src = 64;
+    for spec in input.split('-') {
+        let spec_parts = spec.split(':').collect::<Vec<_>>();
+
+        match &*spec_parts {
+            ["e"] => dl.endian = Endian::Little,
+            ["E"] => dl.endian = Endian::Big,
+            [p] if p.starts_with('P') => {
+                dl.instruction_address_space = parse_address_space(&p[1..], "P")?
+            }
+            ["a", ref a @ ..] => dl.aggregate_align = align(a, "a")?,
+            ["f32", ref a @ ..] => dl.f32_align = align(a, "f32")?,
+            ["f64", ref a @ ..] => dl.f64_align = align(a, "f64")?,
+            [p @ "p", s, ref a @ ..] | [p @ "p0", s, ref a @ ..] => {
+                dl.pointer_size = size(s, p)?;
+                dl.pointer_align = align(a, p)?;
+            }
+            [s, ref a @ ..] if s.starts_with('i') => {
+                let Ok(bits) = s[1..].parse::<u64>() else {
+                    size(&s[1..], "i")?; // For the user error.
+                    continue;
+                };
+                let a = align(a, s)?;
+                match bits {
+                    1 => dl.i1_align = a,
+                    8 => dl.i8_align = a,
+                    16 => dl.i16_align = a,
+                    32 => dl.i32_align = a,
+                    64 => dl.i64_align = a,
+                    _ => {}
+                }
+                if bits >= i128_align_src && bits <= 128 {
+                    // Default alignment for i128 is decided by taking the alignment of
+                    // largest-sized i{64..=128}.
+                    i128_align_src = bits;
+                    dl.i128_align = a;
+                }
+            }
+            [s, ref a @ ..] if s.starts_with('v') => {
+                let v_size = size(&s[1..], "v")?;
+                let a = align(a, s)?;
+                if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
+                    v.1 = a;
+                    continue;
+                }
+                // No existing entry, add a new one.
+                dl.vector_align.push((v_size, a));
+            }
+            _ => {} // Ignore everything else.
+        }
+    }
+    Ok(dl)
 }
diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs
index 5d97a69501f..ba821235f3f 100644
--- a/crates/hir-ty/src/layout/tests.rs
+++ b/crates/hir-ty/src/layout/tests.rs
@@ -9,8 +9,22 @@ use crate::{test_db::TestDB, Interner, Substitution};
 
 use super::layout_of_ty;
 
-fn eval_goal(ra_fixture: &str) -> Result<Layout, LayoutError> {
-    let (db, file_id) = TestDB::with_single_file(ra_fixture);
+fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Layout, LayoutError> {
+    // using unstable cargo features failed, fall back to using plain rustc
+    let mut cmd = std::process::Command::new("rustc");
+    cmd.args(&["-Z", "unstable-options", "--print", "target-spec-json"])
+        .env("RUSTC_BOOTSTRAP", "1");
+    let output = cmd.output().unwrap();
+    assert!(output.status.success(), "{}", output.status);
+    let stdout = String::from_utf8(output.stdout).unwrap();
+    let target_data_layout =
+        stdout.split_once(r#""data-layout": ""#).unwrap().1.split_once('"').unwrap().0.to_owned();
+
+    let ra_fixture = format!(
+        "{minicore}//- /main.rs crate:test target_data_layout:{target_data_layout}\n{ra_fixture}",
+    );
+
+    let (db, file_id) = TestDB::with_single_file(&ra_fixture);
     let module_id = db.module_for_file(file_id);
     let def_map = module_id.def_map(&db);
     let scope = &def_map[module_id.local_id].scope;
@@ -20,31 +34,29 @@ fn eval_goal(ra_fixture: &str) -> Result<Layout, LayoutError> {
         .find_map(|x| match x {
             hir_def::ModuleDefId::AdtId(x) => {
                 let name = match x {
-                    hir_def::AdtId::StructId(x) => db.struct_data(x).name.to_string(),
-                    hir_def::AdtId::UnionId(x) => db.union_data(x).name.to_string(),
-                    hir_def::AdtId::EnumId(x) => db.enum_data(x).name.to_string(),
+                    hir_def::AdtId::StructId(x) => db.struct_data(x).name.to_smol_str(),
+                    hir_def::AdtId::UnionId(x) => db.union_data(x).name.to_smol_str(),
+                    hir_def::AdtId::EnumId(x) => db.enum_data(x).name.to_smol_str(),
                 };
-                if name == "Goal" {
-                    Some(x)
-                } else {
-                    None
-                }
+                (name == "Goal").then(|| x)
             }
             _ => None,
         })
         .unwrap();
     let goal_ty = TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner);
-    layout_of_ty(&db, &goal_ty)
+    layout_of_ty(&db, &goal_ty, module_id.krate())
 }
 
-fn check_size_and_align(ra_fixture: &str, size: u64, align: u64) {
-    let l = eval_goal(ra_fixture).unwrap();
+#[track_caller]
+fn check_size_and_align(ra_fixture: &str, minicore: &str, size: u64, align: u64) {
+    let l = eval_goal(ra_fixture, minicore).unwrap();
     assert_eq!(l.size.bytes(), size);
     assert_eq!(l.align.abi.bytes(), align);
 }
 
+#[track_caller]
 fn check_fail(ra_fixture: &str, e: LayoutError) {
-    let r = eval_goal(ra_fixture);
+    let r = eval_goal(ra_fixture, "");
     assert_eq!(r, Err(e));
 }
 
@@ -54,7 +66,8 @@ macro_rules! size_and_align {
             #[allow(dead_code)]
             $($t)*
             check_size_and_align(
-                &format!("//- minicore: {}\n{}", stringify!($($x),*), stringify!($($t)*)),
+                stringify!($($t)*),
+                &format!("//- minicore: {}\n", stringify!($($x),*)),
                 ::std::mem::size_of::<Goal>() as u64,
                 ::std::mem::align_of::<Goal>() as u64,
             );
@@ -66,6 +79,7 @@ macro_rules! size_and_align {
             $($t)*
             check_size_and_align(
                 stringify!($($t)*),
+                "",
                 ::std::mem::size_of::<Goal>() as u64,
                 ::std::mem::align_of::<Goal>() as u64,
             );
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b841e580b6c..cc983ee0142 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -866,7 +866,7 @@ impl Field {
     }
 
     pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
-        layout_of_ty(db, &self.ty(db).ty)
+        layout_of_ty(db, &self.ty(db).ty, self.parent.module(db).krate().into())
     }
 
     pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 7402e86f36f..6698bf766a0 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -236,6 +236,7 @@ impl Analysis {
             Ok(Vec::new()),
             false,
             CrateOrigin::CratesIo { repo: None, name: None },
+            None,
         );
         change.change_file(file_id, Some(Arc::new(text)));
         change.set_crate_graph(crate_graph);
diff --git a/crates/ide/src/shuffle_crate_graph.rs b/crates/ide/src/shuffle_crate_graph.rs
index 2d86627643d..ae539a5d397 100644
--- a/crates/ide/src/shuffle_crate_graph.rs
+++ b/crates/ide/src/shuffle_crate_graph.rs
@@ -36,6 +36,7 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
             data.proc_macro.clone(),
             data.is_proc_macro,
             data.origin.clone(),
+            data.target_layout.clone(),
         );
         map.insert(old_id, new_id);
     }
diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs
index 575581fa543..835f2b3dd03 100644
--- a/crates/project-model/src/lib.rs
+++ b/crates/project-model/src/lib.rs
@@ -25,6 +25,7 @@ mod sysroot;
 mod workspace;
 mod rustc_cfg;
 mod build_scripts;
+mod target_data_layout;
 
 #[cfg(test)]
 mod tests;
diff --git a/crates/project-model/src/rustc_cfg.rs b/crates/project-model/src/rustc_cfg.rs
index 32313618366..12c8cf70dc0 100644
--- a/crates/project-model/src/rustc_cfg.rs
+++ b/crates/project-model/src/rustc_cfg.rs
@@ -50,7 +50,7 @@ fn get_rust_cfgs(
         cargo_config.envs(extra_env);
         cargo_config
             .current_dir(cargo_toml.parent())
-            .args(&["-Z", "unstable-options", "rustc", "--print", "cfg"])
+            .args(&["rustc", "-Z", "unstable-options", "--print", "cfg"])
             .env("RUSTC_BOOTSTRAP", "1");
         if let Some(target) = target {
             cargo_config.args(&["--target", target]);
diff --git a/crates/project-model/src/target_data_layout.rs b/crates/project-model/src/target_data_layout.rs
new file mode 100644
index 00000000000..b9d7d2338c3
--- /dev/null
+++ b/crates/project-model/src/target_data_layout.rs
@@ -0,0 +1,40 @@
+//! Runs `rustc --print target-spec-json` to get the target_data_layout.
+use std::process::Command;
+
+use rustc_hash::FxHashMap;
+
+use crate::{utf8_stdout, ManifestPath};
+
+pub(super) fn get(
+    cargo_toml: Option<&ManifestPath>,
+    target: Option<&str>,
+    extra_env: &FxHashMap<String, String>,
+) -> Option<String> {
+    let output = (|| {
+        if let Some(cargo_toml) = cargo_toml {
+            let mut cmd = Command::new(toolchain::rustc());
+            cmd.envs(extra_env);
+            cmd.current_dir(cargo_toml.parent())
+                .args(&["-Z", "unstable-options", "rustc", "--print", "target-spec-json"])
+                .env("RUSTC_BOOTSTRAP", "1");
+            if let Some(target) = target {
+                cmd.args(&["--target", target]);
+            }
+            match utf8_stdout(cmd) {
+                Ok(it) => return Ok(it),
+                Err(e) => tracing::debug!("{e:?}: falling back to querying rustc for cfgs"),
+            }
+        }
+        // using unstable cargo features failed, fall back to using plain rustc
+        let mut cmd = Command::new(toolchain::rustc());
+        cmd.envs(extra_env)
+            .args(&["-Z", "unstable-options", "rustc", "--print", "target-spec-json"])
+            .env("RUSTC_BOOTSTRAP", "1");
+        if let Some(target) = target {
+            cmd.args(&["--target", target]);
+        }
+        utf8_stdout(cmd)
+    })()
+    .ok()?;
+    Some(output.split_once(r#""data-layout": ""#)?.1.split_once('"')?.0.to_owned())
+}
diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs
index a1cb438bddc..adb106e9793 100644
--- a/crates/project-model/src/tests.rs
+++ b/crates/project-model/src/tests.rs
@@ -29,6 +29,7 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGr
         rustc_cfg: Vec::new(),
         cfg_overrides,
         toolchain: None,
+        target_layout: None,
     };
     to_crate_graph(project_workspace)
 }
@@ -150,6 +151,7 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                                 "debug_assertions",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -219,6 +221,7 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                                 "debug_assertions",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -297,6 +300,7 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                                 "debug_assertions",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -375,6 +379,7 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                                 "debug_assertions",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -462,6 +467,7 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                                 "feature=use_std",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -547,6 +553,7 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                                 "test",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -618,6 +625,7 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                                 "test",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -698,6 +706,7 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                                 "test",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -778,6 +787,7 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                                 "test",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -865,6 +875,7 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                                 "feature=use_std",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -941,6 +952,7 @@ fn cargo_hello_world_project_model() {
                                 "test",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -1012,6 +1024,7 @@ fn cargo_hello_world_project_model() {
                                 "test",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -1092,6 +1105,7 @@ fn cargo_hello_world_project_model() {
                                 "test",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -1172,6 +1186,7 @@ fn cargo_hello_world_project_model() {
                                 "test",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -1259,6 +1274,7 @@ fn cargo_hello_world_project_model() {
                                 "feature=use_std",
                             ],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
@@ -1327,6 +1343,7 @@ fn rust_project_hello_world_project_model() {
                         potential_cfg_options: CfgOptions(
                             [],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {},
                         },
@@ -1371,6 +1388,7 @@ fn rust_project_hello_world_project_model() {
                         potential_cfg_options: CfgOptions(
                             [],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {},
                         },
@@ -1405,6 +1423,7 @@ fn rust_project_hello_world_project_model() {
                         potential_cfg_options: CfgOptions(
                             [],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {},
                         },
@@ -1439,6 +1458,7 @@ fn rust_project_hello_world_project_model() {
                         potential_cfg_options: CfgOptions(
                             [],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {},
                         },
@@ -1473,6 +1493,7 @@ fn rust_project_hello_world_project_model() {
                         potential_cfg_options: CfgOptions(
                             [],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {},
                         },
@@ -1517,6 +1538,7 @@ fn rust_project_hello_world_project_model() {
                         potential_cfg_options: CfgOptions(
                             [],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {},
                         },
@@ -1551,6 +1573,7 @@ fn rust_project_hello_world_project_model() {
                         potential_cfg_options: CfgOptions(
                             [],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {},
                         },
@@ -1658,6 +1681,7 @@ fn rust_project_hello_world_project_model() {
                         potential_cfg_options: CfgOptions(
                             [],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {},
                         },
@@ -1692,6 +1716,7 @@ fn rust_project_hello_world_project_model() {
                         potential_cfg_options: CfgOptions(
                             [],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {},
                         },
@@ -1726,6 +1751,7 @@ fn rust_project_hello_world_project_model() {
                         potential_cfg_options: CfgOptions(
                             [],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {},
                         },
@@ -1760,6 +1786,7 @@ fn rust_project_hello_world_project_model() {
                         potential_cfg_options: CfgOptions(
                             [],
                         ),
+                        target_layout: None,
                         env: Env {
                             entries: {},
                         },
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index aa54342e39d..52ac3b6dc02 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -21,8 +21,8 @@ use crate::{
     cfg_flag::CfgFlag,
     rustc_cfg,
     sysroot::SysrootCrate,
-    utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath, Package,
-    ProjectJson, ProjectManifest, Sysroot, TargetKind, WorkspaceBuildScripts,
+    target_data_layout, utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath,
+    Package, ProjectJson, ProjectManifest, Sysroot, TargetKind, WorkspaceBuildScripts,
 };
 
 /// A set of cfg-overrides per crate.
@@ -79,6 +79,7 @@ pub enum ProjectWorkspace {
         rustc_cfg: Vec<CfgFlag>,
         cfg_overrides: CfgOverrides,
         toolchain: Option<Version>,
+        target_layout: Option<String>,
     },
     /// Project workspace was manually specified using a `rust-project.json` file.
     Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
@@ -108,6 +109,7 @@ impl fmt::Debug for ProjectWorkspace {
                 rustc_cfg,
                 cfg_overrides,
                 toolchain,
+                target_layout: data_layout,
             } => f
                 .debug_struct("Cargo")
                 .field("root", &cargo.workspace_root().file_name())
@@ -120,6 +122,7 @@ impl fmt::Debug for ProjectWorkspace {
                 .field("n_rustc_cfg", &rustc_cfg.len())
                 .field("n_cfg_overrides", &cfg_overrides.len())
                 .field("toolchain", &toolchain)
+                .field("data_layout", &data_layout)
                 .finish(),
             ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
                 let mut debug_struct = f.debug_struct("Json");
@@ -241,6 +244,11 @@ impl ProjectWorkspace {
                     rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), &config.extra_env);
 
                 let cfg_overrides = config.cfg_overrides();
+                let data_layout = target_data_layout::get(
+                    Some(&cargo_toml),
+                    config.target.as_deref(),
+                    &config.extra_env,
+                );
                 ProjectWorkspace::Cargo {
                     cargo,
                     build_scripts: WorkspaceBuildScripts::default(),
@@ -249,6 +257,7 @@ impl ProjectWorkspace {
                     rustc_cfg,
                     cfg_overrides,
                     toolchain,
+                    target_layout: data_layout,
                 }
             }
         };
@@ -435,6 +444,7 @@ impl ProjectWorkspace {
                 cfg_overrides: _,
                 build_scripts,
                 toolchain: _,
+                target_layout: _,
             } => {
                 cargo
                     .packages()
@@ -530,6 +540,7 @@ impl ProjectWorkspace {
                 project,
                 sysroot,
                 extra_env,
+                None,
             ),
             ProjectWorkspace::Cargo {
                 cargo,
@@ -539,6 +550,7 @@ impl ProjectWorkspace {
                 cfg_overrides,
                 build_scripts,
                 toolchain: _,
+                target_layout,
             } => cargo_to_crate_graph(
                 load_proc_macro,
                 load,
@@ -548,9 +560,10 @@ impl ProjectWorkspace {
                 rustc_cfg.clone(),
                 cfg_overrides,
                 build_scripts,
+                target_layout.as_deref().map(Arc::from),
             ),
             ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
-                detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot)
+                detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot, None)
             }
         };
         if crate_graph.patch_cfg_if() {
@@ -569,11 +582,18 @@ fn project_json_to_crate_graph(
     project: &ProjectJson,
     sysroot: &Option<Sysroot>,
     extra_env: &FxHashMap<String, String>,
+    target_layout: Option<Arc<str>>,
 ) -> CrateGraph {
     let mut crate_graph = CrateGraph::default();
-    let sysroot_deps = sysroot
-        .as_ref()
-        .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load));
+    let sysroot_deps = sysroot.as_ref().map(|sysroot| {
+        sysroot_to_crate_graph(
+            &mut crate_graph,
+            sysroot,
+            rustc_cfg.clone(),
+            target_layout.clone(),
+            load,
+        )
+    });
 
     let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
     let crates: NoHashHashMap<CrateId, CrateId> = project
@@ -625,6 +645,7 @@ fn project_json_to_crate_graph(
                     } else {
                         CrateOrigin::CratesIo { repo: None, name: None }
                     },
+                    target_layout.clone(),
                 ),
             )
         })
@@ -665,11 +686,18 @@ fn cargo_to_crate_graph(
     rustc_cfg: Vec<CfgFlag>,
     override_cfg: &CfgOverrides,
     build_scripts: &WorkspaceBuildScripts,
+    target_layout: Option<Arc<str>>,
 ) -> CrateGraph {
     let _p = profile::span("cargo_to_crate_graph");
     let mut crate_graph = CrateGraph::default();
     let (public_deps, libproc_macro) = match sysroot {
-        Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load),
+        Some(sysroot) => sysroot_to_crate_graph(
+            &mut crate_graph,
+            sysroot,
+            rustc_cfg.clone(),
+            target_layout.clone(),
+            load,
+        ),
         None => (SysrootPublicDeps::default(), None),
     };
 
@@ -732,6 +760,7 @@ fn cargo_to_crate_graph(
                     file_id,
                     &cargo[tgt].name,
                     cargo[tgt].is_proc_macro,
+                    target_layout.clone(),
                 );
                 if cargo[tgt].kind == TargetKind::Lib {
                     lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
@@ -811,6 +840,7 @@ fn cargo_to_crate_graph(
                 &cfg_options,
                 override_cfg,
                 build_scripts,
+                target_layout,
             );
         }
     }
@@ -822,11 +852,18 @@ fn detached_files_to_crate_graph(
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     detached_files: &[AbsPathBuf],
     sysroot: &Option<Sysroot>,
+    target_layout: Option<Arc<str>>,
 ) -> CrateGraph {
     let _p = profile::span("detached_files_to_crate_graph");
     let mut crate_graph = CrateGraph::default();
     let (public_deps, _libproc_macro) = match sysroot {
-        Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load),
+        Some(sysroot) => sysroot_to_crate_graph(
+            &mut crate_graph,
+            sysroot,
+            rustc_cfg.clone(),
+            target_layout.clone(),
+            load,
+        ),
         None => (SysrootPublicDeps::default(), None),
     };
 
@@ -859,6 +896,7 @@ fn detached_files_to_crate_graph(
                 repo: None,
                 name: display_name.map(|n| n.canonical_name().to_string()),
             },
+            target_layout.clone(),
         );
 
         public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate);
@@ -879,6 +917,7 @@ fn handle_rustc_crates(
     cfg_options: &CfgOptions,
     override_cfg: &CfgOverrides,
     build_scripts: &WorkspaceBuildScripts,
+    target_layout: Option<Arc<str>>,
 ) {
     let mut rustc_pkg_crates = FxHashMap::default();
     // The root package of the rustc-dev component is rustc_driver, so we match that
@@ -935,6 +974,7 @@ fn handle_rustc_crates(
                         file_id,
                         &rustc_workspace[tgt].name,
                         rustc_workspace[tgt].is_proc_macro,
+                        target_layout.clone(),
                     );
                     pkg_to_lib_crate.insert(pkg, crate_id);
                     // Add dependencies on core / std / alloc for this crate
@@ -999,6 +1039,7 @@ fn add_target_crate_root(
     file_id: FileId,
     cargo_name: &str,
     is_proc_macro: bool,
+    target_layout: Option<Arc<str>>,
 ) -> CrateId {
     let edition = pkg.edition;
     let mut potential_cfg_options = cfg_options.clone();
@@ -1045,6 +1086,7 @@ fn add_target_crate_root(
         proc_macro,
         is_proc_macro,
         CrateOrigin::CratesIo { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) },
+        target_layout,
     )
 }
 
@@ -1066,6 +1108,7 @@ fn sysroot_to_crate_graph(
     crate_graph: &mut CrateGraph,
     sysroot: &Sysroot,
     rustc_cfg: Vec<CfgFlag>,
+    target_layout: Option<Arc<str>>,
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 ) -> (SysrootPublicDeps, Option<CrateId>) {
     let _p = profile::span("sysroot_to_crate_graph");
@@ -1089,6 +1132,7 @@ fn sysroot_to_crate_graph(
                 Err("no proc macro loaded for sysroot crate".into()),
                 false,
                 CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)),
+                target_layout.clone(),
             );
             Some((krate, crate_id))
         })
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 3e7664d7d3e..faf7a2c2131 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -226,6 +226,7 @@ impl GlobalState {
 
                     build_scripts: _,
                     toolchain: _,
+                    target_layout: _,
                 } => Some((cargo, sysroot, rustc, rustc_cfg, cfg_overrides)),
                 _ => None,
             };
diff --git a/crates/test-utils/src/fixture.rs b/crates/test-utils/src/fixture.rs
index c824f5af725..73e72c18809 100644
--- a/crates/test-utils/src/fixture.rs
+++ b/crates/test-utils/src/fixture.rs
@@ -78,6 +78,7 @@ pub struct Fixture {
     pub edition: Option<String>,
     pub env: FxHashMap<String, String>,
     pub introduce_new_source_root: Option<String>,
+    pub target_data_layout: Option<String>,
 }
 
 pub struct MiniCore {
@@ -181,6 +182,7 @@ impl Fixture {
         let mut cfg_key_values = Vec::new();
         let mut env = FxHashMap::default();
         let mut introduce_new_source_root = None;
+        let mut target_data_layout = None;
         for component in components[1..].iter() {
             let (key, value) = component
                 .split_once(':')
@@ -213,6 +215,7 @@ impl Fixture {
                     }
                 }
                 "new_source_root" => introduce_new_source_root = Some(value.to_string()),
+                "target_data_layout" => target_data_layout = Some(value.to_string()),
                 _ => panic!("bad component: {:?}", component),
             }
         }
@@ -237,6 +240,7 @@ impl Fixture {
             edition,
             env,
             introduce_new_source_root,
+            target_data_layout,
         }
     }
 }