Skip to content

Commit f57f8a0

Browse files
committed
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 4a5f1cc + a3a4327 commit f57f8a0

22 files changed

+629
-24
lines changed

Diff for: compiler/rustc_interface/src/passes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ fn configure_and_expand(
269269

270270
resolver.resolve_crate(&krate);
271271

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

Diff for: 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

Diff for: 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,

Diff for: 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+
}

Diff for: 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);

Diff for: 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::{AssocItemContainer, SymbolName};
2525
use rustc_middle::util::common::to_readable_str;
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;

Diff for: 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,

Diff for: 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,

Diff for: compiler/rustc_session/src/config.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,7 @@ impl Default for Options {
11911191
color: ColorConfig::Auto,
11921192
logical_env: FxIndexMap::default(),
11931193
verbose: false,
1194+
target_modifiers: BTreeMap::default(),
11941195
}
11951196
}
11961197
}
@@ -2337,14 +2338,16 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
23372338
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
23382339
.unwrap_or_else(|e| early_dcx.early_fatal(e));
23392340

2340-
let mut unstable_opts = UnstableOptions::build(early_dcx, matches);
2341+
let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
2342+
2343+
let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
23412344
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
23422345

23432346
check_error_format_stability(early_dcx, &unstable_opts, error_format);
23442347

23452348
let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
23462349

2347-
let mut cg = CodegenOptions::build(early_dcx, matches);
2350+
let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
23482351
let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
23492352
early_dcx,
23502353
&output_types,
@@ -2615,6 +2618,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
26152618
color,
26162619
logical_env,
26172620
verbose,
2621+
target_modifiers,
26182622
}
26192623
}
26202624

Diff for: 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)