diff --git a/compiler/rustc_error_codes/src/error_codes/E0636.md b/compiler/rustc_error_codes/src/error_codes/E0636.md index 41fd701a8ede3..281b119223b77 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 +``` #![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_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 ec6d48cbea2e4..5b53cf1fa2171 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -969,7 +969,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); } } @@ -978,7 +978,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); } @@ -1160,3 +1160,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_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/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/librustdoc/core.rs b/src/librustdoc/core.rs index bb41758c7a2e5..331f02c639aab 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/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..83f8b1ab2596b 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)] //~ DENY 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/feature-gates/duplicate-features.rs b/tests/ui/feature-gates/duplicate-features.rs index 1fae71c3eb2bb..62d9c77eef297 100644 --- a/tests/ui/feature-gates/duplicate-features.rs +++ b/tests/ui/feature-gates/duplicate-features.rs @@ -1,9 +1,11 @@ +//@ check-pass + #![allow(stable_features)] #![feature(rust1)] -#![feature(rust1)] //~ ERROR the feature `rust1` has already been enabled +#![feature(rust1)] //~ WARN the feature `rust1` has already been enabled #![feature(if_let)] -#![feature(if_let)] //~ ERROR the feature `if_let` has already been enabled +#![feature(if_let)] //~ WARN the feature `if_let` has already been enabled fn main() {} diff --git a/tests/ui/feature-gates/duplicate-features.stderr b/tests/ui/feature-gates/duplicate-features.stderr index f667a5b9623ff..c44e8867c2cf7 100644 --- a/tests/ui/feature-gates/duplicate-features.stderr +++ b/tests/ui/feature-gates/duplicate-features.stderr @@ -1,15 +1,16 @@ -error[E0636]: the feature `if_let` has already been enabled - --> $DIR/duplicate-features.rs:7:12 +warning: the feature `if_let` has already been enabled + --> $DIR/duplicate-features.rs:9:12 | LL | #![feature(if_let)] | ^^^^^^ + | + = note: `#[warn(duplicate_features)]` on by default -error[E0636]: the feature `rust1` has already been enabled - --> $DIR/duplicate-features.rs:4:12 +warning: the feature `rust1` has already been enabled + --> $DIR/duplicate-features.rs:6:12 | LL | #![feature(rust1)] | ^^^^^ -error: aborting due to 2 previous errors +warning: 2 warnings emitted -For more information about this error, try `rustc --explain E0636`.