Auto merge of #142589 - Kobzol:rollup-j90fk2j, r=Kobzol
Rollup of 8 pull requests Successful merges: - rust-lang/rust#139340 (Fix RISC-V C function ABI when passing/returning structs containing floats) - rust-lang/rust#142341 (Don't suggest converting `///` to `//` when expecting `,`) - rust-lang/rust#142414 (ignore `run-make` tests that need `std` on targets without `std`) - rust-lang/rust#142498 (Port `#[rustc_as_ptr]` to the new attribute system) - rust-lang/rust#142554 (Fix `PathSource` lifetimes.) - rust-lang/rust#142562 (Update the `backtrace` submodule) - rust-lang/rust#142565 (Test naked asm for wasm32-unknown-unknown) - rust-lang/rust#142573 (`fn candidate_is_applicable` to method) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
45acf54eea
135 changed files with 913 additions and 239 deletions
|
|
@ -188,6 +188,9 @@ pub enum AttributeKind {
|
||||||
/// Represents `#[allow_internal_unstable]`.
|
/// Represents `#[allow_internal_unstable]`.
|
||||||
AllowInternalUnstable(ThinVec<(Symbol, Span)>),
|
AllowInternalUnstable(ThinVec<(Symbol, Span)>),
|
||||||
|
|
||||||
|
/// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
|
||||||
|
AsPtr(Span),
|
||||||
|
|
||||||
/// Represents `#[rustc_default_body_unstable]`.
|
/// Represents `#[rustc_default_body_unstable]`.
|
||||||
BodyStability {
|
BodyStability {
|
||||||
stability: DefaultBodyStability,
|
stability: DefaultBodyStability,
|
||||||
|
|
|
||||||
21
compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
Normal file
21
compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
use rustc_attr_data_structures::AttributeKind;
|
||||||
|
use rustc_span::{Symbol, sym};
|
||||||
|
|
||||||
|
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||||
|
use crate::context::{AcceptContext, Stage};
|
||||||
|
use crate::parser::ArgParser;
|
||||||
|
|
||||||
|
pub(crate) struct AsPtrParser;
|
||||||
|
|
||||||
|
impl<S: Stage> SingleAttributeParser<S> for AsPtrParser {
|
||||||
|
const PATH: &[Symbol] = &[sym::rustc_as_ptr];
|
||||||
|
|
||||||
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||||
|
|
||||||
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
|
|
||||||
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
|
// FIXME: check that there's no args (this is currently checked elsewhere)
|
||||||
|
Some(AttributeKind::AsPtr(cx.attr_span))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,7 @@ pub(crate) mod allow_unstable;
|
||||||
pub(crate) mod cfg;
|
pub(crate) mod cfg;
|
||||||
pub(crate) mod confusables;
|
pub(crate) mod confusables;
|
||||||
pub(crate) mod deprecation;
|
pub(crate) mod deprecation;
|
||||||
|
pub(crate) mod lint_helpers;
|
||||||
pub(crate) mod repr;
|
pub(crate) mod repr;
|
||||||
pub(crate) mod stability;
|
pub(crate) mod stability;
|
||||||
pub(crate) mod transparency;
|
pub(crate) mod transparency;
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
||||||
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
|
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
|
||||||
use crate::attributes::confusables::ConfusablesParser;
|
use crate::attributes::confusables::ConfusablesParser;
|
||||||
use crate::attributes::deprecation::DeprecationParser;
|
use crate::attributes::deprecation::DeprecationParser;
|
||||||
|
use crate::attributes::lint_helpers::AsPtrParser;
|
||||||
use crate::attributes::repr::ReprParser;
|
use crate::attributes::repr::ReprParser;
|
||||||
use crate::attributes::stability::{
|
use crate::attributes::stability::{
|
||||||
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
|
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
|
||||||
|
|
@ -102,6 +103,7 @@ attribute_parsers!(
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
|
Single<AsPtrParser>,
|
||||||
Single<ConstStabilityIndirectParser>,
|
Single<ConstStabilityIndirectParser>,
|
||||||
Single<DeprecationParser>,
|
Single<DeprecationParser>,
|
||||||
Single<TransparencyParser>,
|
Single<TransparencyParser>,
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,18 @@ fn apply_attrs_to_abi_param(param: AbiParam, arg_attrs: ArgAttributes) -> AbiPar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> {
|
fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[(Size, AbiParam); 2]> {
|
||||||
|
if let Some(offset_from_start) = cast.rest_offset {
|
||||||
|
assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
|
||||||
|
assert_eq!(cast.rest.unit.size, cast.rest.total);
|
||||||
|
let first = cast.prefix[0].unwrap();
|
||||||
|
let second = cast.rest.unit;
|
||||||
|
return smallvec![
|
||||||
|
(Size::ZERO, reg_to_abi_param(first)),
|
||||||
|
(offset_from_start, reg_to_abi_param(second))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 {
|
let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 {
|
||||||
(0, 0)
|
(0, 0)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -55,25 +66,32 @@ fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> {
|
||||||
// different types in Cranelift IR. Instead a single array of primitive types is used.
|
// different types in Cranelift IR. Instead a single array of primitive types is used.
|
||||||
|
|
||||||
// Create list of fields in the main structure
|
// Create list of fields in the main structure
|
||||||
let mut args = cast
|
let args = cast
|
||||||
.prefix
|
.prefix
|
||||||
.iter()
|
.iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.map(|®| reg_to_abi_param(reg))
|
.map(|®| reg_to_abi_param(reg))
|
||||||
.chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)))
|
.chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)));
|
||||||
.collect::<SmallVec<_>>();
|
|
||||||
|
let mut res = SmallVec::new();
|
||||||
|
let mut offset = Size::ZERO;
|
||||||
|
|
||||||
|
for arg in args {
|
||||||
|
res.push((offset, arg));
|
||||||
|
offset += Size::from_bytes(arg.value_type.bytes());
|
||||||
|
}
|
||||||
|
|
||||||
// Append final integer
|
// Append final integer
|
||||||
if rem_bytes != 0 {
|
if rem_bytes != 0 {
|
||||||
// Only integers can be really split further.
|
// Only integers can be really split further.
|
||||||
assert_eq!(cast.rest.unit.kind, RegKind::Integer);
|
assert_eq!(cast.rest.unit.kind, RegKind::Integer);
|
||||||
args.push(reg_to_abi_param(Reg {
|
res.push((
|
||||||
kind: RegKind::Integer,
|
offset,
|
||||||
size: Size::from_bytes(rem_bytes),
|
reg_to_abi_param(Reg { kind: RegKind::Integer, size: Size::from_bytes(rem_bytes) }),
|
||||||
}));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
args
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||||
|
|
@ -104,7 +122,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||||
},
|
},
|
||||||
PassMode::Cast { ref cast, pad_i32 } => {
|
PassMode::Cast { ref cast, pad_i32 } => {
|
||||||
assert!(!pad_i32, "padding support not yet implemented");
|
assert!(!pad_i32, "padding support not yet implemented");
|
||||||
cast_target_to_abi_params(cast)
|
cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect()
|
||||||
}
|
}
|
||||||
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
|
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
|
||||||
if on_stack {
|
if on_stack {
|
||||||
|
|
@ -160,9 +178,10 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||||
}
|
}
|
||||||
_ => unreachable!("{:?}", self.layout.backend_repr),
|
_ => unreachable!("{:?}", self.layout.backend_repr),
|
||||||
},
|
},
|
||||||
PassMode::Cast { ref cast, .. } => {
|
PassMode::Cast { ref cast, .. } => (
|
||||||
(None, cast_target_to_abi_params(cast).into_iter().collect())
|
None,
|
||||||
}
|
cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect(),
|
||||||
|
),
|
||||||
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
|
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
|
||||||
assert!(!on_stack);
|
assert!(!on_stack);
|
||||||
(
|
(
|
||||||
|
|
@ -187,12 +206,14 @@ pub(super) fn to_casted_value<'tcx>(
|
||||||
) -> SmallVec<[Value; 2]> {
|
) -> SmallVec<[Value; 2]> {
|
||||||
let (ptr, meta) = arg.force_stack(fx);
|
let (ptr, meta) = arg.force_stack(fx);
|
||||||
assert!(meta.is_none());
|
assert!(meta.is_none());
|
||||||
let mut offset = 0;
|
|
||||||
cast_target_to_abi_params(cast)
|
cast_target_to_abi_params(cast)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|param| {
|
.map(|(offset, param)| {
|
||||||
let val = ptr.offset_i64(fx, offset).load(fx, param.value_type, MemFlags::new());
|
let val = ptr.offset_i64(fx, offset.bytes() as i64).load(
|
||||||
offset += i64::from(param.value_type.bytes());
|
fx,
|
||||||
|
param.value_type,
|
||||||
|
MemFlags::new(),
|
||||||
|
);
|
||||||
val
|
val
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|
@ -205,7 +226,7 @@ pub(super) fn from_casted_value<'tcx>(
|
||||||
cast: &CastTarget,
|
cast: &CastTarget,
|
||||||
) -> CValue<'tcx> {
|
) -> CValue<'tcx> {
|
||||||
let abi_params = cast_target_to_abi_params(cast);
|
let abi_params = cast_target_to_abi_params(cast);
|
||||||
let abi_param_size: u32 = abi_params.iter().map(|param| param.value_type.bytes()).sum();
|
let abi_param_size: u32 = abi_params.iter().map(|(_, param)| param.value_type.bytes()).sum();
|
||||||
let layout_size = u32::try_from(layout.size.bytes()).unwrap();
|
let layout_size = u32::try_from(layout.size.bytes()).unwrap();
|
||||||
let ptr = fx.create_stack_slot(
|
let ptr = fx.create_stack_slot(
|
||||||
// Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
|
// Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
|
||||||
|
|
@ -214,16 +235,13 @@ pub(super) fn from_casted_value<'tcx>(
|
||||||
std::cmp::max(abi_param_size, layout_size),
|
std::cmp::max(abi_param_size, layout_size),
|
||||||
u32::try_from(layout.align.abi.bytes()).unwrap(),
|
u32::try_from(layout.align.abi.bytes()).unwrap(),
|
||||||
);
|
);
|
||||||
let mut offset = 0;
|
|
||||||
let mut block_params_iter = block_params.iter().copied();
|
let mut block_params_iter = block_params.iter().copied();
|
||||||
for param in abi_params {
|
for (offset, _) in abi_params {
|
||||||
let val = ptr.offset_i64(fx, offset).store(
|
ptr.offset_i64(fx, offset.bytes() as i64).store(
|
||||||
fx,
|
fx,
|
||||||
block_params_iter.next().unwrap(),
|
block_params_iter.next().unwrap(),
|
||||||
MemFlags::new(),
|
MemFlags::new(),
|
||||||
);
|
)
|
||||||
offset += i64::from(param.value_type.bytes());
|
|
||||||
val
|
|
||||||
}
|
}
|
||||||
assert_eq!(block_params_iter.next(), None, "Leftover block param");
|
assert_eq!(block_params_iter.next(), None, "Leftover block param");
|
||||||
CValue::by_ref(ptr, layout)
|
CValue::by_ref(ptr, layout)
|
||||||
|
|
|
||||||
|
|
@ -626,7 +626,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||||
bx.lifetime_start(llscratch, scratch_size);
|
bx.lifetime_start(llscratch, scratch_size);
|
||||||
|
|
||||||
// ... where we first store the value...
|
// ... where we first store the value...
|
||||||
bx.store(val, llscratch, scratch_align);
|
rustc_codegen_ssa::mir::store_cast(bx, cast, val, llscratch, scratch_align);
|
||||||
|
|
||||||
// ... and then memcpy it to the intended destination.
|
// ... and then memcpy it to the intended destination.
|
||||||
bx.memcpy(
|
bx.memcpy(
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||||
let llscratch = bx.alloca(scratch_size, scratch_align);
|
let llscratch = bx.alloca(scratch_size, scratch_align);
|
||||||
bx.lifetime_start(llscratch, scratch_size);
|
bx.lifetime_start(llscratch, scratch_size);
|
||||||
// ...store the value...
|
// ...store the value...
|
||||||
bx.store(val, llscratch, scratch_align);
|
rustc_codegen_ssa::mir::store_cast(bx, cast, val, llscratch, scratch_align);
|
||||||
// ... and then memcpy it to the intended destination.
|
// ... and then memcpy it to the intended destination.
|
||||||
bx.memcpy(
|
bx.memcpy(
|
||||||
dst.val.llval,
|
dst.val.llval,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
|
use rustc_abi::{Align, BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||||
use rustc_data_structures::packed::Pu128;
|
use rustc_data_structures::packed::Pu128;
|
||||||
|
|
@ -13,7 +13,7 @@ use rustc_middle::{bug, span_bug};
|
||||||
use rustc_session::config::OptLevel;
|
use rustc_session::config::OptLevel;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
|
use rustc_target::callconv::{ArgAbi, CastTarget, FnAbi, PassMode};
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
use super::operand::OperandRef;
|
use super::operand::OperandRef;
|
||||||
|
|
@ -558,8 +558,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"),
|
ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"),
|
||||||
};
|
};
|
||||||
let ty = bx.cast_backend_type(cast_ty);
|
load_cast(bx, cast_ty, llslot, self.fn_abi.ret.layout.align.abi)
|
||||||
bx.load(ty, llslot, self.fn_abi.ret.layout.align.abi)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
bx.ret(llval);
|
bx.ret(llval);
|
||||||
|
|
@ -1618,8 +1617,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
MemFlags::empty(),
|
MemFlags::empty(),
|
||||||
);
|
);
|
||||||
// ...and then load it with the ABI type.
|
// ...and then load it with the ABI type.
|
||||||
let cast_ty = bx.cast_backend_type(cast);
|
llval = load_cast(bx, cast, llscratch, scratch_align);
|
||||||
llval = bx.load(cast_ty, llscratch, scratch_align);
|
|
||||||
bx.lifetime_end(llscratch, scratch_size);
|
bx.lifetime_end(llscratch, scratch_size);
|
||||||
} else {
|
} else {
|
||||||
// We can't use `PlaceRef::load` here because the argument
|
// We can't use `PlaceRef::load` here because the argument
|
||||||
|
|
@ -1969,3 +1967,47 @@ enum ReturnDest<'tcx, V> {
|
||||||
/// Store a direct return value to an operand local place.
|
/// Store a direct return value to an operand local place.
|
||||||
DirectOperand(mir::Local),
|
DirectOperand(mir::Local),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
|
bx: &mut Bx,
|
||||||
|
cast: &CastTarget,
|
||||||
|
ptr: Bx::Value,
|
||||||
|
align: Align,
|
||||||
|
) -> Bx::Value {
|
||||||
|
let cast_ty = bx.cast_backend_type(cast);
|
||||||
|
if let Some(offset_from_start) = cast.rest_offset {
|
||||||
|
assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
|
||||||
|
assert_eq!(cast.rest.unit.size, cast.rest.total);
|
||||||
|
let first_ty = bx.reg_backend_type(&cast.prefix[0].unwrap());
|
||||||
|
let second_ty = bx.reg_backend_type(&cast.rest.unit);
|
||||||
|
let first = bx.load(first_ty, ptr, align);
|
||||||
|
let second_ptr = bx.inbounds_ptradd(ptr, bx.const_usize(offset_from_start.bytes()));
|
||||||
|
let second = bx.load(second_ty, second_ptr, align.restrict_for_offset(offset_from_start));
|
||||||
|
let res = bx.cx().const_poison(cast_ty);
|
||||||
|
let res = bx.insert_value(res, first, 0);
|
||||||
|
bx.insert_value(res, second, 1)
|
||||||
|
} else {
|
||||||
|
bx.load(cast_ty, ptr, align)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn store_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
|
bx: &mut Bx,
|
||||||
|
cast: &CastTarget,
|
||||||
|
value: Bx::Value,
|
||||||
|
ptr: Bx::Value,
|
||||||
|
align: Align,
|
||||||
|
) {
|
||||||
|
if let Some(offset_from_start) = cast.rest_offset {
|
||||||
|
assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
|
||||||
|
assert_eq!(cast.rest.unit.size, cast.rest.total);
|
||||||
|
assert!(cast.prefix[0].is_some());
|
||||||
|
let first = bx.extract_value(value, 0);
|
||||||
|
let second = bx.extract_value(value, 1);
|
||||||
|
bx.store(first, ptr, align);
|
||||||
|
let second_ptr = bx.inbounds_ptradd(ptr, bx.const_usize(offset_from_start.bytes()));
|
||||||
|
bx.store(second, second_ptr, align.restrict_for_offset(offset_from_start));
|
||||||
|
} else {
|
||||||
|
bx.store(value, ptr, align);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ pub mod place;
|
||||||
mod rvalue;
|
mod rvalue;
|
||||||
mod statement;
|
mod statement;
|
||||||
|
|
||||||
|
pub use self::block::store_cast;
|
||||||
use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
|
use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
|
||||||
use self::operand::{OperandRef, OperandValue};
|
use self::operand::{OperandRef, OperandValue};
|
||||||
use self::place::PlaceRef;
|
use self::place::PlaceRef;
|
||||||
|
|
@ -259,7 +260,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
}
|
}
|
||||||
PassMode::Cast { ref cast, .. } => {
|
PassMode::Cast { ref cast, .. } => {
|
||||||
debug!("alloc: {:?} (return place) -> place", local);
|
debug!("alloc: {:?} (return place) -> place", local);
|
||||||
let size = cast.size(&start_bx);
|
let size = cast.size(&start_bx).max(layout.size);
|
||||||
return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout));
|
return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use rustc_ast::visit::{visit_opt, walk_list};
|
use rustc_ast::visit::{visit_opt, walk_list};
|
||||||
|
use rustc_attr_data_structures::{AttributeKind, find_attr};
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
|
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
|
||||||
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem};
|
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem};
|
||||||
|
|
@ -133,7 +134,7 @@ fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
&& let ty = cx.typeck_results().expr_ty(receiver)
|
&& let ty = cx.typeck_results().expr_ty(receiver)
|
||||||
&& owns_allocation(cx.tcx, ty)
|
&& owns_allocation(cx.tcx, ty)
|
||||||
&& let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
&& let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||||
&& cx.tcx.has_attr(fn_id, sym::rustc_as_ptr)
|
&& find_attr!(cx.tcx.get_all_attrs(fn_id), AttributeKind::AsPtr(_))
|
||||||
{
|
{
|
||||||
// FIXME: use `emit_node_lint` when `#[primary_span]` is added.
|
// FIXME: use `emit_node_lint` when `#[primary_span]` is added.
|
||||||
cx.tcx.emit_node_span_lint(
|
cx.tcx.emit_node_span_lint(
|
||||||
|
|
|
||||||
|
|
@ -686,6 +686,16 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let token::DocComment(kind, style, _) = self.token.kind {
|
if let token::DocComment(kind, style, _) = self.token.kind {
|
||||||
|
// This is to avoid suggesting converting a doc comment to a regular comment
|
||||||
|
// when missing a comma before the doc comment in lists (#142311):
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// enum Foo{
|
||||||
|
// A /// xxxxxxx
|
||||||
|
// B,
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
if !expected.contains(&TokenType::Comma) {
|
||||||
// We have something like `expr //!val` where the user likely meant `expr // !val`
|
// We have something like `expr //!val` where the user likely meant `expr // !val`
|
||||||
let pos = self.token.span.lo() + BytePos(2);
|
let pos = self.token.span.lo() + BytePos(2);
|
||||||
let span = self.token.span.with_lo(pos).with_hi(pos);
|
let span = self.token.span.with_lo(pos).with_hi(pos);
|
||||||
|
|
@ -701,9 +711,10 @@ impl<'a> Parser<'a> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
" ".to_string(),
|
" ".to_string(),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let sp = if self.token == token::Eof {
|
let sp = if self.token == token::Eof {
|
||||||
// This is EOF; don't want to point at the following char, but rather the last token.
|
// This is EOF; don't want to point at the following char, but rather the last token.
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||||
| AttributeKind::ConstStabilityIndirect
|
| AttributeKind::ConstStabilityIndirect
|
||||||
| AttributeKind::MacroTransparency(_),
|
| AttributeKind::MacroTransparency(_),
|
||||||
) => { /* do nothing */ }
|
) => { /* do nothing */ }
|
||||||
|
Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => {
|
||||||
|
self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target)
|
||||||
|
}
|
||||||
Attribute::Unparsed(_) => {
|
Attribute::Unparsed(_) => {
|
||||||
match attr.path().as_slice() {
|
match attr.path().as_slice() {
|
||||||
[sym::diagnostic, sym::do_not_recommend, ..] => {
|
[sym::diagnostic, sym::do_not_recommend, ..] => {
|
||||||
|
|
@ -188,26 +191,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||||
self.check_rustc_std_internal_symbol(attr, span, target)
|
self.check_rustc_std_internal_symbol(attr, span, target)
|
||||||
}
|
}
|
||||||
[sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs),
|
[sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs),
|
||||||
[sym::rustc_as_ptr, ..] => {
|
|
||||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
|
||||||
}
|
|
||||||
[sym::rustc_no_implicit_autorefs, ..] => {
|
[sym::rustc_no_implicit_autorefs, ..] => {
|
||||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||||
}
|
}
|
||||||
[sym::rustc_never_returns_null_ptr, ..] => {
|
[sym::rustc_never_returns_null_ptr, ..] => {
|
||||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||||
}
|
}
|
||||||
[sym::rustc_legacy_const_generics, ..] => {
|
[sym::rustc_legacy_const_generics, ..] => {
|
||||||
self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
|
self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
|
||||||
}
|
}
|
||||||
[sym::rustc_lint_query_instability, ..] => {
|
[sym::rustc_lint_query_instability, ..] => {
|
||||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||||
}
|
}
|
||||||
[sym::rustc_lint_untracked_query_information, ..] => {
|
[sym::rustc_lint_untracked_query_information, ..] => {
|
||||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||||
}
|
}
|
||||||
[sym::rustc_lint_diagnostics, ..] => {
|
[sym::rustc_lint_diagnostics, ..] => {
|
||||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||||
}
|
}
|
||||||
[sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
|
[sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
|
||||||
[sym::rustc_lint_opt_deny_field_access, ..] => {
|
[sym::rustc_lint_opt_deny_field_access, ..] => {
|
||||||
|
|
@ -1825,15 +1825,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||||
fn check_applied_to_fn_or_method(
|
fn check_applied_to_fn_or_method(
|
||||||
&self,
|
&self,
|
||||||
hir_id: HirId,
|
hir_id: HirId,
|
||||||
attr: &Attribute,
|
attr_span: Span,
|
||||||
span: Span,
|
defn_span: Span,
|
||||||
target: Target,
|
target: Target,
|
||||||
) {
|
) {
|
||||||
let is_function = matches!(target, Target::Fn | Target::Method(..));
|
let is_function = matches!(target, Target::Fn | Target::Method(..));
|
||||||
if !is_function {
|
if !is_function {
|
||||||
self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
|
self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
|
||||||
attr_span: attr.span(),
|
attr_span,
|
||||||
defn_span: span,
|
defn_span,
|
||||||
on_crate: hir_id == CRATE_HIR_ID,
|
on_crate: hir_id == CRATE_HIR_ID,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -415,24 +415,24 @@ pub(crate) enum AliasPossibility {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub(crate) enum PathSource<'a, 'c> {
|
pub(crate) enum PathSource<'a, 'ast, 'ra> {
|
||||||
/// Type paths `Path`.
|
/// Type paths `Path`.
|
||||||
Type,
|
Type,
|
||||||
/// Trait paths in bounds or impls.
|
/// Trait paths in bounds or impls.
|
||||||
Trait(AliasPossibility),
|
Trait(AliasPossibility),
|
||||||
/// Expression paths `path`, with optional parent context.
|
/// Expression paths `path`, with optional parent context.
|
||||||
Expr(Option<&'a Expr>),
|
Expr(Option<&'ast Expr>),
|
||||||
/// Paths in path patterns `Path`.
|
/// Paths in path patterns `Path`.
|
||||||
Pat,
|
Pat,
|
||||||
/// Paths in struct expressions and patterns `Path { .. }`.
|
/// Paths in struct expressions and patterns `Path { .. }`.
|
||||||
Struct,
|
Struct,
|
||||||
/// Paths in tuple struct patterns `Path(..)`.
|
/// Paths in tuple struct patterns `Path(..)`.
|
||||||
TupleStruct(Span, &'a [Span]),
|
TupleStruct(Span, &'ra [Span]),
|
||||||
/// `m::A::B` in `<T as m::A>::B::C`.
|
/// `m::A::B` in `<T as m::A>::B::C`.
|
||||||
///
|
///
|
||||||
/// Second field holds the "cause" of this one, i.e. the context within
|
/// Second field holds the "cause" of this one, i.e. the context within
|
||||||
/// which the trait item is resolved. Used for diagnostics.
|
/// which the trait item is resolved. Used for diagnostics.
|
||||||
TraitItem(Namespace, &'c PathSource<'a, 'c>),
|
TraitItem(Namespace, &'a PathSource<'a, 'ast, 'ra>),
|
||||||
/// Paths in delegation item
|
/// Paths in delegation item
|
||||||
Delegation,
|
Delegation,
|
||||||
/// An arg in a `use<'a, N>` precise-capturing bound.
|
/// An arg in a `use<'a, N>` precise-capturing bound.
|
||||||
|
|
@ -443,7 +443,7 @@ pub(crate) enum PathSource<'a, 'c> {
|
||||||
DefineOpaques,
|
DefineOpaques,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PathSource<'a, '_> {
|
impl PathSource<'_, '_, '_> {
|
||||||
fn namespace(self) -> Namespace {
|
fn namespace(self) -> Namespace {
|
||||||
match self {
|
match self {
|
||||||
PathSource::Type
|
PathSource::Type
|
||||||
|
|
@ -773,7 +773,7 @@ struct LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
|
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
|
||||||
impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn visit_attribute(&mut self, _: &'ast Attribute) {
|
fn visit_attribute(&mut self, _: &'ast Attribute) {
|
||||||
// We do not want to resolve expressions that appear in attributes,
|
// We do not want to resolve expressions that appear in attributes,
|
||||||
// as they do not correspond to actual code.
|
// as they do not correspond to actual code.
|
||||||
|
|
@ -1462,7 +1462,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||||
fn new(resolver: &'a mut Resolver<'ra, 'tcx>) -> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
fn new(resolver: &'a mut Resolver<'ra, 'tcx>) -> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||||
// During late resolution we only track the module component of the parent scope,
|
// During late resolution we only track the module component of the parent scope,
|
||||||
// although it may be useful to track other components as well for diagnostics.
|
// although it may be useful to track other components as well for diagnostics.
|
||||||
|
|
@ -2010,7 +2010,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
partial_res: PartialRes,
|
partial_res: PartialRes,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
) {
|
) {
|
||||||
let proj_start = path.len() - partial_res.unresolved_segments();
|
let proj_start = path.len() - partial_res.unresolved_segments();
|
||||||
|
|
@ -4161,7 +4161,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
qself: &Option<P<QSelf>>,
|
qself: &Option<P<QSelf>>,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
source: PathSource<'ast, '_>,
|
source: PathSource<'_, 'ast, '_>,
|
||||||
) {
|
) {
|
||||||
self.smart_resolve_path_fragment(
|
self.smart_resolve_path_fragment(
|
||||||
qself,
|
qself,
|
||||||
|
|
@ -4178,7 +4178,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
qself: &Option<P<QSelf>>,
|
qself: &Option<P<QSelf>>,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
source: PathSource<'ast, '_>,
|
source: PathSource<'_, 'ast, '_>,
|
||||||
finalize: Finalize,
|
finalize: Finalize,
|
||||||
record_partial_res: RecordPartialRes,
|
record_partial_res: RecordPartialRes,
|
||||||
parent_qself: Option<&QSelf>,
|
parent_qself: Option<&QSelf>,
|
||||||
|
|
@ -4482,7 +4482,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
defer_to_typeck: bool,
|
defer_to_typeck: bool,
|
||||||
finalize: Finalize,
|
finalize: Finalize,
|
||||||
source: PathSource<'ast, '_>,
|
source: PathSource<'_, 'ast, '_>,
|
||||||
) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
|
) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
|
||||||
let mut fin_res = None;
|
let mut fin_res = None;
|
||||||
|
|
||||||
|
|
@ -4525,7 +4525,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
ns: Namespace,
|
ns: Namespace,
|
||||||
finalize: Finalize,
|
finalize: Finalize,
|
||||||
source: PathSource<'ast, '_>,
|
source: PathSource<'_, 'ast, '_>,
|
||||||
) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
|
) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
|
||||||
debug!(
|
debug!(
|
||||||
"resolve_qpath(qself={:?}, path={:?}, ns={:?}, finalize={:?})",
|
"resolve_qpath(qself={:?}, path={:?}, ns={:?}, finalize={:?})",
|
||||||
|
|
|
||||||
|
|
@ -170,12 +170,12 @@ impl TypoCandidate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn make_base_error(
|
fn make_base_error(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
span: Span,
|
span: Span,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
res: Option<Res>,
|
res: Option<Res>,
|
||||||
) -> BaseError {
|
) -> BaseError {
|
||||||
// Make the base error.
|
// Make the base error.
|
||||||
|
|
@ -421,7 +421,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
following_seg: Option<&Segment>,
|
following_seg: Option<&Segment>,
|
||||||
span: Span,
|
span: Span,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
res: Option<Res>,
|
res: Option<Res>,
|
||||||
qself: Option<&QSelf>,
|
qself: Option<&QSelf>,
|
||||||
) -> (Diag<'tcx>, Vec<ImportSuggestion>) {
|
) -> (Diag<'tcx>, Vec<ImportSuggestion>) {
|
||||||
|
|
@ -539,7 +539,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
following_seg: Option<&Segment>,
|
following_seg: Option<&Segment>,
|
||||||
span: Span,
|
span: Span,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
res: Option<Res>,
|
res: Option<Res>,
|
||||||
qself: Option<&QSelf>,
|
qself: Option<&QSelf>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -650,7 +650,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn try_lookup_name_relaxed(
|
fn try_lookup_name_relaxed(
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
following_seg: Option<&Segment>,
|
following_seg: Option<&Segment>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
@ -940,7 +940,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn suggest_trait_and_bounds(
|
fn suggest_trait_and_bounds(
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
res: Option<Res>,
|
res: Option<Res>,
|
||||||
span: Span,
|
span: Span,
|
||||||
base_error: &BaseError,
|
base_error: &BaseError,
|
||||||
|
|
@ -1017,7 +1017,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn suggest_typo(
|
fn suggest_typo(
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
following_seg: Option<&Segment>,
|
following_seg: Option<&Segment>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
@ -1063,7 +1063,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn suggest_shadowed(
|
fn suggest_shadowed(
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
following_seg: Option<&Segment>,
|
following_seg: Option<&Segment>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
@ -1096,7 +1096,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn err_code_special_cases(
|
fn err_code_special_cases(
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
|
|
@ -1141,7 +1141,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn suggest_self_ty(
|
fn suggest_self_ty(
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
|
@ -1164,7 +1164,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn suggest_self_value(
|
fn suggest_self_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
|
@ -1332,7 +1332,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn suggest_swapping_misplaced_self_ty_and_trait(
|
fn suggest_swapping_misplaced_self_ty_and_trait(
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
res: Option<Res>,
|
res: Option<Res>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
|
|
@ -1361,7 +1361,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
res: Option<Res>,
|
res: Option<Res>,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
) {
|
) {
|
||||||
let PathSource::TupleStruct(_, _) = source else { return };
|
let PathSource::TupleStruct(_, _) = source else { return };
|
||||||
let Some(Res::Def(DefKind::Fn, _)) = res else { return };
|
let Some(Res::Def(DefKind::Fn, _)) = res else { return };
|
||||||
|
|
@ -1373,7 +1373,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
res: Option<Res>,
|
res: Option<Res>,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
let PathSource::Trait(_) = source else { return };
|
let PathSource::Trait(_) = source else { return };
|
||||||
|
|
@ -1422,7 +1422,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn suggest_pattern_match_with_let(
|
fn suggest_pattern_match_with_let(
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let PathSource::Expr(_) = source
|
if let PathSource::Expr(_) = source
|
||||||
|
|
@ -1448,7 +1448,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn get_single_associated_item(
|
fn get_single_associated_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
source: &PathSource<'_, '_>,
|
source: &PathSource<'_, '_, '_>,
|
||||||
filter_fn: &impl Fn(Res) -> bool,
|
filter_fn: &impl Fn(Res) -> bool,
|
||||||
) -> Option<TypoSuggestion> {
|
) -> Option<TypoSuggestion> {
|
||||||
if let crate::PathSource::TraitItem(_, _) = source {
|
if let crate::PathSource::TraitItem(_, _) = source {
|
||||||
|
|
@ -1556,7 +1556,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
|
|
||||||
/// Check if the source is call expression and the first argument is `self`. If true,
|
/// Check if the source is call expression and the first argument is `self`. If true,
|
||||||
/// return the span of whole call and the span for all arguments expect the first one (`self`).
|
/// return the span of whole call and the span for all arguments expect the first one (`self`).
|
||||||
fn call_has_self_arg(&self, source: PathSource<'_, '_>) -> Option<(Span, Option<Span>)> {
|
fn call_has_self_arg(&self, source: PathSource<'_, '_, '_>) -> Option<(Span, Option<Span>)> {
|
||||||
let mut has_self_arg = None;
|
let mut has_self_arg = None;
|
||||||
if let PathSource::Expr(Some(parent)) = source
|
if let PathSource::Expr(Some(parent)) = source
|
||||||
&& let ExprKind::Call(_, args) = &parent.kind
|
&& let ExprKind::Call(_, args) = &parent.kind
|
||||||
|
|
@ -1614,7 +1614,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
res: Res,
|
res: Res,
|
||||||
path_str: &str,
|
path_str: &str,
|
||||||
|
|
@ -1666,7 +1666,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let find_span = |source: &PathSource<'_, '_>, err: &mut Diag<'_>| {
|
let find_span = |source: &PathSource<'_, '_, '_>, err: &mut Diag<'_>| {
|
||||||
match source {
|
match source {
|
||||||
PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
|
PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
|
||||||
| PathSource::TupleStruct(span, _) => {
|
| PathSource::TupleStruct(span, _) => {
|
||||||
|
|
@ -2699,7 +2699,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
fn suggest_using_enum_variant(
|
fn suggest_using_enum_variant(
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
|
|
@ -2877,7 +2877,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
pub(crate) fn suggest_adding_generic_parameter(
|
pub(crate) fn suggest_adding_generic_parameter(
|
||||||
&self,
|
&self,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
source: PathSource<'_, '_>,
|
source: PathSource<'_, '_, '_>,
|
||||||
) -> Option<(Span, &'static str, String, Applicability)> {
|
) -> Option<(Span, &'static str, String, Applicability)> {
|
||||||
let (ident, span) = match path {
|
let (ident, span) = match path {
|
||||||
[segment]
|
[segment]
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,7 @@ use rustc_abi::{
|
||||||
BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Size, TyAbiInterface,
|
BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Size, TyAbiInterface,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::callconv::{
|
use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform};
|
||||||
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode, Uniform,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
|
fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
|
||||||
// Always sign extend u32 values on 64-bit mips
|
// Always sign extend u32 values on 64-bit mips
|
||||||
|
|
@ -140,16 +138,7 @@ where
|
||||||
|
|
||||||
// Extract first 8 chunks as the prefix
|
// Extract first 8 chunks as the prefix
|
||||||
let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
|
let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
|
||||||
arg.cast_to(CastTarget {
|
arg.cast_to(CastTarget::prefixed(prefix, Uniform::new(Reg::i64(), rest_size)));
|
||||||
prefix,
|
|
||||||
rest: Uniform::new(Reg::i64(), rest_size),
|
|
||||||
attrs: ArgAttributes {
|
|
||||||
regular: ArgAttribute::default(),
|
|
||||||
arg_ext: ArgExtension::None,
|
|
||||||
pointee_size: Size::ZERO,
|
|
||||||
pointee_align: None,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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>)
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,17 @@ impl ArgAttributes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ArgAttribute> for ArgAttributes {
|
||||||
|
fn from(value: ArgAttribute) -> Self {
|
||||||
|
Self {
|
||||||
|
regular: value,
|
||||||
|
arg_ext: ArgExtension::None,
|
||||||
|
pointee_size: Size::ZERO,
|
||||||
|
pointee_align: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An argument passed entirely registers with the
|
/// An argument passed entirely registers with the
|
||||||
/// same kind (e.g., HFA / HVA on PPC64 and AArch64).
|
/// same kind (e.g., HFA / HVA on PPC64 and AArch64).
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||||
|
|
@ -251,6 +262,9 @@ impl Uniform {
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||||
pub struct CastTarget {
|
pub struct CastTarget {
|
||||||
pub prefix: [Option<Reg>; 8],
|
pub prefix: [Option<Reg>; 8],
|
||||||
|
/// The offset of `rest` from the start of the value. Currently only implemented for a `Reg`
|
||||||
|
/// pair created by the `offset_pair` method.
|
||||||
|
pub rest_offset: Option<Size>,
|
||||||
pub rest: Uniform,
|
pub rest: Uniform,
|
||||||
pub attrs: ArgAttributes,
|
pub attrs: ArgAttributes,
|
||||||
}
|
}
|
||||||
|
|
@ -263,42 +277,45 @@ impl From<Reg> for CastTarget {
|
||||||
|
|
||||||
impl From<Uniform> for CastTarget {
|
impl From<Uniform> for CastTarget {
|
||||||
fn from(uniform: Uniform) -> CastTarget {
|
fn from(uniform: Uniform) -> CastTarget {
|
||||||
CastTarget {
|
Self::prefixed([None; 8], uniform)
|
||||||
prefix: [None; 8],
|
|
||||||
rest: uniform,
|
|
||||||
attrs: ArgAttributes {
|
|
||||||
regular: ArgAttribute::default(),
|
|
||||||
arg_ext: ArgExtension::None,
|
|
||||||
pointee_size: Size::ZERO,
|
|
||||||
pointee_align: None,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CastTarget {
|
impl CastTarget {
|
||||||
pub fn pair(a: Reg, b: Reg) -> CastTarget {
|
pub fn prefixed(prefix: [Option<Reg>; 8], rest: Uniform) -> Self {
|
||||||
CastTarget {
|
Self { prefix, rest_offset: None, rest, attrs: ArgAttributes::new() }
|
||||||
prefix: [Some(a), None, None, None, None, None, None, None],
|
|
||||||
rest: Uniform::from(b),
|
|
||||||
attrs: ArgAttributes {
|
|
||||||
regular: ArgAttribute::default(),
|
|
||||||
arg_ext: ArgExtension::None,
|
|
||||||
pointee_size: Size::ZERO,
|
|
||||||
pointee_align: None,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn offset_pair(a: Reg, offset_from_start: Size, b: Reg) -> Self {
|
||||||
|
Self {
|
||||||
|
prefix: [Some(a), None, None, None, None, None, None, None],
|
||||||
|
rest_offset: Some(offset_from_start),
|
||||||
|
rest: b.into(),
|
||||||
|
attrs: ArgAttributes::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_attrs(mut self, attrs: ArgAttributes) -> Self {
|
||||||
|
self.attrs = attrs;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pair(a: Reg, b: Reg) -> CastTarget {
|
||||||
|
Self::prefixed([Some(a), None, None, None, None, None, None, None], Uniform::from(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When you only access the range containing valid data, you can use this unaligned size;
|
/// When you only access the range containing valid data, you can use this unaligned size;
|
||||||
/// otherwise, use the safer `size` method.
|
/// otherwise, use the safer `size` method.
|
||||||
pub fn unaligned_size<C: HasDataLayout>(&self, _cx: &C) -> Size {
|
pub fn unaligned_size<C: HasDataLayout>(&self, _cx: &C) -> Size {
|
||||||
// Prefix arguments are passed in specific designated registers
|
// Prefix arguments are passed in specific designated registers
|
||||||
let prefix_size = self
|
let prefix_size = if let Some(offset_from_start) = self.rest_offset {
|
||||||
.prefix
|
offset_from_start
|
||||||
|
} else {
|
||||||
|
self.prefix
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|x| x.map(|reg| reg.size))
|
.filter_map(|x| x.map(|reg| reg.size))
|
||||||
.fold(Size::ZERO, |acc, size| acc + size);
|
.fold(Size::ZERO, |acc, size| acc + size)
|
||||||
|
};
|
||||||
// Remaining arguments are passed in chunks of the unit size
|
// Remaining arguments are passed in chunks of the unit size
|
||||||
let rest_size =
|
let rest_size =
|
||||||
self.rest.unit.size * self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes());
|
self.rest.unit.size * self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes());
|
||||||
|
|
@ -322,9 +339,22 @@ impl CastTarget {
|
||||||
/// Checks if these two `CastTarget` are equal enough to be considered "the same for all
|
/// Checks if these two `CastTarget` are equal enough to be considered "the same for all
|
||||||
/// function call ABIs".
|
/// function call ABIs".
|
||||||
pub fn eq_abi(&self, other: &Self) -> bool {
|
pub fn eq_abi(&self, other: &Self) -> bool {
|
||||||
let CastTarget { prefix: prefix_l, rest: rest_l, attrs: attrs_l } = self;
|
let CastTarget {
|
||||||
let CastTarget { prefix: prefix_r, rest: rest_r, attrs: attrs_r } = other;
|
prefix: prefix_l,
|
||||||
prefix_l == prefix_r && rest_l == rest_r && attrs_l.eq_abi(attrs_r)
|
rest_offset: rest_offset_l,
|
||||||
|
rest: rest_l,
|
||||||
|
attrs: attrs_l,
|
||||||
|
} = self;
|
||||||
|
let CastTarget {
|
||||||
|
prefix: prefix_r,
|
||||||
|
rest_offset: rest_offset_r,
|
||||||
|
rest: rest_r,
|
||||||
|
attrs: attrs_r,
|
||||||
|
} = other;
|
||||||
|
prefix_l == prefix_r
|
||||||
|
&& rest_offset_l == rest_offset_r
|
||||||
|
&& rest_l == rest_r
|
||||||
|
&& attrs_l.eq_abi(attrs_r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use rustc_abi::{HasDataLayout, Reg, Size, TyAbiInterface};
|
use rustc_abi::{HasDataLayout, Reg, Size, TyAbiInterface};
|
||||||
|
|
||||||
use super::{ArgAttribute, ArgAttributes, ArgExtension, CastTarget};
|
use super::CastTarget;
|
||||||
use crate::callconv::{ArgAbi, FnAbi, Uniform};
|
use crate::callconv::{ArgAbi, FnAbi, Uniform};
|
||||||
|
|
||||||
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||||
|
|
@ -34,16 +34,10 @@ fn classify_aggregate<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if align_bytes == size.bytes() {
|
if align_bytes == size.bytes() {
|
||||||
arg.cast_to(CastTarget {
|
arg.cast_to(CastTarget::prefixed(
|
||||||
prefix: [Some(reg), None, None, None, None, None, None, None],
|
[Some(reg), None, None, None, None, None, None, None],
|
||||||
rest: Uniform::new(Reg::i8(), Size::from_bytes(0)),
|
Uniform::new(Reg::i8(), Size::ZERO),
|
||||||
attrs: ArgAttributes {
|
));
|
||||||
regular: ArgAttribute::default(),
|
|
||||||
arg_ext: ArgExtension::None,
|
|
||||||
pointee_size: Size::ZERO,
|
|
||||||
pointee_align: None,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
arg.cast_to(Uniform::new(reg, size));
|
arg.cast_to(Uniform::new(reg, size));
|
||||||
}
|
}
|
||||||
|
|
@ -78,11 +72,10 @@ where
|
||||||
};
|
};
|
||||||
if arg.layout.size.bytes() / align_bytes == 1 {
|
if arg.layout.size.bytes() / align_bytes == 1 {
|
||||||
// Make sure we pass the struct as array at the LLVM IR level and not as a single integer.
|
// Make sure we pass the struct as array at the LLVM IR level and not as a single integer.
|
||||||
arg.cast_to(CastTarget {
|
arg.cast_to(CastTarget::prefixed(
|
||||||
prefix: [Some(unit), None, None, None, None, None, None, None],
|
[Some(unit), None, None, None, None, None, None, None],
|
||||||
rest: Uniform::new(unit, Size::ZERO),
|
Uniform::new(unit, Size::ZERO),
|
||||||
attrs: ArgAttributes::new(),
|
));
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
arg.cast_to(Uniform::new(unit, arg.layout.size));
|
arg.cast_to(Uniform::new(unit, arg.layout.size));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,16 @@ use crate::spec::HasTargetSpec;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
enum RegPassKind {
|
enum RegPassKind {
|
||||||
Float(Reg),
|
Float { offset_from_start: Size, ty: Reg },
|
||||||
Integer(Reg),
|
Integer { offset_from_start: Size, ty: Reg },
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
enum FloatConv {
|
enum FloatConv {
|
||||||
FloatPair(Reg, Reg),
|
FloatPair { first_ty: Reg, second_ty_offset_from_start: Size, second_ty: Reg },
|
||||||
Float(Reg),
|
Float(Reg),
|
||||||
MixedPair(Reg, Reg),
|
MixedPair { first_ty: Reg, second_ty_offset_from_start: Size, second_ty: Reg },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
|
@ -43,6 +43,7 @@ fn should_use_fp_conv_helper<'a, Ty, C>(
|
||||||
flen: u64,
|
flen: u64,
|
||||||
field1_kind: &mut RegPassKind,
|
field1_kind: &mut RegPassKind,
|
||||||
field2_kind: &mut RegPassKind,
|
field2_kind: &mut RegPassKind,
|
||||||
|
offset_from_start: Size,
|
||||||
) -> Result<(), CannotUseFpConv>
|
) -> Result<(), CannotUseFpConv>
|
||||||
where
|
where
|
||||||
Ty: TyAbiInterface<'a, C> + Copy,
|
Ty: TyAbiInterface<'a, C> + Copy,
|
||||||
|
|
@ -55,16 +56,16 @@ where
|
||||||
}
|
}
|
||||||
match (*field1_kind, *field2_kind) {
|
match (*field1_kind, *field2_kind) {
|
||||||
(RegPassKind::Unknown, _) => {
|
(RegPassKind::Unknown, _) => {
|
||||||
*field1_kind = RegPassKind::Integer(Reg {
|
*field1_kind = RegPassKind::Integer {
|
||||||
kind: RegKind::Integer,
|
offset_from_start,
|
||||||
size: arg_layout.size,
|
ty: Reg { kind: RegKind::Integer, size: arg_layout.size },
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
(RegPassKind::Float(_), RegPassKind::Unknown) => {
|
(RegPassKind::Float { .. }, RegPassKind::Unknown) => {
|
||||||
*field2_kind = RegPassKind::Integer(Reg {
|
*field2_kind = RegPassKind::Integer {
|
||||||
kind: RegKind::Integer,
|
offset_from_start,
|
||||||
size: arg_layout.size,
|
ty: Reg { kind: RegKind::Integer, size: arg_layout.size },
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
_ => return Err(CannotUseFpConv),
|
_ => return Err(CannotUseFpConv),
|
||||||
}
|
}
|
||||||
|
|
@ -75,12 +76,16 @@ where
|
||||||
}
|
}
|
||||||
match (*field1_kind, *field2_kind) {
|
match (*field1_kind, *field2_kind) {
|
||||||
(RegPassKind::Unknown, _) => {
|
(RegPassKind::Unknown, _) => {
|
||||||
*field1_kind =
|
*field1_kind = RegPassKind::Float {
|
||||||
RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
|
offset_from_start,
|
||||||
|
ty: Reg { kind: RegKind::Float, size: arg_layout.size },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
(_, RegPassKind::Unknown) => {
|
(_, RegPassKind::Unknown) => {
|
||||||
*field2_kind =
|
*field2_kind = RegPassKind::Float {
|
||||||
RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
|
offset_from_start,
|
||||||
|
ty: Reg { kind: RegKind::Float, size: arg_layout.size },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
_ => return Err(CannotUseFpConv),
|
_ => return Err(CannotUseFpConv),
|
||||||
}
|
}
|
||||||
|
|
@ -102,13 +107,14 @@ where
|
||||||
flen,
|
flen,
|
||||||
field1_kind,
|
field1_kind,
|
||||||
field2_kind,
|
field2_kind,
|
||||||
|
offset_from_start,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Err(CannotUseFpConv);
|
return Err(CannotUseFpConv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FieldsShape::Array { count, .. } => {
|
FieldsShape::Array { count, .. } => {
|
||||||
for _ in 0..count {
|
for i in 0..count {
|
||||||
let elem_layout = arg_layout.field(cx, 0);
|
let elem_layout = arg_layout.field(cx, 0);
|
||||||
should_use_fp_conv_helper(
|
should_use_fp_conv_helper(
|
||||||
cx,
|
cx,
|
||||||
|
|
@ -117,6 +123,7 @@ where
|
||||||
flen,
|
flen,
|
||||||
field1_kind,
|
field1_kind,
|
||||||
field2_kind,
|
field2_kind,
|
||||||
|
offset_from_start + elem_layout.size * i,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -127,7 +134,15 @@ where
|
||||||
}
|
}
|
||||||
for i in arg_layout.fields.index_by_increasing_offset() {
|
for i in arg_layout.fields.index_by_increasing_offset() {
|
||||||
let field = arg_layout.field(cx, i);
|
let field = arg_layout.field(cx, i);
|
||||||
should_use_fp_conv_helper(cx, &field, xlen, flen, field1_kind, field2_kind)?;
|
should_use_fp_conv_helper(
|
||||||
|
cx,
|
||||||
|
&field,
|
||||||
|
xlen,
|
||||||
|
flen,
|
||||||
|
field1_kind,
|
||||||
|
field2_kind,
|
||||||
|
offset_from_start + arg_layout.fields.offset(i),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -146,14 +161,52 @@ where
|
||||||
{
|
{
|
||||||
let mut field1_kind = RegPassKind::Unknown;
|
let mut field1_kind = RegPassKind::Unknown;
|
||||||
let mut field2_kind = RegPassKind::Unknown;
|
let mut field2_kind = RegPassKind::Unknown;
|
||||||
if should_use_fp_conv_helper(cx, arg, xlen, flen, &mut field1_kind, &mut field2_kind).is_err() {
|
if should_use_fp_conv_helper(
|
||||||
|
cx,
|
||||||
|
arg,
|
||||||
|
xlen,
|
||||||
|
flen,
|
||||||
|
&mut field1_kind,
|
||||||
|
&mut field2_kind,
|
||||||
|
Size::ZERO,
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
match (field1_kind, field2_kind) {
|
match (field1_kind, field2_kind) {
|
||||||
(RegPassKind::Integer(l), RegPassKind::Float(r)) => Some(FloatConv::MixedPair(l, r)),
|
(
|
||||||
(RegPassKind::Float(l), RegPassKind::Integer(r)) => Some(FloatConv::MixedPair(l, r)),
|
RegPassKind::Integer { offset_from_start, .. }
|
||||||
(RegPassKind::Float(l), RegPassKind::Float(r)) => Some(FloatConv::FloatPair(l, r)),
|
| RegPassKind::Float { offset_from_start, .. },
|
||||||
(RegPassKind::Float(f), RegPassKind::Unknown) => Some(FloatConv::Float(f)),
|
_,
|
||||||
|
) if offset_from_start != Size::ZERO => {
|
||||||
|
panic!("type {:?} has a first field with non-zero offset {offset_from_start:?}", arg.ty)
|
||||||
|
}
|
||||||
|
(
|
||||||
|
RegPassKind::Integer { ty: first_ty, .. },
|
||||||
|
RegPassKind::Float { offset_from_start, ty: second_ty },
|
||||||
|
) => Some(FloatConv::MixedPair {
|
||||||
|
first_ty,
|
||||||
|
second_ty_offset_from_start: offset_from_start,
|
||||||
|
second_ty,
|
||||||
|
}),
|
||||||
|
(
|
||||||
|
RegPassKind::Float { ty: first_ty, .. },
|
||||||
|
RegPassKind::Integer { offset_from_start, ty: second_ty },
|
||||||
|
) => Some(FloatConv::MixedPair {
|
||||||
|
first_ty,
|
||||||
|
second_ty_offset_from_start: offset_from_start,
|
||||||
|
second_ty,
|
||||||
|
}),
|
||||||
|
(
|
||||||
|
RegPassKind::Float { ty: first_ty, .. },
|
||||||
|
RegPassKind::Float { offset_from_start, ty: second_ty },
|
||||||
|
) => Some(FloatConv::FloatPair {
|
||||||
|
first_ty,
|
||||||
|
second_ty_offset_from_start: offset_from_start,
|
||||||
|
second_ty,
|
||||||
|
}),
|
||||||
|
(RegPassKind::Float { ty, .. }, RegPassKind::Unknown) => Some(FloatConv::Float(ty)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -171,11 +224,19 @@ where
|
||||||
FloatConv::Float(f) => {
|
FloatConv::Float(f) => {
|
||||||
arg.cast_to(f);
|
arg.cast_to(f);
|
||||||
}
|
}
|
||||||
FloatConv::FloatPair(l, r) => {
|
FloatConv::FloatPair { first_ty, second_ty_offset_from_start, second_ty } => {
|
||||||
arg.cast_to(CastTarget::pair(l, r));
|
arg.cast_to(CastTarget::offset_pair(
|
||||||
|
first_ty,
|
||||||
|
second_ty_offset_from_start,
|
||||||
|
second_ty,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
FloatConv::MixedPair(l, r) => {
|
FloatConv::MixedPair { first_ty, second_ty_offset_from_start, second_ty } => {
|
||||||
arg.cast_to(CastTarget::pair(l, r));
|
arg.cast_to(CastTarget::offset_pair(
|
||||||
|
first_ty,
|
||||||
|
second_ty_offset_from_start,
|
||||||
|
second_ty,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -239,15 +300,27 @@ fn classify_arg<'a, Ty, C>(
|
||||||
arg.cast_to(f);
|
arg.cast_to(f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Some(FloatConv::FloatPair(l, r)) if *avail_fprs >= 2 => {
|
Some(FloatConv::FloatPair { first_ty, second_ty_offset_from_start, second_ty })
|
||||||
|
if *avail_fprs >= 2 =>
|
||||||
|
{
|
||||||
*avail_fprs -= 2;
|
*avail_fprs -= 2;
|
||||||
arg.cast_to(CastTarget::pair(l, r));
|
arg.cast_to(CastTarget::offset_pair(
|
||||||
|
first_ty,
|
||||||
|
second_ty_offset_from_start,
|
||||||
|
second_ty,
|
||||||
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Some(FloatConv::MixedPair(l, r)) if *avail_fprs >= 1 && *avail_gprs >= 1 => {
|
Some(FloatConv::MixedPair { first_ty, second_ty_offset_from_start, second_ty })
|
||||||
|
if *avail_fprs >= 1 && *avail_gprs >= 1 =>
|
||||||
|
{
|
||||||
*avail_gprs -= 1;
|
*avail_gprs -= 1;
|
||||||
*avail_fprs -= 1;
|
*avail_fprs -= 1;
|
||||||
arg.cast_to(CastTarget::pair(l, r));
|
arg.cast_to(CastTarget::offset_pair(
|
||||||
|
first_ty,
|
||||||
|
second_ty_offset_from_start,
|
||||||
|
second_ty,
|
||||||
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,7 @@ use rustc_abi::{
|
||||||
TyAndLayout,
|
TyAndLayout,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::callconv::{
|
use crate::callconv::{ArgAbi, ArgAttribute, CastTarget, FnAbi, Uniform};
|
||||||
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, Uniform,
|
|
||||||
};
|
|
||||||
use crate::spec::HasTargetSpec;
|
use crate::spec::HasTargetSpec;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -197,16 +195,10 @@ where
|
||||||
rest_size = rest_size - Reg::i32().size;
|
rest_size = rest_size - Reg::i32().size;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg.cast_to(CastTarget {
|
arg.cast_to(
|
||||||
prefix: data.prefix,
|
CastTarget::prefixed(data.prefix, Uniform::new(Reg::i64(), rest_size))
|
||||||
rest: Uniform::new(Reg::i64(), rest_size),
|
.with_attrs(data.arg_attribute.into()),
|
||||||
attrs: ArgAttributes {
|
);
|
||||||
regular: data.arg_attribute,
|
|
||||||
arg_ext: ArgExtension::None,
|
|
||||||
pointee_size: Size::ZERO,
|
|
||||||
pointee_align: None,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -842,9 +842,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||||
/// evaluating this entry would not have ended up depending on either a goal
|
/// evaluating this entry would not have ended up depending on either a goal
|
||||||
/// already on the stack or a provisional cache entry.
|
/// already on the stack or a provisional cache entry.
|
||||||
fn candidate_is_applicable(
|
fn candidate_is_applicable(
|
||||||
stack: &Stack<X>,
|
&self,
|
||||||
step_kind_from_parent: PathKind,
|
step_kind_from_parent: PathKind,
|
||||||
provisional_cache: &HashMap<X::Input, Vec<ProvisionalCacheEntry<X>>>,
|
|
||||||
nested_goals: &NestedGoals<X>,
|
nested_goals: &NestedGoals<X>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// If the global cache entry didn't depend on any nested goals, it always
|
// If the global cache entry didn't depend on any nested goals, it always
|
||||||
|
|
@ -855,7 +854,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||||
|
|
||||||
// If a nested goal of the global cache entry is on the stack, we would
|
// If a nested goal of the global cache entry is on the stack, we would
|
||||||
// definitely encounter a cycle.
|
// definitely encounter a cycle.
|
||||||
if stack.iter().any(|e| nested_goals.contains(e.input)) {
|
if self.stack.iter().any(|e| nested_goals.contains(e.input)) {
|
||||||
debug!("cache entry not applicable due to stack");
|
debug!("cache entry not applicable due to stack");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -864,7 +863,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||||
// would apply for any of its nested goals.
|
// would apply for any of its nested goals.
|
||||||
#[allow(rustc::potential_query_instability)]
|
#[allow(rustc::potential_query_instability)]
|
||||||
for (input, path_from_global_entry) in nested_goals.iter() {
|
for (input, path_from_global_entry) in nested_goals.iter() {
|
||||||
let Some(entries) = provisional_cache.get(&input) else {
|
let Some(entries) = self.provisional_cache.get(&input) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -890,7 +889,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||||
// We check if any of the paths taken while computing the global goal
|
// We check if any of the paths taken while computing the global goal
|
||||||
// would end up with an applicable provisional cache entry.
|
// would end up with an applicable provisional cache entry.
|
||||||
let head = heads.highest_cycle_head();
|
let head = heads.highest_cycle_head();
|
||||||
let head_to_curr = Self::cycle_path_kind(stack, step_kind_from_parent, head);
|
let head_to_curr = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head);
|
||||||
let full_paths = path_from_global_entry.extend_with(head_to_curr);
|
let full_paths = path_from_global_entry.extend_with(head_to_curr);
|
||||||
if full_paths.contains(head_to_provisional.into()) {
|
if full_paths.contains(head_to_provisional.into()) {
|
||||||
debug!(
|
debug!(
|
||||||
|
|
@ -918,12 +917,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||||
cx.with_global_cache(|cache| {
|
cx.with_global_cache(|cache| {
|
||||||
cache
|
cache
|
||||||
.get(cx, input, available_depth, |nested_goals| {
|
.get(cx, input, available_depth, |nested_goals| {
|
||||||
Self::candidate_is_applicable(
|
self.candidate_is_applicable(step_kind_from_parent, nested_goals)
|
||||||
&self.stack,
|
|
||||||
step_kind_from_parent,
|
|
||||||
&self.provisional_cache,
|
|
||||||
nested_goals,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.map(|c| c.result)
|
.map(|c| c.result)
|
||||||
})
|
})
|
||||||
|
|
@ -942,12 +936,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||||
cx.with_global_cache(|cache| {
|
cx.with_global_cache(|cache| {
|
||||||
let CacheData { result, required_depth, encountered_overflow, nested_goals } = cache
|
let CacheData { result, required_depth, encountered_overflow, nested_goals } = cache
|
||||||
.get(cx, input, available_depth, |nested_goals| {
|
.get(cx, input, available_depth, |nested_goals| {
|
||||||
Self::candidate_is_applicable(
|
self.candidate_is_applicable(step_kind_from_parent, nested_goals)
|
||||||
&self.stack,
|
|
||||||
step_kind_from_parent,
|
|
||||||
&self.provisional_cache,
|
|
||||||
nested_goals,
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// We don't move cycle participants to the global cache, so the
|
// We don't move cycle participants to the global cache, so the
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 6c882eb11984d737f62e85f36703effaf34c2453
|
Subproject commit b65ab935fb2e0d59dba8966ffca09c9cc5a5f57c
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
// FIXME: add wasm32-unknown when the wasm32-unknown-unknown ABI is fixed
|
//@ revisions: wasm32-unknown wasm64-unknown wasm32-wasip1
|
||||||
// see https://github.com/rust-lang/rust/issues/115666
|
|
||||||
//@ revisions: wasm64-unknown wasm32-wasip1
|
|
||||||
//@ add-core-stubs
|
//@ add-core-stubs
|
||||||
//@ assembly-output: emit-asm
|
//@ assembly-output: emit-asm
|
||||||
|
//@ [wasm32-unknown] compile-flags: --target wasm32-unknown-unknown
|
||||||
//@ [wasm64-unknown] compile-flags: --target wasm64-unknown-unknown
|
//@ [wasm64-unknown] compile-flags: --target wasm64-unknown-unknown
|
||||||
//@ [wasm32-wasip1] compile-flags: --target wasm32-wasip1
|
//@ [wasm32-wasip1] compile-flags: --target wasm32-wasip1
|
||||||
|
//@ [wasm32-unknown] needs-llvm-components: webassembly
|
||||||
//@ [wasm64-unknown] needs-llvm-components: webassembly
|
//@ [wasm64-unknown] needs-llvm-components: webassembly
|
||||||
//@ [wasm32-wasip1] needs-llvm-components: webassembly
|
//@ [wasm32-wasip1] needs-llvm-components: webassembly
|
||||||
|
|
||||||
|
|
@ -97,6 +97,7 @@ extern "C" fn fn_i64_i64(num: i64) -> i64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK-LABEL: fn_i128_i128:
|
// CHECK-LABEL: fn_i128_i128:
|
||||||
|
// wasm32-unknown: .functype fn_i128_i128 (i32, i64, i64) -> ()
|
||||||
// wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> ()
|
// wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> ()
|
||||||
// wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> ()
|
// wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> ()
|
||||||
#[allow(improper_ctypes_definitions)]
|
#[allow(improper_ctypes_definitions)]
|
||||||
|
|
@ -114,6 +115,7 @@ extern "C" fn fn_i128_i128(num: i128) -> i128 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK-LABEL: fn_f128_f128:
|
// CHECK-LABEL: fn_f128_f128:
|
||||||
|
// wasm32-unknown: .functype fn_f128_f128 (i32, i64, i64) -> ()
|
||||||
// wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> ()
|
// wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> ()
|
||||||
// wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> ()
|
// wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> ()
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
@ -136,6 +138,7 @@ struct Compound {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK-LABEL: fn_compound_compound:
|
// CHECK-LABEL: fn_compound_compound:
|
||||||
|
// wasm32-unknown: .functype fn_compound_compound (i32, i32) -> ()
|
||||||
// wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> ()
|
// wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> ()
|
||||||
// wasm64-unknown: .functype fn_compound_compound (i64, i64) -> ()
|
// wasm64-unknown: .functype fn_compound_compound (i64, i64) -> ()
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
||||||
177
tests/assembly/riscv-float-struct-abi.rs
Normal file
177
tests/assembly/riscv-float-struct-abi.rs
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
//@ add-core-stubs
|
||||||
|
//@ assembly-output: emit-asm
|
||||||
|
//@ compile-flags: -Copt-level=3 --target riscv64gc-unknown-linux-gnu
|
||||||
|
//@ needs-llvm-components: riscv
|
||||||
|
|
||||||
|
#![feature(no_core, lang_items)]
|
||||||
|
#![no_std]
|
||||||
|
#![no_core]
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
extern crate minicore;
|
||||||
|
use minicore::*;
|
||||||
|
|
||||||
|
#[repr(C, align(64))]
|
||||||
|
struct Aligned(f64);
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct Padded(u8, Aligned);
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
struct Packed(u8, f32);
|
||||||
|
|
||||||
|
impl Copy for Aligned {}
|
||||||
|
impl Copy for Padded {}
|
||||||
|
impl Copy for Packed {}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn take_padded(x: Padded);
|
||||||
|
fn get_padded() -> Padded;
|
||||||
|
fn take_packed(x: Packed);
|
||||||
|
fn get_packed() -> Packed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: pass_padded
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn pass_padded(out: &mut Padded, x: Padded) {
|
||||||
|
// CHECK: sb a1, 0(a0)
|
||||||
|
// CHECK-NEXT: fsd fa0, 64(a0)
|
||||||
|
// CHECK-NEXT: ret
|
||||||
|
*out = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: ret_padded
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn ret_padded(x: &Padded) -> Padded {
|
||||||
|
// CHECK: fld fa0, 64(a0)
|
||||||
|
// CHECK-NEXT: lbu a0, 0(a0)
|
||||||
|
// CHECK-NEXT: ret
|
||||||
|
*x
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn call_padded(x: &Padded) {
|
||||||
|
// CHECK: fld fa0, 64(a0)
|
||||||
|
// CHECK-NEXT: lbu a0, 0(a0)
|
||||||
|
// CHECK-NEXT: tail take_padded
|
||||||
|
unsafe {
|
||||||
|
take_padded(*x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn receive_padded(out: &mut Padded) {
|
||||||
|
// CHECK: addi sp, sp, -16
|
||||||
|
// CHECK-NEXT: .cfi_def_cfa_offset 16
|
||||||
|
// CHECK-NEXT: sd ra, [[#%d,RA_SPILL:]](sp)
|
||||||
|
// CHECK-NEXT: sd [[TEMP:.*]], [[#%d,TEMP_SPILL:]](sp)
|
||||||
|
// CHECK-NEXT: .cfi_offset ra, [[#%d,RA_SPILL - 16]]
|
||||||
|
// CHECK-NEXT: .cfi_offset [[TEMP]], [[#%d,TEMP_SPILL - 16]]
|
||||||
|
// CHECK-NEXT: mv [[TEMP]], a0
|
||||||
|
// CHECK-NEXT: call get_padded
|
||||||
|
// CHECK-NEXT: sb a0, 0([[TEMP]])
|
||||||
|
// CHECK-NEXT: fsd fa0, 64([[TEMP]])
|
||||||
|
// CHECK-NEXT: ld ra, [[#%d,RA_SPILL]](sp)
|
||||||
|
// CHECK-NEXT: ld [[TEMP]], [[#%d,TEMP_SPILL]](sp)
|
||||||
|
// CHECK: addi sp, sp, 16
|
||||||
|
// CHECK: ret
|
||||||
|
unsafe {
|
||||||
|
*out = get_padded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: pass_packed
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn pass_packed(out: &mut Packed, x: Packed) {
|
||||||
|
// CHECK: addi sp, sp, -16
|
||||||
|
// CHECK-NEXT: .cfi_def_cfa_offset 16
|
||||||
|
// CHECK-NEXT: sb a1, 0(a0)
|
||||||
|
// CHECK-NEXT: fsw fa0, 8(sp)
|
||||||
|
// CHECK-NEXT: lw [[VALUE:.*]], 8(sp)
|
||||||
|
// CHECK-DAG: srli [[BYTE4:.*]], [[VALUE]], 24
|
||||||
|
// CHECK-DAG: srli [[BYTE3:.*]], [[VALUE]], 16
|
||||||
|
// CHECK-DAG: srli [[BYTE2:.*]], [[VALUE]], 8
|
||||||
|
// CHECK-DAG: sb [[VALUE]], 1(a0)
|
||||||
|
// CHECK-DAG: sb [[BYTE2]], 2(a0)
|
||||||
|
// CHECK-DAG: sb [[BYTE3]], 3(a0)
|
||||||
|
// CHECK-DAG: sb [[BYTE4]], 4(a0)
|
||||||
|
// CHECK-NEXT: addi sp, sp, 16
|
||||||
|
// CHECK: ret
|
||||||
|
*out = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: ret_packed
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn ret_packed(x: &Packed) -> Packed {
|
||||||
|
// CHECK: addi sp, sp, -16
|
||||||
|
// CHECK-NEXT: .cfi_def_cfa_offset 16
|
||||||
|
// CHECK-NEXT: lbu [[BYTE2:.*]], 2(a0)
|
||||||
|
// CHECK-NEXT: lbu [[BYTE1:.*]], 1(a0)
|
||||||
|
// CHECK-NEXT: lbu [[BYTE3:.*]], 3(a0)
|
||||||
|
// CHECK-NEXT: lbu [[BYTE4:.*]], 4(a0)
|
||||||
|
// CHECK-NEXT: slli [[SHIFTED2:.*]], [[BYTE2]], 8
|
||||||
|
// CHECK-NEXT: or [[BYTE12:.*]], [[SHIFTED2]], [[BYTE1]]
|
||||||
|
// CHECK-NEXT: slli [[SHIFTED3:.*]], [[BYTE3]], 16
|
||||||
|
// CHECK-NEXT: slli [[SHIFTED4:.*]], [[BYTE4]], 24
|
||||||
|
// CHECK-NEXT: or [[BYTE34:.*]], [[SHIFTED3]], [[SHIFTED4]]
|
||||||
|
// CHECK-NEXT: or [[VALUE:.*]], [[BYTE12]], [[BYTE34]]
|
||||||
|
// CHECK-NEXT: sw [[VALUE]], 8(sp)
|
||||||
|
// CHECK-NEXT: flw fa0, 8(sp)
|
||||||
|
// CHECK-NEXT: lbu a0, 0(a0)
|
||||||
|
// CHECK-NEXT: addi sp, sp, 16
|
||||||
|
// CHECK: ret
|
||||||
|
*x
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn call_packed(x: &Packed) {
|
||||||
|
// CHECK: addi sp, sp, -16
|
||||||
|
// CHECK-NEXT: .cfi_def_cfa_offset 16
|
||||||
|
// CHECK-NEXT: lbu [[BYTE2:.*]], 2(a0)
|
||||||
|
// CHECK-NEXT: lbu [[BYTE1:.*]], 1(a0)
|
||||||
|
// CHECK-NEXT: lbu [[BYTE3:.*]], 3(a0)
|
||||||
|
// CHECK-NEXT: lbu [[BYTE4:.*]], 4(a0)
|
||||||
|
// CHECK-NEXT: slli [[SHIFTED2:.*]], [[BYTE2]], 8
|
||||||
|
// CHECK-NEXT: or [[BYTE12:.*]], [[SHIFTED2]], [[BYTE1]]
|
||||||
|
// CHECK-NEXT: slli [[SHIFTED3:.*]], [[BYTE3]], 16
|
||||||
|
// CHECK-NEXT: slli [[SHIFTED4:.*]], [[BYTE4]], 24
|
||||||
|
// CHECK-NEXT: or [[BYTE34:.*]], [[SHIFTED3]], [[SHIFTED4]]
|
||||||
|
// CHECK-NEXT: or [[VALUE:.*]], [[BYTE12]], [[BYTE34]]
|
||||||
|
// CHECK-NEXT: sw [[VALUE]], 8(sp)
|
||||||
|
// CHECK-NEXT: flw fa0, 8(sp)
|
||||||
|
// CHECK-NEXT: lbu a0, 0(a0)
|
||||||
|
// CHECK-NEXT: addi sp, sp, 16
|
||||||
|
// CHECK: tail take_packed
|
||||||
|
unsafe {
|
||||||
|
take_packed(*x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn receive_packed(out: &mut Packed) {
|
||||||
|
// CHECK: addi sp, sp, -32
|
||||||
|
// CHECK-NEXT: .cfi_def_cfa_offset 32
|
||||||
|
// CHECK-NEXT: sd ra, [[#%d,RA_SPILL:]](sp)
|
||||||
|
// CHECK-NEXT: sd [[TEMP:.*]], [[#%d,TEMP_SPILL:]](sp)
|
||||||
|
// CHECK-NEXT: .cfi_offset ra, [[#%d,RA_SPILL - 32]]
|
||||||
|
// CHECK-NEXT: .cfi_offset [[TEMP]], [[#%d,TEMP_SPILL - 32]]
|
||||||
|
// CHECK-NEXT: mv [[TEMP]], a0
|
||||||
|
// CHECK-NEXT: call get_packed
|
||||||
|
// CHECK-NEXT: sb a0, 0([[TEMP]])
|
||||||
|
// CHECK-NEXT: fsw fa0, [[FLOAT_SPILL:.*]](sp)
|
||||||
|
// CHECK-NEXT: lw [[VALUE:.*]], [[FLOAT_SPILL]](sp)
|
||||||
|
// CHECK-DAG: srli [[BYTE4:.*]], [[VALUE]], 24
|
||||||
|
// CHECK-DAG: srli [[BYTE3:.*]], [[VALUE]], 16
|
||||||
|
// CHECK-DAG: srli [[BYTE2:.*]], [[VALUE]], 8
|
||||||
|
// CHECK-DAG: sb [[VALUE]], 1([[TEMP]])
|
||||||
|
// CHECK-DAG: sb [[BYTE2]], 2([[TEMP]])
|
||||||
|
// CHECK-DAG: sb [[BYTE3]], 3([[TEMP]])
|
||||||
|
// CHECK-DAG: sb [[BYTE4]], 4([[TEMP]])
|
||||||
|
// CHECK-NEXT: ld ra, [[#%d,RA_SPILL]](sp)
|
||||||
|
// CHECK-NEXT: ld [[TEMP]], [[#%d,TEMP_SPILL]](sp)
|
||||||
|
// CHECK: addi sp, sp, 32
|
||||||
|
// CHECK: ret
|
||||||
|
unsafe {
|
||||||
|
*out = get_packed();
|
||||||
|
}
|
||||||
|
}
|
||||||
44
tests/codegen/riscv-abi/cast-local-large-enough.rs
Normal file
44
tests/codegen/riscv-abi/cast-local-large-enough.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
//@ add-core-stubs
|
||||||
|
//@ compile-flags: -Copt-level=0 -Cdebuginfo=0 --target riscv64gc-unknown-linux-gnu
|
||||||
|
//@ needs-llvm-components: riscv
|
||||||
|
|
||||||
|
#![feature(no_core, lang_items)]
|
||||||
|
#![no_std]
|
||||||
|
#![no_core]
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
extern crate minicore;
|
||||||
|
use minicore::*;
|
||||||
|
|
||||||
|
#[repr(C, align(64))]
|
||||||
|
struct Aligned(f64);
|
||||||
|
|
||||||
|
#[repr(C, align(64))]
|
||||||
|
struct AlignedPair(f32, f64);
|
||||||
|
|
||||||
|
impl Copy for Aligned {}
|
||||||
|
impl Copy for AlignedPair {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: define double @read_aligned
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn read_aligned(x: &Aligned) -> Aligned {
|
||||||
|
// CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64
|
||||||
|
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false)
|
||||||
|
// CHECK-NEXT: %[[RES:.*]] = load double, ptr %[[TEMP]], align 64
|
||||||
|
// CHECK-NEXT: ret double %[[RES]]
|
||||||
|
*x
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: define { float, double } @read_aligned_pair
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn read_aligned_pair(x: &AlignedPair) -> AlignedPair {
|
||||||
|
// CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64
|
||||||
|
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false)
|
||||||
|
// CHECK-NEXT: %[[FIRST:.*]] = load float, ptr %[[TEMP]], align 64
|
||||||
|
// CHECK-NEXT: %[[SECOND_PTR:.*]] = getelementptr inbounds i8, ptr %[[TEMP]], i64 8
|
||||||
|
// CHECK-NEXT: %[[SECOND:.*]] = load double, ptr %[[SECOND_PTR]], align 8
|
||||||
|
// CHECK-NEXT: %[[RES1:.*]] = insertvalue { float, double } poison, float %[[FIRST]], 0
|
||||||
|
// CHECK-NEXT: %[[RES2:.*]] = insertvalue { float, double } %[[RES1]], double %[[SECOND]], 1
|
||||||
|
// CHECK-NEXT: ret { float, double } %[[RES2]]
|
||||||
|
*x
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
// ignore-tidy-linelength
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
// Check that the `CURRENT_RUSTC_VERSION` placeholder is correctly replaced by the current
|
// Check that the `CURRENT_RUSTC_VERSION` placeholder is correctly replaced by the current
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
// Test that `-Awarnings` suppresses warnings for unstable APIs.
|
// Test that `-Awarnings` suppresses warnings for unstable APIs.
|
||||||
|
|
||||||
use run_make_support::rustc;
|
use run_make_support::rustc;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// emitting an object file is not necessary if user didn't ask for one
|
// emitting an object file is not necessary if user didn't ask for one
|
||||||
//
|
//
|
||||||
// This test is similar to run-make/artifact-incr-cache but it doesn't
|
// This test is similar to run-make/artifact-incr-cache but it doesn't
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// rustc should be able to emit required files (asm, llvm-*, etc) during incremental
|
// rustc should be able to emit required files (asm, llvm-*, etc) during incremental
|
||||||
// compilation on the first pass by running the code gen as well as on subsequent runs -
|
// compilation on the first pass by running the code gen as well as on subsequent runs -
|
||||||
// extracting them from the cache
|
// extracting them from the cache
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// When setting the crate type as a "bin" (in app.rs),
|
// When setting the crate type as a "bin" (in app.rs),
|
||||||
// this could cause a bug where some symbols would not be
|
// this could cause a bug where some symbols would not be
|
||||||
// emitted in the object files. This has been fixed, and
|
// emitted in the object files. This has been fixed, and
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// The crate "foo" tied to this test executes a very specific function,
|
// The crate "foo" tied to this test executes a very specific function,
|
||||||
// which involves boxing an instance of the struct Foo. However,
|
// which involves boxing an instance of the struct Foo. However,
|
||||||
// this once caused a segmentation fault in cargo release builds due to an LLVM
|
// this once caused a segmentation fault in cargo release builds due to an LLVM
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
use run_make_support::{rfs, rustc};
|
use run_make_support::{rfs, rustc};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// This test checks that extern crate declarations in Cargo without a corresponding declaration
|
// This test checks that extern crate declarations in Cargo without a corresponding declaration
|
||||||
// in the manifest of a dependency are NOT allowed. The last rustc call does it anyways, which
|
// in the manifest of a dependency are NOT allowed. The last rustc call does it anyways, which
|
||||||
// should result in a compilation failure.
|
// should result in a compilation failure.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Since #19941, rustc can accept specifications on its library search paths.
|
// Since #19941, rustc can accept specifications on its library search paths.
|
||||||
// This test runs Rust programs with varied library dependencies, expecting them
|
// This test runs Rust programs with varied library dependencies, expecting them
|
||||||
// to succeed or fail depending on the situation.
|
// to succeed or fail depending on the situation.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Test output of const super trait errors in both stable and nightly.
|
// Test output of const super trait errors in both stable and nightly.
|
||||||
// We don't want to provide suggestions on stable that only make sense in nightly.
|
// We don't want to provide suggestions on stable that only make sense in nightly.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Test that previously triggered a linker failure with root cause
|
// Test that previously triggered a linker failure with root cause
|
||||||
// similar to one found in the issue #69368.
|
// similar to one found in the issue #69368.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// When using the flag -C linker-plugin-lto, static libraries could lose their upstream object
|
// When using the flag -C linker-plugin-lto, static libraries could lose their upstream object
|
||||||
// files during compilation. This bug was fixed in #53031, and this test compiles a staticlib
|
// files during compilation. This bug was fixed in #53031, and this test compiles a staticlib
|
||||||
// dependent on upstream, checking that the upstream object file still exists after no LTO and
|
// dependent on upstream, checking that the upstream object file still exists after no LTO and
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// This test checks that the object files we generate are actually
|
// This test checks that the object files we generate are actually
|
||||||
// LLVM bitcode files (as used by linker LTO plugins) when compiling with
|
// LLVM bitcode files (as used by linker LTO plugins) when compiling with
|
||||||
// -Clinker-plugin-lto.
|
// -Clinker-plugin-lto.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// This test checks that files referenced via #[debugger_visualizer] are
|
// This test checks that files referenced via #[debugger_visualizer] are
|
||||||
// included in `--emit dep-info` output.
|
// included in `--emit dep-info` output.
|
||||||
// See https://github.com/rust-lang/rust/pull/111641
|
// See https://github.com/rust-lang/rust/pull/111641
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// This is a simple smoke test for rustc's `--emit dep-info` feature. It prints out
|
// This is a simple smoke test for rustc's `--emit dep-info` feature. It prints out
|
||||||
// information about dependencies in a Makefile-compatible format, as a `.d` file.
|
// information about dependencies in a Makefile-compatible format, as a `.d` file.
|
||||||
// Note that this test does not check that the `.d` file is Makefile-compatible.
|
// Note that this test does not check that the `.d` file is Makefile-compatible.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Non-regression test for issue #132920 where multiple versions of the same crate are present in
|
// Non-regression test for issue #132920 where multiple versions of the same crate are present in
|
||||||
// the dependency graph, and an unexpected error in a dependent crate caused an ICE in the
|
// the dependency graph, and an unexpected error in a dependent crate caused an ICE in the
|
||||||
// unsatisfied bounds diagnostics for traits present in multiple crate versions.
|
// unsatisfied bounds diagnostics for traits present in multiple crate versions.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use run_make_support::{cwd, diff, rustc, rustdoc};
|
use run_make_support::{cwd, diff, rustc, rustdoc};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Tests behavior of rustdoc `--test-runtool`.
|
// Tests behavior of rustdoc `--test-runtool`.
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// A flag named dump-mono-stats was added to the compiler in 2022, which
|
// A flag named dump-mono-stats was added to the compiler in 2022, which
|
||||||
// collects stats on instantiation of items and their associated costs.
|
// collects stats on instantiation of items and their associated costs.
|
||||||
// This test checks that the output stat file exists, and that it contains
|
// This test checks that the output stat file exists, and that it contains
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
use run_make_support::rustc;
|
use run_make_support::rustc;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Tests the -Zembed-metadata compiler flag.
|
// Tests the -Zembed-metadata compiler flag.
|
||||||
// Tracking issue: https://github.com/rust-lang/rust/issues/139165
|
// Tracking issue: https://github.com/rust-lang/rust/issues/139165
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
//@ ignore-windows
|
//@ ignore-windows
|
||||||
//@ ignore-apple
|
//@ ignore-apple
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use run_make_support::{rfs, rustc};
|
use run_make_support::{rfs, rustc};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Specifying how rustc outputs a file can be done in different ways, such as
|
// Specifying how rustc outputs a file can be done in different ways, such as
|
||||||
// the output flag or the KIND=NAME syntax. However, some of these methods used
|
// the output flag or the KIND=NAME syntax. However, some of these methods used
|
||||||
// to result in different hashes on output files even though they yielded the
|
// to result in different hashes on output files even though they yielded the
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
// this diagnostics information should be located.
|
// this diagnostics information should be located.
|
||||||
// See https://github.com/rust-lang/rust/pull/51946
|
// See https://github.com/rust-lang/rust/pull/51946
|
||||||
|
|
||||||
|
//@ needs-target-std
|
||||||
//@ ignore-windows
|
//@ ignore-windows
|
||||||
//@ ignore-apple
|
//@ ignore-apple
|
||||||
// Reason: this feature only works when the output object format is ELF.
|
// Reason: this feature only works when the output object format is ELF.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
//! If `-o -` or `--emit KIND=-` is provided, output should be written to stdout
|
//! If `-o -` or `--emit KIND=-` is provided, output should be written to stdout
|
||||||
//! instead. Binary output (`obj`, `llvm-bc`, `link` and `metadata`)
|
//! instead. Binary output (`obj`, `llvm-bc`, `link` and `metadata`)
|
||||||
//! being written this way will result in an error if stdout is a tty.
|
//! being written this way will result in an error if stdout is a tty.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Inside dep-info emit files, #71858 made it so all accessed environment
|
// Inside dep-info emit files, #71858 made it so all accessed environment
|
||||||
// variables are usefully printed. This test checks that this feature works
|
// variables are usefully printed. This test checks that this feature works
|
||||||
// as intended by checking if the environment variables used in compilation
|
// as intended by checking if the environment variables used in compilation
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// When rustc is looking for a crate but is given a staticlib instead,
|
// When rustc is looking for a crate but is given a staticlib instead,
|
||||||
// the error message should be helpful and indicate precisely the cause
|
// the error message should be helpful and indicate precisely the cause
|
||||||
// of the compilation failure.
|
// of the compilation failure.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Test that we exit with the correct exit code for successful / unsuccessful / ICE compilations
|
// Test that we exit with the correct exit code for successful / unsuccessful / ICE compilations
|
||||||
|
|
||||||
use run_make_support::{rustc, rustdoc};
|
use run_make_support::{rustc, rustdoc};
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
|
//@ needs-target-std
|
||||||
use run_make_support::rustc;
|
use run_make_support::rustc;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
rustc()
|
rustc().env("RUSTC_FORCE_RUSTC_VERSION", "1").input("libr.rs").run();
|
||||||
.env("RUSTC_FORCE_RUSTC_VERSION", "1")
|
rustc().env("RUSTC_FORCE_RUSTC_VERSION", "2").input("app.rs").run();
|
||||||
.input("libr.rs")
|
|
||||||
.run();
|
|
||||||
rustc()
|
|
||||||
.env("RUSTC_FORCE_RUSTC_VERSION", "2")
|
|
||||||
.input("app.rs")
|
|
||||||
.run();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
use run_make_support::{rustc, dynamic_lib_name};
|
//@ needs-target-std
|
||||||
|
use run_make_support::{dynamic_lib_name, rustc};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
rustc()
|
rustc().env("RUSTC_FORCE_RUSTC_VERSION", "1").input("libr.rs").run();
|
||||||
.env("RUSTC_FORCE_RUSTC_VERSION", "1")
|
|
||||||
.input("libr.rs")
|
|
||||||
.run();
|
|
||||||
|
|
||||||
rustc()
|
rustc()
|
||||||
.env("RUSTC_FORCE_RUSTC_VERSION", "2")
|
.env("RUSTC_FORCE_RUSTC_VERSION", "2")
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
|
//@ needs-target-std
|
||||||
use run_make_support::rustc;
|
use run_make_support::rustc;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
rustc()
|
rustc().env("RUSTC_FORCE_RUSTC_VERSION", "1").input("libr.rs").run();
|
||||||
.env("RUSTC_FORCE_RUSTC_VERSION", "1")
|
rustc().env("RUSTC_FORCE_RUSTC_VERSION", "2").input("app.rs").run();
|
||||||
.input("libr.rs")
|
|
||||||
.run();
|
|
||||||
rustc()
|
|
||||||
.env("RUSTC_FORCE_RUSTC_VERSION", "2")
|
|
||||||
.input("app.rs")
|
|
||||||
.run();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// In the following scenario:
|
// In the following scenario:
|
||||||
// 1. The crate foo, is referenced multiple times
|
// 1. The crate foo, is referenced multiple times
|
||||||
// 2. --extern foo=./path/to/libbar.rlib is specified to rustc
|
// 2. --extern foo=./path/to/libbar.rlib is specified to rustc
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// The --extern flag can override the default crate search of
|
// The --extern flag can override the default crate search of
|
||||||
// the compiler and directly fetch a given path. There are a few rules
|
// the compiler and directly fetch a given path. There are a few rules
|
||||||
// to follow: for example, there can't be more than one rlib, the crates must
|
// to follow: for example, there can't be more than one rlib, the crates must
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// In this test, baz.rs is looking for an extern crate "a" which
|
// In this test, baz.rs is looking for an extern crate "a" which
|
||||||
// does not exist, and can only run through the --extern rustc flag
|
// does not exist, and can only run through the --extern rustc flag
|
||||||
// defining that the "a" crate is in fact just "foo". This test
|
// defining that the "a" crate is in fact just "foo". This test
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// In this test, the rust library foo1 exists in two different locations, but only one
|
// In this test, the rust library foo1 exists in two different locations, but only one
|
||||||
// is required by the --extern flag. This test checks that the copy is ignored (as --extern
|
// is required by the --extern flag. This test checks that the copy is ignored (as --extern
|
||||||
// demands fetching only the original instance of foo1) and that no error is emitted, resulting
|
// demands fetching only the original instance of foo1) and that no error is emitted, resulting
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Almost identical to `extern-multiple-copies`, but with a variation in the --extern calls
|
// Almost identical to `extern-multiple-copies`, but with a variation in the --extern calls
|
||||||
// and the addition of #[macro_use] in the rust code files, which used to break --extern
|
// and the addition of #[macro_use] in the rust code files, which used to break --extern
|
||||||
// until #33625.
|
// until #33625.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Trying to access mid-level internal representation (MIR) in statics
|
// Trying to access mid-level internal representation (MIR) in statics
|
||||||
// used to cause an internal compiler error (ICE), now handled as a proper
|
// used to cause an internal compiler error (ICE), now handled as a proper
|
||||||
// error since #100211. This test checks that the correct error is printed
|
// error since #100211. This test checks that the correct error is printed
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
// See https://github.com/rust-lang/rust/pull/95604
|
// See https://github.com/rust-lang/rust/pull/95604
|
||||||
// See https://github.com/rust-lang/rust/issues/47384
|
// See https://github.com/rust-lang/rust/issues/47384
|
||||||
|
|
||||||
|
//@ needs-target-std
|
||||||
//@ ignore-wasm differences in object file formats causes errors in the llvm_objdump step.
|
//@ ignore-wasm differences in object file formats causes errors in the llvm_objdump step.
|
||||||
//@ ignore-windows differences in object file formats causes errors in the llvm_objdump step.
|
//@ ignore-windows differences in object file formats causes errors in the llvm_objdump step.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// include_bytes! and include_str! in `main.rs`
|
// include_bytes! and include_str! in `main.rs`
|
||||||
// should register the included file as of #24423,
|
// should register the included file as of #24423,
|
||||||
// and this test checks that this is still the case.
|
// and this test checks that this is still the case.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// This test ensures that changes to files referenced via #[debugger_visualizer]
|
// This test ensures that changes to files referenced via #[debugger_visualizer]
|
||||||
// (in this case, foo.py and foo.natvis) are picked up when compiling incrementally.
|
// (in this case, foo.py and foo.natvis) are picked up when compiling incrementally.
|
||||||
// See https://github.com/rust-lang/rust/pull/111641
|
// See https://github.com/rust-lang/rust/pull/111641
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
use run_make_support::regex::Regex;
|
use run_make_support::regex::Regex;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// When a fake library was given to the compiler, it would
|
// When a fake library was given to the compiler, it would
|
||||||
// result in an obscure and unhelpful error message. This test
|
// result in an obscure and unhelpful error message. This test
|
||||||
// creates a false "foo" dylib, and checks that the standard error
|
// creates a false "foo" dylib, and checks that the standard error
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// If the static library provided is not valid (in this test,
|
// If the static library provided is not valid (in this test,
|
||||||
// created as an empty file),
|
// created as an empty file),
|
||||||
// rustc should print a normal error message and not throw
|
// rustc should print a normal error message and not throw
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
//
|
//
|
||||||
// See https://github.com/rust-lang/rust/issues/26006
|
// See https://github.com/rust-lang/rust/issues/26006
|
||||||
|
|
||||||
|
//@ needs-target-std
|
||||||
//@ needs-symlink
|
//@ needs-symlink
|
||||||
//Reason: symlink requires elevated permission in Windows
|
//Reason: symlink requires elevated permission in Windows
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// When the TMP (on Windows) or TMPDIR (on Unix) variable is set to an invalid
|
// When the TMP (on Windows) or TMPDIR (on Unix) variable is set to an invalid
|
||||||
// or non-existing directory, this used to cause an internal compiler error (ICE). After the
|
// or non-existing directory, this used to cause an internal compiler error (ICE). After the
|
||||||
// addition of proper error handling in #28430, this test checks that the expected message is
|
// addition of proper error handling in #28430, this test checks that the expected message is
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Non-regression test for issues #125474, #125484, #125646, with the repro taken from #125484. Some
|
// Non-regression test for issues #125474, #125484, #125646, with the repro taken from #125484. Some
|
||||||
// queries use "used dependencies" while others use "speculatively loaded dependencies", and an
|
// queries use "used dependencies" while others use "speculatively loaded dependencies", and an
|
||||||
// indexing ICE appeared in some cases when these were unexpectedly used in the same context.
|
// indexing ICE appeared in some cases when these were unexpectedly used in the same context.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// The byte positions in json format error logging used to have a small, difficult
|
// The byte positions in json format error logging used to have a small, difficult
|
||||||
// to predict offset. This was changed to be the top of the file every time in #42973,
|
// to predict offset. This was changed to be the top of the file every time in #42973,
|
||||||
// and this test checks that the measurements appearing in the standard error are correct.
|
// and this test checks that the measurements appearing in the standard error are correct.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Inside a library, implementing a trait for another trait
|
// Inside a library, implementing a trait for another trait
|
||||||
// with a lifetime used to cause an internal compiler error (ICE).
|
// with a lifetime used to cause an internal compiler error (ICE).
|
||||||
// This test checks that this bug does not make a resurgence -
|
// This test checks that this bug does not make a resurgence -
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// In 2016, the rustc flag "-C link-arg" was introduced - it can be repeatedly used
|
// In 2016, the rustc flag "-C link-arg" was introduced - it can be repeatedly used
|
||||||
// to add single arguments to the linker. This test passes 2 arguments to the linker using it,
|
// to add single arguments to the linker. This test passes 2 arguments to the linker using it,
|
||||||
// then checks that the compiler's output contains the arguments passed to it.
|
// then checks that the compiler's output contains the arguments passed to it.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Passing linker arguments to the compiler used to be lost or reordered in a messy way
|
// Passing linker arguments to the compiler used to be lost or reordered in a messy way
|
||||||
// as they were passed further to the linker. This was fixed in #70665, and this test
|
// as they were passed further to the linker. This was fixed in #70665, and this test
|
||||||
// checks that linker arguments remain intact and in the order they were originally passed in.
|
// checks that linker arguments remain intact and in the order they were originally passed in.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// When native libraries are passed to the linker, there used to be an annoyance
|
// When native libraries are passed to the linker, there used to be an annoyance
|
||||||
// where multiple instances of the same library in a row would cause duplication in
|
// where multiple instances of the same library in a row would cause duplication in
|
||||||
// outputs. This has been fixed, and this test checks that it stays fixed.
|
// outputs. This has been fixed, and this test checks that it stays fixed.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
use run_make_support::{Rustc, diff, regex, rustc};
|
use run_make_support::{Rustc, diff, regex, rustc};
|
||||||
|
|
||||||
fn run_rustc() -> Rustc {
|
fn run_rustc() -> Rustc {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
// test that directories get created when emitting llvm bitcode and IR
|
// test that directories get created when emitting llvm bitcode and IR
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
// This test makes sure that functions defined in the upstream crates do not
|
// This test makes sure that functions defined in the upstream crates do not
|
||||||
// appear twice in the final staticlib when listing all the symbols from it.
|
// appear twice in the final staticlib when listing all the symbols from it.
|
||||||
|
|
||||||
|
//@ needs-target-std
|
||||||
//@ ignore-windows
|
//@ ignore-windows
|
||||||
// Reason: `llvm-objdump`'s output looks different on windows than on other platforms.
|
// Reason: `llvm-objdump`'s output looks different on windows than on other platforms.
|
||||||
// Only checking on Unix platforms should suffice.
|
// Only checking on Unix platforms should suffice.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
use run_make_support::{path, rustc};
|
use run_make_support::{path, rustc};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// An extended version of the ui/changing-crates.rs test, this test puts
|
// An extended version of the ui/changing-crates.rs test, this test puts
|
||||||
// multiple mismatching crates into the search path of crateC (A2 and A3)
|
// multiple mismatching crates into the search path of crateC (A2 and A3)
|
||||||
// and checks that the standard error contains helpful messages to indicate
|
// and checks that the standard error contains helpful messages to indicate
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// Emitting dep-info alongside metadata would present subtle discrepancies
|
// Emitting dep-info alongside metadata would present subtle discrepancies
|
||||||
// in the output file, such as the filename transforming underscores_ into hyphens-.
|
// in the output file, such as the filename transforming underscores_ into hyphens-.
|
||||||
// After the fix in #114750, this test checks that the emitted files are identical
|
// After the fix in #114750, this test checks that the emitted files are identical
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// In a dependency hierarchy, metadata-only crates could cause an Internal
|
// In a dependency hierarchy, metadata-only crates could cause an Internal
|
||||||
// Compiler Error (ICE) due to a compiler bug - not correctly fetching sources for
|
// Compiler Error (ICE) due to a compiler bug - not correctly fetching sources for
|
||||||
// metadata-only crates. This test is a minimal reproduction of a program that triggered
|
// metadata-only crates. This test is a minimal reproduction of a program that triggered
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// A simple smoke test to check that rustc fails compilation
|
// A simple smoke test to check that rustc fails compilation
|
||||||
// and outputs a helpful message when a dependency is missing
|
// and outputs a helpful message when a dependency is missing
|
||||||
// in a dependency chain.
|
// in a dependency chain.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
use run_make_support::{path, rustc};
|
use run_make_support::{path, rustc};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// On MSVC the alternative naming format for static libraries (`libfoo.a`) is accepted in addition
|
// On MSVC the alternative naming format for static libraries (`libfoo.a`) is accepted in addition
|
||||||
// to the default format (`foo.lib`).
|
// to the default format (`foo.lib`).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// This test is the same as native-link-modifier-rustc, but without rlibs.
|
// This test is the same as native-link-modifier-rustc, but without rlibs.
|
||||||
// See https://github.com/rust-lang/rust/issues/99425
|
// See https://github.com/rust-lang/rust/issues/99425
|
||||||
|
|
||||||
|
//@ needs-target-std
|
||||||
//@ ignore-apple
|
//@ ignore-apple
|
||||||
// Reason: linking fails due to the unusual ".ext" staticlib name.
|
// Reason: linking fails due to the unusual ".ext" staticlib name.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// `verbatim` is a native link modifier that forces rustc to only accept libraries with
|
// `verbatim` is a native link modifier that forces rustc to only accept libraries with
|
||||||
// a specified name. This test checks that this modifier works as intended.
|
// a specified name. This test checks that this modifier works as intended.
|
||||||
// This test is the same as native-link-modifier-linker, but with rlibs.
|
// This test is the same as native-link-modifier-linker, but with rlibs.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// `no_builtins` is an attribute related to LLVM's optimizations. In order to ensure that it has an
|
// `no_builtins` is an attribute related to LLVM's optimizations. In order to ensure that it has an
|
||||||
// effect on link-time optimizations (LTO), it should be added to function declarations in a crate.
|
// effect on link-time optimizations (LTO), it should be added to function declarations in a crate.
|
||||||
// This test uses the `llvm-filecheck` tool to determine that this attribute is successfully
|
// This test uses the `llvm-filecheck` tool to determine that this attribute is successfully
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// The rlib produced by a no_builtins crate should be explicitly linked
|
// The rlib produced by a no_builtins crate should be explicitly linked
|
||||||
// during compilation, and as a result be present in the linker arguments.
|
// during compilation, and as a result be present in the linker arguments.
|
||||||
// See the comments inside this file for more details.
|
// See the comments inside this file for more details.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
use run_make_support::{rfs, rustc};
|
use run_make_support::{rfs, rustc};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@ needs-target-std
|
||||||
use run_make_support::{rfs, rustc};
|
use run_make_support::{rfs, rustc};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// rust should produce artifact notifications about files it was asked to --emit.
|
// rust should produce artifact notifications about files it was asked to --emit.
|
||||||
//
|
//
|
||||||
// It should work in incremental mode both on the first pass where files are generated as well
|
// It should work in incremental mode both on the first pass where files are generated as well
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// In this test, the function `bar` has #[inline(never)] and the function `foo`
|
// In this test, the function `bar` has #[inline(never)] and the function `foo`
|
||||||
// does not. This test outputs LLVM optimization remarks twice - first for all
|
// does not. This test outputs LLVM optimization remarks twice - first for all
|
||||||
// functions (including `bar`, and the `inline` mention), and then for only `foo`
|
// functions (including `bar`, and the `inline` mention), and then for only `foo`
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// An attempt to set the output `-o` into a directory or a file we cannot write into should indeed
|
// An attempt to set the output `-o` into a directory or a file we cannot write into should indeed
|
||||||
// be an error; but not an ICE (Internal Compiler Error). This test attempts both and checks
|
// be an error; but not an ICE (Internal Compiler Error). This test attempts both and checks
|
||||||
// that the standard error matches what is expected.
|
// that the standard error matches what is expected.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// When two instances of rustc are invoked in parallel, they
|
// When two instances of rustc are invoked in parallel, they
|
||||||
// can conflict on their temporary files and overwrite each others',
|
// can conflict on their temporary files and overwrite each others',
|
||||||
// leading to unsuccessful compilation. The -Z temps-dir flag adds
|
// leading to unsuccessful compilation. The -Z temps-dir flag adds
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// A similar test to pass-linker-flags, testing that the `-l link-arg` flag
|
// A similar test to pass-linker-flags, testing that the `-l link-arg` flag
|
||||||
// respects the order relative to other `-l` flags, but this time, the flags
|
// respects the order relative to other `-l` flags, but this time, the flags
|
||||||
// are passed on the compilation of a dependency. This test checks that the
|
// are passed on the compilation of a dependency. This test checks that the
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// This test checks the proper function of `-l link-arg=NAME`, which, unlike
|
// This test checks the proper function of `-l link-arg=NAME`, which, unlike
|
||||||
// -C link-arg, is supposed to guarantee that the order relative to other -l
|
// -C link-arg, is supposed to guarantee that the order relative to other -l
|
||||||
// options will be respected. In this test, compilation fails (because none of the
|
// options will be respected. In this test, compilation fails (because none of the
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ needs-target-std
|
||||||
|
//
|
||||||
// LLVM's profiling instrumentation adds a few symbols that are used by the profiler runtime.
|
// LLVM's profiling instrumentation adds a few symbols that are used by the profiler runtime.
|
||||||
// Since these show up as globals in the LLVM IR, the compiler generates dllimport-related
|
// Since these show up as globals in the LLVM IR, the compiler generates dllimport-related
|
||||||
// __imp_ stubs for them. This can lead to linker errors because the instrumentation
|
// __imp_ stubs for them. This can lead to linker errors because the instrumentation
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue