Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions compiler/rustc_attr_ir/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,9 @@ pub enum StabilityLevel {
/// Rust release which stabilized this feature.
since: StableSince,
/// This is `Some` if this item allowed to be referred to on stable via unstable modules;
/// the `Symbol` is the deprecation message printed in that case.
allowed_through_unstable_modules: Option<Symbol>,
/// the first `Symbol` is the deprecation message printed in that case,
/// the second `Symbol` is the correct module to use.
allowed_through_unstable_modules: Option<(Symbol, Symbol)>,
},
}

Expand Down
54 changes: 45 additions & 9 deletions compiler/rustc_attr_parsing/src/attributes/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use rustc_feature::{ACCEPTED_LANG_FEATURES, AttributeStability};

use super::prelude::*;
use super::util::parse_version;
use crate::context::ExpectNameValue;
use crate::diagnostics;

const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
Expand Down Expand Up @@ -49,7 +50,7 @@ const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[

#[derive(Default)]
pub(crate) struct StabilityParser {
allowed_through_unstable_modules: Option<Symbol>,
allowed_through_unstable_modules: Option<(Symbol, Symbol)>,
stability: Option<(Stability, Span)>,
}

Expand Down Expand Up @@ -93,16 +94,51 @@ impl AttributeParser for StabilityParser {
),
(
&[sym::rustc_allowed_through_unstable_modules],
template!(NameValueStr: "deprecation message"),
template!(List: &[r#"message = "...", module = "..."#]),
unstable!(staged_api),
|this, cx, args| {
let Some(nv) = cx.expect_name_value(args, cx.attr_span, None) else {
return;
};
let Some(value_str) = cx.expect_string_literal(nv) else {
return;
};
this.allowed_through_unstable_modules = Some(value_str);
let Some(list) = cx.expect_list(args, cx.attr_span) else { return };
let mut message = None;
let mut module = None;

for item in list.mixed() {
let Some((name, value)) = item.expect_name_value(cx, item.span(), None) else {
return;
};
let Some(value) = cx.expect_string_literal(value) else {
return;
};

match name.name {
sym::message => {
if message.is_some() {
cx.adcx().duplicate_key(name.span, name.name);
} else {
message = Some(value)
}
}
sym::module => {
if module.is_some() {
cx.adcx().duplicate_key(name.span, name.name);
} else {
module = Some(value)
}
}
_ => {
cx.adcx().expected_specific_argument(
name.span,
&[sym::message, sym::module],
);
}
}
}

let allowed_through_unstable_modules = try { (message?, module?) };
if allowed_through_unstable_modules.is_none() {
cx.emit_err(diagnostics::RustcAtumMissingParams { span: cx.attr_span });
}

this.allowed_through_unstable_modules = allowed_through_unstable_modules;
},
),
];
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_attr_parsing/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,15 @@ pub(crate) struct RustcAllowedUnstablePairing {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(
"`rustc_allowed_through_unstable_modules` attribute must have `message` and `module` params"
)]
pub(crate) struct RustcAtumMissingParams {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("suggestions on deprecated items are unstable")]
pub(crate) struct DeprecatedItemSuggestion {
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0789.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ Erroneous code example:

#![unstable(feature = "foo_module", reason = "...", issue = "123")]

#[rustc_allowed_through_unstable_modules = "deprecation message"]
#[rustc_allowed_through_unstable_modules(
message = "deprecation message",
module = "stable_module",
)]
// #[stable(feature = "foo", since = "1.0")]
struct Foo;
// ^^^ error: `rustc_allowed_through_unstable_modules` attribute must be
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,15 @@ fn deprecation_lint(is_in_effect: bool) -> &'static Lint {
style = "verbose",
applicability = "machine-applicable"
)]
pub struct DeprecationSuggestion {
pub(crate) struct DeprecationSuggestion {
#[primary_span]
pub span: Span,

pub kind: String,
pub suggestion: Symbol,
}

pub struct Deprecated {
pub(crate) struct Deprecated {
pub sub: Option<DeprecationSuggestion>,

pub kind: String,
Expand Down
17 changes: 17 additions & 0 deletions compiler/rustc_passes/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1164,3 +1164,20 @@ pub(crate) struct ConstFnLinkage {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("use of deprecated import through accidentally stabilized module `{$module}`")]
pub(crate) struct RustcAtumSuggestion {
#[primary_span]
pub import_span: Span,
pub message: Symbol,
pub suggestion: Symbol,
pub module: Ident,
#[suggestion(
"{$message}",
code = "{suggestion}",
style = "verbose",
applicability = "machine-applicable"
)]
pub unstable_mod_span: Span,
}
36 changes: 16 additions & 20 deletions compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,15 @@ use rustc_hir::{
ItemKind, Path, Stability, StabilityLevel, StableSince, TraitRef, Ty, TyKind, UnstableReason,
UsePath, VERSION_PLACEHOLDER, Variant, find_attr,
};
use rustc_lint_defs as lint;
use rustc_lint_defs::builtin::{
DEPRECATED, DUPLICATE_FEATURES, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, STABLE_FEATURES,
};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::middle::stability::{AllowUnstable, Deprecated, DeprecationEntry, EvalResult};
use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, EvalResult};
use rustc_middle::query::{LocalCrate, Providers};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::span_bug;
use rustc_middle::ty::{AssocContainer, TyCtxt};
use rustc_span::{Span, Symbol, sym};
use tracing::instrument;
Expand Down Expand Up @@ -790,7 +789,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {

if item_is_allowed {
// The item itself is allowed; check whether the path there is also allowed.
let is_allowed_through_unstable_modules: Option<Symbol> =
let is_allowed_through_unstable_modules: Option<(Symbol, Symbol)> =
self.tcx.lookup_stability(def_id).and_then(|stab| match stab.level {
StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
allowed_through_unstable_modules
Expand Down Expand Up @@ -829,7 +828,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
},
);
}
Some(deprecation) => {
Some((message, suggestion)) => {
// Call the stability check directly so that we can control which
// diagnostic is emitted.
let eval_result = self.tcx.eval_stability_allow_unstable(
Expand All @@ -845,22 +844,19 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
);
let is_allowed = matches!(eval_result, EvalResult::Allow);
if !is_allowed {
// Calculating message for lint involves calling `self.def_path_str`,
// which will by default invoke the expensive `visible_parent_map` query.
// Skip all that work if the lint is allowed anyway.
if self.tcx.lint_level_spec_at_node(DEPRECATED, id).is_allow() {
return;
}
// Show a deprecation message.
let def_path =
with_no_trimmed_paths!(self.tcx.def_path_str(def_id));
let def_kind = self.tcx.def_descr(def_id);
let diag = Deprecated {
sub: None,
kind: def_kind.to_owned(),
path: def_path,
note: Some(deprecation),
since_kind: lint::DeprecatedSinceKind::InEffect,
let [.., intrinsics_module, _intrinsic] = path.segments else {
span_bug!(
path.span,
"no module for `is_allowed_through_unstable_modules` intrinsic {path:?}"
)
};
let diag = diagnostics::RustcAtumSuggestion {
message,
import_span: path.span,
unstable_mod_span: { intrinsics_module.ident.span },
module: intrinsics_module.ident,
suggestion,
};
self.tcx.emit_node_span_lint(
DEPRECATED,
Expand Down
20 changes: 16 additions & 4 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,10 @@ pub const fn forget<T: ?Sized>(_: T);
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead"]
#[rustc_allowed_through_unstable_modules(
message = "import this function via the `mem` module instead",
module = "mem"
)]
#[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
#[rustc_diagnostic_item = "transmute"]
#[rustc_nounwind]
Expand Down Expand Up @@ -3296,7 +3299,10 @@ pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + PointeeSized, M>(ptr:
// debug assertions; if you are writing compiler tests or code inside the standard library
// that wants to avoid those debug assertions, directly call this intrinsic instead.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
#[rustc_allowed_through_unstable_modules(
message = "import this function via the `ptr` module instead",
module = "ptr"
)]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
#[rustc_nounwind]
#[rustc_intrinsic]
Expand All @@ -3307,7 +3313,10 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
// debug assertions; if you are writing compiler tests or code inside the standard library
// that wants to avoid those debug assertions, directly call this intrinsic instead.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
#[rustc_allowed_through_unstable_modules(
message = "import this function via the `ptr` module instead",
module = "ptr"
)]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
#[rustc_nounwind]
#[rustc_intrinsic]
Expand All @@ -3318,7 +3327,10 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
// debug assertions; if you are writing compiler tests or code inside the standard library
// that wants to avoid those debug assertions, directly call this intrinsic instead.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
#[rustc_allowed_through_unstable_modules(
message = "import this function via the `ptr` module instead",
module = "ptr"
)]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
#[rustc_nounwind]
#[rustc_intrinsic]
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ impl Item {
// were never supposed to work at all.
let stab = self.stability(tcx)?;
if let rustc_hir::StabilityLevel::Stable {
allowed_through_unstable_modules: Some(note),
allowed_through_unstable_modules: Some((note, _)),
..
} = stab.level
{
Expand Down Expand Up @@ -2534,7 +2534,7 @@ mod size_asserts {
static_assert_size!(GenericParamDef, 40);
static_assert_size!(Generics, 16);
static_assert_size!(Item, 8);
static_assert_size!(ItemInner, 136);
static_assert_size!(ItemInner, 144);
static_assert_size!(ItemKind, 48);
static_assert_size!(PathSegment, 32);
static_assert_size!(Type, 32);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ pub mod stb1 {
#[unstable(feature = "uns", issue = "135003")]
pub mod uns {
#[stable(since = "1.0", feature = "stb1")]
#[rustc_allowed_through_unstable_modules = "use stable path instead"]
#[rustc_allowed_through_unstable_modules(message = "use stable path instead", module = "stb1")]
pub struct Inside1;
#[stable(since = "1.0", feature = "stb2")]
#[rustc_allowed_through_unstable_modules = "use stable path instead"]
#[rustc_allowed_through_unstable_modules(message = "use stable path instead", module = "stb2")]
pub struct Inside2;
}

Expand Down
5 changes: 4 additions & 1 deletion tests/rustdoc-html/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ pub mod stable_later {
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allowed_through_unstable_modules = "use stable path instead"]
#[rustc_allowed_through_unstable_modules(
message = "use stable path instead",
module = "stable_module",
)]
pub mod stable_earlier1 {
//@ has stability/stable_earlier1/struct.StableInUnstable.html \
// '//div[@class="main-heading"]//span[@class="since"]' '1.0.0'
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/error-codes/E0789.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#![feature(staged_api)]
#![unstable(feature = "foo_module", reason = "...", issue = "123")]

#[rustc_allowed_through_unstable_modules = "use stable path instead"]
#[rustc_allowed_through_unstable_modules(message = "use stable path instead", module = "stable")]
// #[stable(feature = "foo", since = "1.0")]
struct Foo;
//~^ ERROR `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ LL | use core::unicode::UNICODE_VERSION;
= help: add `#![feature(unicode_internals)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

warning: use of deprecated module `std::intrinsics`: import this function via `std::mem` instead
--> $DIR/accidental-stable-in-unstable.rs:10:23
warning: use of deprecated import through accidentally stabilized module `intrinsics`
--> $DIR/accidental-stable-in-unstable.rs:10:5
|
LL | use core::intrinsics::transmute; // depended upon by rand_core
| ^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(deprecated)]` on by default
help: import this function via the `mem` module instead
|
LL - use core::intrinsics::transmute; // depended upon by rand_core
LL + use core::mem::transmute; // depended upon by rand_core
|

error: aborting due to 1 previous error; 1 warning emitted

Expand Down
39 changes: 39 additions & 0 deletions tests/ui/stability-attribute/accidentally-stable-intrinsics.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//@ run-rustfix
#![crate_type = "lib"]
#![allow(unnecessary_transmutes, unused_imports)]
#![deny(deprecated)]

extern crate core;

use std::mem::transmute as _;
//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics`
use core::ptr::copy as _;
//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics`
use std::ptr::copy_nonoverlapping as _;
//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics`
use core::ptr::write_bytes as _;
//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics`

use core::ptr::{
copy as _,
//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics`
copy_nonoverlapping as _,
//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics`
write_bytes as _,
//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics`
};

pub fn what() {
unsafe {
let value = 42_u8;
let mut dst = 0;
let _ = std::mem::transmute::<u8, i8>(value);
//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics`
core::ptr::copy(&value, &mut dst, 1);
//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics`
core::ptr::copy_nonoverlapping(&value, &mut dst, 1);
//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics`
std::ptr::write_bytes(&mut dst, value, 1)
//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics`
}
}
Loading
Loading