Skip to content

Commit 7daf4cf

Browse files
committedFeb 3, 2025
Auto merge of rust-lang#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: rust-lang/rfcs#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.
2 parents 613bdd4 + 05c88a3 commit 7daf4cf

22 files changed

+666
-24
lines changed
 

‎compiler/rustc_interface/src/passes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ fn configure_and_expand(
268268

269269
resolver.resolve_crate(&krate);
270270

271+
CStore::from_tcx(tcx).report_incompatible_target_modifiers(tcx, &krate);
271272
krate
272273
}
273274

‎compiler/rustc_metadata/messages.ftl

+10
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,14 @@ metadata_incompatible_rustc =
113113
found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info}
114114
.help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first)
115115
116+
metadata_incompatible_target_modifiers =
117+
mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}`
118+
.note = `{$flag_name_prefixed}={$flag_local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$flag_extern_value}` in dependency `{$extern_crate}`
119+
.help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
120+
121+
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
122+
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}`
123+
116124
metadata_incompatible_wasm_link =
117125
`wasm_import_module` is incompatible with other arguments in `#[link]` attributes
118126
@@ -284,6 +292,8 @@ metadata_unknown_link_kind =
284292
metadata_unknown_link_modifier =
285293
unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
286294
295+
metadata_unknown_target_modifier_unsafe_allowed = unknown target modifier `{$flag_name}`, requested by `-Cunsafe-allow-abi-mismatch={$flag_name}`
296+
287297
metadata_unsupported_abi =
288298
ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
289299

‎compiler/rustc_metadata/src/creader.rs

+95-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ use rustc_hir::definitions::Definitions;
2323
use rustc_index::IndexVec;
2424
use rustc_middle::bug;
2525
use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
26-
use rustc_session::config::{self, CrateType, ExternLocation};
26+
use rustc_session::config::{
27+
self, CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers,
28+
TargetModifier,
29+
};
2730
use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
2831
use rustc_session::lint::{self, BuiltinLintDiag};
2932
use rustc_session::output::validate_crate_name;
@@ -35,7 +38,9 @@ use tracing::{debug, info, trace};
3538

3639
use crate::errors;
3740
use crate::locator::{CrateError, CrateLocator, CratePaths};
38-
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
41+
use crate::rmeta::{
42+
CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers,
43+
};
3944

4045
/// The backend's way to give the crate store access to the metadata in a library.
4146
/// Note that it returns the raw metadata bytes stored in the library file, whether
@@ -296,6 +301,94 @@ impl CStore {
296301
}
297302
}
298303

304+
fn report_target_modifiers_extended(
305+
tcx: TyCtxt<'_>,
306+
krate: &Crate,
307+
mods: &TargetModifiers,
308+
dep_mods: &TargetModifiers,
309+
data: &CrateMetadata,
310+
) {
311+
let span = krate.spans.inner_span.shrink_to_lo();
312+
let allowed_flag_mismatches = &tcx.sess.opts.cg.unsafe_allow_abi_mismatch;
313+
let name = tcx.crate_name(LOCAL_CRATE);
314+
let tmod_extender = |tmod: &TargetModifier| (tmod.extend(), tmod.clone());
315+
let report_diff = |prefix: &String,
316+
opt_name: &String,
317+
flag_local_value: &String,
318+
flag_extern_value: &String| {
319+
if allowed_flag_mismatches.contains(&opt_name) {
320+
return;
321+
}
322+
tcx.dcx().emit_err(errors::IncompatibleTargetModifiers {
323+
span,
324+
extern_crate: data.name(),
325+
local_crate: name,
326+
flag_name: opt_name.clone(),
327+
flag_name_prefixed: format!("-{}{}", prefix, opt_name),
328+
flag_local_value: flag_local_value.to_string(),
329+
flag_extern_value: flag_extern_value.to_string(),
330+
});
331+
};
332+
let mut it1 = mods.iter().map(tmod_extender);
333+
let mut it2 = dep_mods.iter().map(tmod_extender);
334+
let mut left_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
335+
let mut right_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
336+
let no_val = "*".to_string();
337+
loop {
338+
left_name_val = left_name_val.or_else(|| it1.next());
339+
right_name_val = right_name_val.or_else(|| it2.next());
340+
match (&left_name_val, &right_name_val) {
341+
(Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {
342+
cmp::Ordering::Equal => {
343+
if l.0.tech_value != r.0.tech_value {
344+
report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &r.1.value_name);
345+
}
346+
left_name_val = None;
347+
right_name_val = None;
348+
}
349+
cmp::Ordering::Greater => {
350+
report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name);
351+
right_name_val = None;
352+
}
353+
cmp::Ordering::Less => {
354+
report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val);
355+
left_name_val = None;
356+
}
357+
},
358+
(Some(l), None) => {
359+
report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val);
360+
left_name_val = None;
361+
}
362+
(None, Some(r)) => {
363+
report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name);
364+
right_name_val = None;
365+
}
366+
(None, None) => break,
367+
}
368+
}
369+
}
370+
371+
pub fn report_incompatible_target_modifiers(&self, tcx: TyCtxt<'_>, krate: &Crate) {
372+
for flag_name in &tcx.sess.opts.cg.unsafe_allow_abi_mismatch {
373+
if !OptionsTargetModifiers::is_target_modifier(flag_name) {
374+
tcx.dcx().emit_err(errors::UnknownTargetModifierUnsafeAllowed {
375+
span: krate.spans.inner_span.shrink_to_lo(),
376+
flag_name: flag_name.clone(),
377+
});
378+
}
379+
}
380+
let mods = tcx.sess.opts.gather_target_modifiers();
381+
for (_cnum, data) in self.iter_crate_data() {
382+
if data.is_proc_macro_crate() {
383+
continue;
384+
}
385+
let dep_mods = data.target_modifiers();
386+
if mods != dep_mods {
387+
Self::report_target_modifiers_extended(tcx, krate, &mods, &dep_mods, data);
388+
}
389+
}
390+
}
391+
299392
pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
300393
CStore {
301394
metadata_loader,

‎compiler/rustc_metadata/src/errors.rs

+25
Original file line numberDiff line numberDiff line change
@@ -739,3 +739,28 @@ pub(crate) struct WasmCAbi {
739739
#[primary_span]
740740
pub span: Span,
741741
}
742+
743+
#[derive(Diagnostic)]
744+
#[diag(metadata_incompatible_target_modifiers)]
745+
#[help]
746+
#[note]
747+
#[help(metadata_incompatible_target_modifiers_help_fix)]
748+
#[help(metadata_incompatible_target_modifiers_help_allow)]
749+
pub struct IncompatibleTargetModifiers {
750+
#[primary_span]
751+
pub span: Span,
752+
pub extern_crate: Symbol,
753+
pub local_crate: Symbol,
754+
pub flag_name: String,
755+
pub flag_name_prefixed: String,
756+
pub flag_local_value: String,
757+
pub flag_extern_value: String,
758+
}
759+
760+
#[derive(Diagnostic)]
761+
#[diag(metadata_unknown_target_modifier_unsafe_allowed)]
762+
pub struct UnknownTargetModifierUnsafeAllowed {
763+
#[primary_span]
764+
pub span: Span,
765+
pub flag_name: String,
766+
}

‎compiler/rustc_metadata/src/rmeta/decoder.rs

+15
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use rustc_middle::{bug, implement_ty_decoder};
2929
use rustc_serialize::opaque::MemDecoder;
3030
use rustc_serialize::{Decodable, Decoder};
3131
use rustc_session::Session;
32+
use rustc_session::config::TargetModifier;
3233
use rustc_session::cstore::{CrateSource, ExternCrate};
3334
use rustc_span::hygiene::HygieneDecodeContext;
3435
use rustc_span::{BytePos, DUMMY_SP, Pos, SpanData, SpanDecoder, SyntaxContext, kw};
@@ -73,6 +74,9 @@ impl MetadataBlob {
7374
/// own crate numbers.
7475
pub(crate) type CrateNumMap = IndexVec<CrateNum, CrateNum>;
7576

77+
/// Target modifiers - abi or exploit mitigations flags
78+
pub(crate) type TargetModifiers = Vec<TargetModifier>;
79+
7680
pub(crate) struct CrateMetadata {
7781
/// The primary crate data - binary metadata blob.
7882
blob: MetadataBlob,
@@ -961,6 +965,13 @@ impl CrateRoot {
961965
) -> impl ExactSizeIterator<Item = CrateDep> + Captures<'a> {
962966
self.crate_deps.decode(metadata)
963967
}
968+
969+
pub(crate) fn decode_target_modifiers<'a>(
970+
&self,
971+
metadata: &'a MetadataBlob,
972+
) -> impl ExactSizeIterator<Item = TargetModifier> + Captures<'a> {
973+
self.target_modifiers.decode(metadata)
974+
}
964975
}
965976

966977
impl<'a> CrateMetadataRef<'a> {
@@ -1883,6 +1894,10 @@ impl CrateMetadata {
18831894
self.dependencies.push(cnum);
18841895
}
18851896

1897+
pub(crate) fn target_modifiers(&self) -> TargetModifiers {
1898+
self.root.decode_target_modifiers(&self.blob).collect()
1899+
}
1900+
18861901
pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool {
18871902
let update =
18881903
Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);

‎compiler/rustc_metadata/src/rmeta/encoder.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use rustc_middle::ty::fast_reject::{self, TreatParams};
2525
use rustc_middle::ty::{AssocItemContainer, SymbolName};
2626
use rustc_middle::{bug, span_bug};
2727
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque};
28-
use rustc_session::config::{CrateType, OptLevel};
28+
use rustc_session::config::{CrateType, OptLevel, TargetModifier};
2929
use rustc_span::hygiene::HygieneEncodeContext;
3030
use rustc_span::{
3131
ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, SyntaxContext,
@@ -692,6 +692,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
692692
// Encode source_map. This needs to be done last, because encoding `Span`s tells us which
693693
// `SourceFiles` we actually need to encode.
694694
let source_map = stat!("source-map", || self.encode_source_map());
695+
let target_modifiers = stat!("target-modifiers", || self.encode_target_modifiers());
695696

696697
let root = stat!("final", || {
697698
let attrs = tcx.hir().krate_attrs();
@@ -735,6 +736,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
735736
native_libraries,
736737
foreign_modules,
737738
source_map,
739+
target_modifiers,
738740
traits,
739741
impls,
740742
incoherent_impls,
@@ -2009,6 +2011,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
20092011
self.lazy_array(deps.iter().map(|(_, dep)| dep))
20102012
}
20112013

2014+
fn encode_target_modifiers(&mut self) -> LazyArray<TargetModifier> {
2015+
empty_proc_macro!(self);
2016+
let tcx = self.tcx;
2017+
self.lazy_array(tcx.sess.opts.gather_target_modifiers())
2018+
}
2019+
20122020
fn encode_lib_features(&mut self) -> LazyArray<(Symbol, FeatureStability)> {
20132021
empty_proc_macro!(self);
20142022
let tcx = self.tcx;

‎compiler/rustc_metadata/src/rmeta/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::marker::PhantomData;
22
use std::num::NonZero;
33

4-
pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
4+
pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob, TargetModifiers};
55
use decoder::{DecodeContext, Metadata};
66
use def_path_hash_map::DefPathHashMapRef;
77
use encoder::EncodeContext;
@@ -32,7 +32,7 @@ use rustc_middle::ty::{
3232
use rustc_middle::util::Providers;
3333
use rustc_middle::{mir, trivially_parameterized_over_tcx};
3434
use rustc_serialize::opaque::FileEncoder;
35-
use rustc_session::config::SymbolManglingVersion;
35+
use rustc_session::config::{SymbolManglingVersion, TargetModifier};
3636
use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
3737
use rustc_span::edition::Edition;
3838
use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData};
@@ -282,6 +282,7 @@ pub(crate) struct CrateRoot {
282282
def_path_hash_map: LazyValue<DefPathHashMapRef<'static>>,
283283

284284
source_map: LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>>,
285+
target_modifiers: LazyArray<TargetModifier>,
285286

286287
compiler_builtins: bool,
287288
needs_allocator: bool,

‎compiler/rustc_middle/src/ty/parameterized.rs

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ trivially_parameterized_over_tcx! {
101101
rustc_session::cstore::ForeignModule,
102102
rustc_session::cstore::LinkagePreference,
103103
rustc_session::cstore::NativeLib,
104+
rustc_session::config::TargetModifier,
104105
rustc_span::ExpnData,
105106
rustc_span::ExpnHash,
106107
rustc_span::ExpnId,

‎compiler/rustc_session/src/config.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,7 @@ impl Default for Options {
12241224
color: ColorConfig::Auto,
12251225
logical_env: FxIndexMap::default(),
12261226
verbose: false,
1227+
target_modifiers: BTreeMap::default(),
12271228
}
12281229
}
12291230
}
@@ -2370,14 +2371,16 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
23702371
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
23712372
.unwrap_or_else(|e| early_dcx.early_fatal(e));
23722373

2373-
let mut unstable_opts = UnstableOptions::build(early_dcx, matches);
2374+
let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
2375+
2376+
let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
23742377
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
23752378

23762379
check_error_format_stability(early_dcx, &unstable_opts, error_format);
23772380

23782381
let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
23792382

2380-
let mut cg = CodegenOptions::build(early_dcx, matches);
2383+
let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
23812384
let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
23822385
early_dcx,
23832386
&output_types,
@@ -2648,6 +2651,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
26482651
color,
26492652
logical_env,
26502653
verbose,
2654+
target_modifiers,
26512655
}
26522656
}
26532657

‎compiler/rustc_session/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
#![feature(let_chains)]
55
#![feature(map_many_mut)]
66
#![feature(rustc_attrs)]
7+
// To generate CodegenOptionsTargetModifiers and UnstableOptionsTargetModifiers enums
8+
// with macro_rules, it is necessary to use recursive mechanic ("Incremental TT Munchers").
9+
#![recursion_limit = "256"]
710
#![warn(unreachable_pub)]
811
// tidy-alphabetical-end
912

0 commit comments

Comments
 (0)
Please sign in to comment.