llvm: simplify data layout check

Don't skip the inconsistent data layout check for custom LLVMs.

With #118708, all targets will have a simple test that would trigger this
check if LLVM's data layouts do change - so data layouts would be
corrected during the LLVM upgrade. Therefore, with builtin targets, this
check won't trigger with our LLVM because each target will have been
confirmed to work. With non-builtin targets, this check is probably
useful to have because you can change the data layout in your target and
if its wrong then that could lead to bugs.

When using a custom LLVM, the same justification makes sense for
non-builtin targets as with our LLVM, the user can update their target to
match their LLVM and that's probably a good thing to do. However, with
a custom LLVM, the user cannot change the builtin target data layouts if
they don't match - though given that the compiler's data layout is used
for layout computation and a bunch of other things - you could get some
bugs because of the mismatch and probably want to know about that.

`CFG_LLVM_ROOT` was also always set during local development with
`download-ci-llvm` so this bug would never trigger locally.

Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
David Wood 2024-01-17 14:26:26 +00:00
parent c485ee7147
commit 46652dd254
No known key found for this signature in database
9 changed files with 57 additions and 38 deletions

View File

@ -39,6 +39,9 @@ codegen_llvm_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdy
codegen_llvm_lto_proc_macro = lto cannot be used for `proc-macro` crate type without `-Zdylib-lto` codegen_llvm_lto_proc_macro = lto cannot be used for `proc-macro` crate type without `-Zdylib-lto`
codegen_llvm_mismatch_data_layout =
data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}`
codegen_llvm_missing_features = codegen_llvm_missing_features =
add the missing features in a `target_feature` attribute add the missing features in a `target_feature` attribute

View File

@ -34,6 +34,7 @@
use smallvec::SmallVec; use smallvec::SmallVec;
use libc::c_uint; use libc::c_uint;
use std::borrow::Borrow;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::ffi::CStr; use std::ffi::CStr;
use std::str; use std::str;
@ -147,8 +148,7 @@ pub unsafe fn create_module<'ll>(
} }
// Ensure the data-layout values hardcoded remain the defaults. // Ensure the data-layout values hardcoded remain the defaults.
if sess.target.is_builtin { {
// tm is disposed by its drop impl
let tm = crate::back::write::create_informational_target_machine(tcx.sess); let tm = crate::back::write::create_informational_target_machine(tcx.sess);
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
@ -156,33 +156,13 @@ pub unsafe fn create_module<'ll>(
let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes()) let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes())
.expect("got a non-UTF8 data-layout from LLVM"); .expect("got a non-UTF8 data-layout from LLVM");
// Unfortunately LLVM target specs change over time, and right now we if target_data_layout != llvm_data_layout {
// don't have proper support to work with any more than one tcx.dcx().emit_err(crate::errors::MismatchedDataLayout {
// `data_layout` than the one that is in the rust-lang/rust repo. If rustc_target: sess.opts.target_triple.to_string().as_str(),
// this compiler is configured against a custom LLVM, we may have a rustc_layout: target_data_layout.as_str(),
// differing data layout, even though we should update our own to use llvm_target: sess.target.llvm_target.borrow(),
// that one. llvm_layout: llvm_data_layout,
// });
// As an interim hack, if CFG_LLVM_ROOT is not an empty string then we
// disable this check entirely as we may be configured with something
// that has a different target layout.
//
// Unsure if this will actually cause breakage when rustc is configured
// as such.
//
// FIXME(#34960)
let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or("");
let custom_llvm_used = !cfg_llvm_root.trim().is_empty();
if !custom_llvm_used && target_data_layout != llvm_data_layout {
bug!(
"data-layout for target `{rustc_target}`, `{rustc_layout}`, \
differs from LLVM target's `{llvm_target}` default layout, `{llvm_layout}`",
rustc_target = sess.opts.target_triple,
rustc_layout = target_data_layout,
llvm_target = sess.target.llvm_target,
llvm_layout = llvm_data_layout
);
} }
} }

View File

@ -244,3 +244,12 @@ pub(crate) struct CopyBitcode {
pub struct UnknownCompression { pub struct UnknownCompression {
pub algorithm: &'static str, pub algorithm: &'static str,
} }
#[derive(Diagnostic)]
#[diag(codegen_llvm_mismatch_data_layout)]
pub struct MismatchedDataLayout<'a> {
pub rustc_target: &'a str,
pub rustc_layout: &'a str,
pub llvm_target: &'a str,
pub llvm_layout: &'a str,
}

View File

@ -1103,16 +1103,11 @@ pub fn rustc_cargo_env(
/// Pass down configuration from the LLVM build into the build of /// Pass down configuration from the LLVM build into the build of
/// rustc_llvm and rustc_codegen_llvm. /// rustc_llvm and rustc_codegen_llvm.
fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {
let target_config = builder.config.target_config.get(&target);
if builder.is_rust_llvm(target) { if builder.is_rust_llvm(target) {
cargo.env("LLVM_RUSTLLVM", "1"); cargo.env("LLVM_RUSTLLVM", "1");
} }
let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target }); let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target });
cargo.env("LLVM_CONFIG", &llvm_config); cargo.env("LLVM_CONFIG", &llvm_config);
if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
cargo.env("CFG_LLVM_ROOT", s);
}
// Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script
// expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by

View File

@ -24,6 +24,7 @@
const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[
"tests/ui/asm/named-asm-labels.s", // loading an external asm file to test named labels lint "tests/ui/asm/named-asm-labels.s", // loading an external asm file to test named labels lint
"tests/ui/codegen/mismatched-data-layout.json", // testing mismatched data layout w/ custom targets
"tests/ui/check-cfg/my-awesome-platform.json", // testing custom targets with cfgs "tests/ui/check-cfg/my-awesome-platform.json", // testing custom targets with cfgs
"tests/ui/commandline-argfile-badutf8.args", // passing args via a file "tests/ui/commandline-argfile-badutf8.args", // passing args via a file
"tests/ui/commandline-argfile.args", // passing args via a file "tests/ui/commandline-argfile.args", // passing args via a file

View File

@ -9,4 +9,4 @@ all:
$(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json - $(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json -
$(RUSTC) foo.rs --target=definitely-not-builtin-target 2>&1 | $(CGREP) 'may not set is_builtin' $(RUSTC) foo.rs --target=definitely-not-builtin-target 2>&1 | $(CGREP) 'may not set is_builtin'
$(RUSTC) foo.rs --target=endianness-mismatch 2>&1 | $(CGREP) '"data-layout" claims architecture is little-endian' $(RUSTC) foo.rs --target=endianness-mismatch 2>&1 | $(CGREP) '"data-layout" claims architecture is little-endian'
$(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib $(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib 2>&1 | $(CGREP) 'data-layout for target'

View File

@ -0,0 +1,13 @@
{
"llvm-target": "x86_64-unknown-none-gnu",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"os": "unknown",
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"executables": true
}

View File

@ -0,0 +1,14 @@
// This test checks that data layout mismatches emit an error.
//
// build-fail
// needs-llvm-components: x86
// compile-flags: --crate-type=lib --target={{src-base}}/codegen/mismatched-data-layout.json -Z unstable-options
// error-pattern: differs from LLVM target's
// normalize-stderr-test: "`, `[A-Za-z0-9-:]*`" -> "`, `normalized data layout`"
// normalize-stderr-test: "layout, `[A-Za-z0-9-:]*`" -> "layout, `normalized data layout`"
#![feature(lang_items, no_core, auto_traits)]
#![no_core]
#[lang = "sized"]
trait Sized {}

View File

@ -0,0 +1,4 @@
error: data-layout for target `mismatched-data-layout-7814813422914914169`, `normalized data layout`, differs from LLVM target's `x86_64-unknown-none-gnu` default layout, `normalized data layout`
error: aborting due to 1 previous error