Auto merge of #79273 - Dylan-DPC:rollup-zd10xlt, r=Dylan-DPC
Rollup of 8 pull requests Successful merges: - #77844 (clarify rules for ZST Boxes) - #79067 (Refactor the abi handling code a bit) - #79182 (Fix links to extern types in rustdoc (fixes #78777)) - #79231 (Exhaustively match in variant count instrinsic) - #79238 (Direct RUSTC_LOG (tracing/log) output to stderr instead of stdout.) - #79256 (Fix typos) - #79264 (Get rid of some doctree items) - #79272 (Support building clone shims for arrays with generic size) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
da38469480
@ -36,17 +36,17 @@ impl ArgAttributeExt for ArgAttribute {
|
||||
where
|
||||
F: FnMut(llvm::Attribute),
|
||||
{
|
||||
for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
|
||||
for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ArgAttributesExt {
|
||||
fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>);
|
||||
fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>);
|
||||
fn apply_attrs_to_llfn(&self, idx: AttributePlace, llfn: &Value);
|
||||
fn apply_attrs_to_callsite(&self, idx: AttributePlace, callsite: &Value);
|
||||
}
|
||||
|
||||
impl ArgAttributesExt for ArgAttributes {
|
||||
fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>) {
|
||||
fn apply_attrs_to_llfn(&self, idx: AttributePlace, llfn: &Value) {
|
||||
let mut regular = self.regular;
|
||||
unsafe {
|
||||
let deref = self.pointee_size.bytes();
|
||||
@ -61,14 +61,20 @@ impl ArgAttributesExt for ArgAttributes {
|
||||
if let Some(align) = self.pointee_align {
|
||||
llvm::LLVMRustAddAlignmentAttr(llfn, idx.as_uint(), align.bytes() as u32);
|
||||
}
|
||||
if regular.contains(ArgAttribute::ByVal) {
|
||||
llvm::LLVMRustAddByValAttr(llfn, idx.as_uint(), ty.unwrap());
|
||||
}
|
||||
regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
|
||||
match self.arg_ext {
|
||||
ArgExtension::None => {}
|
||||
ArgExtension::Zext => {
|
||||
llvm::Attribute::ZExt.apply_llfn(idx, llfn);
|
||||
}
|
||||
ArgExtension::Sext => {
|
||||
llvm::Attribute::SExt.apply_llfn(idx, llfn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>) {
|
||||
fn apply_attrs_to_callsite(&self, idx: AttributePlace, callsite: &Value) {
|
||||
let mut regular = self.regular;
|
||||
unsafe {
|
||||
let deref = self.pointee_size.bytes();
|
||||
@ -91,10 +97,16 @@ impl ArgAttributesExt for ArgAttributes {
|
||||
align.bytes() as u32,
|
||||
);
|
||||
}
|
||||
if regular.contains(ArgAttribute::ByVal) {
|
||||
llvm::LLVMRustAddByValCallSiteAttr(callsite, idx.as_uint(), ty.unwrap());
|
||||
}
|
||||
regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
|
||||
match self.arg_ext {
|
||||
ArgExtension::None => {}
|
||||
ArgExtension::Zext => {
|
||||
llvm::Attribute::ZExt.apply_callsite(idx, callsite);
|
||||
}
|
||||
ArgExtension::Sext => {
|
||||
llvm::Attribute::SExt.apply_callsite(idx, callsite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,7 +158,7 @@ impl LlvmType for CastTarget {
|
||||
.prefix
|
||||
.iter()
|
||||
.flat_map(|option_kind| {
|
||||
option_kind.map(|kind| Reg { kind, size: self.prefix_chunk }.llvm_type(cx))
|
||||
option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.llvm_type(cx))
|
||||
})
|
||||
.chain((0..rest_count).map(|_| rest_ll_unit))
|
||||
.collect();
|
||||
@ -267,10 +279,12 @@ impl ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||
PassMode::Pair(..) => {
|
||||
OperandValue::Pair(next(), next()).store(bx, dst);
|
||||
}
|
||||
PassMode::Indirect(_, Some(_)) => {
|
||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
||||
OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
|
||||
}
|
||||
PassMode::Direct(_) | PassMode::Indirect(_, None) | PassMode::Cast(_) => {
|
||||
PassMode::Direct(_)
|
||||
| PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }
|
||||
| PassMode::Cast(_) => {
|
||||
let next_arg = next();
|
||||
self.store(bx, next_arg, dst);
|
||||
}
|
||||
@ -315,14 +329,14 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 }
|
||||
).sum();
|
||||
let mut llargument_tys = Vec::with_capacity(
|
||||
if let PassMode::Indirect(..) = self.ret.mode { 1 } else { 0 } + args_capacity,
|
||||
if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 } + args_capacity,
|
||||
);
|
||||
|
||||
let llreturn_ty = match self.ret.mode {
|
||||
PassMode::Ignore => cx.type_void(),
|
||||
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx),
|
||||
PassMode::Cast(cast) => cast.llvm_type(cx),
|
||||
PassMode::Indirect(..) => {
|
||||
PassMode::Indirect { .. } => {
|
||||
llargument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
|
||||
cx.type_void()
|
||||
}
|
||||
@ -342,7 +356,7 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
|
||||
continue;
|
||||
}
|
||||
PassMode::Indirect(_, Some(_)) => {
|
||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
||||
let ptr_ty = cx.tcx.mk_mut_ptr(arg.layout.ty);
|
||||
let ptr_layout = cx.layout_of(ptr_ty);
|
||||
llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true));
|
||||
@ -350,7 +364,9 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
continue;
|
||||
}
|
||||
PassMode::Cast(cast) => cast.llvm_type(cx),
|
||||
PassMode::Indirect(_, None) => cx.type_ptr_to(arg.memory_ty(cx)),
|
||||
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
|
||||
cx.type_ptr_to(arg.memory_ty(cx))
|
||||
}
|
||||
};
|
||||
llargument_tys.push(llarg_ty);
|
||||
}
|
||||
@ -402,35 +418,54 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
|
||||
attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn, ty);
|
||||
let mut apply = |attrs: &ArgAttributes| {
|
||||
attrs.apply_attrs_to_llfn(llvm::AttributePlace::Argument(i), llfn);
|
||||
i += 1;
|
||||
i - 1
|
||||
};
|
||||
match self.ret.mode {
|
||||
PassMode::Direct(ref attrs) => {
|
||||
attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn, None);
|
||||
attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, llfn);
|
||||
}
|
||||
PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
|
||||
assert!(!on_stack);
|
||||
let i = apply(attrs);
|
||||
llvm::Attribute::StructRet.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
|
||||
}
|
||||
PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(cx))),
|
||||
_ => {}
|
||||
}
|
||||
for arg in &self.args {
|
||||
if arg.pad.is_some() {
|
||||
apply(&ArgAttributes::new(), None);
|
||||
apply(&ArgAttributes::new());
|
||||
}
|
||||
match arg.mode {
|
||||
PassMode::Ignore => {}
|
||||
PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => {
|
||||
apply(attrs, Some(arg.layout.llvm_type(cx)))
|
||||
PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => {
|
||||
let i = apply(attrs);
|
||||
unsafe {
|
||||
llvm::LLVMRustAddByValAttr(
|
||||
llfn,
|
||||
llvm::AttributePlace::Argument(i).as_uint(),
|
||||
arg.layout.llvm_type(cx),
|
||||
);
|
||||
}
|
||||
}
|
||||
PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
|
||||
apply(attrs, None);
|
||||
apply(extra_attrs, None);
|
||||
PassMode::Direct(ref attrs)
|
||||
| PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => {
|
||||
apply(attrs);
|
||||
}
|
||||
PassMode::Indirect { ref attrs, extra_attrs: Some(ref extra_attrs), on_stack } => {
|
||||
assert!(!on_stack);
|
||||
apply(attrs);
|
||||
apply(extra_attrs);
|
||||
}
|
||||
PassMode::Pair(ref a, ref b) => {
|
||||
apply(a, None);
|
||||
apply(b, None);
|
||||
apply(a);
|
||||
apply(b);
|
||||
}
|
||||
PassMode::Cast(_) => {
|
||||
apply(&ArgAttributes::new());
|
||||
}
|
||||
PassMode::Cast(_) => apply(&ArgAttributes::new(), None),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -439,15 +474,21 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
// FIXME(wesleywiser, eddyb): We should apply `nounwind` and `noreturn` as appropriate to this callsite.
|
||||
|
||||
let mut i = 0;
|
||||
let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
|
||||
attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite, ty);
|
||||
let mut apply = |attrs: &ArgAttributes| {
|
||||
attrs.apply_attrs_to_callsite(llvm::AttributePlace::Argument(i), callsite);
|
||||
i += 1;
|
||||
i - 1
|
||||
};
|
||||
match self.ret.mode {
|
||||
PassMode::Direct(ref attrs) => {
|
||||
attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite, None);
|
||||
attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, callsite);
|
||||
}
|
||||
PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
|
||||
assert!(!on_stack);
|
||||
let i = apply(attrs);
|
||||
llvm::Attribute::StructRet
|
||||
.apply_callsite(llvm::AttributePlace::Argument(i), callsite);
|
||||
}
|
||||
PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(bx))),
|
||||
_ => {}
|
||||
}
|
||||
if let abi::Abi::Scalar(ref scalar) = self.ret.layout.abi {
|
||||
@ -465,22 +506,39 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
}
|
||||
for arg in &self.args {
|
||||
if arg.pad.is_some() {
|
||||
apply(&ArgAttributes::new(), None);
|
||||
apply(&ArgAttributes::new());
|
||||
}
|
||||
match arg.mode {
|
||||
PassMode::Ignore => {}
|
||||
PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => {
|
||||
apply(attrs, Some(arg.layout.llvm_type(bx)))
|
||||
PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => {
|
||||
let i = apply(attrs);
|
||||
unsafe {
|
||||
llvm::LLVMRustAddByValCallSiteAttr(
|
||||
callsite,
|
||||
llvm::AttributePlace::Argument(i).as_uint(),
|
||||
arg.layout.llvm_type(bx),
|
||||
);
|
||||
}
|
||||
}
|
||||
PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
|
||||
apply(attrs, None);
|
||||
apply(extra_attrs, None);
|
||||
PassMode::Direct(ref attrs)
|
||||
| PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => {
|
||||
apply(attrs);
|
||||
}
|
||||
PassMode::Indirect {
|
||||
ref attrs,
|
||||
extra_attrs: Some(ref extra_attrs),
|
||||
on_stack: _,
|
||||
} => {
|
||||
apply(attrs);
|
||||
apply(extra_attrs);
|
||||
}
|
||||
PassMode::Pair(ref a, ref b) => {
|
||||
apply(a, None);
|
||||
apply(b, None);
|
||||
apply(a);
|
||||
apply(b);
|
||||
}
|
||||
PassMode::Cast(_) => {
|
||||
apply(&ArgAttributes::new());
|
||||
}
|
||||
PassMode::Cast(_) => apply(&ArgAttributes::new(), None),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,7 +255,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
return;
|
||||
}
|
||||
let llval = match self.fn_abi.ret.mode {
|
||||
PassMode::Ignore | PassMode::Indirect(..) => {
|
||||
PassMode::Ignore | PassMode::Indirect { .. } => {
|
||||
bx.ret_void();
|
||||
return;
|
||||
}
|
||||
@ -1101,7 +1101,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
// Force by-ref if we have to load through a cast pointer.
|
||||
let (mut llval, align, by_ref) = match op.val {
|
||||
Immediate(_) | Pair(..) => match arg.mode {
|
||||
PassMode::Indirect(..) | PassMode::Cast(_) => {
|
||||
PassMode::Indirect { .. } | PassMode::Cast(_) => {
|
||||
let scratch = PlaceRef::alloca(bx, arg.layout);
|
||||
op.val.store(bx, scratch);
|
||||
(scratch.llval, scratch.align, true)
|
||||
|
@ -1286,6 +1286,7 @@ pub fn init_env_logger(env: &str) {
|
||||
}
|
||||
let filter = tracing_subscriber::EnvFilter::from_env(env);
|
||||
let layer = tracing_tree::HierarchicalLayer::default()
|
||||
.with_writer(io::stderr)
|
||||
.with_indent_lines(true)
|
||||
.with_ansi(true)
|
||||
.with_targets(true)
|
||||
|
@ -947,7 +947,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||
}
|
||||
|
||||
fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
self.root.tables.ty.get(self, id).unwrap().decode((self, tcx))
|
||||
self.root
|
||||
.tables
|
||||
.ty
|
||||
.get(self, id)
|
||||
.unwrap_or_else(|| panic!("Not a type: {:?}", id))
|
||||
.decode((self, tcx))
|
||||
}
|
||||
|
||||
fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
|
||||
|
@ -15,7 +15,7 @@ use rustc_session::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::abi::call::{
|
||||
ArgAbi, ArgAttribute, ArgAttributes, Conv, FnAbi, PassMode, Reg, RegKind,
|
||||
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
|
||||
};
|
||||
use rustc_target::abi::*;
|
||||
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy};
|
||||
@ -2619,7 +2619,7 @@ where
|
||||
is_return: bool| {
|
||||
// Booleans are always an i1 that needs to be zero-extended.
|
||||
if scalar.is_bool() {
|
||||
attrs.set(ArgAttribute::ZExt);
|
||||
attrs.ext(ArgExtension::Zext);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2801,9 +2801,6 @@ where
|
||||
for arg in &mut self.args {
|
||||
fixup(arg, false);
|
||||
}
|
||||
if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
|
||||
attrs.set(ArgAttribute::StructRet);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -75,13 +75,35 @@ crate fn eval_nullary_intrinsic<'tcx>(
|
||||
ensure_monomorphic_enough(tcx, tp_ty)?;
|
||||
ConstValue::from_u64(tcx.type_id_hash(tp_ty))
|
||||
}
|
||||
sym::variant_count => {
|
||||
if let ty::Adt(ref adt, _) = tp_ty.kind() {
|
||||
ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx)
|
||||
} else {
|
||||
ConstValue::from_machine_usize(0u64, &tcx)
|
||||
}
|
||||
}
|
||||
sym::variant_count => match tp_ty.kind() {
|
||||
ty::Adt(ref adt, _) => ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx),
|
||||
ty::Projection(_)
|
||||
| ty::Opaque(_, _)
|
||||
| ty::Param(_)
|
||||
| ty::Bound(_, _)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(_) => throw_inval!(TooGeneric),
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Array(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(_)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(_)
|
||||
| ty::Dynamic(_, _)
|
||||
| ty::Closure(_, _)
|
||||
| ty::Generator(_, _, _)
|
||||
| ty::GeneratorWitness(_)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
| ty::Error(_) => ConstValue::from_machine_usize(0u64, &tcx),
|
||||
},
|
||||
other => bug!("`{}` is not a zero arg intrinsic", other),
|
||||
})
|
||||
}
|
||||
|
@ -308,10 +308,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
|
||||
|
||||
match self_ty.kind() {
|
||||
_ if is_copy => builder.copy_shim(),
|
||||
ty::Array(ty, len) => {
|
||||
let len = len.eval_usize(tcx, param_env);
|
||||
builder.array_shim(dest, src, ty, len)
|
||||
}
|
||||
ty::Array(ty, len) => builder.array_shim(dest, src, ty, len),
|
||||
ty::Closure(_, substs) => {
|
||||
builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys())
|
||||
}
|
||||
@ -485,7 +482,13 @@ impl CloneShimBuilder<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn array_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, ty: Ty<'tcx>, len: u64) {
|
||||
fn array_shim(
|
||||
&mut self,
|
||||
dest: Place<'tcx>,
|
||||
src: Place<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
len: &'tcx ty::Const<'tcx>,
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
let span = self.span;
|
||||
|
||||
@ -503,7 +506,11 @@ impl CloneShimBuilder<'tcx> {
|
||||
))),
|
||||
self.make_statement(StatementKind::Assign(box (
|
||||
end,
|
||||
Rvalue::Use(Operand::Constant(self.make_usize(len))),
|
||||
Rvalue::Use(Operand::Constant(box Constant {
|
||||
span: self.span,
|
||||
user_ty: None,
|
||||
literal: len,
|
||||
})),
|
||||
))),
|
||||
];
|
||||
self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
|
||||
|
@ -33,11 +33,11 @@ pub struct QueryInfo<Q> {
|
||||
|
||||
pub(crate) type QueryMap<D, Q> = FxHashMap<QueryJobId<D>, QueryJobInfo<D, Q>>;
|
||||
|
||||
/// A value uniquely identifiying an active query job within a shard in the query cache.
|
||||
/// A value uniquely identifying an active query job within a shard in the query cache.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct QueryShardJobId(pub NonZeroU32);
|
||||
|
||||
/// A value uniquely identifiying an active query job.
|
||||
/// A value uniquely identifying an active query job.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct QueryJobId<D> {
|
||||
/// Which job within a shard is this
|
||||
@ -536,7 +536,7 @@ fn remove_cycle<CTX: QueryContext>(
|
||||
};
|
||||
|
||||
// We unwrap `waiter` here since there must always be one
|
||||
// edge which is resumeable / waited using a query latch
|
||||
// edge which is resumable / waited using a query latch
|
||||
let (waitee_query, waiter_idx) = waiter.unwrap();
|
||||
|
||||
// Extract the waiter we want to resume
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
|
||||
use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
|
||||
use crate::abi::{self, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods};
|
||||
|
||||
fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
|
||||
@ -7,7 +7,7 @@ fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
|
||||
if let abi::Int(i, signed) = scalar.value {
|
||||
if !signed && i.size().bits() == 32 {
|
||||
if let PassMode::Direct(ref mut attrs) = arg.mode {
|
||||
attrs.set(ArgAttribute::SExt);
|
||||
attrs.ext(ArgExtension::Sext);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -137,7 +137,7 @@ where
|
||||
let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
|
||||
arg.cast_to(CastTarget {
|
||||
prefix,
|
||||
prefix_chunk: Size::from_bytes(8),
|
||||
prefix_chunk_size: Size::from_bytes(8),
|
||||
rest: Uniform { unit: Reg::i64(), total: rest_size },
|
||||
});
|
||||
}
|
||||
|
@ -36,9 +36,12 @@ pub enum PassMode {
|
||||
/// a single uniform or a pair of registers.
|
||||
Cast(CastTarget),
|
||||
/// Pass the argument indirectly via a hidden pointer.
|
||||
/// The second value, if any, is for the extra data (vtable or length)
|
||||
/// The `extra_attrs` value, if any, is for the extra data (vtable or length)
|
||||
/// which indicates that it refers to an unsized rvalue.
|
||||
Indirect(ArgAttributes, Option<ArgAttributes>),
|
||||
/// `on_stack` defines that the the value should be passed at a fixed
|
||||
/// stack offset in accordance to the ABI rather than passed using a
|
||||
/// pointer. This corresponds to the `byval` LLVM argument attribute.
|
||||
Indirect { attrs: ArgAttributes, extra_attrs: Option<ArgAttributes>, on_stack: bool },
|
||||
}
|
||||
|
||||
// Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
|
||||
@ -52,24 +55,31 @@ mod attr_impl {
|
||||
bitflags::bitflags! {
|
||||
#[derive(Default)]
|
||||
pub struct ArgAttribute: u16 {
|
||||
const ByVal = 1 << 0;
|
||||
const NoAlias = 1 << 1;
|
||||
const NoCapture = 1 << 2;
|
||||
const NonNull = 1 << 3;
|
||||
const ReadOnly = 1 << 4;
|
||||
const SExt = 1 << 5;
|
||||
const StructRet = 1 << 6;
|
||||
const ZExt = 1 << 7;
|
||||
const InReg = 1 << 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sometimes an ABI requires small integers to be extended to a full or partial register. This enum
|
||||
/// defines if this extension should be zero-extension or sign-extension when necssary. When it is
|
||||
/// not necesary to extend the argument, this enum is ignored.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum ArgExtension {
|
||||
None,
|
||||
Zext,
|
||||
Sext,
|
||||
}
|
||||
|
||||
/// A compact representation of LLVM attributes (at least those relevant for this module)
|
||||
/// that can be manipulated without interacting with LLVM's Attribute machinery.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct ArgAttributes {
|
||||
pub regular: ArgAttribute,
|
||||
pub arg_ext: ArgExtension,
|
||||
/// The minimum size of the pointee, guaranteed to be valid for the duration of the whole call
|
||||
/// (corresponding to LLVM's dereferenceable and dereferenceable_or_null attributes).
|
||||
pub pointee_size: Size,
|
||||
@ -80,11 +90,18 @@ impl ArgAttributes {
|
||||
pub fn new() -> Self {
|
||||
ArgAttributes {
|
||||
regular: ArgAttribute::default(),
|
||||
arg_ext: ArgExtension::None,
|
||||
pointee_size: Size::ZERO,
|
||||
pointee_align: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ext(&mut self, ext: ArgExtension) -> &mut Self {
|
||||
assert!(self.arg_ext == ArgExtension::None || self.arg_ext == ext);
|
||||
self.arg_ext = ext;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
|
||||
self.regular |= attr;
|
||||
self
|
||||
@ -180,7 +197,7 @@ impl Uniform {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct CastTarget {
|
||||
pub prefix: [Option<RegKind>; 8],
|
||||
pub prefix_chunk: Size,
|
||||
pub prefix_chunk_size: Size,
|
||||
pub rest: Uniform,
|
||||
}
|
||||
|
||||
@ -192,7 +209,7 @@ impl From<Reg> for CastTarget {
|
||||
|
||||
impl From<Uniform> for CastTarget {
|
||||
fn from(uniform: Uniform) -> CastTarget {
|
||||
CastTarget { prefix: [None; 8], prefix_chunk: Size::ZERO, rest: uniform }
|
||||
CastTarget { prefix: [None; 8], prefix_chunk_size: Size::ZERO, rest: uniform }
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,13 +217,13 @@ impl CastTarget {
|
||||
pub fn pair(a: Reg, b: Reg) -> CastTarget {
|
||||
CastTarget {
|
||||
prefix: [Some(a.kind), None, None, None, None, None, None, None],
|
||||
prefix_chunk: a.size,
|
||||
prefix_chunk_size: a.size,
|
||||
rest: Uniform::from(b),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size<C: HasDataLayout>(&self, cx: &C) -> Size {
|
||||
(self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
|
||||
(self.prefix_chunk_size * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
|
||||
.align_to(self.rest.align(cx))
|
||||
+ self.rest.total
|
||||
}
|
||||
@ -214,7 +231,7 @@ impl CastTarget {
|
||||
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
|
||||
self.prefix
|
||||
.iter()
|
||||
.filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk }.align(cx)))
|
||||
.filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk_size }.align(cx)))
|
||||
.fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| {
|
||||
acc.max(align)
|
||||
})
|
||||
@ -438,14 +455,14 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
|
||||
|
||||
let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new());
|
||||
|
||||
self.mode = PassMode::Indirect(attrs, extra_attrs);
|
||||
self.mode = PassMode::Indirect { attrs, extra_attrs, on_stack: false };
|
||||
}
|
||||
|
||||
pub fn make_indirect_byval(&mut self) {
|
||||
self.make_indirect();
|
||||
match self.mode {
|
||||
PassMode::Indirect(ref mut attrs, _) => {
|
||||
attrs.set(ArgAttribute::ByVal);
|
||||
PassMode::Indirect { attrs: _, extra_attrs: _, ref mut on_stack } => {
|
||||
*on_stack = true;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
@ -457,7 +474,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
|
||||
if let abi::Int(i, signed) = scalar.value {
|
||||
if i.size().bits() < bits {
|
||||
if let PassMode::Direct(ref mut attrs) = self.mode {
|
||||
attrs.set(if signed { ArgAttribute::SExt } else { ArgAttribute::ZExt });
|
||||
if signed {
|
||||
attrs.ext(ArgExtension::Sext)
|
||||
} else {
|
||||
attrs.ext(ArgExtension::Zext)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -474,15 +495,15 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
|
||||
}
|
||||
|
||||
pub fn is_indirect(&self) -> bool {
|
||||
matches!(self.mode, PassMode::Indirect(..))
|
||||
matches!(self.mode, PassMode::Indirect {..})
|
||||
}
|
||||
|
||||
pub fn is_sized_indirect(&self) -> bool {
|
||||
matches!(self.mode, PassMode::Indirect(_, None))
|
||||
matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ })
|
||||
}
|
||||
|
||||
pub fn is_unsized_indirect(&self) -> bool {
|
||||
matches!(self.mode, PassMode::Indirect(_, Some(_)))
|
||||
matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ })
|
||||
}
|
||||
|
||||
pub fn is_ignore(&self) -> bool {
|
||||
@ -591,10 +612,6 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
||||
a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
|
||||
}
|
||||
|
||||
if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
|
||||
attrs.set(ArgAttribute::StructRet);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Reference: Clang RISC-V ELF psABI lowering code
|
||||
// https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773
|
||||
|
||||
use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
|
||||
use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
|
||||
use crate::abi::{
|
||||
self, Abi, FieldsShape, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods,
|
||||
};
|
||||
@ -308,7 +308,7 @@ fn extend_integer_width<'a, Ty>(arg: &mut ArgAbi<'a, Ty>, xlen: u64) {
|
||||
// 32-bit integers are always sign-extended
|
||||
if i.size().bits() == 32 && xlen > 32 {
|
||||
if let PassMode::Direct(ref mut attrs) = arg.mode {
|
||||
attrs.set(ArgAttribute::SExt);
|
||||
attrs.ext(ArgExtension::Sext);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -92,9 +92,14 @@ where
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
let attrs = match arg.mode {
|
||||
PassMode::Ignore | PassMode::Indirect(_, None) => continue,
|
||||
PassMode::Ignore
|
||||
| PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
|
||||
continue;
|
||||
}
|
||||
PassMode::Direct(ref mut attrs) => attrs,
|
||||
PassMode::Pair(..) | PassMode::Indirect(_, Some(_)) | PassMode::Cast(_) => {
|
||||
PassMode::Pair(..)
|
||||
| PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ }
|
||||
| PassMode::Cast(_) => {
|
||||
unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
|
||||
}
|
||||
};
|
||||
|
@ -62,6 +62,13 @@
|
||||
//! T` obtained from [`Box::<T>::into_raw`] may be deallocated using the
|
||||
//! [`Global`] allocator with [`Layout::for_value(&*value)`].
|
||||
//!
|
||||
//! For zero-sized values, the `Box` pointer still has to be [valid] for reads
|
||||
//! and writes and sufficiently aligned. In particular, casting any aligned
|
||||
//! non-zero integer literal to a raw pointer produces a valid pointer, but a
|
||||
//! pointer pointing into previously allocated memory that since got freed is
|
||||
//! not valid. The recommended way to build a Box to a ZST if `Box::new` cannot
|
||||
//! be used is to use [`ptr::NonNull::dangling`].
|
||||
//!
|
||||
//! So long as `T: Sized`, a `Box<T>` is guaranteed to be represented
|
||||
//! as a single pointer and is also ABI-compatible with C pointers
|
||||
//! (i.e. the C type `T*`). This means that if you have extern "C"
|
||||
@ -125,6 +132,7 @@
|
||||
//! [`Global`]: crate::alloc::Global
|
||||
//! [`Layout`]: crate::alloc::Layout
|
||||
//! [`Layout::for_value(&*value)`]: crate::alloc::Layout::for_value
|
||||
//! [valid]: ptr#safety
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
@ -530,7 +538,10 @@ impl<T: ?Sized> Box<T> {
|
||||
/// memory problems. For example, a double-free may occur if the
|
||||
/// function is called twice on the same raw pointer.
|
||||
///
|
||||
/// The safety conditions are described in the [memory layout] section.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Recreate a `Box` which was previously converted to a raw pointer
|
||||
/// using [`Box::into_raw`]:
|
||||
/// ```
|
||||
|
@ -16,12 +16,16 @@
|
||||
//! provided at this point are very minimal:
|
||||
//!
|
||||
//! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst].
|
||||
//! * All pointers (except for the null pointer) are valid for all operations of
|
||||
//! [size zero][zst].
|
||||
//! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer
|
||||
//! be *dereferenceable*: the memory range of the given size starting at the pointer must all be
|
||||
//! within the bounds of a single allocated object. Note that in Rust,
|
||||
//! every (stack-allocated) variable is considered a separate allocated object.
|
||||
//! * Even for operations of [size zero][zst], the pointer must not be pointing to deallocated
|
||||
//! memory, i.e., deallocation makes pointers invalid even for zero-sized operations. However,
|
||||
//! casting any non-zero integer *literal* to a pointer is valid for zero-sized accesses, even if
|
||||
//! some memory happens to exist at that address and gets deallocated. This corresponds to writing
|
||||
//! your own allocator: allocating zero-sized objects is not very hard. The canonical way to
|
||||
//! obtain a pointer that is valid for zero-sized accesses is [`NonNull::dangling`].
|
||||
//! * All accesses performed by functions in this module are *non-atomic* in the sense
|
||||
//! of [atomic operations] used to synchronize between threads. This means it is
|
||||
//! undefined behavior to perform two concurrent accesses to the same location from different
|
||||
|
@ -231,21 +231,14 @@ impl Clean<Item> for doctree::Module<'_> {
|
||||
let mut items: Vec<Item> = vec![];
|
||||
items.extend(self.extern_crates.iter().flat_map(|x| x.clean(cx)));
|
||||
items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
|
||||
items.extend(self.structs.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.unions.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.enums.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.fns.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.mods.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.opaque_tys.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.statics.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.constants.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.items.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.traits.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
|
||||
items.extend(self.macros.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.proc_macros.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.trait_aliases.iter().map(|x| x.clean(cx)));
|
||||
|
||||
// determine if we should display the inner contents or
|
||||
// the outer `mod` item for the source code.
|
||||
@ -1020,20 +1013,6 @@ impl Clean<Item> for doctree::Trait<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::TraitAlias<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Item {
|
||||
Item::from_hir_id_and_parts(
|
||||
self.id,
|
||||
Some(self.name),
|
||||
TraitAliasItem(TraitAlias {
|
||||
generics: self.generics.clean(cx),
|
||||
bounds: self.bounds.clean(cx),
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<bool> for hir::IsAuto {
|
||||
fn clean(&self, _: &DocContext<'_>) -> bool {
|
||||
match *self {
|
||||
@ -1777,38 +1756,6 @@ impl Clean<Visibility> for ty::Visibility {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Struct<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Item {
|
||||
Item::from_hir_id_and_parts(
|
||||
self.id,
|
||||
Some(self.name),
|
||||
StructItem(Struct {
|
||||
struct_type: self.struct_type,
|
||||
generics: self.generics.clean(cx),
|
||||
fields: self.fields.clean(cx),
|
||||
fields_stripped: false,
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Union<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Item {
|
||||
Item::from_hir_id_and_parts(
|
||||
self.id,
|
||||
Some(self.name),
|
||||
UnionItem(Union {
|
||||
struct_type: self.struct_type,
|
||||
generics: self.generics.clean(cx),
|
||||
fields: self.fields.clean(cx),
|
||||
fields_stripped: false,
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<VariantStruct> for rustc_hir::VariantData<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
|
||||
VariantStruct {
|
||||
@ -1819,21 +1766,6 @@ impl Clean<VariantStruct> for rustc_hir::VariantData<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Enum<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Item {
|
||||
Item::from_hir_id_and_parts(
|
||||
self.id,
|
||||
Some(self.name),
|
||||
EnumItem(Enum {
|
||||
variants: self.variants.iter().map(|v| v.clean(cx)).collect(),
|
||||
generics: self.generics.clean(cx),
|
||||
variants_stripped: false,
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Variant<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Item {
|
||||
let what_rustc_thinks = Item::from_hir_id_and_parts(
|
||||
@ -1981,33 +1913,6 @@ impl Clean<String> for Symbol {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Typedef<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Item {
|
||||
let type_ = self.ty.clean(cx);
|
||||
let item_type = type_.def_id().and_then(|did| inline::build_ty(cx, did));
|
||||
Item::from_hir_id_and_parts(
|
||||
self.id,
|
||||
Some(self.name),
|
||||
TypedefItem(Typedef { type_, generics: self.gen.clean(cx), item_type }, false),
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::OpaqueTy<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Item {
|
||||
Item::from_hir_id_and_parts(
|
||||
self.id,
|
||||
Some(self.name),
|
||||
OpaqueTyItem(OpaqueTy {
|
||||
bounds: self.opaque_ty.bounds.clean(cx),
|
||||
generics: self.opaque_ty.generics.clean(cx),
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl {
|
||||
let (generic_params, decl) = enter_impl_trait(cx, || {
|
||||
@ -2017,37 +1922,75 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Static<'_> {
|
||||
impl Clean<Item> for (&hir::Item<'_>, Option<Ident>) {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Item {
|
||||
debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
|
||||
Item::from_hir_id_and_parts(
|
||||
self.id,
|
||||
Some(self.name),
|
||||
StaticItem(Static {
|
||||
type_: self.type_.clean(cx),
|
||||
mutability: self.mutability,
|
||||
expr: print_const_expr(cx, self.expr),
|
||||
use hir::ItemKind;
|
||||
|
||||
let (item, renamed) = self;
|
||||
let def_id = cx.tcx.hir().local_def_id(item.hir_id).to_def_id();
|
||||
let name = match renamed {
|
||||
Some(ident) => ident.name,
|
||||
None => cx.tcx.hir().name(item.hir_id),
|
||||
};
|
||||
let kind = match item.kind {
|
||||
ItemKind::Static(ty, mutability, body_id) => StaticItem(Static {
|
||||
type_: ty.clean(cx),
|
||||
mutability,
|
||||
expr: print_const_expr(cx, body_id),
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
ItemKind::Const(ty, body_id) => ConstantItem(Constant {
|
||||
type_: ty.clean(cx),
|
||||
expr: print_const_expr(cx, body_id),
|
||||
value: print_evaluated_const(cx, def_id),
|
||||
is_literal: is_literal_expr(cx, body_id.hir_id),
|
||||
}),
|
||||
ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
|
||||
bounds: ty.bounds.clean(cx),
|
||||
generics: ty.generics.clean(cx),
|
||||
}),
|
||||
ItemKind::TyAlias(ty, ref generics) => {
|
||||
let rustdoc_ty = ty.clean(cx);
|
||||
let item_type = rustdoc_ty.def_id().and_then(|did| inline::build_ty(cx, did));
|
||||
TypedefItem(
|
||||
Typedef { type_: rustdoc_ty, generics: generics.clean(cx), item_type },
|
||||
false,
|
||||
)
|
||||
}
|
||||
ItemKind::Enum(ref def, ref generics) => EnumItem(Enum {
|
||||
variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
|
||||
generics: generics.clean(cx),
|
||||
variants_stripped: false,
|
||||
}),
|
||||
ItemKind::TraitAlias(ref generics, bounds) => TraitAliasItem(TraitAlias {
|
||||
generics: generics.clean(cx),
|
||||
bounds: bounds.clean(cx),
|
||||
}),
|
||||
ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
|
||||
struct_type: doctree::struct_type_from_def(&variant_data),
|
||||
generics: generics.clean(cx),
|
||||
fields: variant_data.fields().clean(cx),
|
||||
fields_stripped: false,
|
||||
}),
|
||||
ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
|
||||
struct_type: doctree::struct_type_from_def(&variant_data),
|
||||
generics: generics.clean(cx),
|
||||
fields: variant_data.fields().clean(cx),
|
||||
fields_stripped: false,
|
||||
}),
|
||||
_ => unreachable!("not yet converted"),
|
||||
};
|
||||
|
||||
Item::from_def_id_and_parts(def_id, Some(name), kind, cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Constant<'_> {
|
||||
impl Clean<Item> for hir::Variant<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Item {
|
||||
let def_id = cx.tcx.hir().local_def_id(self.id).to_def_id();
|
||||
|
||||
Item::from_def_id_and_parts(
|
||||
def_id,
|
||||
Some(self.name),
|
||||
ConstantItem(Constant {
|
||||
type_: self.type_.clean(cx),
|
||||
expr: print_const_expr(cx, self.expr),
|
||||
value: print_evaluated_const(cx, def_id),
|
||||
is_literal: is_literal_expr(cx, self.expr.hir_id),
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
let kind = VariantItem(Variant { kind: self.data.clean(cx) });
|
||||
let what_rustc_thinks =
|
||||
Item::from_hir_id_and_parts(self.id, Some(self.ident.name), kind, cx);
|
||||
// don't show `pub` for variants, which are always public
|
||||
Item { visibility: Inherited, ..what_rustc_thinks }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ crate use self::StructType::*;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::{self, Span, Symbol};
|
||||
use rustc_span::{self, symbol::Ident, Span, Symbol};
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
@ -17,22 +17,16 @@ crate struct Module<'hir> {
|
||||
crate where_inner: Span,
|
||||
crate extern_crates: Vec<ExternCrate<'hir>>,
|
||||
crate imports: Vec<Import<'hir>>,
|
||||
crate structs: Vec<Struct<'hir>>,
|
||||
crate unions: Vec<Union<'hir>>,
|
||||
crate enums: Vec<Enum<'hir>>,
|
||||
crate fns: Vec<Function<'hir>>,
|
||||
crate mods: Vec<Module<'hir>>,
|
||||
crate id: hir::HirId,
|
||||
crate typedefs: Vec<Typedef<'hir>>,
|
||||
crate opaque_tys: Vec<OpaqueTy<'hir>>,
|
||||
crate statics: Vec<Static<'hir>>,
|
||||
crate constants: Vec<Constant<'hir>>,
|
||||
// (item, renamed)
|
||||
crate items: Vec<(&'hir hir::Item<'hir>, Option<Ident>)>,
|
||||
crate traits: Vec<Trait<'hir>>,
|
||||
crate impls: Vec<Impl<'hir>>,
|
||||
crate foreigns: Vec<ForeignItem<'hir>>,
|
||||
crate macros: Vec<Macro>,
|
||||
crate proc_macros: Vec<ProcMacro>,
|
||||
crate trait_aliases: Vec<TraitAlias<'hir>>,
|
||||
crate is_crate: bool,
|
||||
}
|
||||
|
||||
@ -46,21 +40,14 @@ impl Module<'hir> {
|
||||
attrs,
|
||||
extern_crates: Vec::new(),
|
||||
imports: Vec::new(),
|
||||
structs: Vec::new(),
|
||||
unions: Vec::new(),
|
||||
enums: Vec::new(),
|
||||
fns: Vec::new(),
|
||||
mods: Vec::new(),
|
||||
typedefs: Vec::new(),
|
||||
opaque_tys: Vec::new(),
|
||||
statics: Vec::new(),
|
||||
constants: Vec::new(),
|
||||
items: Vec::new(),
|
||||
traits: Vec::new(),
|
||||
impls: Vec::new(),
|
||||
foreigns: Vec::new(),
|
||||
macros: Vec::new(),
|
||||
proc_macros: Vec::new(),
|
||||
trait_aliases: Vec::new(),
|
||||
is_crate: false,
|
||||
}
|
||||
}
|
||||
@ -76,29 +63,6 @@ crate enum StructType {
|
||||
Unit,
|
||||
}
|
||||
|
||||
crate struct Struct<'hir> {
|
||||
crate id: hir::HirId,
|
||||
crate struct_type: StructType,
|
||||
crate name: Symbol,
|
||||
crate generics: &'hir hir::Generics<'hir>,
|
||||
crate fields: &'hir [hir::StructField<'hir>],
|
||||
}
|
||||
|
||||
crate struct Union<'hir> {
|
||||
crate id: hir::HirId,
|
||||
crate struct_type: StructType,
|
||||
crate name: Symbol,
|
||||
crate generics: &'hir hir::Generics<'hir>,
|
||||
crate fields: &'hir [hir::StructField<'hir>],
|
||||
}
|
||||
|
||||
crate struct Enum<'hir> {
|
||||
crate variants: Vec<Variant<'hir>>,
|
||||
crate generics: &'hir hir::Generics<'hir>,
|
||||
crate id: hir::HirId,
|
||||
crate name: Symbol,
|
||||
}
|
||||
|
||||
crate struct Variant<'hir> {
|
||||
crate name: Symbol,
|
||||
crate id: hir::HirId,
|
||||
@ -114,38 +78,6 @@ crate struct Function<'hir> {
|
||||
crate body: hir::BodyId,
|
||||
}
|
||||
|
||||
crate struct Typedef<'hir> {
|
||||
crate ty: &'hir hir::Ty<'hir>,
|
||||
crate gen: &'hir hir::Generics<'hir>,
|
||||
crate name: Symbol,
|
||||
crate id: hir::HirId,
|
||||
}
|
||||
|
||||
crate struct OpaqueTy<'hir> {
|
||||
crate opaque_ty: &'hir hir::OpaqueTy<'hir>,
|
||||
crate name: Symbol,
|
||||
crate id: hir::HirId,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
crate struct Static<'hir> {
|
||||
crate type_: &'hir hir::Ty<'hir>,
|
||||
crate mutability: hir::Mutability,
|
||||
crate expr: hir::BodyId,
|
||||
crate name: Symbol,
|
||||
crate attrs: &'hir [ast::Attribute],
|
||||
crate vis: &'hir hir::Visibility<'hir>,
|
||||
crate id: hir::HirId,
|
||||
crate span: Span,
|
||||
}
|
||||
|
||||
crate struct Constant<'hir> {
|
||||
crate type_: &'hir hir::Ty<'hir>,
|
||||
crate expr: hir::BodyId,
|
||||
crate name: Symbol,
|
||||
crate id: hir::HirId,
|
||||
}
|
||||
|
||||
crate struct Trait<'hir> {
|
||||
crate is_auto: hir::IsAuto,
|
||||
crate unsafety: hir::Unsafety,
|
||||
@ -157,13 +89,6 @@ crate struct Trait<'hir> {
|
||||
crate id: hir::HirId,
|
||||
}
|
||||
|
||||
crate struct TraitAlias<'hir> {
|
||||
crate name: Symbol,
|
||||
crate generics: &'hir hir::Generics<'hir>,
|
||||
crate bounds: &'hir [hir::GenericBound<'hir>],
|
||||
crate id: hir::HirId,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
crate struct Impl<'hir> {
|
||||
crate unsafety: hir::Unsafety,
|
||||
|
@ -492,7 +492,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||
Res::PrimTy(prim) => Some(
|
||||
self.resolve_primitive_associated_item(prim, ns, module_id, item_name, item_str),
|
||||
),
|
||||
Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did) => {
|
||||
Res::Def(
|
||||
DefKind::Struct
|
||||
| DefKind::Union
|
||||
| DefKind::Enum
|
||||
| DefKind::TyAlias
|
||||
| DefKind::ForeignTy,
|
||||
did,
|
||||
) => {
|
||||
debug!("looking for associated item named {} for item {:?}", item_name, did);
|
||||
// Checks if item_name belongs to `impl SomeItem`
|
||||
let assoc_item = cx
|
||||
|
@ -82,50 +82,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
module
|
||||
}
|
||||
|
||||
fn visit_variant_data(
|
||||
&mut self,
|
||||
item: &'tcx hir::Item<'_>,
|
||||
name: Symbol,
|
||||
sd: &'tcx hir::VariantData<'_>,
|
||||
generics: &'tcx hir::Generics<'_>,
|
||||
) -> Struct<'tcx> {
|
||||
debug!("visiting struct");
|
||||
let struct_type = struct_type_from_def(&*sd);
|
||||
Struct { id: item.hir_id, struct_type, name, generics, fields: sd.fields() }
|
||||
}
|
||||
|
||||
fn visit_union_data(
|
||||
&mut self,
|
||||
item: &'tcx hir::Item<'_>,
|
||||
name: Symbol,
|
||||
sd: &'tcx hir::VariantData<'_>,
|
||||
generics: &'tcx hir::Generics<'_>,
|
||||
) -> Union<'tcx> {
|
||||
debug!("visiting union");
|
||||
let struct_type = struct_type_from_def(&*sd);
|
||||
Union { id: item.hir_id, struct_type, name, generics, fields: sd.fields() }
|
||||
}
|
||||
|
||||
fn visit_enum_def(
|
||||
&mut self,
|
||||
it: &'tcx hir::Item<'_>,
|
||||
name: Symbol,
|
||||
def: &'tcx hir::EnumDef<'_>,
|
||||
generics: &'tcx hir::Generics<'_>,
|
||||
) -> Enum<'tcx> {
|
||||
debug!("visiting enum");
|
||||
Enum {
|
||||
name,
|
||||
variants: def
|
||||
.variants
|
||||
.iter()
|
||||
.map(|v| Variant { name: v.ident.name, id: v.id, def: &v.data })
|
||||
.collect(),
|
||||
generics,
|
||||
id: it.hir_id,
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_fn(
|
||||
&mut self,
|
||||
om: &mut Module<'tcx>,
|
||||
@ -414,45 +370,21 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
Some(ident.name),
|
||||
));
|
||||
}
|
||||
hir::ItemKind::Enum(ref ed, ref gen) => {
|
||||
om.enums.push(self.visit_enum_def(item, ident.name, ed, gen))
|
||||
}
|
||||
hir::ItemKind::Struct(ref sd, ref gen) => {
|
||||
om.structs.push(self.visit_variant_data(item, ident.name, sd, gen))
|
||||
}
|
||||
hir::ItemKind::Union(ref sd, ref gen) => {
|
||||
om.unions.push(self.visit_union_data(item, ident.name, sd, gen))
|
||||
}
|
||||
hir::ItemKind::Fn(ref sig, ref gen, body) => {
|
||||
self.visit_fn(om, item, ident.name, &sig.decl, sig.header, gen, body)
|
||||
}
|
||||
hir::ItemKind::TyAlias(ty, ref gen) => {
|
||||
let t = Typedef { ty, gen, name: ident.name, id: item.hir_id };
|
||||
om.typedefs.push(t);
|
||||
}
|
||||
hir::ItemKind::OpaqueTy(ref opaque_ty) => {
|
||||
let t = OpaqueTy { opaque_ty, name: ident.name, id: item.hir_id };
|
||||
om.opaque_tys.push(t);
|
||||
}
|
||||
hir::ItemKind::Static(type_, mutability, expr) => {
|
||||
let s = Static {
|
||||
type_,
|
||||
mutability,
|
||||
expr,
|
||||
id: item.hir_id,
|
||||
name: ident.name,
|
||||
attrs: &item.attrs,
|
||||
span: item.span,
|
||||
vis: &item.vis,
|
||||
};
|
||||
om.statics.push(s);
|
||||
}
|
||||
hir::ItemKind::Const(type_, expr) => {
|
||||
hir::ItemKind::Enum(..)
|
||||
| hir::ItemKind::Struct(..)
|
||||
| hir::ItemKind::Union(..)
|
||||
| hir::ItemKind::TyAlias(..)
|
||||
| hir::ItemKind::OpaqueTy(..)
|
||||
| hir::ItemKind::Static(..)
|
||||
| hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed)),
|
||||
hir::ItemKind::Const(..) => {
|
||||
// Underscore constants do not correspond to a nameable item and
|
||||
// so are never useful in documentation.
|
||||
if ident.name != kw::Underscore {
|
||||
let s = Constant { type_, expr, id: item.hir_id, name: ident.name };
|
||||
om.constants.push(s);
|
||||
om.items.push((item, renamed));
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
|
||||
@ -469,11 +401,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
};
|
||||
om.traits.push(t);
|
||||
}
|
||||
hir::ItemKind::TraitAlias(ref generics, ref bounds) => {
|
||||
let t = TraitAlias { name: ident.name, generics, bounds, id: item.hir_id };
|
||||
om.trait_aliases.push(t);
|
||||
}
|
||||
|
||||
hir::ItemKind::Impl {
|
||||
unsafety,
|
||||
polarity,
|
||||
|
@ -16,12 +16,6 @@ note: the lint level is defined here
|
||||
LL | #![deny(missing_doc_code_examples)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing code example in this documentation
|
||||
--> $DIR/doc-without-codeblock.rs:3:1
|
||||
|
|
||||
LL | /// Some docs.
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: missing code example in this documentation
|
||||
--> $DIR/doc-without-codeblock.rs:7:1
|
||||
|
|
||||
@ -34,5 +28,11 @@ error: missing code example in this documentation
|
||||
LL | /// Or maybe not because she saved herself!
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing code example in this documentation
|
||||
--> $DIR/doc-without-codeblock.rs:3:1
|
||||
|
|
||||
LL | /// Some docs.
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -1,14 +1,29 @@
|
||||
error: `ambiguous` is both a struct and a function
|
||||
--> $DIR/intra-links-ambiguity.rs:27:6
|
||||
error: `true` is both a module and a builtin type
|
||||
--> $DIR/intra-links-ambiguity.rs:38:6
|
||||
|
|
||||
LL | /// [`ambiguous`] is ambiguous.
|
||||
| ^^^^^^^^^^^ ambiguous link
|
||||
LL | /// [true]
|
||||
| ^^^^ ambiguous link
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/intra-links-ambiguity.rs:1:9
|
||||
|
|
||||
LL | #![deny(broken_intra_doc_links)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: to link to the module, prefix with `mod@`
|
||||
|
|
||||
LL | /// [mod@true]
|
||||
| ^^^^^^^^
|
||||
help: to link to the builtin type, prefix with `prim@`
|
||||
|
|
||||
LL | /// [prim@true]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: `ambiguous` is both a struct and a function
|
||||
--> $DIR/intra-links-ambiguity.rs:27:6
|
||||
|
|
||||
LL | /// [`ambiguous`] is ambiguous.
|
||||
| ^^^^^^^^^^^ ambiguous link
|
||||
|
|
||||
help: to link to the struct, prefix with `struct@`
|
||||
|
|
||||
LL | /// [`struct@ambiguous`] is ambiguous.
|
||||
@ -82,20 +97,5 @@ help: to link to the function, add parentheses
|
||||
LL | /// Ambiguous non-implied shortcut link [`foo::bar()`].
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: `true` is both a module and a builtin type
|
||||
--> $DIR/intra-links-ambiguity.rs:38:6
|
||||
|
|
||||
LL | /// [true]
|
||||
| ^^^^ ambiguous link
|
||||
|
|
||||
help: to link to the module, prefix with `mod@`
|
||||
|
|
||||
LL | /// [mod@true]
|
||||
| ^^^^^^^^
|
||||
help: to link to the builtin type, prefix with `prim@`
|
||||
|
|
||||
LL | /// [prim@true]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
@ -36,6 +36,60 @@ warning: unresolved link to `Qux::Z`
|
||||
LL | //! , [Uniooon::X] and [Qux::Z].
|
||||
| ^^^^^^ no item named `Qux` in scope
|
||||
|
||||
warning: unresolved link to `BarA`
|
||||
--> $DIR/intra-links-warning.rs:21:10
|
||||
|
|
||||
LL | /// bar [BarA] bar
|
||||
| ^^^^ no item named `BarA` in scope
|
||||
|
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
|
||||
warning: unresolved link to `BarB`
|
||||
--> $DIR/intra-links-warning.rs:27:9
|
||||
|
|
||||
LL | * bar [BarB] bar
|
||||
| ^^^^ no item named `BarB` in scope
|
||||
|
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
|
||||
warning: unresolved link to `BarC`
|
||||
--> $DIR/intra-links-warning.rs:34:6
|
||||
|
|
||||
LL | bar [BarC] bar
|
||||
| ^^^^ no item named `BarC` in scope
|
||||
|
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
|
||||
warning: unresolved link to `BarD`
|
||||
--> $DIR/intra-links-warning.rs:45:1
|
||||
|
|
||||
LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the link appears in this line:
|
||||
|
||||
bar [BarD] bar
|
||||
^^^^
|
||||
= note: no item named `BarD` in scope
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
|
||||
warning: unresolved link to `BarF`
|
||||
--> $DIR/intra-links-warning.rs:50:9
|
||||
|
|
||||
LL | #[doc = $f]
|
||||
| ^^^^^^^^^^^
|
||||
...
|
||||
LL | f!("Foo\nbar [BarF] bar\nbaz");
|
||||
| ------------------------------- in this macro invocation
|
||||
|
|
||||
= note: the link appears in this line:
|
||||
|
||||
bar [BarF] bar
|
||||
^^^^
|
||||
= note: no item named `BarF` in scope
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: unresolved link to `Qux:Y`
|
||||
--> $DIR/intra-links-warning.rs:14:13
|
||||
|
|
||||
@ -117,59 +171,5 @@ LL | /// docs [error2]
|
||||
|
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
|
||||
warning: unresolved link to `BarA`
|
||||
--> $DIR/intra-links-warning.rs:21:10
|
||||
|
|
||||
LL | /// bar [BarA] bar
|
||||
| ^^^^ no item named `BarA` in scope
|
||||
|
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
|
||||
warning: unresolved link to `BarB`
|
||||
--> $DIR/intra-links-warning.rs:27:9
|
||||
|
|
||||
LL | * bar [BarB] bar
|
||||
| ^^^^ no item named `BarB` in scope
|
||||
|
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
|
||||
warning: unresolved link to `BarC`
|
||||
--> $DIR/intra-links-warning.rs:34:6
|
||||
|
|
||||
LL | bar [BarC] bar
|
||||
| ^^^^ no item named `BarC` in scope
|
||||
|
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
|
||||
warning: unresolved link to `BarD`
|
||||
--> $DIR/intra-links-warning.rs:45:1
|
||||
|
|
||||
LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the link appears in this line:
|
||||
|
||||
bar [BarD] bar
|
||||
^^^^
|
||||
= note: no item named `BarD` in scope
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
|
||||
warning: unresolved link to `BarF`
|
||||
--> $DIR/intra-links-warning.rs:50:9
|
||||
|
|
||||
LL | #[doc = $f]
|
||||
| ^^^^^^^^^^^
|
||||
...
|
||||
LL | f!("Foo\nbar [BarF] bar\nbaz");
|
||||
| ------------------------------- in this macro invocation
|
||||
|
|
||||
= note: the link appears in this line:
|
||||
|
||||
bar [BarF] bar
|
||||
^^^^
|
||||
= note: no item named `BarF` in scope
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: 19 warnings emitted
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
error: missing code example in this documentation
|
||||
--> $DIR/lint-missing-doc-code-example.rs:49:1
|
||||
--> $DIR/lint-missing-doc-code-example.rs:19:1
|
||||
|
|
||||
LL | /// Doc
|
||||
| ^^^^^^^
|
||||
LL | / mod module1 {
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/lint-missing-doc-code-example.rs:2:9
|
||||
@ -11,7 +12,13 @@ LL | #![deny(missing_doc_code_examples)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing code example in this documentation
|
||||
--> $DIR/lint-missing-doc-code-example.rs:63:1
|
||||
--> $DIR/lint-missing-doc-code-example.rs:37:3
|
||||
|
|
||||
LL | /// doc
|
||||
| ^^^^^^^
|
||||
|
||||
error: missing code example in this documentation
|
||||
--> $DIR/lint-missing-doc-code-example.rs:49:1
|
||||
|
|
||||
LL | /// Doc
|
||||
| ^^^^^^^
|
||||
@ -23,17 +30,10 @@ LL | /// Doc
|
||||
| ^^^^^^^
|
||||
|
||||
error: missing code example in this documentation
|
||||
--> $DIR/lint-missing-doc-code-example.rs:19:1
|
||||
--> $DIR/lint-missing-doc-code-example.rs:63:1
|
||||
|
|
||||
LL | / mod module1 {
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: missing code example in this documentation
|
||||
--> $DIR/lint-missing-doc-code-example.rs:37:3
|
||||
|
|
||||
LL | /// doc
|
||||
| ^^^^^^^
|
||||
LL | /// Doc
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
18
src/test/rustdoc/intra-link-extern-type.rs
Normal file
18
src/test/rustdoc/intra-link-extern-type.rs
Normal file
@ -0,0 +1,18 @@
|
||||
#![feature(extern_types)]
|
||||
|
||||
extern {
|
||||
pub type ExternType;
|
||||
}
|
||||
|
||||
impl ExternType {
|
||||
pub fn f(&self) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// @has 'intra_link_extern_type/foreigntype.ExternType.html'
|
||||
// @has 'intra_link_extern_type/fn.links_to_extern_type.html' \
|
||||
// 'href="../intra_link_extern_type/foreigntype.ExternType.html#method.f"'
|
||||
/// See also [ExternType::f]
|
||||
pub fn links_to_extern_type() {
|
||||
}
|
@ -4,6 +4,10 @@ mod hidden {
|
||||
// @has foo/hidden/struct.Foo.html
|
||||
// @has - '//p/a' '../../foo/struct.FooBar.html'
|
||||
pub struct Foo {}
|
||||
pub union U { a: usize }
|
||||
pub enum Empty {}
|
||||
pub const C: usize = 1;
|
||||
pub static S: usize = 1;
|
||||
|
||||
// @has foo/hidden/bar/index.html
|
||||
// @has - '//p/a' '../../foo/baz/index.html'
|
||||
@ -16,6 +20,14 @@ mod hidden {
|
||||
|
||||
// @has foo/struct.FooBar.html
|
||||
pub use hidden::Foo as FooBar;
|
||||
// @has foo/union.FooU.html
|
||||
pub use hidden::U as FooU;
|
||||
// @has foo/enum.FooEmpty.html
|
||||
pub use hidden::Empty as FooEmpty;
|
||||
// @has foo/constant.FooC.html
|
||||
pub use hidden::C as FooC;
|
||||
// @has foo/static.FooS.html
|
||||
pub use hidden::S as FooS;
|
||||
|
||||
// @has foo/baz/index.html
|
||||
// @has foo/baz/struct.Thing.html
|
||||
|
19
src/test/ui/consts/issue-79137-monomorphic.rs
Normal file
19
src/test/ui/consts/issue-79137-monomorphic.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// check-pass
|
||||
|
||||
// Verify that variant count intrinsic can still evaluate for types like `Option<T>`.
|
||||
|
||||
#![feature(variant_count)]
|
||||
|
||||
pub struct GetVariantCount<T>(T);
|
||||
|
||||
impl<T> GetVariantCount<T> {
|
||||
pub const VALUE: usize = std::mem::variant_count::<T>();
|
||||
}
|
||||
|
||||
const fn check_variant_count<T>() -> bool {
|
||||
matches!(GetVariantCount::<Option<T>>::VALUE, GetVariantCount::<Option<()>>::VALUE)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert!(check_variant_count::<()>());
|
||||
}
|
19
src/test/ui/consts/issue-79137-toogeneric.rs
Normal file
19
src/test/ui/consts/issue-79137-toogeneric.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Test that `variant_count` only gets evaluated once the type is concrete enough.
|
||||
|
||||
#![feature(variant_count)]
|
||||
|
||||
pub struct GetVariantCount<T>(T);
|
||||
|
||||
impl<T> GetVariantCount<T> {
|
||||
pub const VALUE: usize = std::mem::variant_count::<T>();
|
||||
}
|
||||
|
||||
const fn check_variant_count<T>() -> bool {
|
||||
matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
|
||||
//~^ ERROR constant pattern depends on a generic parameter
|
||||
//~| ERROR constant pattern depends on a generic parameter
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert!(check_variant_count::<Option<()>>());
|
||||
}
|
14
src/test/ui/consts/issue-79137-toogeneric.stderr
Normal file
14
src/test/ui/consts/issue-79137-toogeneric.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error: constant pattern depends on a generic parameter
|
||||
--> $DIR/issue-79137-toogeneric.rs:12:43
|
||||
|
|
||||
LL | matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: constant pattern depends on a generic parameter
|
||||
--> $DIR/issue-79137-toogeneric.rs:12:43
|
||||
|
|
||||
LL | matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -0,0 +1,13 @@
|
||||
// Checks that we can build a clone shim for array with generic size.
|
||||
// Regression test for issue #79269.
|
||||
//
|
||||
// build-pass
|
||||
// compile-flags: -Zmir-opt-level=2 -Zvalidate-mir
|
||||
#![feature(min_const_generics)]
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Array<T, const N: usize>([T; N]);
|
||||
|
||||
fn main() {
|
||||
let _ = Array([0u32, 1u32, 2u32]).clone();
|
||||
}
|
Loading…
Reference in New Issue
Block a user