diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index b7e7f65c95c78..3a7c1ea65f3d8 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -111,23 +111,30 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .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 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { 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 } } diff --git a/compiler/rustc_error_codes/src/error_codes/E0636.md b/compiler/rustc_error_codes/src/error_codes/E0636.md index 41fd701a8ede3..18e5af6f87e11 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0636.md +++ b/compiler/rustc_error_codes/src/error_codes/E0636.md @@ -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 diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 38ffecbafa06b..cdd8f3f42c3f2 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -39,6 +39,7 @@ declare_lint_pass! { 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 @@ declare_lint! { "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. diff --git a/compiler/rustc_middle/src/query/job.rs b/compiler/rustc_middle/src/query/job.rs index 23ca15d3f8a12..923eae045cae2 100644 --- a/compiler/rustc_middle/src/query/job.rs +++ b/compiler/rustc_middle/src/query/job.rs @@ -77,22 +77,15 @@ pub struct QueryWaiter<'tcx> { pub cycle: Mutex>>>, } -#[derive(Debug)] -pub struct QueryLatchInfo<'tcx> { - pub complete: bool, - pub waiters: Vec>>, -} - #[derive(Clone, Debug)] pub struct QueryLatch<'tcx> { - pub info: Arc>>, + /// The `Option` is `Some(..)` when the job is active, and `None` once completed. + pub waiters: Arc>>>>>, } 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 @@ impl<'tcx> QueryLatch<'tcx> { query: Option, span: Span, ) -> Result<(), CycleError>> { - 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 @@ impl<'tcx> QueryLatch<'tcx> { // 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 @@ impl<'tcx> QueryLatch<'tcx> { // 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 @@ impl<'tcx> QueryLatch<'tcx> { /// 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 @@ impl<'tcx> QueryLatch<'tcx> { /// Removes a single waiter from the list of waiters. /// This is used to break query cycles. pub fn extract_waiter(&self, waiter: usize) -> Arc> { - 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) } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 7c7698ac3bb8e..228f21c81b947 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -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" diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 18263506a03b2..3193bf8ac0011 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -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 }, + ); +} diff --git a/compiler/rustc_query_impl/src/job.rs b/compiler/rustc_query_impl/src/job.rs index 2a7f7bf5efd41..9c095603cc848 100644 --- a/compiler/rustc_query_impl/src/job.rs +++ b/compiler/rustc_query_impl/src/job.rs @@ -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)))?; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 257ac3f51c2c1..48cdf46b821f9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1073,6 +1073,7 @@ symbols! { include_bytes, include_str, inclusive_range_syntax, + incomplete_features, index, index_mut, infer_outlives_requirements, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 364152475e94d..fdb3859022125 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -3178,6 +3178,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.suggest_tuple_wrapping(err, root_obligation, obligation); } + self.suggest_shadowed_inherent_method(err, obligation, trait_predicate); } fn add_help_message_for_fn_trait( diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 14aff65d4b518..ee2f8d9783cfe 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4916,6 +4916,79 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } + 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<'_>, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 73e93657b02f7..7ac9cdc3833d3 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -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)] diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index bf3d3e0a5aca7..e97398aa5dc4a 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -19,7 +19,7 @@ use crate::{cmp, ptr}; /// /// # Example /// -/// ``` +/// ```standalone_crate /// use std::alloc::{GlobalAlloc, Layout}; /// use std::cell::UnsafeCell; /// use std::ptr::null_mut; diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 03ed04dc5a666..a8e01e6e78b4b 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -514,7 +514,7 @@ pub const fn black_box(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 /// }) /// }; diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 939298268c934..7659e0042b379 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -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)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 29869dd91982d..e12c43068245a 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -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( diff --git a/library/core/src/range.rs b/library/core/src/range.rs index d12a4ef43e49e..3c2c40d492005 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -584,7 +584,7 @@ impl const From> for RangeFrom { /// /// The `..=last` syntax is a `RangeToInclusive`: /// -/// ``` +/// ```standalone_crate /// #![feature(new_range)] /// assert_eq!((..=5), std::range::RangeToInclusive { last: 5 }); /// ``` diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index d86159d3cc7e9..e6148af617674 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -600,6 +600,12 @@ impl Step for ErrorIndex { } 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(), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 0813816b470ac..89b4df1a51ce5 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -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(), ]; diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 5d3715c70e087..a61f85bd40074 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -32,7 +32,7 @@ use rustc_span::edition::Edition; 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 run_test( 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, diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index a77efaaed8d58..7dd738abca433 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -555,7 +555,10 @@ fn parse_source( // 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 { diff --git a/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.rs b/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.rs index bd02e7f5fb44b..2bea47e32dd96 100644 --- a/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.rs +++ b/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.rs @@ -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 } } diff --git a/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.stderr b/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.stderr index e019a350ba17d..b0862cf94b9ab 100644 --- a/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.stderr +++ b/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.stderr @@ -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 diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_op_discr_uninhabited.rs b/src/tools/miri/tests/fail/validity/invalid_enum_op_discr_uninhabited.rs new file mode 100644 index 0000000000000..3d1ae64b57826 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/invalid_enum_op_discr_uninhabited.rs @@ -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 + } +} diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_op_discr_uninhabited.stderr b/src/tools/miri/tests/fail/validity/invalid_enum_op_discr_uninhabited.stderr new file mode 100644 index 0000000000000..2e2ad81a04514 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/invalid_enum_op_discr_uninhabited.stderr @@ -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 + diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_op_niche_out_of_range.rs b/src/tools/miri/tests/fail/validity/invalid_enum_op_niche_out_of_range.rs new file mode 100644 index 0000000000000..51237c360f1cf --- /dev/null +++ b/src/tools/miri/tests/fail/validity/invalid_enum_op_niche_out_of_range.rs @@ -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; + // 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 + } +} diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_op_niche_out_of_range.stderr b/src/tools/miri/tests/fail/validity/invalid_enum_op_niche_out_of_range.stderr new file mode 100644 index 0000000000000..65fcddbb43da4 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/invalid_enum_op_niche_out_of_range.stderr @@ -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 + diff --git a/tests/rustdoc-html/assoc/assoc-type-bindings-20646.rs b/tests/rustdoc-html/assoc/assoc-type-bindings-20646.rs index c79d07ff5bd7d..96cc612b597c5 100644 --- a/tests/rustdoc-html/assoc/assoc-type-bindings-20646.rs +++ b/tests/rustdoc-html/assoc/assoc-type-bindings-20646.rs @@ -3,7 +3,6 @@ // https://github.com/rust-lang/rust/issues/20646 #![crate_name="issue_20646"] -#![feature(associated_types)] extern crate issue_20646; diff --git a/tests/rustdoc-html/doc-cfg/doc-cfg.rs b/tests/rustdoc-html/doc-cfg/doc-cfg.rs index 652c8419b4fb8..ba2a8de5b29e5 100644 --- a/tests/rustdoc-html/doc-cfg/doc-cfg.rs +++ b/tests/rustdoc-html/doc-cfg/doc-cfg.rs @@ -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"]' '' diff --git a/tests/rustdoc-ui/issues/issue-79494.rs b/tests/rustdoc-ui/issues/issue-79494.rs index 737c00a0269bb..c80e0a9842136 100644 --- a/tests/rustdoc-ui/issues/issue-79494.rs +++ b/tests/rustdoc-ui/issues/issue-79494.rs @@ -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 diff --git a/tests/rustdoc-ui/issues/issue-79494.stderr b/tests/rustdoc-ui/issues/issue-79494.stderr index fa797bfd50a69..31ed8f18ab07c 100644 --- a/tests/rustdoc-ui/issues/issue-79494.stderr +++ b/tests/rustdoc-ui/issues/issue-79494.stderr @@ -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 diff --git a/tests/rustdoc-ui/rustc-check-passes.rs b/tests/rustdoc-ui/rustc-check-passes.rs index 56d59164d68f1..54028a6d18ee1 100644 --- a/tests/rustdoc-ui/rustc-check-passes.rs +++ b/tests/rustdoc-ui/rustc-check-passes.rs @@ -1,4 +1,4 @@ #![feature(rustdoc_internals)] -#![feature(rustdoc_internals)] //~ ERROR +#![feature(rustdoc_internals)] //~ ERROR duplicate pub fn foo() {} diff --git a/tests/rustdoc-ui/rustc-check-passes.stderr b/tests/rustdoc-ui/rustc-check-passes.stderr index 5b20d1128c595..2789d8236d32b 100644 --- a/tests/rustdoc-ui/rustc-check-passes.stderr +++ b/tests/rustdoc-ui/rustc-check-passes.stderr @@ -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`. diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index 9149baaa40871..48a338db297e5 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -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 diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr index 48138fc9fb55a..28800016cea9b 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr @@ -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 diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index be3b539b269a0..acbf19d6ad77a 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -31,7 +31,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute 01 │ . } -error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant +error[E0080]: constructing invalid value at .: encountered 0x03, but expected a valid enum tag --> $DIR/raw-bytes.rs:47:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index 9950ac726ca76..52d32fd3f875e 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -31,7 +31,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute 01 │ . } -error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant +error[E0080]: constructing invalid value at .: encountered 0x03, but expected a valid enum tag --> $DIR/raw-bytes.rs:47:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; diff --git a/tests/ui/consts/const-eval/ub-enum.rs b/tests/ui/consts/const-eval/ub-enum.rs index 9c78bb6efed7e..63029e17da229 100644 --- a/tests/ui/consts/const-eval/ub-enum.rs +++ b/tests/ui/consts/const-eval/ub-enum.rs @@ -83,7 +83,7 @@ const GOOD_INHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(2u8) 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 diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr index 1efd93832291e..da63af30480e6 100644 --- a/tests/ui/consts/const-eval/ub-enum.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -86,7 +86,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute HEX_DUMP } -error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant +error[E0080]: constructing invalid value at .: encountered 0x03, but expected a valid enum tag --> $DIR/ub-enum.rs:85:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; diff --git a/tests/ui/feature-gates/duplicate-features.stderr b/tests/ui/feature-gates/duplicate-features.stderr index f667a5b9623ff..81a9eeb9650cc 100644 --- a/tests/ui/feature-gates/duplicate-features.stderr +++ b/tests/ui/feature-gates/duplicate-features.stderr @@ -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`. diff --git a/tests/ui/methods/shadowed-intrinsic-method-deref.fixed b/tests/ui/methods/shadowed-intrinsic-method-deref.fixed new file mode 100644 index 0000000000000..927c168af5682 --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method-deref.fixed @@ -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>; + +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>: Borrow` is not satisfied [E0277] + //~| NOTE: the trait `Borrow` is not implemented for `Rc>` + //~| NOTE: there's an inherent method on `RefCell` of the same name + println!("{:?}", sb.flag); +} diff --git a/tests/ui/methods/shadowed-intrinsic-method-deref.rs b/tests/ui/methods/shadowed-intrinsic-method-deref.rs new file mode 100644 index 0000000000000..1e8ddb152d87f --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method-deref.rs @@ -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>; + +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>: Borrow` is not satisfied [E0277] + //~| NOTE: the trait `Borrow` is not implemented for `Rc>` + //~| NOTE: there's an inherent method on `RefCell` of the same name + println!("{:?}", sb.flag); +} diff --git a/tests/ui/methods/shadowed-intrinsic-method-deref.stderr b/tests/ui/methods/shadowed-intrinsic-method-deref.stderr new file mode 100644 index 0000000000000..4e0c5dfc55f09 --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method-deref.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `Rc>: Borrow` is not satisfied + --> $DIR/shadowed-intrinsic-method-deref.rs:16:22 + | +LL | let sb : &S = &s.borrow(); + | ^^^^^^ the trait `Borrow` is not implemented for `Rc>` + | +help: the trait `Borrow` is not implemented for `Rc>` + but trait `Borrow>` is implemented for it + --> $SRC_DIR/alloc/src/rc.rs:LL:COL + = help: for that trait implementation, expected `RefCell`, found `S` + = note: there's an inherent method on `RefCell` of the same name, which can be auto-dereferenced from `&RefCell` +help: to access the inherent method on `RefCell`, 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`.