Auto merge of #3791 - rust-lang:rustup-2024-08-06, r=RalfJung

Automatic Rustup
This commit is contained in:
bors 2024-08-06 08:12:07 +00:00
commit 5b2cdc1f65
94 changed files with 1387 additions and 894 deletions

View file

@ -2330,10 +2330,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
match (cast_ty_from, cast_ty_to) {
(Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
let mut normalize = |t| self.normalize(t, location);
// N.B. `struct_tail_with_normalize` only "structurally resolves"
// the type. It is not fully normalized, so we have to normalize it
// afterwards.
let src_tail =
tcx.struct_tail_with_normalize(src.ty, &mut normalize, || ());
let src_tail = normalize(src_tail);
let dst_tail =
tcx.struct_tail_with_normalize(dst.ty, &mut normalize, || ());
let dst_tail = normalize(dst_tail);
// This checks (lifetime part of) vtable validity for pointer casts,
// which is irrelevant when there are aren't principal traits on both sides (aka only auto traits).

View file

@ -646,6 +646,22 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
}
}
// This is a workaround for a LLVM bug that doesn't implicitly enable
// `simd128` when `relaxed-simd` is.
// See <https://github.com/llvm/llvm-project/pull/99803>, which didn't make
// it into a released version of LLVM yet.
//
// This doesn't use the "implicit target feature" system because it is only
// used for function attributes in other targets, which fixes this bug as
// well on the function attribute level.
if sess.target.families.contains(&"wasm".into()) {
if features.iter().any(|f| f == "+relaxed-simd")
&& !features.iter().any(|f| f == "+simd128")
{
features.push("+simd128".into());
}
}
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
features: f,

View file

@ -8,7 +8,7 @@ use rustc_span::Span;
use crate::traits::*;
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum IntPredicate {
IntEQ,
IntNE,
@ -22,7 +22,7 @@ pub enum IntPredicate {
IntSLE,
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum RealPredicate {
RealPredicateFalse,
RealOEQ,
@ -42,7 +42,7 @@ pub enum RealPredicate {
RealPredicateTrue,
}
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AtomicRmwBinOp {
AtomicXchg,
AtomicAdd,
@ -57,7 +57,7 @@ pub enum AtomicRmwBinOp {
AtomicUMin,
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum AtomicOrdering {
Unordered,
Relaxed,
@ -67,7 +67,7 @@ pub enum AtomicOrdering {
SequentiallyConsistent,
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum SynchronizationScope {
SingleThread,
CrossThread,

View file

@ -97,6 +97,14 @@ pub fn from_target_feature(
Some(Symbol::intern(feature))
}));
}
for (feature, requires) in tcx.sess.target.implicit_target_features() {
if target_features.iter().any(|f| f.as_str() == *feature)
&& !target_features.iter().any(|f| f.as_str() == *requires)
{
target_features.push(Symbol::intern(requires));
}
}
}
/// Computes the set of target features used in a function for the purposes of

View file

@ -23,7 +23,7 @@ use crate::mir::operand::{OperandRef, OperandValue};
use crate::mir::place::{PlaceRef, PlaceValue};
use crate::MemFlags;
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum OverflowOp {
Add,
Sub,

View file

@ -458,7 +458,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
_unwind: mir::UnwindAction,
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
// Shared intrinsics.
if ecx.emulate_intrinsic(instance, args, dest, target)? {
if ecx.eval_intrinsic(instance, args, dest, target)? {
return Ok(None);
}
let intrinsic_name = ecx.tcx.item_name(instance.def_id());

View file

@ -97,7 +97,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Returns `true` if emulation happened.
/// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
/// intrinsic handling.
pub fn emulate_intrinsic(
pub fn eval_intrinsic(
&mut self,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx, M::Provenance>],
@ -447,7 +447,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
Ok(true)
}
pub(super) fn emulate_nondiverging_intrinsic(
pub(super) fn eval_nondiverging_intrinsic(
&mut self,
intrinsic: &NonDivergingIntrinsic<'tcx>,
) -> InterpResult<'tcx> {

View file

@ -1,8 +1,9 @@
use either::Either;
use rustc_apfloat::{Float, FloatConvert};
use rustc_middle::mir::interpret::{InterpResult, Scalar};
use rustc_middle::mir::NullOp;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, FloatTy, ScalarInt};
use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty};
use rustc_middle::{bug, mir, span_bug};
use rustc_span::symbol::sym;
use tracing::trace;
@ -480,4 +481,38 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
}
}
pub fn nullary_op(
&self,
null_op: NullOp<'tcx>,
arg_ty: Ty<'tcx>,
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
use rustc_middle::mir::NullOp::*;
let layout = self.layout_of(arg_ty)?;
let usize_layout = || self.layout_of(self.tcx.types.usize).unwrap();
Ok(match null_op {
SizeOf => {
if !layout.abi.is_sized() {
span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`");
}
let val = layout.size.bytes();
ImmTy::from_uint(val, usize_layout())
}
AlignOf => {
if !layout.abi.is_sized() {
span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`");
}
let val = layout.align.abi.bytes();
ImmTy::from_uint(val, usize_layout())
}
OffsetOf(fields) => {
let val =
self.tcx.offset_of_subfield(self.param_env, layout, fields.iter()).bytes();
ImmTy::from_uint(val, usize_layout())
}
UbChecks => ImmTy::from_bool(self.tcx.sess.ub_checks(), *self.tcx),
})
}
}

View file

@ -4,8 +4,7 @@
use either::Either;
use rustc_index::IndexSlice;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::{bug, mir, span_bug};
use rustc_middle::{bug, mir};
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
use tracing::{info, instrument, trace};
@ -94,7 +93,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
M::retag_place_contents(self, *kind, &dest)?;
}
Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
Intrinsic(box intrinsic) => self.eval_nondiverging_intrinsic(intrinsic)?,
// Evaluate the place expression, without reading from it.
PlaceMention(box place) => {
@ -179,6 +178,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.write_immediate(*result, &dest)?;
}
NullaryOp(null_op, ty) => {
let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;
let val = self.nullary_op(null_op, ty)?;
self.write_immediate(*val, &dest)?;
}
Aggregate(box ref kind, ref operands) => {
self.write_aggregate(kind, operands, &dest)?;
}
@ -230,38 +235,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.write_immediate(*val, &dest)?;
}
NullaryOp(ref null_op, ty) => {
let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;
let layout = self.layout_of(ty)?;
if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op
&& layout.is_unsized()
{
span_bug!(
self.frame().current_span(),
"{null_op:?} MIR operator called for unsized type {ty}",
);
}
let val = match null_op {
mir::NullOp::SizeOf => {
let val = layout.size.bytes();
Scalar::from_target_usize(val, self)
}
mir::NullOp::AlignOf => {
let val = layout.align.abi.bytes();
Scalar::from_target_usize(val, self)
}
mir::NullOp::OffsetOf(fields) => {
let val = self
.tcx
.offset_of_subfield(self.param_env, layout, fields.iter())
.bytes();
Scalar::from_target_usize(val, self)
}
mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.ub_checks()),
};
self.write_scalar(val, &dest)?;
}
ShallowInitBox(ref operand, _) => {
let src = self.eval_operand(operand, None)?;
let v = self.read_immediate(&src)?;

View file

@ -2,7 +2,7 @@ use rustc_ast::InlineAsmTemplatePiece;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::{self as hir, LangItem};
use rustc_middle::bug;
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::Symbol;
@ -455,32 +455,22 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
);
}
}
// No special checking is needed for these:
// - Typeck has checked that Const operands are integers.
// - AST lowering guarantees that SymStatic points to a static.
hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymStatic { .. } => {}
// Check that sym actually points to a function. Later passes
// depend on this.
hir::InlineAsmOperand::SymFn { anon_const } => {
let ty = self.tcx.type_of(anon_const.def_id).instantiate_identity();
match ty.kind() {
ty::Never | ty::Error(_) => {}
ty::FnDef(..) => {}
_ => {
self.tcx
.dcx()
.struct_span_err(*op_sp, "invalid `sym` operand")
.with_span_label(
self.tcx.def_span(anon_const.def_id),
format!("is {} `{}`", ty.kind().article(), ty),
)
.with_help(
"`sym` operands must refer to either a function or a static",
)
.emit();
}
};
// Typeck has checked that Const operands are integers.
hir::InlineAsmOperand::Const { anon_const } => {
debug_assert!(matches!(
self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
ty::Error(_) | ty::Int(_) | ty::Uint(_)
));
}
// Typeck has checked that SymFn refers to a function.
hir::InlineAsmOperand::SymFn { anon_const } => {
debug_assert!(matches!(
self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
ty::Error(_) | ty::FnDef(..)
));
}
// AST lowering guarantees that SymStatic points to a static.
hir::InlineAsmOperand::SymStatic { .. } => {}
// No special checking is needed for labels.
hir::InlineAsmOperand::Label { .. } => {}
}

View file

@ -7,7 +7,7 @@ use rustc_hir::HirId;
use rustc_middle::query::plumbing::CyclePlaceholder;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{self, Article, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::{bug, span_bug};
use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
@ -34,6 +34,20 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
let parent_node_id = tcx.parent_hir_id(hir_id);
let parent_node = tcx.hir_node(parent_node_id);
let find_sym_fn = |&(op, op_sp)| match op {
hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == hir_id => {
Some((anon_const, op_sp))
}
_ => None,
};
let find_const = |&(op, op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => {
Some((anon_const, op_sp))
}
_ => None,
};
match parent_node {
// Anon consts "inside" the type system.
Node::ConstArg(&ConstArg {
@ -45,13 +59,51 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
// Anon consts outside the type system.
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
if asm.operands.iter().any(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const }
| hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
_ => false,
}) =>
if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_sym_fn) =>
{
tcx.typeck(def_id).node_type(hir_id)
let ty = tcx.typeck(def_id).node_type(hir_id);
match ty.kind() {
ty::Error(_) => ty,
ty::FnDef(..) => ty,
_ => {
let guar = tcx
.dcx()
.struct_span_err(op_sp, "invalid `sym` operand")
.with_span_label(
tcx.def_span(anon_const.def_id),
format!("is {} `{}`", ty.kind().article(), ty),
)
.with_help("`sym` operands must refer to either a function or a static")
.emit();
Ty::new_error(tcx, guar)
}
}
}
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_const) =>
{
let ty = tcx.typeck(def_id).node_type(hir_id);
match ty.kind() {
ty::Error(_) => ty,
ty::Int(_) | ty::Uint(_) => ty,
_ => {
let guar = tcx
.dcx()
.struct_span_err(op_sp, "invalid type for `const` operand")
.with_span_label(
tcx.def_span(anon_const.def_id),
format!("is {} `{}`", ty.kind().article(), ty),
)
.with_help("`const` operands must be of an integer type")
.emit();
Ty::new_error(tcx, guar)
}
}
}
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)

View file

@ -265,11 +265,10 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), span, .. })
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), span, .. }) => {
asm.operands.iter().find_map(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => {
// Inline assembly constants must be integers.
Some(fcx.next_int_var())
}
hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == id => {
hir::InlineAsmOperand::Const { anon_const }
| hir::InlineAsmOperand::SymFn { anon_const }
if anon_const.hir_id == id =>
{
Some(fcx.next_ty_var(span))
}
_ => None,

View file

@ -774,18 +774,23 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// instantiation that replaces `Self` with the object type itself. Hence,
// a `&self` method will wind up with an argument type like `&dyn Trait`.
let trait_ref = principal.with_self_ty(self.tcx, self_ty);
self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
this.push_candidate(
Candidate { item, kind: ObjectCandidate(new_trait_ref), import_ids: smallvec![] },
true,
);
});
self.assemble_candidates_for_bounds(
traits::supertraits(self.tcx, trait_ref),
|this, new_trait_ref, item| {
this.push_candidate(
Candidate {
item,
kind: ObjectCandidate(new_trait_ref),
import_ids: smallvec![],
},
true,
);
},
);
}
#[instrument(level = "debug", skip(self))]
fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
// FIXME: do we want to commit to this behavior for param bounds?
let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
@ -806,7 +811,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
});
self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
self.assemble_candidates_for_bounds(bounds, |this, poly_trait_ref, item| {
this.push_candidate(
Candidate {
item,
@ -820,15 +825,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// Do a search through a list of bounds, using a callback to actually
// create the candidates.
fn elaborate_bounds<F>(
fn assemble_candidates_for_bounds<F>(
&mut self,
bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
mut mk_cand: F,
) where
F: for<'b> FnMut(&mut ProbeContext<'b, 'tcx>, ty::PolyTraitRef<'tcx>, ty::AssocItem),
{
let tcx = self.tcx;
for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
for bound_trait_ref in bounds {
debug!("elaborate_bounds(bound_trait_ref={:?})", bound_trait_ref);
for item in self.impl_or_trait_item(bound_trait_ref.def_id()) {
if !self.has_applicable_self(&item) {

View file

@ -75,6 +75,9 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
@call(mir_call, args) => {
self.parse_call(args)
},
@call(mir_tail_call, args) => {
self.parse_tail_call(args)
},
ExprKind::Match { scrutinee, arms, .. } => {
let discr = self.parse_operand(*scrutinee)?;
self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
@ -187,6 +190,25 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
)
}
fn parse_tail_call(&self, args: &[ExprId]) -> PResult<TerminatorKind<'tcx>> {
parse_by_kind!(self, args[0], _, "tail call",
ExprKind::Call { fun, args, fn_span, .. } => {
let fun = self.parse_operand(*fun)?;
let args = args
.iter()
.map(|arg|
Ok(Spanned { node: self.parse_operand(*arg)?, span: self.thir.exprs[*arg].span } )
)
.collect::<PResult<Box<[_]>>>()?;
Ok(TerminatorKind::TailCall {
func: fun,
args,
fn_span: *fn_span,
})
},
)
}
fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
parse_by_kind!(self, expr_id, expr, "rvalue",
@call(mir_discriminant, args) => self.parse_place(args[0]).map(Rvalue::Discriminant),

View file

@ -7,7 +7,7 @@ use rustc_type_ir::data_structures::HashMap;
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_type_ir::{self as ty, Interner, Upcast as _};
use rustc_type_ir::{self as ty, elaborate, Interner, Upcast as _};
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use tracing::instrument;
@ -671,11 +671,19 @@ where
{
let cx = ecx.cx();
let mut requirements = vec![];
requirements.extend(
// Elaborating all supertrait outlives obligations here is not soundness critical,
// since if we just used the unelaborated set, then the transitive supertraits would
// be reachable when proving the former. However, since we elaborate all supertrait
// outlives obligations when confirming impls, we would end up with a different set
// of outlives obligations here if we didn't do the same, leading to ambiguity.
// FIXME(-Znext-solver=coinductive): Adding supertraits here can be removed once we
// make impls coinductive always, since they'll always need to prove their supertraits.
requirements.extend(elaborate::elaborate(
cx,
cx.explicit_super_predicates_of(trait_ref.def_id)
.iter_instantiated(cx, trait_ref.args)
.map(|(pred, _)| pred),
);
));
// FIXME(associated_const_equality): Also add associated consts to
// the requirements here.

View file

@ -87,6 +87,19 @@ where
.map(|pred| goal.with(cx, pred));
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
// We currently elaborate all supertrait outlives obligations from impls.
// This can be removed when we actually do coinduction correctly, and prove
// all supertrait obligations unconditionally.
let goal_clause: I::Clause = goal.predicate.upcast(cx);
for clause in elaborate::elaborate(cx, [goal_clause]) {
if matches!(
clause.kind().skip_binder(),
ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
) {
ecx.add_goal(GoalSource::Misc, goal.with(cx, clause));
}
}
ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
})
}

View file

@ -48,6 +48,7 @@ pub(crate) enum ImportKind<'a> {
/// `source` in `use prefix::source as target`.
source: Ident,
/// `target` in `use prefix::source as target`.
/// It will directly use `source` when the format is `use prefix::source`.
target: Ident,
/// Bindings to which `source` refers to.
source_bindings: PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>,

View file

@ -6,7 +6,7 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::bug;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_target::abi::call::{Conv, FnAbi, PassMode};
use tracing::instrument;
@ -112,11 +112,12 @@ pub fn typeid_for_instance<'tcx>(
instance: Instance<'tcx>,
options: TypeIdOptions,
) -> String {
assert!(!instance.has_non_region_param(), "{instance:#?} must be fully monomorphic");
let transform_ty_options = TransformTyOptions::from_bits(options.bits())
.unwrap_or_else(|| bug!("typeid_for_instance: invalid option(s) `{:?}`", options.bits()));
let instance = transform_instance(tcx, instance, transform_ty_options);
let fn_abi = tcx
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
.fn_abi_of_instance(ty::ParamEnv::reveal_all().and((instance, ty::List::empty())))
.unwrap_or_else(|error| {
bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}")
});

View file

@ -1216,6 +1216,7 @@ symbols! {
mir_static_mut,
mir_storage_dead,
mir_storage_live,
mir_tail_call,
mir_unreachable,
mir_unwind_cleanup,
mir_unwind_continue,

View file

@ -21,6 +21,7 @@ pub fn target() -> Target {
llvm_abiname: "lp64d".into(),
max_atomic_width: Some(64),
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
crt_static_default: false,
..base::linux_musl::opts()
},
}

View file

@ -333,12 +333,14 @@ const WASM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
("mutable-globals", Stable),
("nontrapping-fptoint", Stable),
("reference-types", Unstable(sym::wasm_target_feature)),
("relaxed-simd", Unstable(sym::wasm_target_feature)),
("relaxed-simd", Stable),
("sign-ext", Stable),
("simd128", Stable),
// tidy-alphabetical-end
];
const WASM_IMPLICIT_FEATURES: &[(&str, &str)] = &[("relaxed-simd", "simd128")];
const BPF_ALLOWED_FEATURES: &[(&str, Stability)] = &[("alu32", Unstable(sym::bpf_target_feature))];
const CSKY_ALLOWED_FEATURES: &[(&str, Stability)] = &[
@ -455,4 +457,13 @@ impl super::spec::Target {
_ => &[],
}
}
/// Returns a list of target features. Each items first target feature
/// implicitly enables the second one.
pub fn implicit_target_features(&self) -> &'static [(&'static str, &'static str)] {
match &*self.arch {
"wasm32" | "wasm64" => WASM_IMPLICIT_FEATURES,
_ => &[],
}
}
}

View file

@ -62,7 +62,7 @@ pub use self::specialize::{
};
pub use self::structural_normalize::StructurallyNormalizeExt;
pub use self::util::{
elaborate, expand_trait_aliases, impl_item_is_final, supertraits, transitive_bounds,
elaborate, expand_trait_aliases, impl_item_is_final, supertraits,
transitive_bounds_that_define_assoc_item, upcast_choices, with_replaced_escaping_bound_vars,
BoundVarReplacer, PlaceholderReplacer, TraitAliasExpander, TraitAliasExpansionInfo,
};

View file

@ -7,6 +7,7 @@ use std::fmt::{self, Display};
use std::ops::ControlFlow;
use std::{cmp, iter};
use hir::def::DefKind;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Diag, EmissionGuarantee};
@ -14,8 +15,9 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::LangItem;
use rustc_infer::infer::relate::TypeRelation;
use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::util::elaborate;
use rustc_infer::traits::TraitObligation;
use rustc_middle::bug;
use rustc_middle::dep_graph::{dep_kinds, DepNodeIndex};
@ -2798,6 +2800,35 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
});
}
// Register any outlives obligations from the trait here, cc #124336.
if matches!(self.tcx().def_kind(def_id), DefKind::Impl { of_trait: true })
&& let Some(header) = self.tcx().impl_trait_header(def_id)
{
let trait_clause: ty::Clause<'tcx> =
header.trait_ref.instantiate(self.tcx(), args).upcast(self.tcx());
for clause in elaborate(self.tcx(), [trait_clause]) {
if matches!(
clause.kind().skip_binder(),
ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
) {
let clause = normalize_with_depth_to(
self,
param_env,
cause.clone(),
recursion_depth,
clause,
&mut obligations,
);
obligations.push(Obligation {
cause: cause.clone(),
recursion_depth,
param_env,
predicate: clause.as_predicate(),
});
}
}
}
obligations
}
}

View file

@ -264,15 +264,6 @@ pub fn supertraits<I: Interner>(
elaborate(cx, [trait_ref.upcast(cx)]).filter_only_self().filter_to_traits()
}
pub fn transitive_bounds<I: Interner>(
cx: I,
trait_refs: impl Iterator<Item = ty::Binder<I, ty::TraitRef<I>>>,
) -> FilterToTraits<I, Elaborator<I, I::Clause>> {
elaborate(cx, trait_refs.map(|trait_ref| trait_ref.upcast(cx)))
.filter_only_self()
.filter_to_traits()
}
impl<I: Interner> Elaborator<I, I::Clause> {
fn filter_to_traits(self) -> FilterToTraits<I, Self> {
FilterToTraits { _cx: PhantomData, base_iterator: self }

View file

@ -451,6 +451,8 @@ pub trait Clause<I: Interner<Clause = Self>>:
+ UpcastFrom<I, ty::Binder<I, ty::ClauseKind<I>>>
+ UpcastFrom<I, ty::TraitRef<I>>
+ UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
+ UpcastFrom<I, ty::TraitPredicate<I>>
+ UpcastFrom<I, ty::Binder<I, ty::TraitPredicate<I>>>
+ UpcastFrom<I, ty::ProjectionPredicate<I>>
+ UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
+ IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>>

View file

@ -247,6 +247,8 @@
//! otherwise branch.
//! - [`Call`] has an associated function as well, with special syntax:
//! `Call(ret_val = function(arg1, arg2, ...), ReturnTo(next_block), UnwindContinue())`.
//! - [`TailCall`] does not have a return destination or next block, so its syntax is just
//! `TailCall(function(arg1, arg2, ...))`.
#![unstable(
feature = "custom_mir",
@ -350,6 +352,12 @@ define!("mir_call",
/// - [`UnwindCleanup`]
fn Call(call: (), goto: ReturnToArg, unwind_action: UnwindActionArg)
);
define!("mir_tail_call",
/// Call a function.
///
/// The argument must be of the form `fun(arg1, arg2, ...)`.
fn TailCall<T>(call: T)
);
define!("mir_unwind_resume",
/// A terminator that resumes the unwinding.
fn UnwindResume()

View file

@ -12,48 +12,51 @@ use crate::num::flt2dec::{round_up, Decoded, MAX_SIG_DIGITS};
static POW10: [Digit; 10] =
[1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000];
static TWOPOW10: [Digit; 10] =
[2, 20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000];
// precalculated arrays of `Digit`s for 10^(2^n)
static POW10TO16: [Digit; 2] = [0x6fc10000, 0x2386f2];
static POW10TO32: [Digit; 4] = [0, 0x85acef81, 0x2d6d415b, 0x4ee];
static POW10TO64: [Digit; 7] = [0, 0, 0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03];
static POW10TO128: [Digit; 14] = [
0, 0, 0, 0, 0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, 0xbccdb0da,
0xa6337f19, 0xe91f2603, 0x24e,
// precalculated arrays of `Digit`s for 5^(2^n).
static POW5TO16: [Digit; 2] = [0x86f26fc1, 0x23];
static POW5TO32: [Digit; 3] = [0x85acef81, 0x2d6d415b, 0x4ee];
static POW5TO64: [Digit; 5] = [0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03];
static POW5TO128: [Digit; 10] = [
0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, 0xbccdb0da, 0xa6337f19,
0xe91f2603, 0x24e,
];
static POW10TO256: [Digit; 27] = [
0, 0, 0, 0, 0, 0, 0, 0, 0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70,
0xd595d80f, 0x26b2716e, 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0, 0x65f9ef17,
0x55bc28f2, 0x80dcc7f7, 0xf46eeddc, 0x5fdcefce, 0x553f7,
static POW5TO256: [Digit; 19] = [
0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70, 0xd595d80f, 0x26b2716e,
0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0, 0x65f9ef17, 0x55bc28f2, 0x80dcc7f7,
0xf46eeddc, 0x5fdcefce, 0x553f7,
];
#[doc(hidden)]
pub fn mul_pow10(x: &mut Big, n: usize) -> &mut Big {
debug_assert!(n < 512);
// Save ourself the left shift for the smallest cases.
if n < 8 {
return x.mul_small(POW10[n & 7]);
}
// Multiply by the powers of 5 and shift the 2s in at the end.
// This keeps the intermediate products smaller and faster.
if n & 7 != 0 {
x.mul_small(POW10[n & 7]);
x.mul_small(POW10[n & 7] >> (n & 7));
}
if n & 8 != 0 {
x.mul_small(POW10[8]);
x.mul_small(POW10[8] >> 8);
}
if n & 16 != 0 {
x.mul_digits(&POW10TO16);
x.mul_digits(&POW5TO16);
}
if n & 32 != 0 {
x.mul_digits(&POW10TO32);
x.mul_digits(&POW5TO32);
}
if n & 64 != 0 {
x.mul_digits(&POW10TO64);
x.mul_digits(&POW5TO64);
}
if n & 128 != 0 {
x.mul_digits(&POW10TO128);
x.mul_digits(&POW5TO128);
}
if n & 256 != 0 {
x.mul_digits(&POW10TO256);
x.mul_digits(&POW5TO256);
}
x
x.mul_pow2(n)
}
fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big {
@ -62,7 +65,7 @@ fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big {
x.div_rem_small(POW10[largest]);
n -= largest;
}
x.div_rem_small(TWOPOW10[n]);
x.div_rem_small(POW10[n] << 1);
x
}

View file

@ -522,7 +522,7 @@ impl<T> [T] {
/// ```
#[inline]
#[stable(feature = "slice_first_last_chunk", since = "1.77.0")]
#[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")]
#[rustc_const_stable(feature = "const_slice_last_chunk", since = "1.80.0")]
pub const fn last_chunk<const N: usize>(&self) -> Option<&[T; N]> {
if self.len() < N {
None

View file

@ -455,8 +455,18 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
Ok(NonZero::new_unchecked(sinfo.cpu_count as usize))
}
} else if #[cfg(target_os = "vxworks")] {
// Note: there is also `vxCpuConfiguredGet`, closer to _SC_NPROCESSORS_CONF
// expectations than the actual cores availability.
extern "C" {
fn vxCpuEnabledGet() -> libc::cpuset_t;
}
// always fetches a valid bitmask
let set = unsafe { vxCpuEnabledGet() };
Ok(NonZero::new_unchecked(set.count_ones() as usize))
} else {
// FIXME: implement on vxWorks, Redox, l4re
// FIXME: implement on Redox, l4re
Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform"))
}
}

View file

@ -599,6 +599,16 @@ impl Step for Std {
fn run(self, builder: &Builder<'_>) {
let stage = self.stage;
let target = self.target;
let crates = if self.crates.is_empty() {
builder
.in_tree_crates("sysroot", Some(target))
.iter()
.map(|c| c.name.to_string())
.collect()
} else {
self.crates
};
let out = match self.format {
DocumentationFormat::Html => builder.doc_out(target),
DocumentationFormat::Json => builder.json_doc_out(target),
@ -627,7 +637,7 @@ impl Step for Std {
extra_args.push("--disable-minification");
}
doc_std(builder, self.format, stage, target, &out, &extra_args, &self.crates);
doc_std(builder, self.format, stage, target, &out, &extra_args, &crates);
// Don't open if the format is json
if let DocumentationFormat::Json = self.format {
@ -639,7 +649,7 @@ impl Step for Std {
let index = out.join("std").join("index.html");
builder.open_in_browser(index);
} else {
for requested_crate in &*self.crates {
for requested_crate in crates {
if STD_PUBLIC_CRATES.iter().any(|&k| k == requested_crate) {
let index = out.join(requested_crate).join("index.html");
builder.open_in_browser(index);

View file

@ -536,8 +536,7 @@ pub fn get_closest_merge_base_commit(
let merge_base = get_git_merge_base(config, source_dir).unwrap_or_else(|_| "HEAD".into());
git.arg(Path::new("rev-list"));
git.args([&format!("--author={author}"), "-n1", "--first-parent", &merge_base]);
git.args(["rev-list", &format!("--author={author}"), "-n1", "--first-parent", &merge_base]);
if !target_paths.is_empty() {
git.arg("--").args(target_paths);

View file

@ -24,7 +24,8 @@ RUN apt-get update && apt-get build-dep -y clang llvm && apt-get install -y --no
# Needed for apt-key to work:
dirmngr \
gpg-agent \
g++-9-arm-linux-gnueabi
g++-9-arm-linux-gnueabi \
g++-11-riscv64-linux-gnu
RUN apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys 74DA7924C5513486
RUN add-apt-repository -y 'deb https://apt.dilos.org/dilos dilos2 main'
@ -73,6 +74,10 @@ RUN env \
CC=arm-linux-gnueabi-gcc-9 CFLAGS="-march=armv7-a" \
CXX=arm-linux-gnueabi-g++-9 CXXFLAGS="-march=armv7-a" \
bash musl.sh armv7 && \
env \
CC=riscv64-linux-gnu-gcc-11 \
CXX=riscv64-linux-gnu-g++-11 \
bash musl.sh riscv64gc && \
rm -rf /build/*
WORKDIR /tmp
@ -125,6 +130,7 @@ ENV TARGETS=$TARGETS,x86_64-unknown-none
ENV TARGETS=$TARGETS,aarch64-unknown-uefi
ENV TARGETS=$TARGETS,i686-unknown-uefi
ENV TARGETS=$TARGETS,x86_64-unknown-uefi
ENV TARGETS=$TARGETS,riscv64gc-unknown-linux-musl
# As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211
# we need asm in the search path for gcc-9 (for gnux32) but not in the search path of the
@ -132,7 +138,11 @@ ENV TARGETS=$TARGETS,x86_64-unknown-uefi
# Luckily one of the folders is /usr/local/include so symlink /usr/include/x86_64-linux-gnu/asm there
RUN ln -s /usr/include/x86_64-linux-gnu/asm /usr/local/include/asm
# musl-gcc can't find libgcc_s.so.1 since it doesn't use the standard search paths.
RUN ln -s /usr/riscv64-linux-gnu/lib/libgcc_s.so.1 /usr/lib/gcc-cross/riscv64-linux-gnu/11/
ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --enable-llvm-bitcode-linker --disable-docs \
--musl-root-armv7=/musl-armv7
--musl-root-armv7=/musl-armv7 \
--musl-root-riscv64gc=/musl-riscv64gc
ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS

View file

@ -66,6 +66,7 @@
- [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
- [riscv32*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md)
- [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md)
- [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md)
- [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
- [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
- [\*-nto-qnx-\*](platform-support/nto-qnx.md)

View file

@ -98,6 +98,7 @@ target | notes
`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17)
`powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17)
[`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29)
[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3)
`s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17)
`x86_64-unknown-freebsd` | 64-bit FreeBSD
`x86_64-unknown-illumos` | illumos
@ -354,7 +355,6 @@ target | std | host | notes
[`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit
`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD
`riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia
`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.3)
[`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD
[`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
[`riscv64-linux-android`](platform-support/android.md) | | | RISC-V 64-bit Android

View file

@ -0,0 +1,47 @@
# riscv64gc-unknown-linux-musl
**Tier: 2**
Target for RISC-V Linux programs using musl libc.
## Target maintainers
- [@Amanieu](https://github.com/Amanieu)
- [@kraj](https://github.com/kraj)
## Requirements
Building the target itself requires a RISC-V compiler that is supported by `cc-rs`.
## Building the target
The target can be built by enabling it for a `rustc` build.
```toml
[build]
target = ["riscv64gc-unknown-linux-musl"]
```
Make sure your C compiler is included in `$PATH`, then add it to the `config.toml`:
```toml
[target.riscv64gc-unknown-linux-musl]
cc = "riscv64-linux-gnu-gcc"
cxx = "riscv64-linux-gnu-g++"
ar = "riscv64-linux-gnu-ar"
linker = "riscv64-linux-gnu-gcc"
```
## Building Rust programs
This target are distributed through `rustup`, and otherwise require no
special configuration.
## Cross-compilation
This target can be cross-compiled from any host.
## Testing
This target can be tested as normal with `x.py` on a RISC-V host or via QEMU
emulation.

View file

@ -12,7 +12,7 @@ use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::symbol::{sym, Symbol};
use thin_vec::{thin_vec, ThinVec};
use {rustc_ast as ast, rustc_hir as hir};
@ -792,11 +792,7 @@ fn build_macro(
fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics {
for pred in &mut g.where_predicates {
match *pred {
clean::WherePredicate::BoundPredicate {
ty: clean::Generic(ref s),
ref mut bounds,
..
} if *s == kw::SelfUpper => {
clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref mut bounds, .. } => {
bounds.retain(|bound| match bound {
clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => {
trait_.def_id() != trait_did
@ -812,13 +808,13 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
clean::WherePredicate::BoundPredicate {
ty:
clean::QPath(box clean::QPathData {
self_type: clean::Generic(ref s),
self_type: clean::Generic(_),
trait_: Some(trait_),
..
}),
bounds,
..
} => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did),
} => !bounds.is_empty() && trait_.def_id() != trait_did,
_ => true,
});
g
@ -832,9 +828,7 @@ fn separate_supertrait_bounds(
) -> (clean::Generics, Vec<clean::GenericBound>) {
let mut ty_bounds = Vec::new();
g.where_predicates.retain(|pred| match *pred {
clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds, .. }
if *s == kw::SelfUpper =>
{
clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref bounds, .. } => {
ty_bounds.extend(bounds.iter().cloned());
false
}

View file

@ -1351,11 +1351,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
let self_arg_ty =
tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
if self_arg_ty == self_ty {
item.decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
item.decl.inputs.values[0].type_ = SelfTy;
} else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
if ty == self_ty {
match item.decl.inputs.values[0].type_ {
BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
BorrowedRef { ref mut type_, .. } => **type_ = SelfTy,
_ => unreachable!(),
}
}
@ -1439,9 +1439,8 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
if trait_.def_id() != assoc_item.container_id(tcx) {
return true;
}
match *self_type {
Generic(ref s) if *s == kw::SelfUpper => {}
_ => return true,
if *self_type != SelfTy {
return true;
}
match &assoc.args {
GenericArgs::AngleBracketed { args, constraints } => {
@ -2228,6 +2227,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
ty::Param(ref p) => {
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
ImplTrait(bounds)
} else if p.name == kw::SelfUpper {
SelfTy
} else {
Generic(p.name)
}

View file

@ -145,7 +145,6 @@ pub(crate) fn sized_bounds(cx: &mut DocContext<'_>, generics: &mut clean::Generi
// should be handled when cleaning associated types.
generics.where_predicates.retain(|pred| {
if let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred
&& *param != rustc_span::symbol::kw::SelfUpper
&& bounds.iter().any(|b| b.is_sized_bound(cx))
{
sized_params.insert(*param);

View file

@ -34,10 +34,9 @@ use thin_vec::ThinVec;
use {rustc_ast as ast, rustc_hir as hir};
pub(crate) use self::ItemKind::*;
pub(crate) use self::SelfTy::*;
pub(crate) use self::Type::{
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
RawPointer, Slice, Tuple,
RawPointer, SelfTy, Slice, Tuple,
};
use crate::clean::cfg::Cfg;
use crate::clean::clean_middle_path;
@ -1384,8 +1383,8 @@ pub(crate) struct FnDecl {
}
impl FnDecl {
pub(crate) fn self_type(&self) -> Option<SelfTy> {
self.inputs.values.get(0).and_then(|v| v.to_self())
pub(crate) fn receiver_type(&self) -> Option<&Type> {
self.inputs.values.get(0).and_then(|v| v.to_receiver())
}
}
@ -1403,27 +1402,9 @@ pub(crate) struct Argument {
pub(crate) is_const: bool,
}
#[derive(Clone, PartialEq, Debug)]
pub(crate) enum SelfTy {
SelfValue,
SelfBorrowed(Option<Lifetime>, Mutability),
SelfExplicit(Type),
}
impl Argument {
pub(crate) fn to_self(&self) -> Option<SelfTy> {
if self.name != kw::SelfLower {
return None;
}
if self.type_.is_self_type() {
return Some(SelfValue);
}
match self.type_ {
BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => {
Some(SelfBorrowed(lifetime.clone(), mutability))
}
_ => Some(SelfExplicit(self.type_.clone())),
}
pub(crate) fn to_receiver(&self) -> Option<&Type> {
if self.name == kw::SelfLower { Some(&self.type_) } else { None }
}
}
@ -1477,6 +1458,8 @@ pub(crate) enum Type {
DynTrait(Vec<PolyTrait>, Option<Lifetime>),
/// A type parameter.
Generic(Symbol),
/// The `Self` type.
SelfTy,
/// A primitive (aka, builtin) type.
Primitive(PrimitiveType),
/// A function pointer: `extern "ABI" fn(...) -> ...`
@ -1571,6 +1554,8 @@ impl Type {
// If both sides are generic, this returns true.
(_, Type::Generic(_)) => true,
(Type::Generic(_), _) => false,
// `Self` only matches itself.
(Type::SelfTy, Type::SelfTy) => true,
// Paths account for both the path itself and its generics.
(Type::Path { path: a }, Type::Path { path: b }) => {
a.def_id() == b.def_id()
@ -1642,7 +1627,7 @@ impl Type {
pub(crate) fn is_self_type(&self) -> bool {
match *self {
Generic(name) => name == kw::SelfUpper,
SelfTy => true,
_ => false,
}
}
@ -1700,7 +1685,7 @@ impl Type {
Type::Pat(..) => PrimitiveType::Pat,
RawPointer(..) => PrimitiveType::RawPointer,
QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache),
Generic(_) | Infer | ImplTrait(_) => return None,
Generic(_) | SelfTy | Infer | ImplTrait(_) => return None,
};
Primitive(t).def_id(cache)
}

View file

@ -468,7 +468,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
match path.res {
Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } if path.segments.len() == 1 => {
Generic(kw::SelfUpper)
Type::SelfTy
}
Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
_ => {

View file

@ -310,16 +310,16 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
// `public_items` map, so we can skip inserting into the
// paths map if there was already an entry present and we're
// not a public item.
if !self.cache.paths.contains_key(&item.item_id.expect_def_id())
let item_def_id = item.item_id.expect_def_id();
if !self.cache.paths.contains_key(&item_def_id)
|| self
.cache
.effective_visibilities
.is_directly_public(self.tcx, item.item_id.expect_def_id())
.is_directly_public(self.tcx, item_def_id)
{
self.cache.paths.insert(
item.item_id.expect_def_id(),
(self.cache.stack.clone(), item.type_()),
);
self.cache
.paths
.insert(item_def_id, (self.cache.stack.clone(), item.type_()));
}
}
}
@ -381,9 +381,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
&& adt.is_fundamental()
{
for ty in generics {
if let Some(did) = ty.def_id(self.cache) {
dids.insert(did);
}
dids.extend(ty.def_id(self.cache));
}
}
}
@ -396,32 +394,26 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
.primitive_type()
.and_then(|t| self.cache.primitive_locations.get(&t).cloned());
if let Some(did) = did {
dids.insert(did);
}
dids.extend(did);
}
}
if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
for bound in generics {
if let Some(did) = bound.def_id(self.cache) {
dids.insert(did);
}
dids.extend(bound.def_id(self.cache));
}
}
let impl_item = Impl { impl_item: item };
if impl_item.trait_did().map_or(true, |d| self.cache.traits.contains_key(&d)) {
let impl_did = impl_item.def_id();
let trait_did = impl_item.trait_did();
if trait_did.map_or(true, |d| self.cache.traits.contains_key(&d)) {
for did in dids {
if self.impl_ids.entry(did).or_default().insert(impl_item.def_id()) {
self.cache
.impls
.entry(did)
.or_insert_with(Vec::new)
.push(impl_item.clone());
if self.impl_ids.entry(did).or_default().insert(impl_did) {
self.cache.impls.entry(did).or_default().push(impl_item.clone());
}
}
} else {
let trait_did = impl_item.trait_did().expect("no trait did");
let trait_did = trait_did.expect("no trait did");
self.cache.orphan_trait_impls.push((trait_did, dids, impl_item));
}
None

View file

@ -1006,6 +1006,7 @@ fn fmt_type<'cx>(
match *t {
clean::Generic(name) => f.write_str(name.as_str()),
clean::SelfTy => f.write_str("Self"),
clean::Type::Path { ref path } => {
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
let did = path.def_id();
@ -1452,29 +1453,22 @@ impl clean::FnDecl {
let last_input_index = self.inputs.values.len().checked_sub(1);
for (i, input) in self.inputs.values.iter().enumerate() {
if let Some(selfty) = input.to_self() {
if let Some(selfty) = input.to_receiver() {
match selfty {
clean::SelfValue => {
clean::SelfTy => {
write!(f, "self")?;
}
clean::SelfBorrowed(Some(ref lt), mutability) => {
write!(
f,
"{amp}{lifetime} {mutability}self",
lifetime = lt.print(),
mutability = mutability.print_with_space(),
)?;
clean::BorrowedRef { lifetime, mutability, type_: box clean::SelfTy } => {
write!(f, "{amp}")?;
match lifetime {
Some(lt) => write!(f, "{lt} ", lt = lt.print())?,
None => {}
}
write!(f, "{mutability}self", mutability = mutability.print_with_space())?;
}
clean::SelfBorrowed(None, mutability) => {
write!(
f,
"{amp}{mutability}self",
mutability = mutability.print_with_space(),
)?;
}
clean::SelfExplicit(ref typ) => {
_ => {
write!(f, "self: ")?;
typ.print(cx).fmt(f)?;
selfty.print(cx).fmt(f)?;
}
}
} else {

View file

@ -58,7 +58,7 @@ use serde::{Serialize, Serializer};
pub(crate) use self::context::*;
pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
use crate::clean::{self, ItemId, RenderedLink, SelfTy};
use crate::clean::{self, ItemId, RenderedLink};
use crate::error::Error;
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
@ -1372,21 +1372,20 @@ fn render_deref_methods(
fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
let self_type_opt = match *item.kind {
clean::MethodItem(ref method, _) => method.decl.self_type(),
clean::TyMethodItem(ref method) => method.decl.self_type(),
clean::MethodItem(ref method, _) => method.decl.receiver_type(),
clean::TyMethodItem(ref method) => method.decl.receiver_type(),
_ => None,
};
if let Some(self_ty) = self_type_opt {
let (by_mut_ref, by_box, by_value) = match self_ty {
SelfTy::SelfBorrowed(_, mutability)
| SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
let (by_mut_ref, by_box, by_value) = match *self_ty {
clean::Type::BorrowedRef { mutability, .. } => {
(mutability == Mutability::Mut, false, false)
}
SelfTy::SelfExplicit(clean::Type::Path { path }) => {
clean::Type::Path { ref path } => {
(false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
}
SelfTy::SelfValue => (false, false, true),
clean::Type::SelfTy => (false, false, true),
_ => (false, false, false),
};

View file

@ -797,7 +797,11 @@ fn get_index_type_id(
}
}
// Not supported yet
clean::Type::Pat(..) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
clean::Type::Pat(..)
| clean::Generic(_)
| clean::SelfTy
| clean::ImplTrait(_)
| clean::Infer => None,
}
}
@ -850,15 +854,70 @@ fn simplify_fn_type<'tcx, 'a>(
// If this argument is a type parameter and not a trait bound or a type, we need to look
// for its bounds.
if let Type::Generic(arg_s) = *arg {
// First we check if the bounds are in a `where` predicate...
let mut type_bounds = Vec::new();
for where_pred in generics.where_predicates.iter().filter(|g| match g {
WherePredicate::BoundPredicate { ty: Type::Generic(ty_s), .. } => *ty_s == arg_s,
_ => false,
}) {
let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
for bound in bounds.iter() {
match *arg {
Type::Generic(arg_s) => {
// First we check if the bounds are in a `where` predicate...
let mut type_bounds = Vec::new();
for where_pred in generics.where_predicates.iter().filter(|g| match g {
WherePredicate::BoundPredicate { ty, .. } => *ty == *arg,
_ => false,
}) {
let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
for bound in bounds.iter() {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut type_bounds,
rgen,
is_return,
cache,
);
}
}
}
// Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
for bound in bound.get_bounds().unwrap_or(&[]) {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut type_bounds,
rgen,
is_return,
cache,
);
}
}
}
if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
res.push(RenderType {
id: Some(RenderTypeId::Index(*idx)),
generics: None,
bindings: None,
});
} else {
let idx = -isize::try_from(rgen.len() + 1).unwrap();
rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
res.push(RenderType {
id: Some(RenderTypeId::Index(idx)),
generics: None,
bindings: None,
});
}
}
Type::ImplTrait(ref bounds) => {
let mut type_bounds = Vec::new();
for bound in bounds {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
simplify_fn_type(
@ -874,103 +933,22 @@ fn simplify_fn_type<'tcx, 'a>(
);
}
}
}
// Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
for bound in bound.get_bounds().unwrap_or(&[]) {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut type_bounds,
rgen,
is_return,
cache,
);
}
if is_return && !type_bounds.is_empty() {
// In return position, `impl Trait` is a unique thing.
res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
} else {
// In parameter position, `impl Trait` is the same as an unnamed generic parameter.
let idx = -isize::try_from(rgen.len() + 1).unwrap();
rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
res.push(RenderType {
id: Some(RenderTypeId::Index(idx)),
generics: None,
bindings: None,
});
}
}
if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
res.push(RenderType {
id: Some(RenderTypeId::Index(*idx)),
generics: None,
bindings: None,
});
} else {
let idx = -isize::try_from(rgen.len() + 1).unwrap();
rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
res.push(RenderType {
id: Some(RenderTypeId::Index(idx)),
generics: None,
bindings: None,
});
}
} else if let Type::ImplTrait(ref bounds) = *arg {
let mut type_bounds = Vec::new();
for bound in bounds {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut type_bounds,
rgen,
is_return,
cache,
);
}
}
if is_return && !type_bounds.is_empty() {
// In parameter position, `impl Trait` is a unique thing.
res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
} else {
// In parameter position, `impl Trait` is the same as an unnamed generic parameter.
let idx = -isize::try_from(rgen.len() + 1).unwrap();
rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
res.push(RenderType {
id: Some(RenderTypeId::Index(idx)),
generics: None,
bindings: None,
});
}
} else if let Type::Slice(ref ty) = *arg {
let mut ty_generics = Vec::new();
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut ty_generics,
rgen,
is_return,
cache,
);
res.push(get_index_type(arg, ty_generics, rgen));
} else if let Type::Array(ref ty, _) = *arg {
let mut ty_generics = Vec::new();
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut ty_generics,
rgen,
is_return,
cache,
);
res.push(get_index_type(arg, ty_generics, rgen));
} else if let Type::Tuple(ref tys) = *arg {
let mut ty_generics = Vec::new();
for ty in tys {
Type::Slice(ref ty) => {
let mut ty_generics = Vec::new();
simplify_fn_type(
self_,
generics,
@ -982,15 +960,14 @@ fn simplify_fn_type<'tcx, 'a>(
is_return,
cache,
);
res.push(get_index_type(arg, ty_generics, rgen));
}
res.push(get_index_type(arg, ty_generics, rgen));
} else if let Type::BareFunction(ref bf) = *arg {
let mut ty_generics = Vec::new();
for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
Type::Array(ref ty, _) => {
let mut ty_generics = Vec::new();
simplify_fn_type(
self_,
generics,
ty,
&ty,
tcx,
recurse + 1,
&mut ty_generics,
@ -998,62 +975,11 @@ fn simplify_fn_type<'tcx, 'a>(
is_return,
cache,
);
res.push(get_index_type(arg, ty_generics, rgen));
}
// The search index, for simplicity's sake, represents fn pointers and closures
// the same way: as a tuple for the parameters, and an associated type for the
// return type.
let mut ty_output = Vec::new();
simplify_fn_type(
self_,
generics,
&bf.decl.output,
tcx,
recurse + 1,
&mut ty_output,
rgen,
is_return,
cache,
);
let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
res.push(RenderType {
id: get_index_type_id(&arg, rgen),
bindings: Some(ty_bindings),
generics: Some(ty_generics),
});
} else if let Type::BorrowedRef { lifetime: _, mutability, ref type_ } = *arg {
let mut ty_generics = Vec::new();
if mutability.is_mut() {
ty_generics.push(RenderType {
id: Some(RenderTypeId::Mut),
generics: None,
bindings: None,
});
}
simplify_fn_type(
self_,
generics,
&type_,
tcx,
recurse + 1,
&mut ty_generics,
rgen,
is_return,
cache,
);
res.push(get_index_type(arg, ty_generics, rgen));
} else {
// This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
// looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
//
// So in here, we can add it directly and look for its own type parameters (so for `Option`,
// we will look for them but not for `T`).
let mut ty_generics = Vec::new();
let mut ty_constraints = Vec::new();
if let Some(arg_generics) = arg.generic_args() {
for ty in arg_generics.into_iter().filter_map(|param| match param {
clean::GenericArg::Type(ty) => Some(ty),
_ => None,
}) {
Type::Tuple(ref tys) => {
let mut ty_generics = Vec::new();
for ty in tys {
simplify_fn_type(
self_,
generics,
@ -1066,94 +992,181 @@ fn simplify_fn_type<'tcx, 'a>(
cache,
);
}
for constraint in arg_generics.constraints() {
simplify_fn_constraint(
res.push(get_index_type(arg, ty_generics, rgen));
}
Type::BareFunction(ref bf) => {
let mut ty_generics = Vec::new();
for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
simplify_fn_type(
self_,
generics,
&constraint,
ty,
tcx,
recurse + 1,
&mut ty_constraints,
&mut ty_generics,
rgen,
is_return,
cache,
);
}
// The search index, for simplicity's sake, represents fn pointers and closures
// the same way: as a tuple for the parameters, and an associated type for the
// return type.
let mut ty_output = Vec::new();
simplify_fn_type(
self_,
generics,
&bf.decl.output,
tcx,
recurse + 1,
&mut ty_output,
rgen,
is_return,
cache,
);
let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
res.push(RenderType {
id: get_index_type_id(&arg, rgen),
bindings: Some(ty_bindings),
generics: Some(ty_generics),
});
}
// Every trait associated type on self gets assigned to a type parameter index
// this same one is used later for any appearances of these types
//
// for example, Iterator::next is:
//
// trait Iterator {
// fn next(&mut self) -> Option<Self::Item>
// }
//
// Self is technically just Iterator, but we want to pretend it's more like this:
//
// fn next<T>(self: Iterator<Item=T>) -> Option<T>
if is_self
&& let Type::Path { path } = arg
&& let def_id = path.def_id()
&& let Some(trait_) = cache.traits.get(&def_id)
&& trait_.items.iter().any(|at| at.is_ty_associated_type())
{
for assoc_ty in &trait_.items {
if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind
&& let Some(name) = assoc_ty.name
{
let idx = -isize::try_from(rgen.len() + 1).unwrap();
let (idx, stored_bounds) = rgen
.entry(SimplifiedParam::AssociatedType(def_id, name))
.or_insert_with(|| (idx, Vec::new()));
let idx = *idx;
if stored_bounds.is_empty() {
// Can't just pass stored_bounds to simplify_fn_type,
// because it also accepts rgen as a parameter.
// Instead, have it fill in this local, then copy it into the map afterward.
let mut type_bounds = Vec::new();
for bound in bounds {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut type_bounds,
rgen,
is_return,
cache,
);
}
}
let stored_bounds = &mut rgen
.get_mut(&SimplifiedParam::AssociatedType(def_id, name))
.unwrap()
.1;
if stored_bounds.is_empty() {
*stored_bounds = type_bounds;
}
}
ty_constraints.push((
RenderTypeId::AssociatedType(name),
vec![RenderType {
id: Some(RenderTypeId::Index(idx)),
generics: None,
bindings: None,
}],
))
Type::BorrowedRef { lifetime: _, mutability, ref type_ } => {
let mut ty_generics = Vec::new();
if mutability.is_mut() {
ty_generics.push(RenderType {
id: Some(RenderTypeId::Mut),
generics: None,
bindings: None,
});
}
simplify_fn_type(
self_,
generics,
&type_,
tcx,
recurse + 1,
&mut ty_generics,
rgen,
is_return,
cache,
);
res.push(get_index_type(arg, ty_generics, rgen));
}
_ => {
// This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
// looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
//
// So in here, we can add it directly and look for its own type parameters (so for `Option`,
// we will look for them but not for `T`).
let mut ty_generics = Vec::new();
let mut ty_constraints = Vec::new();
if let Some(arg_generics) = arg.generic_args() {
for ty in arg_generics.into_iter().filter_map(|param| match param {
clean::GenericArg::Type(ty) => Some(ty),
_ => None,
}) {
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut ty_generics,
rgen,
is_return,
cache,
);
}
for constraint in arg_generics.constraints() {
simplify_fn_constraint(
self_,
generics,
&constraint,
tcx,
recurse + 1,
&mut ty_constraints,
rgen,
is_return,
cache,
);
}
}
}
let id = get_index_type_id(&arg, rgen);
if id.is_some() || !ty_generics.is_empty() {
res.push(RenderType {
id,
bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
});
// Every trait associated type on self gets assigned to a type parameter index
// this same one is used later for any appearances of these types
//
// for example, Iterator::next is:
//
// trait Iterator {
// fn next(&mut self) -> Option<Self::Item>
// }
//
// Self is technically just Iterator, but we want to pretend it's more like this:
//
// fn next<T>(self: Iterator<Item=T>) -> Option<T>
if is_self
&& let Type::Path { path } = arg
&& let def_id = path.def_id()
&& let Some(trait_) = cache.traits.get(&def_id)
&& trait_.items.iter().any(|at| at.is_ty_associated_type())
{
for assoc_ty in &trait_.items {
if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind
&& let Some(name) = assoc_ty.name
{
let idx = -isize::try_from(rgen.len() + 1).unwrap();
let (idx, stored_bounds) = rgen
.entry(SimplifiedParam::AssociatedType(def_id, name))
.or_insert_with(|| (idx, Vec::new()));
let idx = *idx;
if stored_bounds.is_empty() {
// Can't just pass stored_bounds to simplify_fn_type,
// because it also accepts rgen as a parameter.
// Instead, have it fill in this local, then copy it into the map afterward.
let mut type_bounds = Vec::new();
for bound in bounds {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut type_bounds,
rgen,
is_return,
cache,
);
}
}
let stored_bounds = &mut rgen
.get_mut(&SimplifiedParam::AssociatedType(def_id, name))
.unwrap()
.1;
if stored_bounds.is_empty() {
*stored_bounds = type_bounds;
}
}
ty_constraints.push((
RenderTypeId::AssociatedType(name),
vec![RenderType {
id: Some(RenderTypeId::Index(idx)),
generics: None,
bindings: None,
}],
))
}
}
}
let id = get_index_type_id(&arg, rgen);
if id.is_some() || !ty_generics.is_empty() {
res.push(RenderType {
id,
bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
});
}
}
}
}

View file

@ -578,7 +578,7 @@ impl FromWithTcx<clean::Type> for Type {
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
use clean::Type::{
Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
RawPointer, Slice, Tuple,
RawPointer, SelfTy, Slice, Tuple,
};
match ty {
@ -588,6 +588,8 @@ impl FromWithTcx<clean::Type> for Type {
traits: bounds.into_tcx(tcx),
}),
Generic(s) => Type::Generic(s.to_string()),
// FIXME: add dedicated variant to json Type?
SelfTy => Type::Generic("Self".to_owned()),
Primitive(p) => Type::Primitive(p.as_sym().to_string()),
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
Tuple(t) => Type::Tuple(t.into_tcx(tcx)),

View file

@ -216,13 +216,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
fn after_krate(&mut self) -> Result<(), Error> {
debug!("Done with crate");
debug!("Adding Primitive impls");
for primitive in Rc::clone(&self.cache).primitive_locations.values() {
self.get_impls(*primitive);
}
let e = ExternalCrate { crate_num: LOCAL_CRATE };
let index = (*self.index).clone().into_inner();
debug!("Constructing Output");

View file

@ -141,6 +141,7 @@ static TARGETS: &[&str] = &[
"riscv64gc-unknown-hermit",
"riscv64gc-unknown-none-elf",
"riscv64gc-unknown-linux-gnu",
"riscv64gc-unknown-linux-musl",
"s390x-unknown-linux-gnu",
"sparc64-unknown-linux-gnu",
"sparcv9-sun-solaris",

View file

@ -1 +1 @@
29e924841f06bb181d87494eba2783761bc1ddec
c9687a95a602091777e28703aa5abf20f1ce1797

View file

@ -33,7 +33,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let this = self.eval_context_mut();
// See if the core engine can handle this intrinsic.
if this.emulate_intrinsic(instance, args, dest, ret)? {
if this.eval_intrinsic(instance, args, dest, ret)? {
return Ok(None);
}
let intrinsic_name = this.tcx.item_name(instance.def_id());

View file

@ -1,6 +1,5 @@
use std::path::PathBuf;
use super::cygpath::get_windows_path;
use crate::artifact_names::{dynamic_lib_name, static_lib_name};
use crate::external_deps::cc::{cc, cxx};
use crate::external_deps::llvm::llvm_ar;
@ -44,8 +43,7 @@ pub fn build_native_dynamic_lib(lib_name: &str) -> PathBuf {
};
let obj_file = if is_msvc() { format!("{lib_name}.obj") } else { format!("{lib_name}.o") };
if is_msvc() {
let mut out_arg = "-out:".to_owned();
out_arg.push_str(&get_windows_path(&lib_path));
let out_arg = format!("-out:{lib_path}");
cc().input(&obj_file).args(&["-link", "-dll", &out_arg]).run();
} else if is_darwin() {
cc().out_exe(&lib_path).input(&obj_file).args(&["-dynamiclib", "-Wl,-dylib"]).run();

View file

@ -1,7 +1,5 @@
use std::path::Path;
// FIXME(jieyouxu): can we get rid of the `cygpath` external dependency?
use super::cygpath::get_windows_path;
use crate::command::Command;
use crate::{env_var, is_msvc, is_windows, uname};
@ -97,12 +95,12 @@ impl Cc {
if is_msvc() {
path.set_extension("exe");
let fe_path = get_windows_path(&path);
let fe_path = path.clone();
path.set_extension("");
path.set_extension("obj");
let fo_path = get_windows_path(path);
self.cmd.arg(format!("-Fe:{fe_path}"));
self.cmd.arg(format!("-Fo:{fo_path}"));
let fo_path = path;
self.cmd.arg(format!("-Fe:{}", fe_path.to_str().unwrap()));
self.cmd.arg(format!("-Fo:{}", fo_path.to_str().unwrap()));
} else {
self.cmd.arg("-o");
self.cmd.arg(name);

View file

@ -1,35 +0,0 @@
use std::panic;
use std::path::Path;
use crate::command::Command;
use crate::util::handle_failed_output;
/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
/// available on the platform!
///
/// # FIXME
///
/// FIXME(jieyouxu): we should consider not depending on `cygpath`.
///
/// > The cygpath program is a utility that converts Windows native filenames to Cygwin POSIX-style
/// > pathnames and vice versa.
/// >
/// > [irrelevant entries omitted...]
/// >
/// > `-w, --windows print Windows form of NAMEs (C:\WINNT)`
/// >
/// > -- *from [cygpath documentation](https://cygwin.com/cygwin-ug-net/cygpath.html)*.
#[track_caller]
#[must_use]
pub fn get_windows_path<P: AsRef<Path>>(path: P) -> String {
let caller = panic::Location::caller();
let mut cygpath = Command::new("cygpath");
cygpath.arg("-w");
cygpath.arg(path.as_ref());
let output = cygpath.run();
if !output.status().success() {
handle_failed_output(&cygpath, output, caller.line());
}
// cygpath -w can attach a newline
output.stdout_utf8().trim().to_string()
}

View file

@ -151,7 +151,8 @@ impl LlvmReadobj {
self
}
/// Pass `--symbols` to display the symbol.
/// Pass `--symbols` to display the symbol table, including both local
/// and global symbols.
pub fn symbols(&mut self) -> &mut Self {
self.cmd.arg("--symbols");
self

View file

@ -9,6 +9,3 @@ pub mod llvm;
pub mod python;
pub mod rustc;
pub mod rustdoc;
// Library-internal external dependency.
mod cygpath;

View file

@ -9,11 +9,19 @@ pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
if link.as_ref().exists() {
std::fs::remove_dir(link.as_ref()).unwrap();
}
std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
"failed to create symlink {:?} for {:?}",
link.as_ref().display(),
original.as_ref().display(),
));
if original.as_ref().is_file() {
std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
"failed to create symlink {:?} for {:?}",
link.as_ref().display(),
original.as_ref().display(),
));
} else {
std::os::windows::fs::symlink_dir(original.as_ref(), link.as_ref()).expect(&format!(
"failed to create symlink {:?} for {:?}",
link.as_ref().display(),
original.as_ref().display(),
));
}
}
/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix.
@ -41,6 +49,8 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
let ty = entry.file_type()?;
if ty.is_dir() {
copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
} else if ty.is_symlink() {
copy_symlink(entry.path(), dst.join(entry.file_name()))?;
} else {
std::fs::copy(entry.path(), dst.join(entry.file_name()))?;
}
@ -59,6 +69,12 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
}
}
fn copy_symlink<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
let target_path = std::fs::read_link(from).unwrap();
create_symlink(target_path, to);
Ok(())
}
/// Helper for reading entries in a given directory.
pub fn read_dir_entries<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, mut callback: F) {
for entry in read_dir(dir) {

View file

@ -27,12 +27,10 @@ run-make/raw-dylib-alt-calling-convention/Makefile
run-make/raw-dylib-c/Makefile
run-make/redundant-libs/Makefile
run-make/remap-path-prefix-dwarf/Makefile
run-make/reproducible-build-2/Makefile
run-make/reproducible-build/Makefile
run-make/rlib-format-packed-bundled-libs/Makefile
run-make/simd-ffi/Makefile
run-make/split-debuginfo/Makefile
run-make/stable-symbol-names/Makefile
run-make/staticlib-dylib-linkage/Makefile
run-make/symbol-mangling-hashed/Makefile
run-make/sysroot-crates-are-unstable/Makefile

14
tests/crashes/128094.rs Normal file
View file

@ -0,0 +1,14 @@
//@ known-bug: rust-lang/rust#128094
//@ compile-flags: -Zmir-opt-level=5 --edition=2018
pub enum Request {
TestSome(T),
}
pub async fn handle_event(event: Request) {
async move {
static instance: Request = Request { bar: 17 };
&instance
}
.await;
}

13
tests/crashes/128176.rs Normal file
View file

@ -0,0 +1,13 @@
//@ known-bug: rust-lang/rust#128176
#![feature(generic_const_exprs)]
#![feature(object_safe_for_dispatch)]
trait X {
type Y<const N: i16>;
}
const _: () = {
fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
};
fn main() {}

7
tests/crashes/128190.rs Normal file
View file

@ -0,0 +1,7 @@
//@ known-bug: rust-lang/rust#128190
fn a(&self) {
15
}
reuse a as b { struct S; }

5
tests/crashes/128327.rs Normal file
View file

@ -0,0 +1,5 @@
//@ known-bug: rust-lang/rust#128327
use std::ops::Deref;
struct Apple((Apple, <&'static [f64] as Deref>::Target(Banana ? Citron)));
fn main(){}

13
tests/crashes/128346.rs Normal file
View file

@ -0,0 +1,13 @@
//@ known-bug: rust-lang/rust#128346
macro_rules! one_rep {
( $($a:ident)* ) => {
A(
const ${concat($a, Z)}: i32 = 3;
)*
};
}
fn main() {
one_rep!(A B C);
}

View file

@ -22,6 +22,18 @@ fn direct_call(x: i32) -> i32 {
}
}
// EMIT_MIR terminators.tail_call.built.after.mir
#[custom_mir(dialect = "built")]
fn tail_call(x: i32) -> i32 {
mir! {
let y;
{
y = x + 42;
TailCall(ident(y))
}
}
}
// EMIT_MIR terminators.indirect_call.built.after.mir
#[custom_mir(dialect = "built")]
fn indirect_call(x: i32, f: fn(i32) -> i32) -> i32 {

View file

@ -0,0 +1,11 @@
// MIR for `tail_call` after built
fn tail_call(_1: i32) -> i32 {
let mut _0: i32;
let mut _2: i32;
bb0: {
_2 = Add(_1, const 42_i32);
tailcall ident::<i32>(Spanned { node: _2, span: $DIR/terminators.rs:32:28: 32:29 (#0) });
}
}

View file

@ -1,27 +0,0 @@
# ignore-cross-compile
include ../tools.mk
# ignore-musl
# ignore-windows
# Objects are reproducible but their path is not.
all: \
fat_lto \
sysroot
fat_lto:
rm -rf $(TMPDIR) && mkdir $(TMPDIR)
$(RUSTC) reproducible-build-aux.rs
$(RUSTC) reproducible-build.rs -C lto=fat
cp $(TMPDIR)/reproducible-build $(TMPDIR)/reproducible-build-a
$(RUSTC) reproducible-build.rs -C lto=fat
cmp "$(TMPDIR)/reproducible-build-a" "$(TMPDIR)/reproducible-build" || exit 1
sysroot:
rm -rf $(TMPDIR) && mkdir $(TMPDIR)
$(RUSTC) reproducible-build-aux.rs
$(RUSTC) reproducible-build.rs --crate-type rlib --sysroot $(shell $(RUSTC) --print sysroot) --remap-path-prefix=$(shell $(RUSTC) --print sysroot)=/sysroot
cp -R $(shell $(RUSTC) --print sysroot) $(TMPDIR)/sysroot
cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfoo.rlib
$(RUSTC) reproducible-build.rs --crate-type rlib --sysroot $(TMPDIR)/sysroot --remap-path-prefix=$(TMPDIR)/sysroot=/sysroot
cmp "$(TMPDIR)/libreproducible_build.rlib" "$(TMPDIR)/libfoo.rlib" || exit 1

View file

@ -0,0 +1,47 @@
// Builds with fat link-time-optimizations and the --sysroot flag used to be
// non-deterministic - that means, compiling twice with no changes would create
// slightly different outputs. This has been fixed by #63352 and #63505.
// Test 1: Compile with fat-lto twice, check that both compilation outputs are identical.
// Test 2: Compile with sysroot, then change the sysroot path from absolute to relative.
// Outputs should be identical.
// See https://github.com/rust-lang/rust/issues/34902
//@ ignore-windows
// Reasons:
// 1. The object files are reproducible, but their paths are not, which causes
// the first assertion in the test to fail.
// 2. When the sysroot gets copied, some symlinks must be re-created,
// which is a privileged action on Windows.
use run_make_support::{bin_name, rfs, rust_lib_name, rustc};
fn main() {
// test 1: fat lto
rustc().input("reproducible-build-aux.rs").run();
rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run();
rfs::rename("reproducible-build", "reproducible-build-a");
rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run();
assert_eq!(rfs::read("reproducible-build"), rfs::read("reproducible-build-a"));
// test 2: sysroot
let sysroot = rustc().print("sysroot").run().stdout_utf8();
let sysroot = sysroot.trim();
rustc().input("reproducible-build-aux.rs").run();
rustc()
.input("reproducible-build.rs")
.crate_type("rlib")
.sysroot(&sysroot)
.arg(format!("--remap-path-prefix={sysroot}=/sysroot"))
.run();
rfs::copy_dir_all(&sysroot, "sysroot");
rfs::rename(rust_lib_name("reproducible_build"), rust_lib_name("foo"));
rustc()
.input("reproducible-build.rs")
.crate_type("rlib")
.sysroot("sysroot")
.arg("--remap-path-prefix=/sysroot=/sysroot")
.run();
assert_eq!(rfs::read(rust_lib_name("reproducible_build")), rfs::read(rust_lib_name("foo")));
}

View file

@ -1,41 +0,0 @@
include ../tools.mk
# The following command will:
# 1. dump the symbols of a library using `nm`
# 2. extract only those lines that we are interested in via `grep`
# 3. from those lines, extract just the symbol name via `sed`, which:
# * always starts with "_ZN" and ends with "E" (`legacy` mangling)
# * always starts with "_R" (`v0` mangling)
# 4. sort those symbol names for deterministic comparison
# 5. write the result into a file
dump-symbols = nm "$(TMPDIR)/lib$(1).rlib" \
| grep -E "$(2)" \
| sed -E "s/.*(_ZN.*E|_R[a-zA-Z0-9_]*).*/\1/" \
| sort \
> "$(TMPDIR)/$(1)$(3).nm"
# This test
# - compiles each of the two crates 2 times and makes sure each time we get
# exactly the same symbol names
# - makes sure that both crates agree on the same symbol names for monomorphic
# functions
all:
$(RUSTC) stable-symbol-names1.rs
$(call dump-symbols,stable_symbol_names1,generic_|mono_,_v1)
rm $(TMPDIR)/libstable_symbol_names1.rlib
$(RUSTC) stable-symbol-names1.rs
$(call dump-symbols,stable_symbol_names1,generic_|mono_,_v2)
cmp "$(TMPDIR)/stable_symbol_names1_v1.nm" "$(TMPDIR)/stable_symbol_names1_v2.nm"
$(RUSTC) stable-symbol-names2.rs
$(call dump-symbols,stable_symbol_names2,generic_|mono_,_v1)
rm $(TMPDIR)/libstable_symbol_names2.rlib
$(RUSTC) stable-symbol-names2.rs
$(call dump-symbols,stable_symbol_names2,generic_|mono_,_v2)
cmp "$(TMPDIR)/stable_symbol_names2_v1.nm" "$(TMPDIR)/stable_symbol_names2_v2.nm"
$(call dump-symbols,stable_symbol_names1,mono_,_cross)
$(call dump-symbols,stable_symbol_names2,mono_,_cross)
cmp "$(TMPDIR)/stable_symbol_names1_cross.nm" "$(TMPDIR)/stable_symbol_names2_cross.nm"

View file

@ -0,0 +1,68 @@
// A typo in rustc caused generic symbol names to be non-deterministic -
// that is, it was possible to compile the same file twice with no changes
// and get outputs with different symbol names.
// This test compiles each of the two crates twice, and checks that each output
// contains exactly the same symbol names.
// Additionally, both crates should agree on the same symbol names for monomorphic
// functions.
// See https://github.com/rust-lang/rust/issues/32554
use std::collections::HashSet;
use run_make_support::{llvm_readobj, regex, rfs, rust_lib_name, rustc};
static LEGACY_PATTERN: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
static V0_PATTERN: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
fn main() {
LEGACY_PATTERN.set(regex::Regex::new(r"_ZN.*E").unwrap()).unwrap();
V0_PATTERN.set(regex::Regex::new(r"_R[a-zA-Z0-9_]*").unwrap()).unwrap();
// test 1: first file
rustc().input("stable-symbol-names1.rs").run();
let sym1 = process_symbols("stable_symbol_names1", "generic_|mono_");
rfs::remove_file(rust_lib_name("stable_symbol_names1"));
rustc().input("stable-symbol-names1.rs").run();
let sym2 = process_symbols("stable_symbol_names1", "generic_|mono_");
assert_eq!(sym1, sym2);
// test 2: second file
rustc().input("stable-symbol-names2.rs").run();
let sym1 = process_symbols("stable_symbol_names2", "generic_|mono_");
rfs::remove_file(rust_lib_name("stable_symbol_names2"));
rustc().input("stable-symbol-names2.rs").run();
let sym2 = process_symbols("stable_symbol_names2", "generic_|mono_");
assert_eq!(sym1, sym2);
// test 3: crossed files
let sym1 = process_symbols("stable_symbol_names1", "mono_");
let sym2 = process_symbols("stable_symbol_names2", "mono_");
assert_eq!(sym1, sym2);
}
#[track_caller]
fn process_symbols(path: &str, symbol: &str) -> Vec<String> {
// Dump all symbols.
let out = llvm_readobj().input(rust_lib_name(path)).symbols().run().stdout_utf8();
// Extract only lines containing `symbol`.
let symbol_regex = regex::Regex::new(symbol).unwrap();
let out = out.lines().filter(|&line| symbol_regex.find(line).is_some());
// HashSet - duplicates should be excluded!
let mut symbols: HashSet<String> = HashSet::new();
// From those lines, extract just the symbol name via `regex`, which:
// * always starts with "_ZN" and ends with "E" (`legacy` mangling)
// * always starts with "_R" (`v0` mangling)
for line in out {
if let Some(mat) = LEGACY_PATTERN.get().unwrap().find(line) {
symbols.insert(mat.as_str().to_string());
}
if let Some(mat) = V0_PATTERN.get().unwrap().find(line) {
symbols.insert(mat.as_str().to_string());
}
}
let mut symbols: Vec<String> = symbols.into_iter().collect();
// Sort those symbol names for deterministic comparison.
symbols.sort();
symbols
}

View file

@ -4,12 +4,8 @@
// are exported, and that generics are only shown if explicitely requested.
// See https://github.com/rust-lang/rust/issues/37530
//@ ignore-windows-msvc
//FIXME(Oneirical): This currently uses llvm-nm for symbol detection. However,
// the custom Rust-based solution of #128314 may prove to be an interesting alternative.
use run_make_support::{bin_name, dynamic_lib_name, is_darwin, is_windows, llvm_nm, regex, rustc};
use run_make_support::object::read::Object;
use run_make_support::{bin_name, dynamic_lib_name, is_msvc, object, regex, rfs, rustc};
fn main() {
let cdylib_name = dynamic_lib_name("a_cdylib");
@ -64,16 +60,15 @@ fn main() {
);
// FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
// if is_windows() {
// // Check that an executable does not export any dynamic symbols
// symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib")
//, false);
// symbols_check(
// &exe_name,
// SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
// false,
// );
// }
if is_msvc() {
// Check that an executable does not export any dynamic symbols
symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), false);
symbols_check(
&exe_name,
SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
false,
);
}
// Check the combined case, where we generate a cdylib and an rlib in the same
// compilation session:
@ -131,44 +126,37 @@ fn main() {
);
// FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
// if is_windows() {
// // Check that an executable does not export any dynamic symbols
// symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib")
//, false);
// symbols_check(
// &exe_name,
// SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
// false,
// );
// }
if is_msvc() {
// Check that an executable does not export any dynamic symbols
symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), false);
symbols_check(
&exe_name,
SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
false,
);
}
}
#[track_caller]
fn symbols_check(path: &str, symbol_check_type: SymbolCheckType, exists_once: bool) {
let mut nm = llvm_nm();
if is_windows() {
nm.arg("--extern-only");
} else if is_darwin() {
nm.arg("--extern-only").arg("--defined-only");
} else {
nm.arg("--dynamic");
let binary_data = rfs::read(path);
let file = object::File::parse(&*binary_data).unwrap();
let mut found: u64 = 0;
for export in file.exports().unwrap() {
let name = std::str::from_utf8(export.name()).unwrap();
if has_symbol(name, symbol_check_type) {
found += 1;
}
}
let out = nm.input(path).run().stdout_utf8();
assert_eq!(
out.lines()
.filter(|&line| !line.contains("__imp_") && has_symbol(line, symbol_check_type))
.count()
== 1,
exists_once
);
assert_eq!(found, exists_once as u64);
}
fn has_symbol(line: &str, symbol_check_type: SymbolCheckType) -> bool {
fn has_symbol(name: &str, symbol_check_type: SymbolCheckType) -> bool {
if let SymbolCheckType::StrSymbol(expected) = symbol_check_type {
line.contains(expected)
name.contains(expected)
} else {
let regex = regex::Regex::new(r#"_ZN.*h.*E\|_R[a-zA-Z0-9_]+"#).unwrap();
regex.is_match(line)
regex.is_match(name)
}
}

View file

@ -0,0 +1,22 @@
// exact-check
const EXPECTED = [
{
'query': 'A -> A',
'others': [
{ 'path': 'self_is_not_generic::Thing', 'name': 'from' }
],
},
{
'query': 'A -> B',
'others': [
{ 'path': 'self_is_not_generic::Thing', 'name': 'try_from' }
],
},
{
'query': 'Combine -> Combine',
'others': [
{ 'path': 'self_is_not_generic::Combine', 'name': 'combine' }
],
}
];

View file

@ -0,0 +1,11 @@
pub trait Combine {
fn combine(&self, other: &Self) -> Self;
}
pub struct Thing;
impl Combine for Thing {
fn combine(&self, other: &Self) -> Self {
Self
}
}

View file

@ -0,0 +1,5 @@
// This test asserts that `index` is not polluted with unrelated items.
// See https://github.com/rust-lang/rust/issues/114039
//@ count "$.index[*]" 1
fn main() {}

View file

@ -15,15 +15,6 @@ fn main() {
unsafe {
// Inputs must be initialized
// Sym operands must point to a function or static
const C: i32 = 0;
static S: i32 = 0;
asm!("{}", sym S);
asm!("{}", sym main);
asm!("{}", sym C);
//~^ ERROR invalid `sym` operand
// Register operands must be Copy
asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
@ -65,12 +56,3 @@ fn main() {
asm!("{}", in(reg) u);
}
}
// Sym operands must point to a function or static
const C: i32 = 0;
static S: i32 = 0;
global_asm!("{}", sym S);
global_asm!("{}", sym main);
global_asm!("{}", sym C);
//~^ ERROR invalid `sym` operand

View file

@ -1,29 +1,13 @@
error: invalid `sym` operand
--> $DIR/type-check-2.rs:75:19
|
LL | global_asm!("{}", sym C);
| ^^^^^ is an `i32`
|
= help: `sym` operands must refer to either a function or a static
error: invalid `sym` operand
--> $DIR/type-check-2.rs:24:20
|
LL | asm!("{}", sym C);
| ^^^^^ is an `i32`
|
= help: `sym` operands must refer to either a function or a static
error: arguments for inline assembly must be copyable
--> $DIR/type-check-2.rs:29:31
--> $DIR/type-check-2.rs:20:31
|
LL | asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `SimdNonCopy` does not implement the Copy trait
error: cannot use value of type `{closure@$DIR/type-check-2.rs:41:28: 41:36}` for inline assembly
--> $DIR/type-check-2.rs:41:28
error: cannot use value of type `{closure@$DIR/type-check-2.rs:32:28: 32:36}` for inline assembly
--> $DIR/type-check-2.rs:32:28
|
LL | asm!("{}", in(reg) |x: i32| x);
| ^^^^^^^^^^
@ -31,7 +15,7 @@ LL | asm!("{}", in(reg) |x: i32| x);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `Vec<i32>` for inline assembly
--> $DIR/type-check-2.rs:43:28
--> $DIR/type-check-2.rs:34:28
|
LL | asm!("{}", in(reg) vec![0]);
| ^^^^^^^
@ -40,7 +24,7 @@ LL | asm!("{}", in(reg) vec![0]);
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error: cannot use value of type `(i32, i32, i32)` for inline assembly
--> $DIR/type-check-2.rs:45:28
--> $DIR/type-check-2.rs:36:28
|
LL | asm!("{}", in(reg) (1, 2, 3));
| ^^^^^^^^^
@ -48,7 +32,7 @@ LL | asm!("{}", in(reg) (1, 2, 3));
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `[i32; 3]` for inline assembly
--> $DIR/type-check-2.rs:47:28
--> $DIR/type-check-2.rs:38:28
|
LL | asm!("{}", in(reg) [1, 2, 3]);
| ^^^^^^^^^
@ -56,7 +40,7 @@ LL | asm!("{}", in(reg) [1, 2, 3]);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `fn() {main}` for inline assembly
--> $DIR/type-check-2.rs:55:31
--> $DIR/type-check-2.rs:46:31
|
LL | asm!("{}", inout(reg) f);
| ^
@ -64,12 +48,12 @@ LL | asm!("{}", inout(reg) f);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `&mut i32` for inline assembly
--> $DIR/type-check-2.rs:58:31
--> $DIR/type-check-2.rs:49:31
|
LL | asm!("{}", inout(reg) r);
| ^
|
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: aborting due to 9 previous errors
error: aborting due to 7 previous errors

View file

@ -0,0 +1,51 @@
//@ needs-asm-support
//@ ignore-nvptx64
//@ ignore-spirv
#![feature(asm_const)]
use std::arch::{asm, global_asm};
// Const operands must be integers and must be constants.
global_asm!("{}", const 0);
global_asm!("{}", const 0i32);
global_asm!("{}", const 0i128);
global_asm!("{}", const 0f32);
//~^ ERROR invalid type for `const` operand
global_asm!("{}", const 0 as *mut u8);
//~^ ERROR invalid type for `const` operand
fn main() {
unsafe {
// Const operands must be integers and must be constants.
asm!("{}", const 0);
asm!("{}", const 0i32);
asm!("{}", const 0i128);
asm!("{}", const 0f32);
//~^ ERROR invalid type for `const` operand
asm!("{}", const 0 as *mut u8);
//~^ ERROR invalid type for `const` operand
asm!("{}", const &0);
//~^ ERROR invalid type for `const` operand
// Constants must be... constant
let x = 0;
const fn const_foo(x: i32) -> i32 {
x
}
const fn const_bar<T>(x: T) -> T {
x
}
asm!("{}", const x);
//~^ ERROR attempt to use a non-constant value in a constant
asm!("{}", const const_foo(0));
asm!("{}", const const_foo(x));
//~^ ERROR attempt to use a non-constant value in a constant
asm!("{}", const const_bar(0));
asm!("{}", const const_bar(x));
//~^ ERROR attempt to use a non-constant value in a constant
}
}

View file

@ -0,0 +1,86 @@
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/invalid-const-operand.rs:42:26
|
LL | asm!("{}", const x);
| ^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const x: /* Type */ = 0;
| ~~~~~ ++++++++++++
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/invalid-const-operand.rs:45:36
|
LL | asm!("{}", const const_foo(x));
| ^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const x: /* Type */ = 0;
| ~~~~~ ++++++++++++
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/invalid-const-operand.rs:48:36
|
LL | asm!("{}", const const_bar(x));
| ^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const x: /* Type */ = 0;
| ~~~~~ ++++++++++++
error: invalid type for `const` operand
--> $DIR/invalid-const-operand.rs:14:19
|
LL | global_asm!("{}", const 0f32);
| ^^^^^^----
| |
| is an `f32`
|
= help: `const` operands must be of an integer type
error: invalid type for `const` operand
--> $DIR/invalid-const-operand.rs:16:19
|
LL | global_asm!("{}", const 0 as *mut u8);
| ^^^^^^------------
| |
| is a `*mut u8`
|
= help: `const` operands must be of an integer type
error: invalid type for `const` operand
--> $DIR/invalid-const-operand.rs:26:20
|
LL | asm!("{}", const 0f32);
| ^^^^^^----
| |
| is an `f32`
|
= help: `const` operands must be of an integer type
error: invalid type for `const` operand
--> $DIR/invalid-const-operand.rs:28:20
|
LL | asm!("{}", const 0 as *mut u8);
| ^^^^^^------------
| |
| is a `*mut u8`
|
= help: `const` operands must be of an integer type
error: invalid type for `const` operand
--> $DIR/invalid-const-operand.rs:30:20
|
LL | asm!("{}", const &0);
| ^^^^^^--
| |
| is a `&i32`
|
= help: `const` operands must be of an integer type
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0435`.

View file

@ -0,0 +1,34 @@
//@ needs-asm-support
//@ ignore-nvptx64
//@ ignore-spirv
use std::arch::{asm, global_asm};
// Sym operands must point to a function or static
const C: i32 = 0;
static S: i32 = 0;
global_asm!("{}", sym S);
global_asm!("{}", sym main);
global_asm!("{}", sym C);
//~^ ERROR invalid `sym` operand
fn main() {
unsafe {
// Sym operands must point to a function or static
let x: u64 = 0;
const C: i32 = 0;
static S: i32 = 0;
asm!("{}", sym S);
asm!("{}", sym main);
asm!("{}", sym C);
//~^ ERROR invalid `sym` operand
asm!("{}", sym x);
//~^ ERROR invalid `sym` operand
}
}
unsafe fn generic<T>() {
asm!("{}", sym generic::<T>);
}

View file

@ -0,0 +1,26 @@
error: invalid `sym` operand
--> $DIR/invalid-sym-operand.rs:27:24
|
LL | asm!("{}", sym x);
| ^ is a local variable
|
= help: `sym` operands must refer to either a function or a static
error: invalid `sym` operand
--> $DIR/invalid-sym-operand.rs:13:19
|
LL | global_asm!("{}", sym C);
| ^^^^^ is an `i32`
|
= help: `sym` operands must refer to either a function or a static
error: invalid `sym` operand
--> $DIR/invalid-sym-operand.rs:25:20
|
LL | asm!("{}", sym C);
| ^^^^^ is an `i32`
|
= help: `sym` operands must refer to either a function or a static
error: aborting due to 3 previous errors

View file

@ -28,51 +28,5 @@ fn main() {
asm!("{}", inout(reg) v[..]);
//~^ ERROR the size for values of type `[u64]` cannot be known at compilation time
//~| ERROR cannot use value of type `[u64]` for inline assembly
// Constants must be... constant
let x = 0;
const fn const_foo(x: i32) -> i32 {
x
}
const fn const_bar<T>(x: T) -> T {
x
}
asm!("{}", const x);
//~^ ERROR attempt to use a non-constant value in a constant
asm!("{}", const const_foo(0));
asm!("{}", const const_foo(x));
//~^ ERROR attempt to use a non-constant value in a constant
asm!("{}", const const_bar(0));
asm!("{}", const const_bar(x));
//~^ ERROR attempt to use a non-constant value in a constant
asm!("{}", sym x);
//~^ ERROR invalid `sym` operand
// Const operands must be integers and must be constants.
asm!("{}", const 0);
asm!("{}", const 0i32);
asm!("{}", const 0i128);
asm!("{}", const 0f32);
//~^ ERROR mismatched types
asm!("{}", const 0 as *mut u8);
//~^ ERROR mismatched types
asm!("{}", const &0);
//~^ ERROR mismatched types
}
}
unsafe fn generic<T>() {
asm!("{}", sym generic::<T>);
}
// Const operands must be integers and must be constants.
global_asm!("{}", const 0);
global_asm!("{}", const 0i32);
global_asm!("{}", const 0i128);
global_asm!("{}", const 0f32);
//~^ ERROR mismatched types
global_asm!("{}", const 0 as *mut u8);
//~^ ERROR mismatched types

View file

@ -1,44 +1,3 @@
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/type-check-1.rs:41:26
|
LL | asm!("{}", const x);
| ^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const x: /* Type */ = 0;
| ~~~~~ ++++++++++++
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/type-check-1.rs:44:36
|
LL | asm!("{}", const const_foo(x));
| ^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const x: /* Type */ = 0;
| ~~~~~ ++++++++++++
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/type-check-1.rs:47:36
|
LL | asm!("{}", const const_bar(x));
| ^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const x: /* Type */ = 0;
| ~~~~~ ++++++++++++
error: invalid `sym` operand
--> $DIR/type-check-1.rs:49:24
|
LL | asm!("{}", sym x);
| ^ is a local variable
|
= help: `sym` operands must refer to either a function or a static
error: invalid asm output
--> $DIR/type-check-1.rs:14:29
|
@ -102,49 +61,6 @@ LL | asm!("{}", inout(reg) v[..]);
|
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error[E0308]: mismatched types
--> $DIR/type-check-1.rs:57:26
|
LL | asm!("{}", const 0f32);
| ^^^^ expected integer, found `f32`
error: aborting due to 8 previous errors
error[E0308]: mismatched types
--> $DIR/type-check-1.rs:59:26
|
LL | asm!("{}", const 0 as *mut u8);
| ^^^^^^^^^^^^ expected integer, found `*mut u8`
|
= note: expected type `{integer}`
found raw pointer `*mut u8`
error[E0308]: mismatched types
--> $DIR/type-check-1.rs:61:26
|
LL | asm!("{}", const &0);
| ^^ expected integer, found `&{integer}`
|
help: consider removing the borrow
|
LL - asm!("{}", const &0);
LL + asm!("{}", const 0);
|
error[E0308]: mismatched types
--> $DIR/type-check-1.rs:75:25
|
LL | global_asm!("{}", const 0f32);
| ^^^^ expected integer, found `f32`
error[E0308]: mismatched types
--> $DIR/type-check-1.rs:77:25
|
LL | global_asm!("{}", const 0 as *mut u8);
| ^^^^^^^^^^^^ expected integer, found `*mut u8`
|
= note: expected type `{integer}`
found raw pointer `*mut u8`
error: aborting due to 17 previous errors
Some errors have detailed explanations: E0277, E0308, E0435.
For more information about an error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0277`.

View file

@ -27,17 +27,6 @@ fn main() {
asm!("{}", out(reg) v[0]);
asm!("{}", inout(reg) v[0]);
// Sym operands must point to a function or static
const C: i32 = 0;
static S: i32 = 0;
asm!("{}", sym S);
asm!("{}", sym main);
asm!("{}", sym C);
//~^ ERROR invalid `sym` operand
asm!("{}", sym x);
//~^ ERROR invalid `sym` operand
// Register operands must be Copy
asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
@ -79,12 +68,3 @@ fn main() {
asm!("{}", in(reg) u);
}
}
// Sym operands must point to a function or static
const C: i32 = 0;
static S: i32 = 0;
global_asm!("{}", sym S);
global_asm!("{}", sym main);
global_asm!("{}", sym C);
//~^ ERROR invalid `sym` operand

View file

@ -1,37 +1,13 @@
error: invalid `sym` operand
--> $DIR/type-check-2.rs:38:24
|
LL | asm!("{}", sym x);
| ^ is a local variable
|
= help: `sym` operands must refer to either a function or a static
error: invalid `sym` operand
--> $DIR/type-check-2.rs:89:19
|
LL | global_asm!("{}", sym C);
| ^^^^^ is an `i32`
|
= help: `sym` operands must refer to either a function or a static
error: invalid `sym` operand
--> $DIR/type-check-2.rs:36:20
|
LL | asm!("{}", sym C);
| ^^^^^ is an `i32`
|
= help: `sym` operands must refer to either a function or a static
error: arguments for inline assembly must be copyable
--> $DIR/type-check-2.rs:43:32
--> $DIR/type-check-2.rs:32:32
|
LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `SimdNonCopy` does not implement the Copy trait
error: cannot use value of type `{closure@$DIR/type-check-2.rs:55:28: 55:36}` for inline assembly
--> $DIR/type-check-2.rs:55:28
error: cannot use value of type `{closure@$DIR/type-check-2.rs:44:28: 44:36}` for inline assembly
--> $DIR/type-check-2.rs:44:28
|
LL | asm!("{}", in(reg) |x: i32| x);
| ^^^^^^^^^^
@ -39,7 +15,7 @@ LL | asm!("{}", in(reg) |x: i32| x);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `Vec<i32>` for inline assembly
--> $DIR/type-check-2.rs:57:28
--> $DIR/type-check-2.rs:46:28
|
LL | asm!("{}", in(reg) vec![0]);
| ^^^^^^^
@ -48,7 +24,7 @@ LL | asm!("{}", in(reg) vec![0]);
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error: cannot use value of type `(i32, i32, i32)` for inline assembly
--> $DIR/type-check-2.rs:59:28
--> $DIR/type-check-2.rs:48:28
|
LL | asm!("{}", in(reg) (1, 2, 3));
| ^^^^^^^^^
@ -56,7 +32,7 @@ LL | asm!("{}", in(reg) (1, 2, 3));
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `[i32; 3]` for inline assembly
--> $DIR/type-check-2.rs:61:28
--> $DIR/type-check-2.rs:50:28
|
LL | asm!("{}", in(reg) [1, 2, 3]);
| ^^^^^^^^^
@ -64,7 +40,7 @@ LL | asm!("{}", in(reg) [1, 2, 3]);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `fn() {main}` for inline assembly
--> $DIR/type-check-2.rs:69:31
--> $DIR/type-check-2.rs:58:31
|
LL | asm!("{}", inout(reg) f);
| ^
@ -72,7 +48,7 @@ LL | asm!("{}", inout(reg) f);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `&mut i32` for inline assembly
--> $DIR/type-check-2.rs:72:31
--> $DIR/type-check-2.rs:61:31
|
LL | asm!("{}", inout(reg) r);
| ^
@ -121,7 +97,7 @@ help: consider changing this to be mutable
LL | let mut v: Vec<u64> = vec![0, 1, 2];
| +++
error: aborting due to 13 previous errors
error: aborting due to 10 previous errors
Some errors have detailed explanations: E0381, E0596.
For more information about an error, try `rustc --explain E0381`.

View file

@ -0,0 +1,21 @@
//@ check-pass
trait Trait {
type Associated;
}
impl Trait for i32 {
type Associated = i64;
}
trait Generic<T> {}
type TraitObject = dyn Generic<<i32 as Trait>::Associated>;
struct Wrap(TraitObject);
fn cast(x: *mut TraitObject) {
x as *mut Wrap;
}
fn main() {}

View file

@ -1,4 +1,4 @@
error: internal compiler error: compiler/rustc_const_eval/src/interpret/step.rs:LL:CC: SizeOf MIR operator called for unsized type dyn Debug
error: internal compiler error: compiler/rustc_const_eval/src/interpret/operator.rs:LL:CC: unsized type for `NullaryOp::SizeOf`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
Box<dyn Any>

View file

@ -5,6 +5,7 @@ trait Trait<'a>: 'a {
// if the `T: 'a` bound gets implied we would probably get ub here again
impl<'a, T> Trait<'a> for T {
//~^ ERROR the parameter type `T` may not live long enough
//~| ERROR the parameter type `T` may not live long enough
type Type = ();
}

View file

@ -16,8 +16,21 @@ help: consider adding an explicit lifetime bound
LL | impl<'a, T: 'a> Trait<'a> for T {
| ++++
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/implied-bounds-unnorm-associated-type-5.rs:6:27
|
LL | impl<'a, T> Trait<'a> for T {
| -- ^ ...so that the type `T` will meet its required lifetime bounds
| |
| the parameter type `T` must be valid for the lifetime `'a` as defined here...
|
help: consider adding an explicit lifetime bound
|
LL | impl<'a, T: 'a> Trait<'a> for T {
| ++++
error[E0505]: cannot move out of `x` because it is borrowed
--> $DIR/implied-bounds-unnorm-associated-type-5.rs:21:10
--> $DIR/implied-bounds-unnorm-associated-type-5.rs:22:10
|
LL | let x = String::from("Hello World!");
| - binding `x` declared here
@ -33,7 +46,7 @@ help: consider cloning the value if the performance cost is acceptable
LL | let y = f(&x.clone(), ());
| ++++++++
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0309, E0505.
For more information about an error, try `rustc --explain E0309`.

View file

@ -0,0 +1,44 @@
//@ needs-sanitizer-cfi
//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
//@ no-prefer-dynamic
//@ only-x86_64-unknown-linux-gnu
//@ build-pass
// See comment below for why this test exists.
trait Tr<U> {
type Projection;
}
impl<F, U> Tr<U> for F
where
F: Fn() -> U
{
type Projection = U;
}
fn test<B: Tr<U>, U>(b: B) -> B::Projection
{
todo!()
}
fn main() {
fn rpit_fn() -> impl Sized {}
// When CFI runs, it tries to compute the signature of the call. This
// ends up giving us a signature of:
// `fn test::<rpit_fn, ()>() -> <rpit_fn as Tr<()>>::Projection`,
// where `rpit_fn` is the ZST FnDef for the function. However, we were
// previously using a Reveal::UserFacing param-env. This means that the
// `<rpit_fn as Tr<()>>::Projection` return type is impossible to normalize,
// since it would require proving `rpit_fn: Fn() -> ()`, but we cannot
// prove that the `impl Sized` opaque is `()` with a user-facing param-env.
// This leads to a normalization error, and then an ICE.
//
// Side-note:
// So why is the second generic of `test` "`()`", and not the
// `impl Sized` since we inferred it from the return type of `rpit_fn`
// during typeck? Well, that's because we're using the generics from the
// terminator of the MIR, which has had the RevealAll pass performed on it.
let _ = test(rpit_fn);
}

View file

@ -1,6 +1,7 @@
pub trait Arbitrary: Sized + 'static {}
impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} //~ ERROR lifetime bound
//~^ ERROR cannot infer an appropriate lifetime for lifetime parameter `'a`
fn main() {
}

View file

@ -11,6 +11,32 @@ LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
| ^^
= note: but lifetime parameter must outlive the static lifetime
error: aborting due to 1 previous error
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> $DIR/static-lifetime.rs:3:34
|
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
--> $DIR/static-lifetime.rs:3:6
|
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
| ^^
note: ...so that the types are compatible
--> $DIR/static-lifetime.rs:3:34
|
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `<Cow<'a, A> as Arbitrary>`
found `<Cow<'_, A> as Arbitrary>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the declared lifetime parameter bounds are satisfied
--> $DIR/static-lifetime.rs:3:34
|
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0478`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0478, E0495.
For more information about an error, try `rustc --explain E0478`.

View file

@ -0,0 +1,9 @@
//@ only-wasm32-wasip1
//@ compile-flags: -Ctarget-feature=+relaxed-simd --crate-type=lib
//@ build-pass
use std::arch::wasm32::*;
pub fn test(a: v128, b: v128, m: v128) -> v128 {
i64x2_relaxed_laneselect(a, b, m)
}

View file

@ -0,0 +1,10 @@
//@ only-wasm32-wasip1
//@ compile-flags: --crate-type=lib
//@ build-pass
use std::arch::wasm32::*;
#[target_feature(enable = "relaxed-simd")]
pub fn test(a: v128, b: v128, m: v128) -> v128 {
i64x2_relaxed_laneselect(a, b, m)
}

View file

@ -0,0 +1,9 @@
//@ only-wasm32-wasip1
//@ compile-flags: -Ctarget-feature=+relaxed-simd --crate-type=lib
//@ build-pass
use std::arch::wasm32::*;
pub fn test(a: v128, b: v128, m: v128) -> v128 {
i64x2_relaxed_laneselect(a, b, m)
}

View file

@ -0,0 +1,12 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/wf-in-where-clause-static.rs:18:18
|
LL | let s = foo(&String::from("blah blah blah"));
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
| | |
| | creates a temporary value which is freed while still in use
| argument requires that borrow lasts for `'static`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0716`.

View file

@ -0,0 +1,12 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/wf-in-where-clause-static.rs:18:18
|
LL | let s = foo(&String::from("blah blah blah"));
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
| | |
| | creates a temporary value which is freed while still in use
| argument requires that borrow lasts for `'static`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0716`.

View file

@ -1,9 +1,6 @@
//@ check-pass
//@ known-bug: #98117
// Should fail. Functions are responsible for checking the well-formedness of
// their own where clauses, so this should fail and require an explicit bound
// `T: 'static`.
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
use std::fmt::Display;
@ -19,5 +16,6 @@ where
fn main() {
let s = foo(&String::from("blah blah blah"));
//~^ ERROR temporary value dropped while borrowed
println!("{}", s);
}