Skip to content

Commit 05c88a3

Browse files
committed
Target modifiers (special marked options) are recorded in metainfo and compared to be equal in different crates
1 parent 01a26c0 commit 05c88a3

22 files changed

+666
-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)