Auto merge of #108821 - matthiaskrgr:rollup-cmkbgpr, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #107801 (const_eval: `implies_by` in `rustc_const_unstable`)
 - #108750 (Fix `ObligationCtxt::sub`)
 - #108780 (Add regression tests for issue 70919)
 - #108786 (Check for free regions in MIR validation)
 - #108790 (Do not ICE when interpreting a cast between non-monomorphic types)
 - #108803 (Do not ICE when failing to normalize in ConstProp.)
 - #108807 (Emit the suspicious_auto_trait_impls for negative impls as well)
 - #108812 (Add regression test for #98444)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-03-06 22:15:55 +00:00
commit 81be7b86d3
33 changed files with 443 additions and 46 deletions

View File

@ -1,3 +1,4 @@
use rustc_attr as attr;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
@ -5,11 +6,17 @@ use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
/// Whether the `def_id` is an unstable const fn and what feature gate(s) are necessary to enable
/// it.
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<(Symbol, Option<Symbol>)> {
if tcx.is_const_fn_raw(def_id) {
let const_stab = tcx.lookup_const_stability(def_id)?;
if const_stab.is_const_unstable() { Some(const_stab.feature) } else { None }
match const_stab.level {
attr::StabilityLevel::Unstable { implied_by, .. } => {
Some((const_stab.feature, implied_by))
}
attr::StabilityLevel::Stable { .. } => None,
}
} else {
None
}

View File

@ -67,12 +67,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
Pointer(PointerCast::ReifyFnPointer) => {
// All reifications must be monomorphic, bail out otherwise.
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
// The src operand does not matter, just its type
match *src.layout.ty.kind() {
ty::FnDef(def_id, substs) => {
// All reifications must be monomorphic, bail out otherwise.
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
let instance = ty::Instance::resolve_for_fn_ptr(
*self.tcx,
self.param_env,
@ -100,12 +100,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
Pointer(PointerCast::ClosureFnPointer(_)) => {
// All reifications must be monomorphic, bail out otherwise.
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
// The src operand does not matter, just its type
match *src.layout.ty.kind() {
ty::Closure(def_id, substs) => {
// All reifications must be monomorphic, bail out otherwise.
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
let instance = ty::Instance::resolve_closure(
*self.tcx,
def_id,
@ -359,8 +359,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx);
self.write_immediate(val, dest)
}
_ => {
// Do not ICE if we are not monomorphic enough.
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
ensure_monomorphic_enough(*self.tcx, cast_ty)?;
span_bug!(
self.cur_span(),
"invalid pointer unsizing {:?} -> {:?}",
@ -404,12 +407,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
Ok(())
}
_ => span_bug!(
self.cur_span(),
"unsize_into: invalid conversion: {:?} -> {:?}",
src.layout,
dest.layout
),
_ => {
// Do not ICE if we are not monomorphic enough.
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
ensure_monomorphic_enough(*self.tcx, cast_ty.ty)?;
span_bug!(
self.cur_span(),
"unsize_into: invalid conversion: {:?} -> {:?}",
src.layout,
dest.layout
)
}
}
}
}

View File

@ -7,7 +7,7 @@ use either::{Either, Left, Right};
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
use rustc_index::vec::IndexVec;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{ErrorHandled, InterpError, InvalidProgramInfo};
use rustc_middle::mir::interpret::{ErrorHandled, InterpError};
use rustc_middle::ty::layout::{
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
TyAndLayout,
@ -508,14 +508,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
frame
.instance
.try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value)
.map_err(|e| {
self.tcx.sess.delay_span_bug(
self.cur_span(),
format!("failed to normalize {}", e.get_type_for_failure()).as_str(),
);
InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric)
})
.map_err(|_| err_inval!(TooGeneric))
}
/// The `substs` are assumed to already be in our interpreter "universe" (param_env).

View File

@ -926,15 +926,24 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// If the `const fn` we are trying to call is not const-stable, ensure that we have
// the proper feature gate enabled.
if let Some(gate) = is_unstable_const_fn(tcx, callee) {
if let Some((gate, implied_by)) = is_unstable_const_fn(tcx, callee) {
trace!(?gate, "calling unstable const fn");
if self.span.allows_unstable(gate) {
return;
}
if let Some(implied_by_gate) = implied_by && self.span.allows_unstable(implied_by_gate) {
return;
}
// Calling an unstable function *always* requires that the corresponding gate
// be enabled, even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`.
if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) {
// (or implied gate) be enabled, even if the function has
// `#[rustc_allow_const_fn_unstable(the_gate)]`.
let gate_declared = |gate| {
tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate)
};
let feature_gate_declared = gate_declared(gate);
let implied_gate_declared = implied_by.map(gate_declared).unwrap_or(false);
if !feature_gate_declared && !implied_gate_declared {
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
return;
}
@ -947,7 +956,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
// Otherwise, we are something const-stable calling a const-unstable fn.
if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
trace!("rustc_allow_const_fn_unstable gate active");
return;

View File

@ -72,6 +72,17 @@ impl<'tcx> MirPass<'tcx> for Validator {
};
checker.visit_body(body);
checker.check_cleanup_control_flow();
if let MirPhase::Runtime(_) = body.phase {
if let ty::InstanceDef::Item(_) = body.source.instance {
if body.has_free_regions() {
checker.fail(
Location::START,
format!("Free regions in optimized {} MIR", body.phase.name()),
);
}
}
}
}
}

View File

@ -478,10 +478,6 @@ fn lint_auto_trait_impl<'tcx>(
trait_ref: ty::TraitRef<'tcx>,
impl_def_id: LocalDefId,
) {
if tcx.impl_polarity(impl_def_id) != ImplPolarity::Positive {
return;
}
assert_eq!(trait_ref.substs.len(), 1);
let self_ty = trait_ref.self_ty();
let (self_type_did, substs) = match self_ty.kind() {

View File

@ -416,8 +416,6 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None);
debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
body
}
@ -626,8 +624,6 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
debug!("body: {:#?}", body);
run_optimization_passes(tcx, &mut body);
debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
body
}
@ -651,7 +647,5 @@ fn promoted_mir(
run_analysis_to_runtime_passes(tcx, body);
}
debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
tcx.arena.alloc(promoted)
}

View File

@ -265,6 +265,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
self.index.implications.insert(implied_by, feature);
}
if let Some(ConstStability {
level: Unstable { implied_by: Some(implied_by), .. },
feature,
..
}) = const_stab
{
self.index.implications.insert(implied_by, feature);
}
self.index.stab_map.insert(def_id, stab);
stab
});

View File

@ -158,7 +158,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
self.infcx
.at(cause, param_env)
.define_opaque_types(true)
.sup(expected, actual)
.sub(expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}

View File

@ -1,4 +1,10 @@
// check-pass
// revisions: check build
// [check]check-pass
//
// This second configuration aims to verify that we do not ICE in ConstProp because of
// normalization failure.
// [build]build-pass
// [build]compile-flags: -Zmir-opt-level=3 --emit=mir
#![allow(dead_code)]

View File

@ -0,0 +1,21 @@
#![feature(negative_impls)]
#![deny(suspicious_auto_trait_impls)]
use std::marker::PhantomData;
struct ContainsVec<T>(Vec<T>);
impl !Send for ContainsVec<u32> {}
//~^ ERROR
//~| WARNING this will change its meaning
pub struct WithPhantomDataSend<T, U>(PhantomData<T>, U);
impl<T> !Send for WithPhantomDataSend<*const T, u8> {}
//~^ ERROR
//~| WARNING this will change its meaning
pub struct WithLifetime<'a, T>(&'a (), T);
impl<T> !Sync for WithLifetime<'static, Option<T>> {}
//~^ ERROR
//~| WARNING this will change its meaning
fn main() {}

View File

@ -0,0 +1,52 @@
error: cross-crate traits with a default impl, like `Send`, should not be specialized
--> $DIR/suspicious-negative-impls-lint.rs:7:1
|
LL | impl !Send for ContainsVec<u32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this will change its meaning in a future release!
= note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367>
= note: `u32` is not a generic parameter
note: try using the same sequence of generic parameters as the struct definition
--> $DIR/suspicious-negative-impls-lint.rs:6:1
|
LL | struct ContainsVec<T>(Vec<T>);
| ^^^^^^^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/suspicious-negative-impls-lint.rs:2:9
|
LL | #![deny(suspicious_auto_trait_impls)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: cross-crate traits with a default impl, like `Send`, should not be specialized
--> $DIR/suspicious-negative-impls-lint.rs:12:1
|
LL | impl<T> !Send for WithPhantomDataSend<*const T, u8> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this will change its meaning in a future release!
= note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367>
= note: `*const T` is not a generic parameter
note: try using the same sequence of generic parameters as the struct definition
--> $DIR/suspicious-negative-impls-lint.rs:11:1
|
LL | pub struct WithPhantomDataSend<T, U>(PhantomData<T>, U);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: cross-crate traits with a default impl, like `Sync`, should not be specialized
--> $DIR/suspicious-negative-impls-lint.rs:17:1
|
LL | impl<T> !Sync for WithLifetime<'static, Option<T>> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this will change its meaning in a future release!
= note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367>
= note: `Option<T>` is not a generic parameter
note: try using the same sequence of generic parameters as the struct definition
--> $DIR/suspicious-negative-impls-lint.rs:16:1
|
LL | pub struct WithLifetime<'a, T>(&'a (), T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors

View File

@ -0,0 +1,24 @@
// A version of `issue-70919-drop-in-loop`, but without
// the necessary `drop` call.
//
// This should fail to compile, since the `Drop` impl
// for `WrapperWithDrop` could observe the changed
// `base` value.
struct WrapperWithDrop<'a>(&'a mut bool);
impl<'a> Drop for WrapperWithDrop<'a> {
fn drop(&mut self) {
}
}
fn drop_in_loop() {
let mut base = true;
let mut wrapper = WrapperWithDrop(&mut base);
loop {
base = false; //~ ERROR: cannot assign to `base`
wrapper = WrapperWithDrop(&mut base);
}
}
fn main() {
}

View File

@ -0,0 +1,14 @@
error[E0506]: cannot assign to `base` because it is borrowed
--> $DIR/drop-in-loop.rs:18:9
|
LL | let mut wrapper = WrapperWithDrop(&mut base);
| --------- `base` is borrowed here
LL | loop {
LL | base = false;
| ^^^^^^^^^^^^ `base` is assigned to here but it was already borrowed
LL | wrapper = WrapperWithDrop(&mut base);
| ------- borrow might be used here, when `wrapper` is dropped and runs the `Drop` code for type `WrapperWithDrop`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0506`.

View File

@ -0,0 +1,25 @@
// Regression test for issue #70919
// Tests that we don't emit a spurious "borrow might be used" error
// when we have an explicit `drop` in a loop
// check-pass
struct WrapperWithDrop<'a>(&'a mut bool);
impl<'a> Drop for WrapperWithDrop<'a> {
fn drop(&mut self) {
}
}
fn drop_in_loop() {
let mut base = true;
let mut wrapper = WrapperWithDrop(&mut base);
loop {
drop(wrapper);
base = false;
wrapper = WrapperWithDrop(&mut base);
}
}
fn main() {
}

View File

@ -13,5 +13,7 @@ impl<T: MyTrait> !Send for TestType<T> {} //~ ERROR found both positive and nega
unsafe impl<T: 'static> Send for TestType<T> {} //~ ERROR conflicting implementations
impl !Send for TestType<i32> {}
//~^ WARNING
//~| WARNING this will change its meaning
fn main() {}

View File

@ -16,7 +16,23 @@ LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
LL | unsafe impl<T: 'static> Send for TestType<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>`
error: aborting due to 2 previous errors
warning: cross-crate traits with a default impl, like `Send`, should not be specialized
--> $DIR/coherence-conflicting-negative-trait-impl.rs:15:1
|
LL | impl !Send for TestType<i32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this will change its meaning in a future release!
= note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367>
= note: `i32` is not a generic parameter
note: try using the same sequence of generic parameters as the struct definition
--> $DIR/coherence-conflicting-negative-trait-impl.rs:7:1
|
LL | struct TestType<T>(::std::marker::PhantomData<T>);
| ^^^^^^^^^^^^^^^^^^
= note: `#[warn(suspicious_auto_trait_impls)]` on by default
error: aborting due to 2 previous errors; 1 warning emitted
Some errors have detailed explanations: E0119, E0751.
For more information about an error, try `rustc --explain E0119`.

View File

@ -14,7 +14,8 @@ impl TheTrait<TheType> for isize { }
impl TheTrait<isize> for TheType { }
impl !Send for Vec<isize> { }
//~^ ERROR E0117
impl !Send for Vec<isize> { } //~ ERROR E0117
//~^ WARNING
//~| WARNING this will change its meaning
fn main() { }

View File

@ -21,6 +21,19 @@ LL | impl !Send for Vec<isize> { }
|
= note: define and implement a trait or new type instead
error: aborting due to 2 previous errors
warning: cross-crate traits with a default impl, like `Send`, should not be specialized
--> $DIR/coherence-orphan.rs:17:1
|
LL | impl !Send for Vec<isize> { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this will change its meaning in a future release!
= note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367>
= note: `isize` is not a generic parameter
note: try using the same sequence of generic parameters as the struct definition
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
= note: `#[warn(suspicious_auto_trait_impls)]` on by default
error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0117`.

View File

@ -15,5 +15,7 @@ impl<T: MyTrait> !Send for TestType<T> {} //~ ERROR found both positive and nega
unsafe impl<T: 'static> Send for TestType<T> {} //~ ERROR conflicting implementations
impl !Send for TestType<i32> {}
//~^ WARNING
//~| WARNING this will change its meaning
fn main() {}

View File

@ -16,7 +16,23 @@ LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
LL | unsafe impl<T: 'static> Send for TestType<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>`
error: aborting due to 2 previous errors
warning: cross-crate traits with a default impl, like `Send`, should not be specialized
--> $DIR/issue-106755.rs:17:1
|
LL | impl !Send for TestType<i32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this will change its meaning in a future release!
= note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367>
= note: `i32` is not a generic parameter
note: try using the same sequence of generic parameters as the struct definition
--> $DIR/issue-106755.rs:9:1
|
LL | struct TestType<T>(::std::marker::PhantomData<T>);
| ^^^^^^^^^^^^^^^^^^
= note: `#[warn(suspicious_auto_trait_impls)]` on by default
error: aborting due to 2 previous errors; 1 warning emitted
Some errors have detailed explanations: E0119, E0751.
For more information about an error, try `rustc --explain E0119`.

View File

@ -0,0 +1,7 @@
// build-fail
fn main() {
let xs: [i32; 5] = [1, 2, 3, 4, 5];
let _ = &xs;
let _ = xs[7]; //~ ERROR: this operation will panic at runtime [unconditional_panic]
}

View File

@ -0,0 +1,10 @@
error: this operation will panic at runtime
--> $DIR/unconditional_panic_98444.rs:6:13
|
LL | let _ = xs[7];
| ^^^^^ index out of bounds: the length is 5 but the index is 7
|
= note: `#[deny(unconditional_panic)]` on by default
error: aborting due to previous error

View File

@ -0,0 +1,15 @@
// Check that the interpreter does not ICE when trying to unsize `B` to `[u8]`.
// This is a `build` test to ensure that const-prop-lint runs.
// build-pass
#![feature(unsize)]
fn foo<B>(buffer: &mut [B; 2])
where B: std::marker::Unsize<[u8]>,
{
let buffer: &[u8] = &buffer[0];
}
fn main() {
foo(&mut [[0], [5]]);
}

View File

@ -0,0 +1,12 @@
#![crate_type = "lib"]
#![feature(staged_api)]
#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
#![rustc_const_stable(feature = "stability_attribute_implies", since = "1.0.0")]
#[stable(feature = "stability_attribute_implies", since = "1.0.0")]
#[rustc_const_stable(feature = "const_foo", since = "1.62.0")]
pub const fn foo() {}
#[stable(feature = "stability_attribute_implies", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_foo")]
pub const fn foobar() {}

View File

@ -0,0 +1,16 @@
#![crate_type = "lib"]
#![feature(staged_api)]
#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
#![rustc_const_stable(feature = "stability_attribute_implies", since = "1.0.0")]
// Tests that `implied_by = "const_bar"` results in an error being emitted if `const_bar` does not
// exist.
#[stable(feature = "stability_attribute_implies", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")]
//~^ ERROR feature `const_bar` implying `const_foobar` does not exist
pub const fn foobar() -> u32 {
0
}
const VAR: u32 = foobar();

View File

@ -0,0 +1,8 @@
error: feature `const_bar` implying `const_foobar` does not exist
--> $DIR/const-stability-attribute-implies-missing.rs:10:1
|
LL | #[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -0,0 +1,16 @@
// aux-build:const-stability-attribute-implies.rs
#![crate_type = "lib"]
// Tests that despite the `const_foobar` feature being implied by now-stable feature `const_foo`,
// if `const_foobar` isn't allowed in this crate then an error will be emitted.
extern crate const_stability_attribute_implies;
use const_stability_attribute_implies::{foo, foobar};
pub const fn bar() -> u32 {
foo(); // no error - stable
foobar(); //~ ERROR `foobar` is not yet stable as a const fn
0
}
pub const VAR: u32 = bar();

View File

@ -0,0 +1,10 @@
error: `foobar` is not yet stable as a const fn
--> $DIR/const-stability-attribute-implies-no-feature.rs:12:5
|
LL | foobar();
| ^^^^^^^^
|
= help: add `#![feature(const_foobar)]` to the crate attributes to enable
error: aborting due to previous error

View File

@ -0,0 +1,19 @@
// aux-build:const-stability-attribute-implies.rs
#![crate_type = "lib"]
#![deny(stable_features)]
#![feature(const_foo)]
//~^ ERROR the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
// Tests that the use of `implied_by` in the `#[rustc_const_unstable]` attribute results in a
// diagnostic mentioning partial stabilization, and that given the implied unstable feature is
// unused (there is no `foobar` call), that the compiler suggests removing the flag.
extern crate const_stability_attribute_implies;
use const_stability_attribute_implies::foo;
pub const fn bar() -> u32 {
foo();
0
}
pub const VAR: u32 = bar();

View File

@ -0,0 +1,22 @@
error: the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
--> $DIR/const-stability-attribute-implies-using-stable.rs:4:12
|
LL | #![feature(const_foo)]
| ^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/const-stability-attribute-implies-using-stable.rs:3:9
|
LL | #![deny(stable_features)]
| ^^^^^^^^^^^^^^^
help: if you are using features which are still unstable, change to using `const_foobar`
|
LL | #![feature(const_foobar)]
| ~~~~~~~~~~~~
help: if you are using features which are now stable, remove this line
|
LL - #![feature(const_foo)]
|
error: aborting due to previous error

View File

@ -0,0 +1,21 @@
// aux-build:const-stability-attribute-implies.rs
#![crate_type = "lib"]
#![deny(stable_features)]
#![feature(const_foo)]
//~^ ERROR the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
// Tests that the use of `implied_by` in the `#[rustc_const_unstable]` attribute results in a
// diagnostic mentioning partial stabilization and that given the implied unstable feature is
// used (there is a `const_foobar` call), that the compiler suggests changing to that feature and
// doesn't error about its use.
extern crate const_stability_attribute_implies;
use const_stability_attribute_implies::{foo, foobar};
pub const fn bar() -> u32 {
foo();
foobar(); // no error!
0
}
pub const VAR: u32 = bar();

View File

@ -0,0 +1,22 @@
error: the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
--> $DIR/const-stability-attribute-implies-using-unstable.rs:4:12
|
LL | #![feature(const_foo)]
| ^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/const-stability-attribute-implies-using-unstable.rs:3:9
|
LL | #![deny(stable_features)]
| ^^^^^^^^^^^^^^^
help: if you are using features which are still unstable, change to using `const_foobar`
|
LL | #![feature(const_foobar)]
| ~~~~~~~~~~~~
help: if you are using features which are now stable, remove this line
|
LL - #![feature(const_foo)]
|
error: aborting due to previous error