Auto merge of #133138 - azhogin:azhogin/target-modifiers, r=davidtwco,saethlin
Target modifiers (special marked options) are recorded in metainfo Target modifiers (special marked options) are recorded in metainfo and compared to be equal in different linked crates. PR for this RFC: https://github.com/rust-lang/rfcs/pull/3716 Option may be marked as `TARGET_MODIFIER`, example: `regparm: Option<u32> = (None, parse_opt_number, [TRACKED TARGET_MODIFIER]`. If an TARGET_MODIFIER-marked option has non-default value, it will be recorded in crate metainfo as a `Vec<TargetModifier>`: ``` pub struct TargetModifier { pub opt: OptionsTargetModifiers, pub value_name: String, } ``` OptionsTargetModifiers is a macro-generated enum. Option value code (for comparison) is generated using `Debug` trait. Error example: ``` error: mixing `-Zregparm` will cause an ABI mismatch in crate `incompatible_regparm` --> $DIR/incompatible_regparm.rs:10:1 | LL | #![crate_type = "lib"] | ^ | = 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, use `-Cunsafe-allow-abi-mismatch=regparm` to silence this error error: aborting due to 1 previous error ``` `-Cunsafe-allow-abi-mismatch=regparm,reg-struct-return` to disable list of flags.
This commit is contained in:
commit
7daf4cf911
22 changed files with 666 additions and 24 deletions
|
@ -113,6 +113,14 @@ metadata_incompatible_rustc =
|
|||
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)
|
||||
|
||||
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 =
|
||||
`wasm_import_module` is incompatible with other arguments in `#[link]` attributes
|
||||
|
||||
|
@ -284,6 +292,8 @@ metadata_unknown_link_kind =
|
|||
metadata_unknown_link_modifier =
|
||||
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 =
|
||||
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_middle::bug;
|
||||
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::lint::{self, BuiltinLintDiag};
|
||||
use rustc_session::output::validate_crate_name;
|
||||
|
@ -35,7 +38,9 @@ use tracing::{debug, info, trace};
|
|||
|
||||
use crate::errors;
|
||||
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.
|
||||
/// 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 {
|
||||
CStore {
|
||||
metadata_loader,
|
||||
|
|
|
@ -739,3 +739,28 @@ pub(crate) struct WasmCAbi {
|
|||
#[primary_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::{Decodable, Decoder};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::TargetModifier;
|
||||
use rustc_session::cstore::{CrateSource, ExternCrate};
|
||||
use rustc_span::hygiene::HygieneDecodeContext;
|
||||
use rustc_span::{BytePos, DUMMY_SP, Pos, SpanData, SpanDecoder, SyntaxContext, kw};
|
||||
|
@ -73,6 +74,9 @@ impl MetadataBlob {
|
|||
/// own crate numbers.
|
||||
pub(crate) type CrateNumMap = IndexVec<CrateNum, CrateNum>;
|
||||
|
||||
/// Target modifiers - abi or exploit mitigations flags
|
||||
pub(crate) type TargetModifiers = Vec<TargetModifier>;
|
||||
|
||||
pub(crate) struct CrateMetadata {
|
||||
/// The primary crate data - binary metadata blob.
|
||||
blob: MetadataBlob,
|
||||
|
@ -961,6 +965,13 @@ impl CrateRoot {
|
|||
) -> impl ExactSizeIterator<Item = CrateDep> + Captures<'a> {
|
||||
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> {
|
||||
|
@ -1883,6 +1894,10 @@ impl CrateMetadata {
|
|||
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 {
|
||||
let update =
|
||||
Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);
|
||||
|
|
|
@ -25,7 +25,7 @@ use rustc_middle::ty::fast_reject::{self, TreatParams};
|
|||
use rustc_middle::ty::{AssocItemContainer, SymbolName};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
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::{
|
||||
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
|
||||
// `SourceFiles` we actually need to encode.
|
||||
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 attrs = tcx.hir().krate_attrs();
|
||||
|
@ -735,6 +736,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
native_libraries,
|
||||
foreign_modules,
|
||||
source_map,
|
||||
target_modifiers,
|
||||
traits,
|
||||
impls,
|
||||
incoherent_impls,
|
||||
|
@ -2009,6 +2011,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
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)> {
|
||||
empty_proc_macro!(self);
|
||||
let tcx = self.tcx;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::marker::PhantomData;
|
||||
use std::num::NonZero;
|
||||
|
||||
pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
|
||||
pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob, TargetModifiers};
|
||||
use decoder::{DecodeContext, Metadata};
|
||||
use def_path_hash_map::DefPathHashMapRef;
|
||||
use encoder::EncodeContext;
|
||||
|
@ -32,7 +32,7 @@ use rustc_middle::ty::{
|
|||
use rustc_middle::util::Providers;
|
||||
use rustc_middle::{mir, trivially_parameterized_over_tcx};
|
||||
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_span::edition::Edition;
|
||||
use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData};
|
||||
|
@ -282,6 +282,7 @@ pub(crate) struct CrateRoot {
|
|||
def_path_hash_map: LazyValue<DefPathHashMapRef<'static>>,
|
||||
|
||||
source_map: LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>>,
|
||||
target_modifiers: LazyArray<TargetModifier>,
|
||||
|
||||
compiler_builtins: bool,
|
||||
needs_allocator: bool,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue