Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 43e5956

Browse files
committedNov 20, 2024·
Target modifiers (special marked options) are recorded in metainfo and compared to be equal in different crates
1 parent bca5fde commit 43e5956

File tree

14 files changed

+362
-6
lines changed

14 files changed

+362
-6
lines changed
 

‎compiler/rustc_interface/src/passes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ fn configure_and_expand(
281281

282282
resolver.resolve_crate(&krate);
283283

284+
CStore::from_tcx(tcx).report_incompatible_target_modifiers(tcx, &krate, resolver.lint_buffer());
284285
krate
285286
}
286287

‎compiler/rustc_lint/messages.ftl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,16 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re
415415
lint_improper_ctypes_union_layout_reason = this union has unspecified layout
416416
lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
417417
418+
lint_incompatible_target_modifiers =
419+
mixing `{$flag_name_suffixed}` will cause an ABI mismatch
420+
.note1 = `{$flag_name_suffixed}`=`{$flag_local_value}` in crate `{$local_crate}`, `{$flag_name_suffixed}`=`{$flag_extern_value}` in crate `{$extern_crate}`
421+
.help = This error occurs because the `{$flag_name_suffixed}` flag modifies the ABI,
422+
and different crates in your project were compiled with inconsistent settings
423+
.suggestion = To resolve this, ensure that `{$flag_name_suffixed}` is set to the same value
424+
for all crates during compilation
425+
.note2 = To ignore this error, recompile with the following flag:
426+
-Cunsafe-allow-abi-mismatch=`{$flag_name}`
427+
418428
lint_incomplete_include =
419429
include macro expected single expression in source
420430

‎compiler/rustc_lint/src/context/diagnostics.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,23 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
422422
lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
423423
}
424424
BuiltinLintDiag::WasmCAbi => lints::WasmCAbi.decorate_lint(diag),
425+
BuiltinLintDiag::IncompatibleTargetModifiers {
426+
extern_crate,
427+
local_crate,
428+
flag_name,
429+
flag_name_suffixed,
430+
flag_local_value,
431+
flag_extern_value
432+
} => {
433+
lints::IncompatibleTargetModifiers {
434+
extern_crate,
435+
local_crate,
436+
flag_name,
437+
flag_name_suffixed,
438+
flag_local_value,
439+
flag_extern_value
440+
}.decorate_lint(diag)
441+
}
425442
BuiltinLintDiag::IllFormedAttributeInput { suggestions } => {
426443
lints::IllFormedAttributeInput {
427444
num_suggestions: suggestions.len(),

‎compiler/rustc_lint/src/lints.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2470,6 +2470,20 @@ pub(crate) struct UnusedCrateDependency {
24702470
pub local_crate: Symbol,
24712471
}
24722472

2473+
#[derive(LintDiagnostic)]
2474+
#[diag(lint_incompatible_target_modifiers)]
2475+
#[help]
2476+
#[note(lint_note1)]
2477+
#[note(lint_note2)]
2478+
pub(crate) struct IncompatibleTargetModifiers {
2479+
pub extern_crate: Symbol,
2480+
pub local_crate: Symbol,
2481+
pub flag_name: String,
2482+
pub flag_name_suffixed: String,
2483+
pub flag_local_value: String,
2484+
pub flag_extern_value: String,
2485+
}
2486+
24732487
#[derive(LintDiagnostic)]
24742488
#[diag(lint_wasm_c_abi)]
24752489
pub(crate) struct WasmCAbi;

‎compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ declare_lint_pass! {
5050
HIDDEN_GLOB_REEXPORTS,
5151
ILL_FORMED_ATTRIBUTE_INPUT,
5252
INCOMPLETE_INCLUDE,
53+
INCOMPATIBLE_TARGET_MODIFIERS,
5354
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
5455
INLINE_NO_SANITIZE,
5556
INVALID_DOC_ATTRIBUTES,
@@ -578,6 +579,43 @@ declare_lint! {
578579
crate_level_only
579580
}
580581

582+
declare_lint! {
583+
/// The `incompatible_target_modifiers` lint detects crates with incompatible target modifiers
584+
/// (abi-changing or vulnerability-affecting flags).
585+
///
586+
/// ### Example
587+
///
588+
/// ```rust,ignore (needs extern crate)
589+
/// #![deny(incompatible_target_modifiers)]
590+
/// ```
591+
///
592+
/// When main and dependency crates are compiled with `-Zregparm=1` and `-Zregparm=2` correspondingly.
593+
///
594+
/// This will produce:
595+
///
596+
/// ```text
597+
/// error: crate `incompatible_regparm` has incompatible target modifier with extern crate `wrong_regparm`: `regparm = ( Some(1) | Some(2) )`
598+
/// --> $DIR/incompatible_regparm.rs:5:1
599+
/// |
600+
/// 1 | #![no_core]
601+
/// | ^
602+
/// |
603+
/// = note: `#[deny(incompatible_target_modifiers)]` on by default
604+
/// ```
605+
///
606+
/// ### Explanation
607+
///
608+
/// `Target modifiers` are compilation flags that affects abi or vulnerability resistance.
609+
/// Linking together crates with incompatible target modifiers would produce incorrect code
610+
/// or degradation of vulnerability resistance.
611+
/// So this lint should find such inconsistency.
612+
///
613+
pub INCOMPATIBLE_TARGET_MODIFIERS,
614+
Deny,
615+
"Incompatible target modifiers",
616+
crate_level_only
617+
}
618+
581619
declare_lint! {
582620
/// The `unused_qualifications` lint detects unnecessarily qualified
583621
/// names.

‎compiler/rustc_lint_defs/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,14 @@ pub enum BuiltinLintDiag {
719719
AvoidUsingIntelSyntax,
720720
AvoidUsingAttSyntax,
721721
IncompleteInclude,
722+
IncompatibleTargetModifiers {
723+
extern_crate: Symbol,
724+
local_crate: Symbol,
725+
flag_name: String,
726+
flag_name_suffixed: String,
727+
flag_local_value: String,
728+
flag_extern_value: String,
729+
},
722730
UnnameableTestItems,
723731
DuplicateMacroAttribute,
724732
CfgAttrNoAttributes,

‎compiler/rustc_metadata/src/creader.rs

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use rustc_middle::bug;
2424
use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
2525
use rustc_session::config::{self, CrateType, ExternLocation};
2626
use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
27-
use rustc_session::lint::{self, BuiltinLintDiag};
27+
use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
2828
use rustc_session::output::validate_crate_name;
2929
use rustc_session::search_paths::PathKind;
3030
use rustc_span::edition::Edition;
@@ -35,7 +35,9 @@ use tracing::{debug, info, trace};
3535

3636
use crate::errors;
3737
use crate::locator::{CrateError, CrateLocator, CratePaths};
38-
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
38+
use crate::rmeta::{
39+
CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers,
40+
};
3941

4042
/// The backend's way to give the crate store access to the metadata in a library.
4143
/// Note that it returns the raw metadata bytes stored in the library file, whether
@@ -290,6 +292,92 @@ impl CStore {
290292
}
291293
}
292294

295+
pub fn report_incompatible_target_modifiers(
296+
&self,
297+
tcx: TyCtxt<'_>,
298+
krate: &Crate,
299+
lints: &mut LintBuffer,
300+
) {
301+
if tcx.crate_types().contains(&CrateType::ProcMacro) {
302+
return;
303+
}
304+
let sess = tcx.sess;
305+
if let Some(vec) = &sess.opts.cg.unsafe_allow_abi_mismatch && vec.is_empty() {
306+
return;
307+
}
308+
let span = krate.spans.inner_span.shrink_to_lo();
309+
310+
let splitter = |v: &String| {
311+
let splitted: Vec<_> = v.split("=").collect();
312+
(splitted[0].to_string(), splitted[1].to_string())
313+
};
314+
let name = tcx.crate_name(LOCAL_CRATE);
315+
let mods = sess.opts.gather_target_modifiers();
316+
for (_cnum, data) in self.iter_crate_data() {
317+
if data.is_proc_macro_crate() {
318+
continue;
319+
}
320+
let mut report_diff =
321+
|flag_name: &String, flag_local_value: &String, flag_extern_value: &String| {
322+
if let Some(vec) = &sess.opts.cg.unsafe_allow_abi_mismatch {
323+
if vec.contains(flag_name) {
324+
return;
325+
}
326+
}
327+
lints.buffer_lint(
328+
lint::builtin::INCOMPATIBLE_TARGET_MODIFIERS,
329+
ast::CRATE_NODE_ID,
330+
span,
331+
BuiltinLintDiag::IncompatibleTargetModifiers {
332+
extern_crate: data.name(),
333+
local_crate: name,
334+
flag_name: flag_name.to_string(),
335+
flag_name_suffixed: flag_name.to_string(),
336+
flag_local_value: flag_local_value.to_string(),
337+
flag_extern_value: flag_extern_value.to_string(),
338+
},
339+
);
340+
};
341+
let mut it1 = mods.iter().map(splitter);
342+
let mut it2 = data.target_modifiers().map(splitter);
343+
let mut left_name_val: Option<(String, String)> = None;
344+
let mut right_name_val: Option<(String, String)> = None;
345+
let no_val = "*".to_string();
346+
loop {
347+
left_name_val = left_name_val.or_else(|| it1.next());
348+
right_name_val = right_name_val.or_else(|| it2.next());
349+
match (&left_name_val, &right_name_val) {
350+
(Some(l), Some(r)) => match l.0.cmp(&r.0) {
351+
cmp::Ordering::Equal => {
352+
if l.1 != r.1 {
353+
report_diff(&l.0, &l.1, &r.1);
354+
}
355+
left_name_val = None;
356+
right_name_val = None;
357+
}
358+
cmp::Ordering::Greater => {
359+
report_diff(&r.0, &no_val, &r.1);
360+
right_name_val = None;
361+
}
362+
cmp::Ordering::Less => {
363+
report_diff(&l.0, &l.1, &no_val);
364+
left_name_val = None;
365+
}
366+
},
367+
(Some(l), None) => {
368+
report_diff(&l.0, &l.1, &no_val);
369+
left_name_val = None;
370+
}
371+
(None, Some(r)) => {
372+
report_diff(&r.0, &no_val, &r.1);
373+
right_name_val = None;
374+
}
375+
(None, None) => break,
376+
}
377+
}
378+
}
379+
}
380+
293381
pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
294382
CStore {
295383
metadata_loader,
@@ -432,6 +520,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
432520
};
433521

434522
let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, dep_kind)?;
523+
let target_modifiers = self.resolve_target_modifiers(&crate_root, &metadata, cnum)?;
435524

436525
let raw_proc_macros = if crate_root.is_proc_macro_crate() {
437526
let temp_root;
@@ -456,6 +545,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
456545
raw_proc_macros,
457546
cnum,
458547
cnum_map,
548+
target_modifiers,
459549
dep_kind,
460550
source,
461551
private_dep,
@@ -689,6 +779,25 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
689779
Ok(crate_num_map)
690780
}
691781

782+
fn resolve_target_modifiers(
783+
&mut self,
784+
crate_root: &CrateRoot,
785+
metadata: &MetadataBlob,
786+
krate: CrateNum,
787+
) -> Result<TargetModifiers, CrateError> {
788+
debug!("resolving target modifiers of external crate");
789+
if crate_root.is_proc_macro_crate() {
790+
return Ok(TargetModifiers::new());
791+
}
792+
let mods = crate_root.decode_target_modifiers(metadata);
793+
let mut target_modifiers = TargetModifiers::with_capacity(mods.len());
794+
for modifier in mods {
795+
target_modifiers.push(modifier);
796+
}
797+
debug!("resolve_target_modifiers: target mods for {:?} is {:?}", krate, target_modifiers);
798+
Ok(target_modifiers)
799+
}
800+
692801
fn dlsym_proc_macros(
693802
&self,
694803
path: &Path,

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ impl MetadataBlob {
7373
/// own crate numbers.
7474
pub(crate) type CrateNumMap = IndexVec<CrateNum, CrateNum>;
7575

76+
/// Target modifiers - abi / vulnerability-resist affecting flags
77+
pub(crate) type TargetModifiers = Vec<String>;
78+
7679
pub(crate) struct CrateMetadata {
7780
/// The primary crate data - binary metadata blob.
7881
blob: MetadataBlob,
@@ -110,6 +113,8 @@ pub(crate) struct CrateMetadata {
110113
cnum_map: CrateNumMap,
111114
/// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime.
112115
dependencies: Vec<CrateNum>,
116+
/// Target modifiers - abi and vulnerability-resist affecting flags the crate was compiled with
117+
target_modifiers: TargetModifiers,
113118
/// How to link (or not link) this crate to the currently compiled crate.
114119
dep_kind: CrateDepKind,
115120
/// Filesystem location of this crate.
@@ -960,6 +965,13 @@ impl CrateRoot {
960965
) -> impl ExactSizeIterator<Item = CrateDep> + Captures<'a> {
961966
self.crate_deps.decode(metadata)
962967
}
968+
969+
pub(crate) fn decode_target_modifiers<'a>(
970+
&self,
971+
metadata: &'a MetadataBlob,
972+
) -> impl ExactSizeIterator<Item = String> + Captures<'a> {
973+
self.target_modifiers.decode(metadata)
974+
}
963975
}
964976

965977
impl<'a> CrateMetadataRef<'a> {
@@ -1815,6 +1827,7 @@ impl CrateMetadata {
18151827
raw_proc_macros: Option<&'static [ProcMacro]>,
18161828
cnum: CrateNum,
18171829
cnum_map: CrateNumMap,
1830+
target_modifiers: TargetModifiers,
18181831
dep_kind: CrateDepKind,
18191832
source: CrateSource,
18201833
private_dep: bool,
@@ -1846,6 +1859,7 @@ impl CrateMetadata {
18461859
cnum,
18471860
cnum_map,
18481861
dependencies,
1862+
target_modifiers,
18491863
dep_kind,
18501864
source: Lrc::new(source),
18511865
private_dep,
@@ -1875,6 +1889,10 @@ impl CrateMetadata {
18751889
self.dependencies.push(cnum);
18761890
}
18771891

1892+
pub(crate) fn target_modifiers(&self) -> impl Iterator<Item = &String> + '_ {
1893+
self.target_modifiers.iter()
1894+
}
1895+
18781896
pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool {
18791897
let update =
18801898
Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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();
@@ -732,6 +733,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
732733
native_libraries,
733734
foreign_modules,
734735
source_map,
736+
target_modifiers,
735737
traits,
736738
impls,
737739
incoherent_impls,
@@ -1978,6 +1980,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
19781980
self.lazy_array(deps.iter().map(|(_, dep)| dep))
19791981
}
19801982

1983+
fn encode_target_modifiers(&mut self) -> LazyArray<String> {
1984+
empty_proc_macro!(self);
1985+
let tcx = self.tcx;
1986+
self.lazy_array(tcx.sess.opts.gather_target_modifiers())
1987+
}
1988+
19811989
fn encode_lib_features(&mut self) -> LazyArray<(Symbol, FeatureStability)> {
19821990
empty_proc_macro!(self);
19831991
let tcx = self.tcx;

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

Lines changed: 2 additions & 1 deletion
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;
@@ -283,6 +283,7 @@ pub(crate) struct CrateRoot {
283283
def_path_hash_map: LazyValue<DefPathHashMapRef<'static>>,
284284

285285
source_map: LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>>,
286+
target_modifiers: LazyArray<String>,
286287

287288
compiler_builtins: bool,
288289
needs_allocator: bool,

‎compiler/rustc_session/src/options.rs

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,58 @@ macro_rules! hash_substruct {
5858
};
5959
}
6060

61+
macro_rules! gather_tmods {
62+
($_opt_name:ident, $init:expr, $opt_expr:expr, $mods:expr, [SUBSTRUCT], [TMOD]) => {
63+
compile_error!("SUBSTRUCT can't be TMOD (target modifier)");
64+
};
65+
($opt_name:ident, $init:expr, $opt_expr:expr, $mods:expr, [UNTRACKED], [TMOD]) => {
66+
if *$opt_expr != $init {
67+
$mods.push(format!("{}={:?}", stringify!($opt_name), $opt_expr));
68+
}
69+
};
70+
($opt_name:ident, $init:expr, $opt_expr:expr, $mods:expr, [TRACKED], [TMOD]) => {
71+
if *$opt_expr != $init {
72+
$mods.push(format!("{}={:?}", stringify!($opt_name), $opt_expr));
73+
}
74+
};
75+
($opt_name:ident, $init:expr, $opt_expr:expr, $mods:expr, [TRACKED_NO_CRATE_HASH], [TMOD]) => {
76+
if *$opt_expr != $init {
77+
$mods.push(format!("{}={:?}", stringify!($opt_name), $opt_expr));
78+
}
79+
};
80+
($_opt_name:ident, $init:expr, $opt_expr:expr, $mods:expr, [SUBSTRUCT], []) => {
81+
$opt_expr.gather_target_modifiers($mods);
82+
};
83+
($_opt_name:ident, $init:expr, $_opt_expr:expr, $_mods:expr, [UNTRACKED], []) => {{}};
84+
($_opt_name:ident, $init:expr, $_opt_expr:expr, $_mods:expr, [TRACKED], []) => {{}};
85+
($_opt_name:ident, $init:expr, $_opt_expr:expr, $_mods:expr, [TRACKED_NO_CRATE_HASH], []) => {{}};
86+
}
87+
88+
macro_rules! gather_tmods_top_level {
89+
($_opt_name:ident, $opt_expr:expr, $mods:expr, [SUBSTRUCT], [TMOD]) => {
90+
compile_error!("SUBSTRUCT can't be TMOD (target modifier)");
91+
};
92+
($opt_name:ident, $opt_expr:expr, $mods:expr, [UNTRACKED], [TMOD]) => {
93+
compile_error!("Top level option can't be TMOD (target modifier)");
94+
};
95+
($opt_name:ident, $opt_expr:expr, $mods:expr, [TRACKED], [TMOD]) => {
96+
compile_error!("Top level option can't be TMOD (target modifier)");
97+
};
98+
($opt_name:ident, $opt_expr:expr, $mods:expr, [TRACKED_NO_CRATE_HASH], [TMOD]) => {
99+
compile_error!("Top level option can't be TMOD (target modifier)");
100+
};
101+
($_opt_name:ident, $opt_expr:expr, $mods:expr, [SUBSTRUCT], []) => {
102+
$opt_expr.gather_target_modifiers($mods);
103+
};
104+
($_opt_name:ident, $_opt_expr:expr, $_mods:expr, [UNTRACKED], []) => {{}};
105+
($_opt_name:ident, $_opt_expr:expr, $_mods:expr, [TRACKED], []) => {{}};
106+
($_opt_name:ident, $_opt_expr:expr, $_mods:expr, [TRACKED_NO_CRATE_HASH], []) => {{}};
107+
}
108+
61109
macro_rules! top_level_options {
62110
( $( #[$top_level_attr:meta] )* pub struct Options { $(
63111
$( #[$attr:meta] )*
64-
$opt:ident : $t:ty [$dep_tracking_marker:ident],
112+
$opt:ident : $t:ty [$dep_tracking_marker:ident $( $tmod:ident )*],
65113
)* } ) => (
66114
#[derive(Clone)]
67115
$( #[$top_level_attr] )*
@@ -97,6 +145,16 @@ macro_rules! top_level_options {
97145
})*
98146
hasher.finish()
99147
}
148+
149+
pub fn gather_target_modifiers(&self) -> Vec<String> {
150+
let mut mods = Vec::<String>::new();
151+
$({
152+
gather_tmods_top_level!($opt,
153+
&self.$opt, &mut mods, [$dep_tracking_marker], [$($tmod),*]);
154+
})*
155+
mods.sort_unstable();
156+
mods
157+
}
100158
}
101159
);
102160
}
@@ -238,7 +296,7 @@ macro_rules! options {
238296
$($( #[$attr:meta] )* $opt:ident : $t:ty = (
239297
$init:expr,
240298
$parse:ident,
241-
[$dep_tracking_marker:ident],
299+
[$dep_tracking_marker:ident $( $tmod:ident )*],
242300
$desc:expr)
243301
),* ,) =>
244302
(
@@ -277,6 +335,13 @@ macro_rules! options {
277335
);
278336
hasher.finish()
279337
}
338+
339+
pub fn gather_target_modifiers(&self, _mods: &mut Vec<String>) {
340+
$({
341+
gather_tmods!($opt, $init,
342+
&self.$opt, _mods, [$dep_tracking_marker], [$($tmod),*]);
343+
})*
344+
}
280345
}
281346

282347
pub const $stat: OptionDescrs<$struct_name> =
@@ -372,6 +437,7 @@ mod desc {
372437
"a comma-separated list of strings, with elements beginning with + or -";
373438
pub(crate) const parse_comma_list: &str = "a comma-separated list of strings";
374439
pub(crate) const parse_opt_comma_list: &str = parse_comma_list;
440+
pub(crate) const parse_opt_comma_list_or_empty: &str = parse_comma_list;
375441
pub(crate) const parse_number: &str = "a number";
376442
pub(crate) const parse_opt_number: &str = parse_number;
377443
pub(crate) const parse_frame_pointer: &str = "one of `true`/`yes`/`on`, `false`/`no`/`off`, or (with -Zunstable-options) `non-leaf` or `always`";
@@ -656,6 +722,19 @@ mod parse {
656722
}
657723
}
658724

725+
// Allows both "-C(Z)flag=value1,value2,...,valueN" and "-C(Z)flag" (setting empty vector)
726+
pub(crate) fn parse_opt_comma_list_or_empty(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
727+
match v {
728+
Some(s) => {
729+
let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect();
730+
v.sort_unstable();
731+
*slot = Some(v);
732+
true
733+
}
734+
None => { *slot = Some(Vec::<String>::new()); true },
735+
}
736+
}
737+
659738
pub(crate) fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
660739
match v.and_then(|s| s.parse().ok()) {
661740
Some(0) => {
@@ -1656,6 +1735,9 @@ options! {
16561735
target_feature: String = (String::new(), parse_target_feature, [TRACKED],
16571736
"target specific attributes. (`rustc --print target-features` for details). \
16581737
This feature is unsafe."),
1738+
unsafe_allow_abi_mismatch: Option<Vec<String>> = (None, parse_opt_comma_list_or_empty, [UNTRACKED],
1739+
"Allow incompatible target modifiers in dependency crates \
1740+
(comma separated list or empty to allow all)"),
16591741
// tidy-alphabetical-end
16601742

16611743
// If you add a new option, please update:
@@ -2000,7 +2082,7 @@ options! {
20002082
"enable queries of the dependency graph for regression testing (default: no)"),
20012083
randomize_layout: bool = (false, parse_bool, [TRACKED],
20022084
"randomize the layout of types (default: no)"),
2003-
regparm: Option<u32> = (None, parse_opt_number, [TRACKED],
2085+
regparm: Option<u32> = (None, parse_opt_number, [TRACKED TMOD],
20042086
"On x86-32 targets, setting this to N causes the compiler to pass N arguments \
20052087
in registers EAX, EDX, and ECX instead of on the stack for\
20062088
\"C\", \"cdecl\", and \"stdcall\" fn.\
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=2 -Cpanic=abort
2+
//@ needs-llvm-components: x86
3+
#![crate_type = "lib"]
4+
#![no_core]
5+
#![feature(no_core, lang_items, repr_simd)]
6+
7+
#[lang = "sized"]
8+
trait Sized {}
9+
#[lang = "copy"]
10+
trait Copy {}
11+
12+
pub fn somefun() {}
13+
14+
pub struct S;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: mixing `regparm` will cause an ABI mismatch
2+
--> $DIR/incompatible_regparm.rs:12:1
3+
|
4+
LL | #![crate_type = "lib"]
5+
| ^
6+
|
7+
= help: This error occurs because the `regparm` flag modifies the ABI,
8+
and different crates in your project were compiled with inconsistent settings
9+
= note: `regparm`=`Some(1)` in crate `incompatible_regparm`, `regparm`=`Some(2)` in crate `wrong_regparm`
10+
= note: To ignore this error, recompile with the following flag:
11+
-Cunsafe-allow-abi-mismatch=`regparm`
12+
= note: `#[deny(incompatible_target_modifiers)]` on by default
13+
14+
error: aborting due to 1 previous error
15+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ aux-crate:wrong_regparm=wrong_regparm.rs
2+
//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=1 -Cpanic=abort
3+
//@ needs-llvm-components: x86
4+
//@ revisions:error_generated allow_regparm_mismatch allow_any_mismatch allow_attr
5+
6+
//@[allow_regparm_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=regparm
7+
//@[allow_any_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch
8+
//@[allow_regparm_mismatch] build-pass
9+
//@[allow_any_mismatch] build-pass
10+
//@[allow_attr] build-pass
11+
12+
#![crate_type = "lib"]
13+
//[error_generated]~^ ERROR 12:1: 12:1: mixing `regparm` will cause an ABI mismatch [incompatible_target_modifiers]
14+
#![no_core]
15+
#![feature(no_core, lang_items, repr_simd)]
16+
17+
#![cfg_attr(allow_attr, allow(incompatible_target_modifiers))]
18+
19+
fn foo() {
20+
wrong_regparm::somefun();
21+
}

0 commit comments

Comments
 (0)
Please sign in to comment.