Skip to content
/ rust Public
forked from rust-lang/rust

Commit

Permalink
Rollup merge of rust-lang#133138 - azhogin:azhogin/target-modifiers, …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
jhpratt authored Jan 23, 2025
2 parents 3cd8fcb + 2a544ab commit ff39ce9
Show file tree
Hide file tree
Showing 22 changed files with 656 additions and 24 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ fn configure_and_expand(

resolver.resolve_crate(&krate);

CStore::from_tcx(tcx).report_incompatible_target_modifiers(tcx, &krate);
krate
}

Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_metadata/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
120 changes: 118 additions & 2 deletions compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -296,6 +301,96 @@ impl CStore {
}
}

fn report_target_modifiers_extended(
tcx: TyCtxt<'_>,
krate: &Crate,
mods: &Vec<TargetModifier>,
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 = data.target_modifiers().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(),
});
}
}

if tcx.crate_types().contains(&CrateType::ProcMacro) {
return;
}
let mods = tcx.sess.opts.gather_target_modifiers();
for (_cnum, data) in self.iter_crate_data() {
if data.is_proc_macro_crate() {
continue;
}
if mods != *data.target_modifiers() {
Self::report_target_modifiers_extended(tcx, krate, &mods, data);
}
}
}

pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
CStore {
metadata_loader,
Expand Down Expand Up @@ -471,6 +566,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
};

let cnum_map = self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind)?;
let target_modifiers = self.resolve_target_modifiers(&crate_root, &metadata, cnum)?;

let raw_proc_macros = if crate_root.is_proc_macro_crate() {
let temp_root;
Expand All @@ -495,6 +591,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
raw_proc_macros,
cnum,
cnum_map,
target_modifiers,
dep_kind,
source,
private_dep,
Expand Down Expand Up @@ -738,6 +835,25 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
Ok(crate_num_map)
}

fn resolve_target_modifiers(
&mut self,
crate_root: &CrateRoot,
metadata: &MetadataBlob,
krate: CrateNum,
) -> Result<TargetModifiers, CrateError> {
debug!("resolving target modifiers of external crate");
if crate_root.is_proc_macro_crate() {
return Ok(TargetModifiers::new());
}
let mods = crate_root.decode_target_modifiers(metadata);
let mut target_modifiers = TargetModifiers::with_capacity(mods.len());
for modifier in mods {
target_modifiers.push(modifier);
}
debug!("resolve_target_modifiers: target mods for {:?} is {:?}", krate, target_modifiers);
Ok(target_modifiers)
}

fn dlsym_proc_macros(
&self,
path: &Path,
Expand Down
25 changes: 25 additions & 0 deletions compiler/rustc_metadata/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,3 +732,28 @@ pub struct ImportNameTypeRaw {
#[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,
}
19 changes: 19 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -110,6 +114,8 @@ pub(crate) struct CrateMetadata {
cnum_map: CrateNumMap,
/// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime.
dependencies: Vec<CrateNum>,
/// Target modifiers - abi and exploit mitigation flags the crate was compiled with
target_modifiers: TargetModifiers,
/// How to link (or not link) this crate to the currently compiled crate.
dep_kind: CrateDepKind,
/// Filesystem location of this crate.
Expand Down Expand Up @@ -961,6 +967,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> {
Expand Down Expand Up @@ -1823,6 +1836,7 @@ impl CrateMetadata {
raw_proc_macros: Option<&'static [ProcMacro]>,
cnum: CrateNum,
cnum_map: CrateNumMap,
target_modifiers: TargetModifiers,
dep_kind: CrateDepKind,
source: CrateSource,
private_dep: bool,
Expand Down Expand Up @@ -1854,6 +1868,7 @@ impl CrateMetadata {
cnum,
cnum_map,
dependencies,
target_modifiers,
dep_kind,
source: Lrc::new(source),
private_dep,
Expand Down Expand Up @@ -1883,6 +1898,10 @@ impl CrateMetadata {
self.dependencies.push(cnum);
}

pub(crate) fn target_modifiers(&self) -> &TargetModifiers {
&self.target_modifiers
}

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);
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use rustc_middle::ty::{AssocItemContainer, SymbolName};
use rustc_middle::util::common::to_readable_str;
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,
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -735,6 +736,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
native_libraries,
foreign_modules,
source_map,
target_modifiers,
traits,
impls,
incoherent_impls,
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/parameterized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ trivially_parameterized_over_tcx! {
rustc_session::cstore::ForeignModule,
rustc_session::cstore::LinkagePreference,
rustc_session::cstore::NativeLib,
rustc_session::config::TargetModifier,
rustc_span::ExpnData,
rustc_span::ExpnHash,
rustc_span::ExpnId,
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,7 @@ impl Default for Options {
color: ColorConfig::Auto,
logical_env: FxIndexMap::default(),
verbose: false,
target_modifiers: BTreeMap::default(),
}
}
}
Expand Down Expand Up @@ -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)
.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);

check_error_format_stability(early_dcx, &unstable_opts, error_format);

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(
early_dcx,
&output_types,
Expand Down Expand Up @@ -2615,6 +2618,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
color,
logical_env,
verbose,
target_modifiers,
}
}

Expand Down
Loading

0 comments on commit ff39ce9

Please sign in to comment.