From dad96b107c0dd35ce2eecfaecc0e6af4988b3bb4 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sun, 20 Jul 2025 14:35:43 +0200 Subject: [PATCH] Use serde for target spec json deserialize The previous manual parsing of `serde_json::Value` was a lot of complicated code and extremely error-prone. It was full of janky behavior like sometimes ignoring type errors, sometimes erroring for type errors, sometimes warning for type errors, and sometimes just ICEing for type errors (the icing on the top). Additionally, many of the error messages about allowed values were out of date because they were in a completely different place than the FromStr impls. Overall, the system caused confusion for users. I also found the old deserialization code annoying to read. Whenever a `key!` invocation was found, one had to first look for the right macro arm, and no go to definition could help. This PR replaces all this manual parsing with a 2-step process involving serde. First, the string is parsed into a `TargetSpecJson` struct. This struct is a 1:1 representation of the spec JSON. It already parses all the enums and is very simple to read and write. Then, the fields from this struct are copied into the actual `Target`. The reason for this two-step process instead of just serializing into a `Target` is because of a few reasons 1. There are a few transformations performed between the two formats 2. The default logic is implemented this way. Otherwise all the default field values would have to be spelled out again, which is suboptimal. With this logic, they fall out naturally, because everything in the json struct is an `Option`. Overall, the mapping is pretty simple, with the vast majority of fields just doing a 1:1 mapping that is captured by two macros. I have deliberately avoided making the macros generic to keep them simple. All the `FromStr` impls now have the error message right inside them, which increases the chance of it being up to date. Some "`from_str`" impls were turned into proper `FromStr` impls to support this. The new code is much less involved, delegating all the JSON parsing logic to serde, without any manual type matching. This change introduces a few breaking changes for consumers. While it is possible to use this format on stable, it is very much subject to change, so breaking changes are expected. The hope is also that because of the way stricter behavior, breaking changes are easier to deal with, as they come with clearer error messages. 1. Invalid types now always error, everywhere. Previously, they would sometimes error, and sometimes just be ignored (which meant the users JSON was still broken, just silently!) 2. This now makes use of `deny_unknown_fields` instead of just warning on unused fields, which was done previously. Serde doesn't make it easy to get such warning behavior, which was the primary reason that this now changed. But I think error behavior is very reasonable too. If someone has random stale fields in their JSON, it is likely because these fields did something at some point but no longer do, and the user likely wants to be informed of this so they can figure out what to do. This is also relevant for the future. If we remove a field but someone has it set, it probably makes sense for them to take a look whether they need this and should look for alternatives, or whether they can just delete it. Overall, the JSON is made more explicit. This is the only expected breakage, but there could also be small breakage from small mistakes. All targets roundtrip though, so it can't be anything too major. --- Cargo.lock | 13 + compiler/rustc_session/src/config.rs | 4 +- compiler/rustc_session/src/options.rs | 2 +- compiler/rustc_target/Cargo.toml | 3 + compiler/rustc_target/src/json.rs | 15 + compiler/rustc_target/src/spec/json.rs | 1025 ++++++----------- compiler/rustc_target/src/spec/mod.rs | 388 ++++--- compiler/rustc_target/src/tests.rs | 50 +- src/librustdoc/doctest.rs | 2 +- src/tools/tidy/src/deps.rs | 1 + .../rustdoc-target-spec-json-path/target.json | 1 - .../target-specs/endianness-mismatch.json | 1 - .../target-specs/my-awesome-platform.json | 4 +- .../target-specs/my-incomplete-platform.json | 4 +- .../my-x86_64-unknown-linux-gnu-platform.json | 4 +- .../target-specs/require-explicit-cpu.json | 1 - tests/run-make/target-specs/rmake.rs | 4 +- tests/ui/check-cfg/my-awesome-platform.json | 1 - tests/ui/codegen/mismatched-data-layout.json | 1 - tests/ui/codegen/mismatched-data-layouts.rs | 1 + .../ui/codegen/mismatched-data-layouts.stderr | 2 +- 21 files changed, 678 insertions(+), 849 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d2fca8bb3f48..1537a60718623 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4499,7 +4499,10 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", + "serde", + "serde_derive", "serde_json", + "serde_path_to_error", "tracing", ] @@ -4870,6 +4873,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +dependencies = [ + "itoa", + "serde", +] + [[package]] name = "serde_spanned" version = "0.6.9" diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index d6215e1de043a..190cb6c5e0388 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -336,12 +336,12 @@ impl LinkSelfContained { if let Some(component_to_enable) = component.strip_prefix('+') { self.explicitly_set = None; self.enabled_components - .insert(LinkSelfContainedComponents::from_str(component_to_enable)?); + .insert(LinkSelfContainedComponents::from_str(component_to_enable).ok()?); Some(()) } else if let Some(component_to_disable) = component.strip_prefix('-') { self.explicitly_set = None; self.disabled_components - .insert(LinkSelfContainedComponents::from_str(component_to_disable)?); + .insert(LinkSelfContainedComponents::from_str(component_to_disable).ok()?); Some(()) } else { None diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 2bdde2f887a30..313eec6268d3c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1295,7 +1295,7 @@ pub mod parse { } pub(crate) fn parse_linker_flavor(slot: &mut Option, v: Option<&str>) -> bool { - match v.and_then(LinkerFlavorCli::from_str) { + match v.and_then(|v| LinkerFlavorCli::from_str(v).ok()) { Some(lf) => *slot = Some(lf), _ => return false, } diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 0121c752dbdde..56932c24922e5 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -12,7 +12,10 @@ rustc_fs_util = { path = "../rustc_fs_util" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } +serde = "1.0.219" +serde_derive = "1.0.219" serde_json = "1.0.59" +serde_path_to_error = "0.1.17" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs index 4fcc477921ba2..896609bdbe3a7 100644 --- a/compiler/rustc_target/src/json.rs +++ b/compiler/rustc_target/src/json.rs @@ -114,3 +114,18 @@ impl ToJson for rustc_abi::CanonAbi { self.to_string().to_json() } } + +macro_rules! serde_deserialize_from_str { + ($ty:ty) => { + impl<'de> serde::Deserialize<'de> for $ty { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + FromStr::from_str(&s).map_err(serde::de::Error::custom) + } + } + }; +} +pub(crate) use serde_deserialize_from_str; diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index 6c716f8712530..d27c1929aef74 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -1,60 +1,47 @@ -use std::borrow::Cow; use std::collections::BTreeMap; use std::str::FromStr; -use rustc_abi::{Align, AlignFromBytesError, ExternAbi}; -use serde_json::Value; +use rustc_abi::{Align, AlignFromBytesError}; -use super::{Target, TargetKind, TargetOptions, TargetWarnings}; +use super::crt_objects::CrtObjects; +use super::{ + BinaryFormat, CodeModel, DebuginfoKind, FloatAbi, FramePointer, LinkArgsCli, + LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFlavorCli, LldFlavor, + MergeFunctions, PanicStrategy, RelocModel, RelroLevel, RustcAbi, SanitizerSet, + SmallDataThresholdSupport, SplitDebuginfo, StackProbeType, StaticCow, SymbolVisibility, Target, + TargetKind, TargetOptions, TargetWarnings, TlsModel, +}; use crate::json::{Json, ToJson}; use crate::spec::AbiMap; impl Target { /// Loads a target descriptor from a JSON object. - pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> { - // While ugly, this code must remain this way to retain - // compatibility with existing JSON fields and the internal - // expected naming of the Target and TargetOptions structs. - // To ensure compatibility is retained, the built-in targets - // are round-tripped through this code to catch cases where - // the JSON parser is not updated to match the structs. - - let mut obj = match obj { - Value::Object(obj) => obj, - _ => return Err("Expected JSON object for target")?, - }; + pub fn from_json(json: &str) -> Result<(Target, TargetWarnings), String> { + let json_deserializer = &mut serde_json::Deserializer::from_str(json); - let mut get_req_field = |name: &str| { - obj.remove(name) - .and_then(|j| j.as_str().map(str::to_string)) - .ok_or_else(|| format!("Field {name} in target specification is required")) - }; + let json: TargetSpecJson = + serde_path_to_error::deserialize(json_deserializer).map_err(|err| err.to_string())?; let mut base = Target { - llvm_target: get_req_field("llvm-target")?.into(), + llvm_target: json.llvm_target, metadata: Default::default(), - pointer_width: get_req_field("target-pointer-width")? - .parse::() - .map_err(|_| "target-pointer-width must be an integer".to_string())?, - data_layout: get_req_field("data-layout")?.into(), - arch: get_req_field("arch")?.into(), + pointer_width: json + .target_pointer_width + .parse() + .map_err(|err| format!("invalid target-pointer-width: {err}"))?, + data_layout: json.data_layout, + arch: json.arch, options: Default::default(), }; // FIXME: This doesn't properly validate anything and just ignores the data if it's invalid. // That's okay for now, the only use of this is when generating docs, which we don't do for // custom targets. - if let Some(Json::Object(mut metadata)) = obj.remove("metadata") { - base.metadata.description = metadata - .remove("description") - .and_then(|desc| desc.as_str().map(|desc| desc.to_owned().into())); - base.metadata.tier = metadata - .remove("tier") - .and_then(|tier| tier.as_u64()) - .filter(|tier| (1..=3).contains(tier)); - base.metadata.host_tools = - metadata.remove("host_tools").and_then(|host| host.as_bool()); - base.metadata.std = metadata.remove("std").and_then(|host| host.as_bool()); + if let Some(metadata) = json.metadata { + base.metadata.description = metadata.description; + base.metadata.tier = metadata.tier.filter(|tier| (1..=3).contains(tier)); + base.metadata.host_tools = metadata.host_tools; + base.metadata.std = metadata.std; } let alignment_error = |field_name: &str, error: AlignFromBytesError| -> String { @@ -65,640 +52,188 @@ impl Target { format!("`{}` bits is not a valid value for {field_name}: {msg}", error.align() * 8) }; - let mut incorrect_type = vec![]; - - macro_rules! key { - ($key_name:ident) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(s) = obj.remove(&name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) { - base.$key_name = s; - } - } ); - ($key_name:ident = $json_name:expr) => ( { - let name = $json_name; - if let Some(s) = obj.remove(name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) { - base.$key_name = s; - } - } ); - ($key_name:ident = $json_name:expr, u64 as $int_ty:ty) => ( { - let name = $json_name; - if let Some(s) = obj.remove(name).and_then(|b| b.as_u64()) { - base.$key_name = s as $int_ty; - } - } ); - ($key_name:ident, bool) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) { - base.$key_name = s; - } - } ); - ($key_name:ident = $json_name:expr, bool) => ( { - let name = $json_name; - if let Some(s) = obj.remove(name).and_then(|b| b.as_bool()) { - base.$key_name = s; - } - } ); - ($key_name:ident, u32) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) { - if s < 1 || s > 5 { - return Err("Not a valid DWARF version number".into()); - } - base.$key_name = s as u32; - } - } ); - ($key_name:ident, Option) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) { - base.$key_name = Some(s); - } - } ); - ($key_name:ident, Option) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) { - base.$key_name = Some(s); - } - } ); - ($key_name:ident, Option>) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(s) = obj.remove(&name).and_then(|b| Some(b.as_str()?.to_string())) { - base.$key_name = Some(s.into()); - } - } ); - ($key_name:ident, Option) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(b) = obj.remove(&name).and_then(|b| b.as_u64()) { - match Align::from_bits(b) { - Ok(align) => base.$key_name = Some(align), - Err(e) => return Err(alignment_error(&name, e)), - } - } - } ); - ($key_name:ident, BinaryFormat) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|f| f.as_str().and_then(|s| { - match s.parse::() { - Ok(binary_format) => base.$key_name = binary_format, - _ => return Some(Err(format!( - "'{s}' is not a valid value for binary_format. \ - Use 'coff', 'elf', 'mach-o', 'wasm' or 'xcoff' " - ))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, MergeFunctions) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(mergefunc) => base.$key_name = mergefunc, - _ => return Some(Err(format!("'{}' is not a valid value for \ - merge-functions. Use 'disabled', \ - 'trampolines', or 'aliases'.", - s))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, FloatAbi) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(float_abi) => base.$key_name = Some(float_abi), - _ => return Some(Err(format!("'{}' is not a valid value for \ - llvm-floatabi. Use 'soft' or 'hard'.", - s))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, RustcAbi) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(rustc_abi) => base.$key_name = Some(rustc_abi), - _ => return Some(Err(format!( - "'{s}' is not a valid value for rustc-abi. \ - Use 'x86-softfloat' or leave the field unset." - ))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, RelocModel) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(relocation_model) => base.$key_name = relocation_model, - _ => return Some(Err(format!("'{}' is not a valid relocation model. \ - Run `rustc --print relocation-models` to \ - see the list of supported values.", s))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, CodeModel) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(code_model) => base.$key_name = Some(code_model), - _ => return Some(Err(format!("'{}' is not a valid code model. \ - Run `rustc --print code-models` to \ - see the list of supported values.", s))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, TlsModel) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(tls_model) => base.$key_name = tls_model, - _ => return Some(Err(format!("'{}' is not a valid TLS model. \ - Run `rustc --print tls-models` to \ - see the list of supported values.", s))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, SmallDataThresholdSupport) => ( { - obj.remove("small-data-threshold-support").and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(support) => base.small_data_threshold_support = support, - _ => return Some(Err(format!("'{s}' is not a valid value for small-data-threshold-support."))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, PanicStrategy) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match s { - "unwind" => base.$key_name = super::PanicStrategy::Unwind, - "abort" => base.$key_name = super::PanicStrategy::Abort, - _ => return Some(Err(format!("'{}' is not a valid value for \ - panic-strategy. Use 'unwind' or 'abort'.", - s))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, RelroLevel) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(level) => base.$key_name = level, - _ => return Some(Err(format!("'{}' is not a valid value for \ - relro-level. Use 'full', 'partial, or 'off'.", - s))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, Option) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(level) => base.$key_name = Some(level), - _ => return Some(Err(format!("'{}' is not a valid value for \ - symbol-visibility. Use 'hidden', 'protected, or 'interposable'.", - s))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, DebuginfoKind) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(level) => base.$key_name = level, - _ => return Some(Err( - format!("'{s}' is not a valid value for debuginfo-kind. Use 'dwarf', \ - 'dwarf-dsym' or 'pdb'.") - )), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, SplitDebuginfo) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(level) => base.$key_name = level, - _ => return Some(Err(format!("'{}' is not a valid value for \ - split-debuginfo. Use 'off' or 'dsymutil'.", - s))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, list) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(j) = obj.remove(&name) { - if let Some(v) = j.as_array() { - base.$key_name = v.iter() - .map(|a| a.as_str().unwrap().to_string().into()) - .collect(); - } else { - incorrect_type.push(name) - } - } - } ); - ($key_name:ident, opt_list) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(j) = obj.remove(&name) { - if let Some(v) = j.as_array() { - base.$key_name = Some(v.iter() - .map(|a| a.as_str().unwrap().to_string().into()) - .collect()); - } else { - incorrect_type.push(name) - } + macro_rules! forward { + ($name:ident) => { + if let Some($name) = json.$name { + base.$name = $name; } - } ); - ($key_name:ident, fallible_list) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|j| { - if let Some(v) = j.as_array() { - match v.iter().map(|a| FromStr::from_str(a.as_str().unwrap())).collect() { - Ok(l) => { base.$key_name = l }, - // FIXME: `fallible_list` can't re-use the `key!` macro for list - // elements and the error messages from that macro, so it has a bad - // generic message instead - Err(_) => return Some(Err( - format!("`{:?}` is not a valid value for `{}`", j, name) - )), - } - } else { - incorrect_type.push(name) - } - Some(Ok(())) - }).unwrap_or(Ok(())) - } ); - ($key_name:ident, optional) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(o) = obj.remove(&name) { - base.$key_name = o - .as_str() - .map(|s| s.to_string().into()); - } - } ); - ($key_name:ident = $json_name:expr, LldFlavor) => ( { - let name = $json_name; - obj.remove(name).and_then(|o| o.as_str().and_then(|s| { - if let Some(flavor) = super::LldFlavor::from_str(&s) { - base.$key_name = flavor; - } else { - return Some(Err(format!( - "'{}' is not a valid value for lld-flavor. \ - Use 'darwin', 'gnu', 'link' or 'wasm'.", - s))) - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident = $json_name:expr, LinkerFlavorCli) => ( { - let name = $json_name; - obj.remove(name).and_then(|o| o.as_str().and_then(|s| { - match super::LinkerFlavorCli::from_str(s) { - Some(linker_flavor) => base.$key_name = linker_flavor, - _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \ - Use {}", s, super::LinkerFlavorCli::one_of()))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident, StackProbeType) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| match super::StackProbeType::from_json(&o) { - Ok(v) => { - base.$key_name = v; - Some(Ok(())) - }, - Err(s) => Some(Err( - format!("`{:?}` is not a valid value for `{}`: {}", o, name, s) - )), - }).unwrap_or(Ok(())) - } ); - ($key_name:ident, SanitizerSet) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(o) = obj.remove(&name) { - if let Some(a) = o.as_array() { - for s in a { - use super::SanitizerSet; - base.$key_name |= match s.as_str() { - Some("address") => SanitizerSet::ADDRESS, - Some("cfi") => SanitizerSet::CFI, - Some("dataflow") => SanitizerSet::DATAFLOW, - Some("kcfi") => SanitizerSet::KCFI, - Some("kernel-address") => SanitizerSet::KERNELADDRESS, - Some("leak") => SanitizerSet::LEAK, - Some("memory") => SanitizerSet::MEMORY, - Some("memtag") => SanitizerSet::MEMTAG, - Some("safestack") => SanitizerSet::SAFESTACK, - Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK, - Some("thread") => SanitizerSet::THREAD, - Some("hwaddress") => SanitizerSet::HWADDRESS, - Some(s) => return Err(format!("unknown sanitizer {}", s)), - _ => return Err(format!("not a string: {:?}", s)), - }; - } - } else { - incorrect_type.push(name) - } - } - Ok::<(), String>(()) - } ); - ($key_name:ident, link_self_contained_components) => ( { - // Skeleton of what needs to be parsed: - // - // ``` - // $name: { - // "components": [ - // - // ] - // } - // ``` - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(o) = obj.remove(&name) { - if let Some(o) = o.as_object() { - let component_array = o.get("components") - .ok_or_else(|| format!("{name}: expected a \ - JSON object with a `components` field."))?; - let component_array = component_array.as_array() - .ok_or_else(|| format!("{name}.components: expected a JSON array"))?; - let mut components = super::LinkSelfContainedComponents::empty(); - for s in component_array { - components |= match s.as_str() { - Some(s) => { - super::LinkSelfContainedComponents::from_str(s) - .ok_or_else(|| format!("unknown \ - `-Clink-self-contained` component: {s}"))? - }, - _ => return Err(format!("not a string: {:?}", s)), - }; - } - base.$key_name = super::LinkSelfContainedDefault::WithComponents(components); - } else { - incorrect_type.push(name) - } - } - Ok::<(), String>(()) - } ); - ($key_name:ident = $json_name:expr, link_self_contained_backwards_compatible) => ( { - let name = $json_name; - obj.remove(name).and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(lsc_default) => base.$key_name = lsc_default, - _ => return Some(Err(format!("'{}' is not a valid `-Clink-self-contained` default. \ - Use 'false', 'true', 'musl' or 'mingw'", s))), - } - Some(Ok(())) - })).unwrap_or(Ok(())) - } ); - ($key_name:ident = $json_name:expr, link_objects) => ( { - let name = $json_name; - if let Some(val) = obj.remove(name) { - let obj = val.as_object().ok_or_else(|| format!("{}: expected a \ - JSON object with fields per CRT object kind.", name))?; - let mut args = super::CrtObjects::new(); - for (k, v) in obj { - let kind = super::LinkOutputKind::from_str(&k).ok_or_else(|| { - format!("{}: '{}' is not a valid value for CRT object kind. \ - Use '(dynamic,static)-(nopic,pic)-exe' or \ - '(dynamic,static)-dylib' or 'wasi-reactor-exe'", name, k) - })?; - - let v = v.as_array().ok_or_else(|| - format!("{}.{}: expected a JSON array", name, k) - )?.iter().enumerate() - .map(|(i,s)| { - let s = s.as_str().ok_or_else(|| - format!("{}.{}[{}]: expected a JSON string", name, k, i))?; - Ok(s.to_string().into()) - }) - .collect::, String>>()?; - - args.insert(kind, v); - } - base.$key_name = args; - } - } ); - ($key_name:ident = $json_name:expr, link_args) => ( { - let name = $json_name; - if let Some(val) = obj.remove(name) { - let obj = val.as_object().ok_or_else(|| format!("{}: expected a \ - JSON object with fields per linker-flavor.", name))?; - let mut args = super::LinkArgsCli::new(); - for (k, v) in obj { - let flavor = super::LinkerFlavorCli::from_str(&k).ok_or_else(|| { - format!("{}: '{}' is not a valid value for linker-flavor. \ - Use 'em', 'gcc', 'ld' or 'msvc'", name, k) - })?; - - let v = v.as_array().ok_or_else(|| - format!("{}.{}: expected a JSON array", name, k) - )?.iter().enumerate() - .map(|(i,s)| { - let s = s.as_str().ok_or_else(|| - format!("{}.{}[{}]: expected a JSON string", name, k, i))?; - Ok(s.to_string().into()) - }) - .collect::, String>>()?; - - args.insert(flavor, v); - } - base.$key_name = args; - } - } ); - ($key_name:ident, env) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(o) = obj.remove(&name) { - if let Some(a) = o.as_array() { - for o in a { - if let Some(s) = o.as_str() { - if let [k, v] = *s.split('=').collect::>() { - base.$key_name - .to_mut() - .push((k.to_string().into(), v.to_string().into())) - } - } - } - } else { - incorrect_type.push(name) - } + }; + } + macro_rules! forward_opt { + ($name:ident) => { + if let Some($name) = json.$name { + base.$name = Some($name); } - } ); - ($key_name:ident, target_families) => ( { - if let Some(value) = obj.remove("target-family") { - if let Some(v) = value.as_array() { - base.$key_name = v.iter() - .map(|a| a.as_str().unwrap().to_string().into()) - .collect(); - } else if let Some(v) = value.as_str() { - base.$key_name = vec![v.to_string().into()].into(); - } + }; + } + + if let Some(target_endian) = json.target_endian { + base.endian = target_endian.0; + } + + forward!(frame_pointer); + forward!(c_int_width); + forward_opt!(c_enum_min_bits); // if None, matches c_int_width + forward!(os); + forward!(env); + forward!(abi); + forward!(vendor); + forward_opt!(linker); + forward!(linker_flavor_json); + forward!(lld_flavor_json); + forward!(linker_is_gnu_json); + forward!(pre_link_objects); + forward!(post_link_objects); + forward!(pre_link_objects_self_contained); + forward!(post_link_objects_self_contained); + + // Deserializes the backwards-compatible variants of `-Clink-self-contained` + if let Some(link_self_contained) = json.link_self_contained_backwards_compatible { + base.link_self_contained = link_self_contained; + } + // Deserializes the components variant of `-Clink-self-contained` + if let Some(link_self_contained) = json.link_self_contained { + let components = link_self_contained + .components + .into_iter() + .fold(LinkSelfContainedComponents::empty(), |a, b| a | b); + base.link_self_contained = LinkSelfContainedDefault::WithComponents(components); + } + + forward!(pre_link_args_json); + forward!(late_link_args_json); + forward!(late_link_args_dynamic_json); + forward!(late_link_args_static_json); + forward!(post_link_args_json); + forward_opt!(link_script); + + if let Some(link_env) = json.link_env { + for s in link_env { + if let [k, v] = *s.split('=').collect::>() { + base.link_env.to_mut().push((k.to_string().into(), v.to_string().into())) + } else { + return Err(format!("link-env value '{s}' must be of the pattern 'KEY=VALUE'")); } - } ); + } } - if let Some(j) = obj.remove("target-endian") { - if let Some(s) = j.as_str() { - base.endian = s.parse()?; - } else { - incorrect_type.push("target-endian".into()) + forward!(link_env_remove); + forward!(asm_args); + forward!(cpu); + forward!(need_explicit_cpu); + forward!(features); + forward!(dynamic_linking); + forward_opt!(direct_access_external_data); + forward!(dll_tls_export); + forward!(only_cdylib); + forward!(executables); + forward!(relocation_model); + forward_opt!(code_model); + forward!(tls_model); + forward!(disable_redzone); + forward!(function_sections); + forward!(dll_prefix); + forward!(dll_suffix); + forward!(exe_suffix); + forward!(staticlib_prefix); + forward!(staticlib_suffix); + + if let Some(target_family) = json.target_family { + match target_family { + TargetFamiliesJson::Array(families) => base.families = families, + TargetFamiliesJson::String(family) => base.families = vec![family].into(), } } - if let Some(fp) = obj.remove("frame-pointer") { - if let Some(s) = fp.as_str() { - base.frame_pointer = s - .parse() - .map_err(|()| format!("'{s}' is not a valid value for frame-pointer"))?; - } else { - incorrect_type.push("frame-pointer".into()) + forward!(abi_return_struct_as_int); + forward!(is_like_aix); + forward!(is_like_darwin); + forward!(is_like_solaris); + forward!(is_like_windows); + forward!(is_like_msvc); + forward!(is_like_wasm); + forward!(is_like_android); + forward!(binary_format); + forward!(default_dwarf_version); + forward!(allows_weak_linkage); + forward!(has_rpath); + forward!(no_default_libraries); + forward!(position_independent_executables); + forward!(static_position_independent_executables); + forward!(plt_by_default); + forward!(relro_level); + forward!(archive_format); + forward!(allow_asm); + forward!(main_needs_argc_argv); + forward!(has_thread_local); + forward!(obj_is_bitcode); + forward!(bitcode_llvm_cmdline); + forward_opt!(max_atomic_width); + forward_opt!(min_atomic_width); + forward!(atomic_cas); + forward!(panic_strategy); + forward!(crt_static_allows_dylibs); + forward!(crt_static_default); + forward!(crt_static_respected); + forward!(stack_probes); + + if let Some(min_global_align) = json.min_global_align { + match Align::from_bits(min_global_align) { + Ok(align) => base.min_global_align = Some(align), + Err(e) => return Err(alignment_error("min-global-align", e)), } } - key!(c_int_width = "target-c-int-width", u64 as u16); - key!(c_enum_min_bits, Option); // if None, matches c_int_width - key!(os); - key!(env); - key!(abi); - key!(vendor); - key!(linker, optional); - key!(linker_flavor_json = "linker-flavor", LinkerFlavorCli)?; - key!(lld_flavor_json = "lld-flavor", LldFlavor)?; - key!(linker_is_gnu_json = "linker-is-gnu", bool); - key!(pre_link_objects = "pre-link-objects", link_objects); - key!(post_link_objects = "post-link-objects", link_objects); - key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects); - key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects); - // Deserializes the backwards-compatible variants of `-Clink-self-contained` - key!( - link_self_contained = "crt-objects-fallback", - link_self_contained_backwards_compatible - )?; - // Deserializes the components variant of `-Clink-self-contained` - key!(link_self_contained, link_self_contained_components)?; - key!(pre_link_args_json = "pre-link-args", link_args); - key!(late_link_args_json = "late-link-args", link_args); - key!(late_link_args_dynamic_json = "late-link-args-dynamic", link_args); - key!(late_link_args_static_json = "late-link-args-static", link_args); - key!(post_link_args_json = "post-link-args", link_args); - key!(link_script, optional); - key!(link_env, env); - key!(link_env_remove, list); - key!(asm_args, list); - key!(cpu); - key!(need_explicit_cpu, bool); - key!(features); - key!(dynamic_linking, bool); - key!(direct_access_external_data, Option); - key!(dll_tls_export, bool); - key!(only_cdylib, bool); - key!(executables, bool); - key!(relocation_model, RelocModel)?; - key!(code_model, CodeModel)?; - key!(tls_model, TlsModel)?; - key!(disable_redzone, bool); - key!(function_sections, bool); - key!(dll_prefix); - key!(dll_suffix); - key!(exe_suffix); - key!(staticlib_prefix); - key!(staticlib_suffix); - key!(families, target_families); - key!(abi_return_struct_as_int, bool); - key!(is_like_aix, bool); - key!(is_like_darwin, bool); - key!(is_like_solaris, bool); - key!(is_like_windows, bool); - key!(is_like_msvc, bool); - key!(is_like_wasm, bool); - key!(is_like_android, bool); - key!(binary_format, BinaryFormat)?; - key!(default_dwarf_version, u32); - key!(allows_weak_linkage, bool); - key!(has_rpath, bool); - key!(no_default_libraries, bool); - key!(position_independent_executables, bool); - key!(static_position_independent_executables, bool); - key!(plt_by_default, bool); - key!(relro_level, RelroLevel)?; - key!(archive_format); - key!(allow_asm, bool); - key!(main_needs_argc_argv, bool); - key!(has_thread_local, bool); - key!(obj_is_bitcode, bool); - key!(bitcode_llvm_cmdline); - key!(max_atomic_width, Option); - key!(min_atomic_width, Option); - key!(atomic_cas, bool); - key!(panic_strategy, PanicStrategy)?; - key!(crt_static_allows_dylibs, bool); - key!(crt_static_default, bool); - key!(crt_static_respected, bool); - key!(stack_probes, StackProbeType)?; - key!(min_global_align, Option); - key!(default_codegen_units, Option); - key!(default_codegen_backend, Option>); - key!(trap_unreachable, bool); - key!(requires_lto, bool); - key!(singlethread, bool); - key!(no_builtins, bool); - key!(default_visibility, Option)?; - key!(emit_debug_gdb_scripts, bool); - key!(requires_uwtable, bool); - key!(default_uwtable, bool); - key!(simd_types_indirect, bool); - key!(limit_rdylib_exports, bool); - key!(override_export_symbols, opt_list); - key!(merge_functions, MergeFunctions)?; - key!(mcount = "target-mcount"); - key!(llvm_mcount_intrinsic, optional); - key!(llvm_abiname); - key!(llvm_floatabi, FloatAbi)?; - key!(rustc_abi, RustcAbi)?; - key!(relax_elf_relocations, bool); - key!(llvm_args, list); - key!(use_ctors_section, bool); - key!(eh_frame_header, bool); - key!(has_thumb_interworking, bool); - key!(debuginfo_kind, DebuginfoKind)?; - key!(split_debuginfo, SplitDebuginfo)?; - key!(supported_split_debuginfo, fallible_list)?; - key!(supported_sanitizers, SanitizerSet)?; - key!(generate_arange_section, bool); - key!(supports_stack_protector, bool); - key!(small_data_threshold_support, SmallDataThresholdSupport)?; - key!(entry_name); - key!(supports_xray, bool); + forward_opt!(default_codegen_units); + forward_opt!(default_codegen_backend); + forward!(trap_unreachable); + forward!(requires_lto); + forward!(singlethread); + forward!(no_builtins); + forward_opt!(default_visibility); + forward!(emit_debug_gdb_scripts); + forward!(requires_uwtable); + forward!(default_uwtable); + forward!(simd_types_indirect); + forward!(limit_rdylib_exports); + forward_opt!(override_export_symbols); + forward!(merge_functions); + forward!(mcount); + forward_opt!(llvm_mcount_intrinsic); + forward!(llvm_abiname); + forward_opt!(llvm_floatabi); + forward_opt!(rustc_abi); + forward!(relax_elf_relocations); + forward!(llvm_args); + forward!(use_ctors_section); + forward!(eh_frame_header); + forward!(has_thumb_interworking); + forward!(debuginfo_kind); + forward!(split_debuginfo); + forward!(supported_split_debuginfo); + + if let Some(supported_sanitizers) = json.supported_sanitizers { + base.supported_sanitizers = + supported_sanitizers.into_iter().fold(SanitizerSet::empty(), |a, b| a | b); + } + + forward!(generate_arange_section); + forward!(supports_stack_protector); + forward!(small_data_threshold_support); + forward!(entry_name); + forward!(supports_xray); // we're going to run `update_from_cli`, but that won't change the target's AbiMap // FIXME: better factor the Target definition so we enforce this on a type level let abi_map = AbiMap::from_target(&base); - - if let Some(abi_str) = obj.remove("entry-abi") { - if let Json::String(abi_str) = abi_str { - match abi_str.parse::() { - Ok(abi) => base.options.entry_abi = abi_map.canonize_abi(abi, false).unwrap(), - Err(_) => return Err(format!("{abi_str} is not a valid ExternAbi")), - } - } else { - incorrect_type.push("entry-abi".to_owned()) - } + if let Some(entry_abi) = json.entry_abi { + base.options.entry_abi = abi_map.canonize_abi(entry_abi.0, false).unwrap(); } base.update_from_cli(); base.check_consistency(TargetKind::Json)?; - // Each field should have been read using `Json::remove` so any keys remaining are unused. - let remaining_keys = obj.keys(); - Ok(( - base, - TargetWarnings { unused_fields: remaining_keys.cloned().collect(), incorrect_type }, - )) + Ok((base, TargetWarnings { unused_fields: vec![] })) } } @@ -877,3 +412,189 @@ impl ToJson for Target { Json::Object(d) } } + +#[derive(serde_derive::Deserialize)] +struct LinkSelfContainedComponentsWrapper { + components: Vec, +} + +#[derive(serde_derive::Deserialize)] +#[serde(untagged)] +enum TargetFamiliesJson { + Array(StaticCow<[StaticCow]>), + String(StaticCow), +} + +/// `Endian` is in `rustc_abi`, which doesn't have access to the macro and serde. +struct EndianWrapper(rustc_abi::Endian); +impl FromStr for EndianWrapper { + type Err = String; + fn from_str(s: &str) -> Result { + rustc_abi::Endian::from_str(s).map(Self) + } +} +crate::json::serde_deserialize_from_str!(EndianWrapper); + +/// `ExternAbi` is in `rustc_abi`, which doesn't have access to the macro and serde. +struct ExternAbiWrapper(rustc_abi::ExternAbi); +impl FromStr for ExternAbiWrapper { + type Err = String; + fn from_str(s: &str) -> Result { + rustc_abi::ExternAbi::from_str(s) + .map(Self) + .map_err(|_| format!("{s} is not a valid extern ABI")) + } +} +crate::json::serde_deserialize_from_str!(ExternAbiWrapper); + +#[derive(serde_derive::Deserialize)] +struct TargetSpecJsonMetadata { + description: Option>, + tier: Option, + host_tools: Option, + std: Option, +} + +#[derive(serde_derive::Deserialize)] +#[serde(rename_all = "kebab-case")] +// Ensure that all unexpected fields get turned into errors. +// This helps users stay up to date when the schema changes instead of silently +// ignoring their old values. +#[serde(deny_unknown_fields)] +struct TargetSpecJson { + llvm_target: StaticCow, + target_pointer_width: String, + data_layout: StaticCow, + arch: StaticCow, + + metadata: Option, + + // options: + target_endian: Option, + frame_pointer: Option, + #[serde(rename = "target-c-int-width")] + c_int_width: Option, + c_enum_min_bits: Option, + os: Option>, + env: Option>, + abi: Option>, + vendor: Option>, + linker: Option>, + #[serde(rename = "linker-flavor")] + linker_flavor_json: Option, + #[serde(rename = "lld-flavor")] + lld_flavor_json: Option, + #[serde(rename = "linker-is-gnu")] + linker_is_gnu_json: Option, + #[serde(rename = "pre-link-objects")] + pre_link_objects: Option, + #[serde(rename = "post-link-objects")] + post_link_objects: Option, + #[serde(rename = "pre-link-objects-fallback")] + pre_link_objects_self_contained: Option, + #[serde(rename = "post-link-objects-fallback")] + post_link_objects_self_contained: Option, + #[serde(rename = "crt-objects-fallback")] + link_self_contained_backwards_compatible: Option, + link_self_contained: Option, + #[serde(rename = "pre-link-args")] + pre_link_args_json: Option, + #[serde(rename = "late-link-args")] + late_link_args_json: Option, + #[serde(rename = "late-link-args-dynamic")] + late_link_args_dynamic_json: Option, + #[serde(rename = "late-link-args-static")] + late_link_args_static_json: Option, + #[serde(rename = "post-link-args")] + post_link_args_json: Option, + link_script: Option>, + link_env: Option>>, + link_env_remove: Option]>>, + asm_args: Option]>>, + cpu: Option>, + need_explicit_cpu: Option, + features: Option>, + dynamic_linking: Option, + direct_access_external_data: Option, + dll_tls_export: Option, + only_cdylib: Option, + executables: Option, + relocation_model: Option, + code_model: Option, + tls_model: Option, + disable_redzone: Option, + function_sections: Option, + dll_prefix: Option>, + dll_suffix: Option>, + exe_suffix: Option>, + staticlib_prefix: Option>, + staticlib_suffix: Option>, + target_family: Option, + abi_return_struct_as_int: Option, + is_like_aix: Option, + is_like_darwin: Option, + is_like_solaris: Option, + is_like_windows: Option, + is_like_msvc: Option, + is_like_wasm: Option, + is_like_android: Option, + binary_format: Option, + default_dwarf_version: Option, + allows_weak_linkage: Option, + has_rpath: Option, + no_default_libraries: Option, + position_independent_executables: Option, + static_position_independent_executables: Option, + plt_by_default: Option, + relro_level: Option, + archive_format: Option>, + allow_asm: Option, + main_needs_argc_argv: Option, + has_thread_local: Option, + obj_is_bitcode: Option, + bitcode_llvm_cmdline: Option>, + max_atomic_width: Option, + min_atomic_width: Option, + atomic_cas: Option, + panic_strategy: Option, + crt_static_allows_dylibs: Option, + crt_static_default: Option, + crt_static_respected: Option, + stack_probes: Option, + min_global_align: Option, + default_codegen_units: Option, + default_codegen_backend: Option>, + trap_unreachable: Option, + requires_lto: Option, + singlethread: Option, + no_builtins: Option, + default_visibility: Option, + emit_debug_gdb_scripts: Option, + requires_uwtable: Option, + default_uwtable: Option, + simd_types_indirect: Option, + limit_rdylib_exports: Option, + override_export_symbols: Option]>>, + merge_functions: Option, + #[serde(rename = "target-mcount")] + mcount: Option>, + llvm_mcount_intrinsic: Option>, + llvm_abiname: Option>, + llvm_floatabi: Option, + rustc_abi: Option, + relax_elf_relocations: Option, + llvm_args: Option]>>, + use_ctors_section: Option, + eh_frame_header: Option, + has_thumb_interworking: Option, + debuginfo_kind: Option, + split_debuginfo: Option, + supported_split_debuginfo: Option>, + supported_sanitizers: Option>, + generate_arange_section: Option, + supports_stack_protector: Option, + small_data_threshold_support: Option, + entry_name: Option>, + supports_xray: Option, + entry_abi: Option, +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 4bc0d88a910cb..c64cd9a51b7d2 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -37,6 +37,7 @@ //! //! [JSON]: https://json.org +use core::result::Result; use std::borrow::Cow; use std::collections::BTreeMap; use std::hash::{Hash, Hasher}; @@ -198,18 +199,29 @@ impl LldFlavor { LldFlavor::Link => "link", } } +} - fn from_str(s: &str) -> Option { - Some(match s { +impl FromStr for LldFlavor { + type Err = String; + + fn from_str(s: &str) -> Result { + Ok(match s { "darwin" => LldFlavor::Ld64, "gnu" => LldFlavor::Ld, "link" => LldFlavor::Link, "wasm" => LldFlavor::Wasm, - _ => return None, + _ => { + return Err( + "invalid value for lld flavor: '{s}', expected one of 'darwin', 'gnu', 'link', 'wasm'" + .into(), + ); + } }) } } +crate::json::serde_deserialize_from_str!(LldFlavor); + impl ToJson for LldFlavor { fn to_json(&self) -> Json { self.as_str().to_json() @@ -494,19 +506,23 @@ macro_rules! linker_flavor_cli_impls { concat!("one of: ", $($string, " ",)*) } - pub fn from_str(s: &str) -> Option { - Some(match s { - $($string => $($flavor)*,)* - _ => return None, - }) - } - pub fn desc(self) -> &'static str { match self { $($($flavor)* => $string,)* } } } + + impl FromStr for LinkerFlavorCli { + type Err = String; + + fn from_str(s: &str) -> Result { + Ok(match s { + $($string => $($flavor)*,)* + _ => return Err(format!("invalid linker flavor, allowed values: {}", Self::one_of())), + }) + } + } ) } @@ -540,6 +556,8 @@ linker_flavor_cli_impls! { (LinkerFlavorCli::Em) "em" } +crate::json::serde_deserialize_from_str!(LinkerFlavorCli); + impl ToJson for LinkerFlavorCli { fn to_json(&self) -> Json { self.desc().to_json() @@ -573,19 +591,26 @@ pub enum LinkSelfContainedDefault { /// Parses a backwards-compatible `-Clink-self-contained` option string, without components. impl FromStr for LinkSelfContainedDefault { - type Err = (); + type Err = String; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { Ok(match s { "false" => LinkSelfContainedDefault::False, "true" | "wasm" => LinkSelfContainedDefault::True, "musl" => LinkSelfContainedDefault::InferredForMusl, "mingw" => LinkSelfContainedDefault::InferredForMingw, - _ => return Err(()), + _ => { + return Err(format!( + "'{s}' is not a valid `-Clink-self-contained` default. \ + Use 'false', 'true', 'wasm', 'musl' or 'mingw'", + )); + } }) } } +crate::json::serde_deserialize_from_str!(LinkSelfContainedDefault); + impl ToJson for LinkSelfContainedDefault { fn to_json(&self) -> Json { match *self { @@ -652,19 +677,6 @@ bitflags::bitflags! { rustc_data_structures::external_bitflags_debug! { LinkSelfContainedComponents } impl LinkSelfContainedComponents { - /// Parses a single `-Clink-self-contained` well-known component, not a set of flags. - pub fn from_str(s: &str) -> Option { - Some(match s { - "crto" => LinkSelfContainedComponents::CRT_OBJECTS, - "libc" => LinkSelfContainedComponents::LIBC, - "unwind" => LinkSelfContainedComponents::UNWIND, - "linker" => LinkSelfContainedComponents::LINKER, - "sanitizers" => LinkSelfContainedComponents::SANITIZERS, - "mingw" => LinkSelfContainedComponents::MINGW, - _ => return None, - }) - } - /// Return the component's name. /// /// Returns `None` if the bitflags aren't a singular component (but a mix of multiple flags). @@ -708,6 +720,29 @@ impl LinkSelfContainedComponents { } } +impl FromStr for LinkSelfContainedComponents { + type Err = String; + + /// Parses a single `-Clink-self-contained` well-known component, not a set of flags. + fn from_str(s: &str) -> Result { + Ok(match s { + "crto" => LinkSelfContainedComponents::CRT_OBJECTS, + "libc" => LinkSelfContainedComponents::LIBC, + "unwind" => LinkSelfContainedComponents::UNWIND, + "linker" => LinkSelfContainedComponents::LINKER, + "sanitizers" => LinkSelfContainedComponents::SANITIZERS, + "mingw" => LinkSelfContainedComponents::MINGW, + _ => { + return Err(format!( + "'{s}' is not a valid link-self-contained component, expected 'crto', 'libc', 'unwind', 'linker', 'sanitizers', 'mingw'" + )); + } + }) + } +} + +crate::json::serde_deserialize_from_str!(LinkSelfContainedComponents); + impl ToJson for LinkSelfContainedComponents { fn to_json(&self) -> Json { let components: Vec<_> = Self::all_components() @@ -821,6 +856,25 @@ impl PanicStrategy { } } +impl FromStr for PanicStrategy { + type Err = String; + fn from_str(s: &str) -> Result { + Ok(match s { + "unwind" => PanicStrategy::Unwind, + "abort" => PanicStrategy::Abort, + _ => { + return Err(format!( + "'{}' is not a valid value for \ + panic-strategy. Use 'unwind' or 'abort'.", + s + )); + } + }) + } +} + +crate::json::serde_deserialize_from_str!(PanicStrategy); + impl ToJson for PanicStrategy { fn to_json(&self) -> Json { match *self { @@ -867,18 +921,24 @@ impl SymbolVisibility { } impl FromStr for SymbolVisibility { - type Err = (); + type Err = String; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { match s { "hidden" => Ok(SymbolVisibility::Hidden), "protected" => Ok(SymbolVisibility::Protected), "interposable" => Ok(SymbolVisibility::Interposable), - _ => Err(()), + _ => Err(format!( + "'{}' is not a valid value for \ + symbol-visibility. Use 'hidden', 'protected, or 'interposable'.", + s + )), } } } +crate::json::serde_deserialize_from_str!(SymbolVisibility); + impl ToJson for SymbolVisibility { fn to_json(&self) -> Json { match *self { @@ -890,19 +950,25 @@ impl ToJson for SymbolVisibility { } impl FromStr for RelroLevel { - type Err = (); + type Err = String; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { match s { "full" => Ok(RelroLevel::Full), "partial" => Ok(RelroLevel::Partial), "off" => Ok(RelroLevel::Off), "none" => Ok(RelroLevel::None), - _ => Err(()), + _ => Err(format!( + "'{}' is not a valid value for \ + relro-level. Use 'full', 'partial, 'off', or 'none'.", + s + )), } } } +crate::json::serde_deserialize_from_str!(RelroLevel); + impl ToJson for RelroLevel { fn to_json(&self) -> Json { match *self { @@ -923,7 +989,7 @@ pub enum SmallDataThresholdSupport { } impl FromStr for SmallDataThresholdSupport { - type Err = (); + type Err = String; fn from_str(s: &str) -> Result { if s == "none" { @@ -935,11 +1001,13 @@ impl FromStr for SmallDataThresholdSupport { } else if let Some(arg) = s.strip_prefix("llvm-arg=") { Ok(Self::LlvmArg(arg.to_string().into())) } else { - Err(()) + Err(format!("'{s}' is not a valid value for small-data-threshold-support.")) } } } +crate::json::serde_deserialize_from_str!(SmallDataThresholdSupport); + impl ToJson for SmallDataThresholdSupport { fn to_json(&self) -> Value { match self { @@ -969,18 +1037,25 @@ impl MergeFunctions { } impl FromStr for MergeFunctions { - type Err = (); + type Err = String; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { match s { "disabled" => Ok(MergeFunctions::Disabled), "trampolines" => Ok(MergeFunctions::Trampolines), "aliases" => Ok(MergeFunctions::Aliases), - _ => Err(()), + _ => Err(format!( + "'{}' is not a valid value for \ + merge-functions. Use 'disabled', \ + 'trampolines', or 'aliases'.", + s + )), } } } +crate::json::serde_deserialize_from_str!(MergeFunctions); + impl ToJson for MergeFunctions { fn to_json(&self) -> Json { match *self { @@ -1040,9 +1115,9 @@ impl RelocModel { } impl FromStr for RelocModel { - type Err = (); + type Err = String; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { Ok(match s { "static" => RelocModel::Static, "pic" => RelocModel::Pic, @@ -1051,11 +1126,19 @@ impl FromStr for RelocModel { "ropi" => RelocModel::Ropi, "rwpi" => RelocModel::Rwpi, "ropi-rwpi" => RelocModel::RopiRwpi, - _ => return Err(()), + _ => { + return Err(format!( + "invalid relocation model '{s}'. + Run `rustc --print relocation-models` to \ + see the list of supported values.'" + )); + } }) } } +crate::json::serde_deserialize_from_str!(RelocModel); + impl ToJson for RelocModel { fn to_json(&self) -> Json { self.desc().to_json() @@ -1072,20 +1155,28 @@ pub enum CodeModel { } impl FromStr for CodeModel { - type Err = (); + type Err = String; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { Ok(match s { "tiny" => CodeModel::Tiny, "small" => CodeModel::Small, "kernel" => CodeModel::Kernel, "medium" => CodeModel::Medium, "large" => CodeModel::Large, - _ => return Err(()), + _ => { + return Err(format!( + "'{s}' is not a valid code model. \ + Run `rustc --print code-models` to \ + see the list of supported values." + )); + } }) } } +crate::json::serde_deserialize_from_str!(CodeModel); + impl ToJson for CodeModel { fn to_json(&self) -> Json { match *self { @@ -1107,17 +1198,25 @@ pub enum FloatAbi { } impl FromStr for FloatAbi { - type Err = (); + type Err = String; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { Ok(match s { "soft" => FloatAbi::Soft, "hard" => FloatAbi::Hard, - _ => return Err(()), + _ => { + return Err(format!( + "'{}' is not a valid value for \ + llvm-floatabi. Use 'soft' or 'hard'.", + s + )); + } }) } } +crate::json::serde_deserialize_from_str!(FloatAbi); + impl ToJson for FloatAbi { fn to_json(&self) -> Json { match *self { @@ -1138,17 +1237,24 @@ pub enum RustcAbi { } impl FromStr for RustcAbi { - type Err = (); + type Err = String; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { Ok(match s { "x86-sse2" => RustcAbi::X86Sse2, "x86-softfloat" => RustcAbi::X86Softfloat, - _ => return Err(()), + _ => { + return Err(format!( + "'{s}' is not a valid value for rustc-abi. \ + Use 'x86-softfloat' or leave the field unset." + )); + } }) } } +crate::json::serde_deserialize_from_str!(RustcAbi); + impl ToJson for RustcAbi { fn to_json(&self) -> Json { match *self { @@ -1169,9 +1275,9 @@ pub enum TlsModel { } impl FromStr for TlsModel { - type Err = (); + type Err = String; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { Ok(match s { // Note the difference "general" vs "global" difference. The model name is "general", // but the user-facing option name is "global" for consistency with other compilers. @@ -1180,11 +1286,19 @@ impl FromStr for TlsModel { "initial-exec" => TlsModel::InitialExec, "local-exec" => TlsModel::LocalExec, "emulated" => TlsModel::Emulated, - _ => return Err(()), + _ => { + return Err(format!( + "'{s}' is not a valid TLS model. \ + Run `rustc --print tls-models` to \ + see the list of supported values." + )); + } }) } } +crate::json::serde_deserialize_from_str!(TlsModel); + impl ToJson for TlsModel { fn to_json(&self) -> Json { match *self { @@ -1230,19 +1344,6 @@ impl LinkOutputKind { } } - pub(super) fn from_str(s: &str) -> Option { - Some(match s { - "dynamic-nopic-exe" => LinkOutputKind::DynamicNoPicExe, - "dynamic-pic-exe" => LinkOutputKind::DynamicPicExe, - "static-nopic-exe" => LinkOutputKind::StaticNoPicExe, - "static-pic-exe" => LinkOutputKind::StaticPicExe, - "dynamic-dylib" => LinkOutputKind::DynamicDylib, - "static-dylib" => LinkOutputKind::StaticDylib, - "wasi-reactor-exe" => LinkOutputKind::WasiReactorExe, - _ => return None, - }) - } - pub fn can_link_dylib(self) -> bool { match self { LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => false, @@ -1255,6 +1356,31 @@ impl LinkOutputKind { } } +impl FromStr for LinkOutputKind { + type Err = String; + + fn from_str(s: &str) -> Result { + Ok(match s { + "dynamic-nopic-exe" => LinkOutputKind::DynamicNoPicExe, + "dynamic-pic-exe" => LinkOutputKind::DynamicPicExe, + "static-nopic-exe" => LinkOutputKind::StaticNoPicExe, + "static-pic-exe" => LinkOutputKind::StaticPicExe, + "dynamic-dylib" => LinkOutputKind::DynamicDylib, + "static-dylib" => LinkOutputKind::StaticDylib, + "wasi-reactor-exe" => LinkOutputKind::WasiReactorExe, + _ => { + return Err(format!( + "invalid value for CRT object kind. \ + Use '(dynamic,static)-(nopic,pic)-exe' or \ + '(dynamic,static)-dylib' or 'wasi-reactor-exe'" + )); + } + }) + } +} + +crate::json::serde_deserialize_from_str!(LinkOutputKind); + impl fmt::Display for LinkOutputKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.as_str()) @@ -1290,18 +1416,25 @@ impl DebuginfoKind { } impl FromStr for DebuginfoKind { - type Err = (); + type Err = String; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { Ok(match s { "dwarf" => DebuginfoKind::Dwarf, "dwarf-dsym" => DebuginfoKind::DwarfDsym, "pdb" => DebuginfoKind::Pdb, - _ => return Err(()), + _ => { + return Err(format!( + "'{s}' is not a valid value for debuginfo-kind. Use 'dwarf', \ + 'dwarf-dsym' or 'pdb'." + )); + } }) } } +crate::json::serde_deserialize_from_str!(DebuginfoKind); + impl ToJson for DebuginfoKind { fn to_json(&self) -> Json { self.as_str().to_json() @@ -1354,18 +1487,25 @@ impl SplitDebuginfo { } impl FromStr for SplitDebuginfo { - type Err = (); + type Err = String; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { Ok(match s { "off" => SplitDebuginfo::Off, "unpacked" => SplitDebuginfo::Unpacked, "packed" => SplitDebuginfo::Packed, - _ => return Err(()), + _ => { + return Err(format!( + "'{s}' is not a valid value for \ + split-debuginfo. Use 'off', 'unpacked', or 'packed'.", + )); + } }) } } +crate::json::serde_deserialize_from_str!(SplitDebuginfo); + impl ToJson for SplitDebuginfo { fn to_json(&self) -> Json { self.as_str().to_json() @@ -1378,7 +1518,9 @@ impl fmt::Display for SplitDebuginfo { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, serde_derive::Deserialize)] +#[serde(tag = "kind")] +#[serde(rename_all = "kebab-case")] pub enum StackProbeType { /// Don't emit any stack probes. None, @@ -1390,44 +1532,10 @@ pub enum StackProbeType { Call, /// Use inline option for LLVM versions later than specified in `min_llvm_version_for_inline` /// and call `__rust_probestack` otherwise. - InlineOrCall { min_llvm_version_for_inline: (u32, u32, u32) }, -} - -impl StackProbeType { - fn from_json(json: &Json) -> Result { - let object = json.as_object().ok_or_else(|| "expected a JSON object")?; - let kind = object - .get("kind") - .and_then(|o| o.as_str()) - .ok_or_else(|| "expected `kind` to be a string")?; - match kind { - "none" => Ok(StackProbeType::None), - "inline" => Ok(StackProbeType::Inline), - "call" => Ok(StackProbeType::Call), - "inline-or-call" => { - let min_version = object - .get("min-llvm-version-for-inline") - .and_then(|o| o.as_array()) - .ok_or_else(|| "expected `min-llvm-version-for-inline` to be an array")?; - let mut iter = min_version.into_iter().map(|v| { - let int = v.as_u64().ok_or_else( - || "expected `min-llvm-version-for-inline` values to be integers", - )?; - u32::try_from(int) - .map_err(|_| "`min-llvm-version-for-inline` values don't convert to u32") - }); - let min_llvm_version_for_inline = ( - iter.next().unwrap_or(Ok(11))?, - iter.next().unwrap_or(Ok(0))?, - iter.next().unwrap_or(Ok(0))?, - ); - Ok(StackProbeType::InlineOrCall { min_llvm_version_for_inline }) - } - _ => Err(String::from( - "`kind` expected to be one of `none`, `inline`, `call` or `inline-or-call`", - )), - } - } + InlineOrCall { + #[serde(rename = "min-llvm-version-for-inline")] + min_llvm_version_for_inline: (u32, u32, u32), + }, } impl ToJson for StackProbeType { @@ -1549,6 +1657,29 @@ impl fmt::Display for SanitizerSet { } } +impl FromStr for SanitizerSet { + type Err = String; + fn from_str(s: &str) -> Result { + Ok(match s { + "address" => SanitizerSet::ADDRESS, + "cfi" => SanitizerSet::CFI, + "dataflow" => SanitizerSet::DATAFLOW, + "kcfi" => SanitizerSet::KCFI, + "kernel-address" => SanitizerSet::KERNELADDRESS, + "leak" => SanitizerSet::LEAK, + "memory" => SanitizerSet::MEMORY, + "memtag" => SanitizerSet::MEMTAG, + "safestack" => SanitizerSet::SAFESTACK, + "shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK, + "thread" => SanitizerSet::THREAD, + "hwaddress" => SanitizerSet::HWADDRESS, + s => return Err(format!("unknown sanitizer {s}")), + }) + } +} + +crate::json::serde_deserialize_from_str!(SanitizerSet); + impl ToJson for SanitizerSet { fn to_json(&self) -> Json { self.into_iter() @@ -1587,17 +1718,19 @@ impl FramePointer { } impl FromStr for FramePointer { - type Err = (); - fn from_str(s: &str) -> Result { + type Err = String; + fn from_str(s: &str) -> Result { Ok(match s { "always" => Self::Always, "non-leaf" => Self::NonLeaf, "may-omit" => Self::MayOmit, - _ => return Err(()), + _ => return Err(format!("'{s}' is not a valid value for frame-pointer")), }) } } +crate::json::serde_deserialize_from_str!(FramePointer); + impl ToJson for FramePointer { fn to_json(&self) -> Json { match *self { @@ -1685,7 +1818,7 @@ impl BinaryFormat { } impl FromStr for BinaryFormat { - type Err = (); + type Err = String; fn from_str(s: &str) -> Result { match s { "coff" => Ok(Self::Coff), @@ -1693,11 +1826,16 @@ impl FromStr for BinaryFormat { "mach-o" => Ok(Self::MachO), "wasm" => Ok(Self::Wasm), "xcoff" => Ok(Self::Xcoff), - _ => Err(()), + _ => Err(format!( + "'{s}' is not a valid value for binary_format. \ + Use 'coff', 'elf', 'mach-o', 'wasm' or 'xcoff' " + )), } } } +crate::json::serde_deserialize_from_str!(BinaryFormat); + impl ToJson for BinaryFormat { fn to_json(&self) -> Json { match self { @@ -2130,12 +2268,11 @@ pub(crate) use cvs; #[derive(Debug, PartialEq)] pub struct TargetWarnings { unused_fields: Vec, - incorrect_type: Vec, } impl TargetWarnings { pub fn empty() -> Self { - Self { unused_fields: Vec::new(), incorrect_type: Vec::new() } + Self { unused_fields: Vec::new() } } pub fn warning_messages(&self) -> Vec { @@ -2146,12 +2283,6 @@ impl TargetWarnings { self.unused_fields.join(", ") )); } - if !self.incorrect_type.is_empty() { - warnings.push(format!( - "target json file contains fields whose value doesn't have the correct json type: {}", - self.incorrect_type.join(", ") - )); - } warnings } } @@ -3325,7 +3456,8 @@ impl Target { /// Test target self-consistency and JSON encoding/decoding roundtrip. #[cfg(test)] fn test_target(mut self) { - let recycled_target = Target::from_json(self.to_json()).map(|(j, _)| j); + let recycled_target = + Target::from_json(&serde_json::to_string(&self.to_json()).unwrap()).map(|(j, _)| j); self.update_to_cli(); self.check_consistency(TargetKind::Builtin).unwrap(); assert_eq!(recycled_target, Ok(self)); @@ -3373,8 +3505,7 @@ impl Target { fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> { let contents = fs::read_to_string(path).map_err(|e| e.to_string())?; - let obj = serde_json::from_str(&contents).map_err(|e| e.to_string())?; - Target::from_json(obj) + Target::from_json(&contents) } match *target_tuple { @@ -3422,10 +3553,7 @@ impl Target { Err(format!("could not find specification for target {target_tuple:?}")) } } - TargetTuple::TargetJson { ref contents, .. } => { - let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?; - Target::from_json(obj) - } + TargetTuple::TargetJson { ref contents, .. } => Target::from_json(contents), } } diff --git a/compiler/rustc_target/src/tests.rs b/compiler/rustc_target/src/tests.rs index 76375170db63d..ee847a84007f0 100644 --- a/compiler/rustc_target/src/tests.rs +++ b/compiler/rustc_target/src/tests.rs @@ -2,8 +2,7 @@ use crate::spec::Target; #[test] fn report_unused_fields() { - let json = serde_json::from_str( - r#" + let json = r#" { "arch": "powerpc64", "data-layout": "e-m:e-i64:64-n32:64", @@ -11,47 +10,8 @@ fn report_unused_fields() { "target-pointer-width": "64", "code-mode": "foo" } - "#, - ) - .unwrap(); - let warnings = Target::from_json(json).unwrap().1; - assert_eq!(warnings.warning_messages().len(), 1); - assert!(warnings.warning_messages().join("\n").contains("code-mode")); -} - -#[test] -fn report_incorrect_json_type() { - let json = serde_json::from_str( - r#" - { - "arch": "powerpc64", - "data-layout": "e-m:e-i64:64-n32:64", - "llvm-target": "powerpc64le-elf", - "target-pointer-width": "64", - "link-env-remove": "foo" - } - "#, - ) - .unwrap(); - let warnings = Target::from_json(json).unwrap().1; - assert_eq!(warnings.warning_messages().len(), 1); - assert!(warnings.warning_messages().join("\n").contains("link-env-remove")); -} - -#[test] -fn no_warnings_for_valid_target() { - let json = serde_json::from_str( - r#" - { - "arch": "powerpc64", - "data-layout": "e-m:e-i64:64-n32:64", - "llvm-target": "powerpc64le-elf", - "target-pointer-width": "64", - "link-env-remove": ["foo"] - } - "#, - ) - .unwrap(); - let warnings = Target::from_json(json).unwrap().1; - assert_eq!(warnings.warning_messages().len(), 0); + "#; + let result = Target::from_json(json); + eprintln!("{result:#?}"); + assert!(result.is_err()); } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 38ba6b4503dc1..a32c2f7fb18c5 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -444,7 +444,7 @@ fn add_exe_suffix(input: String, target: &TargetTuple) -> String { let exe_suffix = match target { TargetTuple::TargetTuple(_) => Target::expect_builtin(target).options.exe_suffix, TargetTuple::TargetJson { contents, .. } => { - Target::from_json(contents.parse().unwrap()).unwrap().0.options.exe_suffix + Target::from_json(contents).unwrap().0.options.exe_suffix } }; input + &exe_suffix diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index f43f5eae9a560..d17ae162ab235 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -378,6 +378,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "serde", "serde_derive", "serde_json", + "serde_path_to_error", "sha1", "sha2", "sharded-slab", diff --git a/tests/run-make/rustdoc-target-spec-json-path/target.json b/tests/run-make/rustdoc-target-spec-json-path/target.json index c478f1196fae0..d7e4cac57ae75 100644 --- a/tests/run-make/rustdoc-target-spec-json-path/target.json +++ b/tests/run-make/rustdoc-target-spec-json-path/target.json @@ -6,7 +6,6 @@ "dynamic-linking": true, "env": "gnu", "executables": true, - "has-elf-tls": true, "has-rpath": true, "linker-is-gnu": true, "llvm-target": "x86_64-unknown-linux-gnu", diff --git a/tests/run-make/target-specs/endianness-mismatch.json b/tests/run-make/target-specs/endianness-mismatch.json index 431053ea99b60..cc03becc59af6 100644 --- a/tests/run-make/target-specs/endianness-mismatch.json +++ b/tests/run-make/target-specs/endianness-mismatch.json @@ -5,7 +5,6 @@ "llvm-target": "x86_64-unknown-linux-gnu", "target-endian": "big", "target-pointer-width": "64", - "target-c-int-width": "32", "arch": "x86_64", "os": "linux" } diff --git a/tests/run-make/target-specs/my-awesome-platform.json b/tests/run-make/target-specs/my-awesome-platform.json index 1673ef7bd54d1..d41038b84a865 100644 --- a/tests/run-make/target-specs/my-awesome-platform.json +++ b/tests/run-make/target-specs/my-awesome-platform.json @@ -4,8 +4,6 @@ "llvm-target": "i686-unknown-linux-gnu", "target-endian": "little", "target-pointer-width": "32", - "target-c-int-width": "32", "arch": "x86", - "os": "linux", - "morestack": false + "os": "linux" } diff --git a/tests/run-make/target-specs/my-incomplete-platform.json b/tests/run-make/target-specs/my-incomplete-platform.json index ceaa25cdf2fef..8bdc4108f494a 100644 --- a/tests/run-make/target-specs/my-incomplete-platform.json +++ b/tests/run-make/target-specs/my-incomplete-platform.json @@ -3,8 +3,6 @@ "linker-flavor": "gcc", "target-endian": "little", "target-pointer-width": "32", - "target-c-int-width": "32", "arch": "x86", - "os": "foo", - "morestack": false + "os": "foo" } diff --git a/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json b/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json index 0cafce15a9fef..27833f1abdd9e 100644 --- a/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json +++ b/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json @@ -5,8 +5,6 @@ "llvm-target": "x86_64-unknown-linux-gnu", "target-endian": "little", "target-pointer-width": "64", - "target-c-int-width": "32", "arch": "x86_64", - "os": "linux", - "morestack": false + "os": "linux" } diff --git a/tests/run-make/target-specs/require-explicit-cpu.json b/tests/run-make/target-specs/require-explicit-cpu.json index 5cbb9573b3f12..9744bca168e2d 100644 --- a/tests/run-make/target-specs/require-explicit-cpu.json +++ b/tests/run-make/target-specs/require-explicit-cpu.json @@ -4,7 +4,6 @@ "llvm-target": "i686-unknown-linux-gnu", "target-endian": "little", "target-pointer-width": "32", - "target-c-int-width": "32", "arch": "x86", "os": "linux", "need-explicit-cpu": true diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs index 9184e5f772f78..7e565588ed6bc 100644 --- a/tests/run-make/target-specs/rmake.rs +++ b/tests/run-make/target-specs/rmake.rs @@ -8,8 +8,6 @@ use run_make_support::{diff, rfs, rustc}; fn main() { - rustc().input("foo.rs").target("my-awesome-platform.json").crate_type("lib").emit("asm").run(); - assert!(!rfs::read_to_string("foo.s").contains("morestack")); rustc() .input("foo.rs") .target("my-invalid-platform.json") @@ -19,7 +17,7 @@ fn main() { .input("foo.rs") .target("my-incomplete-platform.json") .run_fail() - .assert_stderr_contains("Field llvm-target"); + .assert_stderr_contains("missing field `llvm-target`"); rustc() .env("RUST_TARGET_PATH", ".") .input("foo.rs") diff --git a/tests/ui/check-cfg/my-awesome-platform.json b/tests/ui/check-cfg/my-awesome-platform.json index 03b08b727bd3a..4c16d06c7b7d6 100644 --- a/tests/ui/check-cfg/my-awesome-platform.json +++ b/tests/ui/check-cfg/my-awesome-platform.json @@ -4,7 +4,6 @@ "arch": "x86_64", "target-endian": "little", "target-pointer-width": "64", - "target-c-int-width": "32", "os": "ericos", "linker-flavor": "ld.lld", "linker": "rust-lld", diff --git a/tests/ui/codegen/mismatched-data-layout.json b/tests/ui/codegen/mismatched-data-layout.json index 7adc883252474..f8c510c186362 100644 --- a/tests/ui/codegen/mismatched-data-layout.json +++ b/tests/ui/codegen/mismatched-data-layout.json @@ -4,7 +4,6 @@ "arch": "x86_64", "target-endian": "little", "target-pointer-width": "64", - "target-c-int-width": "32", "os": "none", "linker-flavor": "ld.lld", "linker": "rust-lld", diff --git a/tests/ui/codegen/mismatched-data-layouts.rs b/tests/ui/codegen/mismatched-data-layouts.rs index 6428b8c5247b7..ea1457148a52c 100644 --- a/tests/ui/codegen/mismatched-data-layouts.rs +++ b/tests/ui/codegen/mismatched-data-layouts.rs @@ -5,6 +5,7 @@ //@ compile-flags: --crate-type=lib --target={{src-base}}/codegen/mismatched-data-layout.json -Z unstable-options //@ normalize-stderr: "`, `[A-Za-z0-9-:]*`" -> "`, `normalized data layout`" //@ normalize-stderr: "layout, `[A-Za-z0-9-:]*`" -> "layout, `normalized data layout`" +//@ normalize-stderr: "`mismatched-data-layout-\d+`" -> "`mismatched-data-layout-`" #![feature(lang_items, no_core, auto_traits)] #![no_core] diff --git a/tests/ui/codegen/mismatched-data-layouts.stderr b/tests/ui/codegen/mismatched-data-layouts.stderr index b7d5d82bee08c..d1117564d5b73 100644 --- a/tests/ui/codegen/mismatched-data-layouts.stderr +++ b/tests/ui/codegen/mismatched-data-layouts.stderr @@ -1,4 +1,4 @@ -error: data-layout for target `mismatched-data-layout-7193370089426056427`, `normalized data layout`, differs from LLVM target's `x86_64-unknown-none-gnu` default layout, `normalized data layout` +error: data-layout for target `mismatched-data-layout-`, `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