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:
The Miri Cronjob Bot 2026-01-23 05:10:22 +00:00
commit bf04398434
309 changed files with 3958 additions and 5980 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -67,7 +67,7 @@ pub trait CodegenBackend {
CrateType::Executable,
CrateType::Dylib,
CrateType::Rlib,
CrateType::Staticlib,
CrateType::StaticLib,
CrateType::Cdylib,
CrateType::ProcMacro,
CrateType::Sdylib,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -822,6 +822,10 @@ pub enum AttributeLintKind {
DocTestLiteral,
AttrCrateLevelOnly,
DoNotRecommendDoesNotExpectArgs,
CrateTypeUnknown {
span: Span,
suggested: Option<Symbol>,
},
}
pub type RegisteredTools = FxIndexSet<Ident>;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,4 @@
// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(array_windows))]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(const_type_name)]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1614,6 +1614,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
suggestions.retain(|suggestion| suggestion.is_stable || self.tcx.sess.is_nightly_build());
suggestions
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -362,6 +362,7 @@ symbols! {
Send,
SeqCst,
Sized,
Slice,
SliceIndex,
SliceIter,
Some,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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