Target modifiers (special marked options) are recorded in metainfo and compared to be equal in different crates
This commit is contained in:
parent
01a26c026d
commit
05c88a31e7
22 changed files with 666 additions and 24 deletions
|
@ -269,6 +269,7 @@ fn configure_and_expand(
|
||||||
|
|
||||||
resolver.resolve_crate(&krate);
|
resolver.resolve_crate(&krate);
|
||||||
|
|
||||||
|
CStore::from_tcx(tcx).report_incompatible_target_modifiers(tcx, &krate);
|
||||||
krate
|
krate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,14 @@ metadata_incompatible_rustc =
|
||||||
found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info}
|
found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info}
|
||||||
.help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first)
|
.help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first)
|
||||||
|
|
||||||
|
metadata_incompatible_target_modifiers =
|
||||||
|
mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}`
|
||||||
|
.note = `{$flag_name_prefixed}={$flag_local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$flag_extern_value}` in dependency `{$extern_crate}`
|
||||||
|
.help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
|
||||||
|
|
||||||
|
metadata_incompatible_target_modifiers_help_allow = if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch={$flag_name}` to silence this error
|
||||||
|
metadata_incompatible_target_modifiers_help_fix = set `{$flag_name_prefixed}={$flag_extern_value}` in this crate or `{$flag_name_prefixed}={$flag_local_value}` in `{$extern_crate}`
|
||||||
|
|
||||||
metadata_incompatible_wasm_link =
|
metadata_incompatible_wasm_link =
|
||||||
`wasm_import_module` is incompatible with other arguments in `#[link]` attributes
|
`wasm_import_module` is incompatible with other arguments in `#[link]` attributes
|
||||||
|
|
||||||
|
@ -284,6 +292,8 @@ metadata_unknown_link_kind =
|
||||||
metadata_unknown_link_modifier =
|
metadata_unknown_link_modifier =
|
||||||
unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
|
unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
|
||||||
|
|
||||||
|
metadata_unknown_target_modifier_unsafe_allowed = unknown target modifier `{$flag_name}`, requested by `-Cunsafe-allow-abi-mismatch={$flag_name}`
|
||||||
|
|
||||||
metadata_unsupported_abi =
|
metadata_unsupported_abi =
|
||||||
ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
|
ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,10 @@ use rustc_hir::definitions::Definitions;
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
|
use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
|
||||||
use rustc_session::config::{self, CrateType, ExternLocation};
|
use rustc_session::config::{
|
||||||
|
self, CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers,
|
||||||
|
TargetModifier,
|
||||||
|
};
|
||||||
use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
|
use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
|
||||||
use rustc_session::lint::{self, BuiltinLintDiag};
|
use rustc_session::lint::{self, BuiltinLintDiag};
|
||||||
use rustc_session::output::validate_crate_name;
|
use rustc_session::output::validate_crate_name;
|
||||||
|
@ -35,7 +38,9 @@ use tracing::{debug, info, trace};
|
||||||
|
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::locator::{CrateError, CrateLocator, CratePaths};
|
use crate::locator::{CrateError, CrateLocator, CratePaths};
|
||||||
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
|
use crate::rmeta::{
|
||||||
|
CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers,
|
||||||
|
};
|
||||||
|
|
||||||
/// The backend's way to give the crate store access to the metadata in a library.
|
/// The backend's way to give the crate store access to the metadata in a library.
|
||||||
/// Note that it returns the raw metadata bytes stored in the library file, whether
|
/// Note that it returns the raw metadata bytes stored in the library file, whether
|
||||||
|
@ -296,6 +301,94 @@ impl CStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_target_modifiers_extended(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
krate: &Crate,
|
||||||
|
mods: &TargetModifiers,
|
||||||
|
dep_mods: &TargetModifiers,
|
||||||
|
data: &CrateMetadata,
|
||||||
|
) {
|
||||||
|
let span = krate.spans.inner_span.shrink_to_lo();
|
||||||
|
let allowed_flag_mismatches = &tcx.sess.opts.cg.unsafe_allow_abi_mismatch;
|
||||||
|
let name = tcx.crate_name(LOCAL_CRATE);
|
||||||
|
let tmod_extender = |tmod: &TargetModifier| (tmod.extend(), tmod.clone());
|
||||||
|
let report_diff = |prefix: &String,
|
||||||
|
opt_name: &String,
|
||||||
|
flag_local_value: &String,
|
||||||
|
flag_extern_value: &String| {
|
||||||
|
if allowed_flag_mismatches.contains(&opt_name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tcx.dcx().emit_err(errors::IncompatibleTargetModifiers {
|
||||||
|
span,
|
||||||
|
extern_crate: data.name(),
|
||||||
|
local_crate: name,
|
||||||
|
flag_name: opt_name.clone(),
|
||||||
|
flag_name_prefixed: format!("-{}{}", prefix, opt_name),
|
||||||
|
flag_local_value: flag_local_value.to_string(),
|
||||||
|
flag_extern_value: flag_extern_value.to_string(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
let mut it1 = mods.iter().map(tmod_extender);
|
||||||
|
let mut it2 = dep_mods.iter().map(tmod_extender);
|
||||||
|
let mut left_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
|
||||||
|
let mut right_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
|
||||||
|
let no_val = "*".to_string();
|
||||||
|
loop {
|
||||||
|
left_name_val = left_name_val.or_else(|| it1.next());
|
||||||
|
right_name_val = right_name_val.or_else(|| it2.next());
|
||||||
|
match (&left_name_val, &right_name_val) {
|
||||||
|
(Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {
|
||||||
|
cmp::Ordering::Equal => {
|
||||||
|
if l.0.tech_value != r.0.tech_value {
|
||||||
|
report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &r.1.value_name);
|
||||||
|
}
|
||||||
|
left_name_val = None;
|
||||||
|
right_name_val = None;
|
||||||
|
}
|
||||||
|
cmp::Ordering::Greater => {
|
||||||
|
report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name);
|
||||||
|
right_name_val = None;
|
||||||
|
}
|
||||||
|
cmp::Ordering::Less => {
|
||||||
|
report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val);
|
||||||
|
left_name_val = None;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(Some(l), None) => {
|
||||||
|
report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val);
|
||||||
|
left_name_val = None;
|
||||||
|
}
|
||||||
|
(None, Some(r)) => {
|
||||||
|
report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name);
|
||||||
|
right_name_val = None;
|
||||||
|
}
|
||||||
|
(None, None) => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report_incompatible_target_modifiers(&self, tcx: TyCtxt<'_>, krate: &Crate) {
|
||||||
|
for flag_name in &tcx.sess.opts.cg.unsafe_allow_abi_mismatch {
|
||||||
|
if !OptionsTargetModifiers::is_target_modifier(flag_name) {
|
||||||
|
tcx.dcx().emit_err(errors::UnknownTargetModifierUnsafeAllowed {
|
||||||
|
span: krate.spans.inner_span.shrink_to_lo(),
|
||||||
|
flag_name: flag_name.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mods = tcx.sess.opts.gather_target_modifiers();
|
||||||
|
for (_cnum, data) in self.iter_crate_data() {
|
||||||
|
if data.is_proc_macro_crate() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let dep_mods = data.target_modifiers();
|
||||||
|
if mods != dep_mods {
|
||||||
|
Self::report_target_modifiers_extended(tcx, krate, &mods, &dep_mods, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
|
pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
|
||||||
CStore {
|
CStore {
|
||||||
metadata_loader,
|
metadata_loader,
|
||||||
|
|
|
@ -739,3 +739,28 @@ pub(crate) struct WasmCAbi {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(metadata_incompatible_target_modifiers)]
|
||||||
|
#[help]
|
||||||
|
#[note]
|
||||||
|
#[help(metadata_incompatible_target_modifiers_help_fix)]
|
||||||
|
#[help(metadata_incompatible_target_modifiers_help_allow)]
|
||||||
|
pub struct IncompatibleTargetModifiers {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub extern_crate: Symbol,
|
||||||
|
pub local_crate: Symbol,
|
||||||
|
pub flag_name: String,
|
||||||
|
pub flag_name_prefixed: String,
|
||||||
|
pub flag_local_value: String,
|
||||||
|
pub flag_extern_value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(metadata_unknown_target_modifier_unsafe_allowed)]
|
||||||
|
pub struct UnknownTargetModifierUnsafeAllowed {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub flag_name: String,
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ use rustc_middle::{bug, implement_ty_decoder};
|
||||||
use rustc_serialize::opaque::MemDecoder;
|
use rustc_serialize::opaque::MemDecoder;
|
||||||
use rustc_serialize::{Decodable, Decoder};
|
use rustc_serialize::{Decodable, Decoder};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
|
use rustc_session::config::TargetModifier;
|
||||||
use rustc_session::cstore::{CrateSource, ExternCrate};
|
use rustc_session::cstore::{CrateSource, ExternCrate};
|
||||||
use rustc_span::hygiene::HygieneDecodeContext;
|
use rustc_span::hygiene::HygieneDecodeContext;
|
||||||
use rustc_span::{BytePos, DUMMY_SP, Pos, SpanData, SpanDecoder, SyntaxContext, kw};
|
use rustc_span::{BytePos, DUMMY_SP, Pos, SpanData, SpanDecoder, SyntaxContext, kw};
|
||||||
|
@ -73,6 +74,9 @@ impl MetadataBlob {
|
||||||
/// own crate numbers.
|
/// own crate numbers.
|
||||||
pub(crate) type CrateNumMap = IndexVec<CrateNum, CrateNum>;
|
pub(crate) type CrateNumMap = IndexVec<CrateNum, CrateNum>;
|
||||||
|
|
||||||
|
/// Target modifiers - abi or exploit mitigations flags
|
||||||
|
pub(crate) type TargetModifiers = Vec<TargetModifier>;
|
||||||
|
|
||||||
pub(crate) struct CrateMetadata {
|
pub(crate) struct CrateMetadata {
|
||||||
/// The primary crate data - binary metadata blob.
|
/// The primary crate data - binary metadata blob.
|
||||||
blob: MetadataBlob,
|
blob: MetadataBlob,
|
||||||
|
@ -961,6 +965,13 @@ impl CrateRoot {
|
||||||
) -> impl ExactSizeIterator<Item = CrateDep> + Captures<'a> {
|
) -> impl ExactSizeIterator<Item = CrateDep> + Captures<'a> {
|
||||||
self.crate_deps.decode(metadata)
|
self.crate_deps.decode(metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn decode_target_modifiers<'a>(
|
||||||
|
&self,
|
||||||
|
metadata: &'a MetadataBlob,
|
||||||
|
) -> impl ExactSizeIterator<Item = TargetModifier> + Captures<'a> {
|
||||||
|
self.target_modifiers.decode(metadata)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CrateMetadataRef<'a> {
|
impl<'a> CrateMetadataRef<'a> {
|
||||||
|
@ -1883,6 +1894,10 @@ impl CrateMetadata {
|
||||||
self.dependencies.push(cnum);
|
self.dependencies.push(cnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn target_modifiers(&self) -> TargetModifiers {
|
||||||
|
self.root.decode_target_modifiers(&self.blob).collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool {
|
pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool {
|
||||||
let update =
|
let update =
|
||||||
Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);
|
Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);
|
||||||
|
|
|
@ -25,7 +25,7 @@ use rustc_middle::ty::{AssocItemContainer, SymbolName};
|
||||||
use rustc_middle::util::common::to_readable_str;
|
use rustc_middle::util::common::to_readable_str;
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque};
|
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque};
|
||||||
use rustc_session::config::{CrateType, OptLevel};
|
use rustc_session::config::{CrateType, OptLevel, TargetModifier};
|
||||||
use rustc_span::hygiene::HygieneEncodeContext;
|
use rustc_span::hygiene::HygieneEncodeContext;
|
||||||
use rustc_span::{
|
use rustc_span::{
|
||||||
ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, SyntaxContext,
|
ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, SyntaxContext,
|
||||||
|
@ -692,6 +692,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
// Encode source_map. This needs to be done last, because encoding `Span`s tells us which
|
// Encode source_map. This needs to be done last, because encoding `Span`s tells us which
|
||||||
// `SourceFiles` we actually need to encode.
|
// `SourceFiles` we actually need to encode.
|
||||||
let source_map = stat!("source-map", || self.encode_source_map());
|
let source_map = stat!("source-map", || self.encode_source_map());
|
||||||
|
let target_modifiers = stat!("target-modifiers", || self.encode_target_modifiers());
|
||||||
|
|
||||||
let root = stat!("final", || {
|
let root = stat!("final", || {
|
||||||
let attrs = tcx.hir().krate_attrs();
|
let attrs = tcx.hir().krate_attrs();
|
||||||
|
@ -735,6 +736,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
native_libraries,
|
native_libraries,
|
||||||
foreign_modules,
|
foreign_modules,
|
||||||
source_map,
|
source_map,
|
||||||
|
target_modifiers,
|
||||||
traits,
|
traits,
|
||||||
impls,
|
impls,
|
||||||
incoherent_impls,
|
incoherent_impls,
|
||||||
|
@ -2009,6 +2011,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
self.lazy_array(deps.iter().map(|(_, dep)| dep))
|
self.lazy_array(deps.iter().map(|(_, dep)| dep))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn encode_target_modifiers(&mut self) -> LazyArray<TargetModifier> {
|
||||||
|
empty_proc_macro!(self);
|
||||||
|
let tcx = self.tcx;
|
||||||
|
self.lazy_array(tcx.sess.opts.gather_target_modifiers())
|
||||||
|
}
|
||||||
|
|
||||||
fn encode_lib_features(&mut self) -> LazyArray<(Symbol, FeatureStability)> {
|
fn encode_lib_features(&mut self) -> LazyArray<(Symbol, FeatureStability)> {
|
||||||
empty_proc_macro!(self);
|
empty_proc_macro!(self);
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
|
|
||||||
pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
|
pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob, TargetModifiers};
|
||||||
use decoder::{DecodeContext, Metadata};
|
use decoder::{DecodeContext, Metadata};
|
||||||
use def_path_hash_map::DefPathHashMapRef;
|
use def_path_hash_map::DefPathHashMapRef;
|
||||||
use encoder::EncodeContext;
|
use encoder::EncodeContext;
|
||||||
|
@ -32,7 +32,7 @@ use rustc_middle::ty::{
|
||||||
use rustc_middle::util::Providers;
|
use rustc_middle::util::Providers;
|
||||||
use rustc_middle::{mir, trivially_parameterized_over_tcx};
|
use rustc_middle::{mir, trivially_parameterized_over_tcx};
|
||||||
use rustc_serialize::opaque::FileEncoder;
|
use rustc_serialize::opaque::FileEncoder;
|
||||||
use rustc_session::config::SymbolManglingVersion;
|
use rustc_session::config::{SymbolManglingVersion, TargetModifier};
|
||||||
use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
|
use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData};
|
use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData};
|
||||||
|
@ -282,6 +282,7 @@ pub(crate) struct CrateRoot {
|
||||||
def_path_hash_map: LazyValue<DefPathHashMapRef<'static>>,
|
def_path_hash_map: LazyValue<DefPathHashMapRef<'static>>,
|
||||||
|
|
||||||
source_map: LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>>,
|
source_map: LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>>,
|
||||||
|
target_modifiers: LazyArray<TargetModifier>,
|
||||||
|
|
||||||
compiler_builtins: bool,
|
compiler_builtins: bool,
|
||||||
needs_allocator: bool,
|
needs_allocator: bool,
|
||||||
|
|
|
@ -101,6 +101,7 @@ trivially_parameterized_over_tcx! {
|
||||||
rustc_session::cstore::ForeignModule,
|
rustc_session::cstore::ForeignModule,
|
||||||
rustc_session::cstore::LinkagePreference,
|
rustc_session::cstore::LinkagePreference,
|
||||||
rustc_session::cstore::NativeLib,
|
rustc_session::cstore::NativeLib,
|
||||||
|
rustc_session::config::TargetModifier,
|
||||||
rustc_span::ExpnData,
|
rustc_span::ExpnData,
|
||||||
rustc_span::ExpnHash,
|
rustc_span::ExpnHash,
|
||||||
rustc_span::ExpnId,
|
rustc_span::ExpnId,
|
||||||
|
|
|
@ -1191,6 +1191,7 @@ impl Default for Options {
|
||||||
color: ColorConfig::Auto,
|
color: ColorConfig::Auto,
|
||||||
logical_env: FxIndexMap::default(),
|
logical_env: FxIndexMap::default(),
|
||||||
verbose: false,
|
verbose: false,
|
||||||
|
target_modifiers: BTreeMap::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2337,14 +2338,16 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
|
||||||
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
|
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
|
||||||
.unwrap_or_else(|e| early_dcx.early_fatal(e));
|
.unwrap_or_else(|e| early_dcx.early_fatal(e));
|
||||||
|
|
||||||
let mut unstable_opts = UnstableOptions::build(early_dcx, matches);
|
let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
|
||||||
|
|
||||||
|
let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
|
||||||
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
|
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
|
||||||
|
|
||||||
check_error_format_stability(early_dcx, &unstable_opts, error_format);
|
check_error_format_stability(early_dcx, &unstable_opts, error_format);
|
||||||
|
|
||||||
let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
|
let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
|
||||||
|
|
||||||
let mut cg = CodegenOptions::build(early_dcx, matches);
|
let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
|
||||||
let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
|
let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
|
||||||
early_dcx,
|
early_dcx,
|
||||||
&output_types,
|
&output_types,
|
||||||
|
@ -2615,6 +2618,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
|
||||||
color,
|
color,
|
||||||
logical_env,
|
logical_env,
|
||||||
verbose,
|
verbose,
|
||||||
|
target_modifiers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(map_many_mut)]
|
#![feature(map_many_mut)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
// To generate CodegenOptionsTargetModifiers and UnstableOptionsTargetModifiers enums
|
||||||
|
// with macro_rules, it is necessary to use recursive mechanic ("Incremental TT Munchers").
|
||||||
|
#![recursion_limit = "256"]
|
||||||
#![warn(unreachable_pub)]
|
#![warn(unreachable_pub)]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ use rustc_data_structures::profiling::TimePassesFormat;
|
||||||
use rustc_data_structures::stable_hasher::Hash64;
|
use rustc_data_structures::stable_hasher::Hash64;
|
||||||
use rustc_errors::{ColorConfig, LanguageIdentifier, TerminalUrl};
|
use rustc_errors::{ColorConfig, LanguageIdentifier, TerminalUrl};
|
||||||
use rustc_feature::UnstableFeatures;
|
use rustc_feature::UnstableFeatures;
|
||||||
|
use rustc_macros::{Decodable, Encodable};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::{RealFileName, SourceFileHashAlgorithm};
|
use rustc_span::{RealFileName, SourceFileHashAlgorithm};
|
||||||
use rustc_target::spec::{
|
use rustc_target::spec::{
|
||||||
|
@ -59,18 +60,194 @@ macro_rules! hash_substruct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extended target modifier info.
|
||||||
|
/// For example, when external target modifier is '-Zregparm=2':
|
||||||
|
/// Target modifier enum value + user value ('2') from external crate
|
||||||
|
/// is converted into description: prefix ('Z'), name ('regparm'), tech value ('Some(2)').
|
||||||
|
pub struct ExtendedTargetModifierInfo {
|
||||||
|
/// Flag prefix (usually, 'C' for codegen flags or 'Z' for unstable flags)
|
||||||
|
pub prefix: String,
|
||||||
|
/// Flag name
|
||||||
|
pub name: String,
|
||||||
|
/// Flag parsed technical value
|
||||||
|
pub tech_value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A recorded -Zopt_name=opt_value (or -Copt_name=opt_value)
|
||||||
|
/// which alter the ABI or effectiveness of exploit mitigations.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
|
||||||
|
pub struct TargetModifier {
|
||||||
|
/// Option enum value
|
||||||
|
pub opt: OptionsTargetModifiers,
|
||||||
|
/// User-provided option value (before parsing)
|
||||||
|
pub value_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TargetModifier {
|
||||||
|
pub fn extend(&self) -> ExtendedTargetModifierInfo {
|
||||||
|
self.opt.reparse(&self.value_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tmod_push_impl(
|
||||||
|
opt: OptionsTargetModifiers,
|
||||||
|
tmod_vals: &BTreeMap<OptionsTargetModifiers, String>,
|
||||||
|
tmods: &mut Vec<TargetModifier>,
|
||||||
|
) {
|
||||||
|
tmods.push(TargetModifier { opt, value_name: tmod_vals.get(&opt).cloned().unwrap_or_default() })
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! tmod_push {
|
||||||
|
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $mods:expr, $tmod_vals:expr) => {
|
||||||
|
tmod_push_impl(
|
||||||
|
OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt_name),
|
||||||
|
$tmod_vals,
|
||||||
|
$mods,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! gather_tmods {
|
||||||
|
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
|
||||||
|
[SUBSTRUCT], [TARGET_MODIFIER]) => {
|
||||||
|
compile_error!("SUBSTRUCT can't be target modifier");
|
||||||
|
};
|
||||||
|
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
|
||||||
|
[UNTRACKED], [TARGET_MODIFIER]) => {
|
||||||
|
tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals)
|
||||||
|
};
|
||||||
|
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
|
||||||
|
[TRACKED], [TARGET_MODIFIER]) => {
|
||||||
|
tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals)
|
||||||
|
};
|
||||||
|
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
|
||||||
|
[TRACKED_NO_CRATE_HASH], [TARGET_MODIFIER]) => {
|
||||||
|
tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals)
|
||||||
|
};
|
||||||
|
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
|
||||||
|
[SUBSTRUCT], []) => {
|
||||||
|
$opt_expr.gather_target_modifiers($mods, $tmod_vals);
|
||||||
|
};
|
||||||
|
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
|
||||||
|
[UNTRACKED], []) => {{}};
|
||||||
|
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
|
||||||
|
[TRACKED], []) => {{}};
|
||||||
|
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
|
||||||
|
[TRACKED_NO_CRATE_HASH], []) => {{}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! gather_tmods_top_level {
|
||||||
|
($_opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, [SUBSTRUCT $substruct_enum:ident]) => {
|
||||||
|
$opt_expr.gather_target_modifiers($mods, $tmod_vals);
|
||||||
|
};
|
||||||
|
($opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, [$non_substruct:ident TARGET_MODIFIER]) => {
|
||||||
|
compile_error!("Top level option can't be target modifier");
|
||||||
|
};
|
||||||
|
($opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, [$non_substruct:ident]) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Macro for generating OptionsTargetsModifiers top-level enum with impl.
|
||||||
|
/// Will generate something like:
|
||||||
|
/// ```rust,ignore (illustrative)
|
||||||
|
/// pub enum OptionsTargetModifiers {
|
||||||
|
/// CodegenOptions(CodegenOptionsTargetModifiers),
|
||||||
|
/// UnstableOptions(UnstableOptionsTargetModifiers),
|
||||||
|
/// }
|
||||||
|
/// impl OptionsTargetModifiers {
|
||||||
|
/// pub fn reparse(&self, user_value: &str) -> ExtendedTargetModifierInfo {
|
||||||
|
/// match self {
|
||||||
|
/// Self::CodegenOptions(v) => v.reparse(user_value),
|
||||||
|
/// Self::UnstableOptions(v) => v.reparse(user_value),
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// pub fn is_target_modifier(flag_name: &str) -> bool {
|
||||||
|
/// CodegenOptionsTargetModifiers::is_target_modifier(flag_name) ||
|
||||||
|
/// UnstableOptionsTargetModifiers::is_target_modifier(flag_name)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
macro_rules! top_level_tmod_enum {
|
||||||
|
($( {$($optinfo:tt)*} ),* $(,)*) => {
|
||||||
|
top_level_tmod_enum! { @parse {}, (user_value){}; $($($optinfo)*|)* }
|
||||||
|
};
|
||||||
|
// Termination
|
||||||
|
(
|
||||||
|
@parse
|
||||||
|
{$($variant:tt($substruct_enum:tt))*},
|
||||||
|
($user_value:ident){$($pout:tt)*};
|
||||||
|
) => {
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Encodable, Decodable)]
|
||||||
|
pub enum OptionsTargetModifiers {
|
||||||
|
$($variant($substruct_enum)),*
|
||||||
|
}
|
||||||
|
impl OptionsTargetModifiers {
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
pub fn reparse(&self, $user_value: &str) -> ExtendedTargetModifierInfo {
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
match self {
|
||||||
|
$($pout)*
|
||||||
|
_ => panic!("unknown target modifier option: {:?}", *self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn is_target_modifier(flag_name: &str) -> bool {
|
||||||
|
$($substruct_enum::is_target_modifier(flag_name))||*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Adding SUBSTRUCT option group into $eout
|
||||||
|
(
|
||||||
|
@parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*};
|
||||||
|
[SUBSTRUCT $substruct_enum:ident $variant:ident] |
|
||||||
|
$($tail:tt)*
|
||||||
|
) => {
|
||||||
|
top_level_tmod_enum! {
|
||||||
|
@parse
|
||||||
|
{
|
||||||
|
$($eout)*
|
||||||
|
$variant($substruct_enum)
|
||||||
|
},
|
||||||
|
($puser_value){
|
||||||
|
$($pout)*
|
||||||
|
Self::$variant(v) => v.reparse($puser_value),
|
||||||
|
};
|
||||||
|
$($tail)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Skipping non-target-modifier and non-substruct
|
||||||
|
(
|
||||||
|
@parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*};
|
||||||
|
[$non_substruct:ident] |
|
||||||
|
$($tail:tt)*
|
||||||
|
) => {
|
||||||
|
top_level_tmod_enum! {
|
||||||
|
@parse
|
||||||
|
{
|
||||||
|
$($eout)*
|
||||||
|
},
|
||||||
|
($puser_value){
|
||||||
|
$($pout)*
|
||||||
|
};
|
||||||
|
$($tail)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! top_level_options {
|
macro_rules! top_level_options {
|
||||||
( $( #[$top_level_attr:meta] )* pub struct Options { $(
|
( $( #[$top_level_attr:meta] )* pub struct Options { $(
|
||||||
$( #[$attr:meta] )*
|
$( #[$attr:meta] )*
|
||||||
$opt:ident : $t:ty [$dep_tracking_marker:ident],
|
$opt:ident : $t:ty [$dep_tracking_marker:ident $( $tmod:ident $variant:ident )?],
|
||||||
)* } ) => (
|
)* } ) => (
|
||||||
|
top_level_tmod_enum!( {$([$dep_tracking_marker $($tmod $variant),*])|*} );
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
$( #[$top_level_attr] )*
|
$( #[$top_level_attr] )*
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
$(
|
$(
|
||||||
$( #[$attr] )*
|
$( #[$attr] )*
|
||||||
pub $opt: $t
|
pub $opt: $t
|
||||||
),*
|
),*,
|
||||||
|
pub target_modifiers: BTreeMap<OptionsTargetModifiers, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Options {
|
impl Options {
|
||||||
|
@ -98,6 +275,17 @@ macro_rules! top_level_options {
|
||||||
})*
|
})*
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn gather_target_modifiers(&self) -> Vec<TargetModifier> {
|
||||||
|
let mut mods = Vec::<TargetModifier>::new();
|
||||||
|
$({
|
||||||
|
gather_tmods_top_level!($opt,
|
||||||
|
&self.$opt, &mut mods, &self.target_modifiers,
|
||||||
|
[$dep_tracking_marker $($tmod),*]);
|
||||||
|
})*
|
||||||
|
mods.sort_by(|a, b| a.opt.cmp(&b.opt));
|
||||||
|
mods
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -165,9 +353,9 @@ top_level_options!(
|
||||||
#[rustc_lint_opt_deny_field_access("should only be used via `Config::hash_untracked_state`")]
|
#[rustc_lint_opt_deny_field_access("should only be used via `Config::hash_untracked_state`")]
|
||||||
untracked_state_hash: Hash64 [TRACKED_NO_CRATE_HASH],
|
untracked_state_hash: Hash64 [TRACKED_NO_CRATE_HASH],
|
||||||
|
|
||||||
unstable_opts: UnstableOptions [SUBSTRUCT],
|
unstable_opts: UnstableOptions [SUBSTRUCT UnstableOptionsTargetModifiers UnstableOptions],
|
||||||
prints: Vec<PrintRequest> [UNTRACKED],
|
prints: Vec<PrintRequest> [UNTRACKED],
|
||||||
cg: CodegenOptions [SUBSTRUCT],
|
cg: CodegenOptions [SUBSTRUCT CodegenOptionsTargetModifiers CodegenOptions],
|
||||||
externs: Externs [UNTRACKED],
|
externs: Externs [UNTRACKED],
|
||||||
crate_name: Option<String> [TRACKED],
|
crate_name: Option<String> [TRACKED],
|
||||||
/// Indicates how the compiler should treat unstable features.
|
/// Indicates how the compiler should treat unstable features.
|
||||||
|
@ -226,6 +414,98 @@ top_level_options!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
macro_rules! tmod_enum_opt {
|
||||||
|
($struct_name:ident, $tmod_enum_name:ident, $opt:ident, $v:ident) => {
|
||||||
|
Some(OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt))
|
||||||
|
};
|
||||||
|
($struct_name:ident, $tmod_enum_name:ident, $opt:ident, ) => {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! tmod_enum {
|
||||||
|
($tmod_enum_name:ident, $prefix:expr, $( {$($optinfo:tt)*} ),* $(,)*) => {
|
||||||
|
tmod_enum! { $tmod_enum_name, $prefix, @parse {}, (user_value){}; $($($optinfo)*|)* }
|
||||||
|
};
|
||||||
|
// Termination
|
||||||
|
(
|
||||||
|
$tmod_enum_name:ident, $prefix:expr,
|
||||||
|
@parse
|
||||||
|
{$($eout:tt)*},
|
||||||
|
($user_value:ident){$($pout:tt)*};
|
||||||
|
) => {
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Encodable, Decodable)]
|
||||||
|
pub enum $tmod_enum_name {
|
||||||
|
$($eout),*
|
||||||
|
}
|
||||||
|
impl $tmod_enum_name {
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
pub fn reparse(&self, $user_value: &str) -> ExtendedTargetModifierInfo {
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
match self {
|
||||||
|
$($pout)*
|
||||||
|
_ => panic!("unknown target modifier option: {:?}", *self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn is_target_modifier(flag_name: &str) -> bool {
|
||||||
|
match flag_name.replace('-', "_").as_str() {
|
||||||
|
$(stringify!($eout) => true,)*
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Adding target-modifier option into $eout
|
||||||
|
(
|
||||||
|
$tmod_enum_name:ident, $prefix:expr,
|
||||||
|
@parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*};
|
||||||
|
$opt:ident, $parse:ident, $t:ty, [TARGET_MODIFIER] |
|
||||||
|
$($tail:tt)*
|
||||||
|
) => {
|
||||||
|
tmod_enum! {
|
||||||
|
$tmod_enum_name, $prefix,
|
||||||
|
@parse
|
||||||
|
{
|
||||||
|
$($eout)*
|
||||||
|
$opt
|
||||||
|
},
|
||||||
|
($puser_value){
|
||||||
|
$($pout)*
|
||||||
|
Self::$opt => {
|
||||||
|
let mut parsed : $t = Default::default();
|
||||||
|
parse::$parse(&mut parsed, Some($puser_value));
|
||||||
|
ExtendedTargetModifierInfo {
|
||||||
|
prefix: $prefix.to_string(),
|
||||||
|
name: stringify!($opt).to_string().replace('_', "-"),
|
||||||
|
tech_value: format!("{:?}", parsed),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
$($tail)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Skipping non-target-modifier
|
||||||
|
(
|
||||||
|
$tmod_enum_name:ident, $prefix:expr,
|
||||||
|
@parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*};
|
||||||
|
$opt:ident, $parse:ident, $t:ty, [] |
|
||||||
|
$($tail:tt)*
|
||||||
|
) => {
|
||||||
|
tmod_enum! {
|
||||||
|
$tmod_enum_name, $prefix,
|
||||||
|
@parse
|
||||||
|
{
|
||||||
|
$($eout)*
|
||||||
|
},
|
||||||
|
($puser_value){
|
||||||
|
$($pout)*
|
||||||
|
};
|
||||||
|
$($tail)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
|
/// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
|
||||||
/// macro is to define an interface that can be programmatically used by the option parser
|
/// macro is to define an interface that can be programmatically used by the option parser
|
||||||
/// to initialize the struct without hardcoding field names all over the place.
|
/// to initialize the struct without hardcoding field names all over the place.
|
||||||
|
@ -235,11 +515,11 @@ top_level_options!(
|
||||||
/// generated code to parse an option into its respective field in the struct. There are a few
|
/// generated code to parse an option into its respective field in the struct. There are a few
|
||||||
/// hand-written parsers for parsing specific types of values in this module.
|
/// hand-written parsers for parsing specific types of values in this module.
|
||||||
macro_rules! options {
|
macro_rules! options {
|
||||||
($struct_name:ident, $stat:ident, $optmod:ident, $prefix:expr, $outputname:expr,
|
($struct_name:ident, $tmod_enum_name:ident, $stat:ident, $optmod:ident, $prefix:expr, $outputname:expr,
|
||||||
$($( #[$attr:meta] )* $opt:ident : $t:ty = (
|
$($( #[$attr:meta] )* $opt:ident : $t:ty = (
|
||||||
$init:expr,
|
$init:expr,
|
||||||
$parse:ident,
|
$parse:ident,
|
||||||
[$dep_tracking_marker:ident],
|
[$dep_tracking_marker:ident $( $tmod:ident )?],
|
||||||
$desc:expr
|
$desc:expr
|
||||||
$(, deprecated_do_nothing: $dnn:literal )?)
|
$(, deprecated_do_nothing: $dnn:literal )?)
|
||||||
),* ,) =>
|
),* ,) =>
|
||||||
|
@ -248,6 +528,8 @@ macro_rules! options {
|
||||||
#[rustc_lint_opt_ty]
|
#[rustc_lint_opt_ty]
|
||||||
pub struct $struct_name { $( $( #[$attr] )* pub $opt: $t),* }
|
pub struct $struct_name { $( $( #[$attr] )* pub $opt: $t),* }
|
||||||
|
|
||||||
|
tmod_enum!( $tmod_enum_name, $prefix, {$($opt, $parse, $t, [$($tmod),*])|*} );
|
||||||
|
|
||||||
impl Default for $struct_name {
|
impl Default for $struct_name {
|
||||||
fn default() -> $struct_name {
|
fn default() -> $struct_name {
|
||||||
$struct_name { $($opt: $init),* }
|
$struct_name { $($opt: $init),* }
|
||||||
|
@ -258,8 +540,9 @@ macro_rules! options {
|
||||||
pub fn build(
|
pub fn build(
|
||||||
early_dcx: &EarlyDiagCtxt,
|
early_dcx: &EarlyDiagCtxt,
|
||||||
matches: &getopts::Matches,
|
matches: &getopts::Matches,
|
||||||
|
target_modifiers: &mut BTreeMap<OptionsTargetModifiers, String>,
|
||||||
) -> $struct_name {
|
) -> $struct_name {
|
||||||
build_options(early_dcx, matches, $stat, $prefix, $outputname)
|
build_options(early_dcx, matches, target_modifiers, $stat, $prefix, $outputname)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> u64 {
|
fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> u64 {
|
||||||
|
@ -279,11 +562,23 @@ macro_rules! options {
|
||||||
);
|
);
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn gather_target_modifiers(
|
||||||
|
&self,
|
||||||
|
_mods: &mut Vec<TargetModifier>,
|
||||||
|
_tmod_vals: &BTreeMap<OptionsTargetModifiers, String>,
|
||||||
|
) {
|
||||||
|
$({
|
||||||
|
gather_tmods!($struct_name, $tmod_enum_name, $opt, &self.$opt, _mods, _tmod_vals,
|
||||||
|
[$dep_tracking_marker], [$($tmod),*]);
|
||||||
|
})*
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const $stat: OptionDescrs<$struct_name> =
|
pub const $stat: OptionDescrs<$struct_name> =
|
||||||
&[ $( OptionDesc{ name: stringify!($opt), setter: $optmod::$opt,
|
&[ $( OptionDesc{ name: stringify!($opt), setter: $optmod::$opt,
|
||||||
type_desc: desc::$parse, desc: $desc, is_deprecated_and_do_nothing: false $( || $dnn )? } ),* ];
|
type_desc: desc::$parse, desc: $desc, is_deprecated_and_do_nothing: false $( || $dnn )?,
|
||||||
|
tmod: tmod_enum_opt!($struct_name, $tmod_enum_name, $opt, $($tmod),*) } ),* ];
|
||||||
|
|
||||||
mod $optmod {
|
mod $optmod {
|
||||||
$(
|
$(
|
||||||
|
@ -328,6 +623,7 @@ pub struct OptionDesc<O> {
|
||||||
// description for option from options table
|
// description for option from options table
|
||||||
desc: &'static str,
|
desc: &'static str,
|
||||||
is_deprecated_and_do_nothing: bool,
|
is_deprecated_and_do_nothing: bool,
|
||||||
|
tmod: Option<OptionsTargetModifiers>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<O> OptionDesc<O> {
|
impl<O> OptionDesc<O> {
|
||||||
|
@ -344,6 +640,7 @@ impl<O> OptionDesc<O> {
|
||||||
fn build_options<O: Default>(
|
fn build_options<O: Default>(
|
||||||
early_dcx: &EarlyDiagCtxt,
|
early_dcx: &EarlyDiagCtxt,
|
||||||
matches: &getopts::Matches,
|
matches: &getopts::Matches,
|
||||||
|
target_modifiers: &mut BTreeMap<OptionsTargetModifiers, String>,
|
||||||
descrs: OptionDescrs<O>,
|
descrs: OptionDescrs<O>,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
outputname: &str,
|
outputname: &str,
|
||||||
|
@ -357,7 +654,14 @@ fn build_options<O: Default>(
|
||||||
|
|
||||||
let option_to_lookup = key.replace('-', "_");
|
let option_to_lookup = key.replace('-', "_");
|
||||||
match descrs.iter().find(|opt_desc| opt_desc.name == option_to_lookup) {
|
match descrs.iter().find(|opt_desc| opt_desc.name == option_to_lookup) {
|
||||||
Some(OptionDesc { name: _, setter, type_desc, desc, is_deprecated_and_do_nothing }) => {
|
Some(OptionDesc {
|
||||||
|
name: _,
|
||||||
|
setter,
|
||||||
|
type_desc,
|
||||||
|
desc,
|
||||||
|
is_deprecated_and_do_nothing,
|
||||||
|
tmod,
|
||||||
|
}) => {
|
||||||
if *is_deprecated_and_do_nothing {
|
if *is_deprecated_and_do_nothing {
|
||||||
// deprecation works for prefixed options only
|
// deprecation works for prefixed options only
|
||||||
assert!(!prefix.is_empty());
|
assert!(!prefix.is_empty());
|
||||||
|
@ -377,6 +681,11 @@ fn build_options<O: Default>(
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(tmod) = *tmod
|
||||||
|
&& let Some(value) = value
|
||||||
|
{
|
||||||
|
target_modifiers.insert(tmod, value.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None => early_dcx.early_fatal(format!("unknown {outputname} option: `{key}`")),
|
None => early_dcx.early_fatal(format!("unknown {outputname} option: `{key}`")),
|
||||||
}
|
}
|
||||||
|
@ -1581,7 +1890,7 @@ pub mod parse {
|
||||||
}
|
}
|
||||||
|
|
||||||
options! {
|
options! {
|
||||||
CodegenOptions, CG_OPTIONS, cgopts, "C", "codegen",
|
CodegenOptions, CodegenOptionsTargetModifiers, CG_OPTIONS, cgopts, "C", "codegen",
|
||||||
|
|
||||||
// If you add a new option, please update:
|
// If you add a new option, please update:
|
||||||
// - compiler/rustc_interface/src/tests.rs
|
// - compiler/rustc_interface/src/tests.rs
|
||||||
|
@ -1712,6 +2021,8 @@ options! {
|
||||||
target_feature: String = (String::new(), parse_target_feature, [TRACKED],
|
target_feature: String = (String::new(), parse_target_feature, [TRACKED],
|
||||||
"target specific attributes. (`rustc --print target-features` for details). \
|
"target specific attributes. (`rustc --print target-features` for details). \
|
||||||
This feature is unsafe."),
|
This feature is unsafe."),
|
||||||
|
unsafe_allow_abi_mismatch: Vec<String> = (Vec::new(), parse_comma_list, [UNTRACKED],
|
||||||
|
"Allow incompatible target modifiers in dependency crates (comma separated list)"),
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
// If you add a new option, please update:
|
// If you add a new option, please update:
|
||||||
|
@ -1720,7 +2031,7 @@ options! {
|
||||||
}
|
}
|
||||||
|
|
||||||
options! {
|
options! {
|
||||||
UnstableOptions, Z_OPTIONS, dbopts, "Z", "unstable",
|
UnstableOptions, UnstableOptionsTargetModifiers, Z_OPTIONS, dbopts, "Z", "unstable",
|
||||||
|
|
||||||
// If you add a new option, please update:
|
// If you add a new option, please update:
|
||||||
// - compiler/rustc_interface/src/tests.rs
|
// - compiler/rustc_interface/src/tests.rs
|
||||||
|
@ -2052,10 +2363,10 @@ options! {
|
||||||
"enable queries of the dependency graph for regression testing (default: no)"),
|
"enable queries of the dependency graph for regression testing (default: no)"),
|
||||||
randomize_layout: bool = (false, parse_bool, [TRACKED],
|
randomize_layout: bool = (false, parse_bool, [TRACKED],
|
||||||
"randomize the layout of types (default: no)"),
|
"randomize the layout of types (default: no)"),
|
||||||
reg_struct_return: bool = (false, parse_bool, [TRACKED],
|
reg_struct_return: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
|
||||||
"On x86-32 targets, it overrides the default ABI to return small structs in registers.
|
"On x86-32 targets, it overrides the default ABI to return small structs in registers.
|
||||||
It is UNSOUND to link together crates that use different values for this flag!"),
|
It is UNSOUND to link together crates that use different values for this flag!"),
|
||||||
regparm: Option<u32> = (None, parse_opt_number, [TRACKED],
|
regparm: Option<u32> = (None, parse_opt_number, [TRACKED TARGET_MODIFIER],
|
||||||
"On x86-32 targets, setting this to N causes the compiler to pass N arguments \
|
"On x86-32 targets, setting this to N causes the compiler to pass N arguments \
|
||||||
in registers EAX, EDX, and ECX instead of on the stack for\
|
in registers EAX, EDX, and ECX instead of on the stack for\
|
||||||
\"C\", \"cdecl\", and \"stdcall\" fn.\
|
\"C\", \"cdecl\", and \"stdcall\" fn.\
|
||||||
|
|
|
@ -9,8 +9,8 @@ use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_errors::DiagCtxtHandle;
|
use rustc_errors::DiagCtxtHandle;
|
||||||
use rustc_session::config::{
|
use rustc_session::config::{
|
||||||
self, CodegenOptions, CrateType, ErrorOutputType, Externs, Input, JsonUnusedExterns,
|
self, CodegenOptions, CrateType, ErrorOutputType, Externs, Input, JsonUnusedExterns,
|
||||||
UnstableOptions, get_cmd_lint_options, nightly_options, parse_crate_types_from_list,
|
OptionsTargetModifiers, UnstableOptions, get_cmd_lint_options, nightly_options,
|
||||||
parse_externs, parse_target_triple,
|
parse_crate_types_from_list, parse_externs, parse_target_triple,
|
||||||
};
|
};
|
||||||
use rustc_session::lint::Level;
|
use rustc_session::lint::Level;
|
||||||
use rustc_session::search_paths::SearchPath;
|
use rustc_session::search_paths::SearchPath;
|
||||||
|
@ -387,8 +387,9 @@ impl Options {
|
||||||
config::parse_error_format(early_dcx, matches, color, json_color, json_rendered);
|
config::parse_error_format(early_dcx, matches, color, json_color, json_rendered);
|
||||||
let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default();
|
let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default();
|
||||||
|
|
||||||
let codegen_options = CodegenOptions::build(early_dcx, matches);
|
let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
|
||||||
let unstable_opts = UnstableOptions::build(early_dcx, matches);
|
let codegen_options = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
|
||||||
|
let unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
|
||||||
|
|
||||||
let remap_path_prefix = match parse_remap_path_prefix(matches) {
|
let remap_path_prefix = match parse_remap_path_prefix(matches) {
|
||||||
Ok(prefix_mappings) => prefix_mappings,
|
Ok(prefix_mappings) => prefix_mappings,
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort
|
||||||
|
// Auxiliary build problems with aarch64-apple:
|
||||||
|
// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
|
||||||
|
// Auxiliary build problems with i686-mingw: linker `cc` not found
|
||||||
|
//@ only-x86
|
||||||
|
//@ ignore-windows
|
||||||
|
//@ ignore-apple
|
||||||
|
//@ needs-llvm-components: x86
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
#![no_core]
|
||||||
|
#![feature(no_core, lang_items, repr_simd)]
|
||||||
|
|
||||||
|
#[lang = "sized"]
|
||||||
|
trait Sized {}
|
||||||
|
#[lang = "copy"]
|
||||||
|
trait Copy {}
|
||||||
|
|
||||||
|
pub fn somefun() {}
|
||||||
|
|
||||||
|
pub struct S;
|
20
tests/ui/target_modifiers/auxiliary/wrong_regparm.rs
Normal file
20
tests/ui/target_modifiers/auxiliary/wrong_regparm.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=2 -Cpanic=abort
|
||||||
|
// Auxiliary build problems with aarch64-apple:
|
||||||
|
// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
|
||||||
|
// Auxiliary build problems with i686-mingw: linker `cc` not found
|
||||||
|
//@ only-x86
|
||||||
|
//@ ignore-windows
|
||||||
|
//@ ignore-apple
|
||||||
|
//@ needs-llvm-components: x86
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
#![no_core]
|
||||||
|
#![feature(no_core, lang_items, repr_simd)]
|
||||||
|
|
||||||
|
#[lang = "sized"]
|
||||||
|
trait Sized {}
|
||||||
|
#[lang = "copy"]
|
||||||
|
trait Copy {}
|
||||||
|
|
||||||
|
pub fn somefun() {}
|
||||||
|
|
||||||
|
pub struct S;
|
20
tests/ui/target_modifiers/auxiliary/wrong_regparm_and_ret.rs
Normal file
20
tests/ui/target_modifiers/auxiliary/wrong_regparm_and_ret.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=2 -Zreg-struct-return=true -Cpanic=abort
|
||||||
|
// Auxiliary build problems with aarch64-apple:
|
||||||
|
// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
|
||||||
|
// Auxiliary build problems with i686-mingw: linker `cc` not found
|
||||||
|
//@ only-x86
|
||||||
|
//@ ignore-windows
|
||||||
|
//@ ignore-apple
|
||||||
|
//@ needs-llvm-components: x86
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
#![no_core]
|
||||||
|
#![feature(no_core, lang_items, repr_simd)]
|
||||||
|
|
||||||
|
#[lang = "sized"]
|
||||||
|
trait Sized {}
|
||||||
|
#[lang = "copy"]
|
||||||
|
trait Copy {}
|
||||||
|
|
||||||
|
pub fn somefun() {}
|
||||||
|
|
||||||
|
pub struct S;
|
13
tests/ui/target_modifiers/defaults_check.error.stderr
Normal file
13
tests/ui/target_modifiers/defaults_check.error.stderr
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `defaults_check`
|
||||||
|
--> $DIR/defaults_check.rs:20:1
|
||||||
|
|
|
||||||
|
LL | #![crate_type = "rlib"]
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
|
||||||
|
= note: `-Zreg-struct-return=true` in this crate is incompatible with `-Zreg-struct-return=` in dependency `default_reg_struct_return`
|
||||||
|
= help: set `-Zreg-struct-return=` in this crate or `-Zreg-struct-return=true` in `default_reg_struct_return`
|
||||||
|
= help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
27
tests/ui/target_modifiers/defaults_check.rs
Normal file
27
tests/ui/target_modifiers/defaults_check.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Tests that default unspecified target modifier value in dependency crate is ok linked
|
||||||
|
// with the same value, explicitly specified
|
||||||
|
//@ aux-crate:default_reg_struct_return=default_reg_struct_return.rs
|
||||||
|
//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort
|
||||||
|
//@ revisions:error ok ok_explicit
|
||||||
|
//@[ok] compile-flags:
|
||||||
|
//@[ok_explicit] compile-flags: -Zreg-struct-return=false
|
||||||
|
//@[error] compile-flags: -Zreg-struct-return=true
|
||||||
|
|
||||||
|
// Auxiliary build problems with aarch64-apple:
|
||||||
|
// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
|
||||||
|
// Auxiliary build problems with i686-mingw: linker `cc` not found
|
||||||
|
//@ only-x86
|
||||||
|
//@ ignore-windows
|
||||||
|
//@ ignore-apple
|
||||||
|
//@ needs-llvm-components: x86
|
||||||
|
//@[ok] build-pass
|
||||||
|
//@[ok_explicit] build-pass
|
||||||
|
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
//[error]~^ ERROR mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `defaults_check`
|
||||||
|
#![no_core]
|
||||||
|
#![feature(no_core, lang_items, repr_simd)]
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
default_reg_struct_return::somefun();
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
error: codegen option `unsafe-allow-abi-mismatch` requires a comma-separated list of strings (C unsafe-allow-abi-mismatch=<value>)
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
error: mixing `-Zregparm` will cause an ABI mismatch in crate `incompatible_regparm`
|
||||||
|
--> $DIR/incompatible_regparm.rs:16:1
|
||||||
|
|
|
||||||
|
LL | #![crate_type = "rlib"]
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= help: the `-Zregparm` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
|
||||||
|
= note: `-Zregparm=1` in this crate is incompatible with `-Zregparm=2` in dependency `wrong_regparm`
|
||||||
|
= help: set `-Zregparm=2` in this crate or `-Zregparm=1` in `wrong_regparm`
|
||||||
|
= help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=regparm` to silence this error
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
23
tests/ui/target_modifiers/incompatible_regparm.rs
Normal file
23
tests/ui/target_modifiers/incompatible_regparm.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//@ aux-crate:wrong_regparm=wrong_regparm.rs
|
||||||
|
//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=1 -Cpanic=abort
|
||||||
|
// Auxiliary build problems with aarch64-apple:
|
||||||
|
// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
|
||||||
|
// Auxiliary build problems with i686-mingw: linker `cc` not found
|
||||||
|
//@ only-x86
|
||||||
|
//@ ignore-windows
|
||||||
|
//@ ignore-apple
|
||||||
|
//@ needs-llvm-components: x86
|
||||||
|
//@ revisions:error_generated allow_regparm_mismatch allow_no_value
|
||||||
|
|
||||||
|
//@[allow_regparm_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=regparm
|
||||||
|
//@[allow_regparm_mismatch] build-pass
|
||||||
|
//@[allow_no_value] compile-flags: -Cunsafe-allow-abi-mismatch
|
||||||
|
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
//[error_generated]~^ ERROR mixing `-Zregparm` will cause an ABI mismatch in crate `incompatible_regparm`
|
||||||
|
#![no_core]
|
||||||
|
#![feature(no_core, lang_items, repr_simd)]
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
wrong_regparm::somefun();
|
||||||
|
}
|
23
tests/ui/target_modifiers/two_flags.rs
Normal file
23
tests/ui/target_modifiers/two_flags.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//@ aux-crate:wrong_regparm_and_ret=wrong_regparm_and_ret.rs
|
||||||
|
//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort
|
||||||
|
// Auxiliary build problems with aarch64-apple:
|
||||||
|
// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
|
||||||
|
// Auxiliary build problems with i686-mingw: linker `cc` not found
|
||||||
|
//@ only-x86
|
||||||
|
//@ ignore-windows
|
||||||
|
//@ ignore-apple
|
||||||
|
//@ needs-llvm-components: x86
|
||||||
|
//@ revisions:two_allowed unknown_allowed
|
||||||
|
|
||||||
|
//@[two_allowed] compile-flags: -Cunsafe-allow-abi-mismatch=regparm,reg-struct-return
|
||||||
|
//@[two_allowed] build-pass
|
||||||
|
//@[unknown_allowed] compile-flags: -Cunsafe-allow-abi-mismatch=unknown_flag -Zregparm=2 -Zreg-struct-return=true
|
||||||
|
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
//[unknown_allowed]~^ ERROR unknown target modifier `unknown_flag`, requested by `-Cunsafe-allow-abi-mismatch=unknown_flag`
|
||||||
|
#![no_core]
|
||||||
|
#![feature(no_core, lang_items, repr_simd)]
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
wrong_regparm_and_ret::somefun();
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
error: unknown target modifier `unknown_flag`, requested by `-Cunsafe-allow-abi-mismatch=unknown_flag`
|
||||||
|
--> $DIR/two_flags.rs:16:1
|
||||||
|
|
|
||||||
|
LL | #![crate_type = "rlib"]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue