Auto merge of #87095 - JohnTitor:rollup-mn7ggy2, r=JohnTitor
Rollup of 11 pull requests Successful merges: - #86344 (Split MaybeUninit::write into new feature gate and stabilize it) - #86811 (Remove unstable `io::Cursor::remaining`) - #86846 (stdio_locked: add tracking issue) - #86887 (rustdoc: remove dead code in `clean`) - #87007 (Fix rust-analyzer install when not available.) - #87035 (Fix implementors display) - #87065 (Fix ICE with unsized type in const pattern) - #87070 (Simplify future incompatible reporting.) - #87077 (⬆️ rust-analyzer) - #87078 (Rustdoc: suggest removing disambiguator if linking to field) - #87089 (CTFE engine: small cleanups) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
14c0c3e55d
37 changed files with 316 additions and 204 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -72,4 +72,7 @@ __pycache__/
|
|||
**node_modules
|
||||
**package-lock.json
|
||||
|
||||
## Rustdoc GUI tests
|
||||
src/test/rustdoc-gui/src/**.lock
|
||||
|
||||
# Before adding new lines, see the comment at the top.
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
use Destination::*;
|
||||
|
||||
use rustc_lint_defs::FutureBreakage;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{MultiSpan, SourceFile, Span};
|
||||
|
||||
|
@ -193,7 +192,7 @@ pub trait Emitter {
|
|||
/// other formats can, and will, simply ignore it.
|
||||
fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {}
|
||||
|
||||
fn emit_future_breakage_report(&mut self, _diags: Vec<(FutureBreakage, Diagnostic)>) {}
|
||||
fn emit_future_breakage_report(&mut self, _diags: Vec<Diagnostic>) {}
|
||||
|
||||
/// Emit list of unused externs
|
||||
fn emit_unused_externs(&mut self, _lint_level: &str, _unused_externs: &[&str]) {}
|
||||
|
|
|
@ -16,7 +16,7 @@ use crate::registry::Registry;
|
|||
use crate::DiagnosticId;
|
||||
use crate::ToolMetadata;
|
||||
use crate::{CodeSuggestion, SubDiagnostic};
|
||||
use rustc_lint_defs::{Applicability, FutureBreakage};
|
||||
use rustc_lint_defs::Applicability;
|
||||
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_span::hygiene::ExpnData;
|
||||
|
@ -134,17 +134,14 @@ impl Emitter for JsonEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
fn emit_future_breakage_report(&mut self, diags: Vec<(FutureBreakage, crate::Diagnostic)>) {
|
||||
fn emit_future_breakage_report(&mut self, diags: Vec<crate::Diagnostic>) {
|
||||
let data: Vec<FutureBreakageItem> = diags
|
||||
.into_iter()
|
||||
.map(|(breakage, mut diag)| {
|
||||
.map(|mut diag| {
|
||||
if diag.level == crate::Level::Allow {
|
||||
diag.level = crate::Level::Warning;
|
||||
}
|
||||
FutureBreakageItem {
|
||||
future_breakage_date: breakage.date,
|
||||
diagnostic: Diagnostic::from_errors_diagnostic(&diag, self),
|
||||
}
|
||||
FutureBreakageItem { diagnostic: Diagnostic::from_errors_diagnostic(&diag, self) }
|
||||
})
|
||||
.collect();
|
||||
let report = FutureIncompatReport { future_incompat_report: data };
|
||||
|
@ -326,7 +323,6 @@ struct ArtifactNotification<'a> {
|
|||
|
||||
#[derive(Encodable)]
|
||||
struct FutureBreakageItem {
|
||||
future_breakage_date: Option<&'static str>,
|
||||
diagnostic: Diagnostic,
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
|||
use rustc_data_structures::stable_hasher::StableHasher;
|
||||
use rustc_data_structures::sync::{self, Lock, Lrc};
|
||||
use rustc_data_structures::AtomicRef;
|
||||
use rustc_lint_defs::FutureBreakage;
|
||||
pub use rustc_lint_defs::{pluralize, Applicability};
|
||||
use rustc_serialize::json::Json;
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
|
@ -790,7 +789,7 @@ impl Handler {
|
|||
self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
|
||||
}
|
||||
|
||||
pub fn emit_future_breakage_report(&self, diags: Vec<(FutureBreakage, Diagnostic)>) {
|
||||
pub fn emit_future_breakage_report(&self, diags: Vec<Diagnostic>) {
|
||||
self.inner.borrow_mut().emitter.emit_future_breakage_report(diags)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//! compiler code, rather than using their own custom pass. Those
|
||||
//! lints are all available in `rustc_lint::builtin`.
|
||||
|
||||
use crate::{declare_lint, declare_lint_pass, FutureBreakage, FutureIncompatibilityReason};
|
||||
use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason};
|
||||
use rustc_span::edition::Edition;
|
||||
|
||||
declare_lint! {
|
||||
|
@ -3176,9 +3176,7 @@ declare_lint! {
|
|||
"detects usage of old versions of certain proc-macro crates",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reference: "issue #83125 <https://github.com/rust-lang/rust/issues/83125>",
|
||||
future_breakage: Some(FutureBreakage {
|
||||
date: None
|
||||
})
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -152,10 +152,6 @@ pub struct FutureIncompatibleInfo {
|
|||
/// Set to false for lints that already include a more detailed
|
||||
/// explanation.
|
||||
pub explain_reason: bool,
|
||||
/// Information about a future breakage, which will
|
||||
/// be emitted in JSON messages to be displayed by Cargo
|
||||
/// for upstream deps
|
||||
pub future_breakage: Option<FutureBreakage>,
|
||||
}
|
||||
|
||||
/// The reason for future incompatibility
|
||||
|
@ -164,6 +160,9 @@ pub enum FutureIncompatibilityReason {
|
|||
/// This will be an error in a future release
|
||||
/// for all editions
|
||||
FutureReleaseError,
|
||||
/// This will be an error in a future release, and
|
||||
/// Cargo should create a report even for dependencies
|
||||
FutureReleaseErrorReportNow,
|
||||
/// Previously accepted code that will become an
|
||||
/// error in the provided edition
|
||||
EditionError(Edition),
|
||||
|
@ -182,18 +181,12 @@ impl FutureIncompatibilityReason {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct FutureBreakage {
|
||||
pub date: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl FutureIncompatibleInfo {
|
||||
pub const fn default_fields_for_macro() -> Self {
|
||||
FutureIncompatibleInfo {
|
||||
reference: "",
|
||||
reason: FutureIncompatibilityReason::FutureReleaseError,
|
||||
explain_reason: true,
|
||||
future_breakage: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc_hir::HirId;
|
|||
use rustc_index::vec::IndexVec;
|
||||
use rustc_session::lint::{
|
||||
builtin::{self, FORBIDDEN_LINT_GROUPS},
|
||||
FutureIncompatibilityReason, Level, Lint, LintId,
|
||||
FutureIncompatibilityReason, FutureIncompatibleInfo, Level, Lint, LintId,
|
||||
};
|
||||
use rustc_session::{DiagnosticMessageId, Session};
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
|
@ -223,8 +223,13 @@ pub fn struct_lint_level<'s, 'd>(
|
|||
let lint_id = LintId::of(lint);
|
||||
let future_incompatible = lint.future_incompatible;
|
||||
|
||||
let has_future_breakage =
|
||||
future_incompatible.map_or(false, |incompat| incompat.future_breakage.is_some());
|
||||
let has_future_breakage = matches!(
|
||||
future_incompatible,
|
||||
Some(FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
|
||||
..
|
||||
})
|
||||
);
|
||||
|
||||
let mut err = match (level, span) {
|
||||
(Level::Allow, span) => {
|
||||
|
|
|
@ -512,7 +512,7 @@ impl InitMaskCompressed {
|
|||
/// Transferring the initialization mask to other allocations.
|
||||
impl<Tag, Extra> Allocation<Tag, Extra> {
|
||||
/// Creates a run-length encoding of the initialization mask.
|
||||
pub fn compress_uninit_range(&self, src: Pointer<Tag>, size: Size) -> InitMaskCompressed {
|
||||
pub fn compress_uninit_range(&self, range: AllocRange) -> InitMaskCompressed {
|
||||
// Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`),
|
||||
// a naive initialization mask copying algorithm would repeatedly have to read the initialization mask from
|
||||
// the source and write it to the destination. Even if we optimized the memory accesses,
|
||||
|
@ -526,13 +526,13 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
|
|||
// where each element toggles the state.
|
||||
|
||||
let mut ranges = smallvec::SmallVec::<[u64; 1]>::new();
|
||||
let initial = self.init_mask.get(src.offset);
|
||||
let initial = self.init_mask.get(range.start);
|
||||
let mut cur_len = 1;
|
||||
let mut cur = initial;
|
||||
|
||||
for i in 1..size.bytes() {
|
||||
for i in 1..range.size.bytes() {
|
||||
// FIXME: optimize to bitshift the current uninitialized block's bits and read the top bit.
|
||||
if self.init_mask.get(src.offset + Size::from_bytes(i)) == cur {
|
||||
if self.init_mask.get(range.start + Size::from_bytes(i)) == cur {
|
||||
cur_len += 1;
|
||||
} else {
|
||||
ranges.push(cur_len);
|
||||
|
@ -550,24 +550,23 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
|
|||
pub fn mark_compressed_init_range(
|
||||
&mut self,
|
||||
defined: &InitMaskCompressed,
|
||||
dest: Pointer<Tag>,
|
||||
size: Size,
|
||||
range: AllocRange,
|
||||
repeat: u64,
|
||||
) {
|
||||
// An optimization where we can just overwrite an entire range of initialization
|
||||
// bits if they are going to be uniformly `1` or `0`.
|
||||
if defined.ranges.len() <= 1 {
|
||||
self.init_mask.set_range_inbounds(
|
||||
dest.offset,
|
||||
dest.offset + size * repeat, // `Size` operations
|
||||
range.start,
|
||||
range.start + range.size * repeat, // `Size` operations
|
||||
defined.initial,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
for mut j in 0..repeat {
|
||||
j *= size.bytes();
|
||||
j += dest.offset.bytes();
|
||||
j *= range.size.bytes();
|
||||
j += range.start.bytes();
|
||||
let mut cur = defined.initial;
|
||||
for range in &defined.ranges {
|
||||
let old_j = j;
|
||||
|
|
|
@ -18,8 +18,8 @@ use rustc_span::{Pos, Span};
|
|||
use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
|
||||
|
||||
use super::{
|
||||
Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, Operand, Place, PlaceTy,
|
||||
ScalarMaybeUninit, StackPopJump,
|
||||
Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, MemoryKind, Operand, Place,
|
||||
PlaceTy, ScalarMaybeUninit, StackPopJump,
|
||||
};
|
||||
use crate::transform::validate::equal_up_to_regions;
|
||||
use crate::util::storage::AlwaysLiveLocals;
|
||||
|
@ -900,7 +900,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// due to the local having ZST type.
|
||||
let ptr = ptr.assert_ptr();
|
||||
trace!("deallocating local: {:?}", self.memory.dump_alloc(ptr.alloc_id));
|
||||
self.memory.deallocate_local(ptr)?;
|
||||
self.memory.deallocate(ptr, None, MemoryKind::Stack)?;
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -276,17 +276,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||
Ok(new_ptr)
|
||||
}
|
||||
|
||||
/// Deallocate a local, or do nothing if that local has been made into a global.
|
||||
pub fn deallocate_local(&mut self, ptr: Pointer<M::PointerTag>) -> InterpResult<'tcx> {
|
||||
// The allocation might be already removed by global interning.
|
||||
// This can only really happen in the CTFE instance, not in miri.
|
||||
if self.alloc_map.contains_key(&ptr.alloc_id) {
|
||||
self.deallocate(ptr, None, MemoryKind::Stack)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deallocate(
|
||||
&mut self,
|
||||
ptr: Pointer<M::PointerTag>,
|
||||
|
@ -1049,7 +1038,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||
num_copies,
|
||||
);
|
||||
// Prepare a copy of the initialization mask.
|
||||
let compressed = src_alloc.compress_uninit_range(src, size);
|
||||
let compressed = src_alloc.compress_uninit_range(alloc_range(src.offset, size));
|
||||
// This checks relocation edges on the src.
|
||||
let src_bytes = src_alloc
|
||||
.get_bytes_with_uninit_and_ptr(&tcx, alloc_range(src.offset, size))
|
||||
|
@ -1110,7 +1099,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||
}
|
||||
|
||||
// now fill in all the "init" data
|
||||
dest_alloc.mark_compressed_init_range(&compressed, dest, size, num_copies);
|
||||
dest_alloc.mark_compressed_init_range(
|
||||
&compressed,
|
||||
alloc_range(dest.offset, size),
|
||||
num_copies,
|
||||
);
|
||||
// copy the relocations to the destination
|
||||
dest_alloc.mark_relocation_range(relocations);
|
||||
|
||||
|
|
|
@ -490,17 +490,29 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
// convert the dereferenced constant to a pattern that is the sub-pattern of the
|
||||
// deref pattern.
|
||||
_ => {
|
||||
let old = self.behind_reference.replace(true);
|
||||
// In case there are structural-match violations somewhere in this subpattern,
|
||||
// we fall back to a const pattern. If we do not do this, we may end up with
|
||||
// a !structural-match constant that is not of reference type, which makes it
|
||||
// very hard to invoke `PartialEq::eq` on it as a fallback.
|
||||
let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) {
|
||||
Ok(subpattern) => PatKind::Deref { subpattern },
|
||||
Err(_) => PatKind::Constant { value: cv },
|
||||
};
|
||||
self.behind_reference.set(old);
|
||||
val
|
||||
if !pointee_ty.is_sized(tcx.at(span), param_env) {
|
||||
// `tcx.deref_const()` below will ICE with an unsized type
|
||||
// (except slices, which are handled in a separate arm above).
|
||||
let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
|
||||
if self.include_lint_checks {
|
||||
tcx.sess.span_err(span, &msg);
|
||||
} else {
|
||||
tcx.sess.delay_span_bug(span, &msg);
|
||||
}
|
||||
PatKind::Wild
|
||||
} else {
|
||||
let old = self.behind_reference.replace(true);
|
||||
// In case there are structural-match violations somewhere in this subpattern,
|
||||
// we fall back to a const pattern. If we do not do this, we may end up with
|
||||
// a !structural-match constant that is not of reference type, which makes it
|
||||
// very hard to invoke `PartialEq::eq` on it as a fallback.
|
||||
let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) {
|
||||
Ok(subpattern) => PatKind::Deref { subpattern },
|
||||
Err(_) => PatKind::Constant { value: cv },
|
||||
};
|
||||
self.behind_reference.set(old);
|
||||
val
|
||||
}
|
||||
}
|
||||
},
|
||||
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => {
|
||||
|
|
|
@ -20,8 +20,7 @@ use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter;
|
|||
use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType};
|
||||
use rustc_errors::json::JsonEmitter;
|
||||
use rustc_errors::registry::Registry;
|
||||
use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported};
|
||||
use rustc_lint_defs::FutureBreakage;
|
||||
use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorReported};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
pub use rustc_span::def_id::StableCrateId;
|
||||
use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
|
||||
|
@ -317,23 +316,7 @@ impl Session {
|
|||
if diags.is_empty() {
|
||||
return;
|
||||
}
|
||||
// If any future-breakage lints were registered, this lint store
|
||||
// should be available
|
||||
let lint_store = self.lint_store.get().expect("`lint_store` not initialized!");
|
||||
let diags_and_breakage: Vec<(FutureBreakage, Diagnostic)> = diags
|
||||
.into_iter()
|
||||
.map(|diag| {
|
||||
let lint_name = match &diag.code {
|
||||
Some(DiagnosticId::Lint { name, has_future_breakage: true, .. }) => name,
|
||||
_ => panic!("Unexpected code in diagnostic {:?}", diag),
|
||||
};
|
||||
let lint = lint_store.name_to_lint(&lint_name);
|
||||
let future_breakage =
|
||||
lint.lint.future_incompatible.unwrap().future_breakage.unwrap();
|
||||
(future_breakage, diag)
|
||||
})
|
||||
.collect();
|
||||
self.parse_sess.span_diagnostic.emit_future_breakage_report(diags_and_breakage);
|
||||
self.parse_sess.span_diagnostic.emit_future_breakage_report(diags);
|
||||
}
|
||||
|
||||
pub fn local_stable_crate_id(&self) -> StableCrateId {
|
||||
|
|
|
@ -79,7 +79,7 @@ use crate::ptr;
|
|||
/// // a `MaybeUninit<T>` may be invalid, and hence this is not UB:
|
||||
/// let mut x = MaybeUninit::<&i32>::uninit();
|
||||
/// // Set it to a valid value.
|
||||
/// unsafe { x.as_mut_ptr().write(&0); }
|
||||
/// x.write(&0);
|
||||
/// // Extract the initialized data -- this is only allowed *after* properly
|
||||
/// // initializing `x`!
|
||||
/// let x = unsafe { x.assume_init() };
|
||||
|
@ -135,7 +135,7 @@ use crate::ptr;
|
|||
/// // this loop, we have a memory leak, but there is no memory safety
|
||||
/// // issue.
|
||||
/// for elem in &mut data[..] {
|
||||
/// *elem = MaybeUninit::new(vec![42]);
|
||||
/// elem.write(vec![42]);
|
||||
/// }
|
||||
///
|
||||
/// // Everything is initialized. Transmute the array to the
|
||||
|
@ -161,7 +161,7 @@ use crate::ptr;
|
|||
/// let mut data_len: usize = 0;
|
||||
///
|
||||
/// for elem in &mut data[0..500] {
|
||||
/// *elem = MaybeUninit::new(String::from("hello"));
|
||||
/// elem.write(String::from("hello"));
|
||||
/// data_len += 1;
|
||||
/// }
|
||||
///
|
||||
|
@ -410,7 +410,7 @@ impl<T> MaybeUninit<T> {
|
|||
/// (now safely initialized) contents of `self`.
|
||||
///
|
||||
/// As the content is stored inside a `MaybeUninit`, the destructor is not
|
||||
/// ran for the inner data if the MaybeUninit leaves scope without a call to
|
||||
/// run for the inner data if the MaybeUninit leaves scope without a call to
|
||||
/// [`assume_init`], [`assume_init_drop`], or similar. Code that receives
|
||||
/// the mutable reference returned by this function needs to keep this in
|
||||
/// mind. The safety model of Rust regards leaks as safe, but they are
|
||||
|
@ -426,7 +426,6 @@ impl<T> MaybeUninit<T> {
|
|||
/// Correct usage of this method:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(maybe_uninit_extra)]
|
||||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut x = MaybeUninit::<Vec<u8>>::uninit();
|
||||
|
@ -445,7 +444,6 @@ impl<T> MaybeUninit<T> {
|
|||
/// This usage of the method causes a leak:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(maybe_uninit_extra)]
|
||||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut x = MaybeUninit::<String>::uninit();
|
||||
|
@ -456,8 +454,38 @@ impl<T> MaybeUninit<T> {
|
|||
/// // x is initialized now:
|
||||
/// let s = unsafe { x.assume_init() };
|
||||
/// ```
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
#[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
///
|
||||
/// This method can be used to avoid unsafe in some cases. The example below
|
||||
/// shows a part of an implementation of a fixed sized arena that lends out
|
||||
/// pinned references.
|
||||
/// With `write`, we can avoid the need to write through a raw pointer:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(maybe_uninit_extra)]
|
||||
/// use core::pin::Pin;
|
||||
/// use core::mem::MaybeUninit;
|
||||
///
|
||||
/// struct PinArena<T> {
|
||||
/// memory: Box<[MaybeUninit<T>]>,
|
||||
/// len: usize,
|
||||
/// }
|
||||
///
|
||||
/// impl <T> PinArena<T> {
|
||||
/// pub fn capacity(&self) -> usize {
|
||||
/// self.memory.len()
|
||||
/// }
|
||||
/// pub fn push(&mut self, val: T) -> Pin<&mut T> {
|
||||
/// if self.len >= self.capacity() {
|
||||
/// panic!("Attempted to push to a full pin arena!");
|
||||
/// }
|
||||
/// let ref_ = self.memory[self.len].write(val);
|
||||
/// self.len += 1;
|
||||
/// unsafe { Pin::new_unchecked(ref_) }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "maybe_uninit_write", since = "1.55.0")]
|
||||
#[rustc_const_unstable(feature = "const_maybe_uninit_write", issue = "63567")]
|
||||
#[inline(always)]
|
||||
pub const fn write(&mut self, val: T) -> &mut T {
|
||||
*self = MaybeUninit::new(val);
|
||||
|
@ -478,7 +506,7 @@ impl<T> MaybeUninit<T> {
|
|||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut x = MaybeUninit::<Vec<u32>>::uninit();
|
||||
/// unsafe { x.as_mut_ptr().write(vec![0, 1, 2]); }
|
||||
/// x.write(vec![0, 1, 2]);
|
||||
/// // Create a reference into the `MaybeUninit<T>`. This is okay because we initialized it.
|
||||
/// let x_vec = unsafe { &*x.as_ptr() };
|
||||
/// assert_eq!(x_vec.len(), 3);
|
||||
|
@ -515,7 +543,7 @@ impl<T> MaybeUninit<T> {
|
|||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut x = MaybeUninit::<Vec<u32>>::uninit();
|
||||
/// unsafe { x.as_mut_ptr().write(vec![0, 1, 2]); }
|
||||
/// x.write(vec![0, 1, 2]);
|
||||
/// // Create a reference into the `MaybeUninit<Vec<u32>>`.
|
||||
/// // This is okay because we initialized it.
|
||||
/// let x_vec = unsafe { &mut *x.as_mut_ptr() };
|
||||
|
@ -574,7 +602,7 @@ impl<T> MaybeUninit<T> {
|
|||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut x = MaybeUninit::<bool>::uninit();
|
||||
/// unsafe { x.as_mut_ptr().write(true); }
|
||||
/// x.write(true);
|
||||
/// let x_init = unsafe { x.assume_init() };
|
||||
/// assert_eq!(x_init, true);
|
||||
/// ```
|
||||
|
@ -723,7 +751,7 @@ impl<T> MaybeUninit<T> {
|
|||
///
|
||||
/// let mut x = MaybeUninit::<Vec<u32>>::uninit();
|
||||
/// // Initialize `x`:
|
||||
/// unsafe { x.as_mut_ptr().write(vec![1, 2, 3]); }
|
||||
/// x.write(vec![1, 2, 3]);
|
||||
/// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to
|
||||
/// // create a shared reference to it:
|
||||
/// let x: &Vec<u32> = unsafe {
|
||||
|
@ -897,9 +925,9 @@ impl<T> MaybeUninit<T> {
|
|||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut array: [MaybeUninit<i32>; 3] = MaybeUninit::uninit_array();
|
||||
/// array[0] = MaybeUninit::new(0);
|
||||
/// array[1] = MaybeUninit::new(1);
|
||||
/// array[2] = MaybeUninit::new(2);
|
||||
/// array[0].write(0);
|
||||
/// array[1].write(1);
|
||||
/// array[2].write(2);
|
||||
///
|
||||
/// // SAFETY: Now safe as we initialised all elements
|
||||
/// let array = unsafe {
|
||||
|
|
|
@ -209,32 +209,6 @@ impl<T> Cursor<T>
|
|||
where
|
||||
T: AsRef<[u8]>,
|
||||
{
|
||||
/// Returns the remaining length.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(cursor_remaining)]
|
||||
/// use std::io::Cursor;
|
||||
///
|
||||
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
|
||||
///
|
||||
/// assert_eq!(buff.remaining(), 5);
|
||||
///
|
||||
/// buff.set_position(2);
|
||||
/// assert_eq!(buff.remaining(), 3);
|
||||
///
|
||||
/// buff.set_position(4);
|
||||
/// assert_eq!(buff.remaining(), 1);
|
||||
///
|
||||
/// buff.set_position(6);
|
||||
/// assert_eq!(buff.remaining(), 0);
|
||||
/// ```
|
||||
#[unstable(feature = "cursor_remaining", issue = "86369")]
|
||||
pub fn remaining(&self) -> u64 {
|
||||
(self.inner.as_ref().len() as u64).checked_sub(self.pos).unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Returns the remaining slice.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
@ -277,7 +277,7 @@ pub use self::error::{Error, ErrorKind, Result};
|
|||
pub use self::stdio::set_output_capture;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout};
|
||||
#[unstable(feature = "stdio_locked", issue = "none")]
|
||||
#[unstable(feature = "stdio_locked", issue = "86845")]
|
||||
pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::stdio::{StderrLock, StdinLock, StdoutLock};
|
||||
|
|
|
@ -347,7 +347,7 @@ pub fn stdin() -> Stdin {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "stdio_locked", issue = "none")]
|
||||
#[unstable(feature = "stdio_locked", issue = "86845")]
|
||||
pub fn stdin_locked() -> StdinLock<'static> {
|
||||
stdin().into_locked()
|
||||
}
|
||||
|
@ -442,7 +442,7 @@ impl Stdin {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "stdio_locked", issue = "none")]
|
||||
#[unstable(feature = "stdio_locked", issue = "86845")]
|
||||
pub fn into_locked(self) -> StdinLock<'static> {
|
||||
self.lock_any()
|
||||
}
|
||||
|
@ -668,7 +668,7 @@ pub fn stdout() -> Stdout {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "stdio_locked", issue = "none")]
|
||||
#[unstable(feature = "stdio_locked", issue = "86845")]
|
||||
pub fn stdout_locked() -> StdoutLock<'static> {
|
||||
stdout().into_locked()
|
||||
}
|
||||
|
@ -745,7 +745,7 @@ impl Stdout {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "stdio_locked", issue = "none")]
|
||||
#[unstable(feature = "stdio_locked", issue = "86845")]
|
||||
pub fn into_locked(self) -> StdoutLock<'static> {
|
||||
self.lock_any()
|
||||
}
|
||||
|
@ -945,7 +945,7 @@ pub fn stderr() -> Stderr {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "stdio_locked", issue = "none")]
|
||||
#[unstable(feature = "stdio_locked", issue = "86845")]
|
||||
pub fn stderr_locked() -> StderrLock<'static> {
|
||||
stderr().into_locked()
|
||||
}
|
||||
|
@ -1005,7 +1005,7 @@ impl Stderr {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "stdio_locked", issue = "none")]
|
||||
#[unstable(feature = "stdio_locked", issue = "86845")]
|
||||
pub fn into_locked(self) -> StderrLock<'static> {
|
||||
self.lock_any()
|
||||
}
|
||||
|
|
|
@ -139,11 +139,17 @@ macro_rules! install {
|
|||
|
||||
install!((self, builder, _config),
|
||||
Docs, "src/doc", _config.docs, only_hosts: false, {
|
||||
let tarball = builder.ensure(dist::Docs { host: self.target }).expect("missing docs");
|
||||
install_sh(builder, "docs", self.compiler.stage, Some(self.target), &tarball);
|
||||
if let Some(tarball) = builder.ensure(dist::Docs { host: self.target }) {
|
||||
install_sh(builder, "docs", self.compiler.stage, Some(self.target), &tarball);
|
||||
} else {
|
||||
panic!("docs are not available to install, \
|
||||
check that `build.docs` is true in `config.toml`");
|
||||
}
|
||||
};
|
||||
Std, "library/std", true, only_hosts: false, {
|
||||
for target in &builder.targets {
|
||||
// `expect` should be safe, only None when host != build, but this
|
||||
// only runs when host == build
|
||||
let tarball = builder.ensure(dist::Std {
|
||||
compiler: self.compiler,
|
||||
target: *target
|
||||
|
@ -165,10 +171,15 @@ install!((self, builder, _config),
|
|||
}
|
||||
};
|
||||
RustAnalyzer, "rust-analyzer", Self::should_build(_config), only_hosts: true, {
|
||||
let tarball = builder
|
||||
.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target })
|
||||
.expect("missing rust-analyzer");
|
||||
install_sh(builder, "rust-analyzer", self.compiler.stage, Some(self.target), &tarball);
|
||||
if let Some(tarball) =
|
||||
builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target })
|
||||
{
|
||||
install_sh(builder, "rust-analyzer", self.compiler.stage, Some(self.target), &tarball);
|
||||
} else {
|
||||
builder.info(
|
||||
&format!("skipping Install rust-analyzer stage{} ({})", self.compiler.stage, self.target),
|
||||
);
|
||||
}
|
||||
};
|
||||
Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
|
||||
let tarball = builder.ensure(dist::Clippy { compiler: self.compiler, target: self.target });
|
||||
|
@ -212,6 +223,8 @@ install!((self, builder, _config),
|
|||
}
|
||||
};
|
||||
Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
|
||||
// `expect` should be safe, only None with host != build, but this
|
||||
// only uses the `build` compiler
|
||||
let tarball = builder.ensure(dist::Analysis {
|
||||
// Find the actual compiler (handling the full bootstrap option) which
|
||||
// produced the save-analysis data because that data isn't copied
|
||||
|
|
|
@ -907,27 +907,25 @@ impl Step for RustdocGUI {
|
|||
// We remove existing folder to be sure there won't be artifacts remaining.
|
||||
let _ = fs::remove_dir_all(&out_dir);
|
||||
|
||||
let mut nb_generated = 0;
|
||||
let src_path = "src/test/rustdoc-gui/src";
|
||||
// We generate docs for the libraries present in the rustdoc-gui's src folder.
|
||||
let libs_dir = builder.build.src.join("src/test/rustdoc-gui/src");
|
||||
for entry in libs_dir.read_dir().expect("read_dir call failed") {
|
||||
let entry = entry.expect("invalid entry");
|
||||
let path = entry.path();
|
||||
if path.extension().map(|e| e == "rs").unwrap_or(false) {
|
||||
let mut command = builder.rustdoc_cmd(self.compiler);
|
||||
command.arg(path).arg("-o").arg(&out_dir);
|
||||
builder.run(&mut command);
|
||||
nb_generated += 1;
|
||||
}
|
||||
}
|
||||
assert!(nb_generated > 0, "no documentation was generated...");
|
||||
let mut cargo = Command::new(&builder.initial_cargo);
|
||||
cargo
|
||||
.arg("doc")
|
||||
.arg("--workspace")
|
||||
.arg("--target-dir")
|
||||
.arg(&out_dir)
|
||||
.env("RUSTDOC", builder.rustdoc(self.compiler))
|
||||
.env("RUSTC", builder.rustc(self.compiler))
|
||||
.current_dir(&builder.build.src.join(src_path));
|
||||
builder.run(&mut cargo);
|
||||
|
||||
// We now run GUI tests.
|
||||
let mut command = Command::new(&nodejs);
|
||||
command
|
||||
.arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js"))
|
||||
.arg("--doc-folder")
|
||||
.arg(out_dir)
|
||||
.arg(out_dir.join("doc"))
|
||||
.arg("--tests-folder")
|
||||
.arg(builder.build.src.join("src/test/rustdoc-gui"));
|
||||
for path in &builder.paths {
|
||||
|
|
|
@ -98,7 +98,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
|
|||
visibility: Inherited,
|
||||
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
|
||||
kind: box ImplItem(Impl {
|
||||
span: self.cx.tcx.def_span(impl_def_id).clean(self.cx),
|
||||
span: Span::from_rustc_span(self.cx.tcx.def_span(impl_def_id)),
|
||||
unsafety: hir::Unsafety::Normal,
|
||||
generics: (
|
||||
self.cx.tcx.generics_of(impl_def_id),
|
||||
|
|
|
@ -227,20 +227,6 @@ impl<'tcx> Clean<GenericBound> for ty::PolyTraitRef<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Clean<Option<Vec<GenericBound>>> for InternalSubsts<'tcx> {
|
||||
fn clean(&self, cx: &mut DocContext<'_>) -> Option<Vec<GenericBound>> {
|
||||
let mut v = Vec::new();
|
||||
v.extend(self.regions().filter_map(|r| r.clean(cx)).map(GenericBound::Outlives));
|
||||
v.extend(self.types().map(|t| {
|
||||
GenericBound::TraitBound(
|
||||
PolyTrait { trait_: t.clean(cx), generic_params: Vec::new() },
|
||||
hir::TraitBoundModifier::None,
|
||||
)
|
||||
}));
|
||||
if !v.is_empty() { Some(v) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Lifetime> for hir::Lifetime {
|
||||
fn clean(&self, cx: &mut DocContext<'_>) -> Lifetime {
|
||||
let def = cx.tcx.named_region(self.hir_id);
|
||||
|
@ -296,12 +282,6 @@ impl Clean<Constant> for hir::ConstArg {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clean<Lifetime> for ty::GenericParamDef {
|
||||
fn clean(&self, _cx: &mut DocContext<'_>) -> Lifetime {
|
||||
Lifetime(self.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Option<Lifetime>> for ty::RegionKind {
|
||||
fn clean(&self, _cx: &mut DocContext<'_>) -> Option<Lifetime> {
|
||||
match *self {
|
||||
|
@ -1764,12 +1744,6 @@ impl Clean<Variant> for hir::VariantData<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clean<Span> for rustc_span::Span {
|
||||
fn clean(&self, _cx: &mut DocContext<'_>) -> Span {
|
||||
Span::from_rustc_span(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Path> for hir::Path<'_> {
|
||||
fn clean(&self, cx: &mut DocContext<'_>) -> Path {
|
||||
Path {
|
||||
|
@ -2193,22 +2167,3 @@ impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum SimpleBound {
|
||||
TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParamDef>, hir::TraitBoundModifier),
|
||||
Outlives(Lifetime),
|
||||
}
|
||||
|
||||
impl From<GenericBound> for SimpleBound {
|
||||
fn from(bound: GenericBound) -> Self {
|
||||
match bound.clone() {
|
||||
GenericBound::Outlives(l) => SimpleBound::Outlives(l),
|
||||
GenericBound::TraitBound(t, mod_) => match t.trait_ {
|
||||
Type::ResolvedPath { path, .. } => {
|
||||
SimpleBound::TraitBound(path.segments, Vec::new(), t.generic_params, mod_)
|
||||
}
|
||||
_ => panic!("Unexpected bound {:?}", bound),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -683,6 +683,9 @@ function hideThemeButtonState() {
|
|||
});
|
||||
}
|
||||
|
||||
var currentNbImpls = implementors.getElementsByClassName("impl").length;
|
||||
var traitName = document.querySelector("h1.fqn > .in-band > .trait").textContent;
|
||||
var baseIdName = "impl-" + traitName + "-";
|
||||
var libs = Object.getOwnPropertyNames(imp);
|
||||
for (var i = 0, llength = libs.length; i < llength; ++i) {
|
||||
if (libs[i] === window.currentCrate) { continue; }
|
||||
|
@ -705,6 +708,7 @@ function hideThemeButtonState() {
|
|||
|
||||
var code = document.createElement("code");
|
||||
code.innerHTML = struct.text;
|
||||
addClass(code, "in-band");
|
||||
|
||||
onEachLazy(code.getElementsByTagName("a"), function(elem) {
|
||||
var href = elem.getAttribute("href");
|
||||
|
@ -714,12 +718,18 @@ function hideThemeButtonState() {
|
|||
}
|
||||
});
|
||||
|
||||
var display = document.createElement("h3");
|
||||
var currentId = baseIdName + currentNbImpls;
|
||||
var anchor = document.createElement("a");
|
||||
anchor.href = "#" + currentId;
|
||||
addClass(anchor, "anchor");
|
||||
|
||||
var display = document.createElement("div");
|
||||
display.id = currentId;
|
||||
addClass(display, "impl");
|
||||
display.innerHTML = "<span class=\"in-band\"><table class=\"table-display\">" +
|
||||
"<tbody><tr><td><code>" + code.outerHTML + "</code></td><td></td></tr>" +
|
||||
"</tbody></table></span>";
|
||||
display.appendChild(anchor);
|
||||
display.appendChild(code);
|
||||
list.appendChild(display);
|
||||
currentNbImpls += 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1610,6 +1610,8 @@ impl Disambiguator {
|
|||
return Suggestion::Macro;
|
||||
} else if kind == DefKind::Fn || kind == DefKind::AssocFn {
|
||||
return Suggestion::Function;
|
||||
} else if kind == DefKind::Field {
|
||||
return Suggestion::RemoveDisambiguator;
|
||||
}
|
||||
|
||||
let prefix = match kind {
|
||||
|
@ -1674,6 +1676,8 @@ enum Suggestion {
|
|||
Function,
|
||||
/// `m!`
|
||||
Macro,
|
||||
/// `foo` without any disambiguator
|
||||
RemoveDisambiguator,
|
||||
}
|
||||
|
||||
impl Suggestion {
|
||||
|
@ -1682,6 +1686,7 @@ impl Suggestion {
|
|||
Self::Prefix(x) => format!("prefix with `{}@`", x).into(),
|
||||
Self::Function => "add parentheses".into(),
|
||||
Self::Macro => "add an exclamation mark".into(),
|
||||
Self::RemoveDisambiguator => "remove the disambiguator".into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1691,6 +1696,7 @@ impl Suggestion {
|
|||
Self::Prefix(prefix) => format!("{}@{}", prefix, path_str),
|
||||
Self::Function => format!("{}()", path_str),
|
||||
Self::Macro => format!("{}!", path_str),
|
||||
Self::RemoveDisambiguator => path_str.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
16
src/test/rustdoc-gui/implementors.goml
Normal file
16
src/test/rustdoc-gui/implementors.goml
Normal file
|
@ -0,0 +1,16 @@
|
|||
// The goal of this test is to check that the external trait implementors, generated with JS,
|
||||
// have the same display than the "local" ones.
|
||||
goto: file://|DOC_PATH|/implementors/trait.Whatever.html
|
||||
assert: "#implementors-list"
|
||||
// There are supposed to be two implementors listed.
|
||||
assert-count: ("#implementors-list > .impl", 2)
|
||||
// Now we check that both implementors have an anchor, an ID and a similar DOM.
|
||||
assert: ("#implementors-list > .impl:nth-child(1) > a.anchor")
|
||||
assert-attribute: ("#implementors-list > .impl:nth-child(1)", {"id": "impl-Whatever"})
|
||||
assert-attribute: ("#implementors-list > .impl:nth-child(1) > a.anchor", {"href": "#impl-Whatever"})
|
||||
assert: "#implementors-list > .impl:nth-child(1) > code.in-band"
|
||||
|
||||
assert: ("#implementors-list > .impl:nth-child(2) > a.anchor")
|
||||
assert-attribute: ("#implementors-list > .impl:nth-child(2)", {"id": "impl-Whatever-1"})
|
||||
assert-attribute: ("#implementors-list > .impl:nth-child(2) > a.anchor", {"href": "#impl-Whatever-1"})
|
||||
assert: "#implementors-list > .impl:nth-child(2) > code.in-band"
|
18
src/test/rustdoc-gui/src/Cargo.lock
Normal file
18
src/test/rustdoc-gui/src/Cargo.lock
Normal file
|
@ -0,0 +1,18 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "implementors"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "lib2"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"implementors",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test_docs"
|
||||
version = "0.1.0"
|
6
src/test/rustdoc-gui/src/Cargo.toml
Normal file
6
src/test/rustdoc-gui/src/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"test_docs",
|
||||
"lib2",
|
||||
"implementors",
|
||||
]
|
7
src/test/rustdoc-gui/src/implementors/Cargo.toml
Normal file
7
src/test/rustdoc-gui/src/implementors/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "implementors"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
7
src/test/rustdoc-gui/src/implementors/lib.rs
Normal file
7
src/test/rustdoc-gui/src/implementors/lib.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
pub trait Whatever {
|
||||
fn method() {}
|
||||
}
|
||||
|
||||
pub struct Struct;
|
||||
|
||||
impl Whatever for Struct {}
|
10
src/test/rustdoc-gui/src/lib2/Cargo.toml
Normal file
10
src/test/rustdoc-gui/src/lib2/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "lib2"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
implementors = { path = "../implementors" }
|
|
@ -31,3 +31,5 @@ impl Trait for Foo {
|
|||
type X = u32;
|
||||
const Y: u32 = 0;
|
||||
}
|
||||
|
||||
impl implementors::Whatever for Foo {}
|
7
src/test/rustdoc-gui/src/lib2/src/lib.rs
Normal file
7
src/test/rustdoc-gui/src/lib2/src/lib.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
7
src/test/rustdoc-gui/src/test_docs/Cargo.toml
Normal file
7
src/test/rustdoc-gui/src/test_docs/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "test_docs"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
11
src/test/rustdoc-ui/intra-doc/field-ice.rs
Normal file
11
src/test/rustdoc-ui/intra-doc/field-ice.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
//~^NOTE the lint level is defined here
|
||||
|
||||
/// [`Foo::bar`]
|
||||
/// [`Foo::bar()`]
|
||||
//~^ERROR incompatible link kind for `Foo::bar`
|
||||
//~|HELP to link to the field, remove the disambiguator
|
||||
//~|NOTE this link resolved to a field, which is not a function
|
||||
pub struct Foo {
|
||||
pub bar: u8
|
||||
}
|
15
src/test/rustdoc-ui/intra-doc/field-ice.stderr
Normal file
15
src/test/rustdoc-ui/intra-doc/field-ice.stderr
Normal file
|
@ -0,0 +1,15 @@
|
|||
error: incompatible link kind for `Foo::bar`
|
||||
--> $DIR/field-ice.rs:5:6
|
||||
|
|
||||
LL | /// [`Foo::bar()`]
|
||||
| ^^^^^^^^^^^^ help: to link to the field, remove the disambiguator: ``Foo::bar``
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/field-ice.rs:1:9
|
||||
|
|
||||
LL | #![deny(rustdoc::broken_intra_doc_links)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: this link resolved to a field, which is not a function
|
||||
|
||||
error: aborting due to previous error
|
||||
|
34
src/test/ui/consts/issue-87046.rs
Normal file
34
src/test/ui/consts/issue-87046.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
// Regression test for the ICE described in #87046.
|
||||
|
||||
#![crate_type="lib"]
|
||||
#![allow(unreachable_patterns)]
|
||||
#![feature(const_fn_union)]
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
#[repr(transparent)]
|
||||
pub struct Username(str);
|
||||
|
||||
pub const ROOT_USER: &Username = Username::from_str("root");
|
||||
|
||||
impl Username {
|
||||
pub const fn from_str(raw: &str) -> &Self {
|
||||
union Transmute<'a> {
|
||||
raw: &'a str,
|
||||
typed: &'a Username,
|
||||
}
|
||||
|
||||
unsafe { Transmute { raw }.typed }
|
||||
}
|
||||
|
||||
pub const fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn is_root(&self) -> bool {
|
||||
match self {
|
||||
ROOT_USER => true,
|
||||
//~^ ERROR: cannot use unsized non-slice type `Username` in constant patterns
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
8
src/test/ui/consts/issue-87046.stderr
Normal file
8
src/test/ui/consts/issue-87046.stderr
Normal file
|
@ -0,0 +1,8 @@
|
|||
error: cannot use unsized non-slice type `Username` in constant patterns
|
||||
--> $DIR/issue-87046.rs:29:13
|
||||
|
|
||||
LL | ROOT_USER => true,
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit e5c1c8cf2fcfae3e15c8bcf5256e84cad3bd3436
|
||||
Subproject commit fe00358888a24c64878abc15f09b0e60e16db9d6
|
Loading…
Add table
Add a link
Reference in a new issue