Auto merge of #151144 - JonathanBrouwer:rollup-QW4Ug5q, r=JonathanBrouwer

Rollup of 15 pull requests

Successful merges:

 - rust-lang/rust#150585 (Add a context-consistency check before emitting redundant generic-argument suggestions)
 - rust-lang/rust#150586 (rustdoc: Fix intra-doc link bugs involving type aliases and associated items)
 - rust-lang/rust#150590 (Don't try to recover keyword as non-keyword identifier )
 - rust-lang/rust#150817 (cleanup: remove borrowck handling for inline const patterns)
 - rust-lang/rust#150939 (resolve: Relax some asserts in glob overwriting and add tests)
 - rust-lang/rust#150962 (Remove `FeedConstTy` and provide ty when lowering const arg)
 - rust-lang/rust#150966 (rustc_target: Remove unused Arch::PowerPC64LE)
 - rust-lang/rust#150971 (Disallow eii in statement position)
 - rust-lang/rust#151016 (fix: WASI threading regression by disabling pthread usage)
 - rust-lang/rust#151046 (compiler: Make Externally Implementable Item (eii) macros "semiopaque")
 - rust-lang/rust#151099 (Recover parse gracefully from `<const N>`)
 - rust-lang/rust#151117 (Avoid serde dependency in build_helper when not necessary)
 - rust-lang/rust#151127 (Delete `MetaItemOrLitParser::Err`)
 - rust-lang/rust#151128 (Add temporary new bors e-mail address to the mailmap)
 - rust-lang/rust#151138 (Rename `rust.use-lld` to `rust.bootstrap-override-lld` in INSTALL.md)

r? @ghost
This commit is contained in:
bors 2026-01-14 21:30:22 +00:00
commit b6fdaf2a15
61 changed files with 1156 additions and 626 deletions

View file

@ -96,6 +96,7 @@ boolean_coercion <booleancoercion@gmail.com>
Boris Egorov <jightuse@gmail.com> <egorov@linux.com>
bors <bors@rust-lang.org> bors[bot] <26634292+bors[bot]@users.noreply.github.com>
bors <bors@rust-lang.org> bors[bot] <bors[bot]@users.noreply.github.com>
bors <bors@rust-lang.org> <122020455+rust-bors[bot]@users.noreply.github.com>
BoxyUwU <rust@boxyuwu.dev>
BoxyUwU <rust@boxyuwu.dev> <supbscripter@gmail.com>
Braden Nelson <moonheart08@users.noreply.github.com>

View file

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

View file

@ -94,7 +94,6 @@ pub fn parse_cfg_entry<S: Stage>(
LitKind::Bool(b) => CfgEntry::Bool(b, lit.span),
_ => return Err(cx.expected_identifier(lit.span)),
},
MetaItemOrLitParser::Err(_, err) => return Err(*err),
})
}

View file

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

View file

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

View file

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

View file

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

View file

@ -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<Annotatable> {
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<Box<ast::Item>>| {
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<ast::Stmt>| {
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::*;
// <orig fn>
// }
// <orig fn>
// }
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));

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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]: <https://github.com/rust-lang/project-const-generics/issues/28>.
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>>,

View file

@ -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 `<dyn HirTyLowerer>::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::<Vec<_>>();
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::<Vec<_>>();
@ -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::<Vec<_>>();
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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1725,7 +1725,6 @@ symbols! {
postfix_match,
powerpc,
powerpc64,
powerpc64le,
powerpc_target_feature,
powf16,
powf32,

View file

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

View file

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

View file

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

View file

@ -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(_) => &[],
}
}

View file

@ -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<ThreadInit>) -> io::Result<Thread> {
// 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<libc::pthread_attr_t> = mem::MaybeUninit::uninit();
assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0);

View file

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

View file

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

View file

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

View file

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

View file

@ -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<DefId>,
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<DefId>,
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::<ThinVec<_>>();
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(),

View file

@ -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::<Vec<_>>()
}
fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: DefId) -> Option<Res> {
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<Res> {
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<Disambiguator>,
item_id: DefId,
module_id: DefId,
) -> Result<Vec<(Res, Option<DefId>)>, 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::<Vec<_>>()
@ -503,246 +456,323 @@ 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<Res> {
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,
})
}
/// 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<Ty<'tcx>> {
use PrimitiveType::*;
let tcx = self.cx.tcx;
// 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,
})
}
/// 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<Disambiguator>,
module_id: DefId,
) -> Vec<(Res, DefId)> {
let tcx = self.cx.tcx;
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::<Vec<_>>()
})
.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!(),
}
}
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::<Vec<_>>()
};
if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator {
return search_for_field();
}
// Checks if item_name belongs to `impl SomeItem`
let mut assoc_items: Vec<_> = tcx
.inherent_impls(did)
.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`](<SomeStruct as SomeTrait>::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::<Vec<_>>();
}
debug!("got associated item {assoc_items:?}");
if !assoc_items.is_empty() {
return assoc_items;
}
if ns != Namespace::ValueNS {
return Vec::new();
}
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<_>>(),
_ => Vec::new(),
}
}
}
fn full_res(tcx: TyCtxt<'_>, (base, assoc_item): (Res, Option<DefId>)) -> 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::<Vec<_>>()
}
fn resolve_self_ty<'tcx>(
tcx: TyCtxt<'tcx>,
path_str: &str,
ns: Namespace,
item_id: DefId,
) -> Option<Res> {
if ns != TypeNS || path_str != "Self" {
return None;
}
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 { .. } => ty_to_res(tcx, tcx.type_of(self_id).instantiate_identity()),
DefKind::Use => None,
def_kind => Some(Res::Def(def_kind, self_id)),
}
}
/// 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<Res> {
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,
})
}
/// 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<Ty<'tcx>> {
use PrimitiveType::*;
// 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,
})
}
/// 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<Disambiguator>,
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<_>>(),
_ => Vec::new(),
}
}
// 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()
.map(|item| (root_res, item.def_id))
.collect::<Vec<_>>()
})
.unwrap_or_default()
}
}
fn resolve_assoc_on_adt<'tcx>(
tcx: TyCtxt<'tcx>,
adt_def_id: DefId,
item_ident: Ident,
ns: Namespace,
disambiguator: Option<Disambiguator>,
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 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();
}
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;
}
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![]
}
/// "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`](<SomeStruct as SomeTrait>::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::<Vec<_>>();
debug!("got trait assoc items {trait_assoc_items:?}");
trait_assoc_items
}
fn resolve_structfield<'tcx>(adt_def: ty::AdtDef<'tcx>, item_name: Symbol) -> Option<DefId> {
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`.
///
/// Given `[std::io::Error::source]`, where `source` is unresolved, this would
/// find `std::error::Error::source` and return
/// `<io::Error as error::Error>::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<ty::AssocItem> {
// FIXME: this should also consider blanket impls (`impl<T> 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::<Vec<_>>();
// 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<Disambiguator>,

View file

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

View file

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

View file

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

View file

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

View file

@ -27,6 +27,12 @@ LL | const C: &'static str;
...
LL | fn take1(_: impl Trait1<C = "?">) {}
| ^^^^^^^ 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

View file

@ -0,0 +1,45 @@
// #84327
struct VecWrapper<T>(Vec<T>);
// Correct
impl<T, const N: usize> From<[T; N]> for VecWrapper<T>
where
T: Clone,
{
fn from(slice: [T; N]) -> Self {
VecWrapper(slice.to_vec())
}
}
// Forgot const
impl<T, N: usize> From<[T; N]> for VecWrapper<T> //~ 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<T, const N> From<[T; N]> for VecWrapper<T> //~ ERROR expected `:`, found `>`
where
T: Clone,
{
fn from(slice: [T; N]) -> Self {
VecWrapper(slice.to_vec())
}
}
// Forgot const and type
impl<T, N> From<[T; N]> for VecWrapper<T> //~ 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() {}

View file

@ -0,0 +1,70 @@
error: expected `:`, found `>`
--> $DIR/incorrect-const-param.rs:26:16
|
LL | impl<T, const N> From<[T; N]> for VecWrapper<T>
| ^ expected `:`
|
help: you likely meant to write the type of the const parameter here
|
LL | impl<T, const N: /* Type */> From<[T; N]> for VecWrapper<T>
| ++++++++++++
error[E0423]: expected value, found type parameter `N`
--> $DIR/incorrect-const-param.rs:16:28
|
LL | impl<T, N: usize> From<[T; N]> for VecWrapper<T>
| - ^ not a value
| |
| found this type parameter
error[E0404]: expected trait, found builtin type `usize`
--> $DIR/incorrect-const-param.rs:16:12
|
LL | impl<T, N: usize> From<[T; N]> for VecWrapper<T>
| ^^^^^ not a trait
|
help: you might have meant to write a const parameter here
|
LL | impl<T, const N: usize> From<[T; N]> for VecWrapper<T>
| +++++
error[E0423]: expected value, found type parameter `N`
--> $DIR/incorrect-const-param.rs:20:24
|
LL | impl<T, N: usize> From<[T; N]> for VecWrapper<T>
| - 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<T, N> From<[T; N]> for VecWrapper<T>
| - ^ not a value
| |
| found this type parameter
|
help: you might have meant to write a const parameter here
|
LL | impl<T, const N: /* Type */> From<[T; N]> for VecWrapper<T>
| +++++ ++++++++++++
error[E0423]: expected value, found type parameter `N`
--> $DIR/incorrect-const-param.rs:40:24
|
LL | impl<T, N> From<[T; N]> for VecWrapper<T>
| - 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<T, const N: /* Type */> From<[T; N]> for VecWrapper<T>
| +++++ ++++++++++++
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0404, E0423.
For more information about an error, try `rustc --explain E0404`.

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,15 @@
// Regression test for #149559
struct Foo<T>; //~ ERROR type parameter `T` is never used
macro_rules! foo_ty {
($a:ty, $b:ty) => {
Foo<a, $b>
//~^ 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() {}

View file

@ -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<a, $b>
| ^ 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<a, $b>
| ^^^ 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<T>;
| ^^^ -
= 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<T>;
| ^ 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`.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,11 @@
//! More test coverage for <https://github.com/rust-lang/rust/issues/149692>; this test is
//! specifically for `const` items.
macro_rules! m {
(const $id:item()) => {}
}
m!(const Self());
//~^ ERROR expected one of `!` or `::`, found `(`
fn main() {}

View file

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

View file

@ -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 <https://github.com/rust-lang/rust/issues/149692>.
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() {}

View file

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