Auto merge of #148472 - Zalathar:rollup-zwlz09o, r=Zalathar
Rollup of 4 pull requests Successful merges: - rust-lang/rust#144529 (Add `#[rustc_pass_indirectly_in_non_rustic_abis]`) - rust-lang/rust#147017 (FCW for repr(C) enums whose discriminant values do not fit into a c_int or c_uint) - rust-lang/rust#148459 (bootstrap: Split out a separate `./x test bootstrap-py` step) - rust-lang/rust#148468 (add logging to `fudge_inference_if_ok`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e5efc33672
61 changed files with 1026 additions and 96 deletions
|
|
@ -812,7 +812,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
let (max, min) = largest_niche
|
||||
// We might have no inhabited variants, so pretend there's at least one.
|
||||
.unwrap_or((0, 0));
|
||||
let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max);
|
||||
let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::discr_range_of_repr(tcx, ty, &repr, min, max);
|
||||
|
||||
let mut align = dl.aggregate_align;
|
||||
let mut max_repr_align = repr.align;
|
||||
|
|
|
|||
|
|
@ -172,6 +172,8 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
|
|||
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
|
||||
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
|
||||
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
|
||||
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
|
||||
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
|
||||
}
|
||||
|
||||
impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||
|
|
@ -269,6 +271,30 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|||
Ty::is_transparent(self)
|
||||
}
|
||||
|
||||
/// If this method returns `true`, then this type should always have a `PassMode` of
|
||||
/// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a
|
||||
/// non-Rustic ABI (this is true for structs annotated with the
|
||||
/// `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute).
|
||||
///
|
||||
/// This is used to replicate some of the behaviour of C array-to-pointer decay; however unlike
|
||||
/// C any changes the caller makes to the passed value will not be reflected in the callee, so
|
||||
/// the attribute is only useful for types where observing the value in the caller after the
|
||||
/// function call isn't allowed (a.k.a. `va_list`).
|
||||
///
|
||||
/// This function handles transparent types automatically.
|
||||
pub fn pass_indirectly_in_non_rustic_abis<C>(mut self, cx: &C) -> bool
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
while self.is_transparent()
|
||||
&& let Some((_, field)) = self.non_1zst_field(cx)
|
||||
{
|
||||
self = field;
|
||||
}
|
||||
|
||||
Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(self)
|
||||
}
|
||||
|
||||
/// Finds the one field that is not a 1-ZST.
|
||||
/// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
|
||||
pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(FieldIdx, Self)>
|
||||
|
|
|
|||
|
|
@ -88,14 +88,17 @@ bitflags! {
|
|||
const IS_C = 1 << 0;
|
||||
const IS_SIMD = 1 << 1;
|
||||
const IS_TRANSPARENT = 1 << 2;
|
||||
// Internal only for now. If true, don't reorder fields.
|
||||
// On its own it does not prevent ABI optimizations.
|
||||
/// Internal only for now. If true, don't reorder fields.
|
||||
/// On its own it does not prevent ABI optimizations.
|
||||
const IS_LINEAR = 1 << 3;
|
||||
// If true, the type's crate has opted into layout randomization.
|
||||
// Other flags can still inhibit reordering and thus randomization.
|
||||
// The seed stored in `ReprOptions.field_shuffle_seed`.
|
||||
/// If true, the type's crate has opted into layout randomization.
|
||||
/// Other flags can still inhibit reordering and thus randomization.
|
||||
/// The seed stored in `ReprOptions.field_shuffle_seed`.
|
||||
const RANDOMIZE_LAYOUT = 1 << 4;
|
||||
// Any of these flags being set prevent field reordering optimisation.
|
||||
/// If true, the type is always passed indirectly by non-Rustic ABIs.
|
||||
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
|
||||
const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5;
|
||||
/// Any of these flags being set prevent field reordering optimisation.
|
||||
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
|
||||
| ReprFlags::IS_SIMD.bits()
|
||||
| ReprFlags::IS_LINEAR.bits();
|
||||
|
|
@ -183,6 +186,11 @@ impl ReprOptions {
|
|||
|
||||
/// Returns the discriminant type, given these `repr` options.
|
||||
/// This must only be called on enums!
|
||||
///
|
||||
/// This is the "typeck type" of the discriminant, which is effectively the maximum size:
|
||||
/// discriminant values will be wrapped to fit (with a lint). Layout can later decide to use a
|
||||
/// smaller type for the tag that stores the discriminant at runtime and that will work just
|
||||
/// fine, it just induces casts when getting/setting the discriminant.
|
||||
pub fn discr_type(&self) -> IntegerType {
|
||||
self.int.unwrap_or(IntegerType::Pointer(true))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -676,3 +676,12 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
|
|||
Some(AttributeKind::Sanitize { on_set, off_set, span: cx.attr_span })
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@ use crate::attributes::allow_unstable::{
|
|||
use crate::attributes::body::CoroutineParser;
|
||||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser,
|
||||
NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, SanitizeParser,
|
||||
TargetFeatureParser, TrackCallerParser, UsedParser,
|
||||
NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
|
||||
RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser,
|
||||
TrackCallerParser, UsedParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::crate_level::{
|
||||
|
|
@ -243,6 +244,7 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<PubTransparentParser>>,
|
||||
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
|
||||
Single<WithoutArgs<RustcMainParser>>,
|
||||
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
|
||||
Single<WithoutArgs<SpecializationTraitParser>>,
|
||||
Single<WithoutArgs<StdInternalSymbolParser>>,
|
||||
Single<WithoutArgs<TrackCallerParser>>,
|
||||
|
|
|
|||
|
|
@ -657,6 +657,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-naked-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
// See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details.
|
||||
rustc_attr!(
|
||||
rustc_pass_indirectly_in_non_rustic_abis, Normal, template!(Word), ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic abis."
|
||||
),
|
||||
|
||||
// Limits:
|
||||
ungated!(
|
||||
|
|
|
|||
|
|
@ -679,6 +679,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_object_lifetime_default]`.
|
||||
RustcObjectLifetimeDefault,
|
||||
|
||||
/// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]`
|
||||
RustcPassIndirectlyInNonRusticAbis(Span),
|
||||
|
||||
/// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`.
|
||||
RustcSimdMonomorphizeLaneLimit(Limit),
|
||||
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ impl AttributeKind {
|
|||
RustcLayoutScalarValidRangeStart(..) => Yes,
|
||||
RustcMain => No,
|
||||
RustcObjectLifetimeDefault => No,
|
||||
RustcPassIndirectlyInNonRusticAbis(..) => No,
|
||||
RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
|
||||
Sanitize { .. } => No,
|
||||
ShouldPanic { .. } => No,
|
||||
|
|
|
|||
|
|
@ -782,7 +782,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
|
|||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
crate::collect::lower_enum_variant_types(tcx, def_id.to_def_id());
|
||||
crate::collect::lower_enum_variant_types(tcx, def_id);
|
||||
check_enum(tcx, def_id);
|
||||
check_variances_for_type_defn(tcx, def_id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use std::cell::Cell;
|
|||
use std::iter;
|
||||
use std::ops::Bound;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_abi::{ExternAbi, Size};
|
||||
use rustc_ast::Recovered;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
|
|
@ -605,32 +605,70 @@ pub(super) fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
tcx.ensure_ok().predicates_of(def_id);
|
||||
}
|
||||
|
||||
pub(super) fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
|
||||
pub(super) fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let def = tcx.adt_def(def_id);
|
||||
let repr_type = def.repr().discr_type();
|
||||
let initial = repr_type.initial_discriminant(tcx);
|
||||
let mut prev_discr = None::<Discr<'_>>;
|
||||
// Some of the logic below relies on `i128` being able to hold all c_int and c_uint values.
|
||||
assert!(tcx.sess.target.c_int_width < 128);
|
||||
let mut min_discr = i128::MAX;
|
||||
let mut max_discr = i128::MIN;
|
||||
|
||||
// fill the discriminant values and field types
|
||||
for variant in def.variants() {
|
||||
let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
|
||||
prev_discr = Some(
|
||||
if let ty::VariantDiscr::Explicit(const_def_id) = variant.discr {
|
||||
def.eval_explicit_discr(tcx, const_def_id).ok()
|
||||
} else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
|
||||
Some(discr)
|
||||
} else {
|
||||
let cur_discr = if let ty::VariantDiscr::Explicit(const_def_id) = variant.discr {
|
||||
def.eval_explicit_discr(tcx, const_def_id).ok()
|
||||
} else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
|
||||
Some(discr)
|
||||
} else {
|
||||
let span = tcx.def_span(variant.def_id);
|
||||
tcx.dcx().emit_err(errors::EnumDiscriminantOverflowed {
|
||||
span,
|
||||
discr: prev_discr.unwrap().to_string(),
|
||||
item_name: tcx.item_ident(variant.def_id),
|
||||
wrapped_discr: wrapped_discr.to_string(),
|
||||
});
|
||||
None
|
||||
}
|
||||
.unwrap_or(wrapped_discr);
|
||||
|
||||
if def.repr().c() {
|
||||
let c_int = Size::from_bits(tcx.sess.target.c_int_width);
|
||||
let c_uint_max = i128::try_from(c_int.unsigned_int_max()).unwrap();
|
||||
// c_int is a signed type, so get a proper signed version of the discriminant
|
||||
let discr_size = cur_discr.ty.int_size_and_signed(tcx).0;
|
||||
let discr_val = discr_size.sign_extend(cur_discr.val);
|
||||
min_discr = min_discr.min(discr_val);
|
||||
max_discr = max_discr.max(discr_val);
|
||||
|
||||
// The discriminant range must either fit into c_int or c_uint.
|
||||
if !(min_discr >= c_int.signed_int_min() && max_discr <= c_int.signed_int_max())
|
||||
&& !(min_discr >= 0 && max_discr <= c_uint_max)
|
||||
{
|
||||
let span = tcx.def_span(variant.def_id);
|
||||
tcx.dcx().emit_err(errors::EnumDiscriminantOverflowed {
|
||||
let msg = if discr_val < c_int.signed_int_min() || discr_val > c_uint_max {
|
||||
"`repr(C)` enum discriminant does not fit into C `int` nor into C `unsigned int`"
|
||||
} else if discr_val < 0 {
|
||||
"`repr(C)` enum discriminant does not fit into C `unsigned int`, and a previous discriminant does not fit into C `int`"
|
||||
} else {
|
||||
"`repr(C)` enum discriminant does not fit into C `int`, and a previous discriminant does not fit into C `unsigned int`"
|
||||
};
|
||||
tcx.node_span_lint(
|
||||
rustc_session::lint::builtin::REPR_C_ENUMS_LARGER_THAN_INT,
|
||||
tcx.local_def_id_to_hir_id(def_id),
|
||||
span,
|
||||
discr: prev_discr.unwrap().to_string(),
|
||||
item_name: tcx.item_ident(variant.def_id),
|
||||
wrapped_discr: wrapped_discr.to_string(),
|
||||
});
|
||||
None
|
||||
|d| {
|
||||
d.primary_message(msg)
|
||||
.note("`repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C")
|
||||
.help("use `repr($int_ty)` instead to explicitly set the size of this enum");
|
||||
}
|
||||
);
|
||||
}
|
||||
.unwrap_or(wrapped_discr),
|
||||
);
|
||||
}
|
||||
|
||||
prev_discr = Some(cur_discr);
|
||||
|
||||
for f in &variant.fields {
|
||||
tcx.ensure_ok().generics_of(f.did);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::fmt::Debug;
|
||||
use std::ops::Range;
|
||||
|
||||
use rustc_data_structures::{snapshot_vec as sv, unify as ut};
|
||||
|
|
@ -84,11 +85,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
/// the actual types (`?T`, `Option<?T>`) -- and remember that
|
||||
/// after the snapshot is popped, the variable `?T` is no longer
|
||||
/// unified.
|
||||
#[instrument(skip(self, f), level = "debug")]
|
||||
#[instrument(skip(self, f), level = "debug", ret)]
|
||||
pub fn fudge_inference_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
|
||||
where
|
||||
F: FnOnce() -> Result<T, E>,
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
E: Debug,
|
||||
{
|
||||
let variable_lengths = self.variable_lengths();
|
||||
let (snapshot_vars, value) = self.probe(|_| {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_span::{Span, Symbol, sym};
|
|||
use tracing::debug;
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
mod improper_ctypes; // these filed do the implementation for ImproperCTypesDefinitions,ImproperCTypesDeclarations
|
||||
mod improper_ctypes; // these files do the implementation for ImproperCTypesDefinitions,ImproperCTypesDeclarations
|
||||
pub(crate) use improper_ctypes::ImproperCTypesLint;
|
||||
|
||||
use crate::lints::{
|
||||
|
|
@ -25,7 +25,6 @@ use crate::lints::{
|
|||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
|
||||
mod literal;
|
||||
|
||||
use literal::{int_ty_range, lint_literal, uint_ty_range};
|
||||
|
||||
declare_lint! {
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ declare_lint_pass! {
|
|||
REFINING_IMPL_TRAIT_INTERNAL,
|
||||
REFINING_IMPL_TRAIT_REACHABLE,
|
||||
RENAMED_AND_REMOVED_LINTS,
|
||||
REPR_C_ENUMS_LARGER_THAN_INT,
|
||||
REPR_TRANSPARENT_NON_ZST_FIELDS,
|
||||
RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
|
||||
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
|
||||
|
|
@ -5213,3 +5214,52 @@ declare_lint! {
|
|||
Warn,
|
||||
r#"detects when a function annotated with `#[inline(always)]` and `#[target_feature(enable = "..")]` is inlined into a caller without the required target feature"#,
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `repr_c_enums_larger_than_int` lint detects `repr(C)` enums with discriminant
|
||||
/// values that do not fit into a C `int` or `unsigned int`.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,ignore (only errors on 64bit)
|
||||
/// #[repr(C)]
|
||||
/// enum E {
|
||||
/// V = 9223372036854775807, // i64::MAX
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This will produce:
|
||||
///
|
||||
/// ```text
|
||||
/// error: `repr(C)` enum discriminant does not fit into C `int` nor into C `unsigned int`
|
||||
/// --> $DIR/repr-c-big-discriminant1.rs:16:5
|
||||
/// |
|
||||
/// LL | A = 9223372036854775807, // i64::MAX
|
||||
/// | ^
|
||||
/// |
|
||||
/// = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C
|
||||
/// = help: use `repr($int_ty)` instead to explicitly set the size of this enum
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// In C, enums with discriminants that do not all fit into an `int` or all fit into an
|
||||
/// `unsigned int` are a portability hazard: such enums are only permitted since C23, and not
|
||||
/// supported e.g. by MSVC.
|
||||
///
|
||||
/// Furthermore, Rust interprets the discriminant values of `repr(C)` enums as expressions of
|
||||
/// type `isize`. This makes it impossible to implement the C23 behavior of enums where the enum
|
||||
/// discriminants have no predefined type and instead the enum uses a type large enough to hold
|
||||
/// all discriminants.
|
||||
///
|
||||
/// Therefore, `repr(C)` enums in Rust require that either all discriminants to fit into a C
|
||||
/// `int` or they all fit into an `unsigned int`.
|
||||
pub REPR_C_ENUMS_LARGER_THAN_INT,
|
||||
Warn,
|
||||
"repr(C) enums with discriminant values that do not fit into a C int",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseError,
|
||||
reference: "issue #124403 <https://github.com/rust-lang/rust/issues/124403>",
|
||||
report_in_deps: false,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{cmp, fmt};
|
|||
|
||||
use rustc_abi::{
|
||||
AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo,
|
||||
PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
|
||||
PointerKind, Primitive, ReprFlags, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
|
||||
TyAbiInterface, VariantIdx, Variants,
|
||||
};
|
||||
use rustc_error_messages::DiagMessage;
|
||||
|
|
@ -72,7 +72,10 @@ impl abi::Integer {
|
|||
/// signed discriminant range and `#[repr]` attribute.
|
||||
/// N.B.: `u128` values above `i128::MAX` will be treated as signed, but
|
||||
/// that shouldn't affect anything, other than maybe debuginfo.
|
||||
fn repr_discr<'tcx>(
|
||||
///
|
||||
/// This is the basis for computing the type of the *tag* of an enum (which can be smaller than
|
||||
/// the type of the *discriminant*, which is determined by [`ReprOptions::discr_type`]).
|
||||
fn discr_range_of_repr<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
repr: &ReprOptions,
|
||||
|
|
@ -108,7 +111,8 @@ impl abi::Integer {
|
|||
abi::Integer::I8
|
||||
};
|
||||
|
||||
// Pick the smallest fit.
|
||||
// Pick the smallest fit. Prefer unsigned; that matches clang in cases where this makes a
|
||||
// difference (https://godbolt.org/z/h4xEasW1d) so it is crucial for repr(C).
|
||||
if unsigned_fit <= signed_fit {
|
||||
(cmp::max(unsigned_fit, at_least), false)
|
||||
} else {
|
||||
|
|
@ -1173,6 +1177,11 @@ where
|
|||
fn is_transparent(this: TyAndLayout<'tcx>) -> bool {
|
||||
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
|
||||
}
|
||||
|
||||
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
|
||||
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'tcx>) -> bool {
|
||||
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS))
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates whether a function's ABI can unwind or not.
|
||||
|
|
|
|||
|
|
@ -1573,6 +1573,14 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
flags.insert(ReprFlags::IS_LINEAR);
|
||||
}
|
||||
|
||||
// See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details.
|
||||
if find_attr!(
|
||||
self.get_all_attrs(did),
|
||||
AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
|
||||
) {
|
||||
flags.insert(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS);
|
||||
}
|
||||
|
||||
ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -284,6 +284,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::RustcCoherenceIsCore(..)
|
||||
| AttributeKind::DebuggerVisualizer(..)
|
||||
| AttributeKind::RustcMain
|
||||
| AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
|
||||
| AttributeKind::PinV2(..),
|
||||
) => { /* do nothing */ }
|
||||
Attribute::Unparsed(attr_item) => {
|
||||
|
|
@ -1770,6 +1771,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
target: target.to_string(),
|
||||
});
|
||||
}
|
||||
// Error on `#[repr(transparent)]` in combination with
|
||||
// `#[rustc_pass_indirectly_in_non_rustic_abis]`
|
||||
if is_transparent
|
||||
&& let Some(&pass_indirectly_span) =
|
||||
find_attr!(attrs, AttributeKind::RustcPassIndirectlyInNonRusticAbis(span) => span)
|
||||
{
|
||||
self.dcx().emit_err(errors::TransparentIncompatible {
|
||||
hint_spans: vec![span, pass_indirectly_span],
|
||||
target: target.to_string(),
|
||||
});
|
||||
}
|
||||
if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) {
|
||||
let hint_spans = hint_spans.clone().collect();
|
||||
self.dcx().emit_err(errors::ReprConflicting { hint_spans });
|
||||
|
|
|
|||
|
|
@ -1944,6 +1944,7 @@ symbols! {
|
|||
rustc_partition_codegened,
|
||||
rustc_partition_reused,
|
||||
rustc_pass_by_value,
|
||||
rustc_pass_indirectly_in_non_rustic_abis,
|
||||
rustc_peek,
|
||||
rustc_peek_liveness,
|
||||
rustc_peek_maybe_init,
|
||||
|
|
|
|||
|
|
@ -114,6 +114,10 @@ where
|
|||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
if !arg.layout.is_aggregate() {
|
||||
if kind == AbiKind::DarwinPCS {
|
||||
// On Darwin, when passing an i8/i16, it must be sign-extended to 32 bits,
|
||||
|
|
|
|||
|
|
@ -10,11 +10,15 @@ where
|
|||
ret.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
fn classify_arg<'a, Ty, C>(_cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout,
|
||||
{
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,10 @@ where
|
|||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
if !arg.layout.is_aggregate() {
|
||||
arg.extend_integer_width_to(32);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
//! compatible with AVR-GCC - Rust and AVR-GCC only differ in the small amount
|
||||
//! of compiler frontend specific calling convention logic implemented here.
|
||||
|
||||
use rustc_abi::TyAbiInterface;
|
||||
|
||||
use crate::callconv::{ArgAbi, FnAbi};
|
||||
|
||||
fn classify_ret_ty<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
|
|
@ -38,13 +40,23 @@ fn classify_ret_ty<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn classify_arg_ty<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
fn classify_arg_ty<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
if arg.layout.is_aggregate() {
|
||||
arg.make_indirect();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<Ty>(fty: &mut FnAbi<'_, Ty>) {
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if !fty.ret.is_ignore() {
|
||||
classify_ret_ty(&mut fty.ret);
|
||||
}
|
||||
|
|
@ -54,6 +66,6 @@ pub(crate) fn compute_abi_info<Ty>(fty: &mut FnAbi<'_, Ty>) {
|
|||
continue;
|
||||
}
|
||||
|
||||
classify_arg_ty(arg);
|
||||
classify_arg_ty(cx, arg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
// see https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/BPF/BPFCallingConv.td
|
||||
use rustc_abi::TyAbiInterface;
|
||||
|
||||
use crate::callconv::{ArgAbi, FnAbi};
|
||||
|
||||
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
|
|
@ -9,7 +11,14 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
if arg.layout.is_aggregate() || arg.layout.size.bits() > 64 {
|
||||
arg.make_indirect();
|
||||
} else {
|
||||
|
|
@ -17,7 +26,10 @@ fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
|
@ -26,7 +38,7 @@ pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
|||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(arg);
|
||||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
// Reference: Clang CSKY lowering code
|
||||
// https://github.com/llvm/llvm-project/blob/4a074f32a6914f2a8d7215d78758c24942dddc3d/clang/lib/CodeGen/Targets/CSKY.cpp#L76-L162
|
||||
|
||||
use rustc_abi::TyAbiInterface;
|
||||
|
||||
use crate::callconv::{ArgAbi, FnAbi, Reg, Uniform};
|
||||
|
||||
fn classify_ret<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
|
|
@ -27,11 +29,18 @@ fn classify_ret<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if !arg.layout.is_sized() {
|
||||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
// For argument type, the first 4*XLen parts of aggregate will be passed
|
||||
// in registers, and the rest will be passed in stack.
|
||||
// So we can coerce to integers directly and let backend handle it correctly.
|
||||
|
|
@ -47,7 +56,10 @@ fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
|
@ -56,6 +68,6 @@ pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
|||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(arg);
|
||||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use rustc_abi::TyAbiInterface;
|
||||
|
||||
use crate::callconv::{ArgAbi, FnAbi};
|
||||
|
||||
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
|
|
@ -8,7 +10,14 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 {
|
||||
arg.make_indirect();
|
||||
} else {
|
||||
|
|
@ -16,7 +25,10 @@ fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
|
@ -25,6 +37,6 @@ pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
|||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(arg);
|
||||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -287,6 +287,11 @@ fn classify_arg<'a, Ty, C>(
|
|||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
*avail_gprs = (*avail_gprs).saturating_sub(1);
|
||||
return;
|
||||
}
|
||||
if !is_vararg {
|
||||
match should_use_fp_conv(cx, &arg.layout, xlen, flen) {
|
||||
Some(FloatConv::Float(f)) if *avail_fprs >= 1 => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use rustc_abi::TyAbiInterface;
|
||||
|
||||
use crate::callconv::{ArgAbi, FnAbi};
|
||||
|
||||
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
|
|
@ -8,11 +10,18 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if !arg.layout.is_sized() {
|
||||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
if arg.layout.is_aggregate() {
|
||||
arg.pass_by_stack_offset(None);
|
||||
} else {
|
||||
|
|
@ -20,7 +29,10 @@ fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
|
@ -29,6 +41,6 @@ pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
|||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(arg);
|
||||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_abi::{HasDataLayout, Size};
|
||||
use rustc_abi::{HasDataLayout, Size, TyAbiInterface};
|
||||
|
||||
use crate::callconv::{ArgAbi, FnAbi, Reg, Uniform};
|
||||
|
||||
|
|
@ -14,18 +14,26 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty, C>(cx: &C, arg: &mut ArgAbi<'_, Ty>, offset: &mut Size)
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, offset: &mut Size)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout,
|
||||
{
|
||||
if !arg.layout.is_sized() {
|
||||
// FIXME: Update offset?
|
||||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
let dl = cx.data_layout();
|
||||
let size = arg.layout.size;
|
||||
let align = arg.layout.align.abi.max(dl.i32_align).min(dl.i64_align);
|
||||
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
*offset = offset.align_to(align) + dl.pointer_size().align_to(align);
|
||||
return;
|
||||
}
|
||||
|
||||
let size = arg.layout.size;
|
||||
if arg.layout.is_aggregate() {
|
||||
let pad_i32 = !offset.is_aligned(align);
|
||||
arg.cast_to_and_pad_i32(Uniform::new(Reg::i32(), size), pad_i32);
|
||||
|
|
@ -36,8 +44,9 @@ where
|
|||
*offset = offset.align_to(align) + size.align_to(align);
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<Ty, C>(cx: &C, fn_abi: &mut FnAbi<'_, Ty>)
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout,
|
||||
{
|
||||
let mut offset = Size::ZERO;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,10 @@ where
|
|||
extend_integer_width_mips(arg, 64);
|
||||
return;
|
||||
}
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
|
||||
let dl = cx.data_layout();
|
||||
let size = arg.layout.size;
|
||||
|
|
|
|||
|
|
@ -677,30 +677,30 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
|||
}
|
||||
"amdgpu" => amdgpu::compute_abi_info(cx, self),
|
||||
"arm" => arm::compute_abi_info(cx, self),
|
||||
"avr" => avr::compute_abi_info(self),
|
||||
"avr" => avr::compute_abi_info(cx, self),
|
||||
"loongarch32" | "loongarch64" => loongarch::compute_abi_info(cx, self),
|
||||
"m68k" => m68k::compute_abi_info(self),
|
||||
"csky" => csky::compute_abi_info(self),
|
||||
"m68k" => m68k::compute_abi_info(cx, self),
|
||||
"csky" => csky::compute_abi_info(cx, self),
|
||||
"mips" | "mips32r6" => mips::compute_abi_info(cx, self),
|
||||
"mips64" | "mips64r6" => mips64::compute_abi_info(cx, self),
|
||||
"powerpc" => powerpc::compute_abi_info(cx, self),
|
||||
"powerpc64" => powerpc64::compute_abi_info(cx, self),
|
||||
"s390x" => s390x::compute_abi_info(cx, self),
|
||||
"msp430" => msp430::compute_abi_info(self),
|
||||
"msp430" => msp430::compute_abi_info(cx, self),
|
||||
"sparc" => sparc::compute_abi_info(cx, self),
|
||||
"sparc64" => sparc64::compute_abi_info(cx, self),
|
||||
"nvptx64" => {
|
||||
if abi == ExternAbi::PtxKernel || abi == ExternAbi::GpuKernel {
|
||||
nvptx64::compute_ptx_kernel_abi_info(cx, self)
|
||||
} else {
|
||||
nvptx64::compute_abi_info(self)
|
||||
nvptx64::compute_abi_info(cx, self)
|
||||
}
|
||||
}
|
||||
"hexagon" => hexagon::compute_abi_info(self),
|
||||
"hexagon" => hexagon::compute_abi_info(cx, self),
|
||||
"xtensa" => xtensa::compute_abi_info(cx, self),
|
||||
"riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
|
||||
"wasm32" | "wasm64" => wasm::compute_abi_info(cx, self),
|
||||
"bpf" => bpf::compute_abi_info(self),
|
||||
"bpf" => bpf::compute_abi_info(cx, self),
|
||||
arch => panic!("no lowering implemented for {arch}"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Reference: MSP430 Embedded Application Binary Interface
|
||||
// https://www.ti.com/lit/an/slaa534a/slaa534a.pdf
|
||||
|
||||
use rustc_abi::TyAbiInterface;
|
||||
|
||||
use crate::callconv::{ArgAbi, FnAbi};
|
||||
|
||||
// 3.5 Structures or Unions Passed and Returned by Reference
|
||||
|
|
@ -17,7 +19,14 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 {
|
||||
arg.make_indirect();
|
||||
} else {
|
||||
|
|
@ -25,7 +34,10 @@ fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
|
@ -34,6 +46,6 @@ pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
|||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(arg);
|
||||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,14 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
if arg.layout.is_aggregate() && arg.layout.is_sized() {
|
||||
classify_aggregate(arg)
|
||||
} else if arg.layout.size.bits() < 32 && arg.layout.is_sized() {
|
||||
|
|
@ -81,7 +88,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
|
@ -90,7 +100,7 @@ pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
|||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(arg);
|
||||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use rustc_abi::TyAbiInterface;
|
||||
|
||||
use crate::callconv::{ArgAbi, FnAbi};
|
||||
use crate::spec::HasTargetSpec;
|
||||
|
||||
|
|
@ -9,7 +11,10 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'_, Ty>) {
|
||||
fn classify_arg<'a, Ty, C: HasTargetSpec>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if arg.is_ignore() {
|
||||
// powerpc-unknown-linux-{gnu,musl,uclibc} doesn't ignore ZSTs.
|
||||
if cx.target_spec().os == "linux"
|
||||
|
|
@ -20,14 +25,17 @@ fn classify_arg<Ty>(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
return;
|
||||
}
|
||||
if arg.layout.is_aggregate() {
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) || arg.layout.is_aggregate() {
|
||||
arg.make_indirect();
|
||||
} else {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C: HasTargetSpec>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ where
|
|||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
if !is_ret && arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
if !arg.layout.is_aggregate() {
|
||||
arg.extend_integer_width_to(64);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -290,9 +290,15 @@ fn classify_arg<'a, Ty, C>(
|
|||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
if !arg.layout.is_sized() {
|
||||
// FIXME: Update avail_gprs?
|
||||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
*avail_gprs = (*avail_gprs).saturating_sub(1);
|
||||
return;
|
||||
}
|
||||
if !is_vararg {
|
||||
match should_use_fp_conv(cx, &arg.layout, xlen, flen) {
|
||||
Some(FloatConv::Float(f)) if *avail_fprs >= 1 => {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ where
|
|||
}
|
||||
return;
|
||||
}
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
|
||||
let size = arg.layout.size;
|
||||
if size.bits() <= 128 {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_abi::{HasDataLayout, Size};
|
||||
use rustc_abi::{HasDataLayout, Size, TyAbiInterface};
|
||||
|
||||
use crate::callconv::{ArgAbi, FnAbi, Reg, Uniform};
|
||||
|
||||
|
|
@ -14,15 +14,22 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty, C>(cx: &C, arg: &mut ArgAbi<'_, Ty>, offset: &mut Size)
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, offset: &mut Size)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout,
|
||||
{
|
||||
if !arg.layout.is_sized() {
|
||||
// FIXME: Update offset?
|
||||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
let dl = cx.data_layout();
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
*offset += dl.pointer_size();
|
||||
return;
|
||||
}
|
||||
let size = arg.layout.size;
|
||||
let align = arg.layout.align.abi.max(dl.i32_align).min(dl.i64_align);
|
||||
|
||||
|
|
@ -36,8 +43,9 @@ where
|
|||
*offset = offset.align_to(align) + size.align_to(align);
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<Ty, C>(cx: &C, fn_abi: &mut FnAbi<'_, Ty>)
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout,
|
||||
{
|
||||
let mut offset = Size::ZERO;
|
||||
|
|
|
|||
|
|
@ -140,6 +140,10 @@ where
|
|||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout,
|
||||
{
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
if !arg.layout.is_aggregate() {
|
||||
arg.extend_integer_width_to(64);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ where
|
|||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
arg.extend_integer_width_to(32);
|
||||
if arg.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, arg) {
|
||||
arg.make_indirect();
|
||||
|
|
|
|||
|
|
@ -64,6 +64,11 @@ where
|
|||
continue;
|
||||
}
|
||||
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
continue;
|
||||
}
|
||||
|
||||
let t = cx.target_spec();
|
||||
let align_4 = Align::from_bytes(4).unwrap();
|
||||
let align_16 = Align::from_bytes(16).unwrap();
|
||||
|
|
|
|||
|
|
@ -183,9 +183,15 @@ where
|
|||
|
||||
let mut x86_64_arg_or_ret = |arg: &mut ArgAbi<'a, Ty>, is_arg: bool| {
|
||||
if !arg.layout.is_sized() {
|
||||
// FIXME: Update int_regs?
|
||||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
if is_arg && arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
int_regs = int_regs.saturating_sub(1);
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
let mut cls_or_mem = classify_arg(cx, arg);
|
||||
|
||||
if is_arg {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,11 @@ pub(crate) fn compute_abi_info<'a, Ty, C>(
|
|||
continue;
|
||||
}
|
||||
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2
|
||||
// See https://reviews.llvm.org/D72114 for Clang behavior
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size};
|
||||
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size, TyAbiInterface};
|
||||
|
||||
use crate::callconv::{ArgAbi, FnAbi, Reg};
|
||||
use crate::spec::{HasTargetSpec, RustcAbi};
|
||||
|
||||
// Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing
|
||||
|
||||
pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C: HasTargetSpec>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| {
|
||||
match a.layout.backend_repr {
|
||||
BackendRepr::Memory { sized: false } => {}
|
||||
|
|
@ -59,6 +62,10 @@ pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'
|
|||
arg.make_indirect_from_ignore();
|
||||
continue;
|
||||
}
|
||||
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
arg.make_indirect();
|
||||
continue;
|
||||
}
|
||||
fixup(arg, false);
|
||||
}
|
||||
// FIXME: We should likely also do something about ZST return types, similar to above.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ const NUM_RET_GPRS: u64 = 4;
|
|||
const MAX_ARG_IN_REGS_SIZE: u64 = NUM_ARG_GPRS * 32;
|
||||
const MAX_RET_IN_REGS_SIZE: u64 = NUM_RET_GPRS * 32;
|
||||
|
||||
fn classify_ret_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>)
|
||||
fn classify_ret_ty<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
|
|
@ -26,7 +26,7 @@ where
|
|||
// The rules for return and argument types are the same,
|
||||
// so defer to `classify_arg_ty`.
|
||||
let mut arg_gprs_left = NUM_RET_GPRS;
|
||||
classify_arg_ty(arg, &mut arg_gprs_left, MAX_RET_IN_REGS_SIZE);
|
||||
classify_arg_ty(cx, arg, &mut arg_gprs_left, true);
|
||||
// Ret args cannot be passed via stack, we lower to indirect and let the backend handle the invisible reference
|
||||
match arg.mode {
|
||||
super::PassMode::Indirect { attrs: _, meta_attrs: _, ref mut on_stack } => {
|
||||
|
|
@ -36,12 +36,24 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn classify_arg_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>, arg_gprs_left: &mut u64, max_size: u64)
|
||||
where
|
||||
fn classify_arg_ty<'a, Ty, C>(
|
||||
cx: &C,
|
||||
arg: &mut ArgAbi<'a, Ty>,
|
||||
arg_gprs_left: &mut u64,
|
||||
is_ret: bool,
|
||||
) where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
assert!(*arg_gprs_left <= NUM_ARG_GPRS, "Arg GPR tracking underflow");
|
||||
|
||||
let max_size = if is_ret { MAX_RET_IN_REGS_SIZE } else { MAX_ARG_IN_REGS_SIZE };
|
||||
|
||||
if !is_ret && arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
*arg_gprs_left = arg_gprs_left.saturating_sub(1);
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore empty structs/unions.
|
||||
if arg.layout.is_zst() {
|
||||
return;
|
||||
|
|
@ -95,13 +107,13 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(_cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret_ty(&mut fn_abi.ret);
|
||||
classify_ret_ty(cx, &mut fn_abi.ret);
|
||||
}
|
||||
|
||||
let mut arg_gprs_left = NUM_ARG_GPRS;
|
||||
|
|
@ -110,7 +122,7 @@ where
|
|||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg_ty(arg, &mut arg_gprs_left, MAX_ARG_IN_REGS_SIZE);
|
||||
classify_arg_ty(cx, arg, &mut arg_gprs_left, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::assert_matches::assert_matches;
|
||||
use std::iter;
|
||||
|
||||
use rustc_abi::Primitive::Pointer;
|
||||
|
|
@ -388,6 +389,12 @@ fn fn_abi_sanity_check<'tcx>(
|
|||
if let PassMode::Indirect { on_stack, .. } = arg.mode {
|
||||
assert!(!on_stack, "rust abi shouldn't use on_stack");
|
||||
}
|
||||
} else if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
|
||||
assert_matches!(
|
||||
arg.mode,
|
||||
PassMode::Indirect { on_stack: false, .. },
|
||||
"the {spec_abi} ABI does not implement `#[rustc_pass_indirectly_in_non_rustic_abis]`"
|
||||
);
|
||||
}
|
||||
|
||||
match &arg.mode {
|
||||
|
|
|
|||
|
|
@ -639,8 +639,8 @@ fn layout_of_uncached<'tcx>(
|
|||
// UnsafeCell and UnsafePinned both disable niche optimizations
|
||||
let is_special_no_niche = def.is_unsafe_cell() || def.is_unsafe_pinned();
|
||||
|
||||
let get_discriminant_type =
|
||||
|min, max| abi::Integer::repr_discr(tcx, ty, &def.repr(), min, max);
|
||||
let discr_range_of_repr =
|
||||
|min, max| abi::Integer::discr_range_of_repr(tcx, ty, &def.repr(), min, max);
|
||||
|
||||
let discriminants_iter = || {
|
||||
def.is_enum()
|
||||
|
|
@ -663,7 +663,7 @@ fn layout_of_uncached<'tcx>(
|
|||
def.is_enum(),
|
||||
is_special_no_niche,
|
||||
tcx.layout_scalar_valid_range(def.did()),
|
||||
get_discriminant_type,
|
||||
discr_range_of_repr,
|
||||
discriminants_iter(),
|
||||
!maybe_unsized,
|
||||
)
|
||||
|
|
@ -688,7 +688,7 @@ fn layout_of_uncached<'tcx>(
|
|||
def.is_enum(),
|
||||
is_special_no_niche,
|
||||
tcx.layout_scalar_valid_range(def.did()),
|
||||
get_discriminant_type,
|
||||
discr_range_of_repr,
|
||||
discriminants_iter(),
|
||||
!maybe_unsized,
|
||||
) else {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
|
|||
if layout.size.bytes() >= tcx.data_layout.obj_size_bound() {
|
||||
bug!("size is too large, in the following layout:\n{layout:#?}");
|
||||
}
|
||||
// FIXME(#124403): Once `repr_c_enums_larger_than_int` is a hard error, we could assert
|
||||
// here that a repr(c) enum discriminant is never larger than a c_int.
|
||||
|
||||
if !cfg!(debug_assertions) {
|
||||
// Stop here, the rest is kind of expensive.
|
||||
|
|
|
|||
|
|
@ -299,3 +299,15 @@ impl<'f> Drop for VaListImpl<'f> {
|
|||
// This works for now, since `va_end` is a no-op on all current LLVM targets.
|
||||
}
|
||||
}
|
||||
|
||||
// Checks (via an assert in `compiler/rustc_ty_utils/src/abi.rs`) that the C ABI for the current
|
||||
// target correctly implements `rustc_pass_indirectly_in_non_rustic_abis`.
|
||||
const _: () = {
|
||||
#[repr(C)]
|
||||
#[rustc_pass_indirectly_in_non_rustic_abis]
|
||||
struct Type(usize);
|
||||
|
||||
const extern "C" fn c(_: Type) {}
|
||||
|
||||
c(Type(0))
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3337,6 +3337,42 @@ fn distcheck_rustc_dev(builder: &Builder<'_>, dir: &Path) {
|
|||
builder.remove_dir(dir);
|
||||
}
|
||||
|
||||
/// Runs unit tests in `bootstrap_test.py`, which test the Python parts of bootstrap.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct BootstrapPy;
|
||||
|
||||
impl Step for BootstrapPy {
|
||||
type Output = ();
|
||||
const DEFAULT: bool = true;
|
||||
const IS_HOST: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
// Bootstrap tests might not be perfectly self-contained and can depend
|
||||
// on the environment, so only run them by default in CI, not locally.
|
||||
// See `test::Bootstrap::should_run`.
|
||||
let is_ci = run.builder.config.is_running_on_ci;
|
||||
run.alias("bootstrap-py").default_condition(is_ci)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(BootstrapPy)
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) -> Self::Output {
|
||||
let mut check_bootstrap = command(builder.python());
|
||||
check_bootstrap
|
||||
.args(["-m", "unittest", "bootstrap_test.py"])
|
||||
// Forward command-line args after `--` to unittest, for filtering etc.
|
||||
.args(builder.config.test_args())
|
||||
.env("BUILD_DIR", &builder.out)
|
||||
.env("BUILD_PLATFORM", builder.build.host_target.triple)
|
||||
.env("BOOTSTRAP_TEST_RUSTC_BIN", &builder.initial_rustc)
|
||||
.env("BOOTSTRAP_TEST_CARGO_BIN", &builder.initial_cargo)
|
||||
.current_dir(builder.src.join("src/bootstrap/"));
|
||||
check_bootstrap.delay_failure().run(builder);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Bootstrap;
|
||||
|
||||
|
|
@ -3353,18 +3389,6 @@ impl Step for Bootstrap {
|
|||
// Some tests require cargo submodule to be present.
|
||||
builder.build.require_submodule("src/tools/cargo", None);
|
||||
|
||||
let mut check_bootstrap = command(builder.python());
|
||||
check_bootstrap
|
||||
.args(["-m", "unittest", "bootstrap_test.py"])
|
||||
.env("BUILD_DIR", &builder.out)
|
||||
.env("BUILD_PLATFORM", builder.build.host_target.triple)
|
||||
.env("BOOTSTRAP_TEST_RUSTC_BIN", &builder.initial_rustc)
|
||||
.env("BOOTSTRAP_TEST_CARGO_BIN", &builder.initial_cargo)
|
||||
.current_dir(builder.src.join("src/bootstrap/"));
|
||||
// NOTE: we intentionally don't pass test_args here because the args for unittest and cargo test are mutually incompatible.
|
||||
// Use `python -m unittest` manually if you want to pass arguments.
|
||||
check_bootstrap.delay_failure().run(builder);
|
||||
|
||||
let mut cargo = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
build_compiler,
|
||||
|
|
|
|||
|
|
@ -869,6 +869,7 @@ impl<'a> Builder<'a> {
|
|||
Kind::Test => describe!(
|
||||
crate::core::build_steps::toolstate::ToolStateCheck,
|
||||
test::Tidy,
|
||||
test::BootstrapPy,
|
||||
test::Bootstrap,
|
||||
test::Ui,
|
||||
test::Crashes,
|
||||
|
|
|
|||
|
|
@ -177,6 +177,21 @@ impl Add<isize> for isize {
|
|||
}
|
||||
}
|
||||
|
||||
#[lang = "neg"]
|
||||
pub trait Neg {
|
||||
type Output;
|
||||
|
||||
fn neg(self) -> Self::Output;
|
||||
}
|
||||
|
||||
impl Neg for isize {
|
||||
type Output = isize;
|
||||
|
||||
fn neg(self) -> isize {
|
||||
loop {} // Dummy impl, not actually used
|
||||
}
|
||||
}
|
||||
|
||||
#[lang = "sync"]
|
||||
trait Sync {}
|
||||
impl_marker_trait!(
|
||||
|
|
@ -231,6 +246,13 @@ pub mod mem {
|
|||
#[rustc_nounwind]
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn transmute<Src, Dst>(src: Src) -> Dst;
|
||||
|
||||
#[rustc_nounwind]
|
||||
#[rustc_intrinsic]
|
||||
pub const fn size_of<T>() -> usize;
|
||||
#[rustc_nounwind]
|
||||
#[rustc_intrinsic]
|
||||
pub const fn align_of<T>() -> usize;
|
||||
}
|
||||
|
||||
#[lang = "c_void"]
|
||||
|
|
|
|||
38
tests/ui/abi/pass-indirectly-attr.rs
Normal file
38
tests/ui/abi/pass-indirectly-attr.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
//@ add-minicore
|
||||
//@ check-fail
|
||||
//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
|
||||
//@ ignore-backends: gcc
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![crate_type = "lib"]
|
||||
#![feature(no_core)]
|
||||
#![no_std]
|
||||
#![no_core]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
#[repr(C)]
|
||||
#[rustc_pass_indirectly_in_non_rustic_abis]
|
||||
pub struct Type(u8);
|
||||
|
||||
#[rustc_abi(debug)]
|
||||
pub extern "C" fn extern_c(_: Type) {}
|
||||
//~^ ERROR fn_abi_of(extern_c) = FnAbi {
|
||||
//~| ERROR mode: Indirect
|
||||
//~| ERROR on_stack: false,
|
||||
//~| ERROR conv: C,
|
||||
|
||||
#[rustc_abi(debug)]
|
||||
pub extern "Rust" fn extern_rust(_: Type) {}
|
||||
//~^ ERROR fn_abi_of(extern_rust) = FnAbi {
|
||||
//~| ERROR mode: Cast
|
||||
//~| ERROR conv: Rust
|
||||
|
||||
#[repr(transparent)]
|
||||
struct Inner(u64);
|
||||
|
||||
#[rustc_pass_indirectly_in_non_rustic_abis]
|
||||
//~^ ERROR transparent struct cannot have other repr hints
|
||||
#[repr(transparent)]
|
||||
struct Wrapper(Inner);
|
||||
194
tests/ui/abi/pass-indirectly-attr.stderr
Normal file
194
tests/ui/abi/pass-indirectly-attr.stderr
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
error[E0692]: transparent struct cannot have other repr hints
|
||||
--> $DIR/pass-indirectly-attr.rs:35:1
|
||||
|
|
||||
LL | #[rustc_pass_indirectly_in_non_rustic_abis]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | struct Wrapper(Inner);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: fn_abi_of(extern_c) = FnAbi {
|
||||
args: [
|
||||
ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: Type,
|
||||
layout: Layout {
|
||||
size: Size(1 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
memory_index: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Indirect {
|
||||
attrs: ArgAttributes {
|
||||
regular: CapturesAddress | NoAlias | NonNull | NoUndef,
|
||||
arg_ext: None,
|
||||
pointee_size: Size(1 bytes),
|
||||
pointee_align: Some(
|
||||
Align(1 bytes),
|
||||
),
|
||||
},
|
||||
meta_attrs: None,
|
||||
on_stack: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
ret: ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: (),
|
||||
layout: Layout {
|
||||
size: Size(0 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: [],
|
||||
memory_index: [],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Ignore,
|
||||
},
|
||||
c_variadic: false,
|
||||
fixed_count: 1,
|
||||
conv: C,
|
||||
can_unwind: false,
|
||||
}
|
||||
--> $DIR/pass-indirectly-attr.rs:20:1
|
||||
|
|
||||
LL | pub extern "C" fn extern_c(_: Type) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: fn_abi_of(extern_rust) = FnAbi {
|
||||
args: [
|
||||
ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: Type,
|
||||
layout: Layout {
|
||||
size: Size(1 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
memory_index: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Cast {
|
||||
pad_i32: false,
|
||||
cast: CastTarget {
|
||||
prefix: [
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
],
|
||||
rest_offset: None,
|
||||
rest: Uniform {
|
||||
unit: Reg {
|
||||
kind: Integer,
|
||||
size: Size(1 bytes),
|
||||
},
|
||||
total: Size(1 bytes),
|
||||
is_consecutive: false,
|
||||
},
|
||||
attrs: ArgAttributes {
|
||||
regular: ,
|
||||
arg_ext: None,
|
||||
pointee_size: Size(0 bytes),
|
||||
pointee_align: None,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
ret: ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: (),
|
||||
layout: Layout {
|
||||
size: Size(0 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: [],
|
||||
memory_index: [],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Ignore,
|
||||
},
|
||||
c_variadic: false,
|
||||
fixed_count: 1,
|
||||
conv: Rust,
|
||||
can_unwind: false,
|
||||
}
|
||||
--> $DIR/pass-indirectly-attr.rs:27:1
|
||||
|
|
||||
LL | pub extern "Rust" fn extern_rust(_: Type) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0692`.
|
||||
15
tests/ui/attributes/pass-indirectly.rs
Normal file
15
tests/ui/attributes/pass-indirectly.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
//@ check-fail
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[rustc_pass_indirectly_in_non_rustic_abis]
|
||||
//~^ ERROR: `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute cannot be used on functions
|
||||
fn not_a_struct() {}
|
||||
|
||||
#[repr(C)]
|
||||
#[rustc_pass_indirectly_in_non_rustic_abis]
|
||||
struct YesAStruct {
|
||||
foo: u8,
|
||||
bar: u16,
|
||||
}
|
||||
10
tests/ui/attributes/pass-indirectly.stderr
Normal file
10
tests/ui/attributes/pass-indirectly.stderr
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
error: `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute cannot be used on functions
|
||||
--> $DIR/pass-indirectly.rs:6:1
|
||||
|
|
||||
LL | #[rustc_pass_indirectly_in_non_rustic_abis]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: `#[rustc_pass_indirectly_in_non_rustic_abis]` can only be applied to structs
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
#![feature(core_intrinsics)]
|
||||
|
||||
use std::intrinsics::discriminant_value;
|
||||
use std::mem::size_of;
|
||||
|
||||
enum E1 {
|
||||
A,
|
||||
|
|
@ -20,6 +21,14 @@ enum E3 {
|
|||
B = 100,
|
||||
}
|
||||
|
||||
// Enums like this are found in the ecosystem, let's make sure they get the right size.
|
||||
#[repr(C)]
|
||||
#[allow(overflowing_literals)]
|
||||
enum UnsignedIntEnum {
|
||||
A = 0,
|
||||
O = 0xffffffff, // doesn't fit into `int`, but fits into `unsigned int`
|
||||
}
|
||||
|
||||
#[repr(i128)]
|
||||
enum E4 {
|
||||
A = 0x1223_3445_5667_7889,
|
||||
|
|
@ -27,24 +36,38 @@ enum E4 {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(size_of::<E1>(), 1);
|
||||
let mut target: [isize; 3] = [0, 0, 0];
|
||||
target[1] = discriminant_value(&E1::A);
|
||||
assert_eq!(target, [0, 0, 0]);
|
||||
target[1] = discriminant_value(&E1::B);
|
||||
assert_eq!(target, [0, 1, 0]);
|
||||
|
||||
assert_eq!(size_of::<E2>(), 1);
|
||||
let mut target: [i8; 3] = [0, 0, 0];
|
||||
target[1] = discriminant_value(&E2::A);
|
||||
assert_eq!(target, [0, 7, 0]);
|
||||
target[1] = discriminant_value(&E2::B);
|
||||
assert_eq!(target, [0, -2, 0]);
|
||||
|
||||
// E3's size is target-dependent
|
||||
let mut target: [isize; 3] = [0, 0, 0];
|
||||
target[1] = discriminant_value(&E3::A);
|
||||
assert_eq!(target, [0, 42, 0]);
|
||||
target[1] = discriminant_value(&E3::B);
|
||||
assert_eq!(target, [0, 100, 0]);
|
||||
|
||||
#[allow(overflowing_literals)]
|
||||
{
|
||||
assert_eq!(size_of::<UnsignedIntEnum>(), 4);
|
||||
let mut target: [isize; 3] = [0, -1, 0];
|
||||
target[1] = discriminant_value(&UnsignedIntEnum::A);
|
||||
assert_eq!(target, [0, 0, 0]);
|
||||
target[1] = discriminant_value(&UnsignedIntEnum::O);
|
||||
assert_eq!(target, [0, 0xffffffff as isize, 0]);
|
||||
}
|
||||
|
||||
assert_eq!(size_of::<E4>(), 16);
|
||||
let mut target: [i128; 3] = [0, 0, 0];
|
||||
target[1] = discriminant_value(&E4::A);
|
||||
assert_eq!(target, [0, 0x1223_3445_5667_7889, 0]);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
error: literal out of range for `isize`
|
||||
--> $DIR/repr-c-big-discriminant1.rs:18:9
|
||||
|
|
||||
LL | A = 9223372036854775807, // i64::MAX
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the literal `9223372036854775807` does not fit into the type `isize` whose range is `-2147483648..=2147483647`
|
||||
= note: `#[deny(overflowing_literals)]` on by default
|
||||
|
||||
error: literal out of range for `isize`
|
||||
--> $DIR/repr-c-big-discriminant1.rs:26:9
|
||||
|
|
||||
LL | A = -2147483649, // i32::MIN-1
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: the literal `-2147483649` does not fit into the type `isize` whose range is `-2147483648..=2147483647`
|
||||
|
||||
error: literal out of range for `isize`
|
||||
--> $DIR/repr-c-big-discriminant1.rs:34:9
|
||||
|
|
||||
LL | A = 2147483648, // i32::MAX+1
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: the literal `2147483648` does not fit into the type `isize` whose range is `-2147483648..=2147483647`
|
||||
|
||||
error: literal out of range for `isize`
|
||||
--> $DIR/repr-c-big-discriminant1.rs:43:9
|
||||
|
|
||||
LL | A = 2147483648, // i32::MAX+1
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: the literal `2147483648` does not fit into the type `isize` whose range is `-2147483648..=2147483647`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
error: `repr(C)` enum discriminant does not fit into C `int` nor into C `unsigned int`
|
||||
--> $DIR/repr-c-big-discriminant1.rs:18:5
|
||||
|
|
||||
LL | A = 9223372036854775807, // i64::MAX
|
||||
| ^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #124403 <https://github.com/rust-lang/rust/issues/124403>
|
||||
= note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C
|
||||
= help: use `repr($int_ty)` instead to explicitly set the size of this enum
|
||||
note: the lint level is defined here
|
||||
--> $DIR/repr-c-big-discriminant1.rs:8:9
|
||||
|
|
||||
LL | #![deny(repr_c_enums_larger_than_int)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `repr(C)` enum discriminant does not fit into C `int` nor into C `unsigned int`
|
||||
--> $DIR/repr-c-big-discriminant1.rs:26:5
|
||||
|
|
||||
LL | A = -2147483649, // i32::MIN-1
|
||||
| ^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #124403 <https://github.com/rust-lang/rust/issues/124403>
|
||||
= note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C
|
||||
= help: use `repr($int_ty)` instead to explicitly set the size of this enum
|
||||
|
||||
error: `repr(C)` enum discriminant does not fit into C `unsigned int`, and a previous discriminant does not fit into C `int`
|
||||
--> $DIR/repr-c-big-discriminant1.rs:36:5
|
||||
|
|
||||
LL | B = -1,
|
||||
| ^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #124403 <https://github.com/rust-lang/rust/issues/124403>
|
||||
= note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C
|
||||
= help: use `repr($int_ty)` instead to explicitly set the size of this enum
|
||||
|
||||
error: `repr(C)` enum discriminant does not fit into C `int`, and a previous discriminant does not fit into C `unsigned int`
|
||||
--> $DIR/repr-c-big-discriminant1.rs:43:5
|
||||
|
|
||||
LL | A = 2147483648, // i32::MAX+1
|
||||
| ^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #124403 <https://github.com/rust-lang/rust/issues/124403>
|
||||
= note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C
|
||||
= help: use `repr($int_ty)` instead to explicitly set the size of this enum
|
||||
|
||||
error: `repr(C)` enum discriminant does not fit into C `int` nor into C `unsigned int`
|
||||
--> $DIR/repr-c-big-discriminant1.rs:53:5
|
||||
|
|
||||
LL | A = I64_MAX as isize,
|
||||
| ^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #124403 <https://github.com/rust-lang/rust/issues/124403>
|
||||
= note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C
|
||||
= help: use `repr($int_ty)` instead to explicitly set the size of this enum
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
67
tests/ui/enum-discriminant/repr-c-big-discriminant1.rs
Normal file
67
tests/ui/enum-discriminant/repr-c-big-discriminant1.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
//@ revisions: ptr32 ptr64
|
||||
//@[ptr32] compile-flags: --target i686-unknown-linux-gnu
|
||||
//@[ptr32] needs-llvm-components: x86
|
||||
//@[ptr64] compile-flags: --target x86_64-unknown-linux-gnu
|
||||
//@[ptr64] needs-llvm-components: x86
|
||||
// GCC doesn't like cross-compilation
|
||||
//@ ignore-backends: gcc
|
||||
#![deny(repr_c_enums_larger_than_int)]
|
||||
|
||||
//@ add-minicore
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
#[repr(C)]
|
||||
enum OverflowingEnum1 {
|
||||
A = 9223372036854775807, // i64::MAX
|
||||
//[ptr32]~^ ERROR: literal out of range
|
||||
//[ptr64]~^^ ERROR: discriminant does not fit into C `int` nor into C `unsigned int`
|
||||
//[ptr64]~^^^ WARN: previously accepted
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
enum OverflowingEnum2 {
|
||||
A = -2147483649, // i32::MIN-1
|
||||
//[ptr32]~^ ERROR: literal out of range
|
||||
//[ptr64]~^^ ERROR: discriminant does not fit into C `int` nor into C `unsigned int`
|
||||
//[ptr64]~^^^ WARN: previously accepted
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
enum OverflowingEnum3a {
|
||||
A = 2147483648, // i32::MAX+1
|
||||
//[ptr32]~^ ERROR: literal out of range
|
||||
B = -1,
|
||||
//[ptr64]~^ ERROR: discriminant does not fit into C `unsigned int`, and a previous
|
||||
//[ptr64]~^^ WARN: previously accepted
|
||||
}
|
||||
#[repr(C)]
|
||||
enum OverflowingEnum3b {
|
||||
B = -1,
|
||||
A = 2147483648, // i32::MAX+1
|
||||
//[ptr32]~^ ERROR: literal out of range
|
||||
//[ptr64]~^^ ERROR: discriminant does not fit into C `int`, and a previous
|
||||
//[ptr64]~^^^ WARN: previously accepted
|
||||
}
|
||||
|
||||
const I64_MAX: i64 = 9223372036854775807;
|
||||
|
||||
#[repr(C)]
|
||||
enum OverflowingEnum4 {
|
||||
A = I64_MAX as isize,
|
||||
//[ptr64]~^ ERROR: discriminant does not fit into C `int` nor into C `unsigned int`
|
||||
//[ptr64]~^^ WARN: previously accepted
|
||||
// No warning/error on 32bit targets, but the `as isize` hints that wrapping is occurring.
|
||||
}
|
||||
|
||||
// Enums like this are found in the ecosystem, let's make sure they get accepted.
|
||||
#[repr(C)]
|
||||
#[allow(overflowing_literals)]
|
||||
enum OkayEnum {
|
||||
A = 0,
|
||||
O = 0xffffffff,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
error[E0370]: enum discriminant overflowed
|
||||
--> $DIR/repr-c-big-discriminant2.rs:24:5
|
||||
|
|
||||
LL | B, // +1
|
||||
| ^ overflowed on value after 2147483647
|
||||
|
|
||||
= note: explicitly set `B = -2147483648` if that is desired outcome
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0370`.
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
error: `repr(C)` enum discriminant does not fit into C `int`, and a previous discriminant does not fit into C `unsigned int`
|
||||
--> $DIR/repr-c-big-discriminant2.rs:24:5
|
||||
|
|
||||
LL | B, // +1
|
||||
| ^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #124403 <https://github.com/rust-lang/rust/issues/124403>
|
||||
= note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C
|
||||
= help: use `repr($int_ty)` instead to explicitly set the size of this enum
|
||||
note: the lint level is defined here
|
||||
--> $DIR/repr-c-big-discriminant2.rs:8:9
|
||||
|
|
||||
LL | #![deny(repr_c_enums_larger_than_int)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
30
tests/ui/enum-discriminant/repr-c-big-discriminant2.rs
Normal file
30
tests/ui/enum-discriminant/repr-c-big-discriminant2.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
//@ revisions: ptr32 ptr64
|
||||
//@[ptr32] compile-flags: --target i686-unknown-linux-gnu
|
||||
//@[ptr32] needs-llvm-components: x86
|
||||
//@[ptr64] compile-flags: --target x86_64-unknown-linux-gnu
|
||||
//@[ptr64] needs-llvm-components: x86
|
||||
// GCC doesn't like cross-compilation
|
||||
//@ ignore-backends: gcc
|
||||
#![deny(repr_c_enums_larger_than_int)]
|
||||
|
||||
//@ add-minicore
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// Separate test since it suppresses other errors on ptr32:
|
||||
// ensure we find the bad discriminant when it is implicitly computed by incrementing
|
||||
// the previous discriminant.
|
||||
|
||||
#[repr(C)]
|
||||
enum OverflowingEnum {
|
||||
NEG = -1,
|
||||
A = 2147483647, // i32::MAX
|
||||
B, // +1
|
||||
//[ptr32]~^ ERROR: enum discriminant overflowed
|
||||
//[ptr64]~^^ ERROR: discriminant does not fit into C `int`
|
||||
//[ptr64]~^^^ WARN: previously accepted
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue