diff --git a/.mailmap b/.mailmap index 4c254b396b538..948f1ab14fdea 100644 --- a/.mailmap +++ b/.mailmap @@ -96,6 +96,7 @@ boolean_coercion Boris Egorov bors bors[bot] <26634292+bors[bot]@users.noreply.github.com> bors bors[bot] +bors <122020455+rust-bors[bot]@users.noreply.github.com> BoxyUwU BoxyUwU Braden Nelson diff --git a/INSTALL.md b/INSTALL.md index 98eb825cd10f6..dd6c64b3df5f6 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -97,7 +97,7 @@ See [the rustc-dev-guide for more info][sysllvm]. --set llvm.ninja=false \ --set rust.debug-assertions=false \ --set rust.jemalloc \ - --set rust.use-lld=true \ + --set rust.bootstrap-override-lld=true \ --set rust.lto=thin \ --set rust.codegen-units=1 ``` diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index ccf0a394afd0e..dcb74dda81af6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -94,7 +94,6 @@ pub fn parse_cfg_entry( LitKind::Bool(b) => CfgEntry::Bool(b, lit.span), _ => return Err(cx.expected_identifier(lit.span)), }, - MetaItemOrLitParser::Err(_, err) => return Err(*err), }) } diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 6cc4ac35eadb1..409102a79c06a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -514,9 +514,6 @@ impl DocParser { MetaItemOrLitParser::Lit(lit) => { cx.unexpected_literal(lit.span); } - MetaItemOrLitParser::Err(..) => { - // already had an error here, move on. - } } } } @@ -600,9 +597,6 @@ impl DocParser { MetaItemOrLitParser::Lit(lit) => { cx.expected_name_value(lit.span, None); } - MetaItemOrLitParser::Err(..) => { - // already had an error here, move on. - } } } } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 68265649d1823..ebf12dd1dfdec 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -18,7 +18,7 @@ use rustc_parse::exp; use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr}; use rustc_session::errors::{create_lit_error, report_lit_error}; use rustc_session::parse::ParseSess; -use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym}; +use rustc_span::{Ident, Span, Symbol, sym}; use thin_vec::ThinVec; use crate::ShouldEmit; @@ -192,7 +192,6 @@ impl ArgParser { pub enum MetaItemOrLitParser { MetaItemParser(MetaItemParser), Lit(MetaItemLit), - Err(Span, ErrorGuaranteed), } impl MetaItemOrLitParser { @@ -210,21 +209,20 @@ impl MetaItemOrLitParser { generic_meta_item_parser.span() } MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span, - MetaItemOrLitParser::Err(span, _) => *span, } } pub fn lit(&self) -> Option<&MetaItemLit> { match self { MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit), - _ => None, + MetaItemOrLitParser::MetaItemParser(_) => None, } } pub fn meta_item(&self) -> Option<&MetaItemParser> { match self { MetaItemOrLitParser::MetaItemParser(parser) => Some(parser), - _ => None, + MetaItemOrLitParser::Lit(_) => None, } } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index e5aad4cdbd06c..d2464c7e99ee5 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -19,6 +19,7 @@ use rustc_infer::infer::{ BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, }; use rustc_infer::traits::PredicateObligations; +use rustc_middle::bug; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::traits::query::NoSolution; @@ -28,7 +29,6 @@ use rustc_middle::ty::{ self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, UserArgs, UserTypeAnnotationIndex, fold_regions, }; -use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; @@ -387,18 +387,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[instrument(skip(self), level = "debug")] fn check_user_type_annotations(&mut self) { debug!(?self.user_type_annotations); - let tcx = self.tcx(); for user_annotation in self.user_type_annotations { let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; let annotation = self.instantiate_canonical(span, user_ty); - if let ty::UserTypeKind::TypeOf(def, args) = annotation.kind - && let DefKind::InlineConst = tcx.def_kind(def) - { - assert!(annotation.bounds.is_empty()); - self.check_inline_const(inferred_ty, def.expect_local(), args, span); - } else { - self.ascribe_user_type(inferred_ty, annotation, span); - } + self.ascribe_user_type(inferred_ty, annotation, span); } } @@ -560,36 +552,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.constraints.liveness_constraints.add_location(region, location); } } - - fn check_inline_const( - &mut self, - inferred_ty: Ty<'tcx>, - def_id: LocalDefId, - args: UserArgs<'tcx>, - span: Span, - ) { - assert!(args.user_self_ty.is_none()); - let tcx = self.tcx(); - let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args); - if let Err(terr) = - self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring) - { - span_bug!( - span, - "bad inline const pattern: ({:?} = {:?}) {:?}", - const_ty, - inferred_ty, - terr - ); - } - let args = self.infcx.resolve_vars_if_possible(args.args); - let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span)); - self.normalize_and_prove_instantiated_predicates( - def_id.to_def_id(), - predicates, - Locations::All(span), - ); - } } impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { @@ -1731,12 +1693,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let def_id = uv.def; if tcx.def_kind(def_id) == DefKind::InlineConst { let def_id = def_id.expect_local(); - let predicates = self.prove_closure_bounds( - tcx, - def_id, - uv.args, - location.to_locations(), - ); + let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location); self.normalize_and_prove_instantiated_predicates( def_id.to_def_id(), predicates, @@ -2519,15 +2476,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // clauses on the struct. AggregateKind::Closure(def_id, args) | AggregateKind::CoroutineClosure(def_id, args) - | AggregateKind::Coroutine(def_id, args) => ( - def_id, - self.prove_closure_bounds( - tcx, - def_id.expect_local(), - args, - location.to_locations(), - ), - ), + | AggregateKind::Coroutine(def_id, args) => { + (def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location)) + } AggregateKind::Array(_) | AggregateKind::Tuple | AggregateKind::RawPtr(..) => { (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty()) @@ -2546,12 +2497,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, def_id: LocalDefId, args: GenericArgsRef<'tcx>, - locations: Locations, + location: Location, ) -> ty::InstantiatedPredicates<'tcx> { let root_def_id = self.root_cx.root_def_id(); // We will have to handle propagated closure requirements for this closure, // but need to defer this until the nested body has been fully borrow checked. - self.deferred_closure_requirements.push((def_id, args, locations)); + self.deferred_closure_requirements.push((def_id, args, location.to_locations())); // Equate closure args to regions inherited from `root_def_id`. Fixes #98589. let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, root_def_id); @@ -2575,7 +2526,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Err(_) = self.eq_args( typeck_root_args, parent_args, - locations, + location.to_locations(), ConstraintCategory::BoringNoLocation, ) { span_mirbug!( diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 1501bd6c73e29..f9ffddf790847 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -161,6 +161,8 @@ builtin_macros_eii_only_once = `#[{$name}]` can only be specified once builtin_macros_eii_shared_macro_expected_function = `#[{$name}]` is only valid on functions builtin_macros_eii_shared_macro_expected_max_one_argument = `#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]` +builtin_macros_eii_shared_macro_in_statement_position = `#[{$name}]` can only be used on functions inside a module + .label = `#[{$name}]` is used on this item, which is part of another item's local scope builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index cec7599d68e9c..538f5afae5fc4 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -1,8 +1,7 @@ use rustc_ast::token::{Delimiter, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast::{ - Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, Stmt, StmtKind, - Visibility, ast, + Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, StmtKind, Visibility, ast, }; use rustc_ast_pretty::pprust::path_to_string; use rustc_expand::base::{Annotatable, ExtCtxt}; @@ -12,6 +11,7 @@ use thin_vec::{ThinVec, thin_vec}; use crate::errors::{ EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe, EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroExpectedFunction, + EiiSharedMacroInStatementPosition, }; /// ```rust @@ -55,29 +55,29 @@ fn eii_( ecx: &mut ExtCtxt<'_>, eii_attr_span: Span, meta_item: &ast::MetaItem, - item: Annotatable, + orig_item: Annotatable, impl_unsafe: bool, ) -> Vec { let eii_attr_span = ecx.with_def_site_ctxt(eii_attr_span); - let (item, wrap_item): (_, &dyn Fn(_) -> _) = if let Annotatable::Item(item) = item { - (item, &Annotatable::Item) - } else if let Annotatable::Stmt(ref stmt) = item + let item = if let Annotatable::Item(item) = orig_item { + item + } else if let Annotatable::Stmt(ref stmt) = orig_item && let StmtKind::Item(ref item) = stmt.kind + && let ItemKind::Fn(ref f) = item.kind { - (item.clone(), &|item| { - Annotatable::Stmt(Box::new(Stmt { - id: DUMMY_NODE_ID, - kind: StmtKind::Item(item), - span: eii_attr_span, - })) - }) + ecx.dcx().emit_err(EiiSharedMacroInStatementPosition { + span: eii_attr_span.to(item.span), + name: path_to_string(&meta_item.path), + item_span: f.ident.span, + }); + return vec![orig_item]; } else { ecx.dcx().emit_err(EiiSharedMacroExpectedFunction { span: eii_attr_span, name: path_to_string(&meta_item.path), }); - return vec![item]; + return vec![orig_item]; }; let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } = @@ -87,7 +87,7 @@ fn eii_( span: eii_attr_span, name: path_to_string(&meta_item.path), }); - return vec![wrap_item(item)]; + return vec![Annotatable::Item(item)]; }; // only clone what we need let attrs = attrs.clone(); @@ -98,17 +98,19 @@ fn eii_( filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path); let Ok(macro_name) = name_for_impl_macro(ecx, &func, &meta_item) else { - return vec![wrap_item(item)]; + // we don't need to wrap in Annotatable::Stmt conditionally since + // EII can't be used on items in statement position + return vec![Annotatable::Item(item)]; }; // span of the declaring item without attributes let item_span = func.sig.span; let foreign_item_name = func.ident; - let mut return_items = Vec::new(); + let mut module_items = Vec::new(); if func.body.is_some() { - return_items.push(generate_default_impl( + module_items.push(generate_default_impl( ecx, &func, impl_unsafe, @@ -119,7 +121,7 @@ fn eii_( )) } - return_items.push(generate_foreign_item( + module_items.push(generate_foreign_item( ecx, eii_attr_span, item_span, @@ -127,7 +129,7 @@ fn eii_( vis, &attrs_from_decl, )); - return_items.push(generate_attribute_macro_to_implement( + module_items.push(generate_attribute_macro_to_implement( ecx, eii_attr_span, macro_name, @@ -136,7 +138,9 @@ fn eii_( &attrs_from_decl, )); - return_items.into_iter().map(wrap_item).collect() + // we don't need to wrap in Annotatable::Stmt conditionally since + // EII can't be used on items in statement position + module_items.into_iter().map(Annotatable::Item).collect() } /// Decide on the name of the macro that can be used to implement the EII. @@ -213,29 +217,14 @@ fn generate_default_impl( known_eii_macro_resolution: Some(ast::EiiDecl { foreign_item: ecx.path( foreign_item_name.span, - // prefix super to escape the `dflt` module generated below - vec![Ident::from_str_and_span("super", foreign_item_name.span), foreign_item_name], + // prefix self to explicitly escape the const block generated below + // NOTE: this is why EIIs can't be used on statements + vec![Ident::from_str_and_span("self", foreign_item_name.span), foreign_item_name], ), impl_unsafe, }), }); - let item_mod = |span: Span, name: Ident, items: ThinVec>| { - ecx.item( - item_span, - ThinVec::new(), - ItemKind::Mod( - ast::Safety::Default, - name, - ast::ModKind::Loaded( - items, - ast::Inline::Yes, - ast::ModSpans { inner_span: span, inject_use_span: span }, - ), - ), - ) - }; - let anon_mod = |span: Span, stmts: ThinVec| { let unit = ecx.ty(item_span, ast::TyKind::Tup(ThinVec::new())); let underscore = Ident::new(kw::Underscore, item_span); @@ -248,33 +237,13 @@ fn generate_default_impl( }; // const _: () = { - // mod dflt { - // use super::*; - // - // } + // // } anon_mod( item_span, thin_vec![ecx.stmt_item( item_span, - item_mod( - item_span, - Ident::from_str_and_span("dflt", item_span), - thin_vec![ - ecx.item( - item_span, - thin_vec![ecx.attr_nested_word(sym::allow, sym::unused_imports, item_span)], - ItemKind::Use(ast::UseTree { - prefix: ast::Path::from_ident(Ident::from_str_and_span( - "super", item_span, - )), - kind: ast::UseTreeKind::Glob, - span: item_span, - }) - ), - ecx.item(item_span, attrs, ItemKind::Fn(Box::new(default_func))) - ] - ) + ecx.item(item_span, attrs, ItemKind::Fn(Box::new(default_func))) ),], ) } @@ -366,6 +335,9 @@ fn generate_attribute_macro_to_implement( // errors for eii's in std. macro_attrs.extend_from_slice(attrs_from_decl); + // Avoid "missing stability attribute" errors for eiis in std. See #146993. + macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span)); + // #[builtin_macro(eii_shared_macro)] macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span)); diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 5d4c4e340fa1f..a9ce41c9be76e 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1039,6 +1039,16 @@ pub(crate) struct EiiSharedMacroExpectedFunction { pub name: String, } +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_shared_macro_in_statement_position)] +pub(crate) struct EiiSharedMacroInStatementPosition { + #[primary_span] + pub span: Span, + pub name: String, + #[label] + pub item_span: Span, +} + #[derive(Diagnostic)] #[diag(builtin_macros_eii_only_once)] pub(crate) struct EiiOnlyOnce { diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 1878f4043ee84..838db689e7292 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -144,7 +144,7 @@ impl CodegenCx<'_, '_> { } // PowerPC64 prefers TOC indirection to avoid copy relocations. - if matches!(self.tcx.sess.target.arch, Arch::PowerPC64 | Arch::PowerPC64LE) { + if self.tcx.sess.target.arch == Arch::PowerPC64 { return false; } diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 688f461e7478a..c7da2457ada5c 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -1064,15 +1064,6 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( AllowHigherAlign::Yes, ForceRightAdjust::Yes, ), - Arch::PowerPC64LE => emit_ptr_va_arg( - bx, - addr, - target_ty, - PassMode::Direct, - SlotSize::Bytes8, - AllowHigherAlign::Yes, - ForceRightAdjust::No, - ), Arch::LoongArch32 => emit_ptr_va_arg( bx, addr, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index bacdf0049806e..2c02534093870 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -47,9 +47,7 @@ use rustc_trait_selection::traits::{ use tracing::{debug, instrument}; use crate::errors; -use crate::hir_ty_lowering::{ - FeedConstTy, HirTyLowerer, InherentAssocCandidate, RegionInferReason, -}; +use crate::hir_ty_lowering::{HirTyLowerer, InherentAssocCandidate, RegionInferReason}; pub(crate) mod dump; mod generics_of; @@ -1499,7 +1497,7 @@ fn const_param_default<'tcx>( let ct = icx .lowerer() - .lower_const_arg(default_ct, FeedConstTy::with_type_of(tcx, def_id, identity_args)); + .lower_const_arg(default_ct, tcx.type_of(def_id).instantiate(tcx, identity_args)); ty::EarlyBinder::bind(ct) } @@ -1557,7 +1555,7 @@ fn const_of_item<'tcx>( let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); let ct = icx .lowerer() - .lower_const_arg(ct_arg, FeedConstTy::with_type_of(tcx, def_id.to_def_id(), identity_args)); + .lower_const_arg(ct_arg, tcx.type_of(def_id.to_def_id()).instantiate(tcx, identity_args)); if let Err(e) = icx.check_tainted_by_errors() && !ct.references_error() { diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index d835a7bbb8d29..2b7854769b426 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -988,6 +988,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { gen_arg_spans[self.num_expected_type_or_const_args() - 1] }; let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1]; + if !span_lo_redundant_type_or_const_args.eq_ctxt(span_hi_redundant_type_or_const_args) { + return; + } let span_redundant_type_or_const_args = span_lo_redundant_type_or_const_args .shrink_to_hi() .to(span_hi_redundant_type_or_const_args); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 72d21371f66cc..d6441702b268c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -20,7 +20,7 @@ use tracing::{debug, instrument}; use crate::errors; use crate::hir_ty_lowering::{ - AssocItemQSelf, FeedConstTy, GenericsArgsErrExtend, HirTyLowerer, ImpliedBoundsContext, + AssocItemQSelf, GenericsArgsErrExtend, HirTyLowerer, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, }; @@ -510,7 +510,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Create the generic arguments for the associated type or constant by joining the // parent arguments (the arguments of the trait) and the own arguments (the ones of // the associated item itself) and construct an alias type using them. - let alias_term = candidate.map_bound(|trait_ref| { + candidate.map_bound(|trait_ref| { let item_segment = hir::PathSegment { ident: constraint.ident, hir_id: constraint.hir_id, @@ -528,20 +528,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?alias_args); ty::AliasTerm::new_from_args(tcx, assoc_item.def_id, alias_args) - }); - - // Provide the resolved type of the associated constant to `type_of(AnonConst)`. - if let Some(const_arg) = constraint.ct() - && let hir::ConstArgKind::Anon(anon_const) = const_arg.kind - { - let ty = alias_term - .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args)); - let ty = - check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id); - tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty)); - } - - alias_term + }) }; match constraint.kind { @@ -555,7 +542,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::AssocItemConstraintKind::Equality { term } => { let term = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), - hir::Term::Const(ct) => self.lower_const_arg(ct, FeedConstTy::No).into(), + hir::Term::Const(ct) => { + let ty = projection_term.map_bound(|alias| { + tcx.type_of(alias.def_id).instantiate(tcx, alias.args) + }); + let ty = check_assoc_const_binding_type( + self, + constraint.ident, + ty, + constraint.hir_id, + ); + + self.lower_const_arg(ct, ty).into() + } }; // Find any late-bound regions declared in `ty` that are not @@ -871,7 +870,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// probably gate this behind another feature flag. /// /// [^1]: . -fn check_assoc_const_binding_type<'tcx>( +pub(crate) fn check_assoc_const_binding_type<'tcx>( cx: &dyn HirTyLowerer<'tcx>, assoc_const: Ident, ty: ty::Binder<'tcx, Ty<'tcx>>, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a66a521975c53..6e1e6c157a91e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -253,35 +253,6 @@ impl AssocItemQSelf { } } -/// In some cases, [`hir::ConstArg`]s that are being used in the type system -/// through const generics need to have their type "fed" to them -/// using the query system. -/// -/// Use this enum with `::lower_const_arg` to instruct it with the -/// desired behavior. -#[derive(Debug, Clone, Copy)] -pub enum FeedConstTy<'tcx> { - /// Feed the type to the (anno) const arg. - WithTy(Ty<'tcx>), - /// Don't feed the type. - No, -} - -impl<'tcx> FeedConstTy<'tcx> { - /// The `DefId` belongs to the const param that we are supplying - /// this (anon) const arg to. - /// - /// The list of generic args is used to instantiate the parameters - /// used by the type of the const param specified by `DefId`. - pub fn with_type_of( - tcx: TyCtxt<'tcx>, - def_id: DefId, - generic_args: &[ty::GenericArg<'tcx>], - ) -> Self { - Self::WithTy(tcx.type_of(def_id).instantiate(tcx, generic_args)) - } -} - #[derive(Debug, Clone, Copy)] enum LowerTypeRelativePathMode { Type(PermitVariants), @@ -733,7 +704,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Ambig portions of `ConstArg` are handled in the match arm below .lower_const_arg( ct.as_unambig_ct(), - FeedConstTy::with_type_of(tcx, param.def_id, preceding_args), + tcx.type_of(param.def_id).instantiate(tcx, preceding_args), ) .into(), (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { @@ -1269,10 +1240,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut where_bounds = vec![]; for bound in [bound, bound2].into_iter().chain(matching_candidates) { let bound_id = bound.def_id(); - let bound_span = tcx - .associated_items(bound_id) - .find_by_ident_and_kind(tcx, assoc_ident, assoc_tag, bound_id) - .and_then(|item| tcx.hir_span_if_local(item.def_id)); + let assoc_item = tcx.associated_items(bound_id).find_by_ident_and_kind( + tcx, + assoc_ident, + assoc_tag, + bound_id, + ); + let bound_span = assoc_item.and_then(|item| tcx.hir_span_if_local(item.def_id)); if let Some(bound_span) = bound_span { err.span_label( @@ -1285,7 +1259,43 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let term: ty::Term<'_> = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), hir::Term::Const(ct) => { - self.lower_const_arg(ct, FeedConstTy::No).into() + let assoc_item = + assoc_item.expect("assoc_item should be present"); + let projection_term = bound.map_bound(|trait_ref| { + let item_segment = hir::PathSegment { + ident: constraint.ident, + hir_id: constraint.hir_id, + res: Res::Err, + args: Some(constraint.gen_args), + infer_args: false, + }; + + let alias_args = self.lower_generic_args_of_assoc_item( + constraint.ident.span, + assoc_item.def_id, + &item_segment, + trait_ref.args, + ); + ty::AliasTerm::new_from_args( + tcx, + assoc_item.def_id, + alias_args, + ) + }); + + // FIXME(mgca): code duplication with other places we lower + // the rhs' of associated const bindings + let ty = projection_term.map_bound(|alias| { + tcx.type_of(alias.def_id).instantiate(tcx, alias.args) + }); + let ty = bounds::check_assoc_const_binding_type( + self, + constraint.ident, + ty, + constraint.hir_id, + ); + + self.lower_const_arg(ct, ty).into() } }; if term.references_error() { @@ -2310,16 +2320,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`](Const). #[instrument(skip(self), level = "debug")] - pub fn lower_const_arg( - &self, - const_arg: &hir::ConstArg<'tcx>, - feed: FeedConstTy<'tcx>, - ) -> Const<'tcx> { + pub fn lower_const_arg(&self, const_arg: &hir::ConstArg<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { let tcx = self.tcx(); - if let FeedConstTy::WithTy(anon_const_type) = feed - && let hir::ConstArgKind::Anon(anon) = &const_arg.kind - { + if let hir::ConstArgKind::Anon(anon) = &const_arg.kind { // FIXME(generic_const_parameter_types): Ideally we remove these errors below when // we have the ability to intermix typeck of anon const const args with the parent // bodies typeck. @@ -2329,7 +2333,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // hir typeck was using equality but mir borrowck wound up using subtyping as that could // result in a non-infer in hir typeck but a region variable in borrowck. if tcx.features().generic_const_parameter_types() - && (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions()) + && (ty.has_free_regions() || ty.has_erased_regions()) { let e = self.dcx().span_err( const_arg.span, @@ -2341,7 +2345,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // We must error if the instantiated type has any inference variables as we will // use this type to feed the `type_of` and query results must not contain inference // variables otherwise we will ICE. - if anon_const_type.has_non_region_infer() { + if ty.has_non_region_infer() { let e = self.dcx().span_err( const_arg.span, "anonymous constants with inferred types are not yet supported", @@ -2351,7 +2355,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } // We error when the type contains unsubstituted generics since we do not currently // give the anon const any of the generics from the parent. - if anon_const_type.has_non_region_param() { + if ty.has_non_region_param() { let e = self.dcx().span_err( const_arg.span, "anonymous constants referencing generics are not yet supported", @@ -2360,12 +2364,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return ty::Const::new_error(tcx, e); } - tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(anon_const_type)); + tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(ty)); } let hir_id = const_arg.hir_id; match const_arg.kind { - hir::ConstArgKind::Tup(exprs) => self.lower_const_arg_tup(exprs, feed, const_arg.span), + hir::ConstArgKind::Tup(exprs) => self.lower_const_arg_tup(exprs, ty, const_arg.span), hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); @@ -2389,16 +2393,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::ConstArgKind::TupleCall(qpath, args) => { self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span) } - hir::ConstArgKind::Array(array_expr) => self.lower_const_arg_array(array_expr, feed), + hir::ConstArgKind::Array(array_expr) => self.lower_const_arg_array(array_expr, ty), hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon), hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span), hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e), - hir::ConstArgKind::Literal(kind) if let FeedConstTy::WithTy(anon_const_type) = feed => { - self.lower_const_arg_literal(&kind, anon_const_type, const_arg.span) - } - hir::ConstArgKind::Literal(..) => { - let e = self.dcx().span_err(const_arg.span, "literal of unknown type"); - ty::Const::new_error(tcx, e) + hir::ConstArgKind::Literal(kind) => { + self.lower_const_arg_literal(&kind, ty, const_arg.span) } } } @@ -2406,14 +2406,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn lower_const_arg_array( &self, array_expr: &'tcx hir::ConstArgArrayExpr<'tcx>, - feed: FeedConstTy<'tcx>, + ty: Ty<'tcx>, ) -> Const<'tcx> { let tcx = self.tcx(); - let FeedConstTy::WithTy(ty) = feed else { - return Const::new_error_with_message(tcx, array_expr.span, "unsupported const array"); - }; - let ty::Array(elem_ty, _) = ty.kind() else { let e = tcx .dcx() @@ -2424,7 +2420,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let elems = array_expr .elems .iter() - .map(|elem| self.lower_const_arg(elem, FeedConstTy::WithTy(*elem_ty))) + .map(|elem| self.lower_const_arg(elem, *elem_ty)) .collect::>(); let valtree = ty::ValTree::from_branches(tcx, elems); @@ -2507,7 +2503,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .zip(args) .map(|(field_def, arg)| { - self.lower_const_arg(arg, FeedConstTy::with_type_of(tcx, field_def.did, adt_args)) + self.lower_const_arg(arg, tcx.type_of(field_def.did).instantiate(tcx, adt_args)) }) .collect::>(); @@ -2526,15 +2522,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn lower_const_arg_tup( &self, exprs: &'tcx [&'tcx hir::ConstArg<'tcx>], - feed: FeedConstTy<'tcx>, + ty: Ty<'tcx>, span: Span, ) -> Const<'tcx> { let tcx = self.tcx(); - let FeedConstTy::WithTy(ty) = feed else { - return Const::new_error_with_message(tcx, span, "const tuple lack type information"); - }; - let ty::Tuple(tys) = ty.kind() else { let e = tcx.dcx().span_err(span, format!("expected `{}`, found const tuple", ty)); return Const::new_error(tcx, e); @@ -2543,7 +2535,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let exprs = exprs .iter() .zip(tys.iter()) - .map(|(expr, ty)| self.lower_const_arg(expr, FeedConstTy::WithTy(ty))) + .map(|(expr, ty)| self.lower_const_arg(expr, ty)) .collect::>(); let valtree = ty::ValTree::from_branches(tcx, exprs); @@ -2630,7 +2622,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.lower_const_arg( expr.expr, - FeedConstTy::with_type_of(tcx, field_def.did, adt_args), + tcx.type_of(field_def.did).instantiate(tcx, adt_args), ) } None => { @@ -2992,7 +2984,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) } hir::TyKind::Array(ty, length) => { - let length = self.lower_const_arg(length, FeedConstTy::No); + let length = self.lower_const_arg(length, tcx.types.usize); Ty::new_array_with_const_len(tcx, self.lower_ty(ty), length) } hir::TyKind::Infer(()) => { @@ -3032,8 +3024,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Keep this list of types in sync with the list of types that // the `RangePattern` trait is implemented for. ty::Int(_) | ty::Uint(_) | ty::Char => { - let start = self.lower_const_arg(start, FeedConstTy::No); - let end = self.lower_const_arg(end, FeedConstTy::No); + let start = self.lower_const_arg(start, ty); + let end = self.lower_const_arg(end, ty); Ok(ty::PatternKind::Range { start, end }) } _ => Err(self diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 7296ba6f964a4..a51355adf72fe 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -101,7 +101,7 @@ use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; pub use crate::collect::suggest_impl_trait; -use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer}; +use crate::hir_ty_lowering::HirTyLowerer; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -301,8 +301,8 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { pub fn lower_const_arg_for_rustdoc<'tcx>( tcx: TyCtxt<'tcx>, hir_ct: &hir::ConstArg<'tcx>, - feed: FeedConstTy<'tcx>, + ty: Ty<'tcx>, ) -> Const<'tcx> { let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id); - collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed) + collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, ty) } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 9d7e09b020a75..9f3ff0b2d03c2 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -21,7 +21,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, HirId, QPath, find_attr, is_range_literal}; use rustc_hir_analysis::NoVariantNamed; -use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _}; +use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin}; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; @@ -1749,7 +1749,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let count_span = count.span; let count = self.try_structurally_resolve_const( count_span, - self.normalize(count_span, self.lower_const_arg(count, FeedConstTy::No)), + self.normalize(count_span, self.lower_const_arg(count, tcx.types.usize)), ); if let Some(count) = count.try_to_target_usize(tcx) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index a66ff2a23c250..91f91d9114449 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -14,8 +14,8 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{ check_generic_arg_count_for_call, lower_generic_args, }; use rustc_hir_analysis::hir_ty_lowering::{ - ExplicitLateBound, FeedConstTy, GenericArgCountMismatch, GenericArgCountResult, - GenericArgsLowerer, GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, + ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer, + GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; @@ -525,9 +525,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn lower_const_arg( &self, const_arg: &'tcx hir::ConstArg<'tcx>, - feed: FeedConstTy<'tcx>, + ty: Ty<'tcx>, ) -> ty::Const<'tcx> { - let ct = self.lowerer().lower_const_arg(const_arg, feed); + let ct = self.lowerer().lower_const_arg(const_arg, ty); self.register_wf_obligation( ct.into(), self.tcx.hir_span(const_arg.hir_id), @@ -1228,7 +1228,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Ambiguous parts of `ConstArg` are handled in the match arms below .lower_const_arg( ct.as_unambig_ct(), - FeedConstTy::with_type_of(self.fcx.tcx, param.def_id, preceding_args), + self.fcx + .tcx + .type_of(param.def_id) + .instantiate(self.fcx.tcx, preceding_args), ) .into(), (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index aab4e39855557..270f011b2b15f 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -7,7 +7,7 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{ check_generic_arg_count_for_call, lower_generic_args, }; use rustc_hir_analysis::hir_ty_lowering::{ - FeedConstTy, GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason, + GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::{ BoundRegionConversionTime, DefineOpaqueTypes, InferOk, RegionVariableOrigin, @@ -447,7 +447,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // We handle the ambig portions of `ConstArg` in the match arms below .lower_const_arg( ct.as_unambig_ct(), - FeedConstTy::with_type_of(self.cfcx.tcx, param.def_id, preceding_args), + self.cfcx + .tcx + .type_of(param.def_id) + .instantiate(self.cfcx.tcx, preceding_args), ) .into(), (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 2c76c0fe3583c..ef6c9cc344cea 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -109,7 +109,31 @@ impl<'a> Parser<'a> { self.expect_keyword(exp!(Const))?; let ident = self.parse_ident()?; - self.expect(exp!(Colon))?; + if let Err(mut err) = self.expect(exp!(Colon)) { + return if self.token.kind == token::Comma || self.token.kind == token::Gt { + // Recover parse from `` where the type is missing. + let span = const_span.to(ident.span); + err.span_suggestion_verbose( + ident.span.shrink_to_hi(), + "you likely meant to write the type of the const parameter here", + ": /* Type */".to_string(), + Applicability::HasPlaceholders, + ); + let kind = TyKind::Err(err.emit()); + let ty = self.mk_ty(span, kind); + Ok(GenericParam { + ident, + id: ast::DUMMY_NODE_ID, + attrs: preceding_attrs, + bounds: Vec::new(), + kind: GenericParamKind::Const { ty, span, default: None }, + is_placeholder: false, + colon_span: None, + }) + } else { + Err(err) + }; + } let ty = self.parse_ty()?; // Parse optional const generics default value. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index cdcdaa342a5d0..bc76418429aac 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -408,6 +408,7 @@ impl<'a> Parser<'a> { let insert_span = ident_span.shrink_to_lo(); let ident = if self.token.is_ident() + && self.token.is_non_reserved_ident() && (!is_const || self.look_ahead(1, |t| *t == token::OpenParen)) && self.look_ahead(1, |t| { matches!(t.kind, token::Lt | token::OpenBrace | token::OpenParen) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index b80011e8c0cb7..9f13ba1201f7a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -212,12 +212,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut self, ident: Ident, ns: Namespace, - new_binding: Decl<'ra>, old_binding: Decl<'ra>, + new_binding: Decl<'ra>, ) { // Error on the second of two conflicting names if old_binding.span.lo() > new_binding.span.lo() { - return self.report_conflict(ident, ns, old_binding, new_binding); + return self.report_conflict(ident, ns, new_binding, old_binding); } let container = match old_binding.parent_module.unwrap().kind { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index e525abd00f998..451779ae32c6b 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -300,13 +300,16 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra if let DeclKind::Import { import: import1, source_decl: d1_next } = d1.kind && let DeclKind::Import { import: import2, source_decl: d2_next } = d2.kind && import1 == import2 - && d1.warn_ambiguity.get() == d2.warn_ambiguity.get() { - assert_eq!(d1.ambiguity.get(), d2.ambiguity.get()); - assert!(!d1.warn_ambiguity.get()); assert_eq!(d1.expansion, d2.expansion); assert_eq!(d1.span, d2.span); - assert_eq!(d1.vis(), d2.vis()); + if d1.ambiguity.get() != d2.ambiguity.get() { + assert!(d1.ambiguity.get().is_some()); + assert!(d2.ambiguity.get().is_none()); + } + // Visibility of the new import declaration may be different, + // because it already incorporates the visibility of the source binding. + // `warn_ambiguity` of a re-fetched glob can also change in both directions. remove_same_import(d1_next, d2_next) } else { (d1, d2) @@ -348,8 +351,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// decide which one to keep. fn select_glob_decl( &self, - glob_decl: Decl<'ra>, old_glob_decl: Decl<'ra>, + glob_decl: Decl<'ra>, warn_ambiguity: bool, ) -> Decl<'ra> { assert!(glob_decl.is_glob_import()); @@ -369,7 +372,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // with the re-fetched decls. // This is probably incorrect in corner cases, and the outdated decls still get // propagated to other places and get stuck there, but that's what we have at the moment. - let (deep_decl, old_deep_decl) = remove_same_import(glob_decl, old_glob_decl); + let (old_deep_decl, deep_decl) = remove_same_import(old_glob_decl, glob_decl); if deep_decl != glob_decl { // Some import layers have been removed, need to overwrite. assert_ne!(old_deep_decl, old_glob_decl); @@ -377,6 +380,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // assert_ne!(old_deep_decl, deep_decl); // assert!(old_deep_decl.is_glob_import()); assert!(!deep_decl.is_glob_import()); + if old_glob_decl.ambiguity.get().is_some() && glob_decl.ambiguity.get().is_none() { + // Do not lose glob ambiguities when re-fetching the glob. + glob_decl.ambiguity.set_unchecked(old_glob_decl.ambiguity.get()); + } if glob_decl.is_ambiguity_recursive() { glob_decl.warn_ambiguity.set_unchecked(true); } @@ -436,7 +443,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match (old_decl.is_glob_import(), decl.is_glob_import()) { (true, true) => { resolution.glob_decl = - Some(this.select_glob_decl(decl, old_decl, warn_ambiguity)); + Some(this.select_glob_decl(old_decl, decl, warn_ambiguity)); } (old_glob @ true, false) | (old_glob @ false, true) => { let (glob_decl, non_glob_decl) = @@ -446,7 +453,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && old_glob_decl != glob_decl { resolution.glob_decl = - Some(this.select_glob_decl(glob_decl, old_glob_decl, false)); + Some(this.select_glob_decl(old_glob_decl, glob_decl, false)); } else { resolution.glob_decl = Some(glob_decl); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 34804160ed398..4080c1cd59ec7 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1725,7 +1725,6 @@ symbols! { postfix_match, powerpc, powerpc64, - powerpc64le, powerpc_target_feature, powf16, powf32, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 0078866ab9503..a10699bbce884 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -261,7 +261,7 @@ impl InlineAsmArch { Arch::Mips | Arch::Mips32r6 => Some(Self::Mips), Arch::Mips64 | Arch::Mips64r6 => Some(Self::Mips64), Arch::PowerPC => Some(Self::PowerPC), - Arch::PowerPC64 | Arch::PowerPC64LE => Some(Self::PowerPC64), + Arch::PowerPC64 => Some(Self::PowerPC64), Arch::S390x => Some(Self::S390x), Arch::Sparc => Some(Self::Sparc), Arch::Sparc64 => Some(Self::Sparc64), diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 6faa57252ca2a..6c8e0e181c4a4 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -702,7 +702,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { Arch::RiscV32 | Arch::RiscV64 => riscv::compute_abi_info(cx, self), Arch::Wasm32 | Arch::Wasm64 => wasm::compute_abi_info(cx, self), Arch::Bpf => bpf::compute_abi_info(cx, self), - arch @ (Arch::PowerPC64LE | Arch::SpirV | Arch::Other(_)) => { + arch @ (Arch::SpirV | Arch::Other(_)) => { panic!("no lowering implemented for {arch}") } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index ab52a7d63301a..8650ec00100bd 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1873,7 +1873,6 @@ crate::target_spec_enum! { Nvptx64 = "nvptx64", PowerPC = "powerpc", PowerPC64 = "powerpc64", - PowerPC64LE = "powerpc64le", RiscV32 = "riscv32", RiscV64 = "riscv64", S390x = "s390x", @@ -1911,7 +1910,6 @@ impl Arch { Self::Nvptx64 => sym::nvptx64, Self::PowerPC => sym::powerpc, Self::PowerPC64 => sym::powerpc64, - Self::PowerPC64LE => sym::powerpc64le, Self::RiscV32 => sym::riscv32, Self::RiscV64 => sym::riscv64, Self::S390x => sym::s390x, @@ -1940,8 +1938,8 @@ impl Arch { AArch64 | AmdGpu | Arm | Arm64EC | Avr | CSky | Hexagon | LoongArch32 | LoongArch64 | M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC - | PowerPC64 | PowerPC64LE | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 - | Wasm64 | X86 | X86_64 | Xtensa => true, + | PowerPC64 | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 | Wasm64 | X86 + | X86_64 | Xtensa => true, } } } @@ -3445,7 +3443,6 @@ impl Target { Arch::Arm64EC => (Architecture::Aarch64, Some(object::SubArchitecture::Arm64EC)), Arch::AmdGpu | Arch::Nvptx64 - | Arch::PowerPC64LE | Arch::SpirV | Arch::Wasm32 | Arch::Wasm64 diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 40cc4f40a3336..4eba426dda59f 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -986,7 +986,6 @@ impl Target { Arch::AmdGpu | Arch::Avr | Arch::Msp430 - | Arch::PowerPC64LE | Arch::SpirV | Arch::Xtensa | Arch::Other(_) => &[], @@ -1015,12 +1014,7 @@ impl Target { Arch::CSky => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, // FIXME: for some tier3 targets, we are overly cautious and always give warnings // when passing args in vector registers. - Arch::Avr - | Arch::Msp430 - | Arch::PowerPC64LE - | Arch::SpirV - | Arch::Xtensa - | Arch::Other(_) => &[], + Arch::Avr | Arch::Msp430 | Arch::SpirV | Arch::Xtensa | Arch::Other(_) => &[], } } diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index 82e2e0456e649..6f23c28c04d6a 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -44,6 +44,15 @@ impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn new(stack: usize, init: Box) -> io::Result { + // FIXME: remove this block once wasi-sdk is updated with the fix from + // https://github.com/WebAssembly/wasi-libc/pull/716 + // WASI does not support threading via pthreads. While wasi-libc provides + // pthread stubs, pthread_create returns EAGAIN, which causes confusing + // errors. We return UNSUPPORTED_PLATFORM directly instead. + if cfg!(target_os = "wasi") { + return Err(io::Error::UNSUPPORTED_PLATFORM); + } + let data = init; let mut attr: mem::MaybeUninit = mem::MaybeUninit::uninit(); assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0); diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index e1725db60cfca..e66c0576e9ee5 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -6,7 +6,7 @@ build = "build.rs" default-run = "bootstrap" [features] -build-metrics = ["sysinfo"] +build-metrics = ["dep:sysinfo", "build_helper/metrics"] tracing = ["dep:tracing", "dep:tracing-chrome", "dep:tracing-subscriber", "dep:chrono", "dep:tempfile"] [lib] diff --git a/src/build_helper/Cargo.toml b/src/build_helper/Cargo.toml index 66894e1abc40e..2ec44fe2730b9 100644 --- a/src/build_helper/Cargo.toml +++ b/src/build_helper/Cargo.toml @@ -6,5 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = "1" -serde_derive = "1" +serde = { version = "1", optional = true } +serde_derive = { version = "1", optional = true } + +[features] +metrics = ["dep:serde", "dep:serde_derive"] diff --git a/src/build_helper/src/lib.rs b/src/build_helper/src/lib.rs index 266eedc624582..e23a158ac0598 100644 --- a/src/build_helper/src/lib.rs +++ b/src/build_helper/src/lib.rs @@ -4,6 +4,7 @@ pub mod ci; pub mod drop_bomb; pub mod fs; pub mod git; +#[cfg(feature = "metrics")] pub mod metrics; pub mod npm; pub mod stage0_parser; diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml index 468d8c8a02aa7..539edf60033a5 100644 --- a/src/ci/citool/Cargo.toml +++ b/src/ci/citool/Cargo.toml @@ -15,7 +15,7 @@ serde_yaml = "0.9" serde_json = "1" ureq = { version = "3", features = ["json"] } -build_helper = { path = "../../build_helper" } +build_helper = { path = "../../build_helper", features = ["metrics"] } [dev-dependencies] insta = "1" diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 597a85f397695..0ad9d2fdbe804 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -43,7 +43,6 @@ use rustc_hir::attrs::{AttributeKind, DocAttribute, DocInline}; use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId}; use rustc_hir::{LangItem, PredicateOrigin, find_attr}; -use rustc_hir_analysis::hir_ty_lowering::FeedConstTy; use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty}; use rustc_middle::metadata::Reexport; use rustc_middle::middle::resolve_bound_vars as rbv; @@ -469,11 +468,17 @@ fn clean_middle_term<'tcx>( } } -fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term { +fn clean_hir_term<'tcx>( + assoc_item: Option, + term: &hir::Term<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Term { match term { hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)), hir::Term::Const(c) => { - let ct = lower_const_arg_for_rustdoc(cx.tcx, c, FeedConstTy::No); + // FIXME(generic_const_items): this should instantiate with the alias item's args + let ty = cx.tcx.type_of(assoc_item.unwrap()).instantiate_identity(); + let ct = lower_const_arg_for_rustdoc(cx.tcx, c, ty); Term::Constant(clean_middle_const(ty::Binder::dummy(ct), cx)) } } @@ -650,7 +655,9 @@ fn clean_generic_param<'tcx>( GenericParamDefKind::Const { ty: Box::new(clean_ty(ty, cx)), default: default.map(|ct| { - Box::new(lower_const_arg_for_rustdoc(cx.tcx, ct, FeedConstTy::No).to_string()) + Box::new( + lower_const_arg_for_rustdoc(cx.tcx, ct, lower_ty(cx.tcx, ty)).to_string(), + ) }), }, ), @@ -1531,7 +1538,7 @@ fn first_non_private_clean_path<'tcx>( && path_last.args.is_some() { assert!(new_path_last.args.is_empty()); - new_path_last.args = clean_generic_args(path_last_args, cx); + new_path_last.args = clean_generic_args(None, path_last_args, cx); } new_clean_path } @@ -1812,7 +1819,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T let length = match const_arg.kind { hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => "_".to_string(), hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) => { - let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); + let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, cx.tcx.types.usize); let typing_env = ty::TypingEnv::post_analysis(cx.tcx, *def_id); let ct = cx.tcx.normalize_erasing_regions(typing_env, ct); print_const(cx, ct) @@ -1823,7 +1830,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T | hir::ConstArgKind::Tup(..) | hir::ConstArgKind::Array(..) | hir::ConstArgKind::Literal(..) => { - let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); + let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, cx.tcx.types.usize); print_const(cx, ct) } }; @@ -2516,6 +2523,7 @@ fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path { } fn clean_generic_args<'tcx>( + trait_did: Option, generic_args: &hir::GenericArgs<'tcx>, cx: &mut DocContext<'tcx>, ) -> GenericArgs { @@ -2539,7 +2547,13 @@ fn clean_generic_args<'tcx>( let constraints = generic_args .constraints .iter() - .map(|c| clean_assoc_item_constraint(c, cx)) + .map(|c| { + clean_assoc_item_constraint( + trait_did.expect("only trait ref has constraints"), + c, + cx, + ) + }) .collect::>(); GenericArgs::AngleBracketed { args, constraints } } @@ -2562,7 +2576,11 @@ fn clean_path_segment<'tcx>( path: &hir::PathSegment<'tcx>, cx: &mut DocContext<'tcx>, ) -> PathSegment { - PathSegment { name: path.ident.name, args: clean_generic_args(path.args(), cx) } + let trait_did = match path.res { + hir::def::Res::Def(DefKind::Trait | DefKind::TraitAlias, did) => Some(did), + _ => None, + }; + PathSegment { name: path.ident.name, args: clean_generic_args(trait_did, path.args(), cx) } } fn clean_bare_fn_ty<'tcx>( @@ -3126,17 +3144,27 @@ fn clean_maybe_renamed_foreign_item<'tcx>( } fn clean_assoc_item_constraint<'tcx>( + trait_did: DefId, constraint: &hir::AssocItemConstraint<'tcx>, cx: &mut DocContext<'tcx>, ) -> AssocItemConstraint { AssocItemConstraint { assoc: PathSegment { name: constraint.ident.name, - args: clean_generic_args(constraint.gen_args, cx), + args: clean_generic_args(None, constraint.gen_args, cx), }, kind: match constraint.kind { hir::AssocItemConstraintKind::Equality { ref term } => { - AssocItemConstraintKind::Equality { term: clean_hir_term(term, cx) } + let assoc_tag = match term { + hir::Term::Ty(_) => ty::AssocTag::Type, + hir::Term::Const(_) => ty::AssocTag::Const, + }; + let assoc_item = cx + .tcx + .associated_items(trait_did) + .find_by_ident_and_kind(cx.tcx, constraint.ident, assoc_tag, trait_did) + .map(|item| item.def_id); + AssocItemConstraintKind::Equality { term: clean_hir_term(assoc_item, term, cx) } } hir::AssocItemConstraintKind::Bound { bounds } => AssocItemConstraintKind::Bound { bounds: bounds.iter().filter_map(|b| clean_generic_bound(b, cx)).collect(), diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 07d6efaa97e15..debea4fc0cec6 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -309,24 +309,27 @@ impl<'tcx> LinkCollector<'_, 'tcx> { let ty_res = self.resolve_path(path, TypeNS, item_id, module_id).ok_or_else(no_res)?; match ty_res { - Res::Def(DefKind::Enum, did) => match tcx.type_of(did).instantiate_identity().kind() { - ty::Adt(def, _) if def.is_enum() => { - if let Some(variant) = def.variants().iter().find(|v| v.name == variant_name) - && let Some(field) = - variant.fields.iter().find(|f| f.name == variant_field_name) - { - Ok((ty_res, field.did)) - } else { - Err(UnresolvedPath { - item_id, - module_id, - partial_res: Some(Res::Def(DefKind::Enum, def.did())), - unresolved: variant_field_name.to_string().into(), - }) + Res::Def(DefKind::Enum | DefKind::TyAlias, did) => { + match tcx.type_of(did).instantiate_identity().kind() { + ty::Adt(def, _) if def.is_enum() => { + if let Some(variant) = + def.variants().iter().find(|v| v.name == variant_name) + && let Some(field) = + variant.fields.iter().find(|f| f.name == variant_field_name) + { + Ok((ty_res, field.did)) + } else { + Err(UnresolvedPath { + item_id, + module_id, + partial_res: Some(Res::Def(DefKind::Enum, def.did())), + unresolved: variant_field_name.to_string().into(), + }) + } } + _ => unreachable!(), } - _ => unreachable!(), - }, + } _ => Err(UnresolvedPath { item_id, module_id, @@ -336,58 +339,6 @@ impl<'tcx> LinkCollector<'_, 'tcx> { } } - /// Given a primitive type, try to resolve an associated item. - fn resolve_primitive_associated_item( - &self, - prim_ty: PrimitiveType, - ns: Namespace, - item_name: Symbol, - ) -> Vec<(Res, DefId)> { - let tcx = self.cx.tcx; - - prim_ty - .impls(tcx) - .flat_map(|impl_| { - filter_assoc_items_by_name_and_namespace( - tcx, - impl_, - Ident::with_dummy_span(item_name), - ns, - ) - .map(|item| (Res::Primitive(prim_ty), item.def_id)) - }) - .collect::>() - } - - fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: DefId) -> Option { - if ns != TypeNS || path_str != "Self" { - return None; - } - - let tcx = self.cx.tcx; - let self_id = match tcx.def_kind(item_id) { - def_kind @ (DefKind::AssocFn - | DefKind::AssocConst - | DefKind::AssocTy - | DefKind::Variant - | DefKind::Field) => { - let parent_def_id = tcx.parent(item_id); - if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant { - tcx.parent(parent_def_id) - } else { - parent_def_id - } - } - _ => item_id, - }; - - match tcx.def_kind(self_id) { - DefKind::Impl { .. } => self.def_id_to_res(self_id), - DefKind::Use => None, - def_kind => Some(Res::Def(def_kind, self_id)), - } - } - /// Convenience wrapper around `doc_link_resolutions`. /// /// This also handles resolving `true` and `false` as booleans. @@ -400,7 +351,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> { item_id: DefId, module_id: DefId, ) -> Option { - if let res @ Some(..) = self.resolve_self_ty(path_str, ns, item_id) { + if let res @ Some(..) = resolve_self_ty(self.cx.tcx, path_str, ns, item_id) { return res; } @@ -430,13 +381,15 @@ impl<'tcx> LinkCollector<'_, 'tcx> { /// Resolves a string as a path within a particular namespace. Returns an /// optional URL fragment in the case of variants and methods. fn resolve<'path>( - &mut self, + &self, path_str: &'path str, ns: Namespace, disambiguator: Option, item_id: DefId, module_id: DefId, ) -> Result)>, UnresolvedPath<'path>> { + let tcx = self.cx.tcx; + if let Some(res) = self.resolve_path(path_str, ns, item_id, module_id) { return Ok(match res { Res::Def( @@ -482,7 +435,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> { match resolve_primitive(path_root, TypeNS) .or_else(|| self.resolve_path(path_root, TypeNS, item_id, module_id)) .map(|ty_res| { - self.resolve_associated_item(ty_res, item_name, ns, disambiguator, module_id) + resolve_associated_item(tcx, ty_res, item_name, ns, disambiguator, module_id) .into_iter() .map(|(res, def_id)| (res, Some(def_id))) .collect::>() @@ -503,233 +456,310 @@ impl<'tcx> LinkCollector<'_, 'tcx> { } } } +} - /// Convert a DefId to a Res, where possible. - /// - /// This is used for resolving type aliases. - fn def_id_to_res(&self, ty_id: DefId) -> Option { - use PrimitiveType::*; - Some(match *self.cx.tcx.type_of(ty_id).instantiate_identity().kind() { - ty::Bool => Res::Primitive(Bool), - ty::Char => Res::Primitive(Char), - ty::Int(ity) => Res::Primitive(ity.into()), - ty::Uint(uty) => Res::Primitive(uty.into()), - ty::Float(fty) => Res::Primitive(fty.into()), - ty::Str => Res::Primitive(Str), - ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit), - ty::Tuple(_) => Res::Primitive(Tuple), - ty::Pat(..) => Res::Primitive(Pat), - ty::Array(..) => Res::Primitive(Array), - ty::Slice(_) => Res::Primitive(Slice), - ty::RawPtr(_, _) => Res::Primitive(RawPointer), - ty::Ref(..) => Res::Primitive(Reference), - ty::FnDef(..) => panic!("type alias to a function definition"), - ty::FnPtr(..) => Res::Primitive(Fn), - ty::Never => Res::Primitive(Never), - ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did, .. }, _)), _) | ty::Foreign(did) => { - Res::from_def_id(self.cx.tcx, did) - } - ty::Alias(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Dynamic(..) - | ty::UnsafeBinder(_) - | ty::Param(_) - | ty::Bound(..) - | ty::Placeholder(_) - | ty::Infer(_) - | ty::Error(_) => return None, +fn full_res(tcx: TyCtxt<'_>, (base, assoc_item): (Res, Option)) -> Res { + assoc_item.map_or(base, |def_id| Res::from_def_id(tcx, def_id)) +} + +/// Given a primitive type, try to resolve an associated item. +fn resolve_primitive_inherent_assoc_item<'tcx>( + tcx: TyCtxt<'tcx>, + prim_ty: PrimitiveType, + ns: Namespace, + item_ident: Ident, +) -> Vec<(Res, DefId)> { + prim_ty + .impls(tcx) + .flat_map(|impl_| { + filter_assoc_items_by_name_and_namespace(tcx, impl_, item_ident, ns) + .map(|item| (Res::Primitive(prim_ty), item.def_id)) }) + .collect::>() +} + +fn resolve_self_ty<'tcx>( + tcx: TyCtxt<'tcx>, + path_str: &str, + ns: Namespace, + item_id: DefId, +) -> Option { + if ns != TypeNS || path_str != "Self" { + return None; } - /// Convert a PrimitiveType to a Ty, where possible. - /// - /// This is used for resolving trait impls for primitives - fn primitive_type_to_ty(&mut self, prim: PrimitiveType) -> Option> { - use PrimitiveType::*; - let tcx = self.cx.tcx; + let self_id = match tcx.def_kind(item_id) { + def_kind @ (DefKind::AssocFn + | DefKind::AssocConst + | DefKind::AssocTy + | DefKind::Variant + | DefKind::Field) => { + let parent_def_id = tcx.parent(item_id); + if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant { + tcx.parent(parent_def_id) + } else { + parent_def_id + } + } + _ => item_id, + }; - // FIXME: Only simple types are supported here, see if we can support - // other types such as Tuple, Array, Slice, etc. - // See https://github.com/rust-lang/rust/issues/90703#issuecomment-1004263455 - Some(match prim { - Bool => tcx.types.bool, - Str => tcx.types.str_, - Char => tcx.types.char, - Never => tcx.types.never, - I8 => tcx.types.i8, - I16 => tcx.types.i16, - I32 => tcx.types.i32, - I64 => tcx.types.i64, - I128 => tcx.types.i128, - Isize => tcx.types.isize, - F16 => tcx.types.f16, - F32 => tcx.types.f32, - F64 => tcx.types.f64, - F128 => tcx.types.f128, - U8 => tcx.types.u8, - U16 => tcx.types.u16, - U32 => tcx.types.u32, - U64 => tcx.types.u64, - U128 => tcx.types.u128, - Usize => tcx.types.usize, - _ => return None, - }) + match tcx.def_kind(self_id) { + DefKind::Impl { .. } => ty_to_res(tcx, tcx.type_of(self_id).instantiate_identity()), + DefKind::Use => None, + def_kind => Some(Res::Def(def_kind, self_id)), } +} - /// Resolve an associated item, returning its containing page's `Res` - /// and the fragment targeting the associated item on its page. - fn resolve_associated_item( - &mut self, - root_res: Res, - item_name: Symbol, - ns: Namespace, - disambiguator: Option, - module_id: DefId, - ) -> Vec<(Res, DefId)> { - let tcx = self.cx.tcx; +/// Convert a Ty to a Res, where possible. +/// +/// This is used for resolving type aliases. +fn ty_to_res<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { + use PrimitiveType::*; + Some(match *ty.kind() { + ty::Bool => Res::Primitive(Bool), + ty::Char => Res::Primitive(Char), + ty::Int(ity) => Res::Primitive(ity.into()), + ty::Uint(uty) => Res::Primitive(uty.into()), + ty::Float(fty) => Res::Primitive(fty.into()), + ty::Str => Res::Primitive(Str), + ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit), + ty::Tuple(_) => Res::Primitive(Tuple), + ty::Pat(..) => Res::Primitive(Pat), + ty::Array(..) => Res::Primitive(Array), + ty::Slice(_) => Res::Primitive(Slice), + ty::RawPtr(_, _) => Res::Primitive(RawPointer), + ty::Ref(..) => Res::Primitive(Reference), + ty::FnDef(..) => panic!("type alias to a function definition"), + ty::FnPtr(..) => Res::Primitive(Fn), + ty::Never => Res::Primitive(Never), + ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did, .. }, _)), _) | ty::Foreign(did) => { + Res::from_def_id(tcx, did) + } + ty::Alias(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Dynamic(..) + | ty::UnsafeBinder(_) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(_) + | ty::Error(_) => return None, + }) +} - match root_res { - Res::Primitive(prim) => { - let items = self.resolve_primitive_associated_item(prim, ns, item_name); - if !items.is_empty() { - items - // Inherent associated items take precedence over items that come from trait impls. - } else { - self.primitive_type_to_ty(prim) - .map(|ty| { - resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx) - .iter() - .map(|item| (root_res, item.def_id)) - .collect::>() - }) - .unwrap_or_default() - } - } - Res::Def(DefKind::TyAlias, did) => { - // Resolve the link on the type the alias points to. - // FIXME: if the associated item is defined directly on the type alias, - // it will show up on its documentation page, we should link there instead. - let Some(res) = self.def_id_to_res(did) else { return Vec::new() }; - self.resolve_associated_item(res, item_name, ns, disambiguator, module_id) - } - Res::Def( - def_kind @ (DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy), - did, - ) => { - debug!("looking for associated item named {item_name} for item {did:?}"); - // Checks if item_name is a variant of the `SomeItem` enum - if ns == TypeNS && def_kind == DefKind::Enum { - match tcx.type_of(did).instantiate_identity().kind() { - ty::Adt(adt_def, _) => { - for variant in adt_def.variants() { - if variant.name == item_name { - return vec![(root_res, variant.def_id)]; - } - } - } - _ => unreachable!(), - } - } +/// Convert a PrimitiveType to a Ty, where possible. +/// +/// This is used for resolving trait impls for primitives +fn primitive_type_to_ty<'tcx>(tcx: TyCtxt<'tcx>, prim: PrimitiveType) -> Option> { + use PrimitiveType::*; - let search_for_field = || { - let (DefKind::Struct | DefKind::Union) = def_kind else { return vec![] }; - debug!("looking for fields named {item_name} for {did:?}"); - // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?) - // NOTE: it's different from variant_field because it only resolves struct fields, - // not variant fields (2 path segments, not 3). - // - // We need to handle struct (and union) fields in this code because - // syntactically their paths are identical to associated item paths: - // `module::Type::field` and `module::Type::Assoc`. - // - // On the other hand, variant fields can't be mistaken for associated - // items because they look like this: `module::Type::Variant::field`. - // - // Variants themselves don't need to be handled here, even though - // they also look like associated items (`module::Type::Variant`), - // because they are real Rust syntax (unlike the intra-doc links - // field syntax) and are handled by the compiler's resolver. - let ty::Adt(def, _) = tcx.type_of(did).instantiate_identity().kind() else { - unreachable!() - }; - def.non_enum_variant() - .fields - .iter() - .filter(|field| field.name == item_name) - .map(|field| (root_res, field.did)) - .collect::>() - }; + // FIXME: Only simple types are supported here, see if we can support + // other types such as Tuple, Array, Slice, etc. + // See https://github.com/rust-lang/rust/issues/90703#issuecomment-1004263455 + Some(match prim { + Bool => tcx.types.bool, + Str => tcx.types.str_, + Char => tcx.types.char, + Never => tcx.types.never, + I8 => tcx.types.i8, + I16 => tcx.types.i16, + I32 => tcx.types.i32, + I64 => tcx.types.i64, + I128 => tcx.types.i128, + Isize => tcx.types.isize, + F16 => tcx.types.f16, + F32 => tcx.types.f32, + F64 => tcx.types.f64, + F128 => tcx.types.f128, + U8 => tcx.types.u8, + U16 => tcx.types.u16, + U32 => tcx.types.u32, + U64 => tcx.types.u64, + U128 => tcx.types.u128, + Usize => tcx.types.usize, + _ => return None, + }) +} - if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator { - return search_for_field(); - } +/// Resolve an associated item, returning its containing page's `Res` +/// and the fragment targeting the associated item on its page. +fn resolve_associated_item<'tcx>( + tcx: TyCtxt<'tcx>, + root_res: Res, + item_name: Symbol, + ns: Namespace, + disambiguator: Option, + module_id: DefId, +) -> Vec<(Res, DefId)> { + let item_ident = Ident::with_dummy_span(item_name); + + match root_res { + Res::Def(DefKind::TyAlias, alias_did) => { + // Resolve the link on the type the alias points to. + // FIXME: if the associated item is defined directly on the type alias, + // it will show up on its documentation page, we should link there instead. + let Some(aliased_res) = ty_to_res(tcx, tcx.type_of(alias_did).instantiate_identity()) + else { + return vec![]; + }; + let aliased_items = + resolve_associated_item(tcx, aliased_res, item_name, ns, disambiguator, module_id); + aliased_items + .into_iter() + .map(|(res, assoc_did)| { + if is_assoc_item_on_alias_page(tcx, assoc_did) { + (root_res, assoc_did) + } else { + (res, assoc_did) + } + }) + .collect() + } + Res::Primitive(prim) => resolve_assoc_on_primitive(tcx, prim, ns, item_ident, module_id), + Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, did) => { + resolve_assoc_on_adt(tcx, did, item_ident, ns, disambiguator, module_id) + } + Res::Def(DefKind::ForeignTy, did) => { + resolve_assoc_on_simple_type(tcx, did, item_ident, ns, module_id) + } + Res::Def(DefKind::Trait, did) => filter_assoc_items_by_name_and_namespace( + tcx, + did, + Ident::with_dummy_span(item_name), + ns, + ) + .map(|item| (root_res, item.def_id)) + .collect::>(), + _ => Vec::new(), + } +} - // Checks if item_name belongs to `impl SomeItem` - let mut assoc_items: Vec<_> = tcx - .inherent_impls(did) +// FIXME: make this fully complete by also including ALL inherent impls +// and trait impls BUT ONLY if on alias directly +fn is_assoc_item_on_alias_page<'tcx>(tcx: TyCtxt<'tcx>, assoc_did: DefId) -> bool { + match tcx.def_kind(assoc_did) { + // Variants and fields always have docs on the alias page. + DefKind::Variant | DefKind::Field => true, + _ => false, + } +} + +fn resolve_assoc_on_primitive<'tcx>( + tcx: TyCtxt<'tcx>, + prim: PrimitiveType, + ns: Namespace, + item_ident: Ident, + module_id: DefId, +) -> Vec<(Res, DefId)> { + let root_res = Res::Primitive(prim); + let items = resolve_primitive_inherent_assoc_item(tcx, prim, ns, item_ident); + if !items.is_empty() { + items + // Inherent associated items take precedence over items that come from trait impls. + } else { + primitive_type_to_ty(tcx, prim) + .map(|ty| { + resolve_associated_trait_item(ty, module_id, item_ident, ns, tcx) .iter() - .flat_map(|&imp| { - filter_assoc_items_by_name_and_namespace( - tcx, - imp, - Ident::with_dummy_span(item_name), - ns, - ) - }) .map(|item| (root_res, item.def_id)) - .collect(); - - if assoc_items.is_empty() { - // Check if item_name belongs to `impl SomeTrait for SomeItem` - // FIXME(#74563): This gives precedence to `impl SomeItem`: - // Although having both would be ambiguous, use impl version for compatibility's sake. - // To handle that properly resolve() would have to support - // something like [`ambi_fn`](::ambi_fn) - assoc_items = resolve_associated_trait_item( - tcx.type_of(did).instantiate_identity(), - module_id, - item_name, - ns, - self.cx, - ) - .into_iter() - .map(|item| (root_res, item.def_id)) - .collect::>(); - } + .collect::>() + }) + .unwrap_or_default() + } +} - debug!("got associated item {assoc_items:?}"); +fn resolve_assoc_on_adt<'tcx>( + tcx: TyCtxt<'tcx>, + adt_def_id: DefId, + item_ident: Ident, + ns: Namespace, + disambiguator: Option, + module_id: DefId, +) -> Vec<(Res, DefId)> { + debug!("looking for associated item named {item_ident} for item {adt_def_id:?}"); + let root_res = Res::from_def_id(tcx, adt_def_id); + let adt_ty = tcx.type_of(adt_def_id).instantiate_identity(); + let adt_def = adt_ty.ty_adt_def().expect("must be ADT"); + // Checks if item_name is a variant of the `SomeItem` enum + if ns == TypeNS && adt_def.is_enum() { + for variant in adt_def.variants() { + if variant.name == item_ident.name { + return vec![(root_res, variant.def_id)]; + } + } + } - if !assoc_items.is_empty() { - return assoc_items; - } + if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator + && (adt_def.is_struct() || adt_def.is_union()) + { + return resolve_structfield(adt_def, item_ident.name) + .into_iter() + .map(|did| (root_res, did)) + .collect(); + } - if ns != Namespace::ValueNS { - return Vec::new(); - } + let assoc_items = resolve_assoc_on_simple_type(tcx, adt_def_id, item_ident, ns, module_id); + if !assoc_items.is_empty() { + return assoc_items; + } - search_for_field() - } - Res::Def(DefKind::Trait, did) => filter_assoc_items_by_name_and_namespace( - tcx, - did, - Ident::with_dummy_span(item_name), - ns, - ) - .map(|item| { - let res = Res::Def(item.as_def_kind(), item.def_id); - (res, item.def_id) - }) - .collect::>(), - _ => Vec::new(), - } + if ns == Namespace::ValueNS && (adt_def.is_struct() || adt_def.is_union()) { + return resolve_structfield(adt_def, item_ident.name) + .into_iter() + .map(|did| (root_res, did)) + .collect(); } + + vec![] } -fn full_res(tcx: TyCtxt<'_>, (base, assoc_item): (Res, Option)) -> Res { - assoc_item.map_or(base, |def_id| Res::from_def_id(tcx, def_id)) +/// "Simple" i.e. an ADT, foreign type, etc. -- not a type alias, primitive type, or other trickier type. +fn resolve_assoc_on_simple_type<'tcx>( + tcx: TyCtxt<'tcx>, + ty_def_id: DefId, + item_ident: Ident, + ns: Namespace, + module_id: DefId, +) -> Vec<(Res, DefId)> { + let root_res = Res::from_def_id(tcx, ty_def_id); + // Checks if item_name belongs to `impl SomeItem` + let inherent_assoc_items: Vec<_> = tcx + .inherent_impls(ty_def_id) + .iter() + .flat_map(|&imp| filter_assoc_items_by_name_and_namespace(tcx, imp, item_ident, ns)) + .map(|item| (root_res, item.def_id)) + .collect(); + debug!("got inherent assoc items {inherent_assoc_items:?}"); + if !inherent_assoc_items.is_empty() { + return inherent_assoc_items; + } + + // Check if item_name belongs to `impl SomeTrait for SomeItem` + // FIXME(#74563): This gives precedence to `impl SomeItem`: + // Although having both would be ambiguous, use impl version for compatibility's sake. + // To handle that properly resolve() would have to support + // something like [`ambi_fn`](::ambi_fn) + let ty = tcx.type_of(ty_def_id).instantiate_identity(); + let trait_assoc_items = resolve_associated_trait_item(ty, module_id, item_ident, ns, tcx) + .into_iter() + .map(|item| (root_res, item.def_id)) + .collect::>(); + debug!("got trait assoc items {trait_assoc_items:?}"); + trait_assoc_items +} + +fn resolve_structfield<'tcx>(adt_def: ty::AdtDef<'tcx>, item_name: Symbol) -> Option { + debug!("looking for fields named {item_name} for {adt_def:?}"); + adt_def + .non_enum_variant() + .fields + .iter() + .find(|field| field.name == item_name) + .map(|field| field.did) } /// Look to see if a resolved item has an associated item named `item_name`. @@ -737,12 +767,12 @@ fn full_res(tcx: TyCtxt<'_>, (base, assoc_item): (Res, Option)) -> Res { /// Given `[std::io::Error::source]`, where `source` is unresolved, this would /// find `std::error::Error::source` and return /// `::source`. -fn resolve_associated_trait_item<'a>( - ty: Ty<'a>, +fn resolve_associated_trait_item<'tcx>( + ty: Ty<'tcx>, module: DefId, - item_name: Symbol, + item_ident: Ident, ns: Namespace, - cx: &mut DocContext<'a>, + tcx: TyCtxt<'tcx>, ) -> Vec { // FIXME: this should also consider blanket impls (`impl X for T`). Unfortunately // `get_auto_trait_and_blanket_impls` is broken because the caching behavior is wrong. In the @@ -750,22 +780,17 @@ fn resolve_associated_trait_item<'a>( // Next consider explicit impls: `impl MyTrait for MyType` // Give precedence to inherent impls. - let traits = trait_impls_for(cx, ty, module); - let tcx = cx.tcx; + let traits = trait_impls_for(tcx, ty, module); debug!("considering traits {traits:?}"); let candidates = traits .iter() .flat_map(|&(impl_, trait_)| { - filter_assoc_items_by_name_and_namespace( - tcx, - trait_, - Ident::with_dummy_span(item_name), - ns, + filter_assoc_items_by_name_and_namespace(tcx, trait_, item_ident, ns).map( + move |trait_assoc| { + trait_assoc_to_impl_assoc_item(tcx, impl_, trait_assoc.def_id) + .unwrap_or(*trait_assoc) + }, ) - .map(move |trait_assoc| { - trait_assoc_to_impl_assoc_item(tcx, impl_, trait_assoc.def_id) - .unwrap_or(*trait_assoc) - }) }) .collect::>(); // FIXME(#74563): warn about ambiguity @@ -800,13 +825,12 @@ fn trait_assoc_to_impl_assoc_item<'tcx>( /// /// NOTE: this cannot be a query because more traits could be available when more crates are compiled! /// So it is not stable to serialize cross-crate. -#[instrument(level = "debug", skip(cx))] -fn trait_impls_for<'a>( - cx: &mut DocContext<'a>, - ty: Ty<'a>, +#[instrument(level = "debug", skip(tcx))] +fn trait_impls_for<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, module: DefId, ) -> FxIndexSet<(DefId, DefId)> { - let tcx = cx.tcx; let mut impls = FxIndexSet::default(); for &trait_ in tcx.doc_link_traits_in_scope(module) { @@ -1540,7 +1564,7 @@ impl LinkCollector<'_, '_> { } None => { // Try everything! - let mut candidate = |ns| { + let candidate = |ns| { self.resolve(path_str, ns, None, item_id, module_id) .map_err(ResolutionFailure::NotResolved) }; @@ -1926,7 +1950,7 @@ fn report_diagnostic( /// handled earlier. For example, if passed `Item::Crate(std)` and `path_str` /// `std::io::Error::x`, this will resolve `std::io::Error`. fn resolution_failure( - collector: &mut LinkCollector<'_, '_>, + collector: &LinkCollector<'_, '_>, diag_info: DiagnosticInfo<'_>, path_str: &str, disambiguator: Option, diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index 94649dde47361..b4d53c36d19b3 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -52,7 +52,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | Arch::Bpf | Arch::Msp430 | Arch::Nvptx64 - | Arch::PowerPC64LE | Arch::SpirV | Arch::Other(_)) => bug!("unsupported target architecture for malloc: `{arch}`"), }; diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index f4051ae67d7c0..66c19183f3433 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] -build_helper = { path = "../../build_helper" } +build_helper = { path = "../../build_helper", features = ["metrics"] } env_logger = "0.11" log = "0.4" anyhow = "1" diff --git a/tests/rustdoc-html/intra-doc/adt-through-alias.rs b/tests/rustdoc-html/intra-doc/adt-through-alias.rs new file mode 100644 index 0000000000000..6d5454bbaf200 --- /dev/null +++ b/tests/rustdoc-html/intra-doc/adt-through-alias.rs @@ -0,0 +1,71 @@ +#![crate_name = "foo"] + +//! [`TheStructAlias::the_field`] +//! [`TheEnumAlias::TheVariant`] +//! [`TheEnumAlias::TheVariant::the_field`] +//! [`TheUnionAlias::f1`] +//! +//! [`TheStruct::trait_`] +//! [`TheStructAlias::trait_`] +//! [`TheEnum::trait_`] +//! [`TheEnumAlias::trait_`] +//! +//! [`TheStruct::inherent`] +//! [`TheStructAlias::inherent`] +//! [`TheEnum::inherent`] +//! [`TheEnumAlias::inherent`] + +//@ has foo/index.html '//a[@href="type.TheStructAlias.html#structfield.the_field"]' 'TheStructAlias::the_field' +//@ has foo/index.html '//a[@href="type.TheEnumAlias.html#variant.TheVariant"]' 'TheEnumAlias::TheVariant' +//@ has foo/index.html '//a[@href="type.TheEnumAlias.html#variant.TheVariant.field.the_field"]' 'TheEnumAlias::TheVariant::the_field' +//@ has foo/index.html '//a[@href="type.TheUnionAlias.html#structfield.f1"]' 'TheUnionAlias::f1' + +//@ has foo/index.html '//a[@href="struct.TheStruct.html#method.trait_"]' 'TheStruct::trait_' +//@ has foo/index.html '//a[@href="struct.TheStruct.html#method.trait_"]' 'TheStructAlias::trait_' +//@ has foo/index.html '//a[@href="enum.TheEnum.html#method.trait_"]' 'TheEnum::trait_' +// FIXME: this one should resolve to alias since it's impl Trait for TheEnumAlias +//@ has foo/index.html '//a[@href="enum.TheEnum.html#method.trait_"]' 'TheEnumAlias::trait_' + +//@ has foo/index.html '//a[@href="struct.TheStruct.html#method.inherent"]' 'TheStruct::inherent' +// FIXME: this one should resolve to alias +//@ has foo/index.html '//a[@href="struct.TheStruct.html#method.inherent"]' 'TheStructAlias::inherent' +//@ has foo/index.html '//a[@href="enum.TheEnum.html#method.inherent"]' 'TheEnum::inherent' +// FIXME: this one should resolve to alias +//@ has foo/index.html '//a[@href="enum.TheEnum.html#method.inherent"]' 'TheEnumAlias::inherent' + +pub struct TheStruct { + pub the_field: i32, +} + +pub type TheStructAlias = TheStruct; + +pub enum TheEnum { + TheVariant { the_field: i32 }, +} + +pub type TheEnumAlias = TheEnum; + +pub trait Trait { + fn trait_() {} +} + +impl Trait for TheStruct {} + +impl Trait for TheEnumAlias {} + +impl TheStruct { + pub fn inherent() {} +} + +impl TheEnumAlias { + pub fn inherent() {} +} + +pub union TheUnion { + pub f1: usize, + pub f2: isize, +} + +pub type TheUnionAlias = TheUnion; + +fn main() {} diff --git a/tests/rustdoc-html/intra-doc/associated-items.rs b/tests/rustdoc-html/intra-doc/associated-items.rs index 84cfd06111df7..b3bed196aded0 100644 --- a/tests/rustdoc-html/intra-doc/associated-items.rs +++ b/tests/rustdoc-html/intra-doc/associated-items.rs @@ -13,7 +13,9 @@ pub fn foo() {} //@ has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from struct' //@ has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.clone"]' 'MyStruct::clone' //@ has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#associatedtype.Input"]' 'MyStruct::Input' -pub struct MyStruct { foo: () } +pub struct MyStruct { + foo: (), +} impl Clone for MyStruct { fn clone(&self) -> Self { @@ -31,8 +33,7 @@ impl T for MyStruct { /// [link from method][MyStruct::method] on method //@ has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from method' - fn method(i: usize) { - } + fn method(i: usize) {} } /// Ambiguity between which trait to use @@ -57,7 +58,7 @@ impl T2 for S { fn ambiguous_method() {} } -//@ has associated_items/enum.MyEnum.html '//a/@href' 'enum.MyEnum.html#variant.MyVariant' +//@ has associated_items/enum.MyEnum.html '//a/@href' 'type.MyEnumAlias.html#variant.MyVariant' /// Link to [MyEnumAlias::MyVariant] pub enum MyEnum { MyVariant, diff --git a/tests/ui/const-generics/associated-const-bindings/ambiguity.stderr b/tests/ui/const-generics/associated-const-bindings/ambiguity.stderr index a14afe9d6923b..806708f18d654 100644 --- a/tests/ui/const-generics/associated-const-bindings/ambiguity.stderr +++ b/tests/ui/const-generics/associated-const-bindings/ambiguity.stderr @@ -27,6 +27,12 @@ LL | const C: &'static str; ... LL | fn take1(_: impl Trait1) {} | ^^^^^^^ ambiguous associated constant `C` + | + = help: consider introducing a new type parameter `T` and adding `where` constraints: + where + T: Trait1, + T: Parent2::C = "?", + T: Parent1::C = "?" error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/incorrect-const-param.rs b/tests/ui/const-generics/incorrect-const-param.rs new file mode 100644 index 0000000000000..5f1d8ca2ae990 --- /dev/null +++ b/tests/ui/const-generics/incorrect-const-param.rs @@ -0,0 +1,45 @@ +// #84327 + +struct VecWrapper(Vec); + +// Correct +impl From<[T; N]> for VecWrapper +where + T: Clone, +{ + fn from(slice: [T; N]) -> Self { + VecWrapper(slice.to_vec()) + } +} + +// Forgot const +impl From<[T; N]> for VecWrapper //~ ERROR expected value, found type parameter `N` +where //~^ ERROR expected trait, found builtin type `usize` + T: Clone, +{ + fn from(slice: [T; N]) -> Self { //~ ERROR expected value, found type parameter `N` + VecWrapper(slice.to_vec()) + } +} + +// Forgot type +impl From<[T; N]> for VecWrapper //~ ERROR expected `:`, found `>` +where + T: Clone, +{ + fn from(slice: [T; N]) -> Self { + VecWrapper(slice.to_vec()) + } +} + +// Forgot const and type +impl From<[T; N]> for VecWrapper //~ ERROR expected value, found type parameter `N` +where + T: Clone, +{ + fn from(slice: [T; N]) -> Self { //~ ERROR expected value, found type parameter `N` + VecWrapper(slice.to_vec()) + } +} + +fn main() {} diff --git a/tests/ui/const-generics/incorrect-const-param.stderr b/tests/ui/const-generics/incorrect-const-param.stderr new file mode 100644 index 0000000000000..c5cf54500ee01 --- /dev/null +++ b/tests/ui/const-generics/incorrect-const-param.stderr @@ -0,0 +1,70 @@ +error: expected `:`, found `>` + --> $DIR/incorrect-const-param.rs:26:16 + | +LL | impl From<[T; N]> for VecWrapper + | ^ expected `:` + | +help: you likely meant to write the type of the const parameter here + | +LL | impl From<[T; N]> for VecWrapper + | ++++++++++++ + +error[E0423]: expected value, found type parameter `N` + --> $DIR/incorrect-const-param.rs:16:28 + | +LL | impl From<[T; N]> for VecWrapper + | - ^ not a value + | | + | found this type parameter + +error[E0404]: expected trait, found builtin type `usize` + --> $DIR/incorrect-const-param.rs:16:12 + | +LL | impl From<[T; N]> for VecWrapper + | ^^^^^ not a trait + | +help: you might have meant to write a const parameter here + | +LL | impl From<[T; N]> for VecWrapper + | +++++ + +error[E0423]: expected value, found type parameter `N` + --> $DIR/incorrect-const-param.rs:20:24 + | +LL | impl From<[T; N]> for VecWrapper + | - found this type parameter +... +LL | fn from(slice: [T; N]) -> Self { + | ^ not a value + +error[E0423]: expected value, found type parameter `N` + --> $DIR/incorrect-const-param.rs:36:21 + | +LL | impl From<[T; N]> for VecWrapper + | - ^ not a value + | | + | found this type parameter + | +help: you might have meant to write a const parameter here + | +LL | impl From<[T; N]> for VecWrapper + | +++++ ++++++++++++ + +error[E0423]: expected value, found type parameter `N` + --> $DIR/incorrect-const-param.rs:40:24 + | +LL | impl From<[T; N]> for VecWrapper + | - found this type parameter +... +LL | fn from(slice: [T; N]) -> Self { + | ^ not a value + | +help: you might have meant to write a const parameter here + | +LL | impl From<[T; N]> for VecWrapper + | +++++ ++++++++++++ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0404, E0423. +For more information about an error, try `rustc --explain E0404`. diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.rs b/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.rs new file mode 100644 index 0000000000000..4aecd30e86bbb --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.rs @@ -0,0 +1,8 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +struct Y { + stuff: [u8; { ([1, 2], 3, [4, 5]) }], //~ ERROR expected `usize`, found const tuple +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.stderr b/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.stderr new file mode 100644 index 0000000000000..468bf703d90d4 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.stderr @@ -0,0 +1,8 @@ +error: expected `usize`, found const tuple + --> $DIR/tuple_expr_arg_bad-issue-151048.rs:5:19 + | +LL | stuff: [u8; { ([1, 2], 3, [4, 5]) }], + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/error_statement_position.rs b/tests/ui/eii/error_statement_position.rs index cf81e7e6a8b23..75d87595b9e39 100644 --- a/tests/ui/eii/error_statement_position.rs +++ b/tests/ui/eii/error_statement_position.rs @@ -1,11 +1,6 @@ #![feature(extern_item_impls)] -// EIIs can, despite not being super useful, be declared in statement position -// nested inside items. Items in statement position, when expanded as part of a macro, -// need to be wrapped slightly differently (in an `ast::Statement`). -// We did this on the happy path (no errors), but when there was an error, we'd -// replace it with *just* an `ast::Item` not wrapped in an `ast::Statement`. -// This caused an ICE (https://github.com/rust-lang/rust/issues/149980). -// this test fails to build, but demonstrates that no ICE is produced. +// EIIs cannot be used in statement position. +// This is also a regression test for an ICE (https://github.com/rust-lang/rust/issues/149980). fn main() { struct Bar; @@ -13,4 +8,10 @@ fn main() { #[eii] //~^ ERROR `#[eii]` is only valid on functions impl Bar {} + + + // Even on functions, eiis in statement position are rejected + #[eii] + //~^ ERROR `#[eii]` can only be used on functions inside a module + fn foo() {} } diff --git a/tests/ui/eii/error_statement_position.stderr b/tests/ui/eii/error_statement_position.stderr index 01b7394ef00fa..f14e6c33e64f5 100644 --- a/tests/ui/eii/error_statement_position.stderr +++ b/tests/ui/eii/error_statement_position.stderr @@ -1,8 +1,17 @@ error: `#[eii]` is only valid on functions - --> $DIR/error_statement_position.rs:13:5 + --> $DIR/error_statement_position.rs:8:5 | LL | #[eii] | ^^^^^^ -error: aborting due to 1 previous error +error: `#[eii]` can only be used on functions inside a module + --> $DIR/error_statement_position.rs:14:5 + | +LL | #[eii] + | ^^^^^^ +LL | +LL | fn foo() {} + | --- `#[eii]` is used on this item, which is part of another item's local scope + +error: aborting due to 2 previous errors diff --git a/tests/ui/generics/wrong-number-of-args-in-macro.rs b/tests/ui/generics/wrong-number-of-args-in-macro.rs new file mode 100644 index 0000000000000..953e05434d25a --- /dev/null +++ b/tests/ui/generics/wrong-number-of-args-in-macro.rs @@ -0,0 +1,15 @@ +// Regression test for #149559 + +struct Foo; //~ ERROR type parameter `T` is never used + +macro_rules! foo_ty { + ($a:ty, $b:ty) => { + Foo + //~^ ERROR cannot find type `a` in this scope + //~| ERROR struct takes 1 generic argument but 2 generic arguments were supplied + }; +} + +fn foo<'a, 'b>() -> foo_ty!(&'b (), &'b ()) {} + +fn main() {} diff --git a/tests/ui/generics/wrong-number-of-args-in-macro.stderr b/tests/ui/generics/wrong-number-of-args-in-macro.stderr new file mode 100644 index 0000000000000..62a5eb9414ed5 --- /dev/null +++ b/tests/ui/generics/wrong-number-of-args-in-macro.stderr @@ -0,0 +1,44 @@ +error[E0425]: cannot find type `a` in this scope + --> $DIR/wrong-number-of-args-in-macro.rs:7:13 + | +LL | Foo + | ^ not found in this scope +... +LL | fn foo<'a, 'b>() -> foo_ty!(&'b (), &'b ()) {} + | ----------------------- in this macro invocation + | + = note: this error originates in the macro `foo_ty` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you might be missing a type parameter + | +LL | fn foo<'a, 'b, a>() -> foo_ty!(&'b (), &'b ()) {} + | +++ + +error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/wrong-number-of-args-in-macro.rs:7:9 + | +LL | Foo + | ^^^ expected 1 generic argument +... +LL | fn foo<'a, 'b>() -> foo_ty!(&'b (), &'b ()) {} + | ----------------------- in this macro invocation + | +note: struct defined here, with 1 generic parameter: `T` + --> $DIR/wrong-number-of-args-in-macro.rs:3:8 + | +LL | struct Foo; + | ^^^ - + = note: this error originates in the macro `foo_ty` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0392]: type parameter `T` is never used + --> $DIR/wrong-number-of-args-in-macro.rs:3:12 + | +LL | struct Foo; + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0392, E0425. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/hygiene/cross-crate-redefine.rs b/tests/ui/hygiene/cross-crate-redefine.rs index e42c5e3de0641..a87c933391d46 100644 --- a/tests/ui/hygiene/cross-crate-redefine.rs +++ b/tests/ui/hygiene/cross-crate-redefine.rs @@ -8,7 +8,7 @@ extern crate use_by_macro; use use_by_macro::*; my_struct!(define); -//~^ ERROR the name `MyStruct` is defined multiple times my_struct!(define); +//~^ ERROR the name `MyStruct` is defined multiple times fn main() {} diff --git a/tests/ui/hygiene/cross-crate-redefine.stderr b/tests/ui/hygiene/cross-crate-redefine.stderr index c0fd3f4b7ebf2..8ad7d6d7b0891 100644 --- a/tests/ui/hygiene/cross-crate-redefine.stderr +++ b/tests/ui/hygiene/cross-crate-redefine.stderr @@ -1,11 +1,10 @@ error[E0428]: the name `MyStruct` is defined multiple times - --> $DIR/cross-crate-redefine.rs:10:1 + --> $DIR/cross-crate-redefine.rs:11:1 | -LL | my_struct!(define); - | ^^^^^^^^^^^^^^^^^^ `MyStruct` redefined here -LL | LL | my_struct!(define); | ------------------ previous definition of the type `MyStruct` here +LL | my_struct!(define); + | ^^^^^^^^^^^^^^^^^^ `MyStruct` redefined here | = note: `MyStruct` must be defined only once in the type namespace of this module = note: this error originates in the macro `my_struct` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/imports/overwrite-deep-glob.rs b/tests/ui/imports/overwrite-deep-glob.rs new file mode 100644 index 0000000000000..261b22f6e0a07 --- /dev/null +++ b/tests/ui/imports/overwrite-deep-glob.rs @@ -0,0 +1,22 @@ +//@ check-pass + +mod openssl { + pub use self::handwritten::*; + + mod handwritten { + mod m1 { + pub struct S {} + } + mod m2 { + #[derive(Default)] + pub struct S {} + } + + pub use self::m1::*; //~ WARN ambiguous glob re-exports + pub use self::m2::*; + } +} + +pub use openssl::*; + +fn main() {} diff --git a/tests/ui/imports/overwrite-deep-glob.stderr b/tests/ui/imports/overwrite-deep-glob.stderr new file mode 100644 index 0000000000000..093478c57c93a --- /dev/null +++ b/tests/ui/imports/overwrite-deep-glob.stderr @@ -0,0 +1,12 @@ +warning: ambiguous glob re-exports + --> $DIR/overwrite-deep-glob.rs:15:17 + | +LL | pub use self::m1::*; + | ^^^^^^^^^^^ the name `S` in the type namespace is first re-exported here +LL | pub use self::m2::*; + | ----------- but the name `S` in the type namespace is also re-exported here + | + = note: `#[warn(ambiguous_glob_reexports)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/imports/overwrite-different-ambig-2.rs b/tests/ui/imports/overwrite-different-ambig-2.rs new file mode 100644 index 0000000000000..1b6d20e24d309 --- /dev/null +++ b/tests/ui/imports/overwrite-different-ambig-2.rs @@ -0,0 +1,24 @@ +mod m1 { + mod inner { + pub struct S {} + } + pub use self::inner::*; + + #[derive(Debug)] + pub struct S {} +} + +mod m2 { + pub struct S {} +} + +// First we have a glob ambiguity in this glob (with `m2::*`). +// Then we re-fetch `m1::*` because non-glob `m1::S` materializes from derive, +// and we need to make sure that the glob ambiguity is not lost during re-fetching. +use m1::*; +use m2::*; + +fn main() { + let _: m1::S = S {}; //~ ERROR `S` is ambiguous + //~| WARN this was previously accepted +} diff --git a/tests/ui/imports/overwrite-different-ambig-2.stderr b/tests/ui/imports/overwrite-different-ambig-2.stderr new file mode 100644 index 0000000000000..e75f552d119c1 --- /dev/null +++ b/tests/ui/imports/overwrite-different-ambig-2.stderr @@ -0,0 +1,49 @@ +error: `S` is ambiguous + --> $DIR/overwrite-different-ambig-2.rs:22:20 + | +LL | let _: m1::S = S {}; + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `S` could refer to the struct imported here + --> $DIR/overwrite-different-ambig-2.rs:18:5 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `S` to disambiguate +note: `S` could also refer to the struct imported here + --> $DIR/overwrite-different-ambig-2.rs:19:5 + | +LL | use m2::*; + | ^^^^^ + = help: consider adding an explicit import of `S` to disambiguate + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +error: aborting due to 1 previous error + +Future incompatibility report: Future breakage diagnostic: +error: `S` is ambiguous + --> $DIR/overwrite-different-ambig-2.rs:22:20 + | +LL | let _: m1::S = S {}; + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `S` could refer to the struct imported here + --> $DIR/overwrite-different-ambig-2.rs:18:5 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `S` to disambiguate +note: `S` could also refer to the struct imported here + --> $DIR/overwrite-different-ambig-2.rs:19:5 + | +LL | use m2::*; + | ^^^^^ + = help: consider adding an explicit import of `S` to disambiguate + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + diff --git a/tests/ui/imports/overwrite-different-ambig.rs b/tests/ui/imports/overwrite-different-ambig.rs new file mode 100644 index 0000000000000..9aee63e189731 --- /dev/null +++ b/tests/ui/imports/overwrite-different-ambig.rs @@ -0,0 +1,25 @@ +//@ check-pass +//@ edition:2024 + +mod a { + mod b { + mod c { + pub struct E; + } + mod d { + mod c { + pub struct E; + } + mod d { + #[derive(Debug)] + pub struct E; + } + pub use c::*; + use d::*; + } + use c::*; + use d::*; + } +} + +fn main() {} diff --git a/tests/ui/imports/overwrite-different-vis.rs b/tests/ui/imports/overwrite-different-vis.rs new file mode 100644 index 0000000000000..edcc441bcb77e --- /dev/null +++ b/tests/ui/imports/overwrite-different-vis.rs @@ -0,0 +1,21 @@ +//@ check-pass + +mod b { + pub mod http { + pub struct HeaderMap; + } + + pub(crate) use self::http::*; + #[derive(Debug)] + pub struct HeaderMap; +} + +mod a { + pub use crate::b::*; + + fn check_type() { + let _: HeaderMap = crate::b::HeaderMap; + } +} + +fn main() {} diff --git a/tests/ui/imports/overwrite-different-warn-ambiguity.rs b/tests/ui/imports/overwrite-different-warn-ambiguity.rs new file mode 100644 index 0000000000000..f843208b37d68 --- /dev/null +++ b/tests/ui/imports/overwrite-different-warn-ambiguity.rs @@ -0,0 +1,28 @@ +//@ check-pass +//@ edition:2024 + +mod framing { + mod public_message_in { + mod public_message { + mod public_message { + pub struct ConfirmedTranscriptHashInput; + } + mod public_message_in { + use super::*; + #[derive(Debug)] + pub struct ConfirmedTranscriptHashInput; + } + pub use public_message::*; + use public_message_in::*; + } + mod public_message_in { + #[derive(Debug)] + pub struct ConfirmedTranscriptHashInput; + } + pub use public_message::*; + use public_message_in::*; + } + use public_message_in::*; +} + +fn main() {} diff --git a/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.rs b/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.rs new file mode 100644 index 0000000000000..58bb62bc4bf86 --- /dev/null +++ b/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.rs @@ -0,0 +1,11 @@ +//! More test coverage for ; this test is +//! specifically for `const` items. + +macro_rules! m { + (const $id:item()) => {} +} + +m!(const Self()); +//~^ ERROR expected one of `!` or `::`, found `(` + +fn main() {} diff --git a/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.stderr b/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.stderr new file mode 100644 index 0000000000000..f9b73109dbb49 --- /dev/null +++ b/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.stderr @@ -0,0 +1,11 @@ +error: expected one of `!` or `::`, found `(` + --> $DIR/kw-in-const-item-pos-recovery-149692.rs:8:14 + | +LL | (const $id:item()) => {} + | -------- while parsing argument for this `item` macro fragment +... +LL | m!(const Self()); + | ^ expected one of `!` or `::` + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs b/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs new file mode 100644 index 0000000000000..223864e332966 --- /dev/null +++ b/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs @@ -0,0 +1,19 @@ +//! Regression test for a diagnostic ICE where we tried to recover a keyword as the identifier when +//! we are already trying to recover a missing keyword before item. +//! +//! See . + +macro_rules! m { + ($id:item()) => {} +} + +m!(Self()); +//~^ ERROR expected one of `!` or `::`, found `(` + +m!(Self{}); +//~^ ERROR expected one of `!` or `::`, found `{` + +m!(crate()); +//~^ ERROR expected one of `!` or `::`, found `(` + +fn main() {} diff --git a/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr b/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr new file mode 100644 index 0000000000000..a65214b0d1f93 --- /dev/null +++ b/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr @@ -0,0 +1,29 @@ +error: expected one of `!` or `::`, found `(` + --> $DIR/kw-in-item-pos-recovery-149692.rs:10:8 + | +LL | ($id:item()) => {} + | -------- while parsing argument for this `item` macro fragment +... +LL | m!(Self()); + | ^ expected one of `!` or `::` + +error: expected one of `!` or `::`, found `{` + --> $DIR/kw-in-item-pos-recovery-149692.rs:13:8 + | +LL | ($id:item()) => {} + | -------- while parsing argument for this `item` macro fragment +... +LL | m!(Self{}); + | ^ expected one of `!` or `::` + +error: expected one of `!` or `::`, found `(` + --> $DIR/kw-in-item-pos-recovery-149692.rs:16:9 + | +LL | ($id:item()) => {} + | -------- while parsing argument for this `item` macro fragment +... +LL | m!(crate()); + | ^ expected one of `!` or `::` + +error: aborting due to 3 previous errors +