mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
Auto merge of #153704 - JonathanBrouwer:rollup-f0S4ki3, r=JonathanBrouwer
Rollup of 4 pull requests Successful merges: - rust-lang/rust#153072 (Allow merging all libcore/alloc doctests into a single binary) - rust-lang/rust#153408 (miri: make read_discriminant UB when the tag is not in the validity range of the tag field) - rust-lang/rust#153674 (Detect inherent method behind deref being shadowed by trait method) - rust-lang/rust#153689 (Eliminate `QueryLatchInfo`.)
This commit is contained in:
@@ -111,23 +111,30 @@ pub fn read_discriminant(
|
||||
.try_to_scalar_int()
|
||||
.map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))?
|
||||
.to_bits(tag_layout.size);
|
||||
// Ensure the tag is in its layout range. Codegen adds range metadata on the
|
||||
// discriminant load so we really have to make this UB.
|
||||
if !tag_scalar_layout.valid_range(self).contains(tag_bits) {
|
||||
throw_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size)))
|
||||
}
|
||||
// Cast bits from tag layout to discriminant layout.
|
||||
// After the checks we did above, this cannot fail, as
|
||||
// discriminants are int-like.
|
||||
let discr_val = self.int_to_int_or_float(&tag_val, discr_layout).unwrap();
|
||||
let discr_bits = discr_val.to_scalar().to_bits(discr_layout.size)?;
|
||||
// Convert discriminant to variant index, and catch invalid discriminants.
|
||||
// Convert discriminant to variant index. Since we validated the tag against the
|
||||
// layout range above, this cannot fail.
|
||||
let index = match *ty.kind() {
|
||||
ty::Adt(adt, _) => {
|
||||
adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits)
|
||||
adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits).unwrap()
|
||||
}
|
||||
ty::Coroutine(def_id, args) => {
|
||||
let args = args.as_coroutine();
|
||||
args.discriminants(def_id, *self.tcx).find(|(_, var)| var.val == discr_bits)
|
||||
args.discriminants(def_id, *self.tcx)
|
||||
.find(|(_, var)| var.val == discr_bits)
|
||||
.unwrap()
|
||||
}
|
||||
_ => span_bug!(self.cur_span(), "tagged layout for non-adt non-coroutine"),
|
||||
}
|
||||
.ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?;
|
||||
};
|
||||
// Return the cast value, and the index.
|
||||
index.0
|
||||
}
|
||||
@@ -174,13 +181,22 @@ pub fn read_discriminant(
|
||||
let variants =
|
||||
ty.ty_adt_def().expect("tagged layout for non adt").variants();
|
||||
assert!(variant_index < variants.next_index());
|
||||
// This should imply that the tag is in its layout range.
|
||||
assert!(tag_scalar_layout.valid_range(self).contains(tag_bits));
|
||||
|
||||
if variant_index == untagged_variant {
|
||||
// The untagged variant can be in the niche range, but even then it
|
||||
// is not a valid encoding.
|
||||
// is not a valid encoding. Codegen inserts an `assume` here
|
||||
// so we really have to make this UB.
|
||||
throw_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size)))
|
||||
}
|
||||
variant_index
|
||||
} else {
|
||||
// Ensure the tag is in its layout range. Codegen adds range metadata on
|
||||
// the discriminant load so we really have to make this UB.
|
||||
if !tag_scalar_layout.valid_range(self).contains(tag_bits) {
|
||||
throw_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size)))
|
||||
}
|
||||
untagged_variant
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
The same feature is enabled multiple times with `#![feature]` attributes
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0636
|
||||
```compile_fail
|
||||
#![allow(stable_features)]
|
||||
#![feature(rust1)]
|
||||
#![feature(rust1)] // error: the feature `rust1` has already been enabled
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
DEPRECATED_IN_FUTURE,
|
||||
DEPRECATED_SAFE_2024,
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||
DUPLICATE_FEATURES,
|
||||
DUPLICATE_MACRO_ATTRIBUTES,
|
||||
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
|
||||
ELIDED_LIFETIMES_IN_PATHS,
|
||||
@@ -1093,6 +1094,33 @@
|
||||
"unused features found in crate-level `#[feature]` directives"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `duplicate_features` lint detects duplicate features found in
|
||||
/// crate-level [`feature` attributes].
|
||||
///
|
||||
/// Note: This lint used to be a hard error (E0636).
|
||||
///
|
||||
/// [`feature` attributes]: https://doc.rust-lang.org/nightly/unstable-book/
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// # #![allow(internal_features)]
|
||||
/// #![feature(rustc_attrs)]
|
||||
/// #![feature(rustc_attrs)]
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Enabling a feature more than once is a no-op.
|
||||
/// To avoid this warning, remove the second `feature()` attribute.
|
||||
pub DUPLICATE_FEATURES,
|
||||
Deny,
|
||||
"duplicate features found in crate-level `#[feature]` directives"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `stable_features` lint detects a [`feature` attribute] that
|
||||
/// has since been made stable.
|
||||
|
||||
@@ -77,22 +77,15 @@ pub struct QueryWaiter<'tcx> {
|
||||
pub cycle: Mutex<Option<CycleError<QueryStackDeferred<'tcx>>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct QueryLatchInfo<'tcx> {
|
||||
pub complete: bool,
|
||||
pub waiters: Vec<Arc<QueryWaiter<'tcx>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct QueryLatch<'tcx> {
|
||||
pub info: Arc<Mutex<QueryLatchInfo<'tcx>>>,
|
||||
/// The `Option` is `Some(..)` when the job is active, and `None` once completed.
|
||||
pub waiters: Arc<Mutex<Option<Vec<Arc<QueryWaiter<'tcx>>>>>>,
|
||||
}
|
||||
|
||||
impl<'tcx> QueryLatch<'tcx> {
|
||||
fn new() -> Self {
|
||||
QueryLatch {
|
||||
info: Arc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })),
|
||||
}
|
||||
QueryLatch { waiters: Arc::new(Mutex::new(Some(Vec::new()))) }
|
||||
}
|
||||
|
||||
/// Awaits for the query job to complete.
|
||||
@@ -102,10 +95,10 @@ pub fn wait_on(
|
||||
query: Option<QueryJobId>,
|
||||
span: Span,
|
||||
) -> Result<(), CycleError<QueryStackDeferred<'tcx>>> {
|
||||
let mut info = self.info.lock();
|
||||
if info.complete {
|
||||
return Ok(());
|
||||
}
|
||||
let mut waiters_guard = self.waiters.lock();
|
||||
let Some(waiters) = &mut *waiters_guard else {
|
||||
return Ok(()); // already complete
|
||||
};
|
||||
|
||||
let waiter =
|
||||
Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() });
|
||||
@@ -114,7 +107,7 @@ pub fn wait_on(
|
||||
// the `wait` call below, by 1) the `set` method or 2) by deadlock detection.
|
||||
// Both of these will remove it from the `waiters` list before resuming
|
||||
// this thread.
|
||||
info.waiters.push(Arc::clone(&waiter));
|
||||
waiters.push(Arc::clone(&waiter));
|
||||
|
||||
// Awaits the caller on this latch by blocking the current thread.
|
||||
// If this detects a deadlock and the deadlock handler wants to resume this thread
|
||||
@@ -122,9 +115,9 @@ pub fn wait_on(
|
||||
// getting the self.info lock.
|
||||
rustc_thread_pool::mark_blocked();
|
||||
tcx.jobserver_proxy.release_thread();
|
||||
waiter.condvar.wait(&mut info);
|
||||
waiter.condvar.wait(&mut waiters_guard);
|
||||
// Release the lock before we potentially block in `acquire_thread`
|
||||
drop(info);
|
||||
drop(waiters_guard);
|
||||
tcx.jobserver_proxy.acquire_thread();
|
||||
|
||||
// FIXME: Get rid of this lock. We have ownership of the QueryWaiter
|
||||
@@ -139,11 +132,10 @@ pub fn wait_on(
|
||||
|
||||
/// Sets the latch and resumes all waiters on it
|
||||
fn set(&self) {
|
||||
let mut info = self.info.lock();
|
||||
debug_assert!(!info.complete);
|
||||
info.complete = true;
|
||||
let mut waiters_guard = self.waiters.lock();
|
||||
let waiters = waiters_guard.take().unwrap(); // mark the latch as complete
|
||||
let registry = rustc_thread_pool::Registry::current();
|
||||
for waiter in info.waiters.drain(..) {
|
||||
for waiter in waiters {
|
||||
rustc_thread_pool::mark_unblocked(®istry);
|
||||
waiter.condvar.notify_one();
|
||||
}
|
||||
@@ -152,9 +144,9 @@ fn set(&self) {
|
||||
/// Removes a single waiter from the list of waiters.
|
||||
/// This is used to break query cycles.
|
||||
pub fn extract_waiter(&self, waiter: usize) -> Arc<QueryWaiter<'tcx>> {
|
||||
let mut info = self.info.lock();
|
||||
debug_assert!(!info.complete);
|
||||
let mut waiters_guard = self.waiters.lock();
|
||||
let waiters = waiters_guard.as_mut().expect("non-empty waiters vec");
|
||||
// Remove the waiter from the list of waiters
|
||||
info.waiters.remove(waiter)
|
||||
waiters.remove(waiter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -987,14 +987,6 @@ pub(crate) struct ImpliedFeatureNotExist {
|
||||
pub implied_by: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("the feature `{$feature}` has already been enabled", code = E0636)]
|
||||
pub(crate) struct DuplicateFeatureErr {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub feature: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`"
|
||||
@@ -1144,6 +1136,12 @@ pub(crate) struct ProcMacroBadSig {
|
||||
pub kind: ProcMacroKind,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("the feature `{$feature}` has already been enabled")]
|
||||
pub(crate) struct DuplicateFeature {
|
||||
pub feature: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"the feature `{$feature}` has been stable since {$since} and no longer requires an attribute to enable"
|
||||
|
||||
@@ -972,7 +972,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
|
||||
}
|
||||
if !lang_features.insert(gate_name) {
|
||||
// Warn if the user enables a lang feature multiple times.
|
||||
tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
|
||||
duplicate_feature_lint(tcx, *attr_sp, *gate_name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -981,7 +981,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
|
||||
for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features {
|
||||
if remaining_lib_features.contains_key(gate_name) {
|
||||
// Warn if the user enables a lib feature multiple times.
|
||||
tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
|
||||
duplicate_feature_lint(tcx, *attr_sp, *gate_name);
|
||||
}
|
||||
remaining_lib_features.insert(*gate_name, *attr_sp);
|
||||
}
|
||||
@@ -1166,3 +1166,12 @@ fn unnecessary_stable_feature_lint(
|
||||
errors::UnnecessaryStableFeature { feature, since },
|
||||
);
|
||||
}
|
||||
|
||||
fn duplicate_feature_lint(tcx: TyCtxt<'_>, span: Span, feature: Symbol) {
|
||||
tcx.emit_node_span_lint(
|
||||
lint::builtin::DUPLICATE_FEATURES,
|
||||
hir::CRATE_HIR_ID,
|
||||
span,
|
||||
errors::DuplicateFeature { feature },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ fn visit_waiters<'tcx>(
|
||||
|
||||
// Visit the explicit waiters which use condvars and are resumable
|
||||
if let Some(latch) = job_map.latch_of(query) {
|
||||
for (i, waiter) in latch.info.lock().waiters.iter().enumerate() {
|
||||
for (i, waiter) in latch.waiters.lock().as_ref().unwrap().iter().enumerate() {
|
||||
if let Some(waiter_query) = waiter.query {
|
||||
// Return a value which indicates that this waiter can be resumed
|
||||
visit(waiter.span, waiter_query).map_break(|_| Some((query, i)))?;
|
||||
|
||||
@@ -1073,6 +1073,7 @@
|
||||
include_bytes,
|
||||
include_str,
|
||||
inclusive_range_syntax,
|
||||
incomplete_features,
|
||||
index,
|
||||
index_mut,
|
||||
infer_outlives_requirements,
|
||||
|
||||
@@ -3178,6 +3178,7 @@ fn try_to_add_help_message(
|
||||
|
||||
self.suggest_tuple_wrapping(err, root_obligation, obligation);
|
||||
}
|
||||
self.suggest_shadowed_inherent_method(err, obligation, trait_predicate);
|
||||
}
|
||||
|
||||
fn add_help_message_for_fn_trait(
|
||||
|
||||
@@ -4916,6 +4916,79 @@ pub(super) fn suggest_tuple_wrapping(
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn suggest_shadowed_inherent_method(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_predicate: ty::PolyTraitPredicate<'tcx>,
|
||||
) {
|
||||
let ObligationCauseCode::FunctionArg { call_hir_id, .. } = obligation.cause.code() else {
|
||||
return;
|
||||
};
|
||||
let Node::Expr(call) = self.tcx.hir_node(*call_hir_id) else { return };
|
||||
let hir::ExprKind::MethodCall(segment, rcvr, args, ..) = call.kind else { return };
|
||||
let Some(typeck) = &self.typeck_results else { return };
|
||||
let Some(rcvr_ty) = typeck.expr_ty_adjusted_opt(rcvr) else { return };
|
||||
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
|
||||
let autoderef = (self.autoderef_steps)(rcvr_ty);
|
||||
for (ty, def_id) in autoderef.iter().filter_map(|(ty, obligations)| {
|
||||
if let ty::Adt(def, _) = ty.kind()
|
||||
&& *ty != rcvr_ty.peel_refs()
|
||||
&& obligations.iter().all(|obligation| self.predicate_may_hold(obligation))
|
||||
{
|
||||
Some((ty, def.did()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
for impl_def_id in self.tcx.inherent_impls(def_id) {
|
||||
if *impl_def_id == trait_predicate.def_id() {
|
||||
continue;
|
||||
}
|
||||
for m in self
|
||||
.tcx
|
||||
.provided_trait_methods(*impl_def_id)
|
||||
.filter(|m| m.name() == segment.ident.name)
|
||||
{
|
||||
let fn_sig = self.tcx.fn_sig(m.def_id);
|
||||
if fn_sig.skip_binder().inputs().skip_binder().len() != args.len() + 1 {
|
||||
continue;
|
||||
}
|
||||
let rcvr_ty = fn_sig.skip_binder().input(0).skip_binder();
|
||||
let (mutability, _ty) = match rcvr_ty.kind() {
|
||||
ty::Ref(_, ty, hir::Mutability::Mut) => ("&mut ", ty),
|
||||
ty::Ref(_, ty, _) => ("&", ty),
|
||||
_ => ("", &rcvr_ty),
|
||||
};
|
||||
let path = self.tcx.def_path_str(def_id);
|
||||
err.note(format!(
|
||||
"there's an inherent method on `{ty}` of the same name, which can be \
|
||||
auto-dereferenced from `{rcvr_ty}`"
|
||||
));
|
||||
err.multipart_suggestion(
|
||||
format!(
|
||||
"to access the inherent method on `{ty}`, use the fully-qualified path",
|
||||
),
|
||||
vec![
|
||||
(
|
||||
call.span.until(rcvr.span),
|
||||
format!("{path}::{}({}", m.name(), mutability),
|
||||
),
|
||||
match &args {
|
||||
[] => (
|
||||
rcvr.span.shrink_to_hi().with_hi(call.span.hi()),
|
||||
")".to_string(),
|
||||
),
|
||||
[first, ..] => (rcvr.span.between(first.span), ", ".to_string()),
|
||||
},
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn explain_hrtb_projection(
|
||||
&self,
|
||||
diag: &mut Diag<'_>,
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
#![doc(
|
||||
html_playground_url = "https://play.rust-lang.org/",
|
||||
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
|
||||
test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
|
||||
test(no_crate_inject, attr(allow(unused_variables, duplicate_features), deny(warnings)))
|
||||
)]
|
||||
#![doc(auto_cfg(hide(no_global_oom_handling, no_rc, no_sync, target_has_atomic = "ptr")))]
|
||||
#![doc(rust_logo)]
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// ```standalone_crate
|
||||
/// use std::alloc::{GlobalAlloc, Layout};
|
||||
/// use std::cell::UnsafeCell;
|
||||
/// use std::ptr::null_mut;
|
||||
|
||||
@@ -514,7 +514,7 @@ pub const fn black_box<T>(dummy: T) -> T {
|
||||
/// macro_rules! make_error {
|
||||
/// ($($args:expr),*) => {
|
||||
/// core::hint::must_use({
|
||||
/// let error = $crate::make_error(core::format_args!($($args),*));
|
||||
/// let error = make_error(core::format_args!($($args),*));
|
||||
/// error
|
||||
/// })
|
||||
/// };
|
||||
|
||||
@@ -62,7 +62,9 @@
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```rust
|
||||
#![cfg_attr(panic = "unwind", doc = "```rust")]
|
||||
// This test can't support panic=abort because it generates an UnwindContinue MIR terminator.
|
||||
#![cfg_attr(panic = "abort", doc = "```ignore")]
|
||||
//! #![feature(core_intrinsics, custom_mir)]
|
||||
//! #![allow(internal_features)]
|
||||
//! #![allow(unused_assignments)]
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
html_playground_url = "https://play.rust-lang.org/",
|
||||
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
|
||||
test(no_crate_inject, attr(deny(warnings))),
|
||||
test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
|
||||
test(attr(allow(dead_code, deprecated, unused_variables, unused_mut, duplicate_features)))
|
||||
)]
|
||||
#![doc(rust_logo)]
|
||||
#![doc(auto_cfg(hide(
|
||||
|
||||
@@ -584,7 +584,7 @@ fn from(value: legacy::RangeFrom<T>) -> Self {
|
||||
///
|
||||
/// The `..=last` syntax is a `RangeToInclusive`:
|
||||
///
|
||||
/// ```
|
||||
/// ```standalone_crate
|
||||
/// #![feature(new_range)]
|
||||
/// assert_eq!((..=5), std::range::RangeToInclusive { last: 5 });
|
||||
/// ```
|
||||
|
||||
@@ -600,6 +600,12 @@ fn make_run(run: RunConfig<'_>) {
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
|
||||
builder.require_submodule(
|
||||
"src/doc/reference",
|
||||
Some("error_index_generator requires mdbook-spec"),
|
||||
);
|
||||
builder
|
||||
.require_submodule("src/doc/book", Some("error_index_generator requires mdbook-trpl"));
|
||||
builder.ensure(ToolBuild {
|
||||
build_compiler: self.compilers.build_compiler,
|
||||
target: self.compilers.target(),
|
||||
|
||||
@@ -232,6 +232,9 @@ pub(crate) fn create_config(
|
||||
rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(),
|
||||
rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(),
|
||||
rustc_lint::builtin::UNEXPECTED_CFGS.name.to_string(),
|
||||
rustc_lint::builtin::DUPLICATE_FEATURES.name.to_string(),
|
||||
rustc_lint::builtin::UNUSED_FEATURES.name.to_string(),
|
||||
rustc_lint::builtin::STABLE_FEATURES.name.to_string(),
|
||||
// this lint is needed to support `#[expect]` attributes
|
||||
rustc_lint::builtin::UNFULFILLED_LINT_EXPECTATIONS.name.to_string(),
|
||||
];
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
use rustc_span::{FileName, RemapPathScopeComponents, Span};
|
||||
use rustc_target::spec::{Target, TargetTuple};
|
||||
use tempfile::{Builder as TempFileBuilder, TempDir};
|
||||
use tracing::debug;
|
||||
use tracing::{debug, info};
|
||||
|
||||
use self::rust::HirCollector;
|
||||
use crate::config::{MergeDoctests, Options as RustdocOptions, OutputFormat};
|
||||
@@ -692,7 +692,7 @@ fn run_test(
|
||||
compiler.stderr(Stdio::piped());
|
||||
}
|
||||
|
||||
debug!("compiler invocation for doctest: {compiler:?}");
|
||||
info!("compiler invocation for doctest: {compiler:?}");
|
||||
|
||||
let mut child = match compiler.spawn() {
|
||||
Ok(child) => child,
|
||||
@@ -759,7 +759,7 @@ fn run_test(
|
||||
runner_compiler.stderr(Stdio::inherit());
|
||||
}
|
||||
runner_compiler.arg("--error-format=short");
|
||||
debug!("compiler invocation for doctest runner: {runner_compiler:?}");
|
||||
info!("compiler invocation for doctest runner: {runner_compiler:?}");
|
||||
|
||||
let status = if !status.success() {
|
||||
status
|
||||
@@ -859,6 +859,8 @@ fn drop(&mut self) {
|
||||
cmd.current_dir(run_directory);
|
||||
}
|
||||
|
||||
info!("running doctest executable: {cmd:?}");
|
||||
|
||||
let result = if doctest.is_multiple_tests() || rustdoc_options.no_capture {
|
||||
cmd.status().map(|status| process::Output {
|
||||
status,
|
||||
|
||||
@@ -555,7 +555,10 @@ fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<
|
||||
// consider it only as a crate-level attribute.
|
||||
if attr.has_name(sym::allow)
|
||||
&& let Some(list) = attr.meta_item_list()
|
||||
&& list.iter().any(|sub_attr| sub_attr.has_name(sym::internal_features))
|
||||
&& list.iter().any(|sub_attr| {
|
||||
sub_attr.has_name(sym::internal_features)
|
||||
|| sub_attr.has_name(sym::incomplete_features)
|
||||
})
|
||||
{
|
||||
push_to_s(&mut info.crate_attrs, source, attr.span, &mut prev_span_hi);
|
||||
} else {
|
||||
|
||||
@@ -20,8 +20,8 @@ fn main() {
|
||||
assert!(Foo::Var1 == mem::transmute(2u8));
|
||||
assert!(Foo::Var3 == mem::transmute(4u8));
|
||||
|
||||
let invalid: Foo = mem::transmute(3u8);
|
||||
assert!(matches!(invalid, Foo::Var2(_)));
|
||||
let invalid: *const Foo = mem::transmute(&3u8);
|
||||
assert!(matches!(*invalid, Foo::Var2(_)));
|
||||
//~^ ERROR: invalid tag
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error: Undefined Behavior: enum value has invalid tag: 0x03
|
||||
--> tests/fail/enum-untagged-variant-invalid-encoding.rs:LL:CC
|
||||
|
|
||||
LL | assert!(matches!(invalid, Foo::Var2(_)));
|
||||
| ^^^^^^^ Undefined Behavior occurred here
|
||||
LL | assert!(matches!(*invalid, Foo::Var2(_)));
|
||||
| ^^^^^^^^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// Make sure we find these even with many checks disabled.
|
||||
//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
|
||||
#![feature(never_type)]
|
||||
|
||||
enum Never {}
|
||||
|
||||
// An enum with 4 variants of which only some are uninhabited -- so the uninhabited variants *do*
|
||||
// have a discriminant.
|
||||
#[allow(unused)]
|
||||
enum UninhDiscriminant {
|
||||
A,
|
||||
B(!),
|
||||
C,
|
||||
D(Never),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let x = 3u8;
|
||||
let x_ptr: *const u8 = &x;
|
||||
let cast_ptr = x_ptr as *const UninhDiscriminant;
|
||||
// Reading the discriminant should fail since the tag value is not in the valid
|
||||
// range for the tag field.
|
||||
let _val = matches!(*cast_ptr, UninhDiscriminant::A);
|
||||
//~^ ERROR: invalid tag
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
error: Undefined Behavior: enum value has invalid tag: 0x03
|
||||
--> tests/fail/validity/invalid_enum_op_discr_uninhabited.rs:LL:CC
|
||||
|
|
||||
LL | let _val = matches!(*cast_ptr, UninhDiscriminant::A);
|
||||
| ^^^^^^^^^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Make sure we find these even with many checks disabled.
|
||||
//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let x = 12u8;
|
||||
let x_ptr: *const u8 = &x;
|
||||
let cast_ptr = x_ptr as *const Option<bool>;
|
||||
// Reading the discriminant should fail since the tag value is not in the valid
|
||||
// range for the tag field.
|
||||
let _val = matches!(*cast_ptr, None);
|
||||
//~^ ERROR: invalid tag
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
error: Undefined Behavior: enum value has invalid tag: 0x0c
|
||||
--> tests/fail/validity/invalid_enum_op_niche_out_of_range.rs:LL:CC
|
||||
|
|
||||
LL | let _val = matches!(*cast_ptr, None);
|
||||
| ^^^^^^^^^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/20646
|
||||
#![crate_name="issue_20646"]
|
||||
#![feature(associated_types)]
|
||||
|
||||
extern crate issue_20646;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#![feature(doc_cfg)]
|
||||
#![feature(target_feature, cfg_target_feature)]
|
||||
|
||||
//@ has doc_cfg/struct.Portable.html
|
||||
//@ !has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' ''
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
//@ only-64bit
|
||||
|
||||
#![feature(const_transmute)]
|
||||
|
||||
pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
|
||||
//~^ ERROR transmuting from 8-byte type to 16-byte type
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error[E0080]: transmuting from 8-byte type to 16-byte type: `usize` -> `&[u8]`
|
||||
--> $DIR/issue-79494.rs:5:33
|
||||
--> $DIR/issue-79494.rs:3:33
|
||||
|
|
||||
LL | pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ZST` failed here
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(rustdoc_internals)] //~ ERROR
|
||||
#![feature(rustdoc_internals)] //~ ERROR duplicate
|
||||
|
||||
pub fn foo() {}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
error[E0636]: the feature `rustdoc_internals` has already been enabled
|
||||
error: the feature `rustdoc_internals` has already been enabled
|
||||
--> $DIR/rustc-check-passes.rs:2:12
|
||||
|
|
||||
LL | #![feature(rustdoc_internals)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[deny(duplicate_features)]` on by default
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0636`.
|
||||
|
||||
@@ -13,6 +13,7 @@ help: the nightly-only, unstable trait `IntoDiagArg` is not implemented for `Not
|
||||
LL | struct NotIntoDiagArg;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: normalized in stderr
|
||||
= note: there's an inherent method on `DiagInner` of the same name, which can be auto-dereferenced from `&mut DiagInner`
|
||||
note: required by a bound in `Diag::<'a, G>::arg`
|
||||
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC
|
||||
::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC
|
||||
|
||||
@@ -589,6 +589,7 @@ help: the nightly-only, unstable trait `IntoDiagArg` is not implemented for `Hel
|
||||
LL | struct Hello {}
|
||||
| ^^^^^^^^^^^^
|
||||
= help: normalized in stderr
|
||||
= note: there's an inherent method on `DiagInner` of the same name, which can be auto-dereferenced from `&mut DiagInner`
|
||||
note: required by a bound in `Diag::<'a, G>::arg`
|
||||
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC
|
||||
::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC
|
||||
|
||||
@@ -31,7 +31,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute
|
||||
01 │ .
|
||||
}
|
||||
|
||||
error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant
|
||||
error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x03, but expected a valid enum tag
|
||||
--> $DIR/raw-bytes.rs:47:1
|
||||
|
|
||||
LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
|
||||
|
||||
@@ -31,7 +31,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute
|
||||
01 │ .
|
||||
}
|
||||
|
||||
error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant
|
||||
error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x03, but expected a valid enum tag
|
||||
--> $DIR/raw-bytes.rs:47:1
|
||||
|
|
||||
LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
|
||||
|
||||
@@ -83,7 +83,7 @@ enum UninhDiscriminant {
|
||||
const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
|
||||
//~^ ERROR uninhabited enum variant
|
||||
const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
|
||||
//~^ ERROR uninhabited enum variant
|
||||
//~^ ERROR expected a valid enum tag
|
||||
|
||||
// # other
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute
|
||||
HEX_DUMP
|
||||
}
|
||||
|
||||
error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant
|
||||
error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x03, but expected a valid enum tag
|
||||
--> $DIR/ub-enum.rs:85:1
|
||||
|
|
||||
LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
error[E0636]: the feature `if_let` has already been enabled
|
||||
error: the feature `if_let` has already been enabled
|
||||
--> $DIR/duplicate-features.rs:7:12
|
||||
|
|
||||
LL | #![feature(if_let)]
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: `#[deny(duplicate_features)]` on by default
|
||||
|
||||
error[E0636]: the feature `rust1` has already been enabled
|
||||
error: the feature `rust1` has already been enabled
|
||||
--> $DIR/duplicate-features.rs:4:12
|
||||
|
|
||||
LL | #![feature(rust1)]
|
||||
@@ -12,4 +14,3 @@ LL | #![feature(rust1)]
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0636`.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
//@ run-rustfix
|
||||
#![allow(unused_imports)]
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::borrow::Borrow; // Without this import, the code would compile.
|
||||
|
||||
pub struct S {
|
||||
flag: bool,
|
||||
}
|
||||
|
||||
type SCell = Rc<RefCell<S>>;
|
||||
|
||||
fn main() {
|
||||
// Type annotations just for clarity
|
||||
let s : SCell = Rc::new(RefCell::new(S {flag: false}));
|
||||
let sb : &S = &RefCell::borrow(&s);
|
||||
//~^ ERROR: the trait bound `Rc<RefCell<S>>: Borrow<S>` is not satisfied [E0277]
|
||||
//~| NOTE: the trait `Borrow<S>` is not implemented for `Rc<RefCell<S>>`
|
||||
//~| NOTE: there's an inherent method on `RefCell<S>` of the same name
|
||||
println!("{:?}", sb.flag);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//@ run-rustfix
|
||||
#![allow(unused_imports)]
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::borrow::Borrow; // Without this import, the code would compile.
|
||||
|
||||
pub struct S {
|
||||
flag: bool,
|
||||
}
|
||||
|
||||
type SCell = Rc<RefCell<S>>;
|
||||
|
||||
fn main() {
|
||||
// Type annotations just for clarity
|
||||
let s : SCell = Rc::new(RefCell::new(S {flag: false}));
|
||||
let sb : &S = &s.borrow();
|
||||
//~^ ERROR: the trait bound `Rc<RefCell<S>>: Borrow<S>` is not satisfied [E0277]
|
||||
//~| NOTE: the trait `Borrow<S>` is not implemented for `Rc<RefCell<S>>`
|
||||
//~| NOTE: there's an inherent method on `RefCell<S>` of the same name
|
||||
println!("{:?}", sb.flag);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
error[E0277]: the trait bound `Rc<RefCell<S>>: Borrow<S>` is not satisfied
|
||||
--> $DIR/shadowed-intrinsic-method-deref.rs:16:22
|
||||
|
|
||||
LL | let sb : &S = &s.borrow();
|
||||
| ^^^^^^ the trait `Borrow<S>` is not implemented for `Rc<RefCell<S>>`
|
||||
|
|
||||
help: the trait `Borrow<S>` is not implemented for `Rc<RefCell<S>>`
|
||||
but trait `Borrow<RefCell<S>>` is implemented for it
|
||||
--> $SRC_DIR/alloc/src/rc.rs:LL:COL
|
||||
= help: for that trait implementation, expected `RefCell<S>`, found `S`
|
||||
= note: there's an inherent method on `RefCell<S>` of the same name, which can be auto-dereferenced from `&RefCell<T>`
|
||||
help: to access the inherent method on `RefCell<S>`, use the fully-qualified path
|
||||
|
|
||||
LL - let sb : &S = &s.borrow();
|
||||
LL + let sb : &S = &RefCell::borrow(&s);
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
Reference in New Issue
Block a user