Port rustc_never_type_options to the new attribute parser
This commit is contained in:
parent
a17eb934db
commit
954f483557
10 changed files with 148 additions and 99 deletions
|
|
@ -420,6 +420,88 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcCaptureAnalysisParser {
|
|||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCaptureAnalysis;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcNeverTypeOptionsParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcNeverTypeOptionsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_never_type_options];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &[
|
||||
r#"fallback = "unit", "never", "no""#,
|
||||
r#"diverging_block_default = "unit", "never""#,
|
||||
]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut fallback = None::<Ident>;
|
||||
let mut diverging_block_default = None::<Ident>;
|
||||
|
||||
for arg in list.mixed() {
|
||||
let Some(meta) = arg.meta_item() else {
|
||||
cx.expected_name_value(arg.span(), None);
|
||||
continue;
|
||||
};
|
||||
|
||||
let res = match meta.ident().map(|i| i.name) {
|
||||
Some(sym::fallback) => &mut fallback,
|
||||
Some(sym::diverging_block_default) => &mut diverging_block_default,
|
||||
_ => {
|
||||
cx.expected_specific_argument(
|
||||
meta.path().span(),
|
||||
&[sym::fallback, sym::diverging_block_default],
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let Some(nv) = meta.args().name_value() else {
|
||||
cx.expected_name_value(meta.span(), None);
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(field) = nv.value_as_str() else {
|
||||
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
||||
continue;
|
||||
};
|
||||
|
||||
if res.is_some() {
|
||||
cx.duplicate_key(meta.span(), meta.ident().unwrap().name);
|
||||
continue;
|
||||
}
|
||||
|
||||
*res = Some(Ident { name: field, span: nv.value_span });
|
||||
}
|
||||
|
||||
let fallback = match fallback {
|
||||
None => None,
|
||||
Some(Ident { name: sym::unit, .. }) => Some(DivergingFallbackBehavior::ToUnit),
|
||||
Some(Ident { name: sym::never, .. }) => Some(DivergingFallbackBehavior::ToNever),
|
||||
Some(Ident { name: sym::no, .. }) => Some(DivergingFallbackBehavior::NoFallback),
|
||||
Some(Ident { span, .. }) => {
|
||||
cx.expected_specific_argument_strings(span, &[sym::unit, sym::never, sym::no]);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let diverging_block_default = match diverging_block_default {
|
||||
None => None,
|
||||
Some(Ident { name: sym::unit, .. }) => Some(DivergingBlockBehavior::Unit),
|
||||
Some(Ident { name: sym::never, .. }) => Some(DivergingBlockBehavior::Never),
|
||||
Some(Ident { span, .. }) => {
|
||||
cx.expected_specific_argument_strings(span, &[sym::unit, sym::no]);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
Some(AttributeKind::RustcNeverTypeOptions { fallback, diverging_block_default })
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcLintQueryInstabilityParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintQueryInstabilityParser {
|
||||
|
|
|
|||
|
|
@ -147,9 +147,9 @@ attribute_parsers!(
|
|||
DocParser,
|
||||
MacroUseParser,
|
||||
NakedParser,
|
||||
RustcCguTestAttributeParser,
|
||||
StabilityParser,
|
||||
UsedParser,
|
||||
RustcCguTestAttributeParser,
|
||||
// tidy-alphabetical-end
|
||||
|
||||
// tidy-alphabetical-start
|
||||
|
|
@ -210,6 +210,7 @@ attribute_parsers!(
|
|||
Single<RustcLegacyConstGenericsParser>,
|
||||
Single<RustcLintOptDenyFieldAccessParser>,
|
||||
Single<RustcMustImplementOneOfParser>,
|
||||
Single<RustcNeverTypeOptionsParser>,
|
||||
Single<RustcObjectLifetimeDefaultParser>,
|
||||
Single<RustcReservationImplParser>,
|
||||
Single<RustcScalableVectorParser>,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,44 @@ pub enum CguFields {
|
|||
PartitionCodegened { cfg: Symbol, module: Symbol },
|
||||
ExpectedCguReuse { cfg: Symbol, module: Symbol, kind: CguKind },
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, PrintAttribute)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum DivergingFallbackBehavior {
|
||||
/// Always fallback to `()` (aka "always spontaneous decay")
|
||||
ToUnit,
|
||||
/// Always fallback to `!` (which should be equivalent to never falling back + not making
|
||||
/// never-to-any coercions unless necessary)
|
||||
ToNever,
|
||||
/// Don't fallback at all
|
||||
NoFallback,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, PrintAttribute, Default)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum DivergingBlockBehavior {
|
||||
/// This is the current stable behavior:
|
||||
///
|
||||
/// ```rust
|
||||
/// {
|
||||
/// return;
|
||||
/// } // block has type = !, even though we are supposedly dropping it with `;`
|
||||
/// ```
|
||||
#[default]
|
||||
Never,
|
||||
|
||||
/// Alternative behavior:
|
||||
///
|
||||
/// ```ignore (very-unstable-new-attribute)
|
||||
/// #![rustc_never_type_options(diverging_block_default = "unit")]
|
||||
/// {
|
||||
/// return;
|
||||
/// } // block has type = (), since we are dropping `!` from `return` with `;`
|
||||
/// ```
|
||||
Unit,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
|
||||
pub enum InlineAttr {
|
||||
None,
|
||||
Hint,
|
||||
|
|
@ -1069,6 +1107,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_capture_analysis]`
|
||||
RustcCaptureAnalysis,
|
||||
|
||||
/// Represents `#[rustc_expected_cgu_reuse]`, `#[rustc_partition_codegened]` and `#[rustc_partition_reused]`.
|
||||
RustcCguTestAttr(ThinVec<(Span, CguFields)>),
|
||||
|
||||
/// Represents `#[rustc_clean]`
|
||||
RustcClean(ThinVec<RustcCleanAttribute>),
|
||||
|
||||
|
|
@ -1139,9 +1180,6 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_evaluate_where_clauses]`
|
||||
RustcEvaluateWhereClauses,
|
||||
|
||||
/// Represents `#[rustc_expected_cgu_reuse]`, `#[rustc_partition_codegened]` and `#[rustc_partition_reused]`.
|
||||
RustcCguTestAttr(ThinVec<(Span, CguFields)>),
|
||||
|
||||
/// Represents `#[rustc_has_incoherent_inherent_impls]`
|
||||
RustcHasIncoherentInherentImpls,
|
||||
|
||||
|
|
@ -1199,6 +1237,12 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_never_returns_null_ptr]`
|
||||
RustcNeverReturnsNullPointer,
|
||||
|
||||
/// Represents `#[rustc_never_type_options]`.
|
||||
RustcNeverTypeOptions {
|
||||
fallback: Option<DivergingFallbackBehavior>,
|
||||
diverging_block_default: Option<DivergingBlockBehavior>,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_no_implicit_autorefs]`
|
||||
RustcNoImplicitAutorefs,
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ impl AttributeKind {
|
|||
RustcBodyStability { .. } => No,
|
||||
RustcBuiltinMacro { .. } => Yes,
|
||||
RustcCaptureAnalysis => No,
|
||||
RustcCguTestAttr { .. } => No,
|
||||
RustcClean { .. } => No,
|
||||
RustcCoherenceIsCore(..) => No,
|
||||
RustcCoinductive(..) => No,
|
||||
|
|
@ -139,6 +140,7 @@ impl AttributeKind {
|
|||
RustcMir(..) => Yes,
|
||||
RustcMustImplementOneOf { .. } => No,
|
||||
RustcNeverReturnsNullPointer => Yes,
|
||||
RustcNeverTypeOptions { .. } => No,
|
||||
RustcNoImplicitAutorefs => Yes,
|
||||
RustcNoImplicitBounds => No,
|
||||
RustcNonConstTraitMethod => No, // should be reported via other queries like `constness`
|
||||
|
|
@ -149,7 +151,6 @@ impl AttributeKind {
|
|||
RustcOffloadKernel => Yes,
|
||||
RustcOutlives => No,
|
||||
RustcParenSugar(..) => No,
|
||||
RustcCguTestAttr { .. } => No,
|
||||
RustcPassByValue(..) => Yes,
|
||||
RustcPassIndirectlyInNonRusticAbis(..) => No,
|
||||
RustcPreserveUbChecks => No,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use rustc_data_structures::graph::{self};
|
|||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::attrs::DivergingFallbackBehavior;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{InferKind, Visitor};
|
||||
|
|
@ -19,17 +20,6 @@ use tracing::debug;
|
|||
|
||||
use crate::{FnCtxt, errors};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) enum DivergingFallbackBehavior {
|
||||
/// Always fallback to `()` (aka "always spontaneous decay")
|
||||
ToUnit,
|
||||
/// Always fallback to `!` (which should be equivalent to never falling back + not making
|
||||
/// never-to-any coercions unless necessary)
|
||||
ToNever,
|
||||
/// Don't fallback at all
|
||||
NoFallback,
|
||||
}
|
||||
|
||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
/// Performs type inference fallback, setting [`FnCtxt::diverging_fallback_has_occurred`]
|
||||
/// if the never type fallback has occurred.
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use itertools::Itertools;
|
|||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, listify, pluralize};
|
||||
use rustc_hir::attrs::DivergingBlockBehavior;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
|
@ -47,29 +48,6 @@ rustc_index::newtype_index! {
|
|||
pub(crate) struct GenericIdx {}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub(crate) enum DivergingBlockBehavior {
|
||||
/// This is the current stable behavior:
|
||||
///
|
||||
/// ```rust
|
||||
/// {
|
||||
/// return;
|
||||
/// } // block has type = !, even though we are supposedly dropping it with `;`
|
||||
/// ```
|
||||
#[default]
|
||||
Never,
|
||||
|
||||
/// Alternative behavior:
|
||||
///
|
||||
/// ```ignore (very-unstable-new-attribute)
|
||||
/// #![rustc_never_type_options(diverging_block_default = "unit")]
|
||||
/// {
|
||||
/// return;
|
||||
/// } // block has type = (), since we are dropping `!` from `return` with `;`
|
||||
/// ```
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(in super::super) fn check_casts(&mut self) {
|
||||
let mut deferred_cast_checks = self.root_ctxt.deferred_cast_checks.borrow_mut();
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ use std::ops::Deref;
|
|||
|
||||
use hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_hir::attrs::{AttributeKind, DivergingBlockBehavior, DivergingFallbackBehavior};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{self as hir, HirId, ItemLocalMap};
|
||||
use rustc_hir::{self as hir, HirId, ItemLocalMap, find_attr};
|
||||
use rustc_hir_analysis::hir_ty_lowering::{
|
||||
HirTyLowerer, InherentAssocCandidate, RegionInferReason,
|
||||
};
|
||||
|
|
@ -19,15 +20,13 @@ use rustc_infer::infer::{self, RegionVariableOrigin};
|
|||
use rustc_infer::traits::{DynCompatibilityViolation, Obligation};
|
||||
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym};
|
||||
use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span};
|
||||
use rustc_trait_selection::error_reporting::TypeErrCtxt;
|
||||
use rustc_trait_selection::traits::{
|
||||
self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,
|
||||
};
|
||||
|
||||
use crate::coercion::CoerceMany;
|
||||
use crate::fallback::DivergingFallbackBehavior;
|
||||
use crate::fn_ctxt::checks::DivergingBlockBehavior;
|
||||
use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt};
|
||||
|
||||
/// The `FnCtxt` stores type-checking context needed to type-check bodies of
|
||||
|
|
@ -517,51 +516,5 @@ fn parse_never_type_options_attr(
|
|||
// Error handling is dubious here (unwraps), but that's probably fine for an internal attribute.
|
||||
// Just don't write incorrect attributes <3
|
||||
|
||||
let mut fallback = None;
|
||||
let mut block = None;
|
||||
|
||||
let items = if tcx.features().rustc_attrs() {
|
||||
tcx.get_attr(CRATE_DEF_ID, sym::rustc_never_type_options)
|
||||
.map(|attr| attr.meta_item_list().unwrap())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let items = items.unwrap_or_default();
|
||||
|
||||
for item in items {
|
||||
if item.has_name(sym::fallback) && fallback.is_none() {
|
||||
let mode = item.value_str().unwrap();
|
||||
match mode {
|
||||
sym::unit => fallback = Some(DivergingFallbackBehavior::ToUnit),
|
||||
sym::never => fallback = Some(DivergingFallbackBehavior::ToNever),
|
||||
sym::no => fallback = Some(DivergingFallbackBehavior::NoFallback),
|
||||
_ => {
|
||||
tcx.dcx().span_err(item.span(), format!("unknown never type fallback mode: `{mode}` (supported: `unit`, `niko`, `never` and `no`)"));
|
||||
}
|
||||
};
|
||||
continue;
|
||||
}
|
||||
|
||||
if item.has_name(sym::diverging_block_default) && block.is_none() {
|
||||
let default = item.value_str().unwrap();
|
||||
match default {
|
||||
sym::unit => block = Some(DivergingBlockBehavior::Unit),
|
||||
sym::never => block = Some(DivergingBlockBehavior::Never),
|
||||
_ => {
|
||||
tcx.dcx().span_err(item.span(), format!("unknown diverging block default: `{default}` (supported: `unit` and `never`)"));
|
||||
}
|
||||
};
|
||||
continue;
|
||||
}
|
||||
|
||||
tcx.dcx().span_err(
|
||||
item.span(),
|
||||
format!(
|
||||
"unknown or duplicate never type option: `{}` (supported: `fallback`, `diverging_block_default`)",
|
||||
item.name().unwrap()
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
(fallback, block)
|
||||
find_attr!(tcx.get_all_attrs(CRATE_DEF_ID), AttributeKind::RustcNeverTypeOptions {fallback, diverging_block_default} => (*fallback, *diverging_block_default)).unwrap_or_default()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,6 +295,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::RustcBodyStability { .. }
|
||||
| AttributeKind::RustcBuiltinMacro { .. }
|
||||
| AttributeKind::RustcCaptureAnalysis
|
||||
| AttributeKind::RustcCguTestAttr(..)
|
||||
| AttributeKind::RustcClean(..)
|
||||
| AttributeKind::RustcCoherenceIsCore(..)
|
||||
| AttributeKind::RustcCoinductive(..)
|
||||
|
|
@ -332,6 +333,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::RustcMain
|
||||
| AttributeKind::RustcMir(_)
|
||||
| AttributeKind::RustcNeverReturnsNullPointer
|
||||
| AttributeKind::RustcNeverTypeOptions {..}
|
||||
| AttributeKind::RustcNoImplicitAutorefs
|
||||
| AttributeKind::RustcNoImplicitBounds
|
||||
| AttributeKind::RustcNonConstTraitMethod
|
||||
|
|
@ -341,7 +343,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::RustcOffloadKernel
|
||||
| AttributeKind::RustcOutlives
|
||||
| AttributeKind::RustcParenSugar(..)
|
||||
| AttributeKind::RustcCguTestAttr(..)
|
||||
| AttributeKind::RustcPassByValue (..)
|
||||
| AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
|
||||
| AttributeKind::RustcPreserveUbChecks
|
||||
|
|
@ -405,7 +406,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| sym::rustc_test_marker
|
||||
| sym::rustc_layout
|
||||
| sym::rustc_proc_macro_decls
|
||||
| sym::rustc_never_type_options
|
||||
| sym::rustc_autodiff
|
||||
| sym::rustc_capture_analysis
|
||||
| sym::rustc_mir
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
//! The `rustc_*` attribute is malformed, but ICEing without a `feature(rustc_attrs)` is still bad.
|
||||
|
||||
#![rustc_never_type_options(: Unsize<U> = "hi")]
|
||||
//~^ ERROR expected unsuffixed literal, found `:`
|
||||
//~^ ERROR expected a literal
|
||||
//~| ERROR use of an internal attribute
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
error: expected unsuffixed literal, found `:`
|
||||
--> $DIR/malformed-never-type-options.rs:4:29
|
||||
|
|
||||
LL | #![rustc_never_type_options(: Unsize<U> = "hi")]
|
||||
| ^
|
||||
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/malformed-never-type-options.rs:4:1
|
||||
|
|
||||
|
|
@ -14,6 +8,12 @@ LL | #![rustc_never_type_options(: Unsize<U> = "hi")]
|
|||
= note: the `#[rustc_never_type_options]` attribute is an internal implementation detail that will never be stable
|
||||
= note: `rustc_never_type_options` is used to experiment with never type fallback and work on never type stabilization
|
||||
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `:`
|
||||
--> $DIR/malformed-never-type-options.rs:4:29
|
||||
|
|
||||
LL | #![rustc_never_type_options(: Unsize<U> = "hi")]
|
||||
| ^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue