Auto merge of #3791 - rust-lang:rustup-2024-08-06, r=RalfJung
Automatic Rustup
This commit is contained in:
commit
5b2cdc1f65
94 changed files with 1387 additions and 894 deletions
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
|
|
|||
|
|
@ -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 { .. } => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>>>,
|
||||
|
|
|
|||
|
|
@ -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:?}")
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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>>>
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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) },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
29e924841f06bb181d87494eba2783761bc1ddec
|
||||
c9687a95a602091777e28703aa5abf20f1ce1797
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -9,6 +9,3 @@ pub mod llvm;
|
|||
pub mod python;
|
||||
pub mod rustc;
|
||||
pub mod rustdoc;
|
||||
|
||||
// Library-internal external dependency.
|
||||
mod cygpath;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
14
tests/crashes/128094.rs
Normal 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
13
tests/crashes/128176.rs
Normal 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
7
tests/crashes/128190.rs
Normal 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
5
tests/crashes/128327.rs
Normal 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
13
tests/crashes/128346.rs
Normal 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);
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) });
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
47
tests/run-make/reproducible-build-2/rmake.rs
Normal file
47
tests/run-make/reproducible-build-2/rmake.rs
Normal 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")));
|
||||
}
|
||||
|
|
@ -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"
|
||||
68
tests/run-make/stable-symbol-names/rmake.rs
Normal file
68
tests/run-make/stable-symbol-names/rmake.rs
Normal 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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
22
tests/rustdoc-js/self-is-not-generic.js
Normal file
22
tests/rustdoc-js/self-is-not-generic.js
Normal 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' }
|
||||
],
|
||||
}
|
||||
];
|
||||
11
tests/rustdoc-js/self-is-not-generic.rs
Normal file
11
tests/rustdoc-js/self-is-not-generic.rs
Normal 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
|
||||
}
|
||||
}
|
||||
5
tests/rustdoc-json/the_smallest.rs
Normal file
5
tests/rustdoc-json/the_smallest.rs
Normal 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() {}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
51
tests/ui/asm/invalid-const-operand.rs
Normal file
51
tests/ui/asm/invalid-const-operand.rs
Normal 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
|
||||
}
|
||||
}
|
||||
86
tests/ui/asm/invalid-const-operand.stderr
Normal file
86
tests/ui/asm/invalid-const-operand.stderr
Normal 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`.
|
||||
34
tests/ui/asm/invalid-sym-operand.rs
Normal file
34
tests/ui/asm/invalid-sym-operand.rs
Normal 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>);
|
||||
}
|
||||
26
tests/ui/asm/invalid-sym-operand.stderr
Normal file
26
tests/ui/asm/invalid-sym-operand.stderr
Normal 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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
21
tests/ui/cast/dyn-tails-need-normalization.rs
Normal file
21
tests/ui/cast/dyn-tails-need-normalization.rs
Normal 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() {}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 = ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
44
tests/ui/sanitizer/cfi-can-reveal-opaques.rs
Normal file
44
tests/ui/sanitizer/cfi-can-reveal-opaques.rs
Normal 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);
|
||||
}
|
||||
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
9
tests/ui/target-feature/implicit-features-cli.rs
Normal file
9
tests/ui/target-feature/implicit-features-cli.rs
Normal 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)
|
||||
}
|
||||
10
tests/ui/target-feature/implicit-features.rs
Normal file
10
tests/ui/target-feature/implicit-features.rs
Normal 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)
|
||||
}
|
||||
9
tests/ui/target-feature/wasm-relaxed-simd.rs
Normal file
9
tests/ui/target-feature/wasm-relaxed-simd.rs
Normal 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)
|
||||
}
|
||||
12
tests/ui/wf/wf-in-where-clause-static.current.stderr
Normal file
12
tests/ui/wf/wf-in-where-clause-static.current.stderr
Normal 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`.
|
||||
12
tests/ui/wf/wf-in-where-clause-static.next.stderr
Normal file
12
tests/ui/wf/wf-in-where-clause-static.next.stderr
Normal 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`.
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue