Merge ref 'd10ac47c20' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh.
Upstream ref: rust-lang/rust@d10ac47c20
Filtered ref: rust-lang/miri@79d95ebc75
Upstream diff: d276646872...d10ac47c20
This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
commit
bf04398434
309 changed files with 3958 additions and 5980 deletions
|
|
@ -3356,9 +3356,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.26"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
|
|
@ -3865,7 +3865,6 @@ dependencies = [
|
|||
"rustc_fluent_macro",
|
||||
"rustc_hashes",
|
||||
"rustc_index",
|
||||
"rustc_lexer",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
//! This API is completely unstable and subject to change.
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![doc(test(attr(deny(warnings), allow(internal_features))))]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
use rustc_hir::attrs::WindowsSubsystemKind;
|
||||
use rustc_hir::attrs::{CrateType, WindowsSubsystemKind};
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
|
||||
use super::prelude::*;
|
||||
|
||||
|
|
@ -26,6 +30,56 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CrateTypeParser;
|
||||
|
||||
impl<S: Stage> CombineAttributeParser<S> for CrateTypeParser {
|
||||
const PATH: &[Symbol] = &[sym::crate_type];
|
||||
type Item = CrateType;
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::CrateType(items);
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(NameValueStr: "crate type", "https://doc.rust-lang.org/reference/linkage.html");
|
||||
|
||||
fn extend(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
let ArgParser::NameValue(n) = args else {
|
||||
cx.expected_name_value(cx.attr_span, None);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(crate_type) = n.value_as_str() else {
|
||||
cx.expected_string_literal(n.value_span, Some(n.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
|
||||
let Ok(crate_type) = crate_type.try_into() else {
|
||||
// We don't error on invalid `#![crate_type]` when not applied to a crate
|
||||
if cx.shared.target == Target::Crate {
|
||||
let candidate = find_best_match_for_name(
|
||||
&CrateType::all_stable().iter().map(|(name, _)| *name).collect::<Vec<_>>(),
|
||||
crate_type,
|
||||
None,
|
||||
);
|
||||
cx.emit_lint(
|
||||
UNKNOWN_CRATE_TYPES,
|
||||
AttributeLintKind::CrateTypeUnknown {
|
||||
span: n.value_span,
|
||||
suggested: candidate,
|
||||
},
|
||||
n.value_span,
|
||||
);
|
||||
}
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(crate_type)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RecursionLimitParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
|
||||
|
|
@ -184,3 +238,39 @@ impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
|
|||
Some(AttributeKind::WindowsSubsystem(kind, cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct PanicRuntimeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for PanicRuntimeParser {
|
||||
const PATH: &[Symbol] = &[sym::panic_runtime];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime;
|
||||
}
|
||||
|
||||
pub(crate) struct NeedsPanicRuntimeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for NeedsPanicRuntimeParser {
|
||||
const PATH: &[Symbol] = &[sym::needs_panic_runtime];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime;
|
||||
}
|
||||
|
||||
pub(crate) struct ProfilerRuntimeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for ProfilerRuntimeParser {
|
||||
const PATH: &[Symbol] = &[sym::profiler_runtime];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime;
|
||||
}
|
||||
|
||||
pub(crate) struct NoBuiltinsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for NoBuiltinsParser {
|
||||
const PATH: &[Symbol] = &[sym::no_builtins];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -665,3 +665,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
|
|||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
|
||||
}
|
||||
|
||||
pub(crate) struct CompilerBuiltinsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for CompilerBuiltinsParser {
|
||||
const PATH: &[Symbol] = &[sym::compiler_builtins];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,10 @@ use crate::attributes::codegen_attrs::{
|
|||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::crate_level::{
|
||||
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoMainParser, NoStdParser,
|
||||
PatternComplexityLimitParser, RecursionLimitParser, RustcCoherenceIsCoreParser,
|
||||
TypeLengthLimitParser, WindowsSubsystemParser,
|
||||
CrateNameParser, CrateTypeParser, MoveSizeLimitParser, NeedsPanicRuntimeParser,
|
||||
NoBuiltinsParser, NoCoreParser, NoMainParser, NoStdParser, PanicRuntimeParser,
|
||||
PatternComplexityLimitParser, ProfilerRuntimeParser, RecursionLimitParser,
|
||||
RustcCoherenceIsCoreParser, TypeLengthLimitParser, WindowsSubsystemParser,
|
||||
};
|
||||
use crate::attributes::debugger::DebuggerViualizerParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
|
|
@ -40,8 +41,9 @@ use crate::attributes::dummy::DummyParser;
|
|||
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
|
||||
use crate::attributes::instruction_set::InstructionSetParser;
|
||||
use crate::attributes::link_attrs::{
|
||||
ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
|
||||
LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser, StdInternalSymbolParser,
|
||||
CompilerBuiltinsParser, ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser,
|
||||
LinkOrdinalParser, LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser,
|
||||
StdInternalSymbolParser,
|
||||
};
|
||||
use crate::attributes::lint_helpers::{
|
||||
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
|
||||
|
|
@ -191,6 +193,7 @@ attribute_parsers!(
|
|||
// tidy-alphabetical-start
|
||||
Combine<AllowConstFnUnstableParser>,
|
||||
Combine<AllowInternalUnstableParser>,
|
||||
Combine<CrateTypeParser>,
|
||||
Combine<DebuggerViualizerParser>,
|
||||
Combine<ForceTargetFeatureParser>,
|
||||
Combine<LinkParser>,
|
||||
|
|
@ -251,6 +254,7 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<AutomaticallyDerivedParser>>,
|
||||
Single<WithoutArgs<CoinductiveParser>>,
|
||||
Single<WithoutArgs<ColdParser>>,
|
||||
Single<WithoutArgs<CompilerBuiltinsParser>>,
|
||||
Single<WithoutArgs<ConstContinueParser>>,
|
||||
Single<WithoutArgs<ConstStabilityIndirectParser>>,
|
||||
Single<WithoutArgs<CoroutineParser>>,
|
||||
|
|
@ -266,6 +270,8 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<MarkerParser>>,
|
||||
Single<WithoutArgs<MayDangleParser>>,
|
||||
Single<WithoutArgs<NeedsAllocatorParser>>,
|
||||
Single<WithoutArgs<NeedsPanicRuntimeParser>>,
|
||||
Single<WithoutArgs<NoBuiltinsParser>>,
|
||||
Single<WithoutArgs<NoCoreParser>>,
|
||||
Single<WithoutArgs<NoImplicitPreludeParser>>,
|
||||
Single<WithoutArgs<NoLinkParser>>,
|
||||
|
|
@ -273,12 +279,14 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<NoMangleParser>>,
|
||||
Single<WithoutArgs<NoStdParser>>,
|
||||
Single<WithoutArgs<NonExhaustiveParser>>,
|
||||
Single<WithoutArgs<PanicRuntimeParser>>,
|
||||
Single<WithoutArgs<ParenSugarParser>>,
|
||||
Single<WithoutArgs<PassByValueParser>>,
|
||||
Single<WithoutArgs<PinV2Parser>>,
|
||||
Single<WithoutArgs<PointeeParser>>,
|
||||
Single<WithoutArgs<ProcMacroAttributeParser>>,
|
||||
Single<WithoutArgs<ProcMacroParser>>,
|
||||
Single<WithoutArgs<ProfilerRuntimeParser>>,
|
||||
Single<WithoutArgs<PubTransparentParser>>,
|
||||
Single<WithoutArgs<RustcAllocatorParser>>,
|
||||
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
|
||||
|
|
|
|||
|
|
@ -986,16 +986,6 @@ impl<'a> MethodDef<'a> {
|
|||
f(cx, span, &substructure)
|
||||
}
|
||||
|
||||
fn get_ret_ty(
|
||||
&self,
|
||||
cx: &ExtCtxt<'_>,
|
||||
trait_: &TraitDef<'_>,
|
||||
generics: &Generics,
|
||||
type_ident: Ident,
|
||||
) -> Box<ast::Ty> {
|
||||
self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
|
||||
}
|
||||
|
||||
fn is_static(&self) -> bool {
|
||||
!self.explicit_self
|
||||
}
|
||||
|
|
@ -1068,10 +1058,14 @@ impl<'a> MethodDef<'a> {
|
|||
self_arg.into_iter().chain(nonself_args).collect()
|
||||
};
|
||||
|
||||
let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
|
||||
let ret_type = if let Ty::Unit = &self.ret_ty {
|
||||
ast::FnRetTy::Default(span)
|
||||
} else {
|
||||
ast::FnRetTy::Ty(self.ret_ty.to_ty(cx, span, type_ident, generics))
|
||||
};
|
||||
|
||||
let method_ident = Ident::new(self.name, span);
|
||||
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
|
||||
let fn_decl = cx.fn_decl(args, ret_type);
|
||||
let body_block = body.into_block(cx, span);
|
||||
|
||||
let trait_lo_sp = span.shrink_to_lo();
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ impl DebugContext {
|
|||
let generics = tcx.generics_of(enclosing_fn_def_id);
|
||||
let args = instance.args.truncate_to(tcx, generics);
|
||||
|
||||
type_names::push_generic_params(
|
||||
type_names::push_generic_args(
|
||||
tcx,
|
||||
tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), args),
|
||||
&mut name,
|
||||
|
|
|
|||
|
|
@ -1397,12 +1397,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
fn call(
|
||||
&mut self,
|
||||
llty: &'ll Type,
|
||||
fn_call_attrs: Option<&CodegenFnAttrs>,
|
||||
caller_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
llfn: &'ll Value,
|
||||
args: &[&'ll Value],
|
||||
funclet: Option<&Funclet<'ll>>,
|
||||
instance: Option<Instance<'tcx>>,
|
||||
callee_instance: Option<Instance<'tcx>>,
|
||||
) -> &'ll Value {
|
||||
debug!("call {:?} with args ({:?})", llfn, args);
|
||||
|
||||
|
|
@ -1414,10 +1414,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
// Emit CFI pointer type membership test
|
||||
self.cfi_type_test(fn_call_attrs, fn_abi, instance, llfn);
|
||||
self.cfi_type_test(caller_attrs, fn_abi, callee_instance, llfn);
|
||||
|
||||
// Emit KCFI operand bundle
|
||||
let kcfi_bundle = self.kcfi_operand_bundle(fn_call_attrs, fn_abi, instance, llfn);
|
||||
let kcfi_bundle = self.kcfi_operand_bundle(caller_attrs, fn_abi, callee_instance, llfn);
|
||||
if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.as_ref()) {
|
||||
bundles.push(kcfi_bundle);
|
||||
}
|
||||
|
|
@ -1435,17 +1435,17 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
)
|
||||
};
|
||||
|
||||
if let Some(instance) = instance {
|
||||
if let Some(callee_instance) = callee_instance {
|
||||
// Attributes on the function definition being called
|
||||
let fn_defn_attrs = self.cx.tcx.codegen_fn_attrs(instance.def_id());
|
||||
if let Some(fn_call_attrs) = fn_call_attrs
|
||||
let callee_attrs = self.cx.tcx.codegen_fn_attrs(callee_instance.def_id());
|
||||
if let Some(caller_attrs) = caller_attrs
|
||||
// If there is an inline attribute and a target feature that matches
|
||||
// we will add the attribute to the callsite otherwise we'll omit
|
||||
// this and not add the attribute to prevent soundness issues.
|
||||
&& let Some(inlining_rule) = attributes::inline_attr(&self.cx, self.cx.tcx, instance)
|
||||
&& let Some(inlining_rule) = attributes::inline_attr(&self.cx, self.cx.tcx, callee_instance)
|
||||
&& self.cx.tcx.is_target_feature_call_safe(
|
||||
&fn_defn_attrs.target_features,
|
||||
&fn_call_attrs.target_features.iter().cloned().chain(
|
||||
&callee_attrs.target_features,
|
||||
&caller_attrs.target_features.iter().cloned().chain(
|
||||
self.cx.tcx.sess.target_features.iter().map(|feat| TargetFeature {
|
||||
name: *feat,
|
||||
kind: TargetFeatureKind::Implied,
|
||||
|
|
@ -1470,14 +1470,15 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
fn tail_call(
|
||||
&mut self,
|
||||
llty: Self::Type,
|
||||
fn_attrs: Option<&CodegenFnAttrs>,
|
||||
caller_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
llfn: Self::Value,
|
||||
args: &[Self::Value],
|
||||
funclet: Option<&Self::Funclet>,
|
||||
instance: Option<Instance<'tcx>>,
|
||||
callee_instance: Option<Instance<'tcx>>,
|
||||
) {
|
||||
let call = self.call(llty, fn_attrs, Some(fn_abi), llfn, args, funclet, instance);
|
||||
let call =
|
||||
self.call(llty, caller_attrs, Some(fn_abi), llfn, args, funclet, callee_instance);
|
||||
llvm::LLVMSetTailCallKind(call, llvm::TailCallKind::MustTail);
|
||||
|
||||
match &fn_abi.ret.mode {
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
|
|||
CrateType::Executable
|
||||
| CrateType::Dylib
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Staticlib
|
||||
| CrateType::StaticLib
|
||||
| CrateType::Sdylib => {
|
||||
// These are crate types for which we will embed pretty printers since they
|
||||
// are treated as leaf crates.
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
let generics = tcx.generics_of(enclosing_fn_def_id);
|
||||
let args = instance.args.truncate_to(tcx, generics);
|
||||
|
||||
type_names::push_generic_params(
|
||||
type_names::push_generic_args(
|
||||
tcx,
|
||||
tcx.normalize_erasing_regions(self.typing_env(), args),
|
||||
&mut name,
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ pub fn link_binary(
|
|||
)
|
||||
.build(&out_filename);
|
||||
}
|
||||
CrateType::Staticlib => {
|
||||
CrateType::StaticLib => {
|
||||
link_staticlib(
|
||||
sess,
|
||||
archive_builder_builder,
|
||||
|
|
@ -474,7 +474,7 @@ fn link_staticlib(
|
|||
|
||||
let res = each_linked_rlib(
|
||||
&codegen_results.crate_info,
|
||||
Some(CrateType::Staticlib),
|
||||
Some(CrateType::StaticLib),
|
||||
&mut |cnum, path| {
|
||||
let lto = are_upstream_rust_objects_already_included(sess)
|
||||
&& !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
|
||||
|
|
@ -532,7 +532,7 @@ fn link_staticlib(
|
|||
let fmts = codegen_results
|
||||
.crate_info
|
||||
.dependency_formats
|
||||
.get(&CrateType::Staticlib)
|
||||
.get(&CrateType::StaticLib)
|
||||
.expect("no dependency formats for staticlib");
|
||||
|
||||
let mut all_rust_dylibs = vec![];
|
||||
|
|
@ -1210,7 +1210,7 @@ fn add_sanitizer_libraries(
|
|||
return;
|
||||
}
|
||||
|
||||
if matches!(crate_type, CrateType::Rlib | CrateType::Staticlib) {
|
||||
if matches!(crate_type, CrateType::Rlib | CrateType::StaticLib) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1857,7 +1857,7 @@ pub(crate) fn linked_symbols(
|
|||
| CrateType::Cdylib
|
||||
| CrateType::Dylib
|
||||
| CrateType::Sdylib => (),
|
||||
CrateType::Staticlib | CrateType::Rlib => {
|
||||
CrateType::StaticLib | CrateType::Rlib => {
|
||||
// These are not linked, so no need to generate symbols.o for them.
|
||||
return Vec::new();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ fn crate_type_allows_lto(crate_type: CrateType) -> bool {
|
|||
match crate_type {
|
||||
CrateType::Executable
|
||||
| CrateType::Dylib
|
||||
| CrateType::Staticlib
|
||||
| CrateType::StaticLib
|
||||
| CrateType::Cdylib
|
||||
| CrateType::ProcMacro
|
||||
| CrateType::Sdylib => true,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
|
|||
|
||||
fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel {
|
||||
match crate_type {
|
||||
CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => {
|
||||
CrateType::Executable | CrateType::StaticLib | CrateType::ProcMacro | CrateType::Cdylib => {
|
||||
SymbolExportLevel::C
|
||||
}
|
||||
CrateType::Rlib | CrateType::Dylib | CrateType::Sdylib => SymbolExportLevel::Rust,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use std::sync::mpsc::{Receiver, Sender, channel};
|
|||
use std::{fs, io, mem, str, thread};
|
||||
|
||||
use rustc_abi::Size;
|
||||
use rustc_ast::attr;
|
||||
use rustc_data_structures::assert_matches;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::jobserver::{self, Acquired};
|
||||
|
|
@ -19,6 +18,8 @@ use rustc_errors::{
|
|||
Level, MultiSpan, Style, Suggestions, catch_fatal_errors,
|
||||
};
|
||||
use rustc_fs_util::link_or_copy;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::find_attr;
|
||||
use rustc_incremental::{
|
||||
copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
|
||||
};
|
||||
|
|
@ -31,7 +32,7 @@ use rustc_session::config::{
|
|||
self, CrateType, Lto, OutFileName, OutputFilenames, OutputType, Passes, SwitchWithOptPath,
|
||||
};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{FileName, InnerSpan, Span, SpanData, sym};
|
||||
use rustc_span::{FileName, InnerSpan, Span, SpanData};
|
||||
use rustc_target::spec::{MergeFunctions, SanitizerSet};
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -453,7 +454,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
let (coordinator_send, coordinator_receive) = channel();
|
||||
|
||||
let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
|
||||
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
|
||||
let no_builtins = find_attr!(crate_attrs, AttributeKind::NoBuiltins);
|
||||
|
||||
let crate_info = CrateInfo::new(tcx, target_cpu);
|
||||
|
||||
|
|
|
|||
|
|
@ -1009,7 +1009,7 @@ impl CrateInfo {
|
|||
info.linked_symbols
|
||||
.iter_mut()
|
||||
.filter(|(crate_type, _)| {
|
||||
!matches!(crate_type, CrateType::Rlib | CrateType::Staticlib)
|
||||
!matches!(crate_type, CrateType::Rlib | CrateType::StaticLib)
|
||||
})
|
||||
.for_each(|(_, linked_symbols)| {
|
||||
let mut symbols = missing_weak_lang_items
|
||||
|
|
@ -1041,7 +1041,7 @@ impl CrateInfo {
|
|||
// this is a rare use case and we don't want to slow down the common case.
|
||||
false
|
||||
}
|
||||
CrateType::Staticlib | CrateType::Rlib => {
|
||||
CrateType::StaticLib | CrateType::Rlib => {
|
||||
// We don't invoke the linker for these, so we don't need to collect the NatVis for
|
||||
// them.
|
||||
false
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::str::FromStr;
|
|||
|
||||
use rustc_abi::{Align, ExternAbi};
|
||||
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
|
||||
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
|
||||
use rustc_ast::{LitKind, MetaItem, MetaItemInner};
|
||||
use rustc_hir::attrs::{
|
||||
AttributeKind, EiiImplResolution, InlineAttr, Linkage, RtsanSetting, UsedBy,
|
||||
};
|
||||
|
|
@ -353,7 +353,7 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code
|
|||
// When `no_builtins` is applied at the crate level, we should add the
|
||||
// `no-builtins` attribute to each function to ensure it takes effect in LTO.
|
||||
let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
|
||||
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
|
||||
let no_builtins = find_attr!(crate_attrs, AttributeKind::NoBuiltins);
|
||||
if no_builtins {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,14 +109,14 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
ty_and_layout,
|
||||
&|output, visited| {
|
||||
push_item_name(tcx, def.did(), true, output);
|
||||
push_generic_params_internal(tcx, args, output, visited);
|
||||
push_generic_args_internal(tcx, args, output, visited);
|
||||
},
|
||||
output,
|
||||
visited,
|
||||
);
|
||||
} else {
|
||||
push_item_name(tcx, def.did(), qualified, output);
|
||||
push_generic_params_internal(tcx, args, output, visited);
|
||||
push_generic_args_internal(tcx, args, output, visited);
|
||||
}
|
||||
}
|
||||
ty::Tuple(component_types) => {
|
||||
|
|
@ -253,19 +253,18 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
);
|
||||
push_item_name(tcx, principal.def_id, qualified, output);
|
||||
let principal_has_generic_params =
|
||||
push_generic_params_internal(tcx, principal.args, output, visited);
|
||||
push_generic_args_internal(tcx, principal.args, output, visited);
|
||||
|
||||
let projection_bounds: SmallVec<[_; 4]> = trait_data
|
||||
.projection_bounds()
|
||||
.map(|bound| {
|
||||
let ExistentialProjection { def_id: item_def_id, term, .. } =
|
||||
tcx.instantiate_bound_regions_with_erased(bound);
|
||||
// FIXME(mgca): allow for consts here
|
||||
(item_def_id, term.expect_type())
|
||||
(item_def_id, term)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if projection_bounds.len() != 0 {
|
||||
if !projection_bounds.is_empty() {
|
||||
if principal_has_generic_params {
|
||||
// push_generic_params_internal() above added a `>` but we actually
|
||||
// want to add more items to that list, so remove that again...
|
||||
|
|
@ -279,17 +278,17 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
output.push('<');
|
||||
}
|
||||
|
||||
for (item_def_id, ty) in projection_bounds {
|
||||
for (item_def_id, term) in projection_bounds {
|
||||
if cpp_like_debuginfo {
|
||||
output.push_str("assoc$<");
|
||||
push_item_name(tcx, item_def_id, false, output);
|
||||
push_arg_separator(cpp_like_debuginfo, output);
|
||||
push_debuginfo_type_name(tcx, ty, true, output, visited);
|
||||
push_debuginfo_term_name(tcx, term, true, output, visited);
|
||||
push_close_angle_bracket(cpp_like_debuginfo, output);
|
||||
} else {
|
||||
push_item_name(tcx, item_def_id, false, output);
|
||||
output.push('=');
|
||||
push_debuginfo_type_name(tcx, ty, true, output, visited);
|
||||
push_debuginfo_term_name(tcx, term, true, output, visited);
|
||||
}
|
||||
push_arg_separator(cpp_like_debuginfo, output);
|
||||
}
|
||||
|
|
@ -533,7 +532,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
|
|||
tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref);
|
||||
push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
|
||||
visited.clear();
|
||||
push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
|
||||
push_generic_args_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
|
||||
} else {
|
||||
vtable_name.push('_');
|
||||
}
|
||||
|
|
@ -631,7 +630,13 @@ fn push_unqualified_item_name(
|
|||
};
|
||||
}
|
||||
|
||||
fn push_generic_params_internal<'tcx>(
|
||||
pub fn push_generic_args<'tcx>(tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, output: &mut String) {
|
||||
let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
|
||||
let mut visited = FxHashSet::default();
|
||||
push_generic_args_internal(tcx, args, output, &mut visited);
|
||||
}
|
||||
|
||||
fn push_generic_args_internal<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
output: &mut String,
|
||||
|
|
@ -646,14 +651,10 @@ fn push_generic_params_internal<'tcx>(
|
|||
|
||||
output.push('<');
|
||||
|
||||
for type_parameter in args {
|
||||
match type_parameter {
|
||||
GenericArgKind::Type(type_parameter) => {
|
||||
push_debuginfo_type_name(tcx, type_parameter, true, output, visited);
|
||||
}
|
||||
GenericArgKind::Const(ct) => {
|
||||
push_const_param(tcx, ct, output);
|
||||
}
|
||||
for arg in args {
|
||||
match arg {
|
||||
GenericArgKind::Type(ty) => push_debuginfo_type_name(tcx, ty, true, output, visited),
|
||||
GenericArgKind::Const(ct) => push_debuginfo_const_name(tcx, ct, output),
|
||||
other => bug!("Unexpected non-erasable generic: {:?}", other),
|
||||
}
|
||||
|
||||
|
|
@ -665,7 +666,20 @@ fn push_generic_params_internal<'tcx>(
|
|||
true
|
||||
}
|
||||
|
||||
fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
|
||||
fn push_debuginfo_term_name<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
term: ty::Term<'tcx>,
|
||||
qualified: bool,
|
||||
output: &mut String,
|
||||
visited: &mut FxHashSet<Ty<'tcx>>,
|
||||
) {
|
||||
match term.kind() {
|
||||
ty::TermKind::Ty(ty) => push_debuginfo_type_name(tcx, ty, qualified, output, visited),
|
||||
ty::TermKind::Const(ct) => push_debuginfo_const_name(tcx, ct, output),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_debuginfo_const_name<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Param(param) => {
|
||||
write!(output, "{}", param.name)
|
||||
|
|
@ -715,16 +729,6 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn push_generic_params<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
output: &mut String,
|
||||
) {
|
||||
let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
|
||||
let mut visited = FxHashSet::default();
|
||||
push_generic_params_internal(tcx, args, output, &mut visited);
|
||||
}
|
||||
|
||||
fn push_closure_or_coroutine_name<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
|
|
@ -767,7 +771,7 @@ fn push_closure_or_coroutine_name<'tcx>(
|
|||
// FIXME(async_closures): This is probably not going to be correct w.r.t.
|
||||
// multiple coroutine flavors. Maybe truncate to (parent + 1)?
|
||||
let args = args.truncate_to(tcx, generics);
|
||||
push_generic_params_internal(tcx, args, output, visited);
|
||||
push_generic_args_internal(tcx, args, output, visited);
|
||||
}
|
||||
|
||||
fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
|
||||
|
|
|
|||
|
|
@ -199,12 +199,12 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||
// do an invoke, otherwise do a call.
|
||||
let fn_ty = bx.fn_decl_backend_type(fn_abi);
|
||||
|
||||
let fn_attrs = if bx.tcx().def_kind(fx.instance.def_id()).has_codegen_attrs() {
|
||||
let caller_attrs = if bx.tcx().def_kind(fx.instance.def_id()).has_codegen_attrs() {
|
||||
Some(bx.tcx().codegen_instance_attrs(fx.instance.def))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let fn_attrs = fn_attrs.as_deref();
|
||||
let caller_attrs = caller_attrs.as_deref();
|
||||
|
||||
if !fn_abi.can_unwind {
|
||||
unwind = mir::UnwindAction::Unreachable;
|
||||
|
|
@ -233,7 +233,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||
};
|
||||
|
||||
if kind == CallKind::Tail {
|
||||
bx.tail_call(fn_ty, fn_attrs, fn_abi, fn_ptr, llargs, self.funclet(fx), instance);
|
||||
bx.tail_call(fn_ty, caller_attrs, fn_abi, fn_ptr, llargs, self.funclet(fx), instance);
|
||||
return MergingSucc::False;
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +245,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||
};
|
||||
let invokeret = bx.invoke(
|
||||
fn_ty,
|
||||
fn_attrs,
|
||||
caller_attrs,
|
||||
Some(fn_abi),
|
||||
fn_ptr,
|
||||
llargs,
|
||||
|
|
@ -268,8 +268,15 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||
}
|
||||
MergingSucc::False
|
||||
} else {
|
||||
let llret =
|
||||
bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, self.funclet(fx), instance);
|
||||
let llret = bx.call(
|
||||
fn_ty,
|
||||
caller_attrs,
|
||||
Some(fn_abi),
|
||||
fn_ptr,
|
||||
llargs,
|
||||
self.funclet(fx),
|
||||
instance,
|
||||
);
|
||||
if fx.mir[self.bb].is_cleanup {
|
||||
bx.apply_attrs_to_cleanup_callsite(llret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ pub trait CodegenBackend {
|
|||
CrateType::Executable,
|
||||
CrateType::Dylib,
|
||||
CrateType::Rlib,
|
||||
CrateType::Staticlib,
|
||||
CrateType::StaticLib,
|
||||
CrateType::Cdylib,
|
||||
CrateType::ProcMacro,
|
||||
CrateType::Sdylib,
|
||||
|
|
|
|||
|
|
@ -600,10 +600,13 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
///
|
||||
/// ## Arguments
|
||||
///
|
||||
/// The `fn_attrs`, `fn_abi`, and `instance` arguments are Options because they are advisory.
|
||||
/// They relate to optional codegen enhancements like LLVM CFI, and do not affect ABI per se.
|
||||
/// Any ABI-related transformations should be handled by different, earlier stages of codegen.
|
||||
/// For instance, in the caller of `BuilderMethods::call`.
|
||||
/// `caller_attrs` are the attributes of the surrounding caller; they have nothing to do with
|
||||
/// the callee.
|
||||
///
|
||||
/// The `caller_attrs`, `fn_abi`, and `callee_instance` arguments are Options because they are
|
||||
/// advisory. They relate to optional codegen enhancements like LLVM CFI, and do not affect ABI
|
||||
/// per se. Any ABI-related transformations should be handled by different, earlier stages of
|
||||
/// codegen. For instance, in the caller of `BuilderMethods::call`.
|
||||
///
|
||||
/// This means that a codegen backend which disregards `fn_attrs`, `fn_abi`, and `instance`
|
||||
/// should still do correct codegen, and code should not be miscompiled if they are omitted.
|
||||
|
|
@ -620,23 +623,23 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
fn call(
|
||||
&mut self,
|
||||
llty: Self::Type,
|
||||
fn_attrs: Option<&CodegenFnAttrs>,
|
||||
caller_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
fn_val: Self::Value,
|
||||
args: &[Self::Value],
|
||||
funclet: Option<&Self::Funclet>,
|
||||
instance: Option<Instance<'tcx>>,
|
||||
callee_instance: Option<Instance<'tcx>>,
|
||||
) -> Self::Value;
|
||||
|
||||
fn tail_call(
|
||||
&mut self,
|
||||
llty: Self::Type,
|
||||
fn_attrs: Option<&CodegenFnAttrs>,
|
||||
caller_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
llfn: Self::Value,
|
||||
args: &[Self::Value],
|
||||
funclet: Option<&Self::Funclet>,
|
||||
instance: Option<Instance<'tcx>>,
|
||||
callee_instance: Option<Instance<'tcx>>,
|
||||
);
|
||||
|
||||
fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
|
||||
|
|
|
|||
|
|
@ -343,17 +343,18 @@ where
|
|||
|
||||
// Check the qualifs of the value of `const` items.
|
||||
let uneval = match constant.const_ {
|
||||
Const::Ty(_, ct)
|
||||
if matches!(
|
||||
ct.kind(),
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_)
|
||||
) =>
|
||||
{
|
||||
None
|
||||
}
|
||||
Const::Ty(_, c) => {
|
||||
bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c)
|
||||
}
|
||||
Const::Ty(_, ct) => match ct.kind() {
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) => None,
|
||||
// Unevaluated consts in MIR bodies don't have associated MIR (e.g. `#[type_const]`).
|
||||
ty::ConstKind::Unevaluated(_) => None,
|
||||
// FIXME(mgca): Investigate whether using `None` for `ConstKind::Value` is overly
|
||||
// strict, and if instead we should be doing some kind of value-based analysis.
|
||||
ty::ConstKind::Value(_) => None,
|
||||
_ => bug!(
|
||||
"expected ConstKind::Param, ConstKind::Value, ConstKind::Unevaluated, or ConstKind::Error here, found {:?}",
|
||||
ct
|
||||
),
|
||||
},
|
||||
Const::Unevaluated(uv, _) => Some(uv),
|
||||
Const::Val(..) => None,
|
||||
};
|
||||
|
|
@ -364,10 +365,8 @@ where
|
|||
// check performed after the promotion. Verify that with an assertion.
|
||||
assert!(promoted.is_none() || Q::ALLOW_PROMOTED);
|
||||
|
||||
// Don't peak inside trait associated constants, also `#[type_const] const` items
|
||||
// don't have bodies so there's nothing to look at
|
||||
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !cx.tcx.is_type_const(def)
|
||||
{
|
||||
// Don't peak inside trait associated constants.
|
||||
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() {
|
||||
let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def);
|
||||
|
||||
if !Q::in_qualifs(&qualifs) {
|
||||
|
|
|
|||
|
|
@ -66,6 +66,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
|
||||
variant
|
||||
}
|
||||
ty::Slice(ty) => {
|
||||
let (variant, variant_place) = downcast(sym::Slice)?;
|
||||
let slice_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
|
||||
self.write_slice_type_info(slice_place, *ty)?;
|
||||
|
||||
variant
|
||||
}
|
||||
ty::Bool => {
|
||||
let (variant, _variant_place) = downcast(sym::Bool)?;
|
||||
variant
|
||||
|
|
@ -124,7 +132,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(..)
|
||||
| ty::UnsafeBinder(..)
|
||||
|
|
@ -254,6 +261,27 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
interp_ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn write_slice_type_info(
|
||||
&mut self,
|
||||
place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Iterate over all fields of `type_info::Slice`.
|
||||
for (field_idx, field) in
|
||||
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
|
||||
{
|
||||
let field_place = self.project_field(&place, field_idx)?;
|
||||
|
||||
match field.name {
|
||||
// Write the `TypeId` of the slice's elements to the `element_ty` field.
|
||||
sym::element_ty => self.write_type_id(ty, &field_place)?,
|
||||
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
|
||||
}
|
||||
}
|
||||
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
fn write_int_type_info(
|
||||
&mut self,
|
||||
place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let dest = dest.force_mplace(self)?;
|
||||
|
||||
match intrinsic_name {
|
||||
sym::simd_insert => {
|
||||
sym::simd_insert | sym::simd_insert_dyn => {
|
||||
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
|
||||
let elem = &args[2];
|
||||
let (input, input_len) = self.project_to_simd(&args[0])?;
|
||||
|
|
@ -39,7 +39,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
// Bounds are not checked by typeck so we have to do it ourselves.
|
||||
if index >= input_len {
|
||||
throw_ub_format!(
|
||||
"`simd_insert` index {index} is out-of-bounds of vector with length {input_len}"
|
||||
"`{intrinsic_name}` index {index} is out-of-bounds of vector with length {input_len}"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -50,13 +50,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
self.copy_op(&value, &place)?;
|
||||
}
|
||||
}
|
||||
sym::simd_extract => {
|
||||
sym::simd_extract | sym::simd_extract_dyn => {
|
||||
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
|
||||
let (input, input_len) = self.project_to_simd(&args[0])?;
|
||||
// Bounds are not checked by typeck so we have to do it ourselves.
|
||||
if index >= input_len {
|
||||
throw_ub_format!(
|
||||
"`simd_extract` index {index} is out-of-bounds of vector with length {input_len}"
|
||||
"`{intrinsic_name}` index {index} is out-of-bounds of vector with length {input_len}"
|
||||
);
|
||||
}
|
||||
self.copy_op(&self.project_index(&input, index)?, &dest)?;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#![allow(internal_features)]
|
||||
#![allow(rustc::default_hash_types)]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(ascii_char)]
|
||||
|
|
@ -42,8 +41,11 @@
|
|||
// have to worry about it being moved to a different module in std during stabilization.
|
||||
// FIXME(#151359): Remove this when `feature(assert_matches)` is stable in stage0.
|
||||
// (This doesn't necessarily need to be fixed during the beta bump itself.)
|
||||
#[cfg(bootstrap)]
|
||||
pub use std::assert_matches::{assert_matches, debug_assert_matches};
|
||||
use std::fmt;
|
||||
#[cfg(not(bootstrap))]
|
||||
pub use std::{assert_matches, debug_assert_matches};
|
||||
|
||||
pub use atomic_ref::AtomicRef;
|
||||
pub use ena::{snapshot_vec, undo_log, unify};
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ use rustc_feature::find_gated_cfg;
|
|||
// `rust_index` isn't used in this crate's code, but it must be named in the
|
||||
// `Cargo.toml` for the `rustc_randomized_layouts` feature.
|
||||
use rustc_index as _;
|
||||
use rustc_interface::passes::collect_crate_types;
|
||||
use rustc_interface::util::{self, get_codegen_backend};
|
||||
use rustc_interface::{Linker, create_and_enter_global_ctxt, interface, passes};
|
||||
use rustc_lint::unerased_lint_store;
|
||||
|
|
@ -56,10 +57,10 @@ use rustc_session::config::{
|
|||
};
|
||||
use rustc_session::getopts::{self, Matches};
|
||||
use rustc_session::lint::{Lint, LintId};
|
||||
use rustc_session::output::{CRATE_TYPES, collect_crate_types, invalid_output_for_target};
|
||||
use rustc_session::output::invalid_output_for_target;
|
||||
use rustc_session::{EarlyDiagCtxt, Session, config};
|
||||
use rustc_span::FileName;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::{DUMMY_SP, FileName};
|
||||
use rustc_target::json::ToJson;
|
||||
use rustc_target::spec::{Target, TargetTuple};
|
||||
use tracing::trace;
|
||||
|
|
@ -698,6 +699,7 @@ fn print_crate_info(
|
|||
&codegen_backend.supported_crate_types(sess),
|
||||
codegen_backend.name(),
|
||||
attrs,
|
||||
DUMMY_SP,
|
||||
);
|
||||
for &style in &crate_types {
|
||||
let fname = rustc_session::output::filename_for_input(
|
||||
|
|
@ -849,7 +851,7 @@ fn print_crate_info(
|
|||
}
|
||||
}
|
||||
SupportedCrateTypes => {
|
||||
let supported_crate_types = CRATE_TYPES
|
||||
let supported_crate_types = CrateType::all()
|
||||
.iter()
|
||||
.filter(|(_, crate_type)| !invalid_output_for_target(sess, *crate_type))
|
||||
.filter(|(_, crate_type)| *crate_type != CrateType::Sdylib)
|
||||
|
|
@ -1534,10 +1536,11 @@ fn report_ice(
|
|||
using_internal_features: &AtomicBool,
|
||||
) {
|
||||
let translator = default_translator();
|
||||
let emitter = Box::new(rustc_errors::emitter::HumanEmitter::new(
|
||||
stderr_destination(rustc_errors::ColorConfig::Auto),
|
||||
translator,
|
||||
));
|
||||
let emitter =
|
||||
Box::new(rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter::new(
|
||||
stderr_destination(rustc_errors::ColorConfig::Auto),
|
||||
translator,
|
||||
));
|
||||
let dcx = rustc_errors::DiagCtxt::new(emitter);
|
||||
let dcx = dcx.handle();
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ rustc_error_messages = { path = "../rustc_error_messages" }
|
|||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_hashes = { path = "../rustc_hashes" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
|
|
|
|||
|
|
@ -15,10 +15,9 @@ use rustc_span::source_map::Spanned;
|
|||
use rustc_span::{DUMMY_SP, Span, Symbol};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::snippet::Style;
|
||||
use crate::{
|
||||
CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
|
||||
MultiSpan, StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle,
|
||||
MultiSpan, StashKey, Style, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle,
|
||||
Suggestions,
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -5,7 +5,6 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![allow(rustc::direct_use_of_rustc_type_ir)]
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
@ -51,7 +50,7 @@ pub use diagnostic_impls::{
|
|||
IndicateAnonymousLifetime, SingleLabelManySpans,
|
||||
};
|
||||
pub use emitter::ColorConfig;
|
||||
use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different};
|
||||
use emitter::{DynEmitter, Emitter};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::stable_hasher::StableHasher;
|
||||
use rustc_data_structures::sync::{DynSend, Lock};
|
||||
|
|
@ -68,8 +67,7 @@ use rustc_macros::{Decodable, Encodable};
|
|||
pub use rustc_span::ErrorGuaranteed;
|
||||
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker, catch_fatal_errors};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
|
||||
pub use snippet::Style;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::emitter::TimingEvent;
|
||||
|
|
@ -87,8 +85,6 @@ pub mod json;
|
|||
mod lock;
|
||||
pub mod markdown;
|
||||
pub mod registry;
|
||||
mod snippet;
|
||||
mod styled_buffer;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
pub mod timings;
|
||||
|
|
@ -215,43 +211,6 @@ pub struct TrimmedSubstitutionPart {
|
|||
pub snippet: String,
|
||||
}
|
||||
|
||||
/// Used to translate between `Span`s and byte positions within a single output line in highlighted
|
||||
/// code of structured suggestions.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct SubstitutionHighlight {
|
||||
start: usize,
|
||||
end: usize,
|
||||
}
|
||||
|
||||
impl SubstitutionPart {
|
||||
/// Try to turn a replacement into an addition when the span that is being
|
||||
/// overwritten matches either the prefix or suffix of the replacement.
|
||||
fn trim_trivial_replacements(self, sm: &SourceMap) -> TrimmedSubstitutionPart {
|
||||
let mut trimmed_part = TrimmedSubstitutionPart {
|
||||
original_span: self.span,
|
||||
span: self.span,
|
||||
snippet: self.snippet,
|
||||
};
|
||||
if trimmed_part.snippet.is_empty() {
|
||||
return trimmed_part;
|
||||
}
|
||||
let Ok(snippet) = sm.span_to_snippet(trimmed_part.span) else {
|
||||
return trimmed_part;
|
||||
};
|
||||
|
||||
if let Some((prefix, substr, suffix)) = as_substr(&snippet, &trimmed_part.snippet) {
|
||||
trimmed_part.span = Span::new(
|
||||
trimmed_part.span.lo() + BytePos(prefix as u32),
|
||||
trimmed_part.span.hi() - BytePos(suffix as u32),
|
||||
trimmed_part.span.ctxt(),
|
||||
trimmed_part.span.parent(),
|
||||
);
|
||||
trimmed_part.snippet = substr.to_string();
|
||||
}
|
||||
trimmed_part
|
||||
}
|
||||
}
|
||||
|
||||
impl TrimmedSubstitutionPart {
|
||||
pub fn is_addition(&self, sm: &SourceMap) -> bool {
|
||||
!self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
|
||||
|
|
@ -303,229 +262,6 @@ fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a s
|
|||
}
|
||||
}
|
||||
|
||||
impl CodeSuggestion {
|
||||
/// Returns the assembled code suggestions, whether they should be shown with an underline
|
||||
/// and whether the substitution only differs in capitalization.
|
||||
pub(crate) fn splice_lines(
|
||||
&self,
|
||||
sm: &SourceMap,
|
||||
) -> Vec<(String, Vec<TrimmedSubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)>
|
||||
{
|
||||
// For the `Vec<Vec<SubstitutionHighlight>>` value, the first level of the vector
|
||||
// corresponds to the output snippet's lines, while the second level corresponds to the
|
||||
// substrings within that line that should be highlighted.
|
||||
|
||||
use rustc_span::{CharPos, Pos};
|
||||
|
||||
/// Extracts a substring from the provided `line_opt` based on the specified low and high
|
||||
/// indices, appends it to the given buffer `buf`, and returns the count of newline
|
||||
/// characters in the substring for accurate highlighting. If `line_opt` is `None`, a
|
||||
/// newline character is appended to the buffer, and 0 is returned.
|
||||
///
|
||||
/// ## Returns
|
||||
///
|
||||
/// The count of newline characters in the extracted substring.
|
||||
fn push_trailing(
|
||||
buf: &mut String,
|
||||
line_opt: Option<&Cow<'_, str>>,
|
||||
lo: &Loc,
|
||||
hi_opt: Option<&Loc>,
|
||||
) -> usize {
|
||||
let mut line_count = 0;
|
||||
// Convert `CharPos` to `usize`, as `CharPos` is character offset
|
||||
// Extract low index and high index
|
||||
let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
|
||||
if let Some(line) = line_opt {
|
||||
if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
|
||||
// Get high index while account for rare unicode and emoji with char_indices
|
||||
let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
|
||||
match hi_opt {
|
||||
// If high index exist, take string from low to high index
|
||||
Some(hi) if hi > lo => {
|
||||
// count how many '\n' exist
|
||||
line_count = line[lo..hi].matches('\n').count();
|
||||
buf.push_str(&line[lo..hi])
|
||||
}
|
||||
Some(_) => (),
|
||||
// If high index absence, take string from low index till end string.len
|
||||
None => {
|
||||
// count how many '\n' exist
|
||||
line_count = line[lo..].matches('\n').count();
|
||||
buf.push_str(&line[lo..])
|
||||
}
|
||||
}
|
||||
}
|
||||
// If high index is None
|
||||
if hi_opt.is_none() {
|
||||
buf.push('\n');
|
||||
}
|
||||
}
|
||||
line_count
|
||||
}
|
||||
|
||||
assert!(!self.substitutions.is_empty());
|
||||
|
||||
self.substitutions
|
||||
.iter()
|
||||
.filter(|subst| {
|
||||
// Suggestions coming from macros can have malformed spans. This is a heavy
|
||||
// handed approach to avoid ICEs by ignoring the suggestion outright.
|
||||
let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
|
||||
if invalid {
|
||||
debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
|
||||
}
|
||||
!invalid
|
||||
})
|
||||
.cloned()
|
||||
.filter_map(|mut substitution| {
|
||||
// Assumption: all spans are in the same file, and all spans
|
||||
// are disjoint. Sort in ascending order.
|
||||
substitution.parts.sort_by_key(|part| part.span.lo());
|
||||
|
||||
// Find the bounding span.
|
||||
let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
|
||||
let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
|
||||
let bounding_span = Span::with_root_ctxt(lo, hi);
|
||||
// The different spans might belong to different contexts, if so ignore suggestion.
|
||||
let lines = sm.span_to_lines(bounding_span).ok()?;
|
||||
assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
|
||||
|
||||
// We can't splice anything if the source is unavailable.
|
||||
if !sm.ensure_source_file_source_present(&lines.file) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut highlights = vec![];
|
||||
// To build up the result, we do this for each span:
|
||||
// - push the line segment trailing the previous span
|
||||
// (at the beginning a "phantom" span pointing at the start of the line)
|
||||
// - push lines between the previous and current span (if any)
|
||||
// - if the previous and current span are not on the same line
|
||||
// push the line segment leading up to the current span
|
||||
// - splice in the span substitution
|
||||
//
|
||||
// Finally push the trailing line segment of the last span
|
||||
let sf = &lines.file;
|
||||
let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
|
||||
prev_hi.col = CharPos::from_usize(0);
|
||||
let mut prev_line =
|
||||
lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
|
||||
let mut buf = String::new();
|
||||
|
||||
let mut line_highlight = vec![];
|
||||
// We need to keep track of the difference between the existing code and the added
|
||||
// or deleted code in order to point at the correct column *after* substitution.
|
||||
let mut acc = 0;
|
||||
let mut confusion_type = ConfusionType::None;
|
||||
|
||||
let trimmed_parts = substitution
|
||||
.parts
|
||||
.into_iter()
|
||||
// If this is a replacement of, e.g. `"a"` into `"ab"`, adjust the
|
||||
// suggestion and snippet to look as if we just suggested to add
|
||||
// `"b"`, which is typically much easier for the user to understand.
|
||||
.map(|part| part.trim_trivial_replacements(sm))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for part in &trimmed_parts {
|
||||
let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
|
||||
confusion_type = confusion_type.combine(part_confusion);
|
||||
let cur_lo = sm.lookup_char_pos(part.span.lo());
|
||||
if prev_hi.line == cur_lo.line {
|
||||
let mut count =
|
||||
push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
|
||||
while count > 0 {
|
||||
highlights.push(std::mem::take(&mut line_highlight));
|
||||
acc = 0;
|
||||
count -= 1;
|
||||
}
|
||||
} else {
|
||||
acc = 0;
|
||||
highlights.push(std::mem::take(&mut line_highlight));
|
||||
let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
|
||||
while count > 0 {
|
||||
highlights.push(std::mem::take(&mut line_highlight));
|
||||
count -= 1;
|
||||
}
|
||||
// push lines between the previous and current span (if any)
|
||||
for idx in prev_hi.line..(cur_lo.line - 1) {
|
||||
if let Some(line) = sf.get_line(idx) {
|
||||
buf.push_str(line.as_ref());
|
||||
buf.push('\n');
|
||||
highlights.push(std::mem::take(&mut line_highlight));
|
||||
}
|
||||
}
|
||||
if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
|
||||
let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
|
||||
Some((i, _)) => i,
|
||||
None => cur_line.len(),
|
||||
};
|
||||
buf.push_str(&cur_line[..end]);
|
||||
}
|
||||
}
|
||||
// Add a whole line highlight per line in the snippet.
|
||||
let len: isize = part
|
||||
.snippet
|
||||
.split('\n')
|
||||
.next()
|
||||
.unwrap_or(&part.snippet)
|
||||
.chars()
|
||||
.map(|c| match c {
|
||||
'\t' => 4,
|
||||
_ => 1,
|
||||
})
|
||||
.sum();
|
||||
if !is_different(sm, &part.snippet, part.span) {
|
||||
// Account for cases where we are suggesting the same code that's already
|
||||
// there. This shouldn't happen often, but in some cases for multipart
|
||||
// suggestions it's much easier to handle it here than in the origin.
|
||||
} else {
|
||||
line_highlight.push(SubstitutionHighlight {
|
||||
start: (cur_lo.col.0 as isize + acc) as usize,
|
||||
end: (cur_lo.col.0 as isize + acc + len) as usize,
|
||||
});
|
||||
}
|
||||
buf.push_str(&part.snippet);
|
||||
let cur_hi = sm.lookup_char_pos(part.span.hi());
|
||||
// Account for the difference between the width of the current code and the
|
||||
// snippet being suggested, so that the *later* suggestions are correctly
|
||||
// aligned on the screen. Note that cur_hi and cur_lo can be on different
|
||||
// lines, so cur_hi.col can be smaller than cur_lo.col
|
||||
acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
|
||||
prev_hi = cur_hi;
|
||||
prev_line = sf.get_line(prev_hi.line - 1);
|
||||
for line in part.snippet.split('\n').skip(1) {
|
||||
acc = 0;
|
||||
highlights.push(std::mem::take(&mut line_highlight));
|
||||
let end: usize = line
|
||||
.chars()
|
||||
.map(|c| match c {
|
||||
'\t' => 4,
|
||||
_ => 1,
|
||||
})
|
||||
.sum();
|
||||
line_highlight.push(SubstitutionHighlight { start: 0, end });
|
||||
}
|
||||
}
|
||||
highlights.push(std::mem::take(&mut line_highlight));
|
||||
// if the replacement already ends with a newline, don't print the next line
|
||||
if !buf.ends_with('\n') {
|
||||
push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
|
||||
}
|
||||
// remove trailing newlines
|
||||
while buf.ends_with('\n') {
|
||||
buf.pop();
|
||||
}
|
||||
if highlights.iter().all(|parts| parts.is_empty()) {
|
||||
None
|
||||
} else {
|
||||
Some((buf, trimmed_parts, highlights, confusion_type))
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Signifies that the compiler died with an explicit call to `.bug`
|
||||
/// or `.span_bug` rather than a failed assertion, etc.
|
||||
pub struct ExplicitBug;
|
||||
|
|
@ -1961,15 +1697,6 @@ impl Level {
|
|||
pub fn is_failure_note(&self) -> bool {
|
||||
matches!(*self, FailureNote)
|
||||
}
|
||||
|
||||
// Can this level be used in a subdiagnostic message?
|
||||
fn can_be_subdiag(&self) -> bool {
|
||||
match self {
|
||||
Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
|
||||
|
||||
Warning | Note | Help | OnceNote | OnceHelp => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagArg for Level {
|
||||
|
|
@ -1978,6 +1705,24 @@ impl IntoDiagArg for Level {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub enum Style {
|
||||
MainHeaderMsg,
|
||||
HeaderMsg,
|
||||
LineAndColumn,
|
||||
LineNumber,
|
||||
Quotation,
|
||||
UnderlinePrimary,
|
||||
UnderlineSecondary,
|
||||
LabelPrimary,
|
||||
LabelSecondary,
|
||||
NoStyle,
|
||||
Level(Level),
|
||||
Highlight,
|
||||
Addition,
|
||||
Removal,
|
||||
}
|
||||
|
||||
// FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
|
||||
pub fn elided_lifetime_in_path_suggestion(
|
||||
source_map: &SourceMap,
|
||||
|
|
|
|||
|
|
@ -1,214 +0,0 @@
|
|||
// Code for annotating snippets.
|
||||
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
|
||||
use crate::{Level, Loc};
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub(crate) struct Line {
|
||||
pub line_index: usize,
|
||||
pub annotations: Vec<Annotation>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Default)]
|
||||
pub(crate) struct AnnotationColumn {
|
||||
/// the (0-indexed) column for *display* purposes, counted in characters, not utf-8 bytes
|
||||
pub display: usize,
|
||||
/// the (0-indexed) column in the file, counted in characters, not utf-8 bytes.
|
||||
///
|
||||
/// this may be different from `self.display`,
|
||||
/// e.g. if the file contains hard tabs, because we convert tabs to spaces for error messages.
|
||||
///
|
||||
/// for example:
|
||||
/// ```text
|
||||
/// (hard tab)hello
|
||||
/// ^ this is display column 4, but file column 1
|
||||
/// ```
|
||||
///
|
||||
/// we want to keep around the correct file offset so that column numbers in error messages
|
||||
/// are correct. (motivated by <https://github.com/rust-lang/rust/issues/109537>)
|
||||
pub file: usize,
|
||||
}
|
||||
|
||||
impl AnnotationColumn {
|
||||
pub(crate) fn from_loc(loc: &Loc) -> AnnotationColumn {
|
||||
AnnotationColumn { display: loc.col_display, file: loc.col.0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub(crate) struct MultilineAnnotation {
|
||||
pub depth: usize,
|
||||
pub line_start: usize,
|
||||
pub line_end: usize,
|
||||
pub start_col: AnnotationColumn,
|
||||
pub end_col: AnnotationColumn,
|
||||
pub is_primary: bool,
|
||||
pub label: Option<String>,
|
||||
pub overlaps_exactly: bool,
|
||||
}
|
||||
|
||||
impl MultilineAnnotation {
|
||||
pub(crate) fn increase_depth(&mut self) {
|
||||
self.depth += 1;
|
||||
}
|
||||
|
||||
/// Compare two `MultilineAnnotation`s considering only the `Span` they cover.
|
||||
pub(crate) fn same_span(&self, other: &MultilineAnnotation) -> bool {
|
||||
self.line_start == other.line_start
|
||||
&& self.line_end == other.line_end
|
||||
&& self.start_col == other.start_col
|
||||
&& self.end_col == other.end_col
|
||||
}
|
||||
|
||||
pub(crate) fn as_start(&self) -> Annotation {
|
||||
Annotation {
|
||||
start_col: self.start_col,
|
||||
end_col: AnnotationColumn {
|
||||
// these might not correspond to the same place anymore,
|
||||
// but that's okay for our purposes
|
||||
display: self.start_col.display + 1,
|
||||
file: self.start_col.file + 1,
|
||||
},
|
||||
is_primary: self.is_primary,
|
||||
label: None,
|
||||
annotation_type: AnnotationType::MultilineStart(self.depth),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_end(&self) -> Annotation {
|
||||
Annotation {
|
||||
start_col: AnnotationColumn {
|
||||
// these might not correspond to the same place anymore,
|
||||
// but that's okay for our purposes
|
||||
display: self.end_col.display.saturating_sub(1),
|
||||
file: self.end_col.file.saturating_sub(1),
|
||||
},
|
||||
end_col: self.end_col,
|
||||
is_primary: self.is_primary,
|
||||
label: self.label.clone(),
|
||||
annotation_type: AnnotationType::MultilineEnd(self.depth),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_line(&self) -> Annotation {
|
||||
Annotation {
|
||||
start_col: Default::default(),
|
||||
end_col: Default::default(),
|
||||
is_primary: self.is_primary,
|
||||
label: None,
|
||||
annotation_type: AnnotationType::MultilineLine(self.depth),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub(crate) enum AnnotationType {
|
||||
/// Annotation under a single line of code
|
||||
Singleline,
|
||||
|
||||
// The Multiline type above is replaced with the following three in order
|
||||
// to reuse the current label drawing code.
|
||||
//
|
||||
// Each of these corresponds to one part of the following diagram:
|
||||
//
|
||||
// x | foo(1 + bar(x,
|
||||
// | _________^ < MultilineStart
|
||||
// x | | y), < MultilineLine
|
||||
// | |______________^ label < MultilineEnd
|
||||
// x | z);
|
||||
/// Annotation marking the first character of a fully shown multiline span
|
||||
MultilineStart(usize),
|
||||
/// Annotation marking the last character of a fully shown multiline span
|
||||
MultilineEnd(usize),
|
||||
/// Line at the left enclosing the lines of a fully shown multiline span
|
||||
// Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
|
||||
// and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
|
||||
// `draw_multiline_line`.
|
||||
MultilineLine(usize),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub(crate) struct Annotation {
|
||||
/// Start column.
|
||||
/// Note that it is important that this field goes
|
||||
/// first, so that when we sort, we sort orderings by start
|
||||
/// column.
|
||||
pub start_col: AnnotationColumn,
|
||||
|
||||
/// End column within the line (exclusive)
|
||||
pub end_col: AnnotationColumn,
|
||||
|
||||
/// Is this annotation derived from primary span
|
||||
pub is_primary: bool,
|
||||
|
||||
/// Optional label to display adjacent to the annotation.
|
||||
pub label: Option<String>,
|
||||
|
||||
/// Is this a single line, multiline or multiline span minimized down to a
|
||||
/// smaller span.
|
||||
pub annotation_type: AnnotationType,
|
||||
}
|
||||
|
||||
impl Annotation {
|
||||
/// Whether this annotation is a vertical line placeholder.
|
||||
pub(crate) fn is_line(&self) -> bool {
|
||||
matches!(self.annotation_type, AnnotationType::MultilineLine(_))
|
||||
}
|
||||
|
||||
/// Length of this annotation as displayed in the stderr output
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
// Account for usize underflows
|
||||
self.end_col.display.abs_diff(self.start_col.display)
|
||||
}
|
||||
|
||||
pub(crate) fn has_label(&self) -> bool {
|
||||
if let Some(ref label) = self.label {
|
||||
// Consider labels with no text as effectively not being there
|
||||
// to avoid weird output with unnecessary vertical lines, like:
|
||||
//
|
||||
// X | fn foo(x: u32) {
|
||||
// | -------^------
|
||||
// | | |
|
||||
// | |
|
||||
// |
|
||||
//
|
||||
// Note that this would be the complete output users would see.
|
||||
!label.is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn takes_space(&self) -> bool {
|
||||
// Multiline annotations always have to keep vertical space.
|
||||
matches!(
|
||||
self.annotation_type,
|
||||
AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct StyledString {
|
||||
pub text: String,
|
||||
pub style: Style,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub enum Style {
|
||||
MainHeaderMsg,
|
||||
HeaderMsg,
|
||||
LineAndColumn,
|
||||
LineNumber,
|
||||
Quotation,
|
||||
UnderlinePrimary,
|
||||
UnderlineSecondary,
|
||||
LabelPrimary,
|
||||
LabelSecondary,
|
||||
NoStyle,
|
||||
Level(Level),
|
||||
Highlight,
|
||||
Addition,
|
||||
Removal,
|
||||
}
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
// Code for creating styled buffers
|
||||
|
||||
use crate::snippet::{Style, StyledString};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct StyledBuffer {
|
||||
lines: Vec<Vec<StyledChar>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct StyledChar {
|
||||
chr: char,
|
||||
style: Style,
|
||||
}
|
||||
|
||||
impl StyledChar {
|
||||
const SPACE: Self = StyledChar::new(' ', Style::NoStyle);
|
||||
|
||||
const fn new(chr: char, style: Style) -> Self {
|
||||
StyledChar { chr, style }
|
||||
}
|
||||
}
|
||||
|
||||
impl StyledBuffer {
|
||||
pub(crate) fn new() -> StyledBuffer {
|
||||
StyledBuffer { lines: vec![] }
|
||||
}
|
||||
|
||||
/// Returns content of `StyledBuffer` split by lines and line styles
|
||||
pub(crate) fn render(&self) -> Vec<Vec<StyledString>> {
|
||||
// Tabs are assumed to have been replaced by spaces in calling code.
|
||||
debug_assert!(self.lines.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t')));
|
||||
|
||||
let mut output: Vec<Vec<StyledString>> = vec![];
|
||||
let mut styled_vec: Vec<StyledString> = vec![];
|
||||
|
||||
for styled_line in &self.lines {
|
||||
let mut current_style = Style::NoStyle;
|
||||
let mut current_text = String::new();
|
||||
|
||||
for sc in styled_line {
|
||||
if sc.style != current_style {
|
||||
if !current_text.is_empty() {
|
||||
styled_vec.push(StyledString { text: current_text, style: current_style });
|
||||
}
|
||||
current_style = sc.style;
|
||||
current_text = String::new();
|
||||
}
|
||||
current_text.push(sc.chr);
|
||||
}
|
||||
if !current_text.is_empty() {
|
||||
styled_vec.push(StyledString { text: current_text, style: current_style });
|
||||
}
|
||||
|
||||
// We're done with the row, push and keep going
|
||||
output.push(styled_vec);
|
||||
|
||||
styled_vec = vec![];
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
fn ensure_lines(&mut self, line: usize) {
|
||||
if line >= self.lines.len() {
|
||||
self.lines.resize(line + 1, Vec::new());
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets `chr` with `style` for given `line`, `col`.
|
||||
/// If `line` does not exist in our buffer, adds empty lines up to the given
|
||||
/// and fills the last line with unstyled whitespace.
|
||||
pub(crate) fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
|
||||
self.ensure_lines(line);
|
||||
if col >= self.lines[line].len() {
|
||||
self.lines[line].resize(col + 1, StyledChar::SPACE);
|
||||
}
|
||||
self.lines[line][col] = StyledChar::new(chr, style);
|
||||
}
|
||||
|
||||
/// Sets `string` with `style` for given `line`, starting from `col`.
|
||||
/// If `line` does not exist in our buffer, adds empty lines up to the given
|
||||
/// and fills the last line with unstyled whitespace.
|
||||
pub(crate) fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
|
||||
let mut n = col;
|
||||
for c in string.chars() {
|
||||
self.putc(line, n, c, style);
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn replace(&mut self, line: usize, start: usize, end: usize, string: &str) {
|
||||
if start == end {
|
||||
return;
|
||||
}
|
||||
if start > self.lines[line].len() || end > self.lines[line].len() {
|
||||
return;
|
||||
}
|
||||
let _ = self.lines[line].drain(start..(end - string.chars().count()));
|
||||
for (i, c) in string.chars().enumerate() {
|
||||
self.lines[line][start + i] = StyledChar::new(c, Style::LineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/// For given `line` inserts `string` with `style` before old content of that line,
|
||||
/// adding lines if needed
|
||||
pub(crate) fn prepend(&mut self, line: usize, string: &str, style: Style) {
|
||||
self.ensure_lines(line);
|
||||
let string_len = string.chars().count();
|
||||
|
||||
if !self.lines[line].is_empty() {
|
||||
// Push the old content over to make room for new content
|
||||
for _ in 0..string_len {
|
||||
self.lines[line].insert(0, StyledChar::SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
self.puts(line, 0, string, style);
|
||||
}
|
||||
|
||||
/// For given `line` inserts `string` with `style` after old content of that line,
|
||||
/// adding lines if needed
|
||||
pub(crate) fn append(&mut self, line: usize, string: &str, style: Style) {
|
||||
if line >= self.lines.len() {
|
||||
self.puts(line, 0, string, style);
|
||||
} else {
|
||||
let col = self.lines[line].len();
|
||||
self.puts(line, col, string, style);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn num_lines(&self) -> usize {
|
||||
self.lines.len()
|
||||
}
|
||||
|
||||
/// Set `style` for `line`, `col_start..col_end` range if:
|
||||
/// 1. That line and column range exist in `StyledBuffer`
|
||||
/// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
|
||||
pub(crate) fn set_style_range(
|
||||
&mut self,
|
||||
line: usize,
|
||||
col_start: usize,
|
||||
col_end: usize,
|
||||
style: Style,
|
||||
overwrite: bool,
|
||||
) {
|
||||
for col in col_start..col_end {
|
||||
self.set_style(line, col, style, overwrite);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set `style` for `line`, `col` if:
|
||||
/// 1. That line and column exist in `StyledBuffer`
|
||||
/// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
|
||||
fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
|
||||
if let Some(ref mut line) = self.lines.get_mut(line)
|
||||
&& let Some(StyledChar { style: s, .. }) = line.get_mut(col)
|
||||
&& (overwrite || matches!(s, Style::NoStyle | Style::Quotation))
|
||||
{
|
||||
*s = style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,8 +7,7 @@ pub use rustc_error_messages::{FluentArgs, LazyFallbackBundle};
|
|||
use tracing::{debug, trace};
|
||||
|
||||
use crate::error::{TranslateError, TranslateErrorKind};
|
||||
use crate::snippet::Style;
|
||||
use crate::{DiagArg, DiagMessage, FluentBundle};
|
||||
use crate::{DiagArg, DiagMessage, FluentBundle, Style};
|
||||
|
||||
/// Convert diagnostic arguments (a rustc internal type that exists to implement
|
||||
/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(macro_metavar_expr)]
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ declare_features! (
|
|||
/// Allows a test to fail without failing the whole suite.
|
||||
(removed, allow_fail, "1.60.0", Some(46488), Some("removed due to no clear use cases"), 93416),
|
||||
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
|
||||
(removed, associated_const_equality, "CURRENT_RUSTC_VERSION", Some(92827),
|
||||
(removed, associated_const_equality, "1.94.0", Some(92827),
|
||||
Some("merged into `min_generic_const_args`")),
|
||||
(removed, await_macro, "1.38.0", Some(50547),
|
||||
Some("subsumed by `.await` syntax"), 62293),
|
||||
|
|
@ -275,7 +275,7 @@ declare_features! (
|
|||
(removed, static_nobundle, "1.63.0", Some(37403),
|
||||
Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#), 95818),
|
||||
/// Allows string patterns to dereference values to match them.
|
||||
(removed, string_deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), Some("superseded by `deref_patterns`"), 150530),
|
||||
(removed, string_deref_patterns, "1.94.0", Some(87121), Some("superseded by `deref_patterns`"), 150530),
|
||||
(removed, struct_inherit, "1.0.0", None, None),
|
||||
(removed, test_removed_feature, "1.0.0", None, None),
|
||||
/// Allows using items which are missing stability attributes
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ declare_features! (
|
|||
/// Allows writing custom MIR
|
||||
(internal, custom_mir, "1.65.0", None),
|
||||
/// Implementation details of externally implementable items
|
||||
(internal, eii_internals, "CURRENT_RUSTC_VERSION", None),
|
||||
(internal, eii_internals, "1.94.0", None),
|
||||
/// Outputs useful `assert!` messages
|
||||
(unstable, generic_assert, "1.63.0", None),
|
||||
/// Allows using the #[rustc_intrinsic] attribute.
|
||||
|
|
@ -477,7 +477,7 @@ declare_features! (
|
|||
/// Allows using `#[export_stable]` which indicates that an item is exportable.
|
||||
(incomplete, export_stable, "1.88.0", Some(139939)),
|
||||
/// Externally implementable items
|
||||
(unstable, extern_item_impls, "CURRENT_RUSTC_VERSION", Some(125418)),
|
||||
(unstable, extern_item_impls, "1.94.0", Some(125418)),
|
||||
/// Allows defining `extern type`s.
|
||||
(unstable, extern_types, "1.23.0", Some(43467)),
|
||||
/// Allow using 128-bit (quad precision) floating point numbers.
|
||||
|
|
@ -667,7 +667,7 @@ declare_features! (
|
|||
/// Allows using `try {...}` expressions.
|
||||
(unstable, try_blocks, "1.29.0", Some(31436)),
|
||||
/// Allows using `try bikeshed TargetType {...}` expressions.
|
||||
(unstable, try_blocks_heterogeneous, "CURRENT_RUSTC_VERSION", Some(149488)),
|
||||
(unstable, try_blocks_heterogeneous, "1.94.0", Some(149488)),
|
||||
/// Allows `impl Trait` to be used inside type aliases (RFC 2515).
|
||||
(unstable, type_alias_impl_trait, "1.38.0", Some(63063)),
|
||||
/// Allows creation of instances of a struct by moving fields that have
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ use fluent_syntax::ast::{
|
|||
Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern, PatternElement,
|
||||
};
|
||||
use fluent_syntax::parser::ParserError;
|
||||
#[cfg(not(bootstrap))]
|
||||
use proc_macro::tracked::path;
|
||||
#[cfg(bootstrap)]
|
||||
use proc_macro::tracked_path::path;
|
||||
use proc_macro::{Diagnostic, Level, Span};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(rustc::default_hash_types)]
|
||||
#![cfg_attr(bootstrap, feature(track_path))]
|
||||
#![cfg_attr(not(bootstrap), feature(proc_macro_tracked_path))]
|
||||
#![feature(proc_macro_diagnostic)]
|
||||
#![feature(proc_macro_tracked_path)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
|
|
|||
|
|
@ -588,6 +588,108 @@ pub enum CollapseMacroDebuginfo {
|
|||
Yes = 3,
|
||||
}
|
||||
|
||||
/// Crate type, as specified by `#![crate_type]`
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Default, PartialOrd, Eq, Ord)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable, PrintAttribute)]
|
||||
pub enum CrateType {
|
||||
/// `#![crate_type = "bin"]`
|
||||
Executable,
|
||||
/// `#![crate_type = "dylib"]`
|
||||
Dylib,
|
||||
/// `#![crate_type = "rlib"]` or `#![crate_type = "lib"]`
|
||||
#[default]
|
||||
Rlib,
|
||||
/// `#![crate_type = "staticlib"]`
|
||||
StaticLib,
|
||||
/// `#![crate_type = "cdylib"]`
|
||||
Cdylib,
|
||||
/// `#![crate_type = "proc-macro"]`
|
||||
ProcMacro,
|
||||
/// `#![crate_type = "sdylib"]`
|
||||
// Unstable; feature(export_stable)
|
||||
Sdylib,
|
||||
}
|
||||
|
||||
impl CrateType {
|
||||
/// Pairs of each `#[crate_type] = "..."` value and the crate type it resolves to
|
||||
pub fn all() -> &'static [(Symbol, Self)] {
|
||||
debug_assert_eq!(CrateType::default(), CrateType::Rlib);
|
||||
&[
|
||||
(rustc_span::sym::lib, CrateType::Rlib),
|
||||
(rustc_span::sym::rlib, CrateType::Rlib),
|
||||
(rustc_span::sym::dylib, CrateType::Dylib),
|
||||
(rustc_span::sym::cdylib, CrateType::Cdylib),
|
||||
(rustc_span::sym::staticlib, CrateType::StaticLib),
|
||||
(rustc_span::sym::proc_dash_macro, CrateType::ProcMacro),
|
||||
(rustc_span::sym::bin, CrateType::Executable),
|
||||
(rustc_span::sym::sdylib, CrateType::Sdylib),
|
||||
]
|
||||
}
|
||||
|
||||
/// Same as [`CrateType::all`], but does not include unstable options.
|
||||
/// Used for diagnostics.
|
||||
pub fn all_stable() -> &'static [(Symbol, Self)] {
|
||||
debug_assert_eq!(CrateType::default(), CrateType::Rlib);
|
||||
&[
|
||||
(rustc_span::sym::lib, CrateType::Rlib),
|
||||
(rustc_span::sym::rlib, CrateType::Rlib),
|
||||
(rustc_span::sym::dylib, CrateType::Dylib),
|
||||
(rustc_span::sym::cdylib, CrateType::Cdylib),
|
||||
(rustc_span::sym::staticlib, CrateType::StaticLib),
|
||||
(rustc_span::sym::proc_dash_macro, CrateType::ProcMacro),
|
||||
(rustc_span::sym::bin, CrateType::Executable),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn has_metadata(self) -> bool {
|
||||
match self {
|
||||
CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
|
||||
CrateType::Executable
|
||||
| CrateType::Cdylib
|
||||
| CrateType::StaticLib
|
||||
| CrateType::Sdylib => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Symbol> for CrateType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: Symbol) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
rustc_span::sym::bin => CrateType::Executable,
|
||||
rustc_span::sym::dylib => CrateType::Dylib,
|
||||
rustc_span::sym::staticlib => CrateType::StaticLib,
|
||||
rustc_span::sym::cdylib => CrateType::Cdylib,
|
||||
rustc_span::sym::rlib => CrateType::Rlib,
|
||||
rustc_span::sym::lib => CrateType::default(),
|
||||
rustc_span::sym::proc_dash_macro => CrateType::ProcMacro,
|
||||
rustc_span::sym::sdylib => CrateType::Sdylib,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CrateType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match *self {
|
||||
CrateType::Executable => "bin".fmt(f),
|
||||
CrateType::Dylib => "dylib".fmt(f),
|
||||
CrateType::Rlib => "rlib".fmt(f),
|
||||
CrateType::StaticLib => "staticlib".fmt(f),
|
||||
CrateType::Cdylib => "cdylib".fmt(f),
|
||||
CrateType::ProcMacro => "proc-macro".fmt(f),
|
||||
CrateType::Sdylib => "sdylib".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagArg for CrateType {
|
||||
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
|
||||
self.to_string().into_diag_arg(&mut None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents parsed *built-in* inert attributes.
|
||||
///
|
||||
/// ## Overview
|
||||
|
|
@ -687,6 +789,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[collapse_debuginfo]`.
|
||||
CollapseDebugInfo(CollapseMacroDebuginfo),
|
||||
|
||||
/// Represents `#[compiler_builtins]`.
|
||||
CompilerBuiltins,
|
||||
|
||||
/// Represents `#[rustc_confusables]`.
|
||||
Confusables {
|
||||
symbols: ThinVec<Symbol>,
|
||||
|
|
@ -716,6 +821,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[crate_name = ...]`
|
||||
CrateName { name: Symbol, name_span: Span, attr_span: Span },
|
||||
|
||||
/// Represents `#![crate_type = ...]`
|
||||
CrateType(ThinVec<CrateType>),
|
||||
|
||||
/// Represents `#[custom_mir]`.
|
||||
CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span),
|
||||
|
||||
|
|
@ -843,6 +951,12 @@ pub enum AttributeKind {
|
|||
/// Represents `#[needs_allocator]`
|
||||
NeedsAllocator,
|
||||
|
||||
/// Represents `#[needs_panic_runtime]`
|
||||
NeedsPanicRuntime,
|
||||
|
||||
/// Represents `#[no_builtins]`
|
||||
NoBuiltins,
|
||||
|
||||
/// Represents `#[no_core]`
|
||||
NoCore(Span),
|
||||
|
||||
|
|
@ -873,6 +987,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[optimize(size|speed)]`
|
||||
Optimize(OptimizeAttr, Span),
|
||||
|
||||
/// Represents `#[panic_runtime]`
|
||||
PanicRuntime,
|
||||
|
||||
/// Represents `#[rustc_paren_sugar]`.
|
||||
ParenSugar(Span),
|
||||
|
||||
|
|
@ -903,6 +1020,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[proc_macro_derive]`
|
||||
ProcMacroDerive { trait_name: Symbol, helper_attrs: ThinVec<Symbol>, span: Span },
|
||||
|
||||
/// Represents `#[profiler_runtime]`
|
||||
ProfilerRuntime,
|
||||
|
||||
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
|
||||
PubTransparent(Span),
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ impl AttributeKind {
|
|||
Coinductive(..) => No,
|
||||
Cold(..) => No,
|
||||
CollapseDebugInfo(..) => Yes,
|
||||
CompilerBuiltins => No,
|
||||
Confusables { .. } => Yes,
|
||||
ConstContinue(..) => No,
|
||||
ConstStability { .. } => Yes,
|
||||
|
|
@ -39,6 +40,7 @@ impl AttributeKind {
|
|||
Coroutine(..) => No,
|
||||
Coverage(..) => No,
|
||||
CrateName { .. } => No,
|
||||
CrateType(_) => No,
|
||||
CustomMir(_, _, _) => Yes,
|
||||
DebuggerVisualizer(..) => No,
|
||||
DenyExplicitImpl(..) => No,
|
||||
|
|
@ -76,6 +78,8 @@ impl AttributeKind {
|
|||
MustUse { .. } => Yes,
|
||||
Naked(..) => No,
|
||||
NeedsAllocator => No,
|
||||
NeedsPanicRuntime => No,
|
||||
NoBuiltins => Yes,
|
||||
NoCore(..) => No,
|
||||
NoImplicitPrelude(..) => No,
|
||||
NoLink => No,
|
||||
|
|
@ -86,6 +90,7 @@ impl AttributeKind {
|
|||
ObjcClass { .. } => No,
|
||||
ObjcSelector { .. } => No,
|
||||
Optimize(..) => No,
|
||||
PanicRuntime => No,
|
||||
ParenSugar(..) => No,
|
||||
PassByValue(..) => Yes,
|
||||
PatchableFunctionEntry { .. } => Yes,
|
||||
|
|
@ -96,6 +101,7 @@ impl AttributeKind {
|
|||
ProcMacro(..) => No,
|
||||
ProcMacroAttribute(..) => No,
|
||||
ProcMacroDerive { .. } => No,
|
||||
ProfilerRuntime => No,
|
||||
PubTransparent(..) => Yes,
|
||||
RecursionLimit { .. } => No,
|
||||
Repr { .. } => No,
|
||||
|
|
|
|||
|
|
@ -165,6 +165,11 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
|
|||
hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
|
||||
.label = parameter captured again here
|
||||
|
||||
hir_analysis_dyn_trait_assoc_item_binding_mentions_self =
|
||||
{$kind} binding in trait object type mentions `Self`
|
||||
.label = contains a mention of `Self`
|
||||
.binding_label = this binding mentions `Self`
|
||||
|
||||
hir_analysis_eii_with_generics =
|
||||
`{$impl_name}` cannot have generic parameters other than lifetimes
|
||||
.label = required by this attribute
|
||||
|
|
@ -330,6 +335,31 @@ hir_analysis_manual_implementation =
|
|||
hir_analysis_method_should_return_future = method should be `async` or return a future, but it is synchronous
|
||||
.note = this method is `async` so it expects a future to be returned
|
||||
|
||||
hir_analysis_missing_generic_params =
|
||||
the {$descr} {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} {$parameters} must be explicitly specified
|
||||
.label = {$descr} {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} {$parameters} must be specified for this
|
||||
.suggestion = explicitly specify the {$descr} {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
}
|
||||
.no_suggestion_label = missing {$parameterCount ->
|
||||
[one] reference
|
||||
*[other] references
|
||||
} to {$parameters}
|
||||
.note = because the parameter {$parameterCount ->
|
||||
[one] default references
|
||||
*[other] defaults reference
|
||||
} `Self`, the {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} must be specified on the trait object type
|
||||
|
||||
hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}`
|
||||
.label = missing one of `{$missing_items_msg}` in implementation
|
||||
.note = required because of this annotation
|
||||
|
|
@ -346,34 +376,6 @@ hir_analysis_missing_trait_item_unstable = not all trait items implemented, miss
|
|||
.some_note = use of unstable library feature `{$feature}`: {$reason}
|
||||
.none_note = use of unstable library feature `{$feature}`
|
||||
|
||||
hir_analysis_missing_type_params =
|
||||
the type {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} {$parameters} must be explicitly specified
|
||||
.label = type {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} {$parameters} must be specified for this
|
||||
.suggestion = set the type {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} to the desired {$parameterCount ->
|
||||
[one] type
|
||||
*[other] types
|
||||
}
|
||||
.no_suggestion_label = missing {$parameterCount ->
|
||||
[one] reference
|
||||
*[other] references
|
||||
} to {$parameters}
|
||||
.note = because the parameter {$parameterCount ->
|
||||
[one] default references
|
||||
*[other] defaults reference
|
||||
} `Self`, the {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} must be specified on the object type
|
||||
|
||||
hir_analysis_no_variant_named = no variant named `{$ident}` found for enum `{$ty}`
|
||||
|
||||
hir_analysis_not_supported_delegation = {$descr}
|
||||
|
|
@ -481,9 +483,6 @@ hir_analysis_self_in_impl_self =
|
|||
`Self` is not valid in the self type of an impl block
|
||||
.note = replace `Self` with a different type
|
||||
|
||||
hir_analysis_self_in_type_alias = `Self` is not allowed in type aliases
|
||||
.label = `Self` is only available in impls, traits, and concrete type definitions
|
||||
|
||||
hir_analysis_self_ty_not_captured = `impl Trait` must mention the `Self` type of the trait in `use<...>`
|
||||
.label = `Self` type parameter is implicitly captured by this `impl Trait`
|
||||
.note = currently, all type parameters are required to be mentioned in the precise captures list
|
||||
|
|
|
|||
|
|
@ -1960,7 +1960,7 @@ fn compare_generic_param_kinds<'tcx>(
|
|||
trait_item: ty::AssocItem,
|
||||
delay: bool,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
assert_eq!(impl_item.as_tag(), trait_item.as_tag());
|
||||
assert_eq!(impl_item.tag(), trait_item.tag());
|
||||
|
||||
let ty_const_params_of = |def_id| {
|
||||
tcx.generics_of(def_id).own_params.iter().filter(|param| {
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ use rustc_abi::ExternAbi;
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
|
||||
MultiSpan,
|
||||
MultiSpan, listify,
|
||||
};
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
|
@ -400,35 +400,58 @@ pub(crate) struct UnconstrainedOpaqueType {
|
|||
pub what: &'static str,
|
||||
}
|
||||
|
||||
pub(crate) struct MissingTypeParams {
|
||||
pub(crate) struct MissingGenericParams {
|
||||
pub span: Span,
|
||||
pub def_span: Span,
|
||||
pub span_snippet: Option<String>,
|
||||
pub missing_type_params: Vec<Symbol>,
|
||||
pub missing_generic_params: Vec<(Symbol, ty::GenericParamDefKind)>,
|
||||
pub empty_generic_args: bool,
|
||||
}
|
||||
|
||||
// Manual implementation of `Diagnostic` to be able to call `span_to_snippet`.
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams {
|
||||
// FIXME: This doesn't need to be a manual impl!
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingGenericParams {
|
||||
#[track_caller]
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
let mut err = Diag::new(dcx, level, fluent::hir_analysis_missing_type_params);
|
||||
let mut err = Diag::new(dcx, level, fluent::hir_analysis_missing_generic_params);
|
||||
err.span(self.span);
|
||||
err.code(E0393);
|
||||
err.arg("parameterCount", self.missing_type_params.len());
|
||||
err.arg(
|
||||
"parameters",
|
||||
self.missing_type_params
|
||||
.iter()
|
||||
.map(|n| format!("`{n}`"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
);
|
||||
|
||||
err.span_label(self.def_span, fluent::hir_analysis_label);
|
||||
|
||||
enum Descr {
|
||||
Generic,
|
||||
Type,
|
||||
Const,
|
||||
}
|
||||
|
||||
let mut descr = None;
|
||||
for (_, kind) in &self.missing_generic_params {
|
||||
descr = match (&descr, kind) {
|
||||
(None, ty::GenericParamDefKind::Type { .. }) => Some(Descr::Type),
|
||||
(None, ty::GenericParamDefKind::Const { .. }) => Some(Descr::Const),
|
||||
(Some(Descr::Type), ty::GenericParamDefKind::Const { .. })
|
||||
| (Some(Descr::Const), ty::GenericParamDefKind::Type { .. }) => {
|
||||
Some(Descr::Generic)
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
err.arg(
|
||||
"descr",
|
||||
match descr.unwrap() {
|
||||
Descr::Generic => "generic",
|
||||
Descr::Type => "type",
|
||||
Descr::Const => "const",
|
||||
},
|
||||
);
|
||||
err.arg("parameterCount", self.missing_generic_params.len());
|
||||
err.arg(
|
||||
"parameters",
|
||||
listify(&self.missing_generic_params, |(n, _)| format!("`{n}`")).unwrap(),
|
||||
);
|
||||
|
||||
let mut suggested = false;
|
||||
// Don't suggest setting the type params if there are some already: the order is
|
||||
// Don't suggest setting the generic params if there are some already: The order is
|
||||
// tricky to get right and the user will already know what the syntax is.
|
||||
if let Some(snippet) = self.span_snippet
|
||||
&& self.empty_generic_args
|
||||
|
|
@ -438,16 +461,16 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams {
|
|||
// we would have to preserve the right order. For now, as clearly the user is
|
||||
// aware of the syntax, we do nothing.
|
||||
} else {
|
||||
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
|
||||
// least we can clue them to the correct syntax `Iterator<Type>`.
|
||||
// The user wrote `Trait`, so we don't have a type we can suggest, but at
|
||||
// least we can clue them to the correct syntax `Trait</* Term */>`.
|
||||
err.span_suggestion_verbose(
|
||||
self.span.shrink_to_hi(),
|
||||
fluent::hir_analysis_suggestion,
|
||||
format!(
|
||||
"<{}>",
|
||||
self.missing_type_params
|
||||
self.missing_generic_params
|
||||
.iter()
|
||||
.map(|n| n.to_string())
|
||||
.map(|(n, _)| format!("/* {n} */"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
|
|
@ -1609,11 +1632,14 @@ pub(crate) enum SupertraitItemShadowee {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_self_in_type_alias, code = E0411)]
|
||||
pub(crate) struct SelfInTypeAlias {
|
||||
#[diag(hir_analysis_dyn_trait_assoc_item_binding_mentions_self)]
|
||||
pub(crate) struct DynTraitAssocItemBindingMentionsSelf {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub kind: &'static str,
|
||||
#[label(hir_analysis_binding_label)]
|
||||
pub binding: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use smallvec::{SmallVec, smallvec};
|
|||
use tracing::{debug, instrument};
|
||||
|
||||
use super::HirTyLowerer;
|
||||
use crate::errors::SelfInTypeAlias;
|
||||
use crate::errors::DynTraitAssocItemBindingMentionsSelf;
|
||||
use crate::hir_ty_lowering::{
|
||||
GenericArgCountMismatch, ImpliedBoundsContext, OverlappingAsssocItemConstraints,
|
||||
PredicateFilter, RegionInferReason,
|
||||
|
|
@ -56,8 +56,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
|
||||
let mut user_written_bounds = Vec::new();
|
||||
let mut potential_assoc_types = Vec::new();
|
||||
let mut potential_assoc_items = Vec::new();
|
||||
for poly_trait_ref in hir_bounds.iter() {
|
||||
// FIXME(mgca): We actually leak `trait_object_dummy_self` if the type of any assoc
|
||||
// const mentions `Self` (in "Self projections" which we intentionally
|
||||
// allow). That's because we query feed the instantiated type to `type_of`.
|
||||
// That's really bad, dummy self should never escape lowering! It leads us
|
||||
// to accept less code we'd like to support and can lead to ICEs later.
|
||||
let result = self.lower_poly_trait_ref(
|
||||
poly_trait_ref,
|
||||
dummy_self,
|
||||
|
|
@ -66,7 +71,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
OverlappingAsssocItemConstraints::Forbidden,
|
||||
);
|
||||
if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct {
|
||||
potential_assoc_types.extend(invalid_args);
|
||||
potential_assoc_items.extend(invalid_args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -138,31 +143,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
|
||||
// Map the projection bounds onto a key that makes it easy to remove redundant
|
||||
// bounds that are constrained by supertraits of the principal def id.
|
||||
// bounds that are constrained by supertraits of the principal trait.
|
||||
//
|
||||
// Also make sure we detect conflicting bounds from expanding a trait alias and
|
||||
// also specifying it manually, like:
|
||||
// ```
|
||||
// type Alias = Trait<Assoc = i32>;
|
||||
// let _: &dyn Alias<Assoc = u32> = /* ... */;
|
||||
// ```
|
||||
// Also make sure we detect conflicting bounds from expanding trait aliases.
|
||||
//
|
||||
// FIXME(#150936): Since the elaborated projection bounds also include the user-written ones
|
||||
// and we're separately rejecting duplicate+conflicting bindings for trait
|
||||
// object types when lowering assoc item bindings, there are basic cases
|
||||
// where we're emitting two distinct but very similar diagnostics.
|
||||
let mut projection_bounds = FxIndexMap::default();
|
||||
for (proj, proj_span) in elaborated_projection_bounds {
|
||||
let proj = proj.map_bound(|mut b| {
|
||||
if let Some(term_ty) = &b.term.as_type() {
|
||||
let references_self = term_ty.walk().any(|arg| arg == dummy_self.into());
|
||||
if references_self {
|
||||
// With trait alias and type alias combined, type resolver
|
||||
// may not be able to catch all illegal `Self` usages (issue 139082)
|
||||
let guar = self.dcx().emit_err(SelfInTypeAlias { span });
|
||||
b.term = replace_dummy_self_with_error(tcx, b.term, guar);
|
||||
}
|
||||
let item_def_id = proj.item_def_id();
|
||||
|
||||
let proj = proj.map_bound(|mut proj| {
|
||||
let references_self = proj.term.walk().any(|arg| arg == dummy_self.into());
|
||||
if references_self {
|
||||
let guar = self.dcx().emit_err(DynTraitAssocItemBindingMentionsSelf {
|
||||
span,
|
||||
kind: tcx.def_descr(item_def_id),
|
||||
binding: proj_span,
|
||||
});
|
||||
proj.term = replace_dummy_self_with_error(tcx, proj.term, guar);
|
||||
}
|
||||
b
|
||||
proj
|
||||
});
|
||||
|
||||
let key = (
|
||||
proj.skip_binder().projection_term.def_id,
|
||||
item_def_id,
|
||||
tcx.anonymize_bound_vars(
|
||||
proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
|
||||
),
|
||||
|
|
@ -171,19 +178,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
projection_bounds.insert(key, (proj, proj_span))
|
||||
&& tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj)
|
||||
{
|
||||
let item = tcx.item_name(proj.item_def_id());
|
||||
let kind = tcx.def_descr(item_def_id);
|
||||
let name = tcx.item_name(item_def_id);
|
||||
self.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
format!("conflicting associated type bounds for `{item}`"),
|
||||
)
|
||||
.struct_span_err(span, format!("conflicting {kind} bindings for `{name}`"))
|
||||
.with_span_label(
|
||||
old_proj_span,
|
||||
format!("`{item}` is specified to be `{}` here", old_proj.term()),
|
||||
format!("`{name}` is specified to be `{}` here", old_proj.term()),
|
||||
)
|
||||
.with_span_label(
|
||||
proj_span,
|
||||
format!("`{item}` is specified to be `{}` here", proj.term()),
|
||||
format!("`{name}` is specified to be `{}` here", proj.term()),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
@ -191,13 +196,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
let principal_trait = regular_traits.into_iter().next();
|
||||
|
||||
// A stable ordering of associated types from the principal trait and all its
|
||||
// supertraits. We use this to ensure that different substitutions of a trait
|
||||
// don't result in `dyn Trait` types with different projections lists, which
|
||||
// can be unsound: <https://github.com/rust-lang/rust/pull/136458>.
|
||||
// We achieve a stable ordering by walking over the unsubstituted principal
|
||||
// trait ref.
|
||||
let mut ordered_associated_types = vec![];
|
||||
// A stable ordering of associated types & consts from the principal trait and all its
|
||||
// supertraits. We use this to ensure that different substitutions of a trait don't
|
||||
// result in `dyn Trait` types with different projections lists, which can be unsound:
|
||||
// <https://github.com/rust-lang/rust/pull/136458>.
|
||||
// We achieve a stable ordering by walking over the unsubstituted principal trait ref.
|
||||
let mut ordered_associated_items = vec![];
|
||||
|
||||
if let Some((principal_trait, ref spans)) = principal_trait {
|
||||
let principal_trait = principal_trait.map_bound(|trait_pred| {
|
||||
|
|
@ -223,12 +227,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// FIXME(negative_bounds): Handle this correctly...
|
||||
let trait_ref =
|
||||
tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
|
||||
ordered_associated_types.extend(
|
||||
ordered_associated_items.extend(
|
||||
tcx.associated_items(pred.trait_ref.def_id)
|
||||
.in_definition_order()
|
||||
// We only care about associated types.
|
||||
.filter(|item| item.is_type())
|
||||
// No RPITITs -- they're not dyn-compatible for now.
|
||||
// Only associated types & consts can possibly be constrained via a binding.
|
||||
.filter(|item| item.is_type() || item.is_const())
|
||||
// Traits with RPITITs are simply not dyn compatible (for now).
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
.map(|item| (item.def_id, trait_ref)),
|
||||
);
|
||||
|
|
@ -237,11 +241,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let pred = bound_predicate.rebind(pred);
|
||||
// A `Self` within the original bound will be instantiated with a
|
||||
// `trait_object_dummy_self`, so check for that.
|
||||
let references_self = match pred.skip_binder().term.kind() {
|
||||
ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
|
||||
// FIXME(mgca): We should walk the const instead of not doing anything
|
||||
ty::TermKind::Const(_) => false,
|
||||
};
|
||||
let references_self =
|
||||
pred.skip_binder().term.walk().any(|arg| arg == dummy_self.into());
|
||||
|
||||
// If the projection output contains `Self`, force the user to
|
||||
// elaborate it explicitly to avoid a lot of complexity.
|
||||
|
|
@ -262,7 +263,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// the discussion in #56288 for alternatives.
|
||||
if !references_self {
|
||||
let key = (
|
||||
pred.skip_binder().projection_term.def_id,
|
||||
pred.item_def_id(),
|
||||
tcx.anonymize_bound_vars(
|
||||
pred.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
|
||||
),
|
||||
|
|
@ -283,15 +284,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
// `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where
|
||||
// <Self as Trait>::Assoc = Foo`. So every `Projection` clause is an
|
||||
// `Assoc = Foo` bound. `needed_associated_types` contains all associated
|
||||
// types that we expect to be provided by the user, so the following loop
|
||||
// removes all the associated types that have a corresponding `Projection`
|
||||
// clause, either from expanding trait aliases or written by the user.
|
||||
// Flag assoc item bindings that didn't really need to be specified.
|
||||
for &(projection_bound, span) in projection_bounds.values() {
|
||||
let def_id = projection_bound.item_def_id();
|
||||
if tcx.generics_require_sized_self(def_id) {
|
||||
// FIXME(mgca): Ideally we would generalize the name of this lint to sth. like
|
||||
// `unused_associated_item_bindings` since this can now also trigger on *const*
|
||||
// projections / assoc *const* bindings.
|
||||
tcx.emit_node_span_lint(
|
||||
UNUSED_ASSOCIATED_TYPE_BOUNDS,
|
||||
hir_id,
|
||||
|
|
@ -301,35 +300,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
// We compute the list of projection bounds taking the ordered associated types,
|
||||
// and check if there was an entry in the collected `projection_bounds`. Those
|
||||
// are computed by first taking the user-written associated types, then elaborating
|
||||
// the principal trait ref, and only using those if there was no user-written.
|
||||
// See note below about how we handle missing associated types with `Self: Sized`,
|
||||
// which are not required to be provided, but are still used if they are provided.
|
||||
let mut missing_assoc_types = FxIndexSet::default();
|
||||
let projection_bounds: Vec<_> = ordered_associated_types
|
||||
// The user has to constrain all associated types & consts via bindings unless the
|
||||
// corresponding associated item has a `where Self: Sized` clause. This can be done
|
||||
// in the `dyn Trait` directly, in the supertrait bounds or behind trait aliases.
|
||||
//
|
||||
// Collect all associated items that weren't specified and compute the list of
|
||||
// projection bounds which we'll later turn into existential ones.
|
||||
//
|
||||
// We intentionally keep around projections whose associated item has a `Self: Sized`
|
||||
// bound in order to be able to wfcheck the RHS, allow the RHS to constrain generic
|
||||
// parameters and to imply bounds.
|
||||
// See also <https://github.com/rust-lang/rust/pull/140684>.
|
||||
let mut missing_assoc_items = FxIndexSet::default();
|
||||
let projection_bounds: Vec<_> = ordered_associated_items
|
||||
.into_iter()
|
||||
.filter_map(|key| {
|
||||
if let Some(assoc) = projection_bounds.get(&key) {
|
||||
Some(*assoc)
|
||||
} else {
|
||||
// If the associated type has a `where Self: Sized` bound, then
|
||||
// we do not need to provide the associated type. This results in
|
||||
// a `dyn Trait` type that has a different number of projection
|
||||
// bounds, which may lead to type mismatches.
|
||||
if !tcx.generics_require_sized_self(key.0) {
|
||||
missing_assoc_types.insert(key);
|
||||
}
|
||||
None
|
||||
.filter_map(|key @ (def_id, _)| {
|
||||
if let Some(&assoc) = projection_bounds.get(&key) {
|
||||
return Some(assoc);
|
||||
}
|
||||
if !tcx.generics_require_sized_self(def_id) {
|
||||
missing_assoc_items.insert(key);
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let Err(guar) = self.check_for_required_assoc_tys(
|
||||
// If there are any associated items whose value wasn't provided, bail out with an error.
|
||||
if let Err(guar) = self.check_for_required_assoc_items(
|
||||
principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
|
||||
missing_assoc_types,
|
||||
potential_assoc_types,
|
||||
missing_assoc_items,
|
||||
potential_assoc_items,
|
||||
hir_bounds,
|
||||
) {
|
||||
return Ty::new_error(tcx, guar);
|
||||
|
|
@ -354,9 +354,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
let span = *spans.first().unwrap();
|
||||
|
||||
// Verify that `dummy_self` did not leak inside default type parameters. This
|
||||
// Verify that `dummy_self` did not leak inside generic parameter defaults. This
|
||||
// could not be done at path creation, since we need to see through trait aliases.
|
||||
let mut missing_type_params = vec![];
|
||||
let mut missing_generic_params = Vec::new();
|
||||
let generics = tcx.generics_of(trait_ref.def_id);
|
||||
let args: Vec<_> = trait_ref
|
||||
.args
|
||||
|
|
@ -367,8 +367,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.map(|(index, arg)| {
|
||||
if arg.walk().any(|arg| arg == dummy_self.into()) {
|
||||
let param = &generics.own_params[index];
|
||||
missing_type_params.push(param.name);
|
||||
Ty::new_misc_error(tcx).into()
|
||||
missing_generic_params.push((param.name, param.kind.clone()));
|
||||
param.to_error(tcx)
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
|
|
@ -379,8 +379,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
|
||||
&& hir_bound.span.contains(span)
|
||||
});
|
||||
self.report_missing_type_params(
|
||||
missing_type_params,
|
||||
self.report_missing_generic_params(
|
||||
missing_generic_params,
|
||||
trait_ref.def_id,
|
||||
span,
|
||||
empty_generic_args,
|
||||
|
|
|
|||
|
|
@ -28,31 +28,29 @@ use tracing::debug;
|
|||
|
||||
use super::InherentAssocCandidate;
|
||||
use crate::errors::{
|
||||
self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
|
||||
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
|
||||
self, AssocItemConstraintsNotAllowedHere, ManualImplementation, ParenthesizedFnTraitExpansion,
|
||||
TraitObjectDeclaredWithNoTraits,
|
||||
};
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
|
||||
|
||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
|
||||
/// the type parameter's name as a placeholder.
|
||||
pub(crate) fn report_missing_type_params(
|
||||
pub(crate) fn report_missing_generic_params(
|
||||
&self,
|
||||
missing_type_params: Vec<Symbol>,
|
||||
missing_generic_params: Vec<(Symbol, ty::GenericParamDefKind)>,
|
||||
def_id: DefId,
|
||||
span: Span,
|
||||
empty_generic_args: bool,
|
||||
) {
|
||||
if missing_type_params.is_empty() {
|
||||
if missing_generic_params.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.dcx().emit_err(MissingTypeParams {
|
||||
self.dcx().emit_err(errors::MissingGenericParams {
|
||||
span,
|
||||
def_span: self.tcx().def_span(def_id),
|
||||
span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(),
|
||||
missing_type_params,
|
||||
missing_generic_params,
|
||||
empty_generic_args,
|
||||
});
|
||||
}
|
||||
|
|
@ -171,7 +169,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let all_candidate_names: Vec<_> = all_candidates()
|
||||
.flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
|
||||
.filter_map(|item| {
|
||||
if !item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag {
|
||||
if !item.is_impl_trait_in_trait() && item.tag() == assoc_tag {
|
||||
item.opt_name()
|
||||
} else {
|
||||
None
|
||||
|
|
@ -207,7 +205,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.iter()
|
||||
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
|
||||
.filter_map(|item| {
|
||||
(!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then(|| item.name())
|
||||
(!item.is_impl_trait_in_trait() && item.tag() == assoc_tag).then(|| item.name())
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
@ -220,7 +218,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.filter(|trait_def_id| {
|
||||
tcx.associated_items(trait_def_id)
|
||||
.filter_by_name_unhygienic(suggested_name)
|
||||
.any(|item| item.as_tag() == assoc_tag)
|
||||
.any(|item| item.tag() == assoc_tag)
|
||||
})
|
||||
.collect::<Vec<_>>()[..]
|
||||
{
|
||||
|
|
@ -383,9 +381,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir::Term::Ty(ty) => ty.span,
|
||||
hir::Term::Const(ct) => ct.span,
|
||||
};
|
||||
(span, Some(ident.span), assoc_item.as_tag(), assoc_tag)
|
||||
(span, Some(ident.span), assoc_item.tag(), assoc_tag)
|
||||
} else {
|
||||
(ident.span, None, assoc_tag, assoc_item.as_tag())
|
||||
(ident.span, None, assoc_tag, assoc_item.tag())
|
||||
};
|
||||
|
||||
self.dcx().emit_err(errors::AssocKindMismatch {
|
||||
|
|
@ -393,7 +391,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
expected: assoc_tag_str(expected),
|
||||
got: assoc_tag_str(got),
|
||||
expected_because_label,
|
||||
assoc_kind: assoc_tag_str(assoc_item.as_tag()),
|
||||
assoc_kind: assoc_tag_str(assoc_item.tag()),
|
||||
def_span: tcx.def_span(assoc_item.def_id),
|
||||
bound_on_assoc_const_label,
|
||||
wrap_in_braces_sugg,
|
||||
|
|
@ -909,43 +907,49 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
err.emit()
|
||||
}
|
||||
|
||||
/// When there are any missing associated types, emit an E0191 error and attempt to supply a
|
||||
/// reasonable suggestion on how to write it. For the case of multiple associated types in the
|
||||
/// same trait bound have the same name (as they come from different supertraits), we instead
|
||||
/// emit a generic note suggesting using a `where` clause to constraint instead.
|
||||
pub(crate) fn check_for_required_assoc_tys(
|
||||
/// If there are any missing associated items, emit an error instructing the user to provide
|
||||
/// them unless that's impossible due to shadowing. Moreover, if any corresponding trait refs
|
||||
/// are dyn incompatible due to associated items we emit an dyn incompatibility error instead.
|
||||
pub(crate) fn check_for_required_assoc_items(
|
||||
&self,
|
||||
spans: SmallVec<[Span; 1]>,
|
||||
missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
|
||||
potential_assoc_types: Vec<usize>,
|
||||
missing_assoc_items: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
|
||||
potential_assoc_items: Vec<usize>,
|
||||
trait_bounds: &[hir::PolyTraitRef<'_>],
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
if missing_assoc_types.is_empty() {
|
||||
if missing_assoc_items.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let tcx = self.tcx();
|
||||
let principal_span = *spans.first().unwrap();
|
||||
|
||||
let tcx = self.tcx();
|
||||
// FIXME: This logic needs some more care w.r.t handling of conflicts
|
||||
let missing_assoc_types: Vec<_> = missing_assoc_types
|
||||
let missing_assoc_items: Vec<_> = missing_assoc_items
|
||||
.into_iter()
|
||||
.map(|(def_id, trait_ref)| (tcx.associated_item(def_id), trait_ref))
|
||||
.collect();
|
||||
let mut names: FxIndexMap<_, Vec<Symbol>> = Default::default();
|
||||
let mut names: FxIndexMap<_, Vec<_>> = Default::default();
|
||||
let mut names_len = 0;
|
||||
let mut descr = None;
|
||||
|
||||
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
|
||||
// `issue-22560.rs`.
|
||||
let mut dyn_compatibility_violations = Ok(());
|
||||
for (assoc_item, trait_ref) in &missing_assoc_types {
|
||||
names.entry(trait_ref).or_default().push(assoc_item.name());
|
||||
names_len += 1;
|
||||
enum Descr {
|
||||
Item,
|
||||
Tag(ty::AssocTag),
|
||||
}
|
||||
|
||||
for &(assoc_item, trait_ref) in &missing_assoc_items {
|
||||
// We don't want to suggest specifying associated items if there's something wrong with
|
||||
// any of them that renders the trait dyn incompatible; providing them certainly won't
|
||||
// fix the issue and we could also risk suggesting invalid code.
|
||||
//
|
||||
// Note that this check is only truly necessary in item ctxts where we merely perform
|
||||
// *minimal* dyn compatibility checks. In fn ctxts we would've already bailed out with
|
||||
// an error by this point if the trait was dyn incompatible.
|
||||
let violations =
|
||||
dyn_compatibility_violations_for_assoc_item(tcx, trait_ref.def_id(), *assoc_item);
|
||||
dyn_compatibility_violations_for_assoc_item(tcx, trait_ref.def_id(), assoc_item);
|
||||
if !violations.is_empty() {
|
||||
dyn_compatibility_violations = Err(report_dyn_incompatibility(
|
||||
return Err(report_dyn_incompatibility(
|
||||
tcx,
|
||||
principal_span,
|
||||
None,
|
||||
|
|
@ -954,15 +958,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
)
|
||||
.emit());
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(guar) = dyn_compatibility_violations {
|
||||
return Err(guar);
|
||||
names.entry(trait_ref).or_default().push(assoc_item.name());
|
||||
names_len += 1;
|
||||
|
||||
descr = match descr {
|
||||
None => Some(Descr::Tag(assoc_item.tag())),
|
||||
Some(Descr::Tag(tag)) if tag != assoc_item.tag() => Some(Descr::Item),
|
||||
_ => continue,
|
||||
};
|
||||
}
|
||||
|
||||
// related to issue #91997, turbofishes added only when in an expr or pat
|
||||
let mut in_expr_or_pat = false;
|
||||
if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
|
||||
if let ([], [bound]) = (&potential_assoc_items[..], &trait_bounds) {
|
||||
let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id));
|
||||
in_expr_or_pat = match grandparent {
|
||||
hir::Node::Expr(_) | hir::Node::Pat(_) => true,
|
||||
|
|
@ -970,37 +979,41 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
};
|
||||
}
|
||||
|
||||
// We get all the associated items that _are_ set,
|
||||
// so that we can check if any of their names match one of the ones we are missing.
|
||||
// This would mean that they are shadowing the associated type we are missing,
|
||||
// and we can then use their span to indicate this to the user.
|
||||
let bound_names = trait_bounds
|
||||
.iter()
|
||||
.filter_map(|poly_trait_ref| {
|
||||
let path = poly_trait_ref.trait_ref.path.segments.last()?;
|
||||
let args = path.args?;
|
||||
// We get all the associated items that *are* set, so that we can check if any of
|
||||
// their names match one of the ones we are missing.
|
||||
// This would mean that they are shadowing the associated item we are missing, and
|
||||
// we can then use their span to indicate this to the user.
|
||||
//
|
||||
// FIXME: This does not account for trait aliases. I think we should just make
|
||||
// `lower_trait_object_ty` compute the list of all specified items or give us the
|
||||
// necessary ingredients if it's too expensive to compute in the happy path.
|
||||
let bound_names: UnordMap<_, _> =
|
||||
trait_bounds
|
||||
.iter()
|
||||
.filter_map(|poly_trait_ref| {
|
||||
let path = poly_trait_ref.trait_ref.path.segments.last()?;
|
||||
let args = path.args?;
|
||||
let Res::Def(DefKind::Trait, trait_def_id) = path.res else { return None };
|
||||
|
||||
Some(args.constraints.iter().filter_map(|constraint| {
|
||||
let ident = constraint.ident;
|
||||
Some(args.constraints.iter().filter_map(move |constraint| {
|
||||
let hir::AssocItemConstraintKind::Equality { term } = constraint.kind
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
let tag = match term {
|
||||
hir::Term::Ty(_) => ty::AssocTag::Type,
|
||||
hir::Term::Const(_) => ty::AssocTag::Const,
|
||||
};
|
||||
let assoc_item = tcx
|
||||
.associated_items(trait_def_id)
|
||||
.find_by_ident_and_kind(tcx, constraint.ident, tag, trait_def_id)?;
|
||||
Some(((constraint.ident.name, tag), assoc_item.def_id))
|
||||
}))
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
let Res::Def(DefKind::Trait, trait_def) = path.res else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind(
|
||||
tcx,
|
||||
ident,
|
||||
ty::AssocTag::Type,
|
||||
trait_def,
|
||||
);
|
||||
|
||||
Some((ident.name, assoc_item?))
|
||||
}))
|
||||
})
|
||||
.flatten()
|
||||
.collect::<UnordMap<Symbol, &ty::AssocItem>>();
|
||||
|
||||
let mut names = names
|
||||
let mut names: Vec<_> = names
|
||||
.into_iter()
|
||||
.map(|(trait_, mut assocs)| {
|
||||
assocs.sort();
|
||||
|
|
@ -1010,66 +1023,69 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
listify(&assocs[..], |a| format!("`{a}`")).unwrap_or_default()
|
||||
)
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
.collect();
|
||||
names.sort();
|
||||
let names = names.join(", ");
|
||||
|
||||
let descr = match descr.unwrap() {
|
||||
Descr::Item => "associated item",
|
||||
Descr::Tag(tag) => tag.descr(),
|
||||
};
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
principal_span,
|
||||
E0191,
|
||||
"the value of the associated type{} {} must be specified",
|
||||
pluralize!(names_len),
|
||||
names,
|
||||
"the value of the {descr}{s} {names} must be specified",
|
||||
s = pluralize!(names_len),
|
||||
);
|
||||
let mut suggestions = vec![];
|
||||
let mut types_count = 0;
|
||||
let mut items_count = 0;
|
||||
let mut where_constraints = vec![];
|
||||
let mut already_has_generics_args_suggestion = false;
|
||||
|
||||
let mut names: UnordMap<_, usize> = Default::default();
|
||||
for (item, _) in &missing_assoc_types {
|
||||
types_count += 1;
|
||||
*names.entry(item.name()).or_insert(0) += 1;
|
||||
for (item, _) in &missing_assoc_items {
|
||||
items_count += 1;
|
||||
*names.entry((item.name(), item.tag())).or_insert(0) += 1;
|
||||
}
|
||||
let mut dupes = false;
|
||||
let mut shadows = false;
|
||||
for (item, trait_ref) in &missing_assoc_types {
|
||||
for (item, trait_ref) in &missing_assoc_items {
|
||||
let name = item.name();
|
||||
let prefix = if names[&name] > 1 {
|
||||
let trait_def_id = trait_ref.def_id();
|
||||
let key = (name, item.tag());
|
||||
|
||||
if names[&key] > 1 {
|
||||
dupes = true;
|
||||
format!("{}::", tcx.def_path_str(trait_def_id))
|
||||
} else if bound_names.get(&name).is_some_and(|x| *x != item) {
|
||||
let trait_def_id = trait_ref.def_id();
|
||||
} else if bound_names.get(&key).is_some_and(|&def_id| def_id != item.def_id) {
|
||||
shadows = true;
|
||||
format!("{}::", tcx.def_path_str(trait_def_id))
|
||||
}
|
||||
|
||||
let prefix = if dupes || shadows {
|
||||
format!("{}::", tcx.def_path_str(trait_ref.def_id()))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let mut is_shadowed = false;
|
||||
|
||||
if let Some(assoc_item) = bound_names.get(&name)
|
||||
&& *assoc_item != item
|
||||
if let Some(&def_id) = bound_names.get(&key)
|
||||
&& def_id != item.def_id
|
||||
{
|
||||
is_shadowed = true;
|
||||
|
||||
let rename_message =
|
||||
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
|
||||
let rename_message = if def_id.is_local() { ", consider renaming it" } else { "" };
|
||||
err.span_label(
|
||||
tcx.def_span(assoc_item.def_id),
|
||||
format!("`{}{}` shadowed here{}", prefix, name, rename_message),
|
||||
tcx.def_span(def_id),
|
||||
format!("`{prefix}{name}` shadowed here{rename_message}"),
|
||||
);
|
||||
}
|
||||
|
||||
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
|
||||
|
||||
if let Some(sp) = tcx.hir_span_if_local(item.def_id) {
|
||||
err.span_label(sp, format!("`{}{}` defined here{}", prefix, name, rename_message));
|
||||
err.span_label(sp, format!("`{prefix}{name}` defined here{rename_message}"));
|
||||
}
|
||||
}
|
||||
if potential_assoc_types.len() == missing_assoc_types.len() {
|
||||
if potential_assoc_items.len() == missing_assoc_items.len() {
|
||||
// When the amount of missing associated types equals the number of
|
||||
// extra type arguments present. A suggesting to replace the generic args with
|
||||
// associated types is already emitted.
|
||||
|
|
@ -1077,30 +1093,48 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
} else if let (Ok(snippet), false, false) =
|
||||
(tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows)
|
||||
{
|
||||
let types: Vec<_> = missing_assoc_types
|
||||
let bindings: Vec<_> = missing_assoc_items
|
||||
.iter()
|
||||
.map(|(item, _)| format!("{} = Type", item.name()))
|
||||
.map(|(item, _)| {
|
||||
format!(
|
||||
"{} = /* {} */",
|
||||
item.name(),
|
||||
match item.kind {
|
||||
ty::AssocKind::Const { .. } => "CONST",
|
||||
ty::AssocKind::Type { .. } => "Type",
|
||||
ty::AssocKind::Fn { .. } => unreachable!(),
|
||||
}
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
// FIXME(fmease): Does not account for `dyn Trait<>` (suggs `dyn Trait<, X = Y>`).
|
||||
let code = if let Some(snippet) = snippet.strip_suffix('>') {
|
||||
// The user wrote `Trait<'a>` or similar and we don't have a type we can
|
||||
// suggest, but at least we can clue them to the correct syntax
|
||||
// `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
|
||||
// suggestion.
|
||||
format!("{}, {}>", snippet, types.join(", "))
|
||||
// The user wrote `Trait<'a>` or similar and we don't have a term we can suggest,
|
||||
// but at least we can clue them to the correct syntax `Trait<'a, Item = /* ... */>`
|
||||
// while accounting for the `<'a>` in the suggestion.
|
||||
format!("{}, {}>", snippet, bindings.join(", "))
|
||||
} else if in_expr_or_pat {
|
||||
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
|
||||
// least we can clue them to the correct syntax `Iterator::<Item = Type>`.
|
||||
format!("{}::<{}>", snippet, types.join(", "))
|
||||
// The user wrote `Trait`, so we don't have a term we can suggest, but at least we
|
||||
// can clue them to the correct syntax `Trait::<Item = /* ... */>`.
|
||||
format!("{}::<{}>", snippet, bindings.join(", "))
|
||||
} else {
|
||||
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
|
||||
// least we can clue them to the correct syntax `Iterator<Item = Type>`.
|
||||
format!("{}<{}>", snippet, types.join(", "))
|
||||
// The user wrote `Trait`, so we don't have a term we can suggest, but at least we
|
||||
// can clue them to the correct syntax `Trait<Item = /* ... */>`.
|
||||
format!("{}<{}>", snippet, bindings.join(", "))
|
||||
};
|
||||
suggestions.push((principal_span, code));
|
||||
} else if dupes {
|
||||
where_constraints.push(principal_span);
|
||||
}
|
||||
|
||||
// FIXME: This note doesn't make sense, get rid of this outright.
|
||||
// I don't see how adding a type param (to the trait?) would help.
|
||||
// If the user can modify the trait, they should just rename one of the assoc tys.
|
||||
// What does it mean with the rest of the message?
|
||||
// Does it suggest adding equality predicates (unimplemented) to the trait object
|
||||
// type? (pseudo) "dyn B + <Self as B>::X = T + <Self as A>::X = U"?
|
||||
// Instead, maybe mention shadowing if applicable (yes, even when no "relevant"
|
||||
// bindings were provided).
|
||||
let where_msg = "consider introducing a new type parameter, adding `where` constraints \
|
||||
using the fully-qualified path to the associated types";
|
||||
if !where_constraints.is_empty() && suggestions.is_empty() {
|
||||
|
|
@ -1112,12 +1146,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
if suggestions.len() != 1 || already_has_generics_args_suggestion {
|
||||
// We don't need this label if there's an inline suggestion, show otherwise.
|
||||
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
|
||||
for (item, _) in &missing_assoc_types {
|
||||
types_count += 1;
|
||||
for (item, _) in &missing_assoc_items {
|
||||
items_count += 1;
|
||||
*names.entry(item.name()).or_insert(0) += 1;
|
||||
}
|
||||
let mut label = vec![];
|
||||
for (item, trait_ref) in &missing_assoc_types {
|
||||
for (item, trait_ref) in &missing_assoc_items {
|
||||
let name = item.name();
|
||||
let postfix = if names[&name] > 1 {
|
||||
format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
|
||||
|
|
@ -1130,9 +1164,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
err.span_label(
|
||||
principal_span,
|
||||
format!(
|
||||
"associated type{} {} must be specified",
|
||||
pluralize!(label.len()),
|
||||
label.join(", "),
|
||||
"{descr}{s} {names} must be specified",
|
||||
s = pluralize!(label.len()),
|
||||
names = label.join(", "),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -1153,7 +1187,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let overlaps = suggestions.windows(2).any(|pair| pair[0].0.overlaps(pair[1].0));
|
||||
if !suggestions.is_empty() && !overlaps {
|
||||
err.multipart_suggestion(
|
||||
format!("specify the associated type{}", pluralize!(types_count)),
|
||||
format!("specify the {descr}{s}", s = pluralize!(items_count)),
|
||||
suggestions,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -627,13 +627,10 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes(
|
|||
position: GenericArgPosition,
|
||||
) -> ExplicitLateBound {
|
||||
let param_counts = def.own_counts();
|
||||
let infer_lifetimes = position != GenericArgPosition::Type && !args.has_lifetime_params();
|
||||
|
||||
if infer_lifetimes {
|
||||
return ExplicitLateBound::No;
|
||||
}
|
||||
|
||||
if let Some(span_late) = def.has_late_bound_regions {
|
||||
if let Some(span_late) = def.has_late_bound_regions
|
||||
&& args.has_lifetime_params()
|
||||
{
|
||||
let msg = "cannot specify lifetime arguments explicitly \
|
||||
if late bound lifetime parameters are present";
|
||||
let note = "the late bound lifetime parameter is introduced here";
|
||||
|
|
|
|||
|
|
@ -1768,7 +1768,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let item = tcx
|
||||
.associated_items(scope)
|
||||
.filter_by_name_unhygienic(ident.name)
|
||||
.find(|i| i.as_tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
|
||||
.find(|i| i.tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
|
||||
|
||||
Some((*item, def_scope))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::{self as hir, ExprKind, HirId, PatKind};
|
||||
use rustc_hir_pretty::ty_to_string;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_trait_selection::traits::{
|
||||
MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
||||
};
|
||||
|
|
@ -291,6 +292,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
error
|
||||
}
|
||||
|
||||
/// Check if the span comes from an assert-like macro expansion.
|
||||
fn is_from_assert_macro(&self, span: Span) -> bool {
|
||||
span.ctxt().outer_expn_data().macro_def_id.is_some_and(|def_id| {
|
||||
matches!(
|
||||
self.tcx.get_diagnostic_name(def_id),
|
||||
Some(
|
||||
sym::assert_macro
|
||||
| sym::debug_assert_macro
|
||||
| sym::assert_eq_macro
|
||||
| sym::assert_ne_macro
|
||||
| sym::debug_assert_eq_macro
|
||||
| sym::debug_assert_ne_macro
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Explain why `if` expressions without `else` evaluate to `()` and detect likely irrefutable
|
||||
/// `if let PAT = EXPR {}` expressions that could be turned into `let PAT = EXPR;`.
|
||||
fn explain_if_expr(
|
||||
|
|
@ -302,6 +320,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
then_expr: &'tcx hir::Expr<'tcx>,
|
||||
error: &mut bool,
|
||||
) {
|
||||
let is_assert_macro = self.is_from_assert_macro(if_span);
|
||||
|
||||
if let Some((if_span, msg)) = ret_reason {
|
||||
err.span_label(if_span, msg);
|
||||
} else if let ExprKind::Block(block, _) = then_expr.kind
|
||||
|
|
@ -309,8 +329,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
err.span_label(expr.span, "found here");
|
||||
}
|
||||
err.note("`if` expressions without `else` evaluate to `()`");
|
||||
err.help("consider adding an `else` block that evaluates to the expected type");
|
||||
|
||||
if is_assert_macro {
|
||||
err.code(E0308);
|
||||
err.primary_message("mismatched types");
|
||||
} else {
|
||||
err.note("`if` expressions without `else` evaluate to `()`");
|
||||
err.help("consider adding an `else` block that evaluates to the expected type");
|
||||
}
|
||||
*error = true;
|
||||
if let ExprKind::Let(hir::LetExpr { span, pat, init, .. }) = cond_expr.kind
|
||||
&& let ExprKind::Block(block, _) = then_expr.kind
|
||||
|
|
|
|||
|
|
@ -3300,8 +3300,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) {
|
||||
let can_derive = match diagnostic_name {
|
||||
sym::Default => !adt.is_enum(),
|
||||
sym::Eq
|
||||
sym::Default
|
||||
| sym::Eq
|
||||
| sym::PartialEq
|
||||
| sym::Ord
|
||||
| sym::PartialOrd
|
||||
|
|
|
|||
|
|
@ -30,9 +30,6 @@ interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag
|
|||
interface_input_file_would_be_overwritten =
|
||||
the input file "{$path}" would be overwritten by the generated executable
|
||||
|
||||
interface_invalid_crate_type_value = invalid `crate_type` value
|
||||
.suggestion = did you mean
|
||||
|
||||
interface_mixed_bin_crate =
|
||||
cannot mix `bin` crate type with others
|
||||
|
||||
|
|
@ -51,3 +48,9 @@ interface_proc_macro_crate_panic_abort =
|
|||
|
||||
interface_temps_dir_error =
|
||||
failed to find or create the directory specified by `--temps-dir`
|
||||
|
||||
interface_unsupported_crate_type_for_codegen_backend =
|
||||
dropping unsupported crate type `{$crate_type}` for codegen backend `{$codegen_backend}`
|
||||
|
||||
interface_unsupported_crate_type_for_target =
|
||||
dropping unsupported crate type `{$crate_type}` for target `{$target_triple}`
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_hir::attrs::CrateType;
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::spec::TargetTuple;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(interface_crate_name_does_not_match)]
|
||||
|
|
@ -109,17 +111,16 @@ pub(crate) struct AbiRequiredTargetFeature<'a> {
|
|||
pub enabled: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(interface_invalid_crate_type_value)]
|
||||
pub(crate) struct UnknownCrateTypes {
|
||||
#[subdiagnostic]
|
||||
pub sugg: Option<UnknownCrateTypesSub>,
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(interface_unsupported_crate_type_for_codegen_backend)]
|
||||
pub(crate) struct UnsupportedCrateTypeForCodegenBackend {
|
||||
pub(crate) crate_type: CrateType,
|
||||
pub(crate) codegen_backend: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(interface_suggestion, code = r#""{snippet}""#, applicability = "maybe-incorrect")]
|
||||
pub(crate) struct UnknownCrateTypesSub {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub snippet: Symbol,
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(interface_unsupported_crate_type_for_target)]
|
||||
pub(crate) struct UnsupportedCrateTypeForTarget<'a> {
|
||||
pub(crate) crate_type: CrateType,
|
||||
pub(crate) target_triple: &'a TargetTuple,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ use std::path::{Path, PathBuf};
|
|||
use std::sync::{Arc, LazyLock, OnceLock};
|
||||
use std::{env, fs, iter};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
|
||||
use rustc_ast::{self as ast, CRATE_NODE_ID};
|
||||
use rustc_attr_parsing::{AttributeParser, Early, ShouldEmit};
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
|
|
@ -17,6 +17,7 @@ use rustc_errors::timings::TimingSection;
|
|||
use rustc_expand::base::{ExtCtxt, LintStoreExpand};
|
||||
use rustc_feature::Features;
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use rustc_hir::Attribute;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
|
||||
use rustc_hir::definitions::Definitions;
|
||||
|
|
@ -35,7 +36,7 @@ use rustc_resolve::{Resolver, ResolverOutputs};
|
|||
use rustc_session::Session;
|
||||
use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
|
||||
use rustc_session::cstore::Untracked;
|
||||
use rustc_session::output::{collect_crate_types, filename_for_input};
|
||||
use rustc_session::output::{filename_for_input, invalid_output_for_target};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::search_paths::PathKind;
|
||||
use rustc_span::{
|
||||
|
|
@ -159,8 +160,6 @@ fn configure_and_expand(
|
|||
)
|
||||
});
|
||||
|
||||
util::check_attr_crate_type(sess, pre_configured_attrs, resolver.lint_buffer());
|
||||
|
||||
// Expand all macros
|
||||
krate = sess.time("macro_expand_crate", || {
|
||||
// Windows dlls do not have rpaths, so they don't know how to find their
|
||||
|
|
@ -929,6 +928,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
|
|||
&compiler.codegen_backend.supported_crate_types(sess),
|
||||
compiler.codegen_backend.name(),
|
||||
&pre_configured_attrs,
|
||||
krate.spans.inner_span,
|
||||
);
|
||||
let stable_crate_id = StableCrateId::new(
|
||||
crate_name,
|
||||
|
|
@ -1347,6 +1347,94 @@ pub(crate) fn parse_crate_name(
|
|||
Some((name, name_span))
|
||||
}
|
||||
|
||||
pub fn collect_crate_types(
|
||||
session: &Session,
|
||||
backend_crate_types: &[CrateType],
|
||||
codegen_backend_name: &'static str,
|
||||
attrs: &[ast::Attribute],
|
||||
crate_span: Span,
|
||||
) -> Vec<CrateType> {
|
||||
// If we're generating a test executable, then ignore all other output
|
||||
// styles at all other locations
|
||||
if session.opts.test {
|
||||
if !session.target.executables {
|
||||
session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget {
|
||||
crate_type: CrateType::Executable,
|
||||
target_triple: &session.opts.target_triple,
|
||||
});
|
||||
return Vec::new();
|
||||
}
|
||||
return vec![CrateType::Executable];
|
||||
}
|
||||
|
||||
// Shadow `sdylib` crate type in interface build.
|
||||
if session.opts.unstable_opts.build_sdylib_interface {
|
||||
return vec![CrateType::Rlib];
|
||||
}
|
||||
|
||||
// Only check command line flags if present. If no types are specified by
|
||||
// command line, then reuse the empty `base` Vec to hold the types that
|
||||
// will be found in crate attributes.
|
||||
// JUSTIFICATION: before wrapper fn is available
|
||||
#[allow(rustc::bad_opt_access)]
|
||||
let mut base = session.opts.crate_types.clone();
|
||||
if base.is_empty() {
|
||||
if let Some(Attribute::Parsed(AttributeKind::CrateType(crate_type))) =
|
||||
AttributeParser::<Early>::parse_limited_should_emit(
|
||||
session,
|
||||
attrs,
|
||||
sym::crate_type,
|
||||
crate_span,
|
||||
CRATE_NODE_ID,
|
||||
None,
|
||||
ShouldEmit::EarlyFatal { also_emit_lints: false },
|
||||
)
|
||||
{
|
||||
base.extend(crate_type);
|
||||
}
|
||||
|
||||
if base.is_empty() {
|
||||
base.push(default_output_for_target(session));
|
||||
} else {
|
||||
base.sort();
|
||||
base.dedup();
|
||||
}
|
||||
}
|
||||
|
||||
base.retain(|crate_type| {
|
||||
if invalid_output_for_target(session, *crate_type) {
|
||||
session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget {
|
||||
crate_type: *crate_type,
|
||||
target_triple: &session.opts.target_triple,
|
||||
});
|
||||
false
|
||||
} else if !backend_crate_types.contains(crate_type) {
|
||||
session.dcx().emit_warn(errors::UnsupportedCrateTypeForCodegenBackend {
|
||||
crate_type: *crate_type,
|
||||
codegen_backend: codegen_backend_name,
|
||||
});
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
base
|
||||
}
|
||||
|
||||
/// Returns default crate type for target
|
||||
///
|
||||
/// Default crate type is used when crate type isn't provided neither
|
||||
/// through cmd line arguments nor through crate attributes
|
||||
///
|
||||
/// It is CrateType::Executable for all platforms but iOS as there is no
|
||||
/// way to run iOS binaries anyway without jailbreaking and
|
||||
/// interaction with Rust code through static library is the only
|
||||
/// option for now
|
||||
fn default_output_for_target(sess: &Session) -> CrateType {
|
||||
if !sess.target.executables { CrateType::StaticLib } else { CrateType::Executable }
|
||||
}
|
||||
|
||||
fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
|
||||
let attr = AttributeParser::parse_limited_should_emit(
|
||||
sess,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::sync::{Arc, OnceLock};
|
|||
use std::{env, thread};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr_parsing::{ShouldEmit, validate_attr};
|
||||
use rustc_attr_parsing::ShouldEmit;
|
||||
use rustc_codegen_ssa::back::archive::{ArArchiveBuilderBuilder, ArchiveBuilderBuilder};
|
||||
use rustc_codegen_ssa::back::link::link_binary;
|
||||
use rustc_codegen_ssa::target_features::cfg_target_feature;
|
||||
|
|
@ -15,16 +15,13 @@ use rustc_codegen_ssa::{CodegenResults, CrateInfo, TargetConfig};
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_errors::LintBuffer;
|
||||
use rustc_metadata::{DylibError, EncodedMetadata, load_symbol_from_dylib};
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::ty::{CurrentGcx, TyCtxt};
|
||||
use rustc_session::config::{
|
||||
Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple,
|
||||
};
|
||||
use rustc_session::output::{CRATE_TYPES, categorize_crate_type};
|
||||
use rustc_session::{EarlyDiagCtxt, Session, filesearch, lint};
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_session::{EarlyDiagCtxt, Session, filesearch};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::SourceMapInputs;
|
||||
use rustc_span::{SessionGlobals, Symbol, sym};
|
||||
|
|
@ -575,54 +572,6 @@ fn get_codegen_sysroot(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_attr_crate_type(
|
||||
sess: &Session,
|
||||
attrs: &[ast::Attribute],
|
||||
lint_buffer: &mut LintBuffer,
|
||||
) {
|
||||
// Unconditionally collect crate types from attributes to make them used
|
||||
for a in attrs.iter() {
|
||||
if a.has_name(sym::crate_type) {
|
||||
if let Some(n) = a.value_str() {
|
||||
if categorize_crate_type(n).is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let ast::MetaItemKind::NameValue(spanned) = a.meta_kind().unwrap() {
|
||||
let span = spanned.span;
|
||||
let candidate = find_best_match_for_name(
|
||||
&CRATE_TYPES.iter().map(|(k, _)| *k).collect::<Vec<_>>(),
|
||||
n,
|
||||
None,
|
||||
);
|
||||
lint_buffer.buffer_lint(
|
||||
lint::builtin::UNKNOWN_CRATE_TYPES,
|
||||
ast::CRATE_NODE_ID,
|
||||
span,
|
||||
errors::UnknownCrateTypes {
|
||||
sugg: candidate
|
||||
.map(|cand| errors::UnknownCrateTypesSub { span, snippet: cand }),
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// This is here mainly to check for using a macro, such as
|
||||
// `#![crate_type = foo!()]`. That is not supported since the
|
||||
// crate type needs to be known very early in compilation long
|
||||
// before expansion. Otherwise, validation would normally be
|
||||
// caught during semantic analysis via `TyCtxt::check_mod_attrs`,
|
||||
// but by the time that runs the macro is expanded, and it doesn't
|
||||
// give an error.
|
||||
validate_attr::emit_fatal_malformed_builtin_attribute(
|
||||
&sess.psess,
|
||||
a,
|
||||
sym::crate_type,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn multiple_output_types_to_stdout(
|
||||
output_types: &OutputTypes,
|
||||
single_output_file_is_stdout: bool,
|
||||
|
|
|
|||
|
|
@ -503,6 +503,9 @@ lint_invalid_asm_label_named = avoid using named labels in inline assembly
|
|||
.note = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
|
||||
lint_invalid_asm_label_no_span = the label may be declared in the expansion of a macro
|
||||
|
||||
lint_invalid_crate_type_value = invalid `crate_type` value
|
||||
.suggestion = did you mean
|
||||
|
||||
# FIXME: we should ordinalize $valid_up_to when we add support for doing so
|
||||
lint_invalid_from_utf8_checked = calls to `{$method}` with an invalid literal always return an error
|
||||
.label = the literal was valid UTF-8 up to the {$valid_up_to} bytes
|
||||
|
|
|
|||
|
|
@ -423,5 +423,10 @@ pub fn decorate_attribute_lint(
|
|||
&AttributeLintKind::DoNotRecommendDoesNotExpectArgs => {
|
||||
lints::DoNotRecommendDoesNotExpectArgs.decorate_lint(diag)
|
||||
}
|
||||
|
||||
&AttributeLintKind::CrateTypeUnknown { span, suggested } => lints::UnknownCrateTypes {
|
||||
sugg: suggested.map(|s| lints::UnknownCrateTypesSuggestion { span, snippet: s }),
|
||||
}
|
||||
.decorate_lint(diag),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
|
|
|
|||
|
|
@ -3310,3 +3310,18 @@ pub(crate) struct AttrCrateLevelOnly;
|
|||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_incorrect_do_not_recommend_args)]
|
||||
pub(crate) struct DoNotRecommendDoesNotExpectArgs;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_invalid_crate_type_value)]
|
||||
pub(crate) struct UnknownCrateTypes {
|
||||
#[subdiagnostic]
|
||||
pub sugg: Option<UnknownCrateTypesSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(lint_suggestion, code = r#""{snippet}""#, applicability = "maybe-incorrect")]
|
||||
pub(crate) struct UnknownCrateTypesSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub snippet: Symbol,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -822,6 +822,10 @@ pub enum AttributeLintKind {
|
|||
DocTestLiteral,
|
||||
AttrCrateLevelOnly,
|
||||
DoNotRecommendDoesNotExpectArgs,
|
||||
CrateTypeUnknown {
|
||||
span: Span,
|
||||
suggested: Option<Symbol>,
|
||||
},
|
||||
}
|
||||
|
||||
pub type RegisteredTools = FxIndexSet<Ident>;
|
||||
|
|
|
|||
|
|
@ -527,6 +527,12 @@ LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
|
|||
*unwrap(C), CaptureInfo(CaptureComponents::Address |
|
||||
CaptureComponents::ReadProvenance)));
|
||||
}
|
||||
#endif
|
||||
#if LLVM_VERSION_GE(23, 0)
|
||||
if (RustAttr == LLVMRustAttributeKind::DeadOnReturn) {
|
||||
return wrap(Attribute::getWithDeadOnReturnInfo(*unwrap(C),
|
||||
llvm::DeadOnReturnInfo()));
|
||||
}
|
||||
#endif
|
||||
return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,7 @@ struct RustcVersion {
|
|||
|
||||
impl RustcVersion {
|
||||
fn parse_cfg_release(env_var: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
#[cfg(not(bootstrap))]
|
||||
let value = proc_macro::tracked::env_var(env_var)?;
|
||||
#[cfg(bootstrap)]
|
||||
let value = proc_macro::tracked_env::var(env_var)?;
|
||||
|
||||
Self::parse_str(&value)
|
||||
.ok_or_else(|| format!("failed to parse rustc version: {:?}", value).into())
|
||||
|
|
|
|||
|
|
@ -259,10 +259,6 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
|
|||
break;
|
||||
}
|
||||
|
||||
#[cfg(bootstrap)]
|
||||
let tracked_env = proc_macro::tracked_env::var(env_var.value());
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
let tracked_env = proc_macro::tracked::env_var(env_var.value());
|
||||
|
||||
let value = match tracked_env {
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
CrateType::Dylib | CrateType::Cdylib | CrateType::Sdylib => {
|
||||
if sess.opts.cg.prefer_dynamic { Linkage::Dynamic } else { Linkage::Static }
|
||||
}
|
||||
CrateType::Staticlib => {
|
||||
CrateType::StaticLib => {
|
||||
if sess.opts.unstable_opts.staticlib_prefer_dynamic {
|
||||
Linkage::Dynamic
|
||||
} else {
|
||||
|
|
@ -141,7 +141,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
|
||||
// Static executables must have all static dependencies.
|
||||
// If any are not found, generate some nice pretty errors.
|
||||
if (ty == CrateType::Staticlib && !sess.opts.unstable_opts.staticlib_allow_rdylib_deps)
|
||||
if (ty == CrateType::StaticLib && !sess.opts.unstable_opts.staticlib_allow_rdylib_deps)
|
||||
|| (ty == CrateType::Executable
|
||||
&& sess.crt_static(Some(ty))
|
||||
&& !sess.target.crt_static_allows_dylibs)
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ fn find_bundled_library(
|
|||
) -> Option<Symbol> {
|
||||
let sess = tcx.sess;
|
||||
if let NativeLibKind::Static { bundle: Some(true) | None, whole_archive } = kind
|
||||
&& tcx.crate_types().iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::Staticlib))
|
||||
&& tcx.crate_types().iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::StaticLib))
|
||||
&& (sess.opts.unstable_opts.packed_bundled_libs || has_cfg || whole_archive == Some(true))
|
||||
{
|
||||
let verbatim = verbatim.unwrap_or(false);
|
||||
|
|
|
|||
|
|
@ -741,12 +741,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
externally_implementable_items,
|
||||
proc_macro_data,
|
||||
debugger_visualizers,
|
||||
compiler_builtins: ast::attr::contains_name(attrs, sym::compiler_builtins),
|
||||
compiler_builtins: find_attr!(attrs, AttributeKind::CompilerBuiltins),
|
||||
needs_allocator: find_attr!(attrs, AttributeKind::NeedsAllocator),
|
||||
needs_panic_runtime: ast::attr::contains_name(attrs, sym::needs_panic_runtime),
|
||||
no_builtins: ast::attr::contains_name(attrs, sym::no_builtins),
|
||||
panic_runtime: ast::attr::contains_name(attrs, sym::panic_runtime),
|
||||
profiler_runtime: ast::attr::contains_name(attrs, sym::profiler_runtime),
|
||||
needs_panic_runtime: find_attr!(attrs, AttributeKind::NeedsPanicRuntime),
|
||||
no_builtins: find_attr!(attrs, AttributeKind::NoBuiltins),
|
||||
panic_runtime: find_attr!(attrs, AttributeKind::PanicRuntime),
|
||||
profiler_runtime: find_attr!(attrs, AttributeKind::ProfilerRuntime),
|
||||
symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(),
|
||||
|
||||
crate_deps,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![allow(rustc::direct_use_of_rustc_type_ir)]
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(associated_type_defaults)]
|
||||
|
|
|
|||
|
|
@ -342,22 +342,18 @@ macro_rules! define_callbacks {
|
|||
})*
|
||||
}
|
||||
|
||||
/// Holds per-query arenas for queries with the `arena_cache` modifier.
|
||||
#[derive(Default)]
|
||||
pub struct QueryArenas<'tcx> {
|
||||
$($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*]
|
||||
(TypedArena<<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated>)
|
||||
()
|
||||
),)*
|
||||
}
|
||||
|
||||
impl Default for QueryArenas<'_> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
$($name: query_if_arena!([$($modifiers)*]
|
||||
(Default::default())
|
||||
()
|
||||
),)*
|
||||
}
|
||||
}
|
||||
$(
|
||||
$(#[$attr])*
|
||||
pub $name: query_if_arena!([$($modifiers)*]
|
||||
// Use the `ArenaCached` helper trait to determine the arena's value type.
|
||||
(TypedArena<<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated>)
|
||||
// No arena for this query, so the field type is `()`.
|
||||
()
|
||||
),
|
||||
)*
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
|
|||
|
|
@ -759,14 +759,14 @@ pub struct ImplSourceUserDefinedData<'tcx, N> {
|
|||
pub nested: ThinVec<N>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)]
|
||||
pub enum DynCompatibilityViolation {
|
||||
/// `Self: Sized` declared on the trait.
|
||||
SizedSelf(SmallVec<[Span; 1]>),
|
||||
|
||||
/// Trait is marked `#[rustc_dyn_incompatible_trait]`.
|
||||
ExplicitlyDynIncompatible(SmallVec<[Span; 1]>),
|
||||
|
||||
/// `Self: Sized` declared on the trait.
|
||||
SizedSelf(SmallVec<[Span; 1]>),
|
||||
|
||||
/// Supertrait reference references `Self` an in illegal location
|
||||
/// (e.g., `trait Foo : Bar<Self>`).
|
||||
SupertraitSelf(SmallVec<[Span; 1]>),
|
||||
|
|
@ -778,23 +778,24 @@ pub enum DynCompatibilityViolation {
|
|||
SupertraitConst(SmallVec<[Span; 1]>),
|
||||
|
||||
/// Method has something illegal.
|
||||
Method(Symbol, MethodViolationCode, Span),
|
||||
Method(Symbol, MethodViolation, Span),
|
||||
|
||||
/// Associated const.
|
||||
AssocConst(Symbol, Span),
|
||||
/// Associated constant is faulty.
|
||||
AssocConst(Symbol, AssocConstViolation, Span),
|
||||
|
||||
/// GAT
|
||||
GAT(Symbol, Span),
|
||||
/// Generic associated type (GAT).
|
||||
GenericAssocTy(Symbol, Span),
|
||||
}
|
||||
|
||||
impl DynCompatibilityViolation {
|
||||
pub fn error_msg(&self) -> Cow<'static, str> {
|
||||
// FIXME(mgca): For method violations we just say "method ..." but for assoc const ones we
|
||||
// say "it contains ... associated constant ...". Make it consistent.
|
||||
|
||||
match self {
|
||||
DynCompatibilityViolation::SizedSelf(_) => "it requires `Self: Sized`".into(),
|
||||
DynCompatibilityViolation::ExplicitlyDynIncompatible(_) => {
|
||||
"it opted out of dyn-compatibility".into()
|
||||
}
|
||||
DynCompatibilityViolation::SupertraitSelf(spans) => {
|
||||
Self::ExplicitlyDynIncompatible(_) => "it opted out of dyn-compatibility".into(),
|
||||
Self::SizedSelf(_) => "it requires `Self: Sized`".into(),
|
||||
Self::SupertraitSelf(spans) => {
|
||||
if spans.iter().any(|sp| *sp != DUMMY_SP) {
|
||||
"it uses `Self` as a type parameter".into()
|
||||
} else {
|
||||
|
|
@ -802,94 +803,80 @@ impl DynCompatibilityViolation {
|
|||
.into()
|
||||
}
|
||||
}
|
||||
DynCompatibilityViolation::SupertraitNonLifetimeBinder(_) => {
|
||||
Self::SupertraitNonLifetimeBinder(_) => {
|
||||
"where clause cannot reference non-lifetime `for<...>` variables".into()
|
||||
}
|
||||
DynCompatibilityViolation::SupertraitConst(_) => {
|
||||
"it cannot have a `const` supertrait".into()
|
||||
}
|
||||
DynCompatibilityViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
|
||||
Self::SupertraitConst(_) => "it cannot have a `const` supertrait".into(),
|
||||
Self::Method(name, MethodViolation::StaticMethod(_), _) => {
|
||||
format!("associated function `{name}` has no `self` parameter").into()
|
||||
}
|
||||
DynCompatibilityViolation::Method(
|
||||
name,
|
||||
MethodViolationCode::ReferencesSelfInput(_),
|
||||
DUMMY_SP,
|
||||
) => format!("method `{name}` references the `Self` type in its parameters").into(),
|
||||
DynCompatibilityViolation::Method(
|
||||
name,
|
||||
MethodViolationCode::ReferencesSelfInput(_),
|
||||
_,
|
||||
) => format!("method `{name}` references the `Self` type in this parameter").into(),
|
||||
DynCompatibilityViolation::Method(
|
||||
name,
|
||||
MethodViolationCode::ReferencesSelfOutput,
|
||||
_,
|
||||
) => format!("method `{name}` references the `Self` type in its return type").into(),
|
||||
DynCompatibilityViolation::Method(
|
||||
name,
|
||||
MethodViolationCode::ReferencesImplTraitInTrait(_),
|
||||
_,
|
||||
) => {
|
||||
Self::Method(name, MethodViolation::ReferencesSelfInput(_), DUMMY_SP) => {
|
||||
format!("method `{name}` references the `Self` type in its parameters").into()
|
||||
}
|
||||
Self::Method(name, MethodViolation::ReferencesSelfInput(_), _) => {
|
||||
format!("method `{name}` references the `Self` type in this parameter").into()
|
||||
}
|
||||
Self::Method(name, MethodViolation::ReferencesSelfOutput, _) => {
|
||||
format!("method `{name}` references the `Self` type in its return type").into()
|
||||
}
|
||||
Self::Method(name, MethodViolation::ReferencesImplTraitInTrait(_), _) => {
|
||||
format!("method `{name}` references an `impl Trait` type in its return type").into()
|
||||
}
|
||||
DynCompatibilityViolation::Method(name, MethodViolationCode::AsyncFn, _) => {
|
||||
Self::Method(name, MethodViolation::AsyncFn, _) => {
|
||||
format!("method `{name}` is `async`").into()
|
||||
}
|
||||
DynCompatibilityViolation::Method(name, MethodViolationCode::CVariadic, _) => {
|
||||
Self::Method(name, MethodViolation::CVariadic, _) => {
|
||||
format!("method `{name}` is C-variadic").into()
|
||||
}
|
||||
DynCompatibilityViolation::Method(
|
||||
name,
|
||||
MethodViolationCode::WhereClauseReferencesSelf,
|
||||
_,
|
||||
) => format!("method `{name}` references the `Self` type in its `where` clause").into(),
|
||||
DynCompatibilityViolation::Method(name, MethodViolationCode::Generic, _) => {
|
||||
Self::Method(name, MethodViolation::WhereClauseReferencesSelf, _) => {
|
||||
format!("method `{name}` references the `Self` type in its `where` clause").into()
|
||||
}
|
||||
Self::Method(name, MethodViolation::Generic, _) => {
|
||||
format!("method `{name}` has generic type parameters").into()
|
||||
}
|
||||
DynCompatibilityViolation::Method(
|
||||
name,
|
||||
MethodViolationCode::UndispatchableReceiver(_),
|
||||
_,
|
||||
) => format!("method `{name}`'s `self` parameter cannot be dispatched on").into(),
|
||||
DynCompatibilityViolation::AssocConst(name, DUMMY_SP) => {
|
||||
format!("it contains associated `const` `{name}`").into()
|
||||
Self::Method(name, MethodViolation::UndispatchableReceiver(_), _) => {
|
||||
format!("method `{name}`'s `self` parameter cannot be dispatched on").into()
|
||||
}
|
||||
DynCompatibilityViolation::AssocConst(..) => {
|
||||
"it contains this associated `const`".into()
|
||||
Self::AssocConst(name, AssocConstViolation::FeatureNotEnabled, _) => {
|
||||
format!("it contains associated const `{name}`").into()
|
||||
}
|
||||
DynCompatibilityViolation::GAT(name, _) => {
|
||||
format!("it contains the generic associated type `{name}`").into()
|
||||
Self::AssocConst(name, AssocConstViolation::Generic, _) => {
|
||||
format!("it contains generic associated const `{name}`").into()
|
||||
}
|
||||
Self::AssocConst(name, AssocConstViolation::NonType, _) => {
|
||||
format!("it contains associated const `{name}` that's not marked `#[type_const]`")
|
||||
.into()
|
||||
}
|
||||
Self::AssocConst(name, AssocConstViolation::TypeReferencesSelf, _) => format!(
|
||||
"it contains associated const `{name}` whose type references the `Self` type"
|
||||
)
|
||||
.into(),
|
||||
Self::GenericAssocTy(name, _) => {
|
||||
format!("it contains generic associated type `{name}`").into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn solution(&self) -> DynCompatibilityViolationSolution {
|
||||
match self {
|
||||
DynCompatibilityViolation::SizedSelf(_)
|
||||
| DynCompatibilityViolation::ExplicitlyDynIncompatible(_)
|
||||
| DynCompatibilityViolation::SupertraitSelf(_)
|
||||
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(..)
|
||||
| DynCompatibilityViolation::SupertraitConst(_) => {
|
||||
DynCompatibilityViolationSolution::None
|
||||
}
|
||||
DynCompatibilityViolation::Method(
|
||||
Self::ExplicitlyDynIncompatible(_)
|
||||
| Self::SizedSelf(_)
|
||||
| Self::SupertraitSelf(_)
|
||||
| Self::SupertraitNonLifetimeBinder(..)
|
||||
| Self::SupertraitConst(_) => DynCompatibilityViolationSolution::None,
|
||||
Self::Method(
|
||||
name,
|
||||
MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))),
|
||||
MethodViolation::StaticMethod(Some((add_self_sugg, make_sized_sugg))),
|
||||
_,
|
||||
) => DynCompatibilityViolationSolution::AddSelfOrMakeSized {
|
||||
name: *name,
|
||||
add_self_sugg: add_self_sugg.clone(),
|
||||
make_sized_sugg: make_sized_sugg.clone(),
|
||||
},
|
||||
DynCompatibilityViolation::Method(
|
||||
name,
|
||||
MethodViolationCode::UndispatchableReceiver(Some(span)),
|
||||
_,
|
||||
) => DynCompatibilityViolationSolution::ChangeToRefSelf(*name, *span),
|
||||
DynCompatibilityViolation::AssocConst(name, _)
|
||||
| DynCompatibilityViolation::GAT(name, _)
|
||||
| DynCompatibilityViolation::Method(name, ..) => {
|
||||
Self::Method(name, MethodViolation::UndispatchableReceiver(Some(span)), _) => {
|
||||
DynCompatibilityViolationSolution::ChangeToRefSelf(*name, *span)
|
||||
}
|
||||
Self::Method(name, ..) | Self::AssocConst(name, ..) | Self::GenericAssocTy(name, _) => {
|
||||
DynCompatibilityViolationSolution::MoveToAnotherTrait(*name)
|
||||
}
|
||||
}
|
||||
|
|
@ -899,14 +886,14 @@ impl DynCompatibilityViolation {
|
|||
// When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so
|
||||
// diagnostics use a `note` instead of a `span_label`.
|
||||
match self {
|
||||
DynCompatibilityViolation::SupertraitSelf(spans)
|
||||
| DynCompatibilityViolation::SizedSelf(spans)
|
||||
| DynCompatibilityViolation::ExplicitlyDynIncompatible(spans)
|
||||
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans)
|
||||
| DynCompatibilityViolation::SupertraitConst(spans) => spans.clone(),
|
||||
DynCompatibilityViolation::AssocConst(_, span)
|
||||
| DynCompatibilityViolation::GAT(_, span)
|
||||
| DynCompatibilityViolation::Method(_, _, span) => {
|
||||
Self::ExplicitlyDynIncompatible(spans)
|
||||
| Self::SizedSelf(spans)
|
||||
| Self::SupertraitSelf(spans)
|
||||
| Self::SupertraitNonLifetimeBinder(spans)
|
||||
| Self::SupertraitConst(spans) => spans.clone(),
|
||||
Self::Method(_, _, span)
|
||||
| Self::AssocConst(_, _, span)
|
||||
| Self::GenericAssocTy(_, span) => {
|
||||
if *span != DUMMY_SP {
|
||||
smallvec![*span]
|
||||
} else {
|
||||
|
|
@ -972,8 +959,8 @@ impl DynCompatibilityViolationSolution {
|
|||
}
|
||||
|
||||
/// Reasons a method might not be dyn-compatible.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
|
||||
pub enum MethodViolationCode {
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)]
|
||||
pub enum MethodViolation {
|
||||
/// e.g., `fn foo()`
|
||||
StaticMethod(Option<(/* add &self */ (String, Span), /* add Self: Sized */ (String, Span))>),
|
||||
|
||||
|
|
@ -1002,6 +989,22 @@ pub enum MethodViolationCode {
|
|||
UndispatchableReceiver(Option<Span>),
|
||||
}
|
||||
|
||||
/// Reasons an associated const might not be dyn compatible.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)]
|
||||
pub enum AssocConstViolation {
|
||||
/// Unstable feature `min_generic_const_args` wasn't enabled.
|
||||
FeatureNotEnabled,
|
||||
|
||||
/// Has own generic parameters (GAC).
|
||||
Generic,
|
||||
|
||||
/// Isn't marked `#[type_const]`.
|
||||
NonType,
|
||||
|
||||
/// Its type mentions the `Self` type parameter.
|
||||
TypeReferencesSelf,
|
||||
}
|
||||
|
||||
/// These are the error cases for `codegen_select_candidate`.
|
||||
#[derive(Copy, Clone, Debug, Hash, HashStable, Encodable, Decodable)]
|
||||
pub enum CodegenObligationError {
|
||||
|
|
|
|||
|
|
@ -126,30 +126,19 @@ impl AssocItem {
|
|||
}
|
||||
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match self.kind {
|
||||
ty::AssocKind::Const { .. } => "associated const",
|
||||
ty::AssocKind::Fn { has_self: true, .. } => "method",
|
||||
ty::AssocKind::Fn { has_self: false, .. } => "associated function",
|
||||
ty::AssocKind::Type { .. } => "associated type",
|
||||
}
|
||||
self.kind.descr()
|
||||
}
|
||||
|
||||
pub fn namespace(&self) -> Namespace {
|
||||
match self.kind {
|
||||
ty::AssocKind::Type { .. } => Namespace::TypeNS,
|
||||
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
|
||||
}
|
||||
self.kind.namespace()
|
||||
}
|
||||
|
||||
pub fn as_def_kind(&self) -> DefKind {
|
||||
match self.kind {
|
||||
AssocKind::Const { .. } => DefKind::AssocConst,
|
||||
AssocKind::Fn { .. } => DefKind::AssocFn,
|
||||
AssocKind::Type { .. } => DefKind::AssocTy,
|
||||
}
|
||||
self.kind.as_def_kind()
|
||||
}
|
||||
pub fn is_type(&self) -> bool {
|
||||
matches!(self.kind, ty::AssocKind::Type { .. })
|
||||
|
||||
pub fn is_const(&self) -> bool {
|
||||
matches!(self.kind, ty::AssocKind::Const { .. })
|
||||
}
|
||||
|
||||
pub fn is_fn(&self) -> bool {
|
||||
|
|
@ -160,12 +149,12 @@ impl AssocItem {
|
|||
matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. })
|
||||
}
|
||||
|
||||
pub fn as_tag(&self) -> AssocTag {
|
||||
match self.kind {
|
||||
AssocKind::Const { .. } => AssocTag::Const,
|
||||
AssocKind::Fn { .. } => AssocTag::Fn,
|
||||
AssocKind::Type { .. } => AssocTag::Type,
|
||||
}
|
||||
pub fn is_type(&self) -> bool {
|
||||
matches!(self.kind, ty::AssocKind::Type { .. })
|
||||
}
|
||||
|
||||
pub fn tag(&self) -> AssocTag {
|
||||
self.kind.tag()
|
||||
}
|
||||
|
||||
pub fn is_impl_trait_in_trait(&self) -> bool {
|
||||
|
|
@ -191,40 +180,61 @@ pub enum AssocKind {
|
|||
|
||||
impl AssocKind {
|
||||
pub fn namespace(&self) -> Namespace {
|
||||
match *self {
|
||||
ty::AssocKind::Type { .. } => Namespace::TypeNS,
|
||||
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
|
||||
match self {
|
||||
Self::Type { .. } => Namespace::TypeNS,
|
||||
Self::Const { .. } | Self::Fn { .. } => Namespace::ValueNS,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tag(&self) -> AssocTag {
|
||||
match self {
|
||||
Self::Const { .. } => AssocTag::Const,
|
||||
Self::Fn { .. } => AssocTag::Fn,
|
||||
Self::Type { .. } => AssocTag::Type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_def_kind(&self) -> DefKind {
|
||||
match self {
|
||||
AssocKind::Const { .. } => DefKind::AssocConst,
|
||||
AssocKind::Fn { .. } => DefKind::AssocFn,
|
||||
AssocKind::Type { .. } => DefKind::AssocTy,
|
||||
Self::Const { .. } => DefKind::AssocConst,
|
||||
Self::Fn { .. } => DefKind::AssocFn,
|
||||
Self::Type { .. } => DefKind::AssocTy,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Fn { has_self: true, .. } => "method",
|
||||
_ => self.tag().descr(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AssocKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
|
||||
AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
|
||||
AssocKind::Const { .. } => write!(f, "associated const"),
|
||||
AssocKind::Type { .. } => write!(f, "associated type"),
|
||||
}
|
||||
f.write_str(self.descr())
|
||||
}
|
||||
}
|
||||
|
||||
// Like `AssocKind`, but just the tag, no fields. Used in various kinds of matching.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
/// Like [`AssocKind`], but just the tag, no fields. Used in various kinds of matching.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum AssocTag {
|
||||
Const,
|
||||
Fn,
|
||||
Type,
|
||||
}
|
||||
|
||||
impl AssocTag {
|
||||
pub fn descr(self) -> &'static str {
|
||||
// This should match `DefKind::descr`.
|
||||
match self {
|
||||
Self::Const => "associated constant",
|
||||
Self::Fn => "associated function",
|
||||
Self::Type => "associated type",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
|
||||
///
|
||||
/// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
|
||||
|
|
@ -272,7 +282,7 @@ impl AssocItems {
|
|||
name: Symbol,
|
||||
assoc_tag: AssocTag,
|
||||
) -> impl '_ + Iterator<Item = &ty::AssocItem> {
|
||||
self.filter_by_name_unhygienic(name).filter(move |item| item.as_tag() == assoc_tag)
|
||||
self.filter_by_name_unhygienic(name).filter(move |item| item.tag() == assoc_tag)
|
||||
}
|
||||
|
||||
/// Returns the associated item with the given identifier and `AssocKind`, if one exists.
|
||||
|
|
@ -285,7 +295,7 @@ impl AssocItems {
|
|||
parent_def_id: DefId,
|
||||
) -> Option<&ty::AssocItem> {
|
||||
self.filter_by_name_unhygienic(ident.name)
|
||||
.filter(|item| item.as_tag() == assoc_tag)
|
||||
.filter(|item| item.tag() == assoc_tag)
|
||||
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -147,7 +147,12 @@ impl<'tcx> Value<'tcx> {
|
|||
_ => return None,
|
||||
}
|
||||
|
||||
Some(tcx.arena.alloc_from_iter(self.to_branch().into_iter().map(|ct| ct.to_leaf().to_u8())))
|
||||
// We create an iterator that yields `Option<u8>`
|
||||
let iterator = self.to_branch().into_iter().map(|ct| Some(ct.try_to_leaf()?.to_u8()));
|
||||
// If there is `None` in the iterator, then the array is not a valid array of u8s and we return `None`
|
||||
let bytes: Vec<u8> = iterator.collect::<Option<Vec<u8>>>()?;
|
||||
|
||||
Some(tcx.arena.alloc_from_iter(bytes))
|
||||
}
|
||||
|
||||
/// Converts to a `ValTreeKind::Leaf` value, `panic`'ing
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState};
|
|||
use rustc_hir::intravisit::VisitorExt;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate, find_attr};
|
||||
use rustc_hir::{self as hir, HirId, Node, TraitCandidate, find_attr};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_query_system::cache::WithDepNode;
|
||||
use rustc_query_system::dep_graph::DepNodeIndex;
|
||||
|
|
@ -49,7 +49,7 @@ use rustc_session::config::CrateType;
|
|||
use rustc_session::cstore::{CrateStoreDyn, Untracked};
|
||||
use rustc_session::lint::Lint;
|
||||
use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
|
||||
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;
|
||||
|
|
@ -1980,7 +1980,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn needs_metadata(self) -> bool {
|
||||
self.crate_types().iter().any(|ty| match *ty {
|
||||
CrateType::Executable
|
||||
| CrateType::Staticlib
|
||||
| CrateType::StaticLib
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Sdylib => false,
|
||||
CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
|
||||
|
|
@ -2279,7 +2279,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.crate_types().iter().any(|crate_type| {
|
||||
match crate_type {
|
||||
CrateType::Executable
|
||||
| CrateType::Staticlib
|
||||
| CrateType::StaticLib
|
||||
| CrateType::ProcMacro
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Sdylib => false,
|
||||
|
|
@ -3560,16 +3560,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
providers.is_panic_runtime =
|
||||
|tcx, LocalCrate| contains_name(tcx.hir_krate_attrs(), sym::panic_runtime);
|
||||
|tcx, LocalCrate| find_attr!(tcx.hir_krate_attrs(), AttributeKind::PanicRuntime);
|
||||
providers.is_compiler_builtins =
|
||||
|tcx, LocalCrate| contains_name(tcx.hir_krate_attrs(), sym::compiler_builtins);
|
||||
|tcx, LocalCrate| find_attr!(tcx.hir_krate_attrs(), AttributeKind::CompilerBuiltins);
|
||||
providers.has_panic_handler = |tcx, LocalCrate| {
|
||||
// We want to check if the panic handler was defined in this crate
|
||||
tcx.lang_items().panic_impl().is_some_and(|did| did.is_local())
|
||||
};
|
||||
providers.source_span = |tcx, def_id| tcx.untracked.source_span.get(def_id).unwrap_or(DUMMY_SP);
|
||||
}
|
||||
|
||||
pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
|
||||
attrs.iter().any(|x| x.has_name(name))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1911,14 +1911,16 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
return Ok(());
|
||||
}
|
||||
},
|
||||
(ty::ValTreeKind::Branch(_), ty::Array(t, _)) if t == u8_type => {
|
||||
let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| {
|
||||
bug!("expected to convert valtree to raw bytes for type {:?}", t)
|
||||
});
|
||||
// If it is a branch with an array, and this array can be printed as raw bytes, then dump its bytes
|
||||
(ty::ValTreeKind::Branch(_), ty::Array(t, _))
|
||||
if t == u8_type
|
||||
&& let Some(bytes) = cv.try_to_raw_bytes(self.tcx()) =>
|
||||
{
|
||||
write!(self, "*")?;
|
||||
self.pretty_print_byte_str(bytes)?;
|
||||
return Ok(());
|
||||
}
|
||||
// Otherwise, print the array separated by commas (or if it's a tuple)
|
||||
(ty::ValTreeKind::Branch(fields), ty::Array(..) | ty::Tuple(..)) => {
|
||||
let fields_iter = fields.iter().copied();
|
||||
|
||||
|
|
|
|||
|
|
@ -762,8 +762,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
.principal_def_id()
|
||||
.into_iter()
|
||||
.flat_map(|principal_def_id| {
|
||||
// NOTE: This should agree with `needed_associated_types` in
|
||||
// dyn trait lowering, or else we'll have ICEs.
|
||||
// IMPORTANT: This has to agree with HIR ty lowering of dyn trait!
|
||||
elaborate::supertraits(
|
||||
tcx,
|
||||
ty::Binder::dummy(ty::TraitRef::identity(tcx, principal_def_id)),
|
||||
|
|
@ -771,7 +770,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
.map(|principal| {
|
||||
tcx.associated_items(principal.def_id())
|
||||
.in_definition_order()
|
||||
.filter(|item| item.is_type())
|
||||
.filter(|item| item.is_type() || item.is_const())
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
||||
.count()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(const_type_name)]
|
||||
|
|
|
|||
|
|
@ -1563,11 +1563,22 @@ impl<'v> RootCollector<'_, 'v> {
|
|||
// If we're collecting items eagerly, then recurse into all constants.
|
||||
// Otherwise the value is only collected when explicitly mentioned in other items.
|
||||
if self.strategy == MonoItemCollectionStrategy::Eager {
|
||||
if !self.tcx.generics_of(id.owner_id).own_requires_monomorphization()
|
||||
&& let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id())
|
||||
{
|
||||
collect_const_value(self.tcx, val, self.output);
|
||||
let def_id = id.owner_id.to_def_id();
|
||||
// Type Consts don't have bodies to evaluate
|
||||
// nor do they make sense as a static.
|
||||
if self.tcx.is_type_const(def_id) {
|
||||
// FIXME(mgca): Is this actually what we want? We may want to
|
||||
// normalize to a ValTree then convert to a const allocation and
|
||||
// collect that?
|
||||
return;
|
||||
}
|
||||
if self.tcx.generics_of(id.owner_id).own_requires_monomorphization() {
|
||||
return;
|
||||
}
|
||||
let Ok(val) = self.tcx.const_eval_poly(def_id) else {
|
||||
return;
|
||||
};
|
||||
collect_const_value(self.tcx, val, self.output);
|
||||
}
|
||||
}
|
||||
DefKind::Impl { of_trait: true } => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_ast::{self as ast, PatKind, visit};
|
|||
use rustc_ast_pretty::pprust::item_to_string;
|
||||
use rustc_data_structures::assert_matches;
|
||||
use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
|
||||
use rustc_errors::emitter::{HumanEmitter, OutputTheme};
|
||||
use rustc_errors::emitter::OutputTheme;
|
||||
use rustc_errors::translation::Translator;
|
||||
use rustc_errors::{AutoStream, DiagCtxt, MultiSpan, PResult};
|
||||
use rustc_session::parse::ParseSess;
|
||||
|
|
@ -49,20 +49,12 @@ fn create_test_handler(theme: OutputTheme) -> (DiagCtxt, Arc<SourceMap>, Arc<Mut
|
|||
let translator = Translator::with_fallback_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false);
|
||||
let shared: Box<dyn Write + Send> = Box::new(Shared { data: output.clone() });
|
||||
let auto_stream = AutoStream::never(shared);
|
||||
let dcx = DiagCtxt::new(match theme {
|
||||
OutputTheme::Ascii => Box::new(
|
||||
HumanEmitter::new(auto_stream, translator)
|
||||
.sm(Some(source_map.clone()))
|
||||
.diagnostic_width(Some(140))
|
||||
.theme(theme),
|
||||
),
|
||||
OutputTheme::Unicode => Box::new(
|
||||
AnnotateSnippetEmitter::new(auto_stream, translator)
|
||||
.sm(Some(source_map.clone()))
|
||||
.diagnostic_width(Some(140))
|
||||
.theme(theme),
|
||||
),
|
||||
});
|
||||
let dcx = DiagCtxt::new(Box::new(
|
||||
AnnotateSnippetEmitter::new(auto_stream, translator)
|
||||
.sm(Some(source_map.clone()))
|
||||
.diagnostic_width(Some(140))
|
||||
.theme(theme),
|
||||
));
|
||||
(dcx, source_map, output)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -225,107 +225,116 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
},
|
||||
Attribute::Parsed(AttributeKind::DoNotRecommend{attr_span}) => {self.check_do_not_recommend(*attr_span, hir_id, target, item)},
|
||||
Attribute::Parsed(
|
||||
AttributeKind::EiiDeclaration { .. }
|
||||
| AttributeKind::EiiForeignItem
|
||||
| AttributeKind::BodyStability { .. }
|
||||
| AttributeKind::ConstStabilityIndirect
|
||||
| AttributeKind::MacroTransparency(_)
|
||||
| AttributeKind::CollapseDebugInfo(..)
|
||||
| AttributeKind::CfgTrace(..)
|
||||
| AttributeKind::Pointee(..)
|
||||
| AttributeKind::Dummy
|
||||
| AttributeKind::RustcBuiltinMacro { .. }
|
||||
| AttributeKind::Ignore { .. }
|
||||
| AttributeKind::InstructionSet(..)
|
||||
| AttributeKind::Path(..)
|
||||
| AttributeKind::NoImplicitPrelude(..)
|
||||
// tidy-alphabetical-start
|
||||
AttributeKind::AllowIncoherentImpl(..)
|
||||
| AttributeKind::AsPtr(..)
|
||||
| AttributeKind::AutomaticallyDerived(..)
|
||||
| AttributeKind::Marker(..)
|
||||
| AttributeKind::SkipDuringMethodDispatch { .. }
|
||||
| AttributeKind::BodyStability { .. }
|
||||
| AttributeKind::CfgAttrTrace
|
||||
| AttributeKind::CfgTrace(..)
|
||||
| AttributeKind::CfiEncoding { .. }
|
||||
| AttributeKind::Coinductive(..)
|
||||
| AttributeKind::DenyExplicitImpl(..)
|
||||
| AttributeKind::DynIncompatibleTrait(..)
|
||||
| AttributeKind::SpecializationTrait(..)
|
||||
| AttributeKind::UnsafeSpecializationMarker(..)
|
||||
| AttributeKind::ParenSugar(..)
|
||||
| AttributeKind::AllowIncoherentImpl(..)
|
||||
| AttributeKind::Cold(..)
|
||||
| AttributeKind::CollapseDebugInfo(..)
|
||||
| AttributeKind::CompilerBuiltins
|
||||
| AttributeKind::Confusables { .. }
|
||||
| AttributeKind::TypeConst{..}
|
||||
| AttributeKind::ConstStabilityIndirect
|
||||
| AttributeKind::Coroutine(..)
|
||||
| AttributeKind::Coverage (..)
|
||||
| AttributeKind::CrateName { .. }
|
||||
| AttributeKind::CrateType(..)
|
||||
| AttributeKind::DebuggerVisualizer(..)
|
||||
| AttributeKind::DenyExplicitImpl(..)
|
||||
// `#[doc]` is actually a lot more than just doc comments, so is checked below
|
||||
| AttributeKind::DocComment {..}
|
||||
| AttributeKind::Dummy
|
||||
| AttributeKind::DynIncompatibleTrait(..)
|
||||
| AttributeKind::EiiDeclaration { .. }
|
||||
| AttributeKind::EiiForeignItem
|
||||
| AttributeKind::ExportName { .. }
|
||||
| AttributeKind::ExportStable
|
||||
| AttributeKind::FfiConst(..)
|
||||
| AttributeKind::Fundamental
|
||||
| AttributeKind::Ignore { .. }
|
||||
| AttributeKind::InstructionSet(..)
|
||||
| AttributeKind::LinkName { .. }
|
||||
| AttributeKind::LinkOrdinal { .. }
|
||||
| AttributeKind::LinkSection { .. }
|
||||
| AttributeKind::Linkage(..)
|
||||
| AttributeKind::MacroEscape( .. )
|
||||
| AttributeKind::MacroTransparency(_)
|
||||
| AttributeKind::MacroUse { .. }
|
||||
| AttributeKind::Marker(..)
|
||||
| AttributeKind::MoveSizeLimit { .. }
|
||||
| AttributeKind::MustNotSupend { .. }
|
||||
| AttributeKind::MustUse { .. }
|
||||
| AttributeKind::NeedsAllocator
|
||||
| AttributeKind::NeedsPanicRuntime
|
||||
| AttributeKind::NoBuiltins
|
||||
| AttributeKind::NoCore { .. }
|
||||
| AttributeKind::NoImplicitPrelude(..)
|
||||
| AttributeKind::NoLink
|
||||
| AttributeKind::NoMain
|
||||
| AttributeKind::NoMangle(..)
|
||||
| AttributeKind::NoStd { .. }
|
||||
| AttributeKind::ObjcClass { .. }
|
||||
| AttributeKind::ObjcSelector { .. }
|
||||
| AttributeKind::Optimize(..)
|
||||
| AttributeKind::PanicRuntime
|
||||
| AttributeKind::ParenSugar(..)
|
||||
| AttributeKind::PassByValue (..)
|
||||
| AttributeKind::PatchableFunctionEntry { .. }
|
||||
| AttributeKind::Path(..)
|
||||
| AttributeKind::PatternComplexityLimit { .. }
|
||||
| AttributeKind::PinV2(..)
|
||||
| AttributeKind::Pointee(..)
|
||||
| AttributeKind::ProfilerRuntime
|
||||
| AttributeKind::RecursionLimit { .. }
|
||||
// handled below this loop and elsewhere
|
||||
| AttributeKind::Repr { .. }
|
||||
| AttributeKind::Cold(..)
|
||||
| AttributeKind::ExportName { .. }
|
||||
| AttributeKind::Fundamental
|
||||
| AttributeKind::Optimize(..)
|
||||
| AttributeKind::LinkSection { .. }
|
||||
| AttributeKind::MacroUse { .. }
|
||||
| AttributeKind::MacroEscape( .. )
|
||||
| AttributeKind::NoLink
|
||||
| AttributeKind::RustcNoImplicitAutorefs
|
||||
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
|
||||
| AttributeKind::RustcAllocator
|
||||
| AttributeKind::RustcAllocatorZeroed
|
||||
| AttributeKind::RustcAllocatorZeroedVariant { .. }
|
||||
| AttributeKind::RustcBuiltinMacro { .. }
|
||||
| AttributeKind::RustcCoherenceIsCore(..)
|
||||
| AttributeKind::RustcDeallocator
|
||||
| AttributeKind::RustcDumpDefParents
|
||||
| AttributeKind::RustcDumpItemBounds
|
||||
| AttributeKind::RustcDumpPredicates
|
||||
| AttributeKind::RustcDumpUserArgs
|
||||
| AttributeKind::RustcDumpVtable(..)
|
||||
| AttributeKind::RustcHasIncoherentInherentImpls
|
||||
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
|
||||
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
|
||||
| AttributeKind::RustcLintOptDenyFieldAccess { .. }
|
||||
| AttributeKind::RustcLintOptTy
|
||||
| AttributeKind::RustcLintQueryInstability
|
||||
| AttributeKind::RustcLintUntrackedQueryInformation
|
||||
| AttributeKind::RustcNeverReturnsNullPointer
|
||||
| AttributeKind::RustcScalableVector { .. }
|
||||
| AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
|
||||
| AttributeKind::RustcShouldNotBeCalledOnConstItems(..)
|
||||
| AttributeKind::RustcVariance
|
||||
| AttributeKind::RustcVarianceOfOpaques
|
||||
| AttributeKind::ExportStable
|
||||
| AttributeKind::FfiConst(..)
|
||||
| AttributeKind::UnstableFeatureBound(..)
|
||||
| AttributeKind::AsPtr(..)
|
||||
| AttributeKind::LinkName { .. }
|
||||
| AttributeKind::LinkOrdinal { .. }
|
||||
| AttributeKind::NoMangle(..)
|
||||
| AttributeKind::Used { .. }
|
||||
| AttributeKind::PassByValue (..)
|
||||
| AttributeKind::StdInternalSymbol (..)
|
||||
| AttributeKind::Coverage (..)
|
||||
| AttributeKind::ShouldPanic { .. }
|
||||
| AttributeKind::Coroutine(..)
|
||||
| AttributeKind::Linkage(..)
|
||||
| AttributeKind::MustUse { .. }
|
||||
| AttributeKind::CrateName { .. }
|
||||
| AttributeKind::RecursionLimit { .. }
|
||||
| AttributeKind::MoveSizeLimit { .. }
|
||||
| AttributeKind::TypeLengthLimit { .. }
|
||||
| AttributeKind::PatternComplexityLimit { .. }
|
||||
| AttributeKind::NoCore { .. }
|
||||
| AttributeKind::NoStd { .. }
|
||||
| AttributeKind::NoMain
|
||||
| AttributeKind::ObjcClass { .. }
|
||||
| AttributeKind::ObjcSelector { .. }
|
||||
| AttributeKind::RustcCoherenceIsCore(..)
|
||||
| AttributeKind::DebuggerVisualizer(..)
|
||||
| AttributeKind::RustcMain
|
||||
| AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
|
||||
| AttributeKind::PinV2(..)
|
||||
| AttributeKind::WindowsSubsystem(..)
|
||||
| AttributeKind::CfgAttrTrace
|
||||
| AttributeKind::ThreadLocal
|
||||
| AttributeKind::CfiEncoding { .. }
|
||||
| AttributeKind::RustcHasIncoherentInherentImpls
|
||||
| AttributeKind::MustNotSupend { .. }
|
||||
| AttributeKind::RustcDumpUserArgs
|
||||
| AttributeKind::RustcDumpItemBounds
|
||||
| AttributeKind::RustcDumpPredicates
|
||||
| AttributeKind::RustcDumpDefParents
|
||||
| AttributeKind::RustcDumpVtable(..)
|
||||
| AttributeKind::NeedsAllocator
|
||||
| AttributeKind::RustcAllocator
|
||||
| AttributeKind::RustcAllocatorZeroed
|
||||
| AttributeKind::RustcAllocatorZeroedVariant { .. }
|
||||
| AttributeKind::RustcDeallocator
|
||||
| AttributeKind::RustcReallocator
|
||||
| AttributeKind::RustcNeverReturnsNullPointer
|
||||
| AttributeKind::RustcNoImplicitAutorefs
|
||||
| AttributeKind::RustcNounwind
|
||||
| AttributeKind::RustcOffloadKernel
|
||||
| AttributeKind::PatchableFunctionEntry { .. }
|
||||
| AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
|
||||
| AttributeKind::RustcReallocator
|
||||
| AttributeKind::RustcScalableVector { .. }
|
||||
| AttributeKind::RustcShouldNotBeCalledOnConstItems(..)
|
||||
| AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
|
||||
| AttributeKind::RustcVariance
|
||||
| AttributeKind::RustcVarianceOfOpaques
|
||||
| AttributeKind::ShouldPanic { .. }
|
||||
| AttributeKind::SkipDuringMethodDispatch { .. }
|
||||
| AttributeKind::SpecializationTrait(..)
|
||||
| AttributeKind::StdInternalSymbol (..)
|
||||
| AttributeKind::ThreadLocal
|
||||
| AttributeKind::TypeConst{..}
|
||||
| AttributeKind::TypeLengthLimit { .. }
|
||||
| AttributeKind::UnsafeSpecializationMarker(..)
|
||||
| AttributeKind::UnstableFeatureBound(..)
|
||||
| AttributeKind::Used { .. }
|
||||
| AttributeKind::WindowsSubsystem(..)
|
||||
// tidy-alphabetical-end
|
||||
|
||||
) => { /* do nothing */ }
|
||||
Attribute::Unparsed(attr_item) => {
|
||||
style = Some(attr_item.style);
|
||||
|
|
@ -397,13 +406,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| sym::rustc_no_implicit_bounds
|
||||
| sym::test_runner
|
||||
| sym::reexport_test_harness_main
|
||||
| sym::no_main
|
||||
| sym::no_builtins
|
||||
| sym::crate_type
|
||||
| sym::compiler_builtins
|
||||
| sym::profiler_runtime
|
||||
| sym::needs_panic_runtime
|
||||
| sym::panic_runtime
|
||||
| sym::rustc_preserve_ub_checks,
|
||||
..
|
||||
] => {}
|
||||
|
|
@ -1613,7 +1615,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
.tcx
|
||||
.crate_types()
|
||||
.iter()
|
||||
.all(|kind| matches!(kind, CrateType::Rlib | CrateType::Staticlib));
|
||||
.all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib));
|
||||
if never_needs_link {
|
||||
errors::UnusedNote::LinkerMessagesBinaryCrateOnly
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) {
|
|||
| CrateType::ProcMacro
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Executable
|
||||
| CrateType::Staticlib
|
||||
| CrateType::StaticLib
|
||||
| CrateType::Sdylib => true,
|
||||
CrateType::Rlib => false,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1614,6 +1614,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
suggestions.retain(|suggestion| suggestion.is_stable || self.tcx.sess.is_nightly_build());
|
||||
suggestions
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -141,12 +141,6 @@ session_unleashed_feature_help_unnamed = skipping check that does not even have
|
|||
|
||||
session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
|
||||
|
||||
session_unsupported_crate_type_for_codegen_backend =
|
||||
dropping unsupported crate type `{$crate_type}` for codegen backend `{$codegen_backend}`
|
||||
|
||||
session_unsupported_crate_type_for_target =
|
||||
dropping unsupported crate type `{$crate_type}` for target `{$target_triple}`
|
||||
|
||||
session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is not supported
|
||||
session_unsupported_dwarf_version_help = supported DWARF versions are 2, 3, 4 and 5
|
||||
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ use std::hash::Hash;
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::str::{self, FromStr};
|
||||
use std::sync::LazyLock;
|
||||
use std::{cmp, fmt, fs, iter};
|
||||
use std::{cmp, fs, iter};
|
||||
|
||||
use externs::{ExternOpt, split_extern_opt};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::stable_hasher::{StableHasher, StableOrd, ToStableHashKey};
|
||||
use rustc_errors::emitter::HumanReadableErrorType;
|
||||
use rustc_errors::{ColorConfig, DiagArgValue, DiagCtxtFlags, IntoDiagArg};
|
||||
use rustc_errors::{ColorConfig, DiagCtxtFlags};
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_hashes::Hash64;
|
||||
use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic};
|
||||
|
|
@ -1529,29 +1529,7 @@ pub enum EntryFnType {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, BlobDecodable)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum CrateType {
|
||||
Executable,
|
||||
Dylib,
|
||||
Rlib,
|
||||
Staticlib,
|
||||
Cdylib,
|
||||
ProcMacro,
|
||||
Sdylib,
|
||||
}
|
||||
|
||||
impl CrateType {
|
||||
pub fn has_metadata(self) -> bool {
|
||||
match self {
|
||||
CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
|
||||
CrateType::Executable
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Staticlib
|
||||
| CrateType::Sdylib => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub use rustc_hir::attrs::CrateType;
|
||||
|
||||
#[derive(Clone, Hash, Debug, PartialEq, Eq)]
|
||||
pub enum Passes {
|
||||
|
|
@ -1595,10 +1573,6 @@ pub struct BranchProtection {
|
|||
pub gcs: bool,
|
||||
}
|
||||
|
||||
pub(crate) const fn default_lib_output() -> CrateType {
|
||||
CrateType::Rlib
|
||||
}
|
||||
|
||||
pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
|
||||
// First disallow some configuration given on the command line
|
||||
cfg::disallow_cfgs(sess, &user_cfg);
|
||||
|
|
@ -2873,9 +2847,9 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
|
|||
for unparsed_crate_type in &list_list {
|
||||
for part in unparsed_crate_type.split(',') {
|
||||
let new_part = match part {
|
||||
"lib" => default_lib_output(),
|
||||
"lib" => CrateType::default(),
|
||||
"rlib" => CrateType::Rlib,
|
||||
"staticlib" => CrateType::Staticlib,
|
||||
"staticlib" => CrateType::StaticLib,
|
||||
"dylib" => CrateType::Dylib,
|
||||
"cdylib" => CrateType::Cdylib,
|
||||
"bin" => CrateType::Executable,
|
||||
|
|
@ -2969,26 +2943,6 @@ pub mod nightly_options {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CrateType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
CrateType::Executable => "bin".fmt(f),
|
||||
CrateType::Dylib => "dylib".fmt(f),
|
||||
CrateType::Rlib => "rlib".fmt(f),
|
||||
CrateType::Staticlib => "staticlib".fmt(f),
|
||||
CrateType::Cdylib => "cdylib".fmt(f),
|
||||
CrateType::ProcMacro => "proc-macro".fmt(f),
|
||||
CrateType::Sdylib => "sdylib".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagArg for CrateType {
|
||||
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
|
||||
self.to_string().into_diag_arg(&mut None)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum PpSourceMode {
|
||||
/// `-Zunpretty=normal`
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
|||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTuple};
|
||||
|
||||
use crate::config::CrateType;
|
||||
use crate::parse::ParseSess;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -376,20 +375,6 @@ struct BinaryFloatLiteralNotSupported {
|
|||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_unsupported_crate_type_for_codegen_backend)]
|
||||
pub(crate) struct UnsupportedCrateTypeForCodegenBackend {
|
||||
pub(crate) crate_type: CrateType,
|
||||
pub(crate) codegen_backend: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_unsupported_crate_type_for_target)]
|
||||
pub(crate) struct UnsupportedCrateTypeForTarget<'a> {
|
||||
pub(crate) crate_type: CrateType,
|
||||
pub(crate) target_triple: &'a TargetTuple,
|
||||
}
|
||||
|
||||
pub fn report_lit_error(
|
||||
psess: &ParseSess,
|
||||
err: LitError,
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@
|
|||
|
||||
use std::path::Path;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use crate::Session;
|
||||
use crate::config::{self, CrateType, OutFileName, OutputFilenames, OutputType};
|
||||
use crate::errors::{self, CrateNameEmpty, FileIsNotWriteable, InvalidCharacterInCrateName};
|
||||
use crate::config::{CrateType, OutFileName, OutputFilenames, OutputType};
|
||||
use crate::errors::{CrateNameEmpty, FileIsNotWriteable, InvalidCharacterInCrateName};
|
||||
|
||||
pub fn out_filename(
|
||||
sess: &Session,
|
||||
|
|
@ -101,7 +100,7 @@ pub fn filename_for_input(
|
|||
let (prefix, suffix) = (&sess.target.dll_prefix, &sess.target.dll_suffix);
|
||||
OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")))
|
||||
}
|
||||
CrateType::Staticlib => {
|
||||
CrateType::StaticLib => {
|
||||
let (prefix, suffix) = sess.staticlib_components(false);
|
||||
OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")))
|
||||
}
|
||||
|
|
@ -121,19 +120,6 @@ pub fn filename_for_input(
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns default crate type for target
|
||||
///
|
||||
/// Default crate type is used when crate type isn't provided neither
|
||||
/// through cmd line arguments nor through crate attributes
|
||||
///
|
||||
/// It is CrateType::Executable for all platforms but iOS as there is no
|
||||
/// way to run iOS binaries anyway without jailbreaking and
|
||||
/// interaction with Rust code through static library is the only
|
||||
/// option for now
|
||||
pub fn default_output_for_target(sess: &Session) -> CrateType {
|
||||
if !sess.target.executables { CrateType::Staticlib } else { CrateType::Executable }
|
||||
}
|
||||
|
||||
/// Checks if target supports crate_type as output
|
||||
pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool {
|
||||
if let CrateType::Cdylib | CrateType::Dylib | CrateType::ProcMacro = crate_type {
|
||||
|
|
@ -157,88 +143,3 @@ pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool
|
|||
|
||||
false
|
||||
}
|
||||
|
||||
pub const CRATE_TYPES: &[(Symbol, CrateType)] = &[
|
||||
(sym::rlib, CrateType::Rlib),
|
||||
(sym::dylib, CrateType::Dylib),
|
||||
(sym::cdylib, CrateType::Cdylib),
|
||||
(sym::lib, config::default_lib_output()),
|
||||
(sym::staticlib, CrateType::Staticlib),
|
||||
(sym::proc_dash_macro, CrateType::ProcMacro),
|
||||
(sym::bin, CrateType::Executable),
|
||||
(sym::sdylib, CrateType::Sdylib),
|
||||
];
|
||||
|
||||
pub fn categorize_crate_type(s: Symbol) -> Option<CrateType> {
|
||||
Some(CRATE_TYPES.iter().find(|(key, _)| *key == s)?.1)
|
||||
}
|
||||
|
||||
pub fn collect_crate_types(
|
||||
session: &Session,
|
||||
backend_crate_types: &[CrateType],
|
||||
codegen_backend_name: &'static str,
|
||||
attrs: &[ast::Attribute],
|
||||
) -> Vec<CrateType> {
|
||||
// If we're generating a test executable, then ignore all other output
|
||||
// styles at all other locations
|
||||
if session.opts.test {
|
||||
if !session.target.executables {
|
||||
session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget {
|
||||
crate_type: CrateType::Executable,
|
||||
target_triple: &session.opts.target_triple,
|
||||
});
|
||||
return Vec::new();
|
||||
}
|
||||
return vec![CrateType::Executable];
|
||||
}
|
||||
|
||||
// Shadow `sdylib` crate type in interface build.
|
||||
if session.opts.unstable_opts.build_sdylib_interface {
|
||||
return vec![CrateType::Rlib];
|
||||
}
|
||||
|
||||
// Only check command line flags if present. If no types are specified by
|
||||
// command line, then reuse the empty `base` Vec to hold the types that
|
||||
// will be found in crate attributes.
|
||||
// JUSTIFICATION: before wrapper fn is available
|
||||
#[allow(rustc::bad_opt_access)]
|
||||
let mut base = session.opts.crate_types.clone();
|
||||
if base.is_empty() {
|
||||
let attr_types = attrs.iter().filter_map(|a| {
|
||||
if a.has_name(sym::crate_type)
|
||||
&& let Some(s) = a.value_str()
|
||||
{
|
||||
categorize_crate_type(s)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
base.extend(attr_types);
|
||||
if base.is_empty() {
|
||||
base.push(default_output_for_target(session));
|
||||
} else {
|
||||
base.sort();
|
||||
base.dedup();
|
||||
}
|
||||
}
|
||||
|
||||
base.retain(|crate_type| {
|
||||
if invalid_output_for_target(session, *crate_type) {
|
||||
session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget {
|
||||
crate_type: *crate_type,
|
||||
target_triple: &session.opts.target_triple,
|
||||
});
|
||||
false
|
||||
} else if !backend_crate_types.contains(crate_type) {
|
||||
session.dcx().emit_warn(errors::UnsupportedCrateTypeForCodegenBackend {
|
||||
crate_type: *crate_type,
|
||||
codegen_backend: codegen_backend_name,
|
||||
});
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
base
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ use rustc_ast::attr::AttrIdGenerator;
|
|||
use rustc_ast::node_id::NodeId;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::sync::{AppendOnlyVec, Lock};
|
||||
use rustc_errors::emitter::{EmitterWithNote, HumanEmitter, stderr_destination};
|
||||
use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
|
||||
use rustc_errors::emitter::{EmitterWithNote, stderr_destination};
|
||||
use rustc_errors::translation::Translator;
|
||||
use rustc_errors::{
|
||||
BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle,
|
||||
|
|
@ -283,7 +284,7 @@ impl ParseSess {
|
|||
let translator = Translator::with_fallback_bundle(locale_resources, false);
|
||||
let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let emitter = Box::new(
|
||||
HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator)
|
||||
AnnotateSnippetEmitter::new(stderr_destination(ColorConfig::Auto), translator)
|
||||
.sm(Some(Arc::clone(&sm))),
|
||||
);
|
||||
let dcx = DiagCtxt::new(emitter);
|
||||
|
|
@ -315,8 +316,10 @@ impl ParseSess {
|
|||
pub fn emitter_with_note(locale_resources: Vec<&'static str>, note: String) -> Self {
|
||||
let translator = Translator::with_fallback_bundle(locale_resources, false);
|
||||
let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let emitter =
|
||||
Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator));
|
||||
let emitter = Box::new(AnnotateSnippetEmitter::new(
|
||||
stderr_destination(ColorConfig::Auto),
|
||||
translator,
|
||||
));
|
||||
let dcx = DiagCtxt::new(Box::new(EmitterWithNote { emitter, note }));
|
||||
ParseSess::with_dcx(dcx, sm)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![cfg_attr(target_arch = "loongarch64", feature(stdarch_loongarch))]
|
||||
#![feature(cfg_select)]
|
||||
#![feature(core_io_borrowed_buf)]
|
||||
|
|
|
|||
|
|
@ -362,6 +362,7 @@ symbols! {
|
|||
Send,
|
||||
SeqCst,
|
||||
Sized,
|
||||
Slice,
|
||||
SliceIndex,
|
||||
SliceIter,
|
||||
Some,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ edition = "2024"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
punycode = "0.4.0"
|
||||
rustc-demangle = "0.1.21"
|
||||
rustc-demangle = "0.1.27"
|
||||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
|
|
|
|||
|
|
@ -648,7 +648,10 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
|
|||
p.push_ident(name.as_str());
|
||||
match projection.term.kind() {
|
||||
ty::TermKind::Ty(ty) => ty.print(p),
|
||||
ty::TermKind::Const(c) => c.print(p),
|
||||
ty::TermKind::Const(c) => {
|
||||
p.push("K");
|
||||
c.print(p)
|
||||
}
|
||||
}?;
|
||||
}
|
||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_errors::FatalError;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_hir::{self as hir, LangItem, find_attr};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{
|
||||
self, EarlyBinder, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||
|
|
@ -24,7 +25,8 @@ use crate::infer::TyCtxtInferExt;
|
|||
pub use crate::traits::DynCompatibilityViolation;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::{
|
||||
MethodViolationCode, Obligation, ObligationCause, normalize_param_env_or_error, util,
|
||||
AssocConstViolation, MethodViolation, Obligation, ObligationCause,
|
||||
normalize_param_env_or_error, util,
|
||||
};
|
||||
|
||||
/// Returns the dyn-compatibility violations that affect HIR ty lowering.
|
||||
|
|
@ -229,7 +231,7 @@ fn predicate_references_self<'tcx>(
|
|||
// types for trait objects.
|
||||
//
|
||||
// Note that we *do* allow projection *outputs* to contain
|
||||
// `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
|
||||
// `Self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
|
||||
// we just require the user to specify *both* outputs
|
||||
// in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
|
||||
//
|
||||
|
|
@ -288,7 +290,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|||
return false; /* No Sized trait, can't require it! */
|
||||
};
|
||||
|
||||
// Search for a predicate like `Self : Sized` amongst the trait bounds.
|
||||
// Search for a predicate like `Self: Sized` amongst the trait bounds.
|
||||
let predicates = tcx.predicates_of(def_id);
|
||||
let predicates = predicates.instantiate_identity(tcx).predicates;
|
||||
elaborate(tcx, predicates).any(|pred| match pred.kind().skip_binder() {
|
||||
|
|
@ -306,24 +308,51 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns `Some(_)` if this item makes the containing trait dyn-incompatible.
|
||||
#[instrument(level = "debug", skip(tcx), ret)]
|
||||
pub fn dyn_compatibility_violations_for_assoc_item(
|
||||
tcx: TyCtxt<'_>,
|
||||
trait_def_id: DefId,
|
||||
item: ty::AssocItem,
|
||||
) -> Vec<DynCompatibilityViolation> {
|
||||
// Any item that has a `Self : Sized` requisite is otherwise
|
||||
// exempt from the regulations.
|
||||
// Any item that has a `Self: Sized` requisite is otherwise exempt from the regulations.
|
||||
if tcx.generics_require_sized_self(item.def_id) {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let span = || item.ident(tcx).span;
|
||||
|
||||
match item.kind {
|
||||
// Associated consts are never dyn-compatible, as they can't have `where` bounds yet at all,
|
||||
// and associated const bounds in trait objects aren't a thing yet either.
|
||||
ty::AssocKind::Const { name } => {
|
||||
vec![DynCompatibilityViolation::AssocConst(name, item.ident(tcx).span)]
|
||||
// We will permit type associated consts if they are explicitly mentioned in the
|
||||
// trait object type. We can't check this here, as here we only check if it is
|
||||
// guaranteed to not be possible.
|
||||
|
||||
let mut errors = Vec::new();
|
||||
|
||||
if tcx.features().min_generic_const_args() {
|
||||
if !tcx.generics_of(item.def_id).is_own_empty() {
|
||||
errors.push(AssocConstViolation::Generic);
|
||||
} else if !find_attr!(tcx.get_all_attrs(item.def_id), AttributeKind::TypeConst(_)) {
|
||||
errors.push(AssocConstViolation::NonType);
|
||||
}
|
||||
|
||||
let ty = ty::Binder::dummy(tcx.type_of(item.def_id).instantiate_identity());
|
||||
if contains_illegal_self_type_reference(
|
||||
tcx,
|
||||
trait_def_id,
|
||||
ty,
|
||||
AllowSelfProjections::Yes,
|
||||
) {
|
||||
errors.push(AssocConstViolation::TypeReferencesSelf);
|
||||
}
|
||||
} else {
|
||||
errors.push(AssocConstViolation::FeatureNotEnabled);
|
||||
}
|
||||
|
||||
errors
|
||||
.into_iter()
|
||||
.map(|error| DynCompatibilityViolation::AssocConst(name, error, span()))
|
||||
.collect()
|
||||
}
|
||||
ty::AssocKind::Fn { name, .. } => {
|
||||
virtual_call_violations_for_method(tcx, trait_def_id, item)
|
||||
|
|
@ -332,26 +361,28 @@ pub fn dyn_compatibility_violations_for_assoc_item(
|
|||
let node = tcx.hir_get_if_local(item.def_id);
|
||||
// Get an accurate span depending on the violation.
|
||||
let span = match (&v, node) {
|
||||
(MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
|
||||
(MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
|
||||
(MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
|
||||
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
|
||||
(MethodViolation::ReferencesSelfInput(Some(span)), _) => *span,
|
||||
(MethodViolation::UndispatchableReceiver(Some(span)), _) => *span,
|
||||
(MethodViolation::ReferencesImplTraitInTrait(span), _) => *span,
|
||||
(MethodViolation::ReferencesSelfOutput, Some(node)) => {
|
||||
node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
|
||||
}
|
||||
_ => item.ident(tcx).span,
|
||||
_ => span(),
|
||||
};
|
||||
|
||||
DynCompatibilityViolation::Method(name, v, span)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
// Associated types can only be dyn-compatible if they have `Self: Sized` bounds.
|
||||
ty::AssocKind::Type { .. } => {
|
||||
if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() {
|
||||
vec![DynCompatibilityViolation::GAT(item.name(), item.ident(tcx).span)]
|
||||
ty::AssocKind::Type { data } => {
|
||||
if !tcx.generics_of(item.def_id).is_own_empty()
|
||||
&& let ty::AssocTypeData::Normal(name) = data
|
||||
{
|
||||
vec![DynCompatibilityViolation::GenericAssocTy(name, span())]
|
||||
} else {
|
||||
// We will permit associated types if they are explicitly mentioned in the trait object.
|
||||
// We can't check this here, as here we only check if it is guaranteed to not be possible.
|
||||
// We will permit associated types if they are explicitly mentioned in the trait
|
||||
// object type. We can't check this here, as here we only check if it is
|
||||
// guaranteed to not be possible.
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
|
@ -366,7 +397,7 @@ fn virtual_call_violations_for_method<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
method: ty::AssocItem,
|
||||
) -> Vec<MethodViolationCode> {
|
||||
) -> Vec<MethodViolation> {
|
||||
let sig = tcx.fn_sig(method.def_id).instantiate_identity();
|
||||
|
||||
// The method's first parameter must be named `self`
|
||||
|
|
@ -394,7 +425,7 @@ fn virtual_call_violations_for_method<'tcx>(
|
|||
|
||||
// Not having `self` parameter messes up the later checks,
|
||||
// so we need to return instead of pushing
|
||||
return vec![MethodViolationCode::StaticMethod(sugg)];
|
||||
return vec![MethodViolation::StaticMethod(sugg)];
|
||||
}
|
||||
|
||||
let mut errors = Vec::new();
|
||||
|
|
@ -415,7 +446,7 @@ fn virtual_call_violations_for_method<'tcx>(
|
|||
} else {
|
||||
None
|
||||
};
|
||||
errors.push(MethodViolationCode::ReferencesSelfInput(span));
|
||||
errors.push(MethodViolation::ReferencesSelfInput(span));
|
||||
}
|
||||
}
|
||||
if contains_illegal_self_type_reference(
|
||||
|
|
@ -424,19 +455,19 @@ fn virtual_call_violations_for_method<'tcx>(
|
|||
sig.output(),
|
||||
AllowSelfProjections::Yes,
|
||||
) {
|
||||
errors.push(MethodViolationCode::ReferencesSelfOutput);
|
||||
errors.push(MethodViolation::ReferencesSelfOutput);
|
||||
}
|
||||
if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
|
||||
errors.push(code);
|
||||
if let Some(error) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
|
||||
errors.push(error);
|
||||
}
|
||||
if sig.skip_binder().c_variadic {
|
||||
errors.push(MethodViolationCode::CVariadic);
|
||||
errors.push(MethodViolation::CVariadic);
|
||||
}
|
||||
|
||||
// We can't monomorphize things like `fn foo<A>(...)`.
|
||||
let own_counts = tcx.generics_of(method.def_id).own_counts();
|
||||
if own_counts.types > 0 || own_counts.consts > 0 {
|
||||
errors.push(MethodViolationCode::Generic);
|
||||
errors.push(MethodViolation::Generic);
|
||||
}
|
||||
|
||||
let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
|
||||
|
|
@ -456,7 +487,7 @@ fn virtual_call_violations_for_method<'tcx>(
|
|||
} else {
|
||||
None
|
||||
};
|
||||
errors.push(MethodViolationCode::UndispatchableReceiver(span));
|
||||
errors.push(MethodViolation::UndispatchableReceiver(span));
|
||||
} else {
|
||||
// We confirm that the `receiver_is_dispatchable` is accurate later,
|
||||
// see `check_receiver_correct`. It should be kept in sync with this code.
|
||||
|
|
@ -514,7 +545,7 @@ fn virtual_call_violations_for_method<'tcx>(
|
|||
|
||||
contains_illegal_self_type_reference(tcx, trait_def_id, pred, AllowSelfProjections::Yes)
|
||||
}) {
|
||||
errors.push(MethodViolationCode::WhereClauseReferencesSelf);
|
||||
errors.push(MethodViolation::WhereClauseReferencesSelf);
|
||||
}
|
||||
|
||||
errors
|
||||
|
|
@ -672,13 +703,16 @@ enum AllowSelfProjections {
|
|||
No,
|
||||
}
|
||||
|
||||
/// This is somewhat subtle. In general, we want to forbid
|
||||
/// references to `Self` in the argument and return types,
|
||||
/// since the value of `Self` is erased. However, there is one
|
||||
/// exception: it is ok to reference `Self` in order to access
|
||||
/// an associated type of the current trait, since we retain
|
||||
/// the value of those associated types in the object type
|
||||
/// itself.
|
||||
/// Check if the given value contains illegal `Self` references.
|
||||
///
|
||||
/// This is somewhat subtle. In general, we want to forbid references to `Self` in the
|
||||
/// argument and return types, since the value of `Self` is erased.
|
||||
///
|
||||
/// However, there is one exception: It is ok to reference `Self` in order to access an
|
||||
/// associated type of the current trait, since we retain the value of those associated
|
||||
/// types in the trait object type itself.
|
||||
///
|
||||
/// The same thing holds for associated consts under feature `min_generic_const_args`.
|
||||
///
|
||||
/// ```rust,ignore (example)
|
||||
/// trait SuperTrait {
|
||||
|
|
@ -733,82 +767,88 @@ struct IllegalSelfTypeVisitor<'tcx> {
|
|||
allow_self_projections: AllowSelfProjections,
|
||||
}
|
||||
|
||||
impl<'tcx> IllegalSelfTypeVisitor<'tcx> {
|
||||
fn is_supertrait_of_current_trait(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
|
||||
// Compute supertraits of current trait lazily.
|
||||
let supertraits = self.supertraits.get_or_insert_with(|| {
|
||||
util::supertraits(
|
||||
self.tcx,
|
||||
ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id)),
|
||||
)
|
||||
.map(|trait_ref| {
|
||||
self.tcx.erase_and_anonymize_regions(
|
||||
self.tcx.instantiate_bound_regions_with_erased(trait_ref),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
// Determine whether the given trait ref is in fact a supertrait of the current trait.
|
||||
// In that case, any derived projections are legal, because the term will be specified
|
||||
// in the trait object type.
|
||||
// Note that we can just use direct equality here because all of these types are part of
|
||||
// the formal parameter listing, and hence there should be no inference variables.
|
||||
let trait_ref = trait_ref
|
||||
.fold_with(&mut EraseEscapingBoundRegions { tcx: self.tcx, binder: ty::INNERMOST });
|
||||
supertraits.contains(&trait_ref)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
match t.kind() {
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||
match ty.kind() {
|
||||
ty::Param(_) => {
|
||||
if t == self.tcx.types.self_param {
|
||||
if ty == self.tcx.types.self_param {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
ty::Alias(ty::Projection, data) if self.tcx.is_impl_trait_in_trait(data.def_id) => {
|
||||
ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => {
|
||||
// We'll deny these later in their own pass
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
ty::Alias(ty::Projection, data) => {
|
||||
ty::Alias(ty::Projection, proj) => {
|
||||
match self.allow_self_projections {
|
||||
AllowSelfProjections::Yes => {
|
||||
// This is a projected type `<Foo as SomeTrait>::X`.
|
||||
|
||||
// Compute supertraits of current trait lazily.
|
||||
if self.supertraits.is_none() {
|
||||
self.supertraits = Some(
|
||||
util::supertraits(
|
||||
self.tcx,
|
||||
ty::Binder::dummy(ty::TraitRef::identity(
|
||||
self.tcx,
|
||||
self.trait_def_id,
|
||||
)),
|
||||
)
|
||||
.map(|trait_ref| {
|
||||
self.tcx.erase_and_anonymize_regions(
|
||||
self.tcx.instantiate_bound_regions_with_erased(trait_ref),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
||||
// Determine whether the trait reference `Foo as
|
||||
// SomeTrait` is in fact a supertrait of the
|
||||
// current trait. In that case, this type is
|
||||
// legal, because the type `X` will be specified
|
||||
// in the object type. Note that we can just use
|
||||
// direct equality here because all of these types
|
||||
// are part of the formal parameter listing, and
|
||||
// hence there should be no inference variables.
|
||||
let is_supertrait_of_current_trait =
|
||||
self.supertraits.as_ref().unwrap().contains(
|
||||
&data.trait_ref(self.tcx).fold_with(
|
||||
&mut EraseEscapingBoundRegions {
|
||||
tcx: self.tcx,
|
||||
binder: ty::INNERMOST,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// only walk contained types if it's not a super trait
|
||||
if is_supertrait_of_current_trait {
|
||||
// Only walk contained types if the parent trait is not a supertrait.
|
||||
if self.is_supertrait_of_current_trait(proj.trait_ref(self.tcx)) {
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
t.super_visit_with(self) // POSSIBLY reporting an error
|
||||
ty.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
AllowSelfProjections::No => t.super_visit_with(self),
|
||||
AllowSelfProjections::No => ty.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
_ => t.super_visit_with(self),
|
||||
_ => ty.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
|
||||
// Constants can only influence dyn-compatibility if they are generic and reference `Self`.
|
||||
// This is only possible for unevaluated constants, so we walk these here.
|
||||
self.tcx.expand_abstract_consts(ct).super_visit_with(self)
|
||||
let ct = self.tcx.expand_abstract_consts(ct);
|
||||
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(proj) if self.tcx.features().min_generic_const_args() => {
|
||||
match self.allow_self_projections {
|
||||
AllowSelfProjections::Yes => {
|
||||
let trait_def_id = self.tcx.parent(proj.def);
|
||||
let trait_ref = ty::TraitRef::from_assoc(self.tcx, trait_def_id, proj.args);
|
||||
|
||||
// Only walk contained consts if the parent trait is not a supertrait.
|
||||
if self.is_supertrait_of_current_trait(trait_ref) {
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
ct.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
AllowSelfProjections::No => ct.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
_ => ct.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -847,12 +887,12 @@ fn contains_illegal_impl_trait_in_trait<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
fn_def_id: DefId,
|
||||
ty: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
) -> Option<MethodViolationCode> {
|
||||
) -> Option<MethodViolation> {
|
||||
let ty = tcx.liberate_late_bound_regions(fn_def_id, ty);
|
||||
|
||||
if tcx.asyncness(fn_def_id).is_async() {
|
||||
// Rendering the error as a separate `async-specific` message is better.
|
||||
Some(MethodViolationCode::AsyncFn)
|
||||
Some(MethodViolation::AsyncFn)
|
||||
} else {
|
||||
ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value()
|
||||
}
|
||||
|
|
@ -864,14 +904,14 @@ struct IllegalRpititVisitor<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalRpititVisitor<'tcx> {
|
||||
type Result = ControlFlow<MethodViolationCode>;
|
||||
type Result = ControlFlow<MethodViolation>;
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||
if let ty::Alias(ty::Projection, proj) = *ty.kind()
|
||||
&& Some(proj) != self.allowed
|
||||
&& self.tcx.is_impl_trait_in_trait(proj.def_id)
|
||||
{
|
||||
ControlFlow::Break(MethodViolationCode::ReferencesImplTraitInTrait(
|
||||
ControlFlow::Break(MethodViolation::ReferencesImplTraitInTrait(
|
||||
self.tcx.def_span(proj.def_id),
|
||||
))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,32 @@ rustflags = ["-Cpanic=abort"]
|
|||
[profile.release.package.panic_abort]
|
||||
rustflags = ["-Cpanic=abort"]
|
||||
|
||||
# The "dist" profile is used by bootstrap for prebuilt libstd artifacts
|
||||
# These settings ensure that the prebuilt artifacts support a variety of features
|
||||
# in the user's profile.
|
||||
[profile.dist]
|
||||
inherits = "release"
|
||||
codegen-units = 1
|
||||
debug = 1 # "limited"
|
||||
rustflags = [
|
||||
# `profile.lto=off` implies `-Cembed-bitcode=no`, but unconditionally embedding
|
||||
# bitcode is necessary for when users enable LTO.
|
||||
# Required until Cargo can re-build the standard library based on the value
|
||||
# of `profile.lto` in the user's profile.
|
||||
"-Cembed-bitcode=yes",
|
||||
# Enable frame pointers
|
||||
"-Zunstable-options",
|
||||
"-Cforce-frame-pointers=non-leaf",
|
||||
]
|
||||
|
||||
[profile.dist.package.panic_abort]
|
||||
rustflags = [
|
||||
"-Cpanic=abort",
|
||||
"-Cembed-bitcode=yes",
|
||||
"-Zunstable-options",
|
||||
"-Cforce-frame-pointers=non-leaf",
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
# See comments in `library/rustc-std-workspace-core/README.md` for what's going on here
|
||||
rustc-std-workspace-core = { path = 'rustc-std-workspace-core' }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use core::assert_matches::assert_matches;
|
||||
use core::assert_matches;
|
||||
use std::iter;
|
||||
use std::ops::Bound::{Excluded, Included, Unbounded};
|
||||
use std::panic::{AssertUnwindSafe, catch_unwind};
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use core::cmp::Ordering::{self, Less};
|
|||
use core::mem::MaybeUninit;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::ptr;
|
||||
#[stable(feature = "array_windows", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[stable(feature = "array_windows", since = "1.94.0")]
|
||||
pub use core::slice::ArrayWindows;
|
||||
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
|
||||
pub use core::slice::EscapeAscii;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use alloc::ffi::CString;
|
||||
use alloc::rc::Rc;
|
||||
use alloc::sync::Arc;
|
||||
use core::assert_matches::assert_matches;
|
||||
use core::assert_matches;
|
||||
use core::ffi::{CStr, FromBytesUntilNulError, c_char};
|
||||
#[allow(deprecated)]
|
||||
use core::hash::SipHasher13 as DefaultHasher;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(invalid_from_utf8)]
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::assert_matches;
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering::{Equal, Greater, Less};
|
||||
use std::str::{from_utf8, from_utf8_unchecked};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use std::assert_matches::assert_matches;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
use std::collections::TryReserveErrorKind::*;
|
||||
use std::ops::Bound::*;
|
||||
use std::ops::{Bound, RangeBounds};
|
||||
use std::{panic, str};
|
||||
use std::{assert_matches, panic, str};
|
||||
|
||||
pub trait IntoCow<'a, B: ?Sized>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -3,12 +3,10 @@ use core::num::NonZero;
|
|||
use core::ptr::NonNull;
|
||||
use core::{assert_eq, assert_ne};
|
||||
use std::alloc::System;
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
use std::collections::TryReserveErrorKind::*;
|
||||
use std::fmt::Debug;
|
||||
use std::hint;
|
||||
use std::iter::InPlaceIterable;
|
||||
use std::mem::swap;
|
||||
use std::ops::Bound::*;
|
||||
|
|
@ -16,6 +14,7 @@ use std::panic::{AssertUnwindSafe, catch_unwind};
|
|||
use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::vec::{Drain, IntoIter, PeekMut};
|
||||
use std::{assert_matches, hint};
|
||||
|
||||
use crate::testing::macros::struct_with_counted_drop;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use core::cell::Cell;
|
||||
use core::num::NonZero;
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::assert_matches;
|
||||
use std::collections::TryReserveErrorKind::*;
|
||||
use std::collections::VecDeque;
|
||||
use std::collections::vec_deque::Drain;
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
|
|||
/// assert_eq!(*lazy, 44);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "lazy_get", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[stable(feature = "lazy_get", since = "1.94.0")]
|
||||
pub fn force_mut(this: &mut LazyCell<T, F>) -> &mut T {
|
||||
#[cold]
|
||||
/// # Safety
|
||||
|
|
@ -273,7 +273,7 @@ impl<T, F> LazyCell<T, F> {
|
|||
/// assert_eq!(*lazy, 44);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "lazy_get", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[stable(feature = "lazy_get", since = "1.94.0")]
|
||||
pub fn get_mut(this: &mut LazyCell<T, F>) -> Option<&mut T> {
|
||||
let state = this.state.get_mut();
|
||||
match state {
|
||||
|
|
@ -297,7 +297,7 @@ impl<T, F> LazyCell<T, F> {
|
|||
/// assert_eq!(LazyCell::get(&lazy), Some(&92));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "lazy_get", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[stable(feature = "lazy_get", since = "1.94.0")]
|
||||
pub fn get(this: &LazyCell<T, F>) -> Option<&T> {
|
||||
// SAFETY:
|
||||
// This is sound for the same reason as in `force`: once the state is
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ impl const TryFrom<char> for u16 {
|
|||
///
|
||||
/// Generally speaking, this conversion can be seen as obtaining the character's corresponding
|
||||
/// UTF-32 code point to the extent representable by pointer addresses.
|
||||
#[stable(feature = "usize_try_from_char", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[stable(feature = "usize_try_from_char", since = "1.94.0")]
|
||||
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
|
||||
impl const TryFrom<char> for usize {
|
||||
type Error = TryFromCharError;
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@
|
|||
reason = "MIR is an implementation detail and extremely unstable",
|
||||
issue = "none"
|
||||
)]
|
||||
#![allow(unused_variables, non_snake_case, missing_debug_implementations)]
|
||||
#![allow(unused_variables, non_snake_case, missing_debug_implementations, missing_docs)]
|
||||
|
||||
/// Type representing basic blocks.
|
||||
///
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue