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:
bors 2026-02-10 12:04:24 +00:00
commit d00ba92259
63 changed files with 1923 additions and 1435 deletions

View file

@ -3687,7 +3687,6 @@ dependencies = [
"serde_json",
"smallvec",
"tempfile",
"thin-vec",
"thorin-dwp",
"tracing",
"wasm-encoder 0.219.2",

View file

@ -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(&[

View file

@ -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(&[

View file

@ -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) {

View file

@ -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),

View file

@ -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>>,

View file

@ -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 {

View file

@ -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"

View file

@ -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");

View file

@ -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 {

View file

@ -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 {

View file

@ -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);
}

View file

@ -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) {

View file

@ -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),

View file

@ -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,

View file

@ -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")

View file

@ -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

View file

@ -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,

View file

@ -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)
},
);

View file

@ -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.

View file

@ -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();

View file

@ -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()
}

View file

@ -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>,

View file

@ -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_;

View file

@ -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(

View file

@ -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)

View file

@ -63,7 +63,6 @@
#![allow(unused_parens)]
use std::ffi::OsStr;
use std::mem;
use std::path::PathBuf;
use std::sync::Arc;

View file

@ -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) }
}

View file

@ -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)
}

View file

@ -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()

View 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
}

View file

@ -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

View file

@ -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;

View file

@ -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)
}
}

View file

@ -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();

View file

@ -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]");
}

View file

@ -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

View file

@ -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()

View file

@ -373,7 +373,6 @@ symbols! {
Str,
String,
StructuralPartialEq,
SubdiagMessage,
Subdiagnostic,
SymbolIntern,
Sync,

View file

@ -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>,

View file

@ -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>>:

View file

@ -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.

View file

@ -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,
) {

View file

@ -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 "

View file

@ -1,4 +1,5 @@
// rustfmt-edition: 2018
#![feature(try_blocks)]
fn main() -> Result<(), !> {
let _x: Option<_> = try {

View 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;
}

View file

@ -1,4 +1,5 @@
// rustfmt-edition: 2018
#![feature(try_blocks)]
fn main() -> Result<(), !> {
let _x: Option<_> = try { 4 };

View 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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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() {}

View file

@ -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`.

View file

@ -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() {

View file

@ -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

View file

@ -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");

View file

@ -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

View file

@ -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");

View file

@ -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

View file

@ -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");

View file

@ -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

View 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`
}

View 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`.