Auto merge of #152437 - JonathanBrouwer:rollup-bWpnWOz, r=JonathanBrouwer
Rollup of 10 pull requests Successful merges: - rust-lang/rust#152364 (Port a lot of attributes to the new parser) - rust-lang/rust#151954 (Add help message suggesting explicit reference cast for From/TryFrom) - rust-lang/rust#152148 (Move `impl Interner for TyCtxt` to its own submodule) - rust-lang/rust#152226 (Modernize diagnostic for indeterminate trait object lifetime bounds) - rust-lang/rust#152351 (Remove `SubdiagMessage` in favour of the identical `DiagMessage`) - rust-lang/rust#152417 (Move the needs-drop check for `arena_cache` queries out of macro code) - rust-lang/rust#150688 (typeck: Make it clearer that `check_pat_lit` only handles literal patterns) - rust-lang/rust#152293 (Format heterogeneous try blocks) - rust-lang/rust#152355 (Update documentation of rustc_macros) - rust-lang/rust#152396 (Uplift `Predicate::allow_normalization` to `rustc_type_ir`)
This commit is contained in:
commit
d00ba92259
63 changed files with 1923 additions and 1435 deletions
|
|
@ -3687,7 +3687,6 @@ dependencies = [
|
|||
"serde_json",
|
||||
"smallvec",
|
||||
"tempfile",
|
||||
"thin-vec",
|
||||
"thorin-dwp",
|
||||
"tracing",
|
||||
"wasm-encoder 0.219.2",
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
|
|||
|
||||
pub(crate) struct UnstableFeatureBoundParser;
|
||||
impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
|
||||
const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::unstable_feature_bound];
|
||||
type Item = (Symbol, Span);
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use super::prelude::*;
|
|||
pub(crate) struct InlineParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||
const PATH: &'static [Symbol] = &[sym::inline];
|
||||
const PATH: &[Symbol] = &[sym::inline];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
|
|
@ -67,7 +67,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
|||
pub(crate) struct RustcForceInlineParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
|
||||
const PATH: &[Symbol] = &[sym::rustc_force_inline];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ fn parse_alignment(node: &LitKind) -> Result<Align, &'static str> {
|
|||
pub(crate) struct AlignParser(Option<(Align, Span)>);
|
||||
|
||||
impl AlignParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_align];
|
||||
const PATH: &[Symbol] = &[sym::rustc_align];
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["<alignment in bytes>"]);
|
||||
|
||||
fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
|
||||
|
|
@ -329,7 +329,7 @@ impl<S: Stage> AttributeParser<S> for AlignParser {
|
|||
pub(crate) struct AlignStaticParser(AlignParser);
|
||||
|
||||
impl AlignStaticParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_align_static];
|
||||
const PATH: &[Symbol] = &[sym::rustc_align_static];
|
||||
const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE;
|
||||
|
||||
fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ use std::path::PathBuf;
|
|||
|
||||
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
|
||||
use rustc_hir::attrs::{
|
||||
BorrowckGraphvizFormatKind, RustcCleanAttribute, RustcCleanQueries, RustcLayoutType,
|
||||
BorrowckGraphvizFormatKind, CguFields, CguKind, DivergingBlockBehavior,
|
||||
DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcLayoutType,
|
||||
RustcMirKind,
|
||||
};
|
||||
use rustc_session::errors;
|
||||
|
|
@ -10,12 +11,14 @@ use rustc_span::Symbol;
|
|||
|
||||
use super::prelude::*;
|
||||
use super::util::parse_single_integer;
|
||||
use crate::session_diagnostics::{AttributeRequiresOpt, RustcScalableVectorCountOutOfRange};
|
||||
use crate::session_diagnostics::{
|
||||
AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange,
|
||||
};
|
||||
|
||||
pub(crate) struct RustcMainParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_main];
|
||||
const PATH: &[Symbol] = &[sym::rustc_main];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
|
||||
|
|
@ -100,7 +103,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitAutorefsParser {
|
|||
pub(crate) struct RustcLayoutScalarValidRangeStartParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStartParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
|
||||
const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
|
|
@ -115,7 +118,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStartPars
|
|||
pub(crate) struct RustcLayoutScalarValidRangeEndParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEndParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
|
||||
const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
|
|
@ -204,6 +207,325 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcLintOptTyParser {
|
|||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy;
|
||||
}
|
||||
|
||||
fn parse_cgu_fields<S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser,
|
||||
accepts_kind: bool,
|
||||
) -> Option<(Symbol, Symbol, Option<CguKind>)> {
|
||||
let Some(args) = args.list() else {
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut cfg = None::<(Symbol, Span)>;
|
||||
let mut module = None::<(Symbol, Span)>;
|
||||
let mut kind = None::<(Symbol, Span)>;
|
||||
|
||||
for arg in args.mixed() {
|
||||
let Some(arg) = arg.meta_item() else {
|
||||
cx.expected_name_value(args.span, None);
|
||||
continue;
|
||||
};
|
||||
|
||||
let res = match arg.ident().map(|i| i.name) {
|
||||
Some(sym::cfg) => &mut cfg,
|
||||
Some(sym::module) => &mut module,
|
||||
Some(sym::kind) if accepts_kind => &mut kind,
|
||||
_ => {
|
||||
cx.expected_specific_argument(
|
||||
arg.path().span(),
|
||||
if accepts_kind {
|
||||
&[sym::cfg, sym::module, sym::kind]
|
||||
} else {
|
||||
&[sym::cfg, sym::module]
|
||||
},
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let Some(i) = arg.args().name_value() else {
|
||||
cx.expected_name_value(arg.span(), None);
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(str) = i.value_as_str() else {
|
||||
cx.expected_string_literal(i.value_span, Some(i.value_as_lit()));
|
||||
continue;
|
||||
};
|
||||
|
||||
if res.is_some() {
|
||||
cx.duplicate_key(arg.span(), arg.ident().unwrap().name);
|
||||
continue;
|
||||
}
|
||||
|
||||
*res = Some((str, i.value_span));
|
||||
}
|
||||
|
||||
let Some((cfg, _)) = cfg else {
|
||||
cx.emit_err(CguFieldsMissing { span: args.span, name: &cx.attr_path, field: sym::cfg });
|
||||
return None;
|
||||
};
|
||||
let Some((module, _)) = module else {
|
||||
cx.emit_err(CguFieldsMissing { span: args.span, name: &cx.attr_path, field: sym::module });
|
||||
return None;
|
||||
};
|
||||
let kind = if let Some((kind, span)) = kind {
|
||||
Some(match kind {
|
||||
sym::no => CguKind::No,
|
||||
sym::pre_dash_lto => CguKind::PreDashLto,
|
||||
sym::post_dash_lto => CguKind::PostDashLto,
|
||||
sym::any => CguKind::Any,
|
||||
_ => {
|
||||
cx.expected_specific_argument_strings(
|
||||
span,
|
||||
&[sym::no, sym::pre_dash_lto, sym::post_dash_lto, sym::any],
|
||||
);
|
||||
return None;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// return None so that an unwrap for the attributes that need it is ok.
|
||||
if accepts_kind {
|
||||
cx.emit_err(CguFieldsMissing {
|
||||
span: args.span,
|
||||
name: &cx.attr_path,
|
||||
field: sym::kind,
|
||||
});
|
||||
return None;
|
||||
};
|
||||
|
||||
None
|
||||
};
|
||||
|
||||
Some((cfg, module, kind))
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct RustcCguTestAttributeParser {
|
||||
items: ThinVec<(Span, CguFields)>,
|
||||
}
|
||||
|
||||
impl<S: Stage> AttributeParser<S> for RustcCguTestAttributeParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[
|
||||
(
|
||||
&[sym::rustc_partition_reused],
|
||||
template!(List: &[r#"cfg = "...", module = "...""#]),
|
||||
|this, cx, args| {
|
||||
this.items.extend(parse_cgu_fields(cx, args, false).map(|(cfg, module, _)| {
|
||||
(cx.attr_span, CguFields::PartitionReused { cfg, module })
|
||||
}));
|
||||
},
|
||||
),
|
||||
(
|
||||
&[sym::rustc_partition_codegened],
|
||||
template!(List: &[r#"cfg = "...", module = "...""#]),
|
||||
|this, cx, args| {
|
||||
this.items.extend(parse_cgu_fields(cx, args, false).map(|(cfg, module, _)| {
|
||||
(cx.attr_span, CguFields::PartitionCodegened { cfg, module })
|
||||
}));
|
||||
},
|
||||
),
|
||||
(
|
||||
&[sym::rustc_expected_cgu_reuse],
|
||||
template!(List: &[r#"cfg = "...", module = "...", kind = "...""#]),
|
||||
|this, cx, args| {
|
||||
this.items.extend(parse_cgu_fields(cx, args, true).map(|(cfg, module, kind)| {
|
||||
// unwrap ok because if not given, we return None in `parse_cgu_fields`.
|
||||
(cx.attr_span, CguFields::ExpectedCguReuse { cfg, module, kind: kind.unwrap() })
|
||||
}));
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]);
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
Some(AttributeKind::RustcCguTestAttr(self.items))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcDeprecatedSafe2024Parser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcDeprecatedSafe2024Parser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_deprecated_safe_2024];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &[r#"audit_that = "...""#]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(args) = args.list() else {
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(single) = args.single() else {
|
||||
cx.expected_single_argument(args.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(arg) = single.meta_item() else {
|
||||
cx.expected_name_value(args.span, None);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(args) = arg.word_is(sym::audit_that) else {
|
||||
cx.expected_specific_argument(arg.span(), &[sym::audit_that]);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(nv) = args.name_value() else {
|
||||
cx.expected_name_value(arg.span(), Some(sym::audit_that));
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(suggestion) = nv.value_as_str() else {
|
||||
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(AttributeKind::RustcDeprecatedSafe2024 { suggestion })
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcConversionSuggestionParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcConversionSuggestionParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_conversion_suggestion];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConversionSuggestion;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcCaptureAnalysisParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcCaptureAnalysisParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_capture_analysis];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]);
|
||||
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 RustcTrivialFieldReadsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcTrivialFieldReadsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_trivial_field_reads];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcTrivialFieldReads;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcNoMirInlineParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNoMirInlineParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_no_mir_inline];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoMirInline;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcLintQueryInstabilityParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintQueryInstabilityParser {
|
||||
|
|
@ -253,21 +575,11 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcLintUntrackedQueryInformationPa
|
|||
|
||||
pub(crate) struct RustcObjectLifetimeDefaultParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser {
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcObjectLifetimeDefaultParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_object_lifetime_default];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
if let Err(span) = args.no_args() {
|
||||
cx.expected_no_args(span);
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(AttributeKind::RustcObjectLifetimeDefault)
|
||||
}
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcObjectLifetimeDefault;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;
|
||||
|
|
@ -510,7 +822,7 @@ impl<S: Stage> CombineAttributeParser<S> for RustcMirParser {
|
|||
pub(crate) struct RustcNonConstTraitMethodParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNonConstTraitMethodParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_non_const_trait_method];
|
||||
const PATH: &[Symbol] = &[sym::rustc_non_const_trait_method];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
|
|
@ -755,7 +1067,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcInsignificantDtorParser {
|
|||
pub(crate) struct RustcEffectiveVisibilityParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcEffectiveVisibilityParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_effective_visibility];
|
||||
const PATH: &[Symbol] = &[sym::rustc_effective_visibility];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Use),
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ attribute_parsers!(
|
|||
DocParser,
|
||||
MacroUseParser,
|
||||
NakedParser,
|
||||
RustcCguTestAttributeParser,
|
||||
StabilityParser,
|
||||
UsedParser,
|
||||
// tidy-alphabetical-end
|
||||
|
|
@ -201,6 +202,7 @@ attribute_parsers!(
|
|||
Single<RustcAllocatorZeroedVariantParser>,
|
||||
Single<RustcBuiltinMacroParser>,
|
||||
Single<RustcDefPath>,
|
||||
Single<RustcDeprecatedSafe2024Parser>,
|
||||
Single<RustcForceInlineParser>,
|
||||
Single<RustcIfThisChangedParser>,
|
||||
Single<RustcLayoutScalarValidRangeEndParser>,
|
||||
|
|
@ -208,7 +210,7 @@ attribute_parsers!(
|
|||
Single<RustcLegacyConstGenericsParser>,
|
||||
Single<RustcLintOptDenyFieldAccessParser>,
|
||||
Single<RustcMustImplementOneOfParser>,
|
||||
Single<RustcObjectLifetimeDefaultParser>,
|
||||
Single<RustcNeverTypeOptionsParser>,
|
||||
Single<RustcReservationImplParser>,
|
||||
Single<RustcScalableVectorParser>,
|
||||
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
||||
|
|
@ -261,7 +263,9 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<PubTransparentParser>>,
|
||||
Single<WithoutArgs<RustcAllocatorParser>>,
|
||||
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
|
||||
Single<WithoutArgs<RustcCaptureAnalysisParser>>,
|
||||
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
|
||||
Single<WithoutArgs<RustcConversionSuggestionParser>>,
|
||||
Single<WithoutArgs<RustcDeallocatorParser>>,
|
||||
Single<WithoutArgs<RustcDelayedBugFromInsideQueryParser>>,
|
||||
Single<WithoutArgs<RustcDumpDefParentsParser>>,
|
||||
|
|
@ -283,8 +287,10 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
|
||||
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
|
||||
Single<WithoutArgs<RustcNoImplicitBoundsParser>>,
|
||||
Single<WithoutArgs<RustcNoMirInlineParser>>,
|
||||
Single<WithoutArgs<RustcNonConstTraitMethodParser>>,
|
||||
Single<WithoutArgs<RustcNounwindParser>>,
|
||||
Single<WithoutArgs<RustcObjectLifetimeDefaultParser>>,
|
||||
Single<WithoutArgs<RustcOffloadKernelParser>>,
|
||||
Single<WithoutArgs<RustcOutlivesParser>>,
|
||||
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
|
||||
|
|
@ -293,6 +299,7 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<RustcRegionsParser>>,
|
||||
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
|
||||
Single<WithoutArgs<RustcStrictCoherenceParser>>,
|
||||
Single<WithoutArgs<RustcTrivialFieldReadsParser>>,
|
||||
Single<WithoutArgs<RustcVarianceOfOpaquesParser>>,
|
||||
Single<WithoutArgs<RustcVarianceParser>>,
|
||||
Single<WithoutArgs<SpecializationTraitParser>>,
|
||||
|
|
|
|||
|
|
@ -45,6 +45,15 @@ pub(crate) struct DocAliasStartEnd<'a> {
|
|||
pub attr_str: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[{$name})]` is missing a `{$field}` argument")]
|
||||
pub(crate) struct CguFieldsMissing<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: &'a AttrPath,
|
||||
pub field: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#![doc({$attr_name} = \"...\")]` isn't allowed as a crate-level attribute")]
|
||||
pub(crate) struct DocAttrNotCrateLevel {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ rustc_trait_selection = { path = "../rustc_trait_selection" }
|
|||
serde_json = "1.0.59"
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
tempfile = "3.2"
|
||||
thin-vec = "0.2.12"
|
||||
thorin-dwp = "0.9"
|
||||
tracing = "0.1"
|
||||
wasm-encoder = "0.219"
|
||||
|
|
|
|||
|
|
@ -28,13 +28,13 @@ use std::fmt;
|
|||
|
||||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_errors::{DiagArgValue, IntoDiagArg};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::{AttributeKind, CguFields, CguKind};
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_hir::{self as hir, find_attr};
|
||||
use rustc_middle::mir::mono::CodegenUnitNameBuilder;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::errors;
|
||||
|
|
@ -63,9 +63,7 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&mut CguReuseTr
|
|||
},
|
||||
};
|
||||
|
||||
for attr in tcx.hir_attrs(rustc_hir::CRATE_HIR_ID) {
|
||||
ams.check_attr(attr);
|
||||
}
|
||||
ams.check_attrs(tcx.hir_attrs(rustc_hir::CRATE_HIR_ID));
|
||||
|
||||
set_reuse(&mut ams.cgu_reuse_tracker);
|
||||
|
||||
|
|
@ -89,109 +87,91 @@ struct AssertModuleSource<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> AssertModuleSource<'tcx> {
|
||||
fn check_attr(&mut self, attr: &hir::Attribute) {
|
||||
let (expected_reuse, comp_kind) = if attr.has_name(sym::rustc_partition_reused) {
|
||||
(CguReuse::PreLto, ComparisonKind::AtLeast)
|
||||
} else if attr.has_name(sym::rustc_partition_codegened) {
|
||||
(CguReuse::No, ComparisonKind::Exact)
|
||||
} else if attr.has_name(sym::rustc_expected_cgu_reuse) {
|
||||
match self.field(attr, sym::kind) {
|
||||
sym::no => (CguReuse::No, ComparisonKind::Exact),
|
||||
sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact),
|
||||
sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact),
|
||||
sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
|
||||
other => {
|
||||
self.tcx
|
||||
.dcx()
|
||||
.emit_fatal(errors::UnknownReuseKind { span: attr.span(), kind: other });
|
||||
}
|
||||
fn check_attrs(&mut self, attrs: &[hir::Attribute]) {
|
||||
for &(span, cgu_fields) in find_attr!(attrs,
|
||||
AttributeKind::RustcCguTestAttr(e) => e)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
let (expected_reuse, comp_kind) = match cgu_fields {
|
||||
CguFields::PartitionReused { .. } => (CguReuse::PreLto, ComparisonKind::AtLeast),
|
||||
CguFields::PartitionCodegened { .. } => (CguReuse::No, ComparisonKind::Exact),
|
||||
CguFields::ExpectedCguReuse { kind, .. } => match kind {
|
||||
CguKind::No => (CguReuse::No, ComparisonKind::Exact),
|
||||
CguKind::PreDashLto => (CguReuse::PreLto, ComparisonKind::Exact),
|
||||
CguKind::PostDashLto => (CguReuse::PostLto, ComparisonKind::Exact),
|
||||
CguKind::Any => (CguReuse::PreLto, ComparisonKind::AtLeast),
|
||||
},
|
||||
};
|
||||
let (CguFields::ExpectedCguReuse { cfg, module, .. }
|
||||
| CguFields::PartitionCodegened { cfg, module }
|
||||
| CguFields::PartitionReused { cfg, module }) = cgu_fields;
|
||||
|
||||
if !self.tcx.sess.opts.unstable_opts.query_dep_graph {
|
||||
self.tcx.dcx().emit_fatal(errors::MissingQueryDepGraph { span });
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
if !self.tcx.sess.opts.unstable_opts.query_dep_graph {
|
||||
self.tcx.dcx().emit_fatal(errors::MissingQueryDepGraph { span: attr.span() });
|
||||
}
|
||||
if !self.check_config(cfg) {
|
||||
debug!("check_attr: config does not match, ignoring attr");
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.check_config(attr) {
|
||||
debug!("check_attr: config does not match, ignoring attr");
|
||||
return;
|
||||
}
|
||||
let user_path = module.as_str();
|
||||
let crate_name = self.tcx.crate_name(LOCAL_CRATE);
|
||||
let crate_name = crate_name.as_str();
|
||||
|
||||
let user_path = self.field(attr, sym::module).to_string();
|
||||
let crate_name = self.tcx.crate_name(LOCAL_CRATE).to_string();
|
||||
if !user_path.starts_with(&crate_name) {
|
||||
self.tcx.dcx().emit_fatal(errors::MalformedCguName { span, user_path, crate_name });
|
||||
}
|
||||
|
||||
if !user_path.starts_with(&crate_name) {
|
||||
self.tcx.dcx().emit_fatal(errors::MalformedCguName {
|
||||
span: attr.span(),
|
||||
user_path,
|
||||
crate_name,
|
||||
});
|
||||
}
|
||||
// Split of the "special suffix" if there is one.
|
||||
let (user_path, cgu_special_suffix) = if let Some(index) = user_path.rfind('.') {
|
||||
(&user_path[..index], Some(&user_path[index + 1..]))
|
||||
} else {
|
||||
(&user_path[..], None)
|
||||
};
|
||||
|
||||
// Split of the "special suffix" if there is one.
|
||||
let (user_path, cgu_special_suffix) = if let Some(index) = user_path.rfind('.') {
|
||||
(&user_path[..index], Some(&user_path[index + 1..]))
|
||||
} else {
|
||||
(&user_path[..], None)
|
||||
};
|
||||
let mut iter = user_path.split('-');
|
||||
|
||||
let mut iter = user_path.split('-');
|
||||
// Remove the crate name
|
||||
assert_eq!(iter.next().unwrap(), crate_name);
|
||||
|
||||
// Remove the crate name
|
||||
assert_eq!(iter.next().unwrap(), crate_name);
|
||||
let cgu_path_components = iter.collect::<Vec<_>>();
|
||||
|
||||
let cgu_path_components = iter.collect::<Vec<_>>();
|
||||
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(self.tcx);
|
||||
let cgu_name = cgu_name_builder.build_cgu_name(
|
||||
LOCAL_CRATE,
|
||||
cgu_path_components,
|
||||
cgu_special_suffix,
|
||||
);
|
||||
|
||||
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(self.tcx);
|
||||
let cgu_name =
|
||||
cgu_name_builder.build_cgu_name(LOCAL_CRATE, cgu_path_components, cgu_special_suffix);
|
||||
debug!("mapping '{user_path}' to cgu name '{cgu_name}'");
|
||||
|
||||
debug!("mapping '{}' to cgu name '{}'", self.field(attr, sym::module), cgu_name);
|
||||
if !self.available_cgus.contains(&cgu_name) {
|
||||
let cgu_names: Vec<&str> =
|
||||
self.available_cgus.items().map(|cgu| cgu.as_str()).into_sorted_stable_ord();
|
||||
self.tcx.dcx().emit_err(errors::NoModuleNamed {
|
||||
span,
|
||||
user_path,
|
||||
cgu_name,
|
||||
cgu_names: cgu_names.join(", "),
|
||||
});
|
||||
}
|
||||
|
||||
if !self.available_cgus.contains(&cgu_name) {
|
||||
let cgu_names: Vec<&str> =
|
||||
self.available_cgus.items().map(|cgu| cgu.as_str()).into_sorted_stable_ord();
|
||||
self.tcx.dcx().emit_err(errors::NoModuleNamed {
|
||||
span: attr.span(),
|
||||
user_path,
|
||||
self.cgu_reuse_tracker.set_expectation(
|
||||
cgu_name,
|
||||
cgu_names: cgu_names.join(", "),
|
||||
});
|
||||
user_path,
|
||||
span,
|
||||
expected_reuse,
|
||||
comp_kind,
|
||||
);
|
||||
}
|
||||
|
||||
self.cgu_reuse_tracker.set_expectation(
|
||||
cgu_name,
|
||||
user_path,
|
||||
attr.span(),
|
||||
expected_reuse,
|
||||
comp_kind,
|
||||
);
|
||||
}
|
||||
|
||||
fn field(&self, attr: &hir::Attribute, name: Symbol) -> Symbol {
|
||||
for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) {
|
||||
if item.has_name(name) {
|
||||
if let Some(value) = item.value_str() {
|
||||
return value;
|
||||
} else {
|
||||
self.tcx.dcx().emit_fatal(errors::FieldAssociatedValueExpected {
|
||||
span: item.span(),
|
||||
name,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.tcx.dcx().emit_fatal(errors::NoField { span: attr.span(), name });
|
||||
}
|
||||
|
||||
/// Scan for a `cfg="foo"` attribute and check whether we have a
|
||||
/// cfg flag called `foo`.
|
||||
fn check_config(&self, attr: &hir::Attribute) -> bool {
|
||||
fn check_config(&self, value: Symbol) -> bool {
|
||||
let config = &self.tcx.sess.psess.config;
|
||||
let value = self.field(attr, sym::cfg);
|
||||
debug!("check_config(config={:?}, value={:?})", config, value);
|
||||
if config.iter().any(|&(name, _)| name == value) {
|
||||
debug!("check_config: matched");
|
||||
|
|
|
|||
|
|
@ -42,14 +42,6 @@ pub(crate) struct CguNotRecorded<'a> {
|
|||
pub cgu_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unknown cgu-reuse-kind `{$kind}` specified")]
|
||||
pub(crate) struct UnknownReuseKind {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub kind: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("found CGU-reuse attribute but `-Zquery-dep-graph` was not specified")]
|
||||
pub(crate) struct MissingQueryDepGraph {
|
||||
|
|
@ -61,11 +53,11 @@ pub(crate) struct MissingQueryDepGraph {
|
|||
#[diag(
|
||||
"found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case)"
|
||||
)]
|
||||
pub(crate) struct MalformedCguName {
|
||||
pub(crate) struct MalformedCguName<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub user_path: String,
|
||||
pub crate_name: String,
|
||||
pub user_path: &'a str,
|
||||
pub crate_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -78,22 +70,6 @@ pub(crate) struct NoModuleNamed<'a> {
|
|||
pub cgu_names: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("associated value expected for `{$name}`")]
|
||||
pub(crate) struct FieldAssociatedValueExpected {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("no field `{$name}`")]
|
||||
pub(crate) struct NoField {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("failed to write lib.def file: {$error}")]
|
||||
pub(crate) struct LibDefWriteFailure {
|
||||
|
|
|
|||
|
|
@ -230,38 +230,6 @@ pub fn fallback_fluent_bundle(
|
|||
})))
|
||||
}
|
||||
|
||||
/// Abstraction over a message in a subdiagnostic (i.e. label, note, help, etc) to support both
|
||||
/// translatable and non-translatable diagnostic messages.
|
||||
///
|
||||
/// Translatable messages for subdiagnostics are typically attributes attached to a larger Fluent
|
||||
/// message so messages of this type must be combined with a `DiagMessage` (using
|
||||
/// `DiagMessage::with_subdiagnostic_message`) before rendering. However, subdiagnostics from
|
||||
/// the `Subdiagnostic` derive refer to Fluent identifiers directly.
|
||||
#[rustc_diagnostic_item = "SubdiagMessage"]
|
||||
pub enum SubdiagMessage {
|
||||
/// Non-translatable diagnostic message.
|
||||
Str(Cow<'static, str>),
|
||||
/// An inline Fluent message. Instances of this variant are generated by the
|
||||
/// `Subdiagnostic` derive.
|
||||
Inline(Cow<'static, str>),
|
||||
}
|
||||
|
||||
impl From<String> for SubdiagMessage {
|
||||
fn from(s: String) -> Self {
|
||||
SubdiagMessage::Str(Cow::Owned(s))
|
||||
}
|
||||
}
|
||||
impl From<&'static str> for SubdiagMessage {
|
||||
fn from(s: &'static str) -> Self {
|
||||
SubdiagMessage::Str(Cow::Borrowed(s))
|
||||
}
|
||||
}
|
||||
impl From<Cow<'static, str>> for SubdiagMessage {
|
||||
fn from(s: Cow<'static, str>) -> Self {
|
||||
SubdiagMessage::Str(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// Abstraction over a message in a diagnostic to support both translatable and non-translatable
|
||||
/// diagnostic messages.
|
||||
///
|
||||
|
|
@ -281,18 +249,6 @@ pub enum DiagMessage {
|
|||
}
|
||||
|
||||
impl DiagMessage {
|
||||
/// Given a `SubdiagMessage` which may contain a Fluent attribute, create a new
|
||||
/// `DiagMessage` that combines that attribute with the Fluent identifier of `self`.
|
||||
///
|
||||
/// - If the `SubdiagMessage` is non-translatable then return the message as a `DiagMessage`.
|
||||
/// - If `self` is non-translatable then return `self`'s message.
|
||||
pub fn with_subdiagnostic_message(&self, sub: SubdiagMessage) -> Self {
|
||||
match sub {
|
||||
SubdiagMessage::Str(s) => DiagMessage::Str(s),
|
||||
SubdiagMessage::Inline(s) => DiagMessage::Inline(s),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> Option<&str> {
|
||||
match self {
|
||||
DiagMessage::Str(s) => Some(s),
|
||||
|
|
@ -317,20 +273,6 @@ impl From<Cow<'static, str>> for DiagMessage {
|
|||
}
|
||||
}
|
||||
|
||||
/// Translating *into* a subdiagnostic message from a diagnostic message is a little strange - but
|
||||
/// the subdiagnostic functions (e.g. `span_label`) take a `SubdiagMessage` and the
|
||||
/// subdiagnostic derive refers to typed identifiers that are `DiagMessage`s, so need to be
|
||||
/// able to convert between these, as much as they'll be converted back into `DiagMessage`
|
||||
/// using `with_subdiagnostic_message` eventually. Don't use this other than for the derive.
|
||||
impl From<DiagMessage> for SubdiagMessage {
|
||||
fn from(val: DiagMessage) -> Self {
|
||||
match val {
|
||||
DiagMessage::Str(s) => SubdiagMessage::Str(s),
|
||||
DiagMessage::Inline(s) => SubdiagMessage::Inline(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A span together with some additional data.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SpanLabel {
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@ use tracing::debug;
|
|||
|
||||
use crate::{
|
||||
CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
|
||||
MultiSpan, StashKey, Style, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle,
|
||||
Suggestions,
|
||||
MultiSpan, StashKey, Style, Substitution, SubstitutionPart, SuggestionStyle, Suggestions,
|
||||
};
|
||||
|
||||
pub type DiagArgMap = FxIndexMap<DiagArgName, DiagArgValue>;
|
||||
|
|
@ -325,30 +324,8 @@ impl DiagInner {
|
|||
}
|
||||
}
|
||||
|
||||
// See comment on `Diag::subdiagnostic_message_to_diagnostic_message`.
|
||||
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
|
||||
&self,
|
||||
attr: impl Into<SubdiagMessage>,
|
||||
) -> DiagMessage {
|
||||
let msg =
|
||||
self.messages.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages");
|
||||
msg.with_subdiagnostic_message(attr.into())
|
||||
}
|
||||
|
||||
pub(crate) fn sub(
|
||||
&mut self,
|
||||
level: Level,
|
||||
message: impl Into<SubdiagMessage>,
|
||||
span: MultiSpan,
|
||||
) {
|
||||
let sub = Subdiag {
|
||||
level,
|
||||
messages: vec![(
|
||||
self.subdiagnostic_message_to_diagnostic_message(message),
|
||||
Style::NoStyle,
|
||||
)],
|
||||
span,
|
||||
};
|
||||
pub(crate) fn sub(&mut self, level: Level, message: impl Into<DiagMessage>, span: MultiSpan) {
|
||||
let sub = Subdiag { level, messages: vec![(message.into(), Style::NoStyle)], span };
|
||||
self.children.push(sub);
|
||||
}
|
||||
|
||||
|
|
@ -609,9 +586,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
/// the diagnostic was constructed. However, the label span is *not* considered a
|
||||
/// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
|
||||
/// primary.
|
||||
pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagMessage>) -> &mut Self {
|
||||
let msg = self.subdiagnostic_message_to_diagnostic_message(label);
|
||||
self.span.push_span_label(span, msg);
|
||||
pub fn span_label(&mut self, span: Span, label: impl Into<DiagMessage>) -> &mut Self {
|
||||
self.span.push_span_label(span, label.into());
|
||||
self
|
||||
} }
|
||||
|
||||
|
|
@ -713,7 +689,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
|
||||
with_fn! { with_note,
|
||||
/// Add a note attached to this diagnostic.
|
||||
pub fn note(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
|
||||
pub fn note(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
|
||||
self.sub(Level::Note, msg, MultiSpan::new());
|
||||
self
|
||||
} }
|
||||
|
|
@ -733,7 +709,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
}
|
||||
|
||||
/// This is like [`Diag::note()`], but it's only printed once.
|
||||
pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
|
||||
pub fn note_once(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
|
||||
self.sub(Level::OnceNote, msg, MultiSpan::new());
|
||||
self
|
||||
}
|
||||
|
|
@ -744,7 +720,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
pub fn span_note(
|
||||
&mut self,
|
||||
sp: impl Into<MultiSpan>,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
) -> &mut Self {
|
||||
self.sub(Level::Note, msg, sp.into());
|
||||
self
|
||||
|
|
@ -755,7 +731,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
pub fn span_note_once<S: Into<MultiSpan>>(
|
||||
&mut self,
|
||||
sp: S,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
) -> &mut Self {
|
||||
self.sub(Level::OnceNote, msg, sp.into());
|
||||
self
|
||||
|
|
@ -763,7 +739,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
|
||||
with_fn! { with_warn,
|
||||
/// Add a warning attached to this diagnostic.
|
||||
pub fn warn(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
|
||||
pub fn warn(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
|
||||
self.sub(Level::Warning, msg, MultiSpan::new());
|
||||
self
|
||||
} }
|
||||
|
|
@ -773,7 +749,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
pub fn span_warn<S: Into<MultiSpan>>(
|
||||
&mut self,
|
||||
sp: S,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
) -> &mut Self {
|
||||
self.sub(Level::Warning, msg, sp.into());
|
||||
self
|
||||
|
|
@ -781,13 +757,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
|
||||
with_fn! { with_help,
|
||||
/// Add a help message attached to this diagnostic.
|
||||
pub fn help(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
|
||||
pub fn help(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
|
||||
self.sub(Level::Help, msg, MultiSpan::new());
|
||||
self
|
||||
} }
|
||||
|
||||
/// This is like [`Diag::help()`], but it's only printed once.
|
||||
pub fn help_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
|
||||
pub fn help_once(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
|
||||
self.sub(Level::OnceHelp, msg, MultiSpan::new());
|
||||
self
|
||||
}
|
||||
|
|
@ -814,7 +790,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
pub fn span_help(
|
||||
&mut self,
|
||||
sp: impl Into<MultiSpan>,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
) -> &mut Self {
|
||||
self.sub(Level::Help, msg, sp.into());
|
||||
self
|
||||
|
|
@ -866,7 +842,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
/// In other words, multiple changes need to be applied as part of this suggestion.
|
||||
pub fn multipart_suggestion(
|
||||
&mut self,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
|
@ -882,7 +858,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
/// In other words, multiple changes need to be applied as part of this suggestion.
|
||||
pub fn multipart_suggestion_verbose(
|
||||
&mut self,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
|
@ -897,7 +873,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
/// [`Diag::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
|
||||
pub fn multipart_suggestion_with_style(
|
||||
&mut self,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
mut suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
style: SuggestionStyle,
|
||||
|
|
@ -924,7 +900,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
|
||||
self.push_suggestion(CodeSuggestion {
|
||||
substitutions: vec![Substitution { parts }],
|
||||
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
|
||||
msg: msg.into(),
|
||||
style,
|
||||
applicability,
|
||||
});
|
||||
|
|
@ -939,7 +915,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
/// improve understandability.
|
||||
pub fn tool_only_multipart_suggestion(
|
||||
&mut self,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
|
@ -972,7 +948,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
pub fn span_suggestion(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
suggestion: impl ToString,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
|
@ -990,7 +966,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
pub fn span_suggestion_with_style(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
suggestion: impl ToString,
|
||||
applicability: Applicability,
|
||||
style: SuggestionStyle,
|
||||
|
|
@ -1003,7 +979,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
substitutions: vec![Substitution {
|
||||
parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
|
||||
}],
|
||||
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
|
||||
msg: msg.into(),
|
||||
style,
|
||||
applicability,
|
||||
});
|
||||
|
|
@ -1015,7 +991,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
pub fn span_suggestion_verbose(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
suggestion: impl ToString,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
|
@ -1035,7 +1011,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
pub fn span_suggestions(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
suggestions: impl IntoIterator<Item = String>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
|
@ -1051,7 +1027,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
pub fn span_suggestions_with_style(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
suggestions: impl IntoIterator<Item = String>,
|
||||
applicability: Applicability,
|
||||
style: SuggestionStyle,
|
||||
|
|
@ -1068,7 +1044,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
.collect();
|
||||
self.push_suggestion(CodeSuggestion {
|
||||
substitutions,
|
||||
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
|
||||
msg: msg.into(),
|
||||
style,
|
||||
applicability,
|
||||
});
|
||||
|
|
@ -1080,7 +1056,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
/// See also [`Diag::multipart_suggestion()`].
|
||||
pub fn multipart_suggestions(
|
||||
&mut self,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
suggestions: impl IntoIterator<Item = Vec<(Span, String)>>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
|
@ -1112,7 +1088,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
|
||||
self.push_suggestion(CodeSuggestion {
|
||||
substitutions,
|
||||
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
|
||||
msg: msg.into(),
|
||||
style: SuggestionStyle::ShowAlways,
|
||||
applicability,
|
||||
});
|
||||
|
|
@ -1127,7 +1103,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
pub fn span_suggestion_short(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
suggestion: impl ToString,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
|
@ -1150,7 +1126,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
pub fn span_suggestion_hidden(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
suggestion: impl ToString,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
|
@ -1172,7 +1148,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
pub fn tool_only_span_suggestion(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
suggestion: impl ToString,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
|
@ -1200,10 +1176,9 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
/// one value will clobber the other. Eagerly translating the
|
||||
/// diagnostic uses the variables defined right then, before the
|
||||
/// clobbering occurs.
|
||||
pub fn eagerly_translate(&self, msg: impl Into<SubdiagMessage>) -> SubdiagMessage {
|
||||
pub fn eagerly_translate(&self, msg: impl Into<DiagMessage>) -> DiagMessage {
|
||||
let args = self.args.iter();
|
||||
let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into());
|
||||
self.dcx.eagerly_translate(msg, args)
|
||||
self.dcx.eagerly_translate(msg.into(), args)
|
||||
}
|
||||
|
||||
with_fn! { with_span,
|
||||
|
|
@ -1256,31 +1231,18 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
self
|
||||
} }
|
||||
|
||||
/// Helper function that takes a `SubdiagMessage` and returns a `DiagMessage` by
|
||||
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just
|
||||
/// passes the user's string along).
|
||||
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
|
||||
&self,
|
||||
attr: impl Into<SubdiagMessage>,
|
||||
) -> DiagMessage {
|
||||
self.deref().subdiagnostic_message_to_diagnostic_message(attr)
|
||||
}
|
||||
|
||||
/// Convenience function for internal use, clients should use one of the
|
||||
/// public methods above.
|
||||
///
|
||||
/// Used by `proc_macro_server` for implementing `server::Diagnostic`.
|
||||
pub fn sub(&mut self, level: Level, message: impl Into<SubdiagMessage>, span: MultiSpan) {
|
||||
pub fn sub(&mut self, level: Level, message: impl Into<DiagMessage>, span: MultiSpan) {
|
||||
self.deref_mut().sub(level, message, span);
|
||||
}
|
||||
|
||||
/// Convenience function for internal use, clients should use one of the
|
||||
/// public methods above.
|
||||
fn sub_with_highlights(&mut self, level: Level, messages: Vec<StringPart>, span: MultiSpan) {
|
||||
let messages = messages
|
||||
.into_iter()
|
||||
.map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.content), m.style))
|
||||
.collect();
|
||||
let messages = messages.into_iter().map(|m| (m.content.into(), m.style)).collect();
|
||||
let sub = Subdiag { level, messages, span };
|
||||
self.children.push(sub);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ use rustc_data_structures::sync::{DynSend, Lock};
|
|||
use rustc_data_structures::{AtomicRef, assert_matches};
|
||||
pub use rustc_error_messages::{
|
||||
DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, FluentBundle, IntoDiagArg,
|
||||
LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage,
|
||||
fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display,
|
||||
LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, fallback_fluent_bundle,
|
||||
fluent_bundle, into_diag_arg_using_display,
|
||||
};
|
||||
use rustc_hashes::Hash128;
|
||||
use rustc_lint_defs::LintExpectationId;
|
||||
|
|
@ -488,12 +488,12 @@ impl DiagCtxt {
|
|||
self.inner.borrow_mut().emitter = emitter;
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`.
|
||||
/// Translate `message` eagerly with `args` to `DiagMessage::Eager`.
|
||||
pub fn eagerly_translate<'a>(
|
||||
&self,
|
||||
message: DiagMessage,
|
||||
args: impl Iterator<Item = DiagArg<'a>>,
|
||||
) -> SubdiagMessage {
|
||||
) -> DiagMessage {
|
||||
let inner = self.inner.borrow();
|
||||
inner.eagerly_translate(message, args)
|
||||
}
|
||||
|
|
@ -1423,13 +1423,13 @@ impl DiagCtxtInner {
|
|||
self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`.
|
||||
/// Translate `message` eagerly with `args` to `DiagMessage::Eager`.
|
||||
fn eagerly_translate<'a>(
|
||||
&self,
|
||||
message: DiagMessage,
|
||||
args: impl Iterator<Item = DiagArg<'a>>,
|
||||
) -> SubdiagMessage {
|
||||
SubdiagMessage::Str(Cow::from(self.eagerly_translate_to_string(message, args)))
|
||||
) -> DiagMessage {
|
||||
DiagMessage::Str(Cow::from(self.eagerly_translate_to_string(message, args)))
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args` to `String`.
|
||||
|
|
@ -1450,10 +1450,9 @@ impl DiagCtxtInner {
|
|||
fn eagerly_translate_for_subdiag(
|
||||
&self,
|
||||
diag: &DiagInner,
|
||||
msg: impl Into<SubdiagMessage>,
|
||||
) -> SubdiagMessage {
|
||||
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
|
||||
self.eagerly_translate(msg, diag.args.iter())
|
||||
msg: impl Into<DiagMessage>,
|
||||
) -> DiagMessage {
|
||||
self.eagerly_translate(msg.into(), diag.args.iter())
|
||||
}
|
||||
|
||||
fn flush_delayed(&mut self) {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,57 @@ pub struct EiiDecl {
|
|||
pub name: Ident,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
|
||||
pub enum CguKind {
|
||||
No,
|
||||
PreDashLto,
|
||||
PostDashLto,
|
||||
Any,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
|
||||
pub enum CguFields {
|
||||
PartitionReused { cfg: Symbol, module: Symbol },
|
||||
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,
|
||||
|
|
@ -1053,6 +1104,12 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_builtin_macro]`.
|
||||
RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span },
|
||||
|
||||
/// 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>),
|
||||
|
||||
|
|
@ -1078,6 +1135,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_const_stable_indirect]`.
|
||||
RustcConstStabilityIndirect,
|
||||
|
||||
/// Represents `#[rustc_conversion_suggestion]`
|
||||
RustcConversionSuggestion,
|
||||
|
||||
/// Represents `#[rustc_deallocator]`
|
||||
RustcDeallocator,
|
||||
|
||||
|
|
@ -1090,6 +1150,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_deny_explicit_impl]`.
|
||||
RustcDenyExplicitImpl(Span),
|
||||
|
||||
/// Represents `#[rustc_deprecated_safe_2024]`
|
||||
RustcDeprecatedSafe2024 { suggestion: Symbol },
|
||||
|
||||
/// Represents `#[rustc_dummy]`.
|
||||
RustcDummy,
|
||||
|
||||
|
|
@ -1174,12 +1237,21 @@ 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,
|
||||
|
||||
/// Represents `#[rustc_no_implicit_bounds]`
|
||||
RustcNoImplicitBounds,
|
||||
|
||||
/// Represents `#[rustc_no_mir_inline]`
|
||||
RustcNoMirInline,
|
||||
|
||||
/// Represents `#[rustc_non_const_trait_method]`.
|
||||
RustcNonConstTraitMethod,
|
||||
|
||||
|
|
@ -1257,6 +1329,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_then_this_would_need]`
|
||||
RustcThenThisWouldNeed(Span, ThinVec<Ident>),
|
||||
|
||||
/// Represents `#[rustc_trivial_field_reads]`
|
||||
RustcTrivialFieldReads,
|
||||
|
||||
/// Represents `#[rustc_unsafe_specialization_marker]`.
|
||||
RustcUnsafeSpecializationMarker(Span),
|
||||
|
||||
|
|
|
|||
|
|
@ -98,16 +98,20 @@ impl AttributeKind {
|
|||
RustcAsPtr(..) => Yes,
|
||||
RustcBodyStability { .. } => No,
|
||||
RustcBuiltinMacro { .. } => Yes,
|
||||
RustcCaptureAnalysis => No,
|
||||
RustcCguTestAttr { .. } => No,
|
||||
RustcClean { .. } => No,
|
||||
RustcCoherenceIsCore(..) => No,
|
||||
RustcCoinductive(..) => No,
|
||||
RustcConfusables { .. } => Yes,
|
||||
RustcConstStability { .. } => Yes,
|
||||
RustcConstStabilityIndirect => No,
|
||||
RustcConversionSuggestion => Yes,
|
||||
RustcDeallocator => No,
|
||||
RustcDefPath(..) => No,
|
||||
RustcDelayedBugFromInsideQuery => No,
|
||||
RustcDenyExplicitImpl(..) => No,
|
||||
RustcDeprecatedSafe2024 { .. } => Yes,
|
||||
RustcDummy => No,
|
||||
RustcDumpDefParents => No,
|
||||
RustcDumpItemBounds => No,
|
||||
|
|
@ -136,8 +140,10 @@ impl AttributeKind {
|
|||
RustcMir(..) => Yes,
|
||||
RustcMustImplementOneOf { .. } => No,
|
||||
RustcNeverReturnsNullPointer => Yes,
|
||||
RustcNeverTypeOptions { .. } => No,
|
||||
RustcNoImplicitAutorefs => Yes,
|
||||
RustcNoImplicitBounds => No,
|
||||
RustcNoMirInline => Yes,
|
||||
RustcNonConstTraitMethod => No, // should be reported via other queries like `constness`
|
||||
RustcNounwind => No,
|
||||
RustcObjcClass { .. } => No,
|
||||
|
|
@ -162,6 +168,7 @@ impl AttributeKind {
|
|||
RustcStrictCoherence(..) => Yes,
|
||||
RustcSymbolName(..) => Yes,
|
||||
RustcThenThisWouldNeed(..) => No,
|
||||
RustcTrivialFieldReads => Yes,
|
||||
RustcUnsafeSpecializationMarker(..) => No,
|
||||
RustcVariance => No,
|
||||
RustcVarianceOfOpaques => No,
|
||||
|
|
|
|||
|
|
@ -22,9 +22,7 @@ use rustc_abi::{ExternAbi, Size};
|
|||
use rustc_ast::Recovered;
|
||||
use rustc_data_structures::assert_matches;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey, struct_span_code_err,
|
||||
};
|
||||
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
|
|
@ -318,16 +316,24 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||
}
|
||||
|
||||
fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
|
||||
if let RegionInferReason::ObjectLifetimeDefault = reason {
|
||||
let e = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0228,
|
||||
"the lifetime bound for this object type cannot be deduced \
|
||||
from context; please supply an explicit bound"
|
||||
)
|
||||
.emit();
|
||||
ty::Region::new_error(self.tcx(), e)
|
||||
if let RegionInferReason::ObjectLifetimeDefault(sugg_sp) = reason {
|
||||
// FIXME: Account for trailing plus `dyn Trait+`, the need of parens in
|
||||
// `*const dyn Trait` and `Fn() -> *const dyn Trait`.
|
||||
let guar = self
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
"cannot deduce the lifetime bound for this trait object type from context",
|
||||
)
|
||||
.with_code(E0228)
|
||||
.with_span_suggestion_verbose(
|
||||
sugg_sp,
|
||||
"please supply an explicit bound",
|
||||
" + /* 'a */",
|
||||
Applicability::HasPlaceholders,
|
||||
)
|
||||
.emit();
|
||||
ty::Region::new_error(self.tcx(), guar)
|
||||
} else {
|
||||
// This indicates an illegal lifetime in a non-assoc-trait position
|
||||
ty::Region::new_error_with_message(self.tcx(), span, "unelided lifetime in signature")
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// Parent lifetime must have failed to resolve. Don't emit a redundant error.
|
||||
RegionInferReason::ExplicitObjectLifetime
|
||||
} else {
|
||||
RegionInferReason::ObjectLifetimeDefault
|
||||
RegionInferReason::ObjectLifetimeDefault(span.shrink_to_hi())
|
||||
}
|
||||
} else {
|
||||
RegionInferReason::ExplicitObjectLifetime
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ pub enum RegionInferReason<'a> {
|
|||
/// Lifetime on a trait object that is spelled explicitly, e.g. `+ 'a` or `+ '_`.
|
||||
ExplicitObjectLifetime,
|
||||
/// A trait object's lifetime when it is elided, e.g. `dyn Any`.
|
||||
ObjectLifetimeDefault,
|
||||
ObjectLifetimeDefault(Span),
|
||||
/// Generic lifetime parameter
|
||||
Param(&'a ty::GenericParamDef),
|
||||
RegionPredicate,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use rustc_errors::{Applicability, Diag, MultiSpan, listify};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{self as hir, find_attr};
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||
|
|
@ -1081,19 +1082,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
hir_id,
|
||||
|m| {
|
||||
self.has_only_self_parameter(m)
|
||||
&& self
|
||||
.tcx
|
||||
// This special internal attribute is used to permit
|
||||
// "identity-like" conversion methods to be suggested here.
|
||||
//
|
||||
// FIXME (#46459 and #46460): ideally
|
||||
// `std::convert::Into::into` and `std::borrow:ToOwned` would
|
||||
// also be `#[rustc_conversion_suggestion]`, if not for
|
||||
// method-probing false-positives and -negatives (respectively).
|
||||
//
|
||||
// FIXME? Other potential candidate methods: `as_ref` and
|
||||
// `as_mut`?
|
||||
.has_attr(m.def_id, sym::rustc_conversion_suggestion)
|
||||
// This special internal attribute is used to permit
|
||||
// "identity-like" conversion methods to be suggested here.
|
||||
//
|
||||
// FIXME (#46459 and #46460): ideally
|
||||
// `std::convert::Into::into` and `std::borrow:ToOwned` would
|
||||
// also be `#[rustc_conversion_suggestion]`, if not for
|
||||
// method-probing false-positives and -negatives (respectively).
|
||||
//
|
||||
// FIXME? Other potential candidate methods: `as_ref` and
|
||||
// `as_mut`?
|
||||
&& find_attr!(self.tcx.get_all_attrs(m.def_id), AttributeKind::RustcConversionSuggestion)
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ mod prelude_edition_lints;
|
|||
pub(crate) mod probe;
|
||||
mod suggest;
|
||||
|
||||
use rustc_errors::{Applicability, Diag, SubdiagMessage};
|
||||
use rustc_errors::{Applicability, Diag, DiagMessage};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
|
@ -127,7 +127,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pub(crate) fn suggest_method_call(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
msg: impl Into<SubdiagMessage> + std::fmt::Debug,
|
||||
msg: impl Into<DiagMessage> + std::fmt::Debug,
|
||||
method_name: Ident,
|
||||
self_ty: Ty<'tcx>,
|
||||
call_expr: &hir::Expr<'tcx>,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::collections::hash_map::Entry::{Occupied, Vacant};
|
|||
|
||||
use rustc_abi::FieldIdx;
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::assert_matches;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
|
|
@ -24,7 +25,6 @@ use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
|||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{BytePos, DUMMY_SP, Ident, Span, kw, sym};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
|
||||
|
|
@ -611,7 +611,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.write_ty(*hir_id, ty);
|
||||
ty
|
||||
}
|
||||
PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, &pat_info.top_info),
|
||||
PatKind::Expr(expr @ PatExpr { kind: PatExprKind::Lit { lit, .. }, .. }) => {
|
||||
self.check_pat_lit(pat.span, expr, &lit.node, expected, &pat_info.top_info)
|
||||
}
|
||||
PatKind::Range(lhs, rhs, _) => {
|
||||
self.check_pat_range(pat.span, lhs, rhs, expected, &pat_info.top_info)
|
||||
}
|
||||
|
|
@ -938,23 +940,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fn check_pat_lit(
|
||||
&self,
|
||||
span: Span,
|
||||
lt: &hir::PatExpr<'tcx>,
|
||||
expr: &hir::PatExpr<'tcx>,
|
||||
lit_kind: &ast::LitKind,
|
||||
expected: Ty<'tcx>,
|
||||
ti: &TopInfo<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
assert_matches!(expr.kind, hir::PatExprKind::Lit { .. });
|
||||
|
||||
// We've already computed the type above (when checking for a non-ref pat),
|
||||
// so avoid computing it again.
|
||||
let ty = self.node_ty(lt.hir_id);
|
||||
let ty = self.node_ty(expr.hir_id);
|
||||
|
||||
// Byte string patterns behave the same way as array patterns
|
||||
// They can denote both statically and dynamically-sized byte arrays.
|
||||
// Additionally, when `deref_patterns` is enabled, byte string literal patterns may have
|
||||
// types `[u8]` or `[u8; N]`, in order to type, e.g., `deref!(b"..."): Vec<u8>`.
|
||||
let mut pat_ty = ty;
|
||||
if let hir::PatExprKind::Lit {
|
||||
lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
|
||||
} = lt.kind
|
||||
{
|
||||
if matches!(lit_kind, ast::LitKind::ByteStr(..)) {
|
||||
let tcx = self.tcx;
|
||||
let expected = self.structurally_resolve_type(span, expected);
|
||||
match *expected.kind() {
|
||||
|
|
@ -962,7 +964,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ty::Ref(_, inner_ty, _)
|
||||
if self.try_structurally_resolve_type(span, inner_ty).is_slice() =>
|
||||
{
|
||||
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
|
||||
trace!(?expr.hir_id.local_id, "polymorphic byte string lit");
|
||||
pat_ty = Ty::new_imm_ref(
|
||||
tcx,
|
||||
tcx.lifetimes.re_static,
|
||||
|
|
@ -988,9 +990,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// When `deref_patterns` is enabled, in order to allow `deref!("..."): String`, we allow
|
||||
// string literal patterns to have type `str`. This is accounted for when lowering to MIR.
|
||||
if self.tcx.features().deref_patterns()
|
||||
&& let hir::PatExprKind::Lit {
|
||||
lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
|
||||
} = lt.kind
|
||||
&& matches!(lit_kind, ast::LitKind::Str(..))
|
||||
&& self.try_structurally_resolve_type(span, expected).is_str()
|
||||
{
|
||||
pat_ty = self.tcx.types.str_;
|
||||
|
|
|
|||
|
|
@ -36,10 +36,10 @@ use rustc_abi::FIRST_VARIANT;
|
|||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::unord::{ExtendUnord, UnordSet};
|
||||
use rustc_errors::{Applicability, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{self as hir, HirId, find_attr};
|
||||
use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
|
||||
use rustc_middle::mir::FakeReadCause;
|
||||
use rustc_middle::traits::ObligationCauseCode;
|
||||
|
|
@ -1743,7 +1743,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn should_log_capture_analysis(&self, closure_def_id: LocalDefId) -> bool {
|
||||
self.has_rustc_attrs && self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis)
|
||||
self.has_rustc_attrs
|
||||
&& find_attr!(
|
||||
self.tcx.get_all_attrs(closure_def_id),
|
||||
AttributeKind::RustcCaptureAnalysis
|
||||
)
|
||||
}
|
||||
|
||||
fn log_capture_analysis_first_pass(
|
||||
|
|
|
|||
|
|
@ -21,36 +21,25 @@ use synstructure::Structure;
|
|||
/// # extern crate rust_middle;
|
||||
/// # use rustc_middle::ty::Ty;
|
||||
/// #[derive(Diagnostic)]
|
||||
/// #[diag(borrowck_move_out_of_borrow, code = E0505)]
|
||||
/// pub struct MoveOutOfBorrowError<'tcx> {
|
||||
/// #[diag("this is an example message", code = E0123)]
|
||||
/// pub(crate) struct ExampleError<'tcx> {
|
||||
/// pub name: Ident,
|
||||
/// pub ty: Ty<'tcx>,
|
||||
/// #[primary_span]
|
||||
/// #[label]
|
||||
/// #[label("with a label")]
|
||||
/// pub span: Span,
|
||||
/// #[label(first_borrow_label)]
|
||||
/// pub first_borrow_span: Span,
|
||||
/// #[suggestion(code = "{name}.clone()")]
|
||||
/// pub clone_sugg: Option<(Span, Applicability)>
|
||||
/// #[label("with a label")]
|
||||
/// pub other_span: Span,
|
||||
/// #[suggestion("with a suggestion", code = "{name}.clone()")]
|
||||
/// pub opt_sugg: Option<(Span, Applicability)>,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```fluent
|
||||
/// move_out_of_borrow = cannot move out of {$name} because it is borrowed
|
||||
/// .label = cannot move out of borrow
|
||||
/// .first_borrow_label = `{$ty}` first borrowed here
|
||||
/// .suggestion = consider cloning here
|
||||
/// ```
|
||||
///
|
||||
/// Then, later, to emit the error:
|
||||
///
|
||||
/// ```ignore (rust)
|
||||
/// sess.emit_err(MoveOutOfBorrowError {
|
||||
/// expected,
|
||||
/// actual,
|
||||
/// span,
|
||||
/// first_borrow_span,
|
||||
/// clone_sugg: Some(suggestion, Applicability::MachineApplicable),
|
||||
/// sess.emit_err(ExampleError {
|
||||
/// name, ty, span, other_span, opt_sugg
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
|
|
@ -65,38 +54,24 @@ pub(super) fn diagnostic_derive(s: Structure<'_>) -> TokenStream {
|
|||
///
|
||||
/// ```ignore (rust)
|
||||
/// #[derive(LintDiagnostic)]
|
||||
/// #[diag(lint_atomic_ordering_invalid_fail_success)]
|
||||
/// pub struct AtomicOrderingInvalidLint {
|
||||
/// method: Symbol,
|
||||
/// success_ordering: Symbol,
|
||||
/// fail_ordering: Symbol,
|
||||
/// #[label(fail_label)]
|
||||
/// fail_order_arg_span: Span,
|
||||
/// #[label(success_label)]
|
||||
/// #[suggestion(
|
||||
/// code = "std::sync::atomic::Ordering::{success_suggestion}",
|
||||
/// applicability = "maybe-incorrect"
|
||||
/// #[diag("unused attribute")]
|
||||
/// pub(crate) struct UnusedAttribute {
|
||||
/// #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")]
|
||||
/// pub this: Span,
|
||||
/// #[note("attribute also specified here")]
|
||||
/// pub other: Span,
|
||||
/// #[warning(
|
||||
/// "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!"
|
||||
/// )]
|
||||
/// success_order_arg_span: Span,
|
||||
/// pub warning: bool,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```fluent
|
||||
/// lint_atomic_ordering_invalid_fail_success = `{$method}`'s success ordering must be at least as strong as its failure ordering
|
||||
/// .fail_label = `{$fail_ordering}` failure ordering
|
||||
/// .success_label = `{$success_ordering}` success ordering
|
||||
/// .suggestion = consider using `{$success_suggestion}` success ordering instead
|
||||
/// ```
|
||||
///
|
||||
/// Then, later, to emit the error:
|
||||
///
|
||||
/// ```ignore (rust)
|
||||
/// cx.emit_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg_span, AtomicOrderingInvalidLint {
|
||||
/// method,
|
||||
/// success_ordering,
|
||||
/// fail_ordering,
|
||||
/// fail_order_arg_span,
|
||||
/// success_order_arg_span,
|
||||
/// cx.emit_span_lint(UNUSED_ATTRIBUTES, span, UnusedAttribute {
|
||||
/// ...
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
|
|
@ -112,45 +87,25 @@ pub(super) fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
|
|||
///
|
||||
/// ```ignore (rust)
|
||||
/// #[derive(Subdiagnostic)]
|
||||
/// pub enum ExpectedIdentifierLabel<'tcx> {
|
||||
/// #[label(expected_identifier)]
|
||||
/// WithoutFound {
|
||||
/// #[primary_span]
|
||||
/// span: Span,
|
||||
/// }
|
||||
/// #[label(expected_identifier_found)]
|
||||
/// WithFound {
|
||||
/// #[primary_span]
|
||||
/// span: Span,
|
||||
/// found: String,
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Subdiagnostic)]
|
||||
/// #[suggestion(style = "verbose",parser::raw_identifier)]
|
||||
/// pub struct RawIdentifierSuggestion<'tcx> {
|
||||
/// #[primary_span]
|
||||
/// span: Span,
|
||||
/// #[applicability]
|
||||
/// applicability: Applicability,
|
||||
/// ident: Ident,
|
||||
/// pub(crate) enum BuiltinUnusedDocCommentSub {
|
||||
/// #[help("use `//` for a plain comment")]
|
||||
/// PlainHelp,
|
||||
/// #[help("use `/* */` for a plain comment")]
|
||||
/// BlockHelp,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```fluent
|
||||
/// parser_expected_identifier = expected identifier
|
||||
///
|
||||
/// parser_expected_identifier_found = expected identifier, found {$found}
|
||||
///
|
||||
/// parser_raw_identifier = escape `{$ident}` to use it as an identifier
|
||||
/// ```
|
||||
///
|
||||
/// Then, later, to add the subdiagnostic:
|
||||
/// Then, later, use the subdiagnostic in a diagnostic:
|
||||
///
|
||||
/// ```ignore (rust)
|
||||
/// diag.subdiagnostic(ExpectedIdentifierLabel::WithoutFound { span });
|
||||
///
|
||||
/// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
|
||||
/// #[derive(LintDiagnostic)]
|
||||
/// #[diag("unused doc comment")]
|
||||
/// pub(crate) struct BuiltinUnusedDocComment<'a> {
|
||||
/// pub kind: &'a str,
|
||||
/// #[label("rustdoc does not generate documentation for {$kind}")]
|
||||
/// pub label: Span,
|
||||
/// #[subdiagnostic]
|
||||
/// pub sub: BuiltinUnusedDocCommentSub,
|
||||
/// }
|
||||
/// ```
|
||||
pub(super) fn subdiagnostic_derive(s: Structure<'_>) -> TokenStream {
|
||||
SubdiagnosticDerive::new().into_tokens(s)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@
|
|||
#![allow(unused_parens)]
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::mem;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
use std::mem;
|
||||
|
||||
use rustc_arena::TypedArena;
|
||||
|
||||
use crate::ty::TyCtxt;
|
||||
|
||||
/// Helper trait that allows `arena_cache` queries to return `Option<&T>`
|
||||
/// instead of `&Option<T>`, and avoid allocating `None` in the arena.
|
||||
///
|
||||
|
|
@ -11,10 +17,11 @@ pub trait ArenaCached<'tcx>: Sized {
|
|||
/// Type that is stored in the arena.
|
||||
type Allocated: 'tcx;
|
||||
|
||||
/// Takes a provided value, and allocates it in the arena (if appropriate)
|
||||
/// with the help of the given `arena_alloc` closure.
|
||||
/// Takes a provided value, and allocates it in an appropriate arena,
|
||||
/// unless the particular value doesn't need allocation (e.g. `None`).
|
||||
fn alloc_in_arena(
|
||||
arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typed_arena: &'tcx TypedArena<Self::Allocated>,
|
||||
value: Self::Provided,
|
||||
) -> Self;
|
||||
}
|
||||
|
|
@ -23,12 +30,9 @@ impl<'tcx, T> ArenaCached<'tcx> for &'tcx T {
|
|||
type Provided = T;
|
||||
type Allocated = T;
|
||||
|
||||
fn alloc_in_arena(
|
||||
arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
|
||||
value: Self::Provided,
|
||||
) -> Self {
|
||||
fn alloc_in_arena(tcx: TyCtxt<'tcx>, typed_arena: &'tcx TypedArena<T>, value: T) -> Self {
|
||||
// Just allocate in the arena normally.
|
||||
arena_alloc(value)
|
||||
do_alloc(tcx, typed_arena, value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -38,10 +42,17 @@ impl<'tcx, T> ArenaCached<'tcx> for Option<&'tcx T> {
|
|||
type Allocated = T;
|
||||
|
||||
fn alloc_in_arena(
|
||||
arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
|
||||
value: Self::Provided,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typed_arena: &'tcx TypedArena<T>,
|
||||
value: Option<T>,
|
||||
) -> Self {
|
||||
// Don't store None in the arena, and wrap the allocated reference in Some.
|
||||
value.map(arena_alloc)
|
||||
try { do_alloc(tcx, typed_arena, value?) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocates a value in either its dedicated arena, or in the common dropless
|
||||
/// arena, depending on whether it needs to be dropped.
|
||||
fn do_alloc<'tcx, T>(tcx: TyCtxt<'tcx>, typed_arena: &'tcx TypedArena<T>, value: T) -> &'tcx T {
|
||||
if mem::needs_drop::<T>() { typed_arena.alloc(value) } else { tcx.arena.dropless.alloc(value) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,36 +295,28 @@ macro_rules! define_callbacks {
|
|||
($V)
|
||||
);
|
||||
|
||||
/// This function takes `ProvidedValue` and converts it to an erased `Value` by
|
||||
/// allocating it on an arena if the query has the `arena_cache` modifier. The
|
||||
/// value is then erased and returned. This will happen when computing the query
|
||||
/// using a provider or decoding a stored result.
|
||||
/// This helper function takes a value returned by the query provider
|
||||
/// (or loaded from disk, or supplied by query feeding), allocates
|
||||
/// it in an arena if requested by the `arena_cache` modifier, and
|
||||
/// then returns an erased copy of it.
|
||||
#[inline(always)]
|
||||
pub fn provided_to_erased<'tcx>(
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
provided_value: ProvidedValue<'tcx>,
|
||||
) -> Erased<Value<'tcx>> {
|
||||
// Store the provided value in an arena and get a reference
|
||||
// to it, for queries with `arena_cache`.
|
||||
let value: Value<'tcx> = query_if_arena!([$($modifiers)*]
|
||||
{
|
||||
use $crate::query::arena_cached::ArenaCached;
|
||||
|
||||
if mem::needs_drop::<<$V as ArenaCached<'tcx>>::Allocated>() {
|
||||
<$V as ArenaCached>::alloc_in_arena(
|
||||
|v| _tcx.query_system.arenas.$name.alloc(v),
|
||||
provided_value,
|
||||
)
|
||||
} else {
|
||||
<$V as ArenaCached>::alloc_in_arena(
|
||||
|v| _tcx.arena.dropless.alloc(v),
|
||||
provided_value,
|
||||
)
|
||||
}
|
||||
}
|
||||
// Otherwise, the provided value is the value.
|
||||
(provided_value)
|
||||
);
|
||||
// For queries with the `arena_cache` modifier, store the
|
||||
// provided value in an arena and get a reference to it.
|
||||
let value: Value<'tcx> = query_if_arena!([$($modifiers)*] {
|
||||
<$V as $crate::query::arena_cached::ArenaCached>::alloc_in_arena(
|
||||
tcx,
|
||||
&tcx.query_system.arenas.$name,
|
||||
provided_value,
|
||||
)
|
||||
} {
|
||||
// Otherwise, the provided value is the value (and `tcx` is unused).
|
||||
let _ = tcx;
|
||||
provided_value
|
||||
});
|
||||
erase::erase_val(value)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#![allow(rustc::usage_of_ty_tykind)]
|
||||
|
||||
mod impl_interner;
|
||||
pub mod tls;
|
||||
|
||||
use std::borrow::{Borrow, Cow};
|
||||
|
|
@ -16,6 +17,7 @@ use std::{fmt, iter, mem};
|
|||
|
||||
use rustc_abi::{ExternAbi, FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx};
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::defer;
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
|
|
@ -27,12 +29,9 @@ use rustc_data_structures::steal::Steal;
|
|||
use rustc_data_structures::sync::{
|
||||
self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal,
|
||||
};
|
||||
use rustc_data_structures::{debug_assert_matches, defer};
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan,
|
||||
};
|
||||
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, LintDiagnostic, MultiSpan};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState};
|
||||
use rustc_hir::intravisit::VisitorExt;
|
||||
|
|
@ -50,16 +49,13 @@ use rustc_session::lint::Lint;
|
|||
use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw};
|
||||
use rustc_type_ir::TyKind::*;
|
||||
use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
|
||||
pub use rustc_type_ir::lift::Lift;
|
||||
use rustc_type_ir::{
|
||||
CollectAndApply, Interner, TypeFlags, TypeFoldable, WithCachedTypeInfo, elaborate, search_graph,
|
||||
};
|
||||
use rustc_type_ir::{CollectAndApply, TypeFlags, WithCachedTypeInfo, elaborate, search_graph};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::arena::Arena;
|
||||
use crate::dep_graph::{DepGraph, DepKindVTable};
|
||||
use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind, CanonicalVarKinds};
|
||||
use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind};
|
||||
use crate::lint::lint_level;
|
||||
use crate::metadata::ModChild;
|
||||
use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature};
|
||||
|
|
@ -70,798 +66,16 @@ use crate::query::plumbing::QuerySystem;
|
|||
use crate::query::{IntoQueryParam, LocalCrate, Providers, TyCtxtAt};
|
||||
use crate::thir::Thir;
|
||||
use crate::traits;
|
||||
use crate::traits::cache::WithDepNode;
|
||||
use crate::traits::solve::{
|
||||
self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, PredefinedOpaques,
|
||||
QueryResult, inspect,
|
||||
};
|
||||
use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData, PredefinedOpaques};
|
||||
use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
|
||||
use crate::ty::{
|
||||
self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericArg, GenericArgs,
|
||||
GenericArgsRef, GenericParamDefKind, List, ListWithCachedTypeInfo, ParamConst, ParamTy,
|
||||
Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind,
|
||||
PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid,
|
||||
ValTree, ValTreeKind, Visibility,
|
||||
GenericArgsRef, GenericParamDefKind, List, ListWithCachedTypeInfo, ParamConst, Pattern,
|
||||
PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity,
|
||||
Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, ValTree, ValTreeKind,
|
||||
Visibility,
|
||||
};
|
||||
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
fn next_trait_solver_globally(self) -> bool {
|
||||
self.next_trait_solver_globally()
|
||||
}
|
||||
|
||||
type DefId = DefId;
|
||||
type LocalDefId = LocalDefId;
|
||||
type TraitId = DefId;
|
||||
type ForeignId = DefId;
|
||||
type FunctionId = DefId;
|
||||
type ClosureId = DefId;
|
||||
type CoroutineClosureId = DefId;
|
||||
type CoroutineId = DefId;
|
||||
type AdtId = DefId;
|
||||
type ImplId = DefId;
|
||||
type UnevaluatedConstId = DefId;
|
||||
type Span = Span;
|
||||
|
||||
type GenericArgs = ty::GenericArgsRef<'tcx>;
|
||||
|
||||
type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
|
||||
type GenericArg = ty::GenericArg<'tcx>;
|
||||
type Term = ty::Term<'tcx>;
|
||||
type BoundVarKinds = &'tcx List<ty::BoundVariableKind<'tcx>>;
|
||||
|
||||
type PredefinedOpaques = solve::PredefinedOpaques<'tcx>;
|
||||
|
||||
fn mk_predefined_opaques_in_body(
|
||||
self,
|
||||
data: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)],
|
||||
) -> Self::PredefinedOpaques {
|
||||
self.mk_predefined_opaques_in_body(data)
|
||||
}
|
||||
type LocalDefIds = &'tcx ty::List<LocalDefId>;
|
||||
type CanonicalVarKinds = CanonicalVarKinds<'tcx>;
|
||||
fn mk_canonical_var_kinds(
|
||||
self,
|
||||
kinds: &[ty::CanonicalVarKind<Self>],
|
||||
) -> Self::CanonicalVarKinds {
|
||||
self.mk_canonical_var_kinds(kinds)
|
||||
}
|
||||
|
||||
type ExternalConstraints = ExternalConstraints<'tcx>;
|
||||
fn mk_external_constraints(
|
||||
self,
|
||||
data: ExternalConstraintsData<Self>,
|
||||
) -> ExternalConstraints<'tcx> {
|
||||
self.mk_external_constraints(data)
|
||||
}
|
||||
type DepNodeIndex = DepNodeIndex;
|
||||
fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, DepNodeIndex) {
|
||||
self.dep_graph.with_anon_task(self, crate::dep_graph::dep_kinds::TraitSelect, task)
|
||||
}
|
||||
type Ty = Ty<'tcx>;
|
||||
type Tys = &'tcx List<Ty<'tcx>>;
|
||||
|
||||
type FnInputTys = &'tcx [Ty<'tcx>];
|
||||
type ParamTy = ParamTy;
|
||||
type Symbol = Symbol;
|
||||
|
||||
type ErrorGuaranteed = ErrorGuaranteed;
|
||||
type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
|
||||
|
||||
type AllocId = crate::mir::interpret::AllocId;
|
||||
type Pat = Pattern<'tcx>;
|
||||
type PatList = &'tcx List<Pattern<'tcx>>;
|
||||
type Safety = hir::Safety;
|
||||
type Abi = ExternAbi;
|
||||
type Const = ty::Const<'tcx>;
|
||||
|
||||
type ParamConst = ty::ParamConst;
|
||||
type ValueConst = ty::Value<'tcx>;
|
||||
type ExprConst = ty::Expr<'tcx>;
|
||||
type ValTree = ty::ValTree<'tcx>;
|
||||
type ScalarInt = ty::ScalarInt;
|
||||
|
||||
type Region = Region<'tcx>;
|
||||
type EarlyParamRegion = ty::EarlyParamRegion;
|
||||
type LateParamRegion = ty::LateParamRegion;
|
||||
|
||||
type RegionAssumptions = &'tcx ty::List<ty::ArgOutlivesPredicate<'tcx>>;
|
||||
|
||||
type ParamEnv = ty::ParamEnv<'tcx>;
|
||||
type Predicate = Predicate<'tcx>;
|
||||
|
||||
type Clause = Clause<'tcx>;
|
||||
type Clauses = ty::Clauses<'tcx>;
|
||||
|
||||
type Tracked<T: fmt::Debug + Clone> = WithDepNode<T>;
|
||||
fn mk_tracked<T: fmt::Debug + Clone>(
|
||||
self,
|
||||
data: T,
|
||||
dep_node: DepNodeIndex,
|
||||
) -> Self::Tracked<T> {
|
||||
WithDepNode::new(dep_node, data)
|
||||
}
|
||||
fn get_tracked<T: fmt::Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T {
|
||||
tracked.get(self)
|
||||
}
|
||||
|
||||
fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R {
|
||||
f(&mut *self.new_solver_evaluation_cache.lock())
|
||||
}
|
||||
|
||||
fn canonical_param_env_cache_get_or_insert<R>(
|
||||
self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
f: impl FnOnce() -> ty::CanonicalParamEnvCacheEntry<Self>,
|
||||
from_entry: impl FnOnce(&ty::CanonicalParamEnvCacheEntry<Self>) -> R,
|
||||
) -> R {
|
||||
let mut cache = self.new_solver_canonical_param_env_cache.lock();
|
||||
let entry = cache.entry(param_env).or_insert_with(f);
|
||||
from_entry(entry)
|
||||
}
|
||||
|
||||
fn assert_evaluation_is_concurrent(&self) {
|
||||
// Turns out, the assumption for this function isn't perfect.
|
||||
// See trait-system-refactor-initiative#234.
|
||||
}
|
||||
|
||||
fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T {
|
||||
self.expand_abstract_consts(t)
|
||||
}
|
||||
|
||||
type GenericsOf = &'tcx ty::Generics;
|
||||
|
||||
fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics {
|
||||
self.generics_of(def_id)
|
||||
}
|
||||
|
||||
type VariancesOf = &'tcx [ty::Variance];
|
||||
|
||||
fn variances_of(self, def_id: DefId) -> Self::VariancesOf {
|
||||
self.variances_of(def_id)
|
||||
}
|
||||
|
||||
fn opt_alias_variances(
|
||||
self,
|
||||
kind: impl Into<ty::AliasTermKind>,
|
||||
def_id: DefId,
|
||||
) -> Option<&'tcx [ty::Variance]> {
|
||||
self.opt_alias_variances(kind, def_id)
|
||||
}
|
||||
|
||||
fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
|
||||
self.type_of(def_id)
|
||||
}
|
||||
fn type_of_opaque_hir_typeck(self, def_id: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
|
||||
self.type_of_opaque_hir_typeck(def_id)
|
||||
}
|
||||
fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
|
||||
self.const_of_item(def_id)
|
||||
}
|
||||
fn anon_const_kind(self, def_id: DefId) -> ty::AnonConstKind {
|
||||
self.anon_const_kind(def_id)
|
||||
}
|
||||
|
||||
type AdtDef = ty::AdtDef<'tcx>;
|
||||
fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef {
|
||||
self.adt_def(adt_def_id)
|
||||
}
|
||||
|
||||
fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind {
|
||||
match self.def_kind(alias.def_id) {
|
||||
DefKind::AssocTy => {
|
||||
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
|
||||
{
|
||||
ty::Inherent
|
||||
} else {
|
||||
ty::Projection
|
||||
}
|
||||
}
|
||||
DefKind::OpaqueTy => ty::Opaque,
|
||||
DefKind::TyAlias => ty::Free,
|
||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn alias_term_kind(self, alias: ty::AliasTerm<'tcx>) -> ty::AliasTermKind {
|
||||
match self.def_kind(alias.def_id) {
|
||||
DefKind::AssocTy => {
|
||||
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
|
||||
{
|
||||
ty::AliasTermKind::InherentTy
|
||||
} else {
|
||||
ty::AliasTermKind::ProjectionTy
|
||||
}
|
||||
}
|
||||
DefKind::AssocConst => {
|
||||
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
|
||||
{
|
||||
ty::AliasTermKind::InherentConst
|
||||
} else {
|
||||
ty::AliasTermKind::ProjectionConst
|
||||
}
|
||||
}
|
||||
DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
|
||||
DefKind::TyAlias => ty::AliasTermKind::FreeTy,
|
||||
DefKind::Const => ty::AliasTermKind::FreeConst,
|
||||
DefKind::AnonConst | DefKind::Ctor(_, CtorKind::Const) => {
|
||||
ty::AliasTermKind::UnevaluatedConst
|
||||
}
|
||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn trait_ref_and_own_args_for_alias(
|
||||
self,
|
||||
def_id: DefId,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
|
||||
debug_assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
|
||||
let trait_def_id = self.parent(def_id);
|
||||
debug_assert_matches!(self.def_kind(trait_def_id), DefKind::Trait);
|
||||
let trait_ref = ty::TraitRef::from_assoc(self, trait_def_id, args);
|
||||
(trait_ref, &args[trait_ref.args.len()..])
|
||||
}
|
||||
|
||||
fn mk_args(self, args: &[Self::GenericArg]) -> ty::GenericArgsRef<'tcx> {
|
||||
self.mk_args(args)
|
||||
}
|
||||
|
||||
fn mk_args_from_iter<I, T>(self, args: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<Self::GenericArg, ty::GenericArgsRef<'tcx>>,
|
||||
{
|
||||
self.mk_args_from_iter(args)
|
||||
}
|
||||
|
||||
fn check_args_compatible(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> bool {
|
||||
self.check_args_compatible(def_id, args)
|
||||
}
|
||||
|
||||
fn debug_assert_args_compatible(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) {
|
||||
self.debug_assert_args_compatible(def_id, args);
|
||||
}
|
||||
|
||||
/// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection`
|
||||
/// are compatible with the `DefId`. Since we're missing a `Self` type, stick on
|
||||
/// a dummy self type and forward to `debug_assert_args_compatible`.
|
||||
fn debug_assert_existential_args_compatible(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
args: Self::GenericArgs,
|
||||
) {
|
||||
// FIXME: We could perhaps add a `skip: usize` to `debug_assert_args_compatible`
|
||||
// to avoid needing to reintern the set of args...
|
||||
if cfg!(debug_assertions) {
|
||||
self.debug_assert_args_compatible(
|
||||
def_id,
|
||||
self.mk_args_from_iter(
|
||||
[self.types.trait_object_dummy_self.into()].into_iter().chain(args.iter()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<Ty<'tcx>, &'tcx List<Ty<'tcx>>>,
|
||||
{
|
||||
self.mk_type_list_from_iter(args)
|
||||
}
|
||||
|
||||
fn parent(self, def_id: DefId) -> DefId {
|
||||
self.parent(def_id)
|
||||
}
|
||||
|
||||
fn recursion_limit(self) -> usize {
|
||||
self.recursion_limit().0
|
||||
}
|
||||
|
||||
type Features = &'tcx rustc_feature::Features;
|
||||
|
||||
fn features(self) -> Self::Features {
|
||||
self.features()
|
||||
}
|
||||
|
||||
fn coroutine_hidden_types(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes<TyCtxt<'tcx>>>> {
|
||||
self.coroutine_hidden_types(def_id)
|
||||
}
|
||||
|
||||
fn fn_sig(self, def_id: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
|
||||
self.fn_sig(def_id)
|
||||
}
|
||||
|
||||
fn coroutine_movability(self, def_id: DefId) -> rustc_ast::Movability {
|
||||
self.coroutine_movability(def_id)
|
||||
}
|
||||
|
||||
fn coroutine_for_closure(self, def_id: DefId) -> DefId {
|
||||
self.coroutine_for_closure(def_id)
|
||||
}
|
||||
|
||||
fn generics_require_sized_self(self, def_id: DefId) -> bool {
|
||||
self.generics_require_sized_self(def_id)
|
||||
}
|
||||
|
||||
fn item_bounds(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
self.item_bounds(def_id).map_bound(IntoIterator::into_iter)
|
||||
}
|
||||
|
||||
fn item_self_bounds(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
self.item_self_bounds(def_id).map_bound(IntoIterator::into_iter)
|
||||
}
|
||||
|
||||
fn item_non_self_bounds(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
self.item_non_self_bounds(def_id).map_bound(IntoIterator::into_iter)
|
||||
}
|
||||
|
||||
fn predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.predicates_of(def_id).instantiate_identity(self).predicates.into_iter(),
|
||||
)
|
||||
}
|
||||
|
||||
fn own_predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.predicates_of(def_id).instantiate_own_identity().map(|(clause, _)| clause),
|
||||
)
|
||||
}
|
||||
|
||||
fn explicit_super_predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>> {
|
||||
self.explicit_super_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied())
|
||||
}
|
||||
|
||||
fn explicit_implied_predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>> {
|
||||
self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied())
|
||||
}
|
||||
|
||||
fn impl_super_outlives(
|
||||
self,
|
||||
impl_def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
self.impl_super_outlives(impl_def_id)
|
||||
}
|
||||
|
||||
fn impl_is_const(self, def_id: DefId) -> bool {
|
||||
debug_assert_matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true });
|
||||
self.is_conditionally_const(def_id)
|
||||
}
|
||||
|
||||
fn fn_is_const(self, def_id: DefId) -> bool {
|
||||
debug_assert_matches!(
|
||||
self.def_kind(def_id),
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(CtorOf::Struct, CtorKind::Fn)
|
||||
);
|
||||
self.is_conditionally_const(def_id)
|
||||
}
|
||||
|
||||
fn alias_has_const_conditions(self, def_id: DefId) -> bool {
|
||||
debug_assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::OpaqueTy);
|
||||
self.is_conditionally_const(def_id)
|
||||
}
|
||||
|
||||
fn const_conditions(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.const_conditions(def_id).instantiate_identity(self).into_iter().map(|(c, _)| c),
|
||||
)
|
||||
}
|
||||
|
||||
fn explicit_implied_const_bounds(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.explicit_implied_const_bounds(def_id).iter_identity_copied().map(|(c, _)| c),
|
||||
)
|
||||
}
|
||||
|
||||
fn impl_self_is_guaranteed_unsized(self, impl_def_id: DefId) -> bool {
|
||||
self.impl_self_is_guaranteed_unsized(impl_def_id)
|
||||
}
|
||||
|
||||
fn has_target_features(self, def_id: DefId) -> bool {
|
||||
!self.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
}
|
||||
|
||||
fn require_lang_item(self, lang_item: SolverLangItem) -> DefId {
|
||||
self.require_lang_item(solver_lang_item_to_lang_item(lang_item), DUMMY_SP)
|
||||
}
|
||||
|
||||
fn require_trait_lang_item(self, lang_item: SolverTraitLangItem) -> DefId {
|
||||
self.require_lang_item(solver_trait_lang_item_to_lang_item(lang_item), DUMMY_SP)
|
||||
}
|
||||
|
||||
fn require_adt_lang_item(self, lang_item: SolverAdtLangItem) -> DefId {
|
||||
self.require_lang_item(solver_adt_lang_item_to_lang_item(lang_item), DUMMY_SP)
|
||||
}
|
||||
|
||||
fn is_lang_item(self, def_id: DefId, lang_item: SolverLangItem) -> bool {
|
||||
self.is_lang_item(def_id, solver_lang_item_to_lang_item(lang_item))
|
||||
}
|
||||
|
||||
fn is_trait_lang_item(self, def_id: DefId, lang_item: SolverTraitLangItem) -> bool {
|
||||
self.is_lang_item(def_id, solver_trait_lang_item_to_lang_item(lang_item))
|
||||
}
|
||||
|
||||
fn is_adt_lang_item(self, def_id: DefId, lang_item: SolverAdtLangItem) -> bool {
|
||||
self.is_lang_item(def_id, solver_adt_lang_item_to_lang_item(lang_item))
|
||||
}
|
||||
|
||||
fn is_default_trait(self, def_id: DefId) -> bool {
|
||||
self.is_default_trait(def_id)
|
||||
}
|
||||
|
||||
fn is_sizedness_trait(self, def_id: DefId) -> bool {
|
||||
self.is_sizedness_trait(def_id)
|
||||
}
|
||||
|
||||
fn as_lang_item(self, def_id: DefId) -> Option<SolverLangItem> {
|
||||
lang_item_to_solver_lang_item(self.lang_items().from_def_id(def_id)?)
|
||||
}
|
||||
|
||||
fn as_trait_lang_item(self, def_id: DefId) -> Option<SolverTraitLangItem> {
|
||||
lang_item_to_solver_trait_lang_item(self.lang_items().from_def_id(def_id)?)
|
||||
}
|
||||
|
||||
fn as_adt_lang_item(self, def_id: DefId) -> Option<SolverAdtLangItem> {
|
||||
lang_item_to_solver_adt_lang_item(self.lang_items().from_def_id(def_id)?)
|
||||
}
|
||||
|
||||
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
|
||||
self.associated_items(def_id)
|
||||
.in_definition_order()
|
||||
.filter(|assoc_item| assoc_item.is_type())
|
||||
.map(|assoc_item| assoc_item.def_id)
|
||||
}
|
||||
|
||||
// This implementation is a bit different from `TyCtxt::for_each_relevant_impl`,
|
||||
// since we want to skip over blanket impls for non-rigid aliases, and also we
|
||||
// only want to consider types that *actually* unify with float/int vars.
|
||||
fn for_each_relevant_impl(
|
||||
self,
|
||||
trait_def_id: DefId,
|
||||
self_ty: Ty<'tcx>,
|
||||
mut f: impl FnMut(DefId),
|
||||
) {
|
||||
let tcx = self;
|
||||
let trait_impls = tcx.trait_impls_of(trait_def_id);
|
||||
let mut consider_impls_for_simplified_type = |simp| {
|
||||
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
|
||||
for &impl_def_id in impls_for_type {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match self_ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Array(_, _)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(..)
|
||||
| ty::Dynamic(_, _)
|
||||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
| ty::UnsafeBinder(_) => {
|
||||
if let Some(simp) = ty::fast_reject::simplify_type(
|
||||
tcx,
|
||||
self_ty,
|
||||
ty::fast_reject::TreatParams::AsRigid,
|
||||
) {
|
||||
consider_impls_for_simplified_type(simp);
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: For integer and float variables we have to manually look at all impls
|
||||
// which have some integer or float as a self type.
|
||||
ty::Infer(ty::IntVar(_)) => {
|
||||
use ty::IntTy::*;
|
||||
use ty::UintTy::*;
|
||||
// This causes a compiler error if any new integer kinds are added.
|
||||
let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy;
|
||||
let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy;
|
||||
let possible_integers = [
|
||||
// signed integers
|
||||
ty::SimplifiedType::Int(I8),
|
||||
ty::SimplifiedType::Int(I16),
|
||||
ty::SimplifiedType::Int(I32),
|
||||
ty::SimplifiedType::Int(I64),
|
||||
ty::SimplifiedType::Int(I128),
|
||||
ty::SimplifiedType::Int(Isize),
|
||||
// unsigned integers
|
||||
ty::SimplifiedType::Uint(U8),
|
||||
ty::SimplifiedType::Uint(U16),
|
||||
ty::SimplifiedType::Uint(U32),
|
||||
ty::SimplifiedType::Uint(U64),
|
||||
ty::SimplifiedType::Uint(U128),
|
||||
ty::SimplifiedType::Uint(Usize),
|
||||
];
|
||||
for simp in possible_integers {
|
||||
consider_impls_for_simplified_type(simp);
|
||||
}
|
||||
}
|
||||
|
||||
ty::Infer(ty::FloatVar(_)) => {
|
||||
// This causes a compiler error if any new float kinds are added.
|
||||
let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128);
|
||||
let possible_floats = [
|
||||
ty::SimplifiedType::Float(ty::FloatTy::F16),
|
||||
ty::SimplifiedType::Float(ty::FloatTy::F32),
|
||||
ty::SimplifiedType::Float(ty::FloatTy::F64),
|
||||
ty::SimplifiedType::Float(ty::FloatTy::F128),
|
||||
];
|
||||
|
||||
for simp in possible_floats {
|
||||
consider_impls_for_simplified_type(simp);
|
||||
}
|
||||
}
|
||||
|
||||
// The only traits applying to aliases and placeholders are blanket impls.
|
||||
//
|
||||
// Impls which apply to an alias after normalization are handled by
|
||||
// `assemble_candidates_after_normalizing_self_ty`.
|
||||
ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (),
|
||||
|
||||
// FIXME: These should ideally not exist as a self type. It would be nice for
|
||||
// the builtin auto trait impls of coroutines to instead directly recurse
|
||||
// into the witness.
|
||||
ty::CoroutineWitness(..) => (),
|
||||
|
||||
// These variants should not exist as a self type.
|
||||
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
|
||||
| ty::Param(_)
|
||||
| ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"),
|
||||
}
|
||||
|
||||
#[allow(rustc::usage_of_type_ir_traits)]
|
||||
self.for_each_blanket_impl(trait_def_id, f)
|
||||
}
|
||||
fn for_each_blanket_impl(self, trait_def_id: DefId, mut f: impl FnMut(DefId)) {
|
||||
let trait_impls = self.trait_impls_of(trait_def_id);
|
||||
for &impl_def_id in trait_impls.blanket_impls() {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn has_item_definition(self, def_id: DefId) -> bool {
|
||||
self.defaultness(def_id).has_value()
|
||||
}
|
||||
|
||||
fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool {
|
||||
self.specializes((impl_def_id, victim_def_id))
|
||||
}
|
||||
|
||||
fn impl_is_default(self, impl_def_id: DefId) -> bool {
|
||||
self.defaultness(impl_def_id).is_default()
|
||||
}
|
||||
|
||||
fn impl_trait_ref(self, impl_def_id: DefId) -> ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>> {
|
||||
self.impl_trait_ref(impl_def_id)
|
||||
}
|
||||
|
||||
fn impl_polarity(self, impl_def_id: DefId) -> ty::ImplPolarity {
|
||||
self.impl_polarity(impl_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_auto(self, trait_def_id: DefId) -> bool {
|
||||
self.trait_is_auto(trait_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_coinductive(self, trait_def_id: DefId) -> bool {
|
||||
self.trait_is_coinductive(trait_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_alias(self, trait_def_id: DefId) -> bool {
|
||||
self.trait_is_alias(trait_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_dyn_compatible(self, trait_def_id: DefId) -> bool {
|
||||
self.is_dyn_compatible(trait_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_fundamental(self, def_id: DefId) -> bool {
|
||||
self.trait_def(def_id).is_fundamental
|
||||
}
|
||||
|
||||
fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool {
|
||||
self.trait_def(trait_def_id).safety.is_unsafe()
|
||||
}
|
||||
|
||||
fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
|
||||
self.is_impl_trait_in_trait(def_id)
|
||||
}
|
||||
|
||||
fn delay_bug(self, msg: impl ToString) -> ErrorGuaranteed {
|
||||
self.dcx().span_delayed_bug(DUMMY_SP, msg.to_string())
|
||||
}
|
||||
|
||||
fn is_general_coroutine(self, coroutine_def_id: DefId) -> bool {
|
||||
self.is_general_coroutine(coroutine_def_id)
|
||||
}
|
||||
|
||||
fn coroutine_is_async(self, coroutine_def_id: DefId) -> bool {
|
||||
self.coroutine_is_async(coroutine_def_id)
|
||||
}
|
||||
|
||||
fn coroutine_is_gen(self, coroutine_def_id: DefId) -> bool {
|
||||
self.coroutine_is_gen(coroutine_def_id)
|
||||
}
|
||||
|
||||
fn coroutine_is_async_gen(self, coroutine_def_id: DefId) -> bool {
|
||||
self.coroutine_is_async_gen(coroutine_def_id)
|
||||
}
|
||||
|
||||
type UnsizingParams = &'tcx rustc_index::bit_set::DenseBitSet<u32>;
|
||||
fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams {
|
||||
self.unsizing_params_for_adt(adt_def_id)
|
||||
}
|
||||
|
||||
fn anonymize_bound_vars<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
self,
|
||||
binder: ty::Binder<'tcx, T>,
|
||||
) -> ty::Binder<'tcx, T> {
|
||||
self.anonymize_bound_vars(binder)
|
||||
}
|
||||
|
||||
fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::LocalDefIds {
|
||||
self.opaque_types_defined_by(defining_anchor)
|
||||
}
|
||||
|
||||
fn opaque_types_and_coroutines_defined_by(
|
||||
self,
|
||||
defining_anchor: Self::LocalDefId,
|
||||
) -> Self::LocalDefIds {
|
||||
let coroutines_defined_by = self
|
||||
.nested_bodies_within(defining_anchor)
|
||||
.iter()
|
||||
.filter(|def_id| self.is_coroutine(def_id.to_def_id()));
|
||||
self.mk_local_def_ids_from_iter(
|
||||
self.opaque_types_defined_by(defining_anchor).iter().chain(coroutines_defined_by),
|
||||
)
|
||||
}
|
||||
|
||||
type Probe = &'tcx inspect::Probe<TyCtxt<'tcx>>;
|
||||
fn mk_probe(self, probe: inspect::Probe<Self>) -> &'tcx inspect::Probe<TyCtxt<'tcx>> {
|
||||
self.arena.alloc(probe)
|
||||
}
|
||||
fn evaluate_root_goal_for_proof_tree_raw(
|
||||
self,
|
||||
canonical_goal: CanonicalInput<'tcx>,
|
||||
) -> (QueryResult<'tcx>, &'tcx inspect::Probe<TyCtxt<'tcx>>) {
|
||||
self.evaluate_root_goal_for_proof_tree_raw(canonical_goal)
|
||||
}
|
||||
|
||||
fn item_name(self, id: DefId) -> Symbol {
|
||||
let id = id.into_query_param();
|
||||
self.opt_item_name(id).unwrap_or_else(|| {
|
||||
bug!("item_name: no name for {:?}", self.def_path(id));
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! bidirectional_lang_item_map {
|
||||
(
|
||||
$solver_ty:ident, $to_solver:ident, $from_solver:ident;
|
||||
$($name:ident),+ $(,)?
|
||||
) => {
|
||||
fn $from_solver(lang_item: $solver_ty) -> LangItem {
|
||||
match lang_item {
|
||||
$($solver_ty::$name => LangItem::$name,)+
|
||||
}
|
||||
}
|
||||
|
||||
fn $to_solver(lang_item: LangItem) -> Option<$solver_ty> {
|
||||
Some(match lang_item {
|
||||
$(LangItem::$name => $solver_ty::$name,)+
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bidirectional_lang_item_map! {
|
||||
SolverLangItem, lang_item_to_solver_lang_item, solver_lang_item_to_lang_item;
|
||||
|
||||
// tidy-alphabetical-start
|
||||
AsyncFnKindUpvars,
|
||||
AsyncFnOnceOutput,
|
||||
CallOnceFuture,
|
||||
CallRefFuture,
|
||||
CoroutineReturn,
|
||||
CoroutineYield,
|
||||
DynMetadata,
|
||||
FutureOutput,
|
||||
Metadata,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
bidirectional_lang_item_map! {
|
||||
SolverAdtLangItem, lang_item_to_solver_adt_lang_item, solver_adt_lang_item_to_lang_item;
|
||||
|
||||
// tidy-alphabetical-start
|
||||
Option,
|
||||
Poll,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
bidirectional_lang_item_map! {
|
||||
SolverTraitLangItem, lang_item_to_solver_trait_lang_item, solver_trait_lang_item_to_lang_item;
|
||||
|
||||
// tidy-alphabetical-start
|
||||
AsyncFn,
|
||||
AsyncFnKindHelper,
|
||||
AsyncFnMut,
|
||||
AsyncFnOnce,
|
||||
AsyncFnOnceOutput,
|
||||
AsyncIterator,
|
||||
BikeshedGuaranteedNoDrop,
|
||||
Clone,
|
||||
Copy,
|
||||
Coroutine,
|
||||
Destruct,
|
||||
DiscriminantKind,
|
||||
Drop,
|
||||
Fn,
|
||||
FnMut,
|
||||
FnOnce,
|
||||
FnPtrTrait,
|
||||
FusedIterator,
|
||||
Future,
|
||||
Iterator,
|
||||
MetaSized,
|
||||
PointeeSized,
|
||||
PointeeTrait,
|
||||
Sized,
|
||||
TransmuteTrait,
|
||||
TrivialClone,
|
||||
Tuple,
|
||||
Unpin,
|
||||
Unsize,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::DefId<TyCtxt<'tcx>> for DefId {
|
||||
fn is_local(self) -> bool {
|
||||
self.is_local()
|
||||
|
|
|
|||
806
compiler/rustc_middle/src/ty/context/impl_interner.rs
Normal file
806
compiler/rustc_middle/src/ty/context/impl_interner.rs
Normal file
|
|
@ -0,0 +1,806 @@
|
|||
//! Implementation of [`rustc_type_ir::Interner`] for [`TyCtxt`].
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_data_structures::debug_assert_matches;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{self as hir};
|
||||
use rustc_query_system::dep_graph::DepNodeIndex;
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol};
|
||||
use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
|
||||
use rustc_type_ir::{CollectAndApply, Interner, TypeFoldable, search_graph};
|
||||
|
||||
use crate::infer::canonical::CanonicalVarKinds;
|
||||
use crate::query::IntoQueryParam;
|
||||
use crate::traits::cache::WithDepNode;
|
||||
use crate::traits::solve::{
|
||||
self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, QueryResult, inspect,
|
||||
};
|
||||
use crate::ty::{
|
||||
self, Clause, Const, List, ParamTy, Pattern, PolyExistentialPredicate, Predicate, Region, Ty,
|
||||
TyCtxt,
|
||||
};
|
||||
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
fn next_trait_solver_globally(self) -> bool {
|
||||
self.next_trait_solver_globally()
|
||||
}
|
||||
|
||||
type DefId = DefId;
|
||||
type LocalDefId = LocalDefId;
|
||||
type TraitId = DefId;
|
||||
type ForeignId = DefId;
|
||||
type FunctionId = DefId;
|
||||
type ClosureId = DefId;
|
||||
type CoroutineClosureId = DefId;
|
||||
type CoroutineId = DefId;
|
||||
type AdtId = DefId;
|
||||
type ImplId = DefId;
|
||||
type UnevaluatedConstId = DefId;
|
||||
type Span = Span;
|
||||
|
||||
type GenericArgs = ty::GenericArgsRef<'tcx>;
|
||||
|
||||
type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
|
||||
type GenericArg = ty::GenericArg<'tcx>;
|
||||
type Term = ty::Term<'tcx>;
|
||||
type BoundVarKinds = &'tcx List<ty::BoundVariableKind<'tcx>>;
|
||||
|
||||
type PredefinedOpaques = solve::PredefinedOpaques<'tcx>;
|
||||
|
||||
fn mk_predefined_opaques_in_body(
|
||||
self,
|
||||
data: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)],
|
||||
) -> Self::PredefinedOpaques {
|
||||
self.mk_predefined_opaques_in_body(data)
|
||||
}
|
||||
type LocalDefIds = &'tcx ty::List<LocalDefId>;
|
||||
type CanonicalVarKinds = CanonicalVarKinds<'tcx>;
|
||||
fn mk_canonical_var_kinds(
|
||||
self,
|
||||
kinds: &[ty::CanonicalVarKind<Self>],
|
||||
) -> Self::CanonicalVarKinds {
|
||||
self.mk_canonical_var_kinds(kinds)
|
||||
}
|
||||
|
||||
type ExternalConstraints = ExternalConstraints<'tcx>;
|
||||
fn mk_external_constraints(
|
||||
self,
|
||||
data: ExternalConstraintsData<Self>,
|
||||
) -> ExternalConstraints<'tcx> {
|
||||
self.mk_external_constraints(data)
|
||||
}
|
||||
type DepNodeIndex = DepNodeIndex;
|
||||
fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, DepNodeIndex) {
|
||||
self.dep_graph.with_anon_task(self, crate::dep_graph::dep_kinds::TraitSelect, task)
|
||||
}
|
||||
type Ty = Ty<'tcx>;
|
||||
type Tys = &'tcx List<Ty<'tcx>>;
|
||||
|
||||
type FnInputTys = &'tcx [Ty<'tcx>];
|
||||
type ParamTy = ParamTy;
|
||||
type Symbol = Symbol;
|
||||
|
||||
type ErrorGuaranteed = ErrorGuaranteed;
|
||||
type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
|
||||
|
||||
type AllocId = crate::mir::interpret::AllocId;
|
||||
type Pat = Pattern<'tcx>;
|
||||
type PatList = &'tcx List<Pattern<'tcx>>;
|
||||
type Safety = hir::Safety;
|
||||
type Abi = ExternAbi;
|
||||
type Const = ty::Const<'tcx>;
|
||||
|
||||
type ParamConst = ty::ParamConst;
|
||||
type ValueConst = ty::Value<'tcx>;
|
||||
type ExprConst = ty::Expr<'tcx>;
|
||||
type ValTree = ty::ValTree<'tcx>;
|
||||
type ScalarInt = ty::ScalarInt;
|
||||
|
||||
type Region = Region<'tcx>;
|
||||
type EarlyParamRegion = ty::EarlyParamRegion;
|
||||
type LateParamRegion = ty::LateParamRegion;
|
||||
|
||||
type RegionAssumptions = &'tcx ty::List<ty::ArgOutlivesPredicate<'tcx>>;
|
||||
|
||||
type ParamEnv = ty::ParamEnv<'tcx>;
|
||||
type Predicate = Predicate<'tcx>;
|
||||
|
||||
type Clause = Clause<'tcx>;
|
||||
type Clauses = ty::Clauses<'tcx>;
|
||||
|
||||
type Tracked<T: fmt::Debug + Clone> = WithDepNode<T>;
|
||||
fn mk_tracked<T: fmt::Debug + Clone>(
|
||||
self,
|
||||
data: T,
|
||||
dep_node: DepNodeIndex,
|
||||
) -> Self::Tracked<T> {
|
||||
WithDepNode::new(dep_node, data)
|
||||
}
|
||||
fn get_tracked<T: fmt::Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T {
|
||||
tracked.get(self)
|
||||
}
|
||||
|
||||
fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R {
|
||||
f(&mut *self.new_solver_evaluation_cache.lock())
|
||||
}
|
||||
|
||||
fn canonical_param_env_cache_get_or_insert<R>(
|
||||
self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
f: impl FnOnce() -> ty::CanonicalParamEnvCacheEntry<Self>,
|
||||
from_entry: impl FnOnce(&ty::CanonicalParamEnvCacheEntry<Self>) -> R,
|
||||
) -> R {
|
||||
let mut cache = self.new_solver_canonical_param_env_cache.lock();
|
||||
let entry = cache.entry(param_env).or_insert_with(f);
|
||||
from_entry(entry)
|
||||
}
|
||||
|
||||
fn assert_evaluation_is_concurrent(&self) {
|
||||
// Turns out, the assumption for this function isn't perfect.
|
||||
// See trait-system-refactor-initiative#234.
|
||||
}
|
||||
|
||||
fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T {
|
||||
self.expand_abstract_consts(t)
|
||||
}
|
||||
|
||||
type GenericsOf = &'tcx ty::Generics;
|
||||
|
||||
fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics {
|
||||
self.generics_of(def_id)
|
||||
}
|
||||
|
||||
type VariancesOf = &'tcx [ty::Variance];
|
||||
|
||||
fn variances_of(self, def_id: DefId) -> Self::VariancesOf {
|
||||
self.variances_of(def_id)
|
||||
}
|
||||
|
||||
fn opt_alias_variances(
|
||||
self,
|
||||
kind: impl Into<ty::AliasTermKind>,
|
||||
def_id: DefId,
|
||||
) -> Option<&'tcx [ty::Variance]> {
|
||||
self.opt_alias_variances(kind, def_id)
|
||||
}
|
||||
|
||||
fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
|
||||
self.type_of(def_id)
|
||||
}
|
||||
fn type_of_opaque_hir_typeck(self, def_id: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
|
||||
self.type_of_opaque_hir_typeck(def_id)
|
||||
}
|
||||
fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
|
||||
self.const_of_item(def_id)
|
||||
}
|
||||
fn anon_const_kind(self, def_id: DefId) -> ty::AnonConstKind {
|
||||
self.anon_const_kind(def_id)
|
||||
}
|
||||
|
||||
type AdtDef = ty::AdtDef<'tcx>;
|
||||
fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef {
|
||||
self.adt_def(adt_def_id)
|
||||
}
|
||||
|
||||
fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind {
|
||||
match self.def_kind(alias.def_id) {
|
||||
DefKind::AssocTy => {
|
||||
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
|
||||
{
|
||||
ty::Inherent
|
||||
} else {
|
||||
ty::Projection
|
||||
}
|
||||
}
|
||||
DefKind::OpaqueTy => ty::Opaque,
|
||||
DefKind::TyAlias => ty::Free,
|
||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn alias_term_kind(self, alias: ty::AliasTerm<'tcx>) -> ty::AliasTermKind {
|
||||
match self.def_kind(alias.def_id) {
|
||||
DefKind::AssocTy => {
|
||||
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
|
||||
{
|
||||
ty::AliasTermKind::InherentTy
|
||||
} else {
|
||||
ty::AliasTermKind::ProjectionTy
|
||||
}
|
||||
}
|
||||
DefKind::AssocConst => {
|
||||
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
|
||||
{
|
||||
ty::AliasTermKind::InherentConst
|
||||
} else {
|
||||
ty::AliasTermKind::ProjectionConst
|
||||
}
|
||||
}
|
||||
DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
|
||||
DefKind::TyAlias => ty::AliasTermKind::FreeTy,
|
||||
DefKind::Const => ty::AliasTermKind::FreeConst,
|
||||
DefKind::AnonConst | DefKind::Ctor(_, CtorKind::Const) => {
|
||||
ty::AliasTermKind::UnevaluatedConst
|
||||
}
|
||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn trait_ref_and_own_args_for_alias(
|
||||
self,
|
||||
def_id: DefId,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
|
||||
debug_assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
|
||||
let trait_def_id = self.parent(def_id);
|
||||
debug_assert_matches!(self.def_kind(trait_def_id), DefKind::Trait);
|
||||
let trait_ref = ty::TraitRef::from_assoc(self, trait_def_id, args);
|
||||
(trait_ref, &args[trait_ref.args.len()..])
|
||||
}
|
||||
|
||||
fn mk_args(self, args: &[Self::GenericArg]) -> ty::GenericArgsRef<'tcx> {
|
||||
self.mk_args(args)
|
||||
}
|
||||
|
||||
fn mk_args_from_iter<I, T>(self, args: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<Self::GenericArg, ty::GenericArgsRef<'tcx>>,
|
||||
{
|
||||
self.mk_args_from_iter(args)
|
||||
}
|
||||
|
||||
fn check_args_compatible(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> bool {
|
||||
self.check_args_compatible(def_id, args)
|
||||
}
|
||||
|
||||
fn debug_assert_args_compatible(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) {
|
||||
self.debug_assert_args_compatible(def_id, args);
|
||||
}
|
||||
|
||||
/// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection`
|
||||
/// are compatible with the `DefId`. Since we're missing a `Self` type, stick on
|
||||
/// a dummy self type and forward to `debug_assert_args_compatible`.
|
||||
fn debug_assert_existential_args_compatible(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
args: Self::GenericArgs,
|
||||
) {
|
||||
// FIXME: We could perhaps add a `skip: usize` to `debug_assert_args_compatible`
|
||||
// to avoid needing to reintern the set of args...
|
||||
if cfg!(debug_assertions) {
|
||||
self.debug_assert_args_compatible(
|
||||
def_id,
|
||||
self.mk_args_from_iter(
|
||||
[self.types.trait_object_dummy_self.into()].into_iter().chain(args.iter()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<Ty<'tcx>, &'tcx List<Ty<'tcx>>>,
|
||||
{
|
||||
self.mk_type_list_from_iter(args)
|
||||
}
|
||||
|
||||
fn parent(self, def_id: DefId) -> DefId {
|
||||
self.parent(def_id)
|
||||
}
|
||||
|
||||
fn recursion_limit(self) -> usize {
|
||||
self.recursion_limit().0
|
||||
}
|
||||
|
||||
type Features = &'tcx rustc_feature::Features;
|
||||
|
||||
fn features(self) -> Self::Features {
|
||||
self.features()
|
||||
}
|
||||
|
||||
fn coroutine_hidden_types(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes<TyCtxt<'tcx>>>> {
|
||||
self.coroutine_hidden_types(def_id)
|
||||
}
|
||||
|
||||
fn fn_sig(self, def_id: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
|
||||
self.fn_sig(def_id)
|
||||
}
|
||||
|
||||
fn coroutine_movability(self, def_id: DefId) -> rustc_ast::Movability {
|
||||
self.coroutine_movability(def_id)
|
||||
}
|
||||
|
||||
fn coroutine_for_closure(self, def_id: DefId) -> DefId {
|
||||
self.coroutine_for_closure(def_id)
|
||||
}
|
||||
|
||||
fn generics_require_sized_self(self, def_id: DefId) -> bool {
|
||||
self.generics_require_sized_self(def_id)
|
||||
}
|
||||
|
||||
fn item_bounds(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
self.item_bounds(def_id).map_bound(IntoIterator::into_iter)
|
||||
}
|
||||
|
||||
fn item_self_bounds(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
self.item_self_bounds(def_id).map_bound(IntoIterator::into_iter)
|
||||
}
|
||||
|
||||
fn item_non_self_bounds(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
self.item_non_self_bounds(def_id).map_bound(IntoIterator::into_iter)
|
||||
}
|
||||
|
||||
fn predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.predicates_of(def_id).instantiate_identity(self).predicates.into_iter(),
|
||||
)
|
||||
}
|
||||
|
||||
fn own_predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.predicates_of(def_id).instantiate_own_identity().map(|(clause, _)| clause),
|
||||
)
|
||||
}
|
||||
|
||||
fn explicit_super_predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>> {
|
||||
self.explicit_super_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied())
|
||||
}
|
||||
|
||||
fn explicit_implied_predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>> {
|
||||
self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied())
|
||||
}
|
||||
|
||||
fn impl_super_outlives(
|
||||
self,
|
||||
impl_def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
self.impl_super_outlives(impl_def_id)
|
||||
}
|
||||
|
||||
fn impl_is_const(self, def_id: DefId) -> bool {
|
||||
debug_assert_matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true });
|
||||
self.is_conditionally_const(def_id)
|
||||
}
|
||||
|
||||
fn fn_is_const(self, def_id: DefId) -> bool {
|
||||
debug_assert_matches!(
|
||||
self.def_kind(def_id),
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(CtorOf::Struct, CtorKind::Fn)
|
||||
);
|
||||
self.is_conditionally_const(def_id)
|
||||
}
|
||||
|
||||
fn alias_has_const_conditions(self, def_id: DefId) -> bool {
|
||||
debug_assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::OpaqueTy);
|
||||
self.is_conditionally_const(def_id)
|
||||
}
|
||||
|
||||
fn const_conditions(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.const_conditions(def_id).instantiate_identity(self).into_iter().map(|(c, _)| c),
|
||||
)
|
||||
}
|
||||
|
||||
fn explicit_implied_const_bounds(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.explicit_implied_const_bounds(def_id).iter_identity_copied().map(|(c, _)| c),
|
||||
)
|
||||
}
|
||||
|
||||
fn impl_self_is_guaranteed_unsized(self, impl_def_id: DefId) -> bool {
|
||||
self.impl_self_is_guaranteed_unsized(impl_def_id)
|
||||
}
|
||||
|
||||
fn has_target_features(self, def_id: DefId) -> bool {
|
||||
!self.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
}
|
||||
|
||||
fn require_lang_item(self, lang_item: SolverLangItem) -> DefId {
|
||||
self.require_lang_item(solver_lang_item_to_lang_item(lang_item), DUMMY_SP)
|
||||
}
|
||||
|
||||
fn require_trait_lang_item(self, lang_item: SolverTraitLangItem) -> DefId {
|
||||
self.require_lang_item(solver_trait_lang_item_to_lang_item(lang_item), DUMMY_SP)
|
||||
}
|
||||
|
||||
fn require_adt_lang_item(self, lang_item: SolverAdtLangItem) -> DefId {
|
||||
self.require_lang_item(solver_adt_lang_item_to_lang_item(lang_item), DUMMY_SP)
|
||||
}
|
||||
|
||||
fn is_lang_item(self, def_id: DefId, lang_item: SolverLangItem) -> bool {
|
||||
self.is_lang_item(def_id, solver_lang_item_to_lang_item(lang_item))
|
||||
}
|
||||
|
||||
fn is_trait_lang_item(self, def_id: DefId, lang_item: SolverTraitLangItem) -> bool {
|
||||
self.is_lang_item(def_id, solver_trait_lang_item_to_lang_item(lang_item))
|
||||
}
|
||||
|
||||
fn is_adt_lang_item(self, def_id: DefId, lang_item: SolverAdtLangItem) -> bool {
|
||||
self.is_lang_item(def_id, solver_adt_lang_item_to_lang_item(lang_item))
|
||||
}
|
||||
|
||||
fn is_default_trait(self, def_id: DefId) -> bool {
|
||||
self.is_default_trait(def_id)
|
||||
}
|
||||
|
||||
fn is_sizedness_trait(self, def_id: DefId) -> bool {
|
||||
self.is_sizedness_trait(def_id)
|
||||
}
|
||||
|
||||
fn as_lang_item(self, def_id: DefId) -> Option<SolverLangItem> {
|
||||
lang_item_to_solver_lang_item(self.lang_items().from_def_id(def_id)?)
|
||||
}
|
||||
|
||||
fn as_trait_lang_item(self, def_id: DefId) -> Option<SolverTraitLangItem> {
|
||||
lang_item_to_solver_trait_lang_item(self.lang_items().from_def_id(def_id)?)
|
||||
}
|
||||
|
||||
fn as_adt_lang_item(self, def_id: DefId) -> Option<SolverAdtLangItem> {
|
||||
lang_item_to_solver_adt_lang_item(self.lang_items().from_def_id(def_id)?)
|
||||
}
|
||||
|
||||
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
|
||||
self.associated_items(def_id)
|
||||
.in_definition_order()
|
||||
.filter(|assoc_item| assoc_item.is_type())
|
||||
.map(|assoc_item| assoc_item.def_id)
|
||||
}
|
||||
|
||||
// This implementation is a bit different from `TyCtxt::for_each_relevant_impl`,
|
||||
// since we want to skip over blanket impls for non-rigid aliases, and also we
|
||||
// only want to consider types that *actually* unify with float/int vars.
|
||||
fn for_each_relevant_impl(
|
||||
self,
|
||||
trait_def_id: DefId,
|
||||
self_ty: Ty<'tcx>,
|
||||
mut f: impl FnMut(DefId),
|
||||
) {
|
||||
let tcx = self;
|
||||
let trait_impls = tcx.trait_impls_of(trait_def_id);
|
||||
let mut consider_impls_for_simplified_type = |simp| {
|
||||
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
|
||||
for &impl_def_id in impls_for_type {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match self_ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Array(_, _)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(..)
|
||||
| ty::Dynamic(_, _)
|
||||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
| ty::UnsafeBinder(_) => {
|
||||
if let Some(simp) = ty::fast_reject::simplify_type(
|
||||
tcx,
|
||||
self_ty,
|
||||
ty::fast_reject::TreatParams::AsRigid,
|
||||
) {
|
||||
consider_impls_for_simplified_type(simp);
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: For integer and float variables we have to manually look at all impls
|
||||
// which have some integer or float as a self type.
|
||||
ty::Infer(ty::IntVar(_)) => {
|
||||
use ty::IntTy::*;
|
||||
use ty::UintTy::*;
|
||||
// This causes a compiler error if any new integer kinds are added.
|
||||
let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy;
|
||||
let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy;
|
||||
let possible_integers = [
|
||||
// signed integers
|
||||
ty::SimplifiedType::Int(I8),
|
||||
ty::SimplifiedType::Int(I16),
|
||||
ty::SimplifiedType::Int(I32),
|
||||
ty::SimplifiedType::Int(I64),
|
||||
ty::SimplifiedType::Int(I128),
|
||||
ty::SimplifiedType::Int(Isize),
|
||||
// unsigned integers
|
||||
ty::SimplifiedType::Uint(U8),
|
||||
ty::SimplifiedType::Uint(U16),
|
||||
ty::SimplifiedType::Uint(U32),
|
||||
ty::SimplifiedType::Uint(U64),
|
||||
ty::SimplifiedType::Uint(U128),
|
||||
ty::SimplifiedType::Uint(Usize),
|
||||
];
|
||||
for simp in possible_integers {
|
||||
consider_impls_for_simplified_type(simp);
|
||||
}
|
||||
}
|
||||
|
||||
ty::Infer(ty::FloatVar(_)) => {
|
||||
// This causes a compiler error if any new float kinds are added.
|
||||
let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128);
|
||||
let possible_floats = [
|
||||
ty::SimplifiedType::Float(ty::FloatTy::F16),
|
||||
ty::SimplifiedType::Float(ty::FloatTy::F32),
|
||||
ty::SimplifiedType::Float(ty::FloatTy::F64),
|
||||
ty::SimplifiedType::Float(ty::FloatTy::F128),
|
||||
];
|
||||
|
||||
for simp in possible_floats {
|
||||
consider_impls_for_simplified_type(simp);
|
||||
}
|
||||
}
|
||||
|
||||
// The only traits applying to aliases and placeholders are blanket impls.
|
||||
//
|
||||
// Impls which apply to an alias after normalization are handled by
|
||||
// `assemble_candidates_after_normalizing_self_ty`.
|
||||
ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (),
|
||||
|
||||
// FIXME: These should ideally not exist as a self type. It would be nice for
|
||||
// the builtin auto trait impls of coroutines to instead directly recurse
|
||||
// into the witness.
|
||||
ty::CoroutineWitness(..) => (),
|
||||
|
||||
// These variants should not exist as a self type.
|
||||
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
|
||||
| ty::Param(_)
|
||||
| ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"),
|
||||
}
|
||||
|
||||
#[allow(rustc::usage_of_type_ir_traits)]
|
||||
self.for_each_blanket_impl(trait_def_id, f)
|
||||
}
|
||||
fn for_each_blanket_impl(self, trait_def_id: DefId, mut f: impl FnMut(DefId)) {
|
||||
let trait_impls = self.trait_impls_of(trait_def_id);
|
||||
for &impl_def_id in trait_impls.blanket_impls() {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn has_item_definition(self, def_id: DefId) -> bool {
|
||||
self.defaultness(def_id).has_value()
|
||||
}
|
||||
|
||||
fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool {
|
||||
self.specializes((impl_def_id, victim_def_id))
|
||||
}
|
||||
|
||||
fn impl_is_default(self, impl_def_id: DefId) -> bool {
|
||||
self.defaultness(impl_def_id).is_default()
|
||||
}
|
||||
|
||||
fn impl_trait_ref(self, impl_def_id: DefId) -> ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>> {
|
||||
self.impl_trait_ref(impl_def_id)
|
||||
}
|
||||
|
||||
fn impl_polarity(self, impl_def_id: DefId) -> ty::ImplPolarity {
|
||||
self.impl_polarity(impl_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_auto(self, trait_def_id: DefId) -> bool {
|
||||
self.trait_is_auto(trait_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_coinductive(self, trait_def_id: DefId) -> bool {
|
||||
self.trait_is_coinductive(trait_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_alias(self, trait_def_id: DefId) -> bool {
|
||||
self.trait_is_alias(trait_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_dyn_compatible(self, trait_def_id: DefId) -> bool {
|
||||
self.is_dyn_compatible(trait_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_fundamental(self, def_id: DefId) -> bool {
|
||||
self.trait_def(def_id).is_fundamental
|
||||
}
|
||||
|
||||
fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool {
|
||||
self.trait_def(trait_def_id).safety.is_unsafe()
|
||||
}
|
||||
|
||||
fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
|
||||
self.is_impl_trait_in_trait(def_id)
|
||||
}
|
||||
|
||||
fn delay_bug(self, msg: impl ToString) -> ErrorGuaranteed {
|
||||
self.dcx().span_delayed_bug(DUMMY_SP, msg.to_string())
|
||||
}
|
||||
|
||||
fn is_general_coroutine(self, coroutine_def_id: DefId) -> bool {
|
||||
self.is_general_coroutine(coroutine_def_id)
|
||||
}
|
||||
|
||||
fn coroutine_is_async(self, coroutine_def_id: DefId) -> bool {
|
||||
self.coroutine_is_async(coroutine_def_id)
|
||||
}
|
||||
|
||||
fn coroutine_is_gen(self, coroutine_def_id: DefId) -> bool {
|
||||
self.coroutine_is_gen(coroutine_def_id)
|
||||
}
|
||||
|
||||
fn coroutine_is_async_gen(self, coroutine_def_id: DefId) -> bool {
|
||||
self.coroutine_is_async_gen(coroutine_def_id)
|
||||
}
|
||||
|
||||
type UnsizingParams = &'tcx rustc_index::bit_set::DenseBitSet<u32>;
|
||||
fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams {
|
||||
self.unsizing_params_for_adt(adt_def_id)
|
||||
}
|
||||
|
||||
fn anonymize_bound_vars<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
self,
|
||||
binder: ty::Binder<'tcx, T>,
|
||||
) -> ty::Binder<'tcx, T> {
|
||||
self.anonymize_bound_vars(binder)
|
||||
}
|
||||
|
||||
fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::LocalDefIds {
|
||||
self.opaque_types_defined_by(defining_anchor)
|
||||
}
|
||||
|
||||
fn opaque_types_and_coroutines_defined_by(
|
||||
self,
|
||||
defining_anchor: Self::LocalDefId,
|
||||
) -> Self::LocalDefIds {
|
||||
let coroutines_defined_by = self
|
||||
.nested_bodies_within(defining_anchor)
|
||||
.iter()
|
||||
.filter(|def_id| self.is_coroutine(def_id.to_def_id()));
|
||||
self.mk_local_def_ids_from_iter(
|
||||
self.opaque_types_defined_by(defining_anchor).iter().chain(coroutines_defined_by),
|
||||
)
|
||||
}
|
||||
|
||||
type Probe = &'tcx inspect::Probe<TyCtxt<'tcx>>;
|
||||
fn mk_probe(self, probe: inspect::Probe<Self>) -> &'tcx inspect::Probe<TyCtxt<'tcx>> {
|
||||
self.arena.alloc(probe)
|
||||
}
|
||||
fn evaluate_root_goal_for_proof_tree_raw(
|
||||
self,
|
||||
canonical_goal: CanonicalInput<'tcx>,
|
||||
) -> (QueryResult<'tcx>, &'tcx inspect::Probe<TyCtxt<'tcx>>) {
|
||||
self.evaluate_root_goal_for_proof_tree_raw(canonical_goal)
|
||||
}
|
||||
|
||||
fn item_name(self, id: DefId) -> Symbol {
|
||||
let id = id.into_query_param();
|
||||
self.opt_item_name(id).unwrap_or_else(|| {
|
||||
bug!("item_name: no name for {:?}", self.def_path(id));
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines trivial conversion functions between the main [`LangItem`] enum,
|
||||
/// and some other lang-item enum that is a subset of it.
|
||||
macro_rules! bidirectional_lang_item_map {
|
||||
(
|
||||
$solver_ty:ident, fn $to_solver:ident, fn $from_solver:ident;
|
||||
$($name:ident),+ $(,)?
|
||||
) => {
|
||||
fn $from_solver(lang_item: $solver_ty) -> LangItem {
|
||||
match lang_item {
|
||||
$($solver_ty::$name => LangItem::$name,)+
|
||||
}
|
||||
}
|
||||
|
||||
fn $to_solver(lang_item: LangItem) -> Option<$solver_ty> {
|
||||
Some(match lang_item {
|
||||
$(LangItem::$name => $solver_ty::$name,)+
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bidirectional_lang_item_map! {
|
||||
SolverLangItem, fn lang_item_to_solver_lang_item, fn solver_lang_item_to_lang_item;
|
||||
|
||||
// tidy-alphabetical-start
|
||||
AsyncFnKindUpvars,
|
||||
AsyncFnOnceOutput,
|
||||
CallOnceFuture,
|
||||
CallRefFuture,
|
||||
CoroutineReturn,
|
||||
CoroutineYield,
|
||||
DynMetadata,
|
||||
FutureOutput,
|
||||
Metadata,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
bidirectional_lang_item_map! {
|
||||
SolverAdtLangItem, fn lang_item_to_solver_adt_lang_item, fn solver_adt_lang_item_to_lang_item;
|
||||
|
||||
// tidy-alphabetical-start
|
||||
Option,
|
||||
Poll,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
bidirectional_lang_item_map! {
|
||||
SolverTraitLangItem, fn lang_item_to_solver_trait_lang_item, fn solver_trait_lang_item_to_lang_item;
|
||||
|
||||
// tidy-alphabetical-start
|
||||
AsyncFn,
|
||||
AsyncFnKindHelper,
|
||||
AsyncFnMut,
|
||||
AsyncFnOnce,
|
||||
AsyncFnOnceOutput,
|
||||
AsyncIterator,
|
||||
BikeshedGuaranteedNoDrop,
|
||||
Clone,
|
||||
Copy,
|
||||
Coroutine,
|
||||
Destruct,
|
||||
DiscriminantKind,
|
||||
Drop,
|
||||
Fn,
|
||||
FnMut,
|
||||
FnOnce,
|
||||
FnPtrTrait,
|
||||
FusedIterator,
|
||||
Future,
|
||||
Iterator,
|
||||
MetaSized,
|
||||
PointeeSized,
|
||||
PointeeTrait,
|
||||
Sized,
|
||||
TransmuteTrait,
|
||||
TrivialClone,
|
||||
Tuple,
|
||||
Unpin,
|
||||
Unsize,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
|
@ -2,8 +2,7 @@ use rustc_macros::HashStable;
|
|||
use smallvec::SmallVec;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::ty::context::TyCtxt;
|
||||
use crate::ty::{self, DefId, OpaqueTypeKey, Ty, TypingEnv};
|
||||
use crate::ty::{self, DefId, OpaqueTypeKey, Ty, TyCtxt, TypingEnv};
|
||||
|
||||
/// Represents whether some type is inhabited in a given context.
|
||||
/// Examples of uninhabited types are `!`, `enum Void {}`, or a struct
|
||||
|
|
|
|||
|
|
@ -47,8 +47,7 @@ use rustc_type_ir::TyKind::*;
|
|||
use tracing::instrument;
|
||||
|
||||
use crate::query::Providers;
|
||||
use crate::ty::context::TyCtxt;
|
||||
use crate::ty::{self, DefId, Ty, TypeVisitableExt, VariantDef, Visibility};
|
||||
use crate::ty::{self, DefId, Ty, TyCtxt, TypeVisitableExt, VariantDef, Visibility};
|
||||
|
||||
pub mod inhabited_predicate;
|
||||
|
||||
|
|
|
|||
|
|
@ -49,10 +49,6 @@ impl<'tcx> rustc_type_ir::inherent::Predicate<TyCtxt<'tcx>> for Predicate<'tcx>
|
|||
fn as_clause(self) -> Option<ty::Clause<'tcx>> {
|
||||
self.as_clause()
|
||||
}
|
||||
|
||||
fn allow_normalization(self) -> bool {
|
||||
self.allow_normalization()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::IntoKind for Predicate<'tcx> {
|
||||
|
|
@ -121,25 +117,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
/// unsoundly accept some programs. See #91068.
|
||||
#[inline]
|
||||
pub fn allow_normalization(self) -> bool {
|
||||
match self.kind().skip_binder() {
|
||||
PredicateKind::Clause(ClauseKind::WellFormed(_)) | PredicateKind::AliasRelate(..) => {
|
||||
false
|
||||
}
|
||||
PredicateKind::Clause(ClauseKind::Trait(_))
|
||||
| PredicateKind::Clause(ClauseKind::HostEffect(..))
|
||||
| PredicateKind::Clause(ClauseKind::RegionOutlives(_))
|
||||
| PredicateKind::Clause(ClauseKind::TypeOutlives(_))
|
||||
| PredicateKind::Clause(ClauseKind::Projection(_))
|
||||
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
|
||||
| PredicateKind::Clause(ClauseKind::UnstableFeature(_))
|
||||
| PredicateKind::DynCompatible(_)
|
||||
| PredicateKind::Subtype(_)
|
||||
| PredicateKind::Coerce(_)
|
||||
| PredicateKind::Clause(ClauseKind::ConstEvaluatable(_))
|
||||
| PredicateKind::ConstEquate(_, _)
|
||||
| PredicateKind::NormalizesTo(..)
|
||||
| PredicateKind::Ambiguous => true,
|
||||
}
|
||||
rustc_type_ir::inherent::Predicate::allow_normalization(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
|
|||
use rustc_session::lint::Level;
|
||||
use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
|
||||
use rustc_span::def_id::{DefId, LocalDefId};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use crate::builder::ExprCategory;
|
||||
use crate::errors::*;
|
||||
|
|
@ -98,29 +98,14 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
|||
// from an edition before 2024.
|
||||
&UnsafeOpKind::CallToUnsafeFunction(Some(id))
|
||||
if !span.at_least_rust_2024()
|
||||
&& let Some(attr) = self.tcx.get_attr(id, sym::rustc_deprecated_safe_2024) =>
|
||||
&& let Some(suggestion) = find_attr!(self.tcx.get_all_attrs(id), AttributeKind::RustcDeprecatedSafe2024{suggestion} => suggestion) =>
|
||||
{
|
||||
let suggestion = attr
|
||||
.meta_item_list()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.find(|item| item.has_name(sym::audit_that))
|
||||
.map(|item| {
|
||||
item.value_str().expect(
|
||||
"`#[rustc_deprecated_safe_2024(audit_that)]` must have a string value",
|
||||
)
|
||||
});
|
||||
|
||||
let sm = self.tcx.sess.source_map();
|
||||
let guarantee = suggestion
|
||||
.as_ref()
|
||||
.map(|suggestion| format!("that {}", suggestion))
|
||||
.unwrap_or_else(|| String::from("its unsafe preconditions"));
|
||||
let suggestion = suggestion
|
||||
.and_then(|suggestion| {
|
||||
sm.indentation_before(span).map(|indent| {
|
||||
format!("{}// TODO: Audit that {}.\n", indent, suggestion) // ignore-tidy-todo
|
||||
})
|
||||
let guarantee = format!("that {}", suggestion);
|
||||
let suggestion = sm
|
||||
.indentation_before(span)
|
||||
.map(|indent| {
|
||||
format!("{}// TODO: Audit that {}.\n", indent, suggestion) // ignore-tidy-todo
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
|||
use rustc_middle::mir::{Body, TerminatorKind};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::pass_manager::MirLint;
|
||||
|
||||
|
|
@ -42,7 +41,8 @@ pub(super) fn is_inline_valid_on_fn<'tcx>(
|
|||
def_id: DefId,
|
||||
) -> Result<(), &'static str> {
|
||||
let codegen_attrs = tcx.codegen_fn_attrs(def_id);
|
||||
if tcx.has_attr(def_id, sym::rustc_no_mir_inline) {
|
||||
|
||||
if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::RustcNoMirInline) {
|
||||
return Err("#[rustc_no_mir_inline]");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -294,15 +294,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::RustcAsPtr(..)
|
||||
| AttributeKind::RustcBodyStability { .. }
|
||||
| AttributeKind::RustcBuiltinMacro { .. }
|
||||
| AttributeKind::RustcCaptureAnalysis
|
||||
| AttributeKind::RustcCguTestAttr(..)
|
||||
| AttributeKind::RustcClean(..)
|
||||
| AttributeKind::RustcCoherenceIsCore(..)
|
||||
| AttributeKind::RustcCoinductive(..)
|
||||
| AttributeKind::RustcConfusables { .. }
|
||||
| AttributeKind::RustcConstStabilityIndirect
|
||||
| AttributeKind::RustcConversionSuggestion
|
||||
| AttributeKind::RustcDeallocator
|
||||
| AttributeKind::RustcDefPath(..)
|
||||
| AttributeKind::RustcDelayedBugFromInsideQuery
|
||||
| AttributeKind::RustcDenyExplicitImpl(..)
|
||||
| AttributeKind::RustcDeprecatedSafe2024 {..}
|
||||
| AttributeKind::RustcDummy
|
||||
| AttributeKind::RustcDumpDefParents
|
||||
| AttributeKind::RustcDumpItemBounds
|
||||
|
|
@ -329,8 +333,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::RustcMain
|
||||
| AttributeKind::RustcMir(_)
|
||||
| AttributeKind::RustcNeverReturnsNullPointer
|
||||
| AttributeKind::RustcNeverTypeOptions {..}
|
||||
| AttributeKind::RustcNoImplicitAutorefs
|
||||
| AttributeKind::RustcNoImplicitBounds
|
||||
| AttributeKind::RustcNoMirInline
|
||||
| AttributeKind::RustcNonConstTraitMethod
|
||||
| AttributeKind::RustcNounwind
|
||||
| AttributeKind::RustcObjcClass { .. }
|
||||
|
|
@ -353,6 +359,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::RustcStrictCoherence(..)
|
||||
| AttributeKind::RustcSymbolName(..)
|
||||
| AttributeKind::RustcThenThisWouldNeed(..)
|
||||
| AttributeKind::RustcTrivialFieldReads
|
||||
| AttributeKind::RustcUnsafeSpecializationMarker(..)
|
||||
| AttributeKind::RustcVariance
|
||||
| AttributeKind::RustcVarianceOfOpaques
|
||||
|
|
@ -391,25 +398,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| sym::lang
|
||||
| sym::default_lib_allocator
|
||||
| sym::rustc_diagnostic_item
|
||||
| sym::rustc_no_mir_inline
|
||||
| sym::rustc_nonnull_optimization_guaranteed
|
||||
| sym::rustc_inherit_overflow_checks
|
||||
| sym::rustc_trivial_field_reads
|
||||
| sym::rustc_on_unimplemented
|
||||
| sym::rustc_do_not_const_check
|
||||
| sym::rustc_doc_primitive
|
||||
| sym::rustc_conversion_suggestion
|
||||
| sym::rustc_deprecated_safe_2024
|
||||
| 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
|
||||
| sym::rustc_partition_reused
|
||||
| sym::rustc_partition_codegened
|
||||
| sym::rustc_expected_cgu_reuse
|
||||
// crate-level attrs, are checked below
|
||||
| sym::feature
|
||||
| sym::register_tool
|
||||
|
|
|
|||
|
|
@ -10,10 +10,11 @@ use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
|
|||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{ErrorGuaranteed, MultiSpan};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{self as hir, Node, PatKind, QPath};
|
||||
use rustc_hir::{self as hir, Node, PatKind, QPath, find_attr};
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::middle::privacy::Level;
|
||||
use rustc_middle::query::Providers;
|
||||
|
|
@ -380,7 +381,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
&& let impl_of = self.tcx.parent(impl_item.owner_id.to_def_id())
|
||||
&& self.tcx.is_automatically_derived(impl_of)
|
||||
&& let trait_ref = self.tcx.impl_trait_ref(impl_of).instantiate_identity()
|
||||
&& self.tcx.has_attr(trait_ref.def_id, sym::rustc_trivial_field_reads)
|
||||
&& find_attr!(
|
||||
self.tcx.get_all_attrs(trait_ref.def_id),
|
||||
AttributeKind::RustcTrivialFieldReads
|
||||
)
|
||||
{
|
||||
if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
|
||||
&& let Some(adt_def_id) = adt_def.did().as_local()
|
||||
|
|
|
|||
|
|
@ -373,7 +373,6 @@ symbols! {
|
|||
Str,
|
||||
String,
|
||||
StructuralPartialEq,
|
||||
SubdiagMessage,
|
||||
Subdiagnostic,
|
||||
SymbolIntern,
|
||||
Sync,
|
||||
|
|
|
|||
|
|
@ -277,6 +277,28 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
|
||||
|
||||
let trait_def_id = main_trait_predicate.def_id();
|
||||
if self.tcx.is_diagnostic_item(sym::From, trait_def_id)
|
||||
|| self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id)
|
||||
{
|
||||
let found_ty = leaf_trait_predicate.skip_binder().trait_ref.args.type_at(1);
|
||||
let ty = main_trait_predicate.skip_binder().self_ty();
|
||||
if let Some(cast_ty) = self.find_explicit_cast_type(
|
||||
obligation.param_env,
|
||||
found_ty,
|
||||
ty,
|
||||
) {
|
||||
let found_ty_str = self.tcx.short_string(found_ty, &mut long_ty_file);
|
||||
let cast_ty_str = self.tcx.short_string(cast_ty, &mut long_ty_file);
|
||||
err.help(
|
||||
format!(
|
||||
"consider casting the `{found_ty_str}` value to `{cast_ty_str}`",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
*err.long_ty_path() = long_ty_file;
|
||||
|
||||
let mut suggested = false;
|
||||
|
|
@ -2932,6 +2954,69 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// If `found_ty` is a reference that can be explicitly cast to another reference type for which
|
||||
/// a `From` / `TryFrom` impl exists for `self_ty`, return that type.
|
||||
fn find_explicit_cast_type(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
found_ty: Ty<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
let ty::Ref(region, inner_ty, mutbl) = *found_ty.kind() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut derefs = (self.autoderef_steps)(inner_ty).into_iter();
|
||||
derefs.next(); // skip the first one, which is inner_ty itself
|
||||
let deref_target = derefs.into_iter().next()?.0;
|
||||
|
||||
let cast_ty = Ty::new_ref(self.tcx, region, deref_target, mutbl);
|
||||
|
||||
let Some(from_def_id) = self.tcx.get_diagnostic_item(sym::From) else {
|
||||
return None;
|
||||
};
|
||||
let Some(try_from_def_id) = self.tcx.get_diagnostic_item(sym::TryFrom) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if self.has_impl_for_type(
|
||||
param_env,
|
||||
ty::TraitRef::new(
|
||||
self.tcx,
|
||||
from_def_id,
|
||||
self.tcx.mk_args(&[self_ty.into(), cast_ty.into()]),
|
||||
),
|
||||
) {
|
||||
Some(cast_ty)
|
||||
} else if self.has_impl_for_type(
|
||||
param_env,
|
||||
ty::TraitRef::new(
|
||||
self.tcx,
|
||||
try_from_def_id,
|
||||
self.tcx.mk_args(&[self_ty.into(), cast_ty.into()]),
|
||||
),
|
||||
) {
|
||||
Some(cast_ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn has_impl_for_type(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> bool {
|
||||
let obligation = Obligation::new(
|
||||
self.tcx,
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Positive },
|
||||
);
|
||||
|
||||
self.predicate_must_hold_modulo_regions(&obligation)
|
||||
}
|
||||
|
||||
fn add_tuple_trait_message(
|
||||
&self,
|
||||
obligation_cause_code: &ObligationCauseCode<'tcx>,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use crate::fold::{TypeFoldable, TypeSuperFoldable};
|
|||
use crate::relate::Relate;
|
||||
use crate::solve::{AdtDestructorKind, SizedTraitKind};
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||
use crate::{self as ty, CollectAndApply, Interner, UpcastFrom};
|
||||
use crate::{self as ty, ClauseKind, CollectAndApply, Interner, PredicateKind, UpcastFrom};
|
||||
|
||||
pub trait Ty<I: Interner<Ty = Self>>:
|
||||
Copy
|
||||
|
|
@ -478,8 +478,27 @@ pub trait Predicate<I: Interner<Predicate = Self>>:
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Eventually uplift the impl out of rustc and make this defaulted.
|
||||
fn allow_normalization(self) -> bool;
|
||||
fn allow_normalization(self) -> bool {
|
||||
match self.kind().skip_binder() {
|
||||
PredicateKind::Clause(ClauseKind::WellFormed(_)) | PredicateKind::AliasRelate(..) => {
|
||||
false
|
||||
}
|
||||
PredicateKind::Clause(ClauseKind::Trait(_))
|
||||
| PredicateKind::Clause(ClauseKind::HostEffect(..))
|
||||
| PredicateKind::Clause(ClauseKind::RegionOutlives(_))
|
||||
| PredicateKind::Clause(ClauseKind::TypeOutlives(_))
|
||||
| PredicateKind::Clause(ClauseKind::Projection(_))
|
||||
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
|
||||
| PredicateKind::Clause(ClauseKind::UnstableFeature(_))
|
||||
| PredicateKind::DynCompatible(_)
|
||||
| PredicateKind::Subtype(_)
|
||||
| PredicateKind::Coerce(_)
|
||||
| PredicateKind::Clause(ClauseKind::ConstEvaluatable(_))
|
||||
| PredicateKind::ConstEquate(_, _)
|
||||
| PredicateKind::NormalizesTo(..)
|
||||
| PredicateKind::Ambiguous => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Clause<I: Interner<Clause = Self>>:
|
||||
|
|
|
|||
|
|
@ -135,8 +135,7 @@ translation.
|
|||
### Messages
|
||||
|
||||
All of rustc's traditional diagnostic APIs (e.g. `struct_span_err` or `note`)
|
||||
take any message that can be converted into a `DiagMessage` (or
|
||||
`SubdiagMessage`).
|
||||
take any message that can be converted into a `DiagMessage`.
|
||||
|
||||
[`rustc_error_messages::DiagMessage`] can represent legacy non-translatable
|
||||
diagnostic messages and translatable messages. Non-translatable messages are
|
||||
|
|
@ -149,14 +148,7 @@ with an attribute).
|
|||
Fluent resource (described in more detail below), or `DiagMessage`s will
|
||||
either be created in the macro-generated code of a diagnostic derive.
|
||||
|
||||
`rustc_error_messages::SubdiagMessage` is similar, it can correspond to a
|
||||
legacy non-translatable diagnostic message or the name of an attribute to a
|
||||
Fluent message. Translatable `SubdiagMessage`s must be combined with a
|
||||
`DiagMessage` (using `DiagMessage::with_subdiagnostic_message`) to
|
||||
be emitted (an attribute name on its own is meaningless without a corresponding
|
||||
message identifier, which is what `DiagMessage` provides).
|
||||
|
||||
Both `DiagMessage` and `SubdiagMessage` implement `Into` for any
|
||||
`DiagMessage` implements `Into` for any
|
||||
type that can be converted into a string, and converts these into
|
||||
non-translatable diagnostics - this keeps all existing diagnostic calls
|
||||
working.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
//! Thank you!
|
||||
//! ~The `INTERNAL_METADATA_COLLECTOR` lint
|
||||
|
||||
use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan, SubdiagMessage};
|
||||
use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan};
|
||||
#[cfg(debug_assertions)]
|
||||
use rustc_errors::{EmissionGuarantee, SubstitutionPart, Suggestions};
|
||||
use rustc_hir::HirId;
|
||||
|
|
@ -155,7 +155,7 @@ pub fn span_lint_and_help<T: LintContext>(
|
|||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
help_span: Option<Span>,
|
||||
help: impl Into<SubdiagMessage>,
|
||||
help: impl Into<DiagMessage>,
|
||||
) {
|
||||
#[expect(clippy::disallowed_methods)]
|
||||
cx.span_lint(lint, span, |diag| {
|
||||
|
|
@ -216,7 +216,7 @@ pub fn span_lint_and_note<T: LintContext>(
|
|||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
note_span: Option<Span>,
|
||||
note: impl Into<SubdiagMessage>,
|
||||
note: impl Into<DiagMessage>,
|
||||
) {
|
||||
#[expect(clippy::disallowed_methods)]
|
||||
cx.span_lint(lint, span, |diag| {
|
||||
|
|
@ -390,7 +390,7 @@ pub fn span_lint_and_sugg<T: LintContext>(
|
|||
lint: &'static Lint,
|
||||
sp: Span,
|
||||
msg: impl Into<DiagMessage>,
|
||||
help: impl Into<SubdiagMessage>,
|
||||
help: impl Into<DiagMessage>,
|
||||
sugg: String,
|
||||
applicability: Applicability,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -385,8 +385,33 @@ pub(crate) fn format_expr(
|
|||
))
|
||||
}
|
||||
}
|
||||
// FIXME: heterogeneous try blocks, which include a type so are harder to format
|
||||
ast::ExprKind::TryBlock(_, Some(_)) => Err(RewriteError::Unknown),
|
||||
ast::ExprKind::TryBlock(ref block, Some(ref ty)) => {
|
||||
let keyword = "try bikeshed ";
|
||||
// 2 = " {".len()
|
||||
let ty_shape = shape
|
||||
.shrink_left(keyword.len())
|
||||
.and_then(|shape| shape.sub_width(2))
|
||||
.max_width_error(shape.width, expr.span)?;
|
||||
let ty_str = ty.rewrite_result(context, ty_shape)?;
|
||||
let prefix = format!("{keyword}{ty_str} ");
|
||||
if let rw @ Ok(_) =
|
||||
rewrite_single_line_block(context, &prefix, block, Some(&expr.attrs), None, shape)
|
||||
{
|
||||
rw
|
||||
} else {
|
||||
let budget = shape.width.saturating_sub(prefix.len());
|
||||
Ok(format!(
|
||||
"{prefix}{}",
|
||||
rewrite_block(
|
||||
block,
|
||||
Some(&expr.attrs),
|
||||
None,
|
||||
context,
|
||||
Shape::legacy(budget, shape.indent)
|
||||
)?
|
||||
))
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Gen(capture_by, ref block, ref kind, _) => {
|
||||
let mover = if matches!(capture_by, ast::CaptureBy::Value { .. }) {
|
||||
"move "
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// rustfmt-edition: 2018
|
||||
#![feature(try_blocks)]
|
||||
|
||||
fn main() -> Result<(), !> {
|
||||
let _x: Option<_> = try {
|
||||
|
|
|
|||
39
src/tools/rustfmt/tests/source/try_blocks_heterogeneous.rs
Normal file
39
src/tools/rustfmt/tests/source/try_blocks_heterogeneous.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// rustfmt-edition: 2018
|
||||
#![feature(try_blocks_heterogeneous)]
|
||||
|
||||
fn main() -> Result<(), !> {
|
||||
let _x = try bikeshed Option<_> {
|
||||
4
|
||||
};
|
||||
|
||||
try bikeshed Result<_, _> {}
|
||||
}
|
||||
|
||||
fn baz() -> Option<i32> {
|
||||
if (1 == 1) {
|
||||
return try bikeshed Option<i32> {
|
||||
5
|
||||
};
|
||||
}
|
||||
|
||||
// test
|
||||
let x = try bikeshed Option<()> {
|
||||
// try blocks are great
|
||||
};
|
||||
|
||||
let y = try bikeshed Option<i32> {
|
||||
6
|
||||
}; // comment
|
||||
|
||||
let x = try /* Invisible comment */ bikeshed Option<()> {};
|
||||
let x = try bikeshed /* Invisible comment */ Option<()> {};
|
||||
let x = try bikeshed Option<()> /* Invisible comment */ {};
|
||||
|
||||
let x = try bikeshed Option<i32> { baz()?; baz()?; baz()?; 7 };
|
||||
|
||||
let x = try bikeshed Foo<Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar> { 1 + 1 + 1 };
|
||||
|
||||
let x = try bikeshed Foo<Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar> {};
|
||||
|
||||
return None;
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
// rustfmt-edition: 2018
|
||||
#![feature(try_blocks)]
|
||||
|
||||
fn main() -> Result<(), !> {
|
||||
let _x: Option<_> = try { 4 };
|
||||
|
|
|
|||
41
src/tools/rustfmt/tests/target/try_blocks_heterogeneous.rs
Normal file
41
src/tools/rustfmt/tests/target/try_blocks_heterogeneous.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// rustfmt-edition: 2018
|
||||
#![feature(try_blocks_heterogeneous)]
|
||||
|
||||
fn main() -> Result<(), !> {
|
||||
let _x = try bikeshed Option<_> { 4 };
|
||||
|
||||
try bikeshed Result<_, _> {}
|
||||
}
|
||||
|
||||
fn baz() -> Option<i32> {
|
||||
if (1 == 1) {
|
||||
return try bikeshed Option<i32> { 5 };
|
||||
}
|
||||
|
||||
// test
|
||||
let x = try bikeshed Option<()> {
|
||||
// try blocks are great
|
||||
};
|
||||
|
||||
let y = try bikeshed Option<i32> { 6 }; // comment
|
||||
|
||||
let x = try /* Invisible comment */ bikeshed Option<()> {};
|
||||
let x = try bikeshed /* Invisible comment */ Option<()> {};
|
||||
let x = try bikeshed Option<()> /* Invisible comment */ {};
|
||||
|
||||
let x = try bikeshed Option<i32> {
|
||||
baz()?;
|
||||
baz()?;
|
||||
baz()?;
|
||||
7
|
||||
};
|
||||
|
||||
let x = try bikeshed Foo<Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar> {
|
||||
1 + 1 + 1
|
||||
};
|
||||
|
||||
let x =
|
||||
try bikeshed Foo<Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar> {};
|
||||
|
||||
return None;
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ extern crate rustc_session;
|
|||
extern crate rustc_span;
|
||||
extern crate core;
|
||||
|
||||
use rustc_errors::{Applicability, DiagMessage, SubdiagMessage};
|
||||
use rustc_errors::{Applicability, DiagMessage};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::Span;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ extern crate rustc_middle;
|
|||
use rustc_middle::ty::Ty;
|
||||
|
||||
extern crate rustc_errors;
|
||||
use rustc_errors::{Applicability, DiagMessage, ErrCode, MultiSpan, SubdiagMessage};
|
||||
use rustc_errors::{Applicability, DiagMessage, ErrCode, MultiSpan};
|
||||
|
||||
extern crate rustc_session;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ extern crate rustc_session;
|
|||
extern crate rustc_span;
|
||||
extern crate core;
|
||||
|
||||
use rustc_errors::{Applicability, DiagMessage, SubdiagMessage};
|
||||
use rustc_errors::{Applicability, DiagMessage};
|
||||
use rustc_macros::Subdiagnostic;
|
||||
use rustc_span::Span;
|
||||
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ struct Ref2<'a,'b:'a,T:'a+'b+?Sized> {
|
|||
}
|
||||
|
||||
fn a<'a,'b>(t: Ref2<'a,'b, dyn Test>) {
|
||||
//~^ ERROR lifetime bound for this object type cannot be deduced from context
|
||||
//~^ ERROR cannot deduce the lifetime bound for this trait object type
|
||||
}
|
||||
|
||||
fn b(t: Ref2<dyn Test>) {
|
||||
//~^ ERROR lifetime bound for this object type cannot be deduced from context
|
||||
//~^ ERROR cannot deduce the lifetime bound for this trait object type
|
||||
}
|
||||
|
||||
fn c(t: Ref2<&dyn Test>) {
|
||||
|
|
@ -41,7 +41,7 @@ fn e(t: Ref2<Ref0<dyn Test>>) {
|
|||
}
|
||||
|
||||
fn f(t: &Ref2<dyn Test>) {
|
||||
//~^ ERROR lifetime bound for this object type cannot be deduced from context
|
||||
//~^ ERROR cannot deduce the lifetime bound for this trait object type
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,35 @@
|
|||
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
|
||||
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
|
||||
--> $DIR/object-lifetime-default-ambiguous.rs:23:28
|
||||
|
|
||||
LL | fn a<'a,'b>(t: Ref2<'a,'b, dyn Test>) {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: please supply an explicit bound
|
||||
|
|
||||
LL | fn a<'a,'b>(t: Ref2<'a,'b, dyn Test + /* 'a */>) {
|
||||
| ++++++++++
|
||||
|
||||
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
|
||||
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
|
||||
--> $DIR/object-lifetime-default-ambiguous.rs:27:14
|
||||
|
|
||||
LL | fn b(t: Ref2<dyn Test>) {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: please supply an explicit bound
|
||||
|
|
||||
LL | fn b(t: Ref2<dyn Test + /* 'a */>) {
|
||||
| ++++++++++
|
||||
|
||||
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
|
||||
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
|
||||
--> $DIR/object-lifetime-default-ambiguous.rs:43:15
|
||||
|
|
||||
LL | fn f(t: &Ref2<dyn Test>) {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: please supply an explicit bound
|
||||
|
|
||||
LL | fn f(t: &Ref2<dyn Test + /* 'a */>) {
|
||||
| ++++++++++
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ fn is_static<T>(_: T) where T: 'static { }
|
|||
// Here, we should default to `dyn Bar + 'static`, but the current
|
||||
// code forces us into a conservative, hacky path.
|
||||
fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
|
||||
//~^ ERROR please supply an explicit bound
|
||||
//~^ ERROR cannot deduce the lifetime bound for this trait object type
|
||||
|
||||
fn main() {
|
||||
let s = format!("foo");
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
|
||||
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
|
||||
--> $DIR/object-lifetime-default-dyn-binding-nonstatic1.rs:20:50
|
||||
|
|
||||
LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: please supply an explicit bound
|
||||
|
|
||||
LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar + /* 'a */> { &() }
|
||||
| ++++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ fn is_static<T>(_: T) where T: 'static { }
|
|||
// Here, we default to `dyn Bar + 'a`. Or, we *should*, but the
|
||||
// current code forces us into a conservative, hacky path.
|
||||
fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
|
||||
//~^ ERROR please supply an explicit bound
|
||||
//~^ ERROR cannot deduce the lifetime bound for this trait object type
|
||||
|
||||
fn main() {
|
||||
let s = format!("foo");
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
|
||||
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
|
||||
--> $DIR/object-lifetime-default-dyn-binding-nonstatic2.rs:20:50
|
||||
|
|
||||
LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: please supply an explicit bound
|
||||
|
|
||||
LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar + /* 'a */> { &() }
|
||||
| ++++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ fn is_static<T>(_: T) where T: 'static { }
|
|||
// Here, we should default to `dyn Bar + 'static`, but the current
|
||||
// code forces us into a conservative, hacky path.
|
||||
fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
|
||||
//~^ ERROR please supply an explicit bound
|
||||
//~^ ERROR cannot deduce the lifetime bound for this trait object type
|
||||
|
||||
fn main() {
|
||||
let s = format!("foo");
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
|
||||
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
|
||||
--> $DIR/object-lifetime-default-dyn-binding-nonstatic3.rs:16:36
|
||||
|
|
||||
LL | fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: please supply an explicit bound
|
||||
|
|
||||
LL | fn bar(x: &str) -> &dyn Foo<Item = dyn Bar + /* 'a */> { &() }
|
||||
| ++++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
50
tests/ui/traits/explicit-reference-cast.rs
Normal file
50
tests/ui/traits/explicit-reference-cast.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// compile-fail
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub struct ToolA(PathBuf);
|
||||
//~^ HELP the trait `From<&PathBuf>` is not implemented for `ToolA`
|
||||
|
||||
impl From<&Path> for ToolA {
|
||||
//~^ HELP the following other types implement trait `From<T>`
|
||||
fn from(p: &Path) -> ToolA {
|
||||
ToolA(p.to_path_buf())
|
||||
}
|
||||
}
|
||||
|
||||
// Add a different From<T> impl to ensure we suggest the correct cast
|
||||
impl From<&str> for ToolA {
|
||||
fn from(s: &str) -> ToolA {
|
||||
ToolA(PathBuf::from(s))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ToolB(PathBuf);
|
||||
//~^ HELP the trait `From<&PathBuf>` is not implemented for `ToolB`
|
||||
//~| HELP the trait `From<&PathBuf>` is not implemented for `ToolB`
|
||||
|
||||
impl TryFrom<&Path> for ToolB {
|
||||
//~^ HELP the trait `TryFrom<&PathBuf>` is not implemented for `ToolB`
|
||||
//~| HELP the trait `TryFrom<&PathBuf>` is not implemented for `ToolB`
|
||||
type Error = ();
|
||||
|
||||
fn try_from(p: &Path) -> Result<ToolB, ()> {
|
||||
Ok(ToolB(p.to_path_buf()))
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let path = PathBuf::new();
|
||||
|
||||
let _ = ToolA::from(&path);
|
||||
//~^ ERROR the trait bound `ToolA: From<&PathBuf>` is not satisfied
|
||||
//~| HELP consider casting the `&PathBuf` value to `&Path`
|
||||
let _ = ToolB::try_from(&path);
|
||||
//~^ ERROR the trait bound `ToolB: TryFrom<&PathBuf>` is not satisfied
|
||||
//~| ERROR the trait bound `ToolB: From<&PathBuf>` is not satisfied
|
||||
//~| HELP consider casting the `&PathBuf` value to `&Path`
|
||||
//~| HELP consider casting the `&PathBuf` value to `&Path`
|
||||
//~| HELP for that trait implementation, expected `Path`, found `PathBuf`
|
||||
//~| HELP for that trait implementation, expected `Path`, found `PathBuf`
|
||||
}
|
||||
68
tests/ui/traits/explicit-reference-cast.stderr
Normal file
68
tests/ui/traits/explicit-reference-cast.stderr
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
error[E0277]: the trait bound `ToolA: From<&PathBuf>` is not satisfied
|
||||
--> $DIR/explicit-reference-cast.rs:40:13
|
||||
|
|
||||
LL | let _ = ToolA::from(&path);
|
||||
| ^^^^^ unsatisfied trait bound
|
||||
|
|
||||
= help: consider casting the `&PathBuf` value to `&Path`
|
||||
help: the trait `From<&PathBuf>` is not implemented for `ToolA`
|
||||
--> $DIR/explicit-reference-cast.rs:6:1
|
||||
|
|
||||
LL | pub struct ToolA(PathBuf);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
help: the following other types implement trait `From<T>`
|
||||
--> $DIR/explicit-reference-cast.rs:9:1
|
||||
|
|
||||
LL | impl From<&Path> for ToolA {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `ToolA` implements `From<&Path>`
|
||||
...
|
||||
LL | impl From<&str> for ToolA {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ `ToolA` implements `From<&str>`
|
||||
|
||||
error[E0277]: the trait bound `ToolB: TryFrom<&PathBuf>` is not satisfied
|
||||
--> $DIR/explicit-reference-cast.rs:43:13
|
||||
|
|
||||
LL | let _ = ToolB::try_from(&path);
|
||||
| ^^^^^ unsatisfied trait bound
|
||||
|
|
||||
= help: consider casting the `&PathBuf` value to `&Path`
|
||||
help: the trait `From<&PathBuf>` is not implemented for `ToolB`
|
||||
--> $DIR/explicit-reference-cast.rs:23:1
|
||||
|
|
||||
LL | pub struct ToolB(PathBuf);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
help: the trait `TryFrom<&PathBuf>` is not implemented for `ToolB`
|
||||
but trait `TryFrom<&Path>` is implemented for it
|
||||
--> $DIR/explicit-reference-cast.rs:27:1
|
||||
|
|
||||
LL | impl TryFrom<&Path> for ToolB {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: for that trait implementation, expected `Path`, found `PathBuf`
|
||||
= note: required for `&PathBuf` to implement `Into<ToolB>`
|
||||
= note: required for `ToolB` to implement `TryFrom<&PathBuf>`
|
||||
|
||||
error[E0277]: the trait bound `ToolB: From<&PathBuf>` is not satisfied
|
||||
--> $DIR/explicit-reference-cast.rs:43:13
|
||||
|
|
||||
LL | let _ = ToolB::try_from(&path);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
||||
|
|
||||
= help: consider casting the `&PathBuf` value to `&Path`
|
||||
help: the trait `From<&PathBuf>` is not implemented for `ToolB`
|
||||
--> $DIR/explicit-reference-cast.rs:23:1
|
||||
|
|
||||
LL | pub struct ToolB(PathBuf);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
help: the trait `TryFrom<&PathBuf>` is not implemented for `ToolB`
|
||||
but trait `TryFrom<&Path>` is implemented for it
|
||||
--> $DIR/explicit-reference-cast.rs:27:1
|
||||
|
|
||||
LL | impl TryFrom<&Path> for ToolB {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: for that trait implementation, expected `Path`, found `PathBuf`
|
||||
= note: required for `&PathBuf` to implement `Into<ToolB>`
|
||||
= note: required for `ToolB` to implement `TryFrom<&PathBuf>`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue