Auto merge of #138630 - matthiaskrgr:rollup-kk1gogr, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #138384 (Move `hir::Item::ident` into `hir::ItemKind`.)
 - #138508 (Clarify "owned data" in E0515.md)
 - #138531 (Store test diffs in job summaries and improve analysis formatting)
 - #138533 (Only use `DIST_TRY_BUILD` for try jobs that were not selected explicitly)
 - #138556 (Fix ICE: attempted to remap an already remapped filename)
 - #138608 (rustc_target: Add target feature constraints for LoongArch)
 - #138619 (Flatten `if`s in `rustc_codegen_ssa`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-03-18 05:58:46 +00:00
commit 259fdb5212
105 changed files with 1345 additions and 1150 deletions

View file

@ -239,16 +239,31 @@ jobs:
if: github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1'
- name: postprocess metrics into the summary
# This step is not critical, and if some I/O problem happens, we don't want
# to cancel the build.
continue-on-error: true
run: |
if [ -f build/metrics.json ]; then
./build/citool/debug/citool postprocess-metrics build/metrics.json ${GITHUB_STEP_SUMMARY}
METRICS=build/metrics.json
elif [ -f obj/build/metrics.json ]; then
./build/citool/debug/citool postprocess-metrics obj/build/metrics.json ${GITHUB_STEP_SUMMARY}
METRICS=obj/build/metrics.json
else
echo "No metrics.json found"
exit 0
fi
# Get closest bors merge commit
PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
./build/citool/debug/citool postprocess-metrics \
--job-name ${CI_JOB_NAME} \
--parent ${PARENT_COMMIT} \
${METRICS} >> ${GITHUB_STEP_SUMMARY}
- name: upload job metrics to DataDog
# This step is not critical, and if some I/O problem happens, we don't want
# to cancel the build.
continue-on-error: true
if: needs.calculate_matrix.outputs.run_type != 'pr'
env:
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}

View file

@ -164,7 +164,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
fn visit_item(&mut self, i: &'hir Item<'hir>) {
debug_assert_eq!(i.owner_id, self.owner);
self.with_parent(i.hir_id(), |this| {
if let ItemKind::Struct(struct_def, _) = &i.kind {
if let ItemKind::Struct(_, struct_def, _) = &i.kind {
// If this is a tuple or unit-like struct, register the constructor.
if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));

View file

@ -111,6 +111,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
}
fn lower_foreign_item(&mut self, item: &ForeignItem) {
debug_assert_ne!(item.ident.name, kw::Empty);
self.with_lctx(item.id, |lctx| hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)))
}
}
@ -154,14 +155,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
let mut ident = i.ident;
let vis_span = self.lower_span(i.vis.span);
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
let attrs = self.lower_attrs(hir_id, &i.attrs, i.span);
let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind);
let kind = self.lower_item_kind(i.span, i.id, hir_id, i.ident, attrs, vis_span, &i.kind);
let item = hir::Item {
owner_id: hir_id.expect_owner(),
ident: self.lower_ident(ident),
kind,
vis_span,
span: self.lower_span(i.span),
@ -174,25 +173,34 @@ impl<'hir> LoweringContext<'_, 'hir> {
span: Span,
id: NodeId,
hir_id: hir::HirId,
ident: &mut Ident,
ident: Ident,
attrs: &'hir [hir::Attribute],
vis_span: Span,
i: &ItemKind,
) -> hir::ItemKind<'hir> {
match i {
ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(*orig_name),
ItemKind::ExternCrate(orig_name) => {
debug_assert_ne!(ident.name, kw::Empty);
let ident = self.lower_ident(ident);
hir::ItemKind::ExternCrate(*orig_name, ident)
}
ItemKind::Use(use_tree) => {
debug_assert_eq!(ident.name, kw::Empty);
// Start with an empty prefix.
let prefix = Path { segments: ThinVec::new(), span: use_tree.span, tokens: None };
self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
self.lower_use_tree(use_tree, &prefix, id, vis_span, attrs)
}
ItemKind::Static(box ast::StaticItem { ty: t, safety: _, mutability: m, expr: e }) => {
debug_assert_ne!(ident.name, kw::Empty);
let ident = self.lower_ident(ident);
let (ty, body_id) =
self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy);
hir::ItemKind::Static(ty, *m, body_id)
hir::ItemKind::Static(ident, ty, *m, body_id)
}
ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
debug_assert_ne!(ident.name, kw::Empty);
let ident = self.lower_ident(ident);
let (generics, (ty, body_id)) = self.lower_generics(
generics,
id,
@ -201,7 +209,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy)
},
);
hir::ItemKind::Const(ty, generics, body_id)
hir::ItemKind::Const(ident, ty, generics, body_id)
}
ItemKind::Fn(box Fn {
sig: FnSig { decl, header, span: fn_sig_span },
@ -211,6 +219,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
define_opaque,
..
}) => {
debug_assert_ne!(ident.name, kw::Empty);
self.with_new_scopes(*fn_sig_span, |this| {
// Note: we don't need to change the return type from `T` to
// `impl Future<Output = T>` here because lower_body
@ -238,28 +247,44 @@ impl<'hir> LoweringContext<'_, 'hir> {
span: this.lower_span(*fn_sig_span),
};
this.lower_define_opaque(hir_id, &define_opaque);
hir::ItemKind::Fn { sig, generics, body: body_id, has_body: body.is_some() }
let ident = this.lower_ident(ident);
hir::ItemKind::Fn {
ident,
sig,
generics,
body: body_id,
has_body: body.is_some(),
}
})
}
ItemKind::Mod(_, mod_kind) => match mod_kind {
ModKind::Loaded(items, _, spans, _) => {
hir::ItemKind::Mod(self.lower_mod(items, spans))
ItemKind::Mod(_, mod_kind) => {
debug_assert_ne!(ident.name, kw::Empty);
let ident = self.lower_ident(ident);
match mod_kind {
ModKind::Loaded(items, _, spans, _) => {
hir::ItemKind::Mod(ident, self.lower_mod(items, spans))
}
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
}
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
},
ItemKind::ForeignMod(fm) => hir::ItemKind::ForeignMod {
abi: fm.abi.map_or(ExternAbi::FALLBACK, |abi| self.lower_abi(abi)),
items: self
.arena
.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
},
}
ItemKind::ForeignMod(fm) => {
debug_assert_eq!(ident.name, kw::Empty);
hir::ItemKind::ForeignMod {
abi: fm.abi.map_or(ExternAbi::FALLBACK, |abi| self.lower_abi(abi)),
items: self
.arena
.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
}
}
ItemKind::GlobalAsm(asm) => {
debug_assert_eq!(ident.name, kw::Empty);
let asm = self.lower_inline_asm(span, asm);
let fake_body =
self.lower_body(|this| (&[], this.expr(span, hir::ExprKind::InlineAsm(asm))));
hir::ItemKind::GlobalAsm { asm, fake_body }
}
ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
debug_assert_ne!(ident.name, kw::Empty);
// We lower
//
// type Foo = impl Trait
@ -268,6 +293,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
//
// type Foo = Foo1
// opaque type Foo1: Trait
let ident = self.lower_ident(ident);
let mut generics = generics.clone();
add_ty_alias_where_clause(&mut generics, *where_clauses, true);
let (generics, ty) = self.lower_generics(
@ -293,9 +319,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
),
},
);
hir::ItemKind::TyAlias(ty, generics)
hir::ItemKind::TyAlias(ident, ty, generics)
}
ItemKind::Enum(enum_definition, generics) => {
debug_assert_ne!(ident.name, kw::Empty);
let ident = self.lower_ident(ident);
let (generics, variants) = self.lower_generics(
generics,
id,
@ -306,25 +334,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
)
},
);
hir::ItemKind::Enum(hir::EnumDef { variants }, generics)
hir::ItemKind::Enum(ident, hir::EnumDef { variants }, generics)
}
ItemKind::Struct(struct_def, generics) => {
debug_assert_ne!(ident.name, kw::Empty);
let ident = self.lower_ident(ident);
let (generics, struct_def) = self.lower_generics(
generics,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, struct_def),
);
hir::ItemKind::Struct(struct_def, generics)
hir::ItemKind::Struct(ident, struct_def, generics)
}
ItemKind::Union(vdata, generics) => {
debug_assert_ne!(ident.name, kw::Empty);
let ident = self.lower_ident(ident);
let (generics, vdata) = self.lower_generics(
generics,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, vdata),
);
hir::ItemKind::Union(vdata, generics)
hir::ItemKind::Union(ident, vdata, generics)
}
ItemKind::Impl(box Impl {
safety,
@ -336,6 +368,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self_ty: ty,
items: impl_items,
}) => {
debug_assert_eq!(ident.name, kw::Empty);
// Lower the "impl header" first. This ordering is important
// for in-band lifetimes! Consider `'a` here:
//
@ -401,6 +434,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
}))
}
ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => {
debug_assert_ne!(ident.name, kw::Empty);
let ident = self.lower_ident(ident);
let (generics, (safety, items, bounds)) = self.lower_generics(
generics,
id,
@ -417,9 +452,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
(safety, items, bounds)
},
);
hir::ItemKind::Trait(*is_auto, safety, generics, bounds, items)
hir::ItemKind::Trait(*is_auto, safety, ident, generics, bounds, items)
}
ItemKind::TraitAlias(generics, bounds) => {
debug_assert_ne!(ident.name, kw::Empty);
let ident = self.lower_ident(ident);
let (generics, bounds) = self.lower_generics(
generics,
id,
@ -431,9 +468,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
)
},
);
hir::ItemKind::TraitAlias(generics, bounds)
hir::ItemKind::TraitAlias(ident, generics, bounds)
}
ItemKind::MacroDef(MacroDef { body, macro_rules }) => {
debug_assert_ne!(ident.name, kw::Empty);
let ident = self.lower_ident(ident);
let body = P(self.lower_delim_args(body));
let def_id = self.local_def_id(id);
let def_kind = self.tcx.def_kind(def_id);
@ -444,11 +483,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
};
let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
hir::ItemKind::Macro(macro_def, macro_kind)
hir::ItemKind::Macro(ident, macro_def, macro_kind)
}
ItemKind::Delegation(box delegation) => {
debug_assert_ne!(ident.name, kw::Empty);
let ident = self.lower_ident(ident);
let delegation_results = self.lower_delegation(delegation, id);
hir::ItemKind::Fn {
ident,
sig: delegation_results.sig,
generics: delegation_results.generics,
body: delegation_results.body_id,
@ -479,7 +521,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
prefix: &Path,
id: NodeId,
vis_span: Span,
ident: &mut Ident,
attrs: &'hir [hir::Attribute],
) -> hir::ItemKind<'hir> {
let path = &tree.prefix;
@ -487,7 +528,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
match tree.kind {
UseTreeKind::Simple(rename) => {
*ident = tree.ident();
let mut ident = tree.ident();
// First, apply the prefix to the path.
let mut path = Path { segments, span: path.span, tokens: None };
@ -498,13 +539,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
{
let _ = path.segments.pop();
if rename.is_none() {
*ident = path.segments.last().unwrap().ident;
ident = path.segments.last().unwrap().ident;
}
}
let res = self.lower_import_res(id, path.span);
let path = self.lower_use_path(res, &path, ParamMode::Explicit);
hir::ItemKind::Use(path, hir::UseKind::Single)
let ident = self.lower_ident(ident);
hir::ItemKind::Use(path, hir::UseKind::Single(ident))
}
UseTreeKind::Glob => {
let res = self.expect_full_res(id);
@ -551,20 +593,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
// own its own names, we have to adjust the owner before
// lowering the rest of the import.
self.with_hir_id_owner(id, |this| {
let mut ident = *ident;
// `prefix` is lowered multiple times, but in different HIR owners.
// So each segment gets renewed `HirId` with the same
// `ItemLocalId` and the new owner. (See `lower_node_id`)
let kind =
this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs);
let kind = this.lower_use_tree(use_tree, &prefix, id, vis_span, attrs);
if !attrs.is_empty() {
this.attrs.insert(hir::ItemLocalId::ZERO, attrs);
}
let item = hir::Item {
owner_id: hir::OwnerId { def_id: new_hir_id },
ident: this.lower_ident(ident),
kind,
vis_span,
span: this.lower_span(use_tree.span),
@ -604,7 +642,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ItemKind::Impl(impl_) => {
self.is_in_trait_impl = impl_.of_trait.is_some();
}
hir::ItemKind::Trait(_, _, _, _, _) => {}
hir::ItemKind::Trait(..) => {}
kind => {
span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr())
}
@ -760,6 +798,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
debug_assert_ne!(i.ident.name, kw::Empty);
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
let attrs = self.lower_attrs(hir_id, &i.attrs, i.span);
let trait_item_def_id = hir_id.expect_owner();
@ -907,6 +946,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
debug_assert_ne!(i.ident.name, kw::Empty);
// Since `default impl` is not yet implemented, this is always true in impls.
let has_value = true;
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);

View file

@ -691,7 +691,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
true,
td.is_local(),
td.as_local().and_then(|tld| match self.infcx.tcx.hir_node_by_def_id(tld) {
Node::Item(hir::Item { kind: hir::ItemKind::Trait(_, _, _, _, items), .. }) => {
Node::Item(hir::Item {
kind: hir::ItemKind::Trait(_, _, _, _, _, items), ..
}) => {
let mut f_in_trait_opt = None;
for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
let hi = fi.hir_id();
@ -980,7 +982,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let arg = match tcx.hir_get_if_local(callee_def_id) {
Some(
hir::Node::Item(hir::Item {
ident, kind: hir::ItemKind::Fn { sig, .. }, ..
kind: hir::ItemKind::Fn { ident, sig, .. }, ..
})
| hir::Node::TraitItem(hir::TraitItem {
ident,
@ -1021,7 +1023,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
// return type.
match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(fn_call_id).def_id) {
hir::Node::Item(hir::Item {
ident, kind: hir::ItemKind::Fn { sig, .. }, ..
kind: hir::ItemKind::Fn { ident, sig, .. }, ..
})
| hir::Node::TraitItem(hir::TraitItem {
ident,

View file

@ -389,11 +389,10 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
mut skip: Box<dyn FnMut(&str) -> bool + 'static>,
) -> io::Result<()> {
let mut archive_path = archive_path.to_path_buf();
if self.sess.target.llvm_target.contains("-apple-macosx") {
if let Some(new_archive_path) = try_extract_macho_fat_archive(self.sess, &archive_path)?
{
archive_path = new_archive_path
}
if self.sess.target.llvm_target.contains("-apple-macosx")
&& let Some(new_archive_path) = try_extract_macho_fat_archive(self.sess, &archive_path)?
{
archive_path = new_archive_path
}
if self.src_archives.iter().any(|archive| archive.0 == archive_path) {

View file

@ -151,17 +151,17 @@ pub fn link_binary(
sess.dcx().emit_artifact_notification(&out_filename, "link");
}
if sess.prof.enabled() {
if let Some(artifact_name) = out_filename.file_name() {
// Record size for self-profiling
let file_size = std::fs::metadata(&out_filename).map(|m| m.len()).unwrap_or(0);
if sess.prof.enabled()
&& let Some(artifact_name) = out_filename.file_name()
{
// Record size for self-profiling
let file_size = std::fs::metadata(&out_filename).map(|m| m.len()).unwrap_or(0);
sess.prof.artifact_size(
"linked_artifact",
artifact_name.to_string_lossy(),
file_size,
);
}
sess.prof.artifact_size(
"linked_artifact",
artifact_name.to_string_lossy(),
file_size,
);
}
if output.is_stdout() {
@ -186,16 +186,12 @@ pub fn link_binary(
let maybe_remove_temps_from_module =
|preserve_objects: bool, preserve_dwarf_objects: bool, module: &CompiledModule| {
if !preserve_objects {
if let Some(ref obj) = module.object {
ensure_removed(sess.dcx(), obj);
}
if !preserve_objects && let Some(ref obj) = module.object {
ensure_removed(sess.dcx(), obj);
}
if !preserve_dwarf_objects {
if let Some(ref dwo_obj) = module.dwarf_object {
ensure_removed(sess.dcx(), dwo_obj);
}
if !preserve_dwarf_objects && let Some(ref dwo_obj) = module.dwarf_object {
ensure_removed(sess.dcx(), dwo_obj);
}
};
@ -2116,11 +2112,11 @@ fn add_local_crate_metadata_objects(
// When linking a dynamic library, we put the metadata into a section of the
// executable. This metadata is in a separate object file from the main
// object file, so we link that in here.
if crate_type == CrateType::Dylib || crate_type == CrateType::ProcMacro {
if let Some(obj) = codegen_results.metadata_module.as_ref().and_then(|m| m.object.as_ref())
{
cmd.add_object(obj);
}
if matches!(crate_type, CrateType::Dylib | CrateType::ProcMacro)
&& let Some(m) = &codegen_results.metadata_module
&& let Some(obj) = &m.object
{
cmd.add_object(obj);
}
}
@ -2540,10 +2536,11 @@ fn add_order_independent_options(
cmd.output_filename(out_filename);
if crate_type == CrateType::Executable && sess.target.is_like_windows {
if let Some(ref s) = codegen_results.crate_info.windows_subsystem {
cmd.subsystem(s);
}
if crate_type == CrateType::Executable
&& sess.target.is_like_windows
&& let Some(s) = &codegen_results.crate_info.windows_subsystem
{
cmd.subsystem(s);
}
// Try to strip as much out of the generated object by removing unused

View file

@ -111,24 +111,22 @@ pub(crate) fn get_linker<'a>(
// PATH for the child.
let mut new_path = sess.get_tools_search_paths(self_contained);
let mut msvc_changed_path = false;
if sess.target.is_like_msvc {
if let Some(ref tool) = msvc_tool {
cmd.args(tool.args());
for (k, v) in tool.env() {
if k == "PATH" {
new_path.extend(env::split_paths(v));
msvc_changed_path = true;
} else {
cmd.env(k, v);
}
if sess.target.is_like_msvc
&& let Some(ref tool) = msvc_tool
{
cmd.args(tool.args());
for (k, v) in tool.env() {
if k == "PATH" {
new_path.extend(env::split_paths(v));
msvc_changed_path = true;
} else {
cmd.env(k, v);
}
}
}
if !msvc_changed_path {
if let Some(path) = env::var_os("PATH") {
new_path.extend(env::split_paths(&path));
}
if !msvc_changed_path && let Some(path) = env::var_os("PATH") {
new_path.extend(env::split_paths(&path));
}
cmd.env("PATH", env::join_paths(new_path).unwrap());

View file

@ -566,16 +566,13 @@ fn produce_final_output_artifacts(
// Produce final compile outputs.
let copy_gracefully = |from: &Path, to: &OutFileName| match to {
OutFileName::Stdout => {
if let Err(e) = copy_to_stdout(from) {
sess.dcx().emit_err(errors::CopyPath::new(from, to.as_path(), e));
}
OutFileName::Stdout if let Err(e) = copy_to_stdout(from) => {
sess.dcx().emit_err(errors::CopyPath::new(from, to.as_path(), e));
}
OutFileName::Real(path) => {
if let Err(e) = fs::copy(from, path) {
sess.dcx().emit_err(errors::CopyPath::new(from, path, e));
}
OutFileName::Real(path) if let Err(e) = fs::copy(from, path) => {
sess.dcx().emit_err(errors::CopyPath::new(from, path, e));
}
_ => {}
};
let copy_if_one_unit = |output_type: OutputType, keep_numbered: bool| {
@ -685,14 +682,12 @@ fn produce_final_output_artifacts(
needs_crate_object || (user_wants_objects && sess.codegen_units().as_usize() > 1);
for module in compiled_modules.modules.iter() {
if let Some(ref path) = module.object {
if !keep_numbered_objects {
if !keep_numbered_objects {
if let Some(ref path) = module.object {
ensure_removed(sess.dcx(), path);
}
}
if let Some(ref path) = module.dwarf_object {
if !keep_numbered_objects {
if let Some(ref path) = module.dwarf_object {
ensure_removed(sess.dcx(), path);
}
}
@ -704,12 +699,11 @@ fn produce_final_output_artifacts(
}
}
if !user_wants_bitcode {
if let Some(ref allocator_module) = compiled_modules.allocator_module {
if let Some(ref path) = allocator_module.bytecode {
ensure_removed(sess.dcx(), path);
}
}
if !user_wants_bitcode
&& let Some(ref allocator_module) = compiled_modules.allocator_module
&& let Some(ref path) = allocator_module.bytecode
{
ensure_removed(sess.dcx(), path);
}
}

View file

@ -555,11 +555,9 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &mut String) {
let def_key = tcx.def_key(def_id);
if qualified {
if let Some(parent) = def_key.parent {
push_item_name(tcx, DefId { krate: def_id.krate, index: parent }, true, output);
output.push_str("::");
}
if qualified && let Some(parent) = def_key.parent {
push_item_name(tcx, DefId { krate: def_id.krate, index: parent }, true, output);
output.push_str("::");
}
push_unqualified_item_name(tcx, def_id, def_key.disambiguated_data, output);

View file

@ -163,25 +163,25 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
mergeable_succ: bool,
) -> MergingSucc {
let tcx = bx.tcx();
if let Some(instance) = instance {
if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance) {
if destination.is_some() {
let caller_def = fx.instance.def_id();
let e = CompilerBuiltinsCannotCall {
span: tcx.def_span(caller_def),
caller: with_no_trimmed_paths!(tcx.def_path_str(caller_def)),
callee: with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())),
};
tcx.dcx().emit_err(e);
} else {
info!(
"compiler_builtins call to diverging function {:?} replaced with abort",
instance.def_id()
);
bx.abort();
bx.unreachable();
return MergingSucc::False;
}
if let Some(instance) = instance
&& is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance)
{
if destination.is_some() {
let caller_def = fx.instance.def_id();
let e = CompilerBuiltinsCannotCall {
span: tcx.def_span(caller_def),
caller: with_no_trimmed_paths!(tcx.def_path_str(caller_def)),
callee: with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())),
};
tcx.dcx().emit_err(e);
} else {
info!(
"compiler_builtins call to diverging function {:?} replaced with abort",
instance.def_id()
);
bx.abort();
bx.unreachable();
return MergingSucc::False;
}
}

View file

@ -837,15 +837,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value {
// ZST are passed as operands and require special handling
// because codegen_place() panics if Local is operand.
if let Some(index) = place.as_local() {
if let LocalRef::Operand(op) = self.locals[index] {
if let ty::Array(_, n) = op.layout.ty.kind() {
let n = n
.try_to_target_usize(bx.tcx())
.expect("expected monomorphic const in codegen");
return bx.cx().const_usize(n);
}
}
if let Some(index) = place.as_local()
&& let LocalRef::Operand(op) = self.locals[index]
&& let ty::Array(_, n) = op.layout.ty.kind()
{
let n = n.try_to_target_usize(bx.tcx()).expect("expected monomorphic const in codegen");
return bx.cx().const_usize(n);
}
// use common size calculation for non zero-sized types
let cg_value = self.codegen_place(bx, place.as_ref());

View file

@ -17,10 +17,13 @@ fn get_dangling_iterator<'a>() -> Iter<'a, i32> {
}
```
Local variables, function parameters and temporaries are all dropped before the
end of the function body. So a reference to them cannot be returned.
Local variables, function parameters and temporaries are all dropped before
the end of the function body. A returned reference (or struct containing a
reference) to such a dropped value would immediately be invalid. Therefore
it is not allowed to return such a reference.
Consider returning an owned value instead:
Consider returning a value that takes ownership of local data instead of
referencing it:
```
use std::vec::IntoIter;

View file

@ -3755,7 +3755,10 @@ pub enum UseKind {
/// One import, e.g., `use foo::bar` or `use foo::bar as baz`.
/// Also produced for each element of a list `use`, e.g.
/// `use foo::{a, b}` lowers to `use foo::a; use foo::b;`.
Single,
///
/// The identifier is the name defined by the import. E.g. for `use
/// foo::bar` it is `bar`, for `use foo::bar as baz` it is `baz`.
Single(Ident),
/// Glob import, e.g., `use foo::*`.
Glob,
@ -3897,8 +3900,6 @@ impl ItemId {
/// An item
///
/// The name might be a dummy name in case of anonymous items
///
/// For more details, see the [rust lang reference].
/// Note that the reference does not document nightly-only features.
/// There may be also slight differences in the names and representation of AST nodes between
@ -3907,7 +3908,6 @@ impl ItemId {
/// [rust lang reference]: https://doc.rust-lang.org/reference/items.html
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Item<'hir> {
pub ident: Ident,
pub owner_id: OwnerId,
pub kind: ItemKind<'hir>,
pub span: Span,
@ -3937,46 +3937,56 @@ impl<'hir> Item<'hir> {
}
expect_methods_self_kind! {
expect_extern_crate, Option<Symbol>, ItemKind::ExternCrate(s), *s;
expect_extern_crate, (Option<Symbol>, Ident),
ItemKind::ExternCrate(s, ident), (*s, *ident);
expect_use, (&'hir UsePath<'hir>, UseKind), ItemKind::Use(p, uk), (p, *uk);
expect_static, (&'hir Ty<'hir>, Mutability, BodyId),
ItemKind::Static(ty, mutbl, body), (ty, *mutbl, *body);
expect_static, (Ident, &'hir Ty<'hir>, Mutability, BodyId),
ItemKind::Static(ident, ty, mutbl, body), (*ident, ty, *mutbl, *body);
expect_const, (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
ItemKind::Const(ty, generics, body), (ty, generics, *body);
expect_const, (Ident, &'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
ItemKind::Const(ident, ty, generics, body), (*ident, ty, generics, *body);
expect_fn, (&FnSig<'hir>, &'hir Generics<'hir>, BodyId),
ItemKind::Fn { sig, generics, body, .. }, (sig, generics, *body);
expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId),
ItemKind::Fn { ident, sig, generics, body, .. }, (*ident, sig, generics, *body);
expect_macro, (&ast::MacroDef, MacroKind), ItemKind::Macro(def, mk), (def, *mk);
expect_macro, (Ident, &ast::MacroDef, MacroKind),
ItemKind::Macro(ident, def, mk), (*ident, def, *mk);
expect_mod, &'hir Mod<'hir>, ItemKind::Mod(m), m;
expect_mod, (Ident, &'hir Mod<'hir>), ItemKind::Mod(ident, m), (*ident, m);
expect_foreign_mod, (ExternAbi, &'hir [ForeignItemRef]),
ItemKind::ForeignMod { abi, items }, (*abi, items);
expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm { asm, .. }, asm;
expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>),
ItemKind::TyAlias(ty, generics), (ty, generics);
expect_ty_alias, (Ident, &'hir Ty<'hir>, &'hir Generics<'hir>),
ItemKind::TyAlias(ident, ty, generics), (*ident, ty, generics);
expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, generics), (def, generics);
expect_enum, (Ident, &EnumDef<'hir>, &'hir Generics<'hir>),
ItemKind::Enum(ident, def, generics), (*ident, def, generics);
expect_struct, (&VariantData<'hir>, &'hir Generics<'hir>),
ItemKind::Struct(data, generics), (data, generics);
expect_struct, (Ident, &VariantData<'hir>, &'hir Generics<'hir>),
ItemKind::Struct(ident, data, generics), (*ident, data, generics);
expect_union, (&VariantData<'hir>, &'hir Generics<'hir>),
ItemKind::Union(data, generics), (data, generics);
expect_union, (Ident, &VariantData<'hir>, &'hir Generics<'hir>),
ItemKind::Union(ident, data, generics), (*ident, data, generics);
expect_trait,
(IsAuto, Safety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
ItemKind::Trait(is_auto, safety, generics, bounds, items),
(*is_auto, *safety, generics, bounds, items);
(
IsAuto,
Safety,
Ident,
&'hir Generics<'hir>,
GenericBounds<'hir>,
&'hir [TraitItemRef]
),
ItemKind::Trait(is_auto, safety, ident, generics, bounds, items),
(*is_auto, *safety, *ident, generics, bounds, items);
expect_trait_alias, (&'hir Generics<'hir>, GenericBounds<'hir>),
ItemKind::TraitAlias(generics, bounds), (generics, bounds);
expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds);
expect_impl, &'hir Impl<'hir>, ItemKind::Impl(imp), imp;
}
@ -4094,7 +4104,7 @@ pub enum ItemKind<'hir> {
/// An `extern crate` item, with optional *original* crate name if the crate was renamed.
///
/// E.g., `extern crate foo` or `extern crate foo_bar as foo`.
ExternCrate(Option<Symbol>),
ExternCrate(Option<Symbol>, Ident),
/// `use foo::bar::*;` or `use foo::bar::baz as quux;`
///
@ -4104,11 +4114,12 @@ pub enum ItemKind<'hir> {
Use(&'hir UsePath<'hir>, UseKind),
/// A `static` item.
Static(&'hir Ty<'hir>, Mutability, BodyId),
Static(Ident, &'hir Ty<'hir>, Mutability, BodyId),
/// A `const` item.
Const(&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
Const(Ident, &'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
/// A function declaration.
Fn {
ident: Ident,
sig: FnSig<'hir>,
generics: &'hir Generics<'hir>,
body: BodyId,
@ -4118,9 +4129,9 @@ pub enum ItemKind<'hir> {
has_body: bool,
},
/// A MBE macro definition (`macro_rules!` or `macro`).
Macro(&'hir ast::MacroDef, MacroKind),
Macro(Ident, &'hir ast::MacroDef, MacroKind),
/// A module.
Mod(&'hir Mod<'hir>),
Mod(Ident, &'hir Mod<'hir>),
/// An external module, e.g. `extern { .. }`.
ForeignMod { abi: ExternAbi, items: &'hir [ForeignItemRef] },
/// Module-level inline assembly (from `global_asm!`).
@ -4134,17 +4145,17 @@ pub enum ItemKind<'hir> {
fake_body: BodyId,
},
/// A type alias, e.g., `type Foo = Bar<u8>`.
TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
/// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`.
Enum(EnumDef<'hir>, &'hir Generics<'hir>),
TyAlias(Ident, &'hir Ty<'hir>, &'hir Generics<'hir>),
/// An enum definition, e.g., `enum Foo<A, B> { C<A>, D<B> }`.
Enum(Ident, EnumDef<'hir>, &'hir Generics<'hir>),
/// A struct definition, e.g., `struct Foo<A> {x: A}`.
Struct(VariantData<'hir>, &'hir Generics<'hir>),
Struct(Ident, VariantData<'hir>, &'hir Generics<'hir>),
/// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`.
Union(VariantData<'hir>, &'hir Generics<'hir>),
Union(Ident, VariantData<'hir>, &'hir Generics<'hir>),
/// A trait definition.
Trait(IsAuto, Safety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
Trait(IsAuto, Safety, Ident, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
/// A trait alias.
TraitAlias(&'hir Generics<'hir>, GenericBounds<'hir>),
TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
/// An implementation, e.g., `impl<A> Trait for Foo { .. }`.
Impl(&'hir Impl<'hir>),
@ -4173,16 +4184,39 @@ pub struct Impl<'hir> {
}
impl ItemKind<'_> {
pub fn ident(&self) -> Option<Ident> {
match *self {
ItemKind::ExternCrate(_, ident)
| ItemKind::Use(_, UseKind::Single(ident))
| ItemKind::Static(ident, ..)
| ItemKind::Const(ident, ..)
| ItemKind::Fn { ident, .. }
| ItemKind::Macro(ident, ..)
| ItemKind::Mod(ident, ..)
| ItemKind::TyAlias(ident, ..)
| ItemKind::Enum(ident, ..)
| ItemKind::Struct(ident, ..)
| ItemKind::Union(ident, ..)
| ItemKind::Trait(_, _, ident, ..)
| ItemKind::TraitAlias(ident, ..) => Some(ident),
ItemKind::Use(_, UseKind::Glob | UseKind::ListStem)
| ItemKind::ForeignMod { .. }
| ItemKind::GlobalAsm { .. }
| ItemKind::Impl(_) => None,
}
}
pub fn generics(&self) -> Option<&Generics<'_>> {
Some(match self {
ItemKind::Fn { generics, .. }
| ItemKind::TyAlias(_, generics)
| ItemKind::Const(_, generics, _)
| ItemKind::Enum(_, generics)
| ItemKind::Struct(_, generics)
| ItemKind::Union(_, generics)
| ItemKind::Trait(_, _, generics, _, _)
| ItemKind::TraitAlias(generics, _)
| ItemKind::TyAlias(_, _, generics)
| ItemKind::Const(_, _, generics, _)
| ItemKind::Enum(_, _, generics)
| ItemKind::Struct(_, _, generics)
| ItemKind::Union(_, _, generics)
| ItemKind::Trait(_, _, _, generics, _, _)
| ItemKind::TraitAlias(_, generics, _)
| ItemKind::Impl(Impl { generics, .. }) => generics,
_ => return None,
})
@ -4374,8 +4408,8 @@ impl<'hir> OwnerNode<'hir> {
match self {
OwnerNode::Item(Item {
kind:
ItemKind::Static(_, _, body)
| ItemKind::Const(_, _, body)
ItemKind::Static(_, _, _, body)
| ItemKind::Const(_, _, _, body)
| ItemKind::Fn { body, .. },
..
})
@ -4518,12 +4552,12 @@ impl<'hir> Node<'hir> {
/// ```
pub fn ident(&self) -> Option<Ident> {
match self {
Node::Item(item) => item.kind.ident(),
Node::TraitItem(TraitItem { ident, .. })
| Node::ImplItem(ImplItem { ident, .. })
| Node::ForeignItem(ForeignItem { ident, .. })
| Node::Field(FieldDef { ident, .. })
| Node::Variant(Variant { ident, .. })
| Node::Item(Item { ident, .. })
| Node::PathSegment(PathSegment { ident, .. }) => Some(*ident),
Node::Lifetime(lt) => Some(lt.ident),
Node::GenericParam(p) => Some(p.name.ident()),
@ -4599,9 +4633,9 @@ impl<'hir> Node<'hir> {
pub fn ty(self) -> Option<&'hir Ty<'hir>> {
match self {
Node::Item(it) => match it.kind {
ItemKind::TyAlias(ty, _)
| ItemKind::Static(ty, _, _)
| ItemKind::Const(ty, _, _) => Some(ty),
ItemKind::TyAlias(_, ty, _)
| ItemKind::Static(_, ty, _, _)
| ItemKind::Const(_, ty, _, _) => Some(ty),
ItemKind::Impl(impl_item) => Some(&impl_item.self_ty),
_ => None,
},
@ -4621,7 +4655,7 @@ impl<'hir> Node<'hir> {
pub fn alias_ty(self) -> Option<&'hir Ty<'hir>> {
match self {
Node::Item(Item { kind: ItemKind::TyAlias(ty, ..), .. }) => Some(ty),
Node::Item(Item { kind: ItemKind::TyAlias(_, ty, _), .. }) => Some(ty),
_ => None,
}
}
@ -4632,7 +4666,9 @@ impl<'hir> Node<'hir> {
Node::Item(Item {
owner_id,
kind:
ItemKind::Const(_, _, body) | ItemKind::Static(.., body) | ItemKind::Fn { body, .. },
ItemKind::Const(_, _, _, body)
| ItemKind::Static(.., body)
| ItemKind::Fn { body, .. },
..
})
| Node::TraitItem(TraitItem {
@ -4693,8 +4729,8 @@ impl<'hir> Node<'hir> {
pub fn fn_kind(self) -> Option<FnKind<'hir>> {
match self {
Node::Item(i) => match i.kind {
ItemKind::Fn { sig, generics, .. } => {
Some(FnKind::ItemFn(i.ident, generics, sig.header))
ItemKind::Fn { ident, sig, generics, .. } => {
Some(FnKind::ItemFn(ident, generics, sig.header))
}
_ => None,
},
@ -4767,7 +4803,7 @@ mod size_asserts {
static_assert_size!(ImplItem<'_>, 88);
static_assert_size!(ImplItemKind<'_>, 40);
static_assert_size!(Item<'_>, 88);
static_assert_size!(ItemKind<'_>, 56);
static_assert_size!(ItemKind<'_>, 64);
static_assert_size!(LetStmt<'_>, 64);
static_assert_size!(Param<'_>, 32);
static_assert_size!(Pat<'_>, 72);

View file

@ -533,34 +533,44 @@ pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) ->
pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result {
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(visitor.visit_ident(item.ident));
match item.kind {
ItemKind::ExternCrate(orig_name) => {
ItemKind::ExternCrate(orig_name, ident) => {
visit_opt!(visitor, visit_name, orig_name);
try_visit!(visitor.visit_ident(ident));
}
ItemKind::Use(ref path, _) => {
ItemKind::Use(ref path, kind) => {
try_visit!(visitor.visit_use(path, item.hir_id()));
match kind {
UseKind::Single(ident) => try_visit!(visitor.visit_ident(ident)),
UseKind::Glob | UseKind::ListStem => {}
}
}
ItemKind::Static(ref typ, _, body) => {
ItemKind::Static(ident, ref typ, _, body) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_ty_unambig(typ));
try_visit!(visitor.visit_nested_body(body));
}
ItemKind::Const(ref typ, ref generics, body) => {
ItemKind::Const(ident, ref typ, ref generics, body) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_ty_unambig(typ));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_nested_body(body));
}
ItemKind::Fn { sig, generics, body: body_id, .. } => {
ItemKind::Fn { ident, sig, generics, body: body_id, .. } => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_fn(
FnKind::ItemFn(item.ident, generics, sig.header),
FnKind::ItemFn(ident, generics, sig.header),
sig.decl,
body_id,
item.span,
item.owner_id.def_id,
));
}
ItemKind::Macro(..) => {}
ItemKind::Mod(ref module) => {
ItemKind::Macro(ident, _def, _kind) => {
try_visit!(visitor.visit_ident(ident));
}
ItemKind::Mod(ident, ref module) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_mod(module, item.span, item.hir_id()));
}
ItemKind::ForeignMod { abi: _, items } => {
@ -573,11 +583,13 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
// typeck results set correctly.
try_visit!(visitor.visit_nested_body(fake_body));
}
ItemKind::TyAlias(ref ty, ref generics) => {
ItemKind::TyAlias(ident, ref ty, ref generics) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_ty_unambig(ty));
try_visit!(visitor.visit_generics(generics));
}
ItemKind::Enum(ref enum_definition, ref generics) => {
ItemKind::Enum(ident, ref enum_definition, ref generics) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_enum_def(enum_definition));
}
@ -597,17 +609,20 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
try_visit!(visitor.visit_ty_unambig(self_ty));
walk_list!(visitor, visit_impl_item_ref, *items);
}
ItemKind::Struct(ref struct_definition, ref generics)
| ItemKind::Union(ref struct_definition, ref generics) => {
ItemKind::Struct(ident, ref struct_definition, ref generics)
| ItemKind::Union(ident, ref struct_definition, ref generics) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_variant_data(struct_definition));
}
ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => {
ItemKind::Trait(_is_auto, _safety, ident, ref generics, bounds, trait_item_refs) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
}
ItemKind::TraitAlias(ref generics, bounds) => {
ItemKind::TraitAlias(ident, ref generics, bounds) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds);
}

View file

@ -269,26 +269,26 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
}
res
}
hir::ItemKind::Fn { sig, .. } => {
check_item_fn(tcx, def_id, item.ident, item.span, sig.decl)
hir::ItemKind::Fn { ident, sig, .. } => {
check_item_fn(tcx, def_id, ident, item.span, sig.decl)
}
hir::ItemKind::Static(ty, ..) => {
hir::ItemKind::Static(_, ty, ..) => {
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid)
}
hir::ItemKind::Const(ty, ..) => {
hir::ItemKind::Const(_, ty, ..) => {
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid)
}
hir::ItemKind::Struct(_, hir_generics) => {
hir::ItemKind::Struct(_, _, hir_generics) => {
let res = check_type_defn(tcx, item, false);
check_variances_for_type_defn(tcx, item, hir_generics);
res
}
hir::ItemKind::Union(_, hir_generics) => {
hir::ItemKind::Union(_, _, hir_generics) => {
let res = check_type_defn(tcx, item, true);
check_variances_for_type_defn(tcx, item, hir_generics);
res
}
hir::ItemKind::Enum(_, hir_generics) => {
hir::ItemKind::Enum(_, _, hir_generics) => {
let res = check_type_defn(tcx, item, true);
check_variances_for_type_defn(tcx, item, hir_generics);
res
@ -297,7 +297,9 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
hir::ItemKind::TraitAlias(..) => check_trait(tcx, item),
// `ForeignItem`s are handled separately.
hir::ItemKind::ForeignMod { .. } => Ok(()),
hir::ItemKind::TyAlias(hir_ty, hir_generics) if tcx.type_alias_is_lazy(item.owner_id) => {
hir::ItemKind::TyAlias(_, hir_ty, hir_generics)
if tcx.type_alias_is_lazy(item.owner_id) =>
{
let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| {
let ty = tcx.type_of(def_id).instantiate_identity();
let item_ty = wfcx.normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty);
@ -822,10 +824,10 @@ fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
///
/// In such cases, suggest using `Self` instead.
fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) {
let (trait_name, trait_def_id) =
let (trait_ident, trait_def_id) =
match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(item.hir_id()).def_id) {
hir::Node::Item(item) => match item.kind {
hir::ItemKind::Trait(..) => (item.ident, item.owner_id),
hir::ItemKind::Trait(_, _, ident, ..) => (ident, item.owner_id),
_ => return,
},
_ => return,
@ -862,7 +864,7 @@ fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitI
trait_should_be_self,
"associated item referring to unboxed trait object for its own trait",
)
.with_span_label(trait_name.span, "in this trait")
.with_span_label(trait_ident.span, "in this trait")
.with_multipart_suggestion(
"you might have meant to use `Self` to refer to the implementing type",
sugg,

View file

@ -247,13 +247,13 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
item: &'tcx hir::Item<'tcx>,
) {
let (generics, suggest) = match &item.kind {
hir::ItemKind::Union(_, generics)
| hir::ItemKind::Enum(_, generics)
| hir::ItemKind::TraitAlias(generics, _)
| hir::ItemKind::Trait(_, _, generics, ..)
hir::ItemKind::Union(_, _, generics)
| hir::ItemKind::Enum(_, _, generics)
| hir::ItemKind::TraitAlias(_, generics, _)
| hir::ItemKind::Trait(_, _, _, generics, ..)
| hir::ItemKind::Impl(hir::Impl { generics, .. })
| hir::ItemKind::Struct(_, generics) => (generics, true),
hir::ItemKind::TyAlias(_, generics) => (generics, false),
| hir::ItemKind::Struct(_, _, generics) => (generics, true),
hir::ItemKind::TyAlias(_, _, generics) => (generics, false),
// `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
_ => return,
};
@ -470,9 +470,9 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
.tcx
.hir_expect_item(self.tcx.hir_get_parent_item(self.hir_id()).def_id);
match &item.kind {
hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Struct(_, generics)
| hir::ItemKind::Union(_, generics) => {
hir::ItemKind::Enum(_, _, generics)
| hir::ItemKind::Struct(_, _, generics)
| hir::ItemKind::Union(_, _, generics) => {
let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics);
let (lt_sp, sugg) = match generics.params {
[] => (generics.span, format!("<{lt_name}>")),
@ -667,16 +667,16 @@ fn get_new_lifetime_name<'tcx>(
#[instrument(level = "debug", skip_all)]
fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
let it = tcx.hir_item(item_id);
debug!(item = %it.ident, id = %it.hir_id());
debug!(item = ?it.kind.ident(), id = %it.hir_id());
let def_id = item_id.owner_id.def_id;
let icx = ItemCtxt::new(tcx, def_id);
match &it.kind {
// These don't define types.
hir::ItemKind::ExternCrate(_)
hir::ItemKind::ExternCrate(..)
| hir::ItemKind::Use(..)
| hir::ItemKind::Macro(..)
| hir::ItemKind::Mod(_)
| hir::ItemKind::Mod(..)
| hir::ItemKind::GlobalAsm { .. } => {}
hir::ItemKind::ForeignMod { items, .. } => {
for item in *items {
@ -736,7 +736,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
tcx.at(it.span).explicit_super_predicates_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
}
hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => {
hir::ItemKind::Struct(_, struct_def, _) | hir::ItemKind::Union(_, struct_def, _) => {
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
@ -758,7 +758,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
tcx.ensure_ok().predicates_of(def_id);
}
hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..) => {
hir::ItemKind::Static(_, ty, ..) | hir::ItemKind::Const(_, ty, ..) => {
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
@ -1089,7 +1089,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
let repr = tcx.repr_options_of_def(def_id);
let (kind, variants) = match &item.kind {
ItemKind::Enum(def, _) => {
ItemKind::Enum(_, def, _) => {
let mut distance_from_explicit = 0;
let variants = def
.variants
@ -1117,7 +1117,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
(AdtKind::Enum, variants)
}
ItemKind::Struct(def, _) | ItemKind::Union(def, _) => {
ItemKind::Struct(ident, def, _) | ItemKind::Union(ident, def, _) => {
let adt_kind = match item.kind {
ItemKind::Struct(..) => AdtKind::Struct,
_ => AdtKind::Union,
@ -1125,7 +1125,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
let variants = std::iter::once(lower_variant(
tcx,
None,
item.ident,
*ident,
ty::VariantDiscr::Relative(0),
def,
adt_kind,

View file

@ -134,7 +134,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
};
tcx.vtable_entries(trait_ref)
}
hir::ItemKind::TyAlias(_, _) => {
hir::ItemKind::TyAlias(..) => {
let ty = tcx.type_of(def_id).instantiate_identity();
if ty.has_non_region_param() {
tcx.dcx().span_err(

View file

@ -163,7 +163,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}
}
ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => {
ItemKind::Trait(_, _, _, _, self_bounds, ..)
| ItemKind::TraitAlias(_, _, self_bounds) => {
is_trait = Some(self_bounds);
}
_ => {}
@ -615,7 +616,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
let (generics, superbounds) = match item.kind {
hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits),
hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits),
hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
_ => span_bug!(item.span, "super_predicates invoked on non-trait"),
};
@ -959,7 +960,7 @@ pub(super) fn const_conditions<'tcx>(
Node::Item(item) => match item.kind {
hir::ItemKind::Impl(impl_) => (impl_.generics, None, false),
hir::ItemKind::Fn { generics, .. } => (generics, None, false),
hir::ItemKind::Trait(_, _, generics, supertraits, _) => {
hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => {
(generics, Some((item.owner_id.def_id, supertraits)), false)
}
_ => bug!("const_conditions called on wrong item: {def_id:?}"),

View file

@ -617,7 +617,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
});
}
hir::ItemKind::ExternCrate(_)
hir::ItemKind::ExternCrate(..)
| hir::ItemKind::Use(..)
| hir::ItemKind::Macro(..)
| hir::ItemKind::Mod(..)
@ -627,13 +627,13 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
// These sorts of items have no lifetime parameters at all.
intravisit::walk_item(self, item);
}
hir::ItemKind::TyAlias(_, generics)
| hir::ItemKind::Const(_, generics, _)
| hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Struct(_, generics)
| hir::ItemKind::Union(_, generics)
| hir::ItemKind::Trait(_, _, generics, ..)
| hir::ItemKind::TraitAlias(generics, ..)
hir::ItemKind::TyAlias(_, _, generics)
| hir::ItemKind::Const(_, _, generics, _)
| hir::ItemKind::Enum(_, _, generics)
| hir::ItemKind::Struct(_, _, generics)
| hir::ItemKind::Union(_, _, generics)
| hir::ItemKind::Trait(_, _, _, generics, ..)
| hir::ItemKind::TraitAlias(_, generics, ..)
| hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
// These kinds of items have only early-bound lifetime parameters.
self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item));

View file

@ -202,35 +202,35 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
},
Node::Item(item) => match item.kind {
ItemKind::Static(ty, .., body_id) => {
ItemKind::Static(ident, ty, .., body_id) => {
if ty.is_suggestable_infer_ty() {
infer_placeholder_type(
icx.lowerer(),
def_id,
body_id,
ty.span,
item.ident,
ident,
"static variable",
)
} else {
icx.lower_ty(ty)
}
}
ItemKind::Const(ty, _, body_id) => {
ItemKind::Const(ident, ty, _, body_id) => {
if ty.is_suggestable_infer_ty() {
infer_placeholder_type(
icx.lowerer(),
def_id,
body_id,
ty.span,
item.ident,
ident,
"constant",
)
} else {
icx.lower_ty(ty)
}
}
ItemKind::TyAlias(self_ty, _) => icx.lower_ty(self_ty),
ItemKind::TyAlias(_, self_ty, _) => icx.lower_ty(self_ty),
ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
spans if spans.len() > 0 => {
let guar = tcx
@ -479,5 +479,5 @@ pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) ->
}
}
}
HasTait.visit_ty_unambig(tcx.hir_expect_item(def_id).expect_ty_alias().0).is_break()
HasTait.visit_ty_unambig(tcx.hir_expect_item(def_id).expect_ty_alias().1).is_break()
}

View file

@ -140,14 +140,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let generics = match tcx.hir_node_by_def_id(parent_item) {
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Struct(variant, generics), ..
kind: hir::ItemKind::Struct(_, variant, generics),
..
}) => {
if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) {
return false;
}
generics
}
hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(def, generics), .. }) => {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, def, generics), .. }) => {
if !def
.variants
.iter()
@ -267,7 +268,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::Node::Field(field) => {
// Enums can't have unsized fields, fields can only have an unsized tail field.
if let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Struct(variant, _), ..
kind: hir::ItemKind::Struct(_, variant, _), ..
}) = tcx.parent_hir_node(field.hir_id)
&& variant
.fields()

View file

@ -136,9 +136,9 @@ fn diagnostic_hir_wf_check<'tcx>(
ref item => bug!("Unexpected TraitItem {:?}", item),
},
hir::Node::Item(item) => match item.kind {
hir::ItemKind::TyAlias(ty, _)
| hir::ItemKind::Static(ty, _, _)
| hir::ItemKind::Const(ty, _, _) => vec![ty],
hir::ItemKind::TyAlias(_, ty, _)
| hir::ItemKind::Static(_, ty, _, _)
| hir::ItemKind::Const(_, ty, _, _) => vec![ty],
hir::ItemKind::Impl(impl_) => match &impl_.of_trait {
Some(t) => t
.path

View file

@ -559,7 +559,7 @@ impl<'a> State<'a> {
self.print_attrs_as_outer(attrs);
self.ann.pre(self, AnnNode::Item(item));
match item.kind {
hir::ItemKind::ExternCrate(orig_name) => {
hir::ItemKind::ExternCrate(orig_name, ident) => {
self.head("extern crate");
if let Some(orig_name) = orig_name {
self.print_name(orig_name);
@ -567,7 +567,7 @@ impl<'a> State<'a> {
self.word("as");
self.space();
}
self.print_ident(item.ident);
self.print_ident(ident);
self.word(";");
self.end(); // end inner head-block
self.end(); // end outer head-block
@ -577,11 +577,11 @@ impl<'a> State<'a> {
self.print_path(path, false);
match kind {
hir::UseKind::Single => {
if path.segments.last().unwrap().ident != item.ident {
hir::UseKind::Single(ident) => {
if path.segments.last().unwrap().ident != ident {
self.space();
self.word_space("as");
self.print_ident(item.ident);
self.print_ident(ident);
}
self.word(";");
}
@ -591,12 +591,12 @@ impl<'a> State<'a> {
self.end(); // end inner head-block
self.end(); // end outer head-block
}
hir::ItemKind::Static(ty, m, expr) => {
hir::ItemKind::Static(ident, ty, m, expr) => {
self.head("static");
if m.is_mut() {
self.word_space("mut");
}
self.print_ident(item.ident);
self.print_ident(ident);
self.word_space(":");
self.print_type(ty);
self.space();
@ -607,9 +607,9 @@ impl<'a> State<'a> {
self.word(";");
self.end(); // end the outer cbox
}
hir::ItemKind::Const(ty, generics, expr) => {
hir::ItemKind::Const(ident, ty, generics, expr) => {
self.head("const");
self.print_ident(item.ident);
self.print_ident(ident);
self.print_generic_params(generics.params);
self.word_space(":");
self.print_type(ty);
@ -622,30 +622,23 @@ impl<'a> State<'a> {
self.word(";");
self.end(); // end the outer cbox
}
hir::ItemKind::Fn { sig, generics, body, .. } => {
hir::ItemKind::Fn { ident, sig, generics, body, .. } => {
self.head("");
self.print_fn(
sig.decl,
sig.header,
Some(item.ident.name),
generics,
&[],
Some(body),
);
self.print_fn(sig.decl, sig.header, Some(ident.name), generics, &[], Some(body));
self.word(" ");
self.end(); // need to close a box
self.end(); // need to close a box
self.ann.nested(self, Nested::Body(body));
}
hir::ItemKind::Macro(macro_def, _) => {
self.print_mac_def(macro_def, &item.ident, item.span, |_| {});
hir::ItemKind::Macro(ident, macro_def, _) => {
self.print_mac_def(macro_def, &ident, item.span, |_| {});
}
hir::ItemKind::Mod(_mod) => {
hir::ItemKind::Mod(ident, mod_) => {
self.head("mod");
self.print_ident(item.ident);
self.print_ident(ident);
self.nbsp();
self.bopen();
self.print_mod(_mod, attrs);
self.print_mod(mod_, attrs);
self.bclose(item.span);
}
hir::ItemKind::ForeignMod { abi, items } => {
@ -663,9 +656,9 @@ impl<'a> State<'a> {
self.print_inline_asm(asm);
self.end()
}
hir::ItemKind::TyAlias(ty, generics) => {
hir::ItemKind::TyAlias(ident, ty, generics) => {
self.head("type");
self.print_ident(item.ident);
self.print_ident(ident);
self.print_generic_params(generics.params);
self.end(); // end the inner ibox
@ -676,16 +669,16 @@ impl<'a> State<'a> {
self.word(";");
self.end(); // end the outer ibox
}
hir::ItemKind::Enum(ref enum_definition, params) => {
self.print_enum_def(enum_definition, params, item.ident.name, item.span);
hir::ItemKind::Enum(ident, ref enum_definition, params) => {
self.print_enum_def(enum_definition, params, ident.name, item.span);
}
hir::ItemKind::Struct(ref struct_def, generics) => {
hir::ItemKind::Struct(ident, ref struct_def, generics) => {
self.head("struct");
self.print_struct(struct_def, generics, item.ident.name, item.span, true);
self.print_struct(struct_def, generics, ident.name, item.span, true);
}
hir::ItemKind::Union(ref struct_def, generics) => {
hir::ItemKind::Union(ident, ref struct_def, generics) => {
self.head("union");
self.print_struct(struct_def, generics, item.ident.name, item.span, true);
self.print_struct(struct_def, generics, ident.name, item.span, true);
}
hir::ItemKind::Impl(&hir::Impl {
constness,
@ -733,12 +726,12 @@ impl<'a> State<'a> {
}
self.bclose(item.span);
}
hir::ItemKind::Trait(is_auto, safety, generics, bounds, trait_items) => {
hir::ItemKind::Trait(is_auto, safety, ident, generics, bounds, trait_items) => {
self.head("");
self.print_is_auto(is_auto);
self.print_safety(safety);
self.word_nbsp("trait");
self.print_ident(item.ident);
self.print_ident(ident);
self.print_generic_params(generics.params);
self.print_bounds(":", bounds);
self.print_where_clause(generics);
@ -749,9 +742,9 @@ impl<'a> State<'a> {
}
self.bclose(item.span);
}
hir::ItemKind::TraitAlias(generics, bounds) => {
hir::ItemKind::TraitAlias(ident, generics, bounds) => {
self.head("trait");
self.print_ident(item.ident);
self.print_ident(ident);
self.print_generic_params(generics.params);
self.nbsp();
self.print_bounds("=", bounds);

View file

@ -713,8 +713,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for id in self.tcx.hir_free_items() {
if let Some(node) = self.tcx.hir_get_if_local(id.owner_id.into())
&& let hir::Node::Item(item) = node
&& let hir::ItemKind::Fn { .. } = item.kind
&& item.ident.name == segment.ident.name
&& let hir::ItemKind::Fn { ident, .. } = item.kind
&& ident.name == segment.ident.name
{
err.span_label(
self.tcx.def_span(id.owner_id),

View file

@ -721,8 +721,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
)) => {
if let Some(hir::Node::Item(hir::Item {
ident,
kind: hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..),
kind:
hir::ItemKind::Static(ident, ty, ..)
| hir::ItemKind::Const(ident, ty, ..),
..
})) = self.tcx.hir_get_if_local(*def_id)
{

View file

@ -904,7 +904,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Assumes given function doesn't have a explicit return type.
fn can_add_return_type(&self, fn_id: LocalDefId) -> bool {
match self.tcx.hir_node_by_def_id(fn_id) {
Node::Item(&hir::Item { ident, .. }) => {
Node::Item(item) => {
let (ident, _, _, _) = item.expect_fn();
// This is less than ideal, it will not suggest a return type span on any
// method called `main`, regardless of whether it is actually the entry point,
// but it will still present it as the reason for the expected type.

View file

@ -367,20 +367,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.collect();
// Find an identifier with which this trait was imported (note that `_` doesn't count).
let any_id = import_items.iter().find_map(|item| {
if item.ident.name != kw::Underscore { Some(item.ident) } else { None }
});
if let Some(any_id) = any_id {
if any_id.name == kw::Empty {
// Glob import, so just use its name.
return None;
} else {
return Some(format!("{any_id}"));
for item in import_items.iter() {
let (_, kind) = item.expect_use();
match kind {
hir::UseKind::Single(ident) => {
if ident.name != kw::Underscore {
return Some(format!("{}", ident.name));
}
}
hir::UseKind::Glob => return None, // Glob import, so just use its name.
hir::UseKind::ListStem => unreachable!(),
}
}
// All that is left is `_`! We need to use the full path. It doesn't matter which one we pick,
// so just take the first one.
// All that is left is `_`! We need to use the full path. It doesn't matter which one we
// pick, so just take the first one.
match import_items[0].kind {
ItemKind::Use(path, _) => Some(
path.segments

View file

@ -1204,13 +1204,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
Some(
Node::Item(hir::Item {
ident,
kind: hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..),
kind:
hir::ItemKind::Trait(_, _, ident, ..)
| hir::ItemKind::TraitAlias(ident, ..),
..
})
// We may also encounter unsatisfied GAT or method bounds
| Node::TraitItem(hir::TraitItem { ident, .. })
| Node::ImplItem(hir::ImplItem { ident, .. }),
| Node::ImplItem(hir::ImplItem { ident, .. })
) => {
skip_list.insert(p);
let entry = spanned_predicates.entry(ident.span);
@ -3960,8 +3961,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
Node::Item(hir::Item {
kind: hir::ItemKind::Trait(.., bounds, _),
ident,
kind: hir::ItemKind::Trait(_, _, ident, _, bounds, _),
..
}) => {
let (sp, sep, article) = if bounds.is_empty() {

View file

@ -1250,7 +1250,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match opt_def_id {
Some(def_id) => match self.tcx.hir_get_if_local(def_id) {
Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Const(_, _, body_id),
kind: hir::ItemKind::Const(_, _, _, body_id),
..
})) => match self.tcx.hir_node(body_id.hir_id) {
hir::Node::Expr(expr) => {

View file

@ -441,7 +441,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
// so we will continue to exclude them for compatibility.
//
// The documentation on `ExternCrate` is not used at the moment so no need to warn for it.
if let hir::ItemKind::Impl(..) | hir::ItemKind::Use(..) | hir::ItemKind::ExternCrate(_) =
if let hir::ItemKind::Impl(..) | hir::ItemKind::Use(..) | hir::ItemKind::ExternCrate(..) =
it.kind
{
return;
@ -545,21 +545,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
return;
}
let (def, ty) = match item.kind {
hir::ItemKind::Struct(_, ast_generics) => {
hir::ItemKind::Struct(_, _, ast_generics) => {
if !ast_generics.params.is_empty() {
return;
}
let def = cx.tcx.adt_def(item.owner_id);
(def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
}
hir::ItemKind::Union(_, ast_generics) => {
hir::ItemKind::Union(_, _, ast_generics) => {
if !ast_generics.params.is_empty() {
return;
}
let def = cx.tcx.adt_def(item.owner_id);
(def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
}
hir::ItemKind::Enum(_, ast_generics) => {
hir::ItemKind::Enum(_, _, ast_generics) => {
if !ast_generics.params.is_empty() {
return;
}
@ -1416,7 +1416,7 @@ impl TypeAliasBounds {
impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
let hir::ItemKind::TyAlias(hir_ty, generics) = item.kind else { return };
let hir::ItemKind::TyAlias(_, hir_ty, generics) = item.kind else { return };
// There must not be a where clause.
if generics.predicates.is_empty() {
@ -2119,9 +2119,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
let def_id = item.owner_id.def_id;
if let hir::ItemKind::Struct(_, hir_generics)
| hir::ItemKind::Enum(_, hir_generics)
| hir::ItemKind::Union(_, hir_generics) = item.kind
if let hir::ItemKind::Struct(_, _, hir_generics)
| hir::ItemKind::Enum(_, _, hir_generics)
| hir::ItemKind::Union(_, _, hir_generics) = item.kind
{
let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
if inferred_outlives.is_empty() {
@ -2257,7 +2257,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
// generics, except for tuple struct, which have the `where`
// after the fields of the struct.
let full_where_span =
if let hir::ItemKind::Struct(hir::VariantData::Tuple(..), _) = item.kind {
if let hir::ItemKind::Struct(_, hir::VariantData::Tuple(..), _) = item.kind {
where_span
} else {
hir_generics.span.shrink_to_hi().to(where_span)

View file

@ -93,7 +93,11 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
let orig_fields = match cx.tcx.hir_get_if_local(type_def_id) {
Some(hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Struct(hir::VariantData::Struct { fields, recovered: _ }, _generics),
hir::ItemKind::Struct(
_,
hir::VariantData::Struct { fields, recovered: _ },
_generics,
),
..
})) => fields.iter().map(|f| (f.ident.name, f)).collect::<FxHashMap<_, _>>(),
_ => return,

View file

@ -308,18 +308,18 @@ impl<'tcx> LateLintPass<'tcx> for TypeIr {
[.., penultimate, segment]
if penultimate.res.opt_def_id().is_some_and(is_mod_inherent) =>
{
(segment.ident.span, item.ident.span, "*")
(segment.ident.span, item.kind.ident().unwrap().span, "*")
}
[.., segment]
if path.res.iter().flat_map(Res::opt_def_id).any(is_mod_inherent)
&& let rustc_hir::UseKind::Single = kind =>
&& let rustc_hir::UseKind::Single(ident) = kind =>
{
let (lo, snippet) =
match cx.tcx.sess.source_map().span_to_snippet(path.span).as_deref() {
Ok("self") => (path.span, "*"),
_ => (segment.ident.span.shrink_to_hi(), "::*"),
};
(lo, if segment.ident == item.ident { lo } else { item.ident.span }, snippet)
(lo, if segment.ident == ident { lo } else { ident.span }, snippet)
}
_ => return,
};

View file

@ -39,7 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
let def_id = item.owner_id.to_def_id();
// NOTE(nbdd0121): use `dyn_compatibility_violations` instead of `is_dyn_compatible` because
// the latter will report `where_clause_object_safety` lint.
if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind
if let hir::ItemKind::Trait(_, _, ident, ..) = item.kind
&& cx.tcx.is_dyn_compatible(def_id)
{
let direct_super_traits_iter = cx
@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
cx.emit_span_lint(
MULTIPLE_SUPERTRAIT_UPCASTABLE,
cx.tcx.def_span(def_id),
crate::lints::MultipleSupertraitUpcastable { ident: item.ident },
crate::lints::MultipleSupertraitUpcastable { ident },
);
}
}

View file

@ -181,10 +181,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
&& parent_opt_item_name != Some(kw::Underscore)
&& let Some(parent) = parent.as_local()
&& let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent)
&& let ItemKind::Const(ty, _, _) = item.kind
&& let ItemKind::Const(ident, ty, _, _) = item.kind
&& let TyKind::Tup(&[]) = ty.kind
{
Some(item.ident.span)
Some(ident.span)
} else {
None
};
@ -238,7 +238,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
},
)
}
ItemKind::Macro(_macro, MacroKind::Bang)
ItemKind::Macro(_, _macro, MacroKind::Bang)
if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) =>
{
cx.emit_span_lint(

View file

@ -415,8 +415,8 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
}
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
if let hir::ItemKind::Mod(_) = it.kind {
self.check_snake_case(cx, "module", &it.ident);
if let hir::ItemKind::Mod(ident, _) = it.kind {
self.check_snake_case(cx, "module", &ident);
}
}
@ -498,11 +498,13 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
let attrs = cx.tcx.hir_attrs(it.hir_id());
match it.kind {
hir::ItemKind::Static(..) if !ast::attr::contains_name(attrs, sym::no_mangle) => {
NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident);
hir::ItemKind::Static(ident, ..)
if !ast::attr::contains_name(attrs, sym::no_mangle) =>
{
NonUpperCaseGlobals::check_upper_case(cx, "static variable", &ident);
}
hir::ItemKind::Const(..) => {
NonUpperCaseGlobals::check_upper_case(cx, "constant", &it.ident);
hir::ItemKind::Const(ident, ..) => {
NonUpperCaseGlobals::check_upper_case(cx, "constant", &ident);
}
_ => {}
}

View file

@ -1664,7 +1664,7 @@ impl ImproperCTypesDefinitions {
&& cx.tcx.sess.target.os == "aix"
&& !adt_def.all_fields().next().is_none()
{
let struct_variant_data = item.expect_struct().0;
let struct_variant_data = item.expect_struct().1;
for (index, ..) in struct_variant_data.fields().iter().enumerate() {
// Struct fields (after the first field) are checked for the
// power alignment rule, as fields after the first are likely
@ -1696,9 +1696,9 @@ impl ImproperCTypesDefinitions {
impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
match item.kind {
hir::ItemKind::Static(ty, ..)
| hir::ItemKind::Const(ty, ..)
| hir::ItemKind::TyAlias(ty, ..) => {
hir::ItemKind::Static(_, ty, ..)
| hir::ItemKind::Const(_, ty, ..)
| hir::ItemKind::TyAlias(_, ty, ..) => {
self.check_ty_maybe_containing_foreign_fnptr(
cx,
ty,
@ -1765,7 +1765,7 @@ declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);
impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
if let hir::ItemKind::Enum(ref enum_definition, _) = it.kind {
if let hir::ItemKind::Enum(_, ref enum_definition, _) = it.kind {
let t = cx.tcx.type_of(it.owner_id).instantiate_identity();
let ty = cx.tcx.erase_regions(t);
let Ok(layout) = cx.layout_of(ty) else { return };

View file

@ -1835,7 +1835,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_info_for_macro(&mut self, def_id: LocalDefId) {
let tcx = self.tcx;
let hir::ItemKind::Macro(macro_def, _) = tcx.hir_expect_item(def_id).kind else { bug!() };
let (_, macro_def, _) = tcx.hir_expect_item(def_id).expect_macro();
self.tables.is_macro_rules.set(def_id.local_def_index, macro_def.macro_rules);
record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body);
}

View file

@ -385,7 +385,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn hir_get_module(self, module: LocalModDefId) -> (&'tcx Mod<'tcx>, Span, HirId) {
let hir_id = HirId::make_owner(module.to_local_def_id());
match self.hir_owner_node(hir_id.owner) {
OwnerNode::Item(&Item { span, kind: ItemKind::Mod(m), .. }) => (m, span, hir_id),
OwnerNode::Item(&Item { span, kind: ItemKind::Mod(_, m), .. }) => (m, span, hir_id),
OwnerNode::Crate(item) => (item, item.spans.inner_span, hir_id),
node => panic!("not a module: {node:?}"),
}
@ -847,7 +847,7 @@ impl<'tcx> TyCtxt<'tcx> {
// A `Ctor` doesn't have an identifier itself, but its parent
// struct/variant does. Compare with `hir::Map::span`.
Node::Ctor(..) => match self.parent_hir_node(id) {
Node::Item(item) => Some(item.ident),
Node::Item(item) => Some(item.kind.ident().unwrap()),
Node::Variant(variant) => Some(variant.ident),
_ => unreachable!(),
},
@ -894,18 +894,14 @@ impl<'hir> Map<'hir> {
}
fn named_span(item_span: Span, ident: Ident, generics: Option<&Generics<'_>>) -> Span {
if ident.name != kw::Empty {
let mut span = until_within(item_span, ident.span);
if let Some(g) = generics
&& !g.span.is_dummy()
&& let Some(g_span) = g.span.find_ancestor_inside(item_span)
{
span = span.to(g_span);
}
span
} else {
item_span
let mut span = until_within(item_span, ident.span);
if let Some(g) = generics
&& !g.span.is_dummy()
&& let Some(g_span) = g.span.find_ancestor_inside(item_span)
{
span = span.to(g_span);
}
span
}
let span = match self.tcx.hir_node(hir_id) {
@ -936,7 +932,7 @@ impl<'hir> Map<'hir> {
}) => until_within(*outer_span, generics.where_clause_span),
// Constants and Statics.
Node::Item(Item {
kind: ItemKind::Const(ty, ..) | ItemKind::Static(ty, ..),
kind: ItemKind::Const(_, ty, ..) | ItemKind::Static(_, ty, ..),
span: outer_span,
..
})
@ -957,7 +953,7 @@ impl<'hir> Map<'hir> {
}) => until_within(*outer_span, ty.span),
// With generics and bounds.
Node::Item(Item {
kind: ItemKind::Trait(_, _, generics, bounds, _),
kind: ItemKind::Trait(_, _, _, generics, bounds, _),
span: outer_span,
..
})
@ -977,7 +973,13 @@ impl<'hir> Map<'hir> {
// SyntaxContext of the path.
path.span.find_ancestor_in_same_ctxt(item.span).unwrap_or(item.span)
}
_ => named_span(item.span, item.ident, item.kind.generics()),
_ => {
if let Some(ident) = item.kind.ident() {
named_span(item.span, ident, item.kind.generics())
} else {
item.span
}
}
},
Node::Variant(variant) => named_span(variant.span, variant.ident, None),
Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)),
@ -1327,7 +1329,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
self.items.push(item.item_id());
// Items that are modules are handled here instead of in visit_mod.
if let ItemKind::Mod(module) = &item.kind {
if let ItemKind::Mod(_, module) = &item.kind {
self.submodules.push(item.owner_id);
// A module collector does not recurse inside nested modules.
if self.crate_collector {

View file

@ -3406,20 +3406,18 @@ define_print_and_forward_display! {
}
fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) {
// Iterate all local crate items no matter where they are defined.
// Iterate all (non-anonymous) local crate items no matter where they are defined.
for id in tcx.hir_free_items() {
if matches!(tcx.def_kind(id.owner_id), DefKind::Use) {
continue;
}
let item = tcx.hir_item(id);
if item.ident.name == kw::Empty {
continue;
}
let Some(ident) = item.kind.ident() else { continue };
let def_id = item.owner_id.to_def_id();
let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
collect_fn(&item.ident, ns, def_id);
collect_fn(&ident, ns, def_id);
}
// Now take care of extern crate items.

View file

@ -563,7 +563,7 @@ fn construct_const<'a, 'tcx>(
// Figure out what primary body this item has.
let (span, const_ty_span) = match tcx.hir_node(hir_id) {
Node::Item(hir::Item {
kind: hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _, _),
kind: hir::ItemKind::Static(_, ty, _, _) | hir::ItemKind::Const(_, ty, _, _),
span,
..
})

View file

@ -1044,7 +1044,6 @@ fn find_fallback_pattern_typo<'tcx>(
if let DefKind::Use = cx.tcx.def_kind(item.owner_id) {
// Look for consts being re-exported.
let item = cx.tcx.hir_expect_item(item.owner_id.def_id);
let use_name = item.ident.name;
let hir::ItemKind::Use(path, _) = item.kind else {
continue;
};
@ -1064,8 +1063,9 @@ fn find_fallback_pattern_typo<'tcx>(
{
// The const is accessible only through the re-export, point at
// the `use`.
imported.push(use_name);
imported_spans.push(item.ident.span);
let ident = item.kind.ident().unwrap();
imported.push(ident.name);
imported_spans.push(ident.span);
}
}
}

View file

@ -743,7 +743,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
match target {
Target::Struct => {
if let Some(ItemLike::Item(hir::Item {
kind: hir::ItemKind::Struct(hir::VariantData::Struct { fields, .. }, _),
kind: hir::ItemKind::Struct(_, hir::VariantData::Struct { fields, .. }, _),
..
})) = item
&& !fields.is_empty()
@ -1019,7 +1019,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
_ => None,
};
match item_kind {
Some(ItemKind::Mod(module)) => {
Some(ItemKind::Mod(_, module)) => {
if !module.item_ids.is_empty() {
self.dcx().emit_err(errors::DocKeywordEmptyMod { span: meta.span() });
return;
@ -1072,9 +1072,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
return;
};
match item.kind {
ItemKind::Enum(_, generics) | ItemKind::Struct(_, generics)
ItemKind::Enum(_, _, generics) | ItemKind::Struct(_, _, generics)
if generics.params.len() != 0 => {}
ItemKind::Trait(_, _, generics, _, items)
ItemKind::Trait(_, _, _, generics, _, items)
if generics.params.len() != 0
|| items.iter().any(|item| matches!(item.kind, AssocItemKind::Type)) => {}
_ => {
@ -2293,7 +2293,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
} else {
// special case when `#[macro_export]` is applied to a macro 2.0
let (macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro();
let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro();
let is_decl_macro = !macro_definition.macro_rules;
if is_decl_macro {
@ -2624,7 +2624,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
// Historically we've run more checks on non-exported than exported macros,
// so this lets us continue to run them while maintaining backwards compatibility.
// In the long run, the checks should be harmonized.
if let ItemKind::Macro(macro_def, _) = item.kind {
if let ItemKind::Macro(_, macro_def, _) = item.kind {
let def_id = item.owner_id.to_def_id();
if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
check_non_exported_macro_for_invalid_attrs(self.tcx, item);
@ -2736,7 +2736,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
}
fn is_c_like_enum(item: &Item<'_>) -> bool {
if let ItemKind::Enum(ref def, _) = item.kind {
if let ItemKind::Enum(_, ref def, _) = item.kind {
for variant in def.variants {
match variant.data {
hir::VariantData::Unit(..) => { /* continue */ }
@ -2784,7 +2784,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
.map(|id| tcx.hir_item(id))
.find(|item| !item.span.is_dummy()) // Skip prelude `use`s
.map(|item| errors::ItemFollowingInnerAttr {
span: item.ident.span,
span: if let Some(ident) = item.kind.ident() { ident.span } else { item.span },
kind: item.kind.descr(),
});
let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel {

View file

@ -751,7 +751,7 @@ fn check_item<'tcx>(
match tcx.def_kind(id.owner_id) {
DefKind::Enum => {
let item = tcx.hir_item(id);
if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
if let hir::ItemKind::Enum(_, ref enum_def, _) = item.kind {
if let Some(comes_from_allow) = allow_dead_code {
worklist.extend(
enum_def.variants.iter().map(|variant| (variant.def_id, comes_from_allow)),
@ -806,7 +806,7 @@ fn check_item<'tcx>(
}
DefKind::Struct => {
let item = tcx.hir_item(id);
if let hir::ItemKind::Struct(ref variant_data, _) = item.kind
if let hir::ItemKind::Struct(_, ref variant_data, _) = item.kind
&& let Some(ctor_def_id) = variant_data.ctor_def_id()
{
struct_constructors.insert(ctor_def_id, item.owner_id.def_id);
@ -987,7 +987,7 @@ impl<'tcx> DeadVisitor<'tcx> {
&& let Some(enum_did) = tcx.opt_parent(may_variant.to_def_id())
&& let Some(enum_local_id) = enum_did.as_local()
&& let Node::Item(item) = tcx.hir_node_by_def_id(enum_local_id)
&& let ItemKind::Enum(_, _) = item.kind
&& let ItemKind::Enum(..) = item.kind
{
enum_local_id
} else {
@ -1062,7 +1062,7 @@ impl<'tcx> DeadVisitor<'tcx> {
let tuple_fields = if let Some(parent_id) = parent_item
&& let node = tcx.hir_node_by_def_id(parent_id)
&& let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Struct(hir::VariantData::Tuple(fields, _, _), _),
kind: hir::ItemKind::Struct(_, hir::VariantData::Tuple(fields, _, _), _),
..
}) = node
{

View file

@ -204,7 +204,7 @@ impl<'tcx> ReachableContext<'tcx> {
}
}
hir::ItemKind::Const(_, _, init) => {
hir::ItemKind::Const(_, _, _, init) => {
// Only things actually ending up in the final constant value are reachable
// for codegen. Everything else is only needed during const-eval, so even if
// const-eval happens in a downstream crate, all they need is
@ -232,7 +232,7 @@ impl<'tcx> ReachableContext<'tcx> {
// These are normal, nothing reachable about these
// inherently and their children are already in the
// worklist, as determined by the privacy pass
hir::ItemKind::ExternCrate(_)
hir::ItemKind::ExternCrate(..)
| hir::ItemKind::Use(..)
| hir::ItemKind::TyAlias(..)
| hir::ItemKind::Macro(..)

View file

@ -430,7 +430,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
kind = AnnotationKind::DeprecationProhibited;
const_stab_inherit = InheritConstStability::Yes;
}
hir::ItemKind::Struct(ref sd, _) => {
hir::ItemKind::Struct(_, ref sd, _) => {
if let Some(ctor_def_id) = sd.ctor_def_id() {
self.annotate(
ctor_def_id,
@ -773,10 +773,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
match item.kind {
hir::ItemKind::ExternCrate(_) => {
hir::ItemKind::ExternCrate(_, ident) => {
// compiler-generated `extern crate` items have a dummy span.
// `std` is still checked for the `restricted-std` feature.
if item.span.is_dummy() && item.ident.name != sym::std {
if item.span.is_dummy() && ident.name != sym::std {
return;
}

View file

@ -574,7 +574,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
// privacy and mark them reachable.
DefKind::Macro(_) => {
let item = self.tcx.hir_expect_item(def_id);
if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind {
if let hir::ItemKind::Macro(_, MacroDef { macro_rules: false, .. }, _) = item.kind {
if vis.is_accessible_from(module, self.tcx) {
self.update(def_id, macro_ev, Level::Reachable);
}
@ -598,8 +598,8 @@ impl<'tcx> EmbargoVisitor<'tcx> {
DefKind::Struct | DefKind::Union => {
// While structs and unions have type privacy, their fields do not.
let item = self.tcx.hir_expect_item(def_id);
if let hir::ItemKind::Struct(ref struct_def, _)
| hir::ItemKind::Union(ref struct_def, _) = item.kind
if let hir::ItemKind::Struct(_, ref struct_def, _)
| hir::ItemKind::Union(_, ref struct_def, _) = item.kind
{
for field in struct_def.fields() {
let field_vis = self.tcx.local_visibility(field.def_id);
@ -653,7 +653,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
| hir::ItemKind::GlobalAsm { .. } => {}
// The interface is empty, and all nested items are processed by `visit_item`.
hir::ItemKind::Mod(..) => {}
hir::ItemKind::Macro(macro_def, _) => {
hir::ItemKind::Macro(_, macro_def, _) => {
if let Some(item_ev) = item_ev {
self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev);
}
@ -724,7 +724,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
}
}
}
hir::ItemKind::Enum(ref def, _) => {
hir::ItemKind::Enum(_, ref def, _) => {
if let Some(item_ev) = item_ev {
self.reach(item.owner_id.def_id, item_ev).generics().predicates();
}
@ -762,7 +762,8 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
}
}
}
hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
hir::ItemKind::Struct(_, ref struct_def, _)
| hir::ItemKind::Union(_, ref struct_def, _) => {
if let Some(item_ev) = item_ev {
self.reach(item.owner_id.def_id, item_ev).generics().predicates();
for field in struct_def.fields() {
@ -866,7 +867,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> {
self.effective_visibility_diagnostic(item.owner_id.def_id);
match item.kind {
hir::ItemKind::Enum(ref def, _) => {
hir::ItemKind::Enum(_, ref def, _) => {
for variant in def.variants.iter() {
self.effective_visibility_diagnostic(variant.def_id);
if let Some(ctor_def_id) = variant.data.ctor_def_id() {
@ -877,7 +878,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> {
}
}
}
hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
hir::ItemKind::Struct(_, ref def, _) | hir::ItemKind::Union(_, ref def, _) => {
if let Some(ctor_def_id) = def.ctor_def_id() {
self.effective_visibility_diagnostic(ctor_def_id);
}
@ -1636,7 +1637,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
}
DefKind::Enum => {
let item = tcx.hir_item(id);
if let hir::ItemKind::Enum(ref def, _) = item.kind {
if let hir::ItemKind::Enum(_, ref def, _) = item.kind {
self.check_unnameable(item.owner_id.def_id, effective_vis);
self.check(item.owner_id.def_id, item_visibility, effective_vis)
@ -1674,8 +1675,8 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
// Subitems of structs and unions have their own publicity.
DefKind::Struct | DefKind::Union => {
let item = tcx.hir_item(id);
if let hir::ItemKind::Struct(ref struct_def, _)
| hir::ItemKind::Union(ref struct_def, _) = item.kind
if let hir::ItemKind::Struct(_, ref struct_def, _)
| hir::ItemKind::Union(_, ref struct_def, _) = item.kind
{
self.check_unnameable(item.owner_id.def_id, effective_vis);
self.check(item.owner_id.def_id, item_visibility, effective_vis)

View file

@ -923,6 +923,28 @@ impl Target {
_ => unreachable!(),
}
}
"loongarch64" => {
// LoongArch handles ABI in a very sane way, being fully explicit via `llvm_abiname`
// about what the intended ABI is.
match &*self.llvm_abiname {
"ilp32d" | "lp64d" => {
// Requires d (which implies f), incompatible with nothing.
FeatureConstraints { required: &["d"], incompatible: &[] }
}
"ilp32f" | "lp64f" => {
// Requires f, incompatible with nothing.
FeatureConstraints { required: &["f"], incompatible: &[] }
}
"ilp32s" | "lp64s" => {
// The soft-float ABI does not require any features and is also not
// incompatible with any features. Rust targets explicitly specify the
// LLVM ABI names, which allows for enabling hard-float support even on
// soft-float targets, and ensures that the ABI behavior is as expected.
NOTHING
}
_ => unreachable!(),
}
}
_ => NOTHING,
}
}

View file

@ -2026,7 +2026,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
LetVisitor { span }.visit_body(body).break_value()
}
hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. }) => {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(_, ty, _, _), .. }) => {
Some(&ty.peel_refs().kind)
}
_ => None,

View file

@ -338,7 +338,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
..
},
hir::PathSegment {
ident: assoc_item_name,
ident: assoc_item_ident,
res: Res::Def(_, item_id),
..
},
@ -368,17 +368,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let Some(local_def_id) = data.trait_ref.def_id.as_local()
&& let hir::Node::Item(hir::Item {
ident: trait_name,
kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs),
kind: hir::ItemKind::Trait(_, _, trait_ident, _, _, trait_item_refs),
..
}) = self.tcx.hir_node_by_def_id(local_def_id)
&& let Some(method_ref) = trait_item_refs
.iter()
.find(|item_ref| item_ref.ident == *assoc_item_name)
.find(|item_ref| item_ref.ident == *assoc_item_ident)
{
err.span_label(
method_ref.span,
format!("`{trait_name}::{assoc_item_name}` defined here"),
format!("`{trait_ident}::{assoc_item_ident}` defined here"),
);
}

View file

@ -419,7 +419,12 @@ pub fn report_dyn_incompatibility<'tcx>(
) -> Diag<'tcx> {
let trait_str = tcx.def_path_str(trait_def_id);
let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node {
hir::Node::Item(item) => Some(item.ident.span),
hir::Node::Item(item) => match item.kind {
hir::ItemKind::Trait(_, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => {
Some(ident.span)
}
_ => unreachable!(),
},
_ => None,
});

View file

@ -267,8 +267,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let node = self.tcx.hir_node_by_def_id(body_id);
match node {
hir::Node::Item(hir::Item {
ident,
kind: hir::ItemKind::Trait(_, _, generics, bounds, _),
kind: hir::ItemKind::Trait(_, _, ident, generics, bounds, _),
..
}) if self_ty == self.tcx.types.self_param => {
assert!(param_ty);
@ -282,7 +281,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
None,
projection,
trait_pred,
Some((ident, bounds)),
Some((&ident, bounds)),
);
return;
}
@ -331,7 +330,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Trait(_, _, generics, ..)
hir::ItemKind::Trait(_, _, _, generics, ..)
| hir::ItemKind::Impl(hir::Impl { generics, .. }),
..
}) if projection.is_some() => {
@ -352,15 +351,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Struct(_, generics)
| hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Union(_, generics)
| hir::ItemKind::Trait(_, _, generics, ..)
hir::ItemKind::Struct(_, _, generics)
| hir::ItemKind::Enum(_, _, generics)
| hir::ItemKind::Union(_, _, generics)
| hir::ItemKind::Trait(_, _, _, generics, ..)
| hir::ItemKind::Impl(hir::Impl { generics, .. })
| hir::ItemKind::Fn { generics, .. }
| hir::ItemKind::TyAlias(_, generics)
| hir::ItemKind::Const(_, generics, _)
| hir::ItemKind::TraitAlias(generics, _),
| hir::ItemKind::TyAlias(_, _, generics)
| hir::ItemKind::Const(_, _, generics, _)
| hir::ItemKind::TraitAlias(_, generics, _),
..
})
| hir::Node::TraitItem(hir::TraitItem { generics, .. })
@ -412,15 +411,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Struct(_, generics)
| hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Union(_, generics)
| hir::ItemKind::Trait(_, _, generics, ..)
hir::ItemKind::Struct(_, _, generics)
| hir::ItemKind::Enum(_, _, generics)
| hir::ItemKind::Union(_, _, generics)
| hir::ItemKind::Trait(_, _, _, generics, ..)
| hir::ItemKind::Impl(hir::Impl { generics, .. })
| hir::ItemKind::Fn { generics, .. }
| hir::ItemKind::TyAlias(_, generics)
| hir::ItemKind::Const(_, generics, _)
| hir::ItemKind::TraitAlias(generics, _),
| hir::ItemKind::TyAlias(_, _, generics)
| hir::ItemKind::Const(_, _, generics, _)
| hir::ItemKind::TraitAlias(_, generics, _),
..
}) if !param_ty => {
// Missing generic type parameter bound.
@ -842,7 +841,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
name.to_string()
}
Some(hir::Node::Item(hir::Item {
ident, kind: hir::ItemKind::Fn { .. }, ..
kind: hir::ItemKind::Fn { ident, .. }, ..
})) => {
err.span_label(ident.span, "consider calling this function");
ident.to_string()
@ -1588,20 +1587,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let Some(typeck_results) = &self.typeck_results
&& let ty = typeck_results.expr_ty_adjusted(base)
&& let ty::FnDef(def_id, _args) = ty.kind()
&& let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
self.tcx.hir_get_if_local(*def_id)
&& let Some(hir::Node::Item(item)) = self.tcx.hir_get_if_local(*def_id)
{
let (ident, _, _, _) = item.expect_fn();
let msg = format!("alternatively, consider making `fn {ident}` asynchronous");
if vis_span.is_empty() {
if item.vis_span.is_empty() {
err.span_suggestion_verbose(
span.shrink_to_lo(),
item.span.shrink_to_lo(),
msg,
"async ",
Applicability::MaybeIncorrect,
);
} else {
err.span_suggestion_verbose(
vis_span.shrink_to_hi(),
item.vis_span.shrink_to_hi(),
msg,
" async",
Applicability::MaybeIncorrect,
@ -3303,8 +3302,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut is_auto_trait = false;
match tcx.hir_get_if_local(data.impl_or_alias_def_id) {
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Trait(is_auto, ..),
ident,
kind: hir::ItemKind::Trait(is_auto, _, ident, ..),
..
})) => {
// FIXME: we should do something else so that it works even on crate foreign

View file

@ -516,7 +516,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope))
{
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Trait(_, _, generics, ..),
kind: hir::ItemKind::Trait(_, _, _, generics, ..),
..
})
| hir::Node::Item(hir::Item {

View file

@ -0,0 +1,362 @@
use std::collections::{BTreeMap, HashMap, HashSet};
use build_helper::metrics::{
BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps,
};
use crate::metrics;
use crate::metrics::{JobMetrics, JobName, get_test_suites};
use crate::utils::{output_details, pluralize};
pub fn output_bootstrap_stats(metrics: &JsonRoot) {
if !metrics.invocations.is_empty() {
println!("# Bootstrap steps");
record_bootstrap_step_durations(&metrics);
record_test_suites(&metrics);
}
}
fn record_bootstrap_step_durations(metrics: &JsonRoot) {
for invocation in &metrics.invocations {
let step = BuildStep::from_invocation(invocation);
let table = format_build_steps(&step);
eprintln!("Step `{}`\n{table}\n", invocation.cmdline);
output_details(&invocation.cmdline, || {
println!("<pre><code>{table}</code></pre>");
});
}
eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len());
}
fn record_test_suites(metrics: &JsonRoot) {
let suites = metrics::get_test_suites(&metrics);
if !suites.is_empty() {
let aggregated = aggregate_test_suites(&suites);
let table = render_table(aggregated);
println!("\n# Test results\n");
println!("{table}");
} else {
eprintln!("No test suites found in metrics");
}
}
fn render_table(suites: BTreeMap<String, TestSuiteRecord>) -> String {
use std::fmt::Write;
let mut table = "| Test suite | Passed ✅ | Ignored 🚫 | Failed ❌ |\n".to_string();
writeln!(table, "|:------|------:|------:|------:|").unwrap();
fn compute_pct(value: f64, total: f64) -> f64 {
if total == 0.0 { 0.0 } else { value / total }
}
fn write_row(
buffer: &mut String,
name: &str,
record: &TestSuiteRecord,
surround: &str,
) -> std::fmt::Result {
let TestSuiteRecord { passed, ignored, failed } = record;
let total = (record.passed + record.ignored + record.failed) as f64;
let passed_pct = compute_pct(*passed as f64, total) * 100.0;
let ignored_pct = compute_pct(*ignored as f64, total) * 100.0;
let failed_pct = compute_pct(*failed as f64, total) * 100.0;
write!(buffer, "| {surround}{name}{surround} |")?;
write!(buffer, " {surround}{passed} ({passed_pct:.0}%){surround} |")?;
write!(buffer, " {surround}{ignored} ({ignored_pct:.0}%){surround} |")?;
writeln!(buffer, " {surround}{failed} ({failed_pct:.0}%){surround} |")?;
Ok(())
}
let mut total = TestSuiteRecord::default();
for (name, record) in suites {
write_row(&mut table, &name, &record, "").unwrap();
total.passed += record.passed;
total.ignored += record.ignored;
total.failed += record.failed;
}
write_row(&mut table, "Total", &total, "**").unwrap();
table
}
/// Computes a post merge CI analysis report of test differences
/// between the `parent` and `current` commits.
pub fn output_test_diffs(job_metrics: HashMap<JobName, JobMetrics>) {
let aggregated_test_diffs = aggregate_test_diffs(&job_metrics);
report_test_diffs(aggregated_test_diffs);
}
#[derive(Default)]
struct TestSuiteRecord {
passed: u64,
ignored: u64,
failed: u64,
}
fn test_metadata_name(metadata: &TestSuiteMetadata) -> String {
match metadata {
TestSuiteMetadata::CargoPackage { crates, stage, .. } => {
format!("{} (stage {stage})", crates.join(", "))
}
TestSuiteMetadata::Compiletest { suite, stage, .. } => {
format!("{suite} (stage {stage})")
}
}
}
fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap<String, TestSuiteRecord> {
let mut records: BTreeMap<String, TestSuiteRecord> = BTreeMap::new();
for suite in suites {
let name = test_metadata_name(&suite.metadata);
let record = records.entry(name).or_default();
for test in &suite.tests {
match test.outcome {
TestOutcome::Passed => {
record.passed += 1;
}
TestOutcome::Failed => {
record.failed += 1;
}
TestOutcome::Ignored { .. } => {
record.ignored += 1;
}
}
}
}
records
}
/// Represents a difference in the outcome of tests between a base and a current commit.
/// Maps test diffs to jobs that contained them.
#[derive(Debug)]
struct AggregatedTestDiffs {
diffs: HashMap<TestDiff, Vec<JobName>>,
}
fn aggregate_test_diffs(jobs: &HashMap<JobName, JobMetrics>) -> AggregatedTestDiffs {
let mut diffs: HashMap<TestDiff, Vec<JobName>> = HashMap::new();
// Aggregate test suites
for (name, metrics) in jobs {
if let Some(parent) = &metrics.parent {
let tests_parent = aggregate_tests(parent);
let tests_current = aggregate_tests(&metrics.current);
for diff in calculate_test_diffs(tests_parent, tests_current) {
diffs.entry(diff).or_default().push(name.to_string());
}
}
}
AggregatedTestDiffs { diffs }
}
#[derive(Eq, PartialEq, Hash, Debug)]
enum TestOutcomeDiff {
ChangeOutcome { before: TestOutcome, after: TestOutcome },
Missing { before: TestOutcome },
Added(TestOutcome),
}
#[derive(Eq, PartialEq, Hash, Debug)]
struct TestDiff {
test: Test,
diff: TestOutcomeDiff,
}
fn calculate_test_diffs(parent: TestSuiteData, current: TestSuiteData) -> HashSet<TestDiff> {
let mut diffs = HashSet::new();
for (test, outcome) in &current.tests {
match parent.tests.get(test) {
Some(before) => {
if before != outcome {
diffs.insert(TestDiff {
test: test.clone(),
diff: TestOutcomeDiff::ChangeOutcome {
before: before.clone(),
after: outcome.clone(),
},
});
}
}
None => {
diffs.insert(TestDiff {
test: test.clone(),
diff: TestOutcomeDiff::Added(outcome.clone()),
});
}
}
}
for (test, outcome) in &parent.tests {
if !current.tests.contains_key(test) {
diffs.insert(TestDiff {
test: test.clone(),
diff: TestOutcomeDiff::Missing { before: outcome.clone() },
});
}
}
diffs
}
/// Aggregates test suite executions from all bootstrap invocations in a given CI job.
#[derive(Default)]
struct TestSuiteData {
tests: HashMap<Test, TestOutcome>,
}
#[derive(Hash, PartialEq, Eq, Debug, Clone)]
struct Test {
name: String,
is_doctest: bool,
}
/// Extracts all tests from the passed metrics and map them to their outcomes.
fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData {
let mut tests = HashMap::new();
let test_suites = get_test_suites(&metrics);
for suite in test_suites {
for test in &suite.tests {
// Poor man's detection of doctests based on the "(line XYZ)" suffix
let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. })
&& test.name.contains("(line");
let test_entry = Test { name: generate_test_name(&test.name, &suite), is_doctest };
tests.insert(test_entry, test.outcome.clone());
}
}
TestSuiteData { tests }
}
/// Normalizes Windows-style path delimiters to Unix-style paths
/// and adds suite metadata to the test name.
fn generate_test_name(name: &str, suite: &TestSuite) -> String {
let name = name.replace('\\', "/");
let stage = match suite.metadata {
TestSuiteMetadata::CargoPackage { stage, .. } => stage,
TestSuiteMetadata::Compiletest { stage, .. } => stage,
};
format!("{name} (stage {stage})")
}
/// Prints test changes in Markdown format to stdout.
fn report_test_diffs(diff: AggregatedTestDiffs) {
println!("# Test differences");
if diff.diffs.is_empty() {
println!("No test diffs found");
return;
}
fn format_outcome(outcome: &TestOutcome) -> String {
match outcome {
TestOutcome::Passed => "pass".to_string(),
TestOutcome::Failed => "fail".to_string(),
TestOutcome::Ignored { ignore_reason } => {
let reason = match ignore_reason {
Some(reason) => format!(" ({reason})"),
None => String::new(),
};
format!("ignore{reason}")
}
}
}
fn format_diff(diff: &TestOutcomeDiff) -> String {
match diff {
TestOutcomeDiff::ChangeOutcome { before, after } => {
format!("{} -> {}", format_outcome(before), format_outcome(after))
}
TestOutcomeDiff::Missing { before } => {
format!("{} -> [missing]", format_outcome(before))
}
TestOutcomeDiff::Added(outcome) => {
format!("[missing] -> {}", format_outcome(outcome))
}
}
}
fn format_job_group(group: u64) -> String {
format!("**J{group}**")
}
// It would be quite noisy to repeat the jobs that contained the test changes after/next to
// every test diff. At the same time, grouping the test diffs by
// [unique set of jobs that contained them] also doesn't work well, because the test diffs
// would have to be duplicated several times.
// Instead, we create a set of unique job groups, and then print a job group after each test.
// We then print the job groups at the end, as a sort of index.
let mut grouped_diffs: Vec<(&TestDiff, u64)> = vec![];
let mut job_list_to_group: HashMap<&[JobName], u64> = HashMap::new();
let mut job_index: Vec<&[JobName]> = vec![];
let original_diff_count = diff.diffs.len();
let diffs = diff
.diffs
.into_iter()
.filter(|(diff, _)| !diff.test.is_doctest)
.map(|(diff, mut jobs)| {
jobs.sort();
(diff, jobs)
})
.collect::<Vec<_>>();
let doctest_count = original_diff_count.saturating_sub(diffs.len());
let max_diff_count = 100;
for (diff, jobs) in diffs.iter().take(max_diff_count) {
let jobs = &*jobs;
let job_group = match job_list_to_group.get(jobs.as_slice()) {
Some(id) => *id,
None => {
let id = job_index.len() as u64;
job_index.push(jobs);
job_list_to_group.insert(jobs, id);
id
}
};
grouped_diffs.push((diff, job_group));
}
// Sort diffs by job group and test name
grouped_diffs.sort_by(|(d1, g1), (d2, g2)| g1.cmp(&g2).then(d1.test.name.cmp(&d2.test.name)));
output_details(
&format!("Show {} test {}\n", original_diff_count, pluralize("diff", original_diff_count)),
|| {
for (diff, job_group) in grouped_diffs {
println!(
"- `{}`: {} ({})",
diff.test.name,
format_diff(&diff.diff),
format_job_group(job_group)
);
}
let extra_diffs = diffs.len().saturating_sub(max_diff_count);
if extra_diffs > 0 {
println!(
"\n(and {extra_diffs} additional {})",
pluralize("test diff", extra_diffs)
);
}
if doctest_count > 0 {
println!(
"\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.",
pluralize("diff", doctest_count)
);
}
// Now print the job group index
println!("\n**Job group index**\n");
for (group, jobs) in job_index.into_iter().enumerate() {
println!(
"- {}: {}",
format_job_group(group as u64),
jobs.iter().map(|j| format!("`{j}`")).collect::<Vec<_>>().join(", ")
);
}
},
);
}

View file

@ -185,6 +185,20 @@ fn calculate_jobs(
env.extend(crate::yaml_map_to_json(&job.env));
let full_name = format!("{prefix} - {}", job.name);
// When the default `@bors try` job is executed (which is usually done
// for benchmarking performance, running crater or for downloading the
// built toolchain using `rustup-toolchain-install-master`),
// we inject the `DIST_TRY_BUILD` environment variable to the jobs
// to tell `opt-dist` to make the build faster by skipping certain steps.
if let RunType::TryJob { job_patterns } = run_type {
if job_patterns.is_none() {
env.insert(
"DIST_TRY_BUILD".to_string(),
serde_json::value::Value::Number(1.into()),
);
}
}
GithubActionsJob {
name: job.name,
full_name,

View file

@ -1,25 +1,26 @@
mod analysis;
mod cpu_usage;
mod datadog;
mod jobs;
mod merge_report;
mod metrics;
mod utils;
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashMap};
use std::path::{Path, PathBuf};
use std::process::Command;
use analysis::output_bootstrap_stats;
use anyhow::Context;
use clap::Parser;
use jobs::JobDatabase;
use serde_yaml::Value;
use crate::analysis::output_test_diffs;
use crate::cpu_usage::load_cpu_usage;
use crate::datadog::upload_datadog_metric;
use crate::jobs::RunType;
use crate::merge_report::post_merge_report;
use crate::metrics::postprocess_metrics;
use crate::utils::load_env_var;
use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics};
use crate::utils::{load_env_var, output_details};
const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/..");
const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker");
@ -137,6 +138,56 @@ fn upload_ci_metrics(cpu_usage_csv: &Path) -> anyhow::Result<()> {
Ok(())
}
fn postprocess_metrics(
metrics_path: PathBuf,
parent: Option<String>,
job_name: Option<String>,
) -> anyhow::Result<()> {
let metrics = load_metrics(&metrics_path)?;
output_bootstrap_stats(&metrics);
let (Some(parent), Some(job_name)) = (parent, job_name) else {
return Ok(());
};
// This command is executed also on PR builds, which might not have parent metrics
// available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics
// due to missing permissions.
// To avoid having to detect if this is a PR job, and to avoid having failed steps in PR jobs,
// we simply print an error if the parent metrics were not found, but otherwise exit
// successfully.
match download_job_metrics(&job_name, &parent).context("cannot download parent metrics") {
Ok(parent_metrics) => {
let job_metrics = HashMap::from([(
job_name,
JobMetrics { parent: Some(parent_metrics), current: metrics },
)]);
output_test_diffs(job_metrics);
}
Err(error) => {
eprintln!("Metrics for job `{job_name}` and commit `{parent}` not found: {error:?}");
}
}
Ok(())
}
fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow::Result<()> {
let metrics = download_auto_job_metrics(&db, &parent, &current)?;
output_details("What is this?", || {
println!(
r#"This is an experimental post-merge analysis report that shows differences in
test outcomes between the merged PR and its parent PR."#
);
});
println!("\nComparing {parent} (parent) -> {current} (this PR)\n");
output_test_diffs(metrics);
Ok(())
}
#[derive(clap::Parser)]
enum Args {
/// Calculate a list of jobs that should be executed on CI.
@ -154,13 +205,19 @@ enum Args {
#[clap(long = "type", default_value = "auto")]
job_type: JobType,
},
/// Postprocess the metrics.json file generated by bootstrap.
/// Postprocess the metrics.json file generated by bootstrap and output
/// various statistics.
/// If `--parent` and `--job-name` are provided, also display a diff
/// against previous metrics that are downloaded from CI.
PostprocessMetrics {
/// Path to the metrics.json file
metrics_path: PathBuf,
/// Path to a file where the postprocessed metrics summary will be stored.
/// Usually, this will be GITHUB_STEP_SUMMARY on CI.
summary_path: PathBuf,
/// A parent SHA against which to compare.
#[clap(long, requires("job_name"))]
parent: Option<String>,
/// The name of the current job.
#[clap(long, requires("parent"))]
job_name: Option<String>,
},
/// Upload CI metrics to Datadog.
UploadBuildMetrics {
@ -211,11 +268,11 @@ fn main() -> anyhow::Result<()> {
Args::UploadBuildMetrics { cpu_usage_csv } => {
upload_ci_metrics(&cpu_usage_csv)?;
}
Args::PostprocessMetrics { metrics_path, summary_path } => {
postprocess_metrics(&metrics_path, &summary_path)?;
Args::PostprocessMetrics { metrics_path, parent, job_name } => {
postprocess_metrics(metrics_path, parent, job_name)?;
}
Args::PostMergeReport { current: commit, parent } => {
post_merge_report(load_db(default_jobs_file)?, parent, commit)?;
Args::PostMergeReport { current, parent } => {
post_merge_report(load_db(default_jobs_file)?, current, parent)?;
}
}

View file

@ -1,318 +0,0 @@
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use anyhow::Context;
use build_helper::metrics::{JsonRoot, TestOutcome, TestSuiteMetadata};
use crate::jobs::JobDatabase;
use crate::metrics::get_test_suites;
type Sha = String;
type JobName = String;
/// Computes a post merge CI analysis report between the `parent` and `current` commits.
pub fn post_merge_report(job_db: JobDatabase, parent: Sha, current: Sha) -> anyhow::Result<()> {
let jobs = download_all_metrics(&job_db, &parent, &current)?;
let aggregated_test_diffs = aggregate_test_diffs(&jobs)?;
println!("Comparing {parent} (base) -> {current} (this PR)\n");
report_test_diffs(aggregated_test_diffs);
Ok(())
}
struct JobMetrics {
parent: Option<JsonRoot>,
current: JsonRoot,
}
/// Download before/after metrics for all auto jobs in the job database.
fn download_all_metrics(
job_db: &JobDatabase,
parent: &str,
current: &str,
) -> anyhow::Result<HashMap<JobName, JobMetrics>> {
let mut jobs = HashMap::default();
for job in &job_db.auto_jobs {
eprintln!("Downloading metrics of job {}", job.name);
let metrics_parent = match download_job_metrics(&job.name, parent) {
Ok(metrics) => Some(metrics),
Err(error) => {
eprintln!(
r#"Did not find metrics for job `{}` at `{}`: {error:?}.
Maybe it was newly added?"#,
job.name, parent
);
None
}
};
let metrics_current = download_job_metrics(&job.name, current)?;
jobs.insert(
job.name.clone(),
JobMetrics { parent: metrics_parent, current: metrics_current },
);
}
Ok(jobs)
}
/// Downloads job metrics of the given job for the given commit.
/// Caches the result on the local disk.
fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result<JsonRoot> {
let cache_path = PathBuf::from(".citool-cache").join(sha).join(job_name).join("metrics.json");
if let Some(cache_entry) =
std::fs::read_to_string(&cache_path).ok().and_then(|data| serde_json::from_str(&data).ok())
{
return Ok(cache_entry);
}
let url = get_metrics_url(job_name, sha);
let mut response = ureq::get(&url).call()?;
if !response.status().is_success() {
return Err(anyhow::anyhow!(
"Cannot fetch metrics from {url}: {}\n{}",
response.status(),
response.body_mut().read_to_string()?
));
}
let data: JsonRoot = response
.body_mut()
.read_json()
.with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?;
// Ignore errors if cache cannot be created
if std::fs::create_dir_all(cache_path.parent().unwrap()).is_ok() {
if let Ok(serialized) = serde_json::to_string(&data) {
let _ = std::fs::write(&cache_path, &serialized);
}
}
Ok(data)
}
fn get_metrics_url(job_name: &str, sha: &str) -> String {
let suffix = if job_name.ends_with("-alt") { "-alt" } else { "" };
format!("https://ci-artifacts.rust-lang.org/rustc-builds{suffix}/{sha}/metrics-{job_name}.json")
}
/// Represents a difference in the outcome of tests between a base and a current commit.
/// Maps test diffs to jobs that contained them.
#[derive(Debug)]
struct AggregatedTestDiffs {
diffs: HashMap<TestDiff, Vec<JobName>>,
}
fn aggregate_test_diffs(
jobs: &HashMap<JobName, JobMetrics>,
) -> anyhow::Result<AggregatedTestDiffs> {
let mut diffs: HashMap<TestDiff, Vec<JobName>> = HashMap::new();
// Aggregate test suites
for (name, metrics) in jobs {
if let Some(parent) = &metrics.parent {
let tests_parent = aggregate_tests(parent);
let tests_current = aggregate_tests(&metrics.current);
for diff in calculate_test_diffs(tests_parent, tests_current) {
diffs.entry(diff).or_default().push(name.to_string());
}
}
}
Ok(AggregatedTestDiffs { diffs })
}
#[derive(Eq, PartialEq, Hash, Debug)]
enum TestOutcomeDiff {
ChangeOutcome { before: TestOutcome, after: TestOutcome },
Missing { before: TestOutcome },
Added(TestOutcome),
}
#[derive(Eq, PartialEq, Hash, Debug)]
struct TestDiff {
test: Test,
diff: TestOutcomeDiff,
}
fn calculate_test_diffs(parent: TestSuiteData, current: TestSuiteData) -> HashSet<TestDiff> {
let mut diffs = HashSet::new();
for (test, outcome) in &current.tests {
match parent.tests.get(test) {
Some(before) => {
if before != outcome {
diffs.insert(TestDiff {
test: test.clone(),
diff: TestOutcomeDiff::ChangeOutcome {
before: before.clone(),
after: outcome.clone(),
},
});
}
}
None => {
diffs.insert(TestDiff {
test: test.clone(),
diff: TestOutcomeDiff::Added(outcome.clone()),
});
}
}
}
for (test, outcome) in &parent.tests {
if !current.tests.contains_key(test) {
diffs.insert(TestDiff {
test: test.clone(),
diff: TestOutcomeDiff::Missing { before: outcome.clone() },
});
}
}
diffs
}
/// Aggregates test suite executions from all bootstrap invocations in a given CI job.
#[derive(Default)]
struct TestSuiteData {
tests: HashMap<Test, TestOutcome>,
}
#[derive(Hash, PartialEq, Eq, Debug, Clone)]
struct Test {
name: String,
is_doctest: bool,
}
/// Extracts all tests from the passed metrics and map them to their outcomes.
fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData {
let mut tests = HashMap::new();
let test_suites = get_test_suites(&metrics);
for suite in test_suites {
for test in &suite.tests {
// Poor man's detection of doctests based on the "(line XYZ)" suffix
let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. })
&& test.name.contains("(line");
let test_entry = Test { name: normalize_test_name(&test.name), is_doctest };
tests.insert(test_entry, test.outcome.clone());
}
}
TestSuiteData { tests }
}
/// Normalizes Windows-style path delimiters to Unix-style paths.
fn normalize_test_name(name: &str) -> String {
name.replace('\\', "/")
}
/// Prints test changes in Markdown format to stdout.
fn report_test_diffs(diff: AggregatedTestDiffs) {
println!("## Test differences");
if diff.diffs.is_empty() {
println!("No test diffs found");
return;
}
fn format_outcome(outcome: &TestOutcome) -> String {
match outcome {
TestOutcome::Passed => "pass".to_string(),
TestOutcome::Failed => "fail".to_string(),
TestOutcome::Ignored { ignore_reason } => {
let reason = match ignore_reason {
Some(reason) => format!(" ({reason})"),
None => String::new(),
};
format!("ignore{reason}")
}
}
}
fn format_diff(diff: &TestOutcomeDiff) -> String {
match diff {
TestOutcomeDiff::ChangeOutcome { before, after } => {
format!("{} -> {}", format_outcome(before), format_outcome(after))
}
TestOutcomeDiff::Missing { before } => {
format!("{} -> [missing]", format_outcome(before))
}
TestOutcomeDiff::Added(outcome) => {
format!("[missing] -> {}", format_outcome(outcome))
}
}
}
fn format_job_group(group: u64) -> String {
format!("**J{group}**")
}
// It would be quite noisy to repeat the jobs that contained the test changes after/next to
// every test diff. At the same time, grouping the test diffs by
// [unique set of jobs that contained them] also doesn't work well, because the test diffs
// would have to be duplicated several times.
// Instead, we create a set of unique job groups, and then print a job group after each test.
// We then print the job groups at the end, as a sort of index.
let mut grouped_diffs: Vec<(&TestDiff, u64)> = vec![];
let mut job_list_to_group: HashMap<&[JobName], u64> = HashMap::new();
let mut job_index: Vec<&[JobName]> = vec![];
let original_diff_count = diff.diffs.len();
let diffs = diff
.diffs
.into_iter()
.filter(|(diff, _)| !diff.test.is_doctest)
.map(|(diff, mut jobs)| {
jobs.sort();
(diff, jobs)
})
.collect::<Vec<_>>();
let doctest_count = original_diff_count.saturating_sub(diffs.len());
let max_diff_count = 100;
for (diff, jobs) in diffs.iter().take(max_diff_count) {
let jobs = &*jobs;
let job_group = match job_list_to_group.get(jobs.as_slice()) {
Some(id) => *id,
None => {
let id = job_index.len() as u64;
job_index.push(jobs);
job_list_to_group.insert(jobs, id);
id
}
};
grouped_diffs.push((diff, job_group));
}
// Sort diffs by job group and test name
grouped_diffs.sort_by(|(d1, g1), (d2, g2)| g1.cmp(&g2).then(d1.test.name.cmp(&d2.test.name)));
for (diff, job_group) in grouped_diffs {
println!(
"- `{}`: {} ({})",
diff.test.name,
format_diff(&diff.diff),
format_job_group(job_group)
);
}
let extra_diffs = diffs.len().saturating_sub(max_diff_count);
if extra_diffs > 0 {
println!("\n(and {extra_diffs} additional {})", pluralize("test diff", extra_diffs));
}
if doctest_count > 0 {
println!(
"\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.",
pluralize("diff", doctest_count)
);
}
// Now print the job group index
println!("\n**Job group index**\n");
for (group, jobs) in job_index.into_iter().enumerate() {
println!(
"- {}: {}",
format_job_group(group as u64),
jobs.iter().map(|j| format!("`{j}`")).collect::<Vec<_>>().join(", ")
);
}
}
fn pluralize(text: &str, count: usize) -> String {
if count == 1 { text.to_string() } else { format!("{text}s") }
}

View file

@ -1,146 +1,12 @@
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Write;
use std::collections::HashMap;
use std::path::Path;
use anyhow::Context;
use build_helper::metrics::{
BuildStep, JsonNode, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps,
};
use build_helper::metrics::{JsonNode, JsonRoot, TestSuite};
pub fn postprocess_metrics(metrics_path: &Path, summary_path: &Path) -> anyhow::Result<()> {
let metrics = load_metrics(metrics_path)?;
use crate::jobs::JobDatabase;
let mut file = File::options()
.append(true)
.create(true)
.open(summary_path)
.with_context(|| format!("Cannot open summary file at {summary_path:?}"))?;
if !metrics.invocations.is_empty() {
writeln!(file, "# Bootstrap steps")?;
record_bootstrap_step_durations(&metrics, &mut file)?;
record_test_suites(&metrics, &mut file)?;
}
Ok(())
}
fn record_bootstrap_step_durations(metrics: &JsonRoot, file: &mut File) -> anyhow::Result<()> {
for invocation in &metrics.invocations {
let step = BuildStep::from_invocation(invocation);
let table = format_build_steps(&step);
eprintln!("Step `{}`\n{table}\n", invocation.cmdline);
writeln!(
file,
r"<details>
<summary>{}</summary>
<pre><code>{table}</code></pre>
</details>
",
invocation.cmdline
)?;
}
eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len());
Ok(())
}
fn record_test_suites(metrics: &JsonRoot, file: &mut File) -> anyhow::Result<()> {
let suites = get_test_suites(&metrics);
if !suites.is_empty() {
let aggregated = aggregate_test_suites(&suites);
let table = render_table(aggregated);
writeln!(file, "\n# Test results\n")?;
writeln!(file, "{table}")?;
} else {
eprintln!("No test suites found in metrics");
}
Ok(())
}
fn render_table(suites: BTreeMap<String, TestSuiteRecord>) -> String {
use std::fmt::Write;
let mut table = "| Test suite | Passed ✅ | Ignored 🚫 | Failed ❌ |\n".to_string();
writeln!(table, "|:------|------:|------:|------:|").unwrap();
fn compute_pct(value: f64, total: f64) -> f64 {
if total == 0.0 { 0.0 } else { value / total }
}
fn write_row(
buffer: &mut String,
name: &str,
record: &TestSuiteRecord,
surround: &str,
) -> std::fmt::Result {
let TestSuiteRecord { passed, ignored, failed } = record;
let total = (record.passed + record.ignored + record.failed) as f64;
let passed_pct = compute_pct(*passed as f64, total) * 100.0;
let ignored_pct = compute_pct(*ignored as f64, total) * 100.0;
let failed_pct = compute_pct(*failed as f64, total) * 100.0;
write!(buffer, "| {surround}{name}{surround} |")?;
write!(buffer, " {surround}{passed} ({passed_pct:.0}%){surround} |")?;
write!(buffer, " {surround}{ignored} ({ignored_pct:.0}%){surround} |")?;
writeln!(buffer, " {surround}{failed} ({failed_pct:.0}%){surround} |")?;
Ok(())
}
let mut total = TestSuiteRecord::default();
for (name, record) in suites {
write_row(&mut table, &name, &record, "").unwrap();
total.passed += record.passed;
total.ignored += record.ignored;
total.failed += record.failed;
}
write_row(&mut table, "Total", &total, "**").unwrap();
table
}
#[derive(Default)]
struct TestSuiteRecord {
passed: u64,
ignored: u64,
failed: u64,
}
fn test_metadata_name(metadata: &TestSuiteMetadata) -> String {
match metadata {
TestSuiteMetadata::CargoPackage { crates, stage, .. } => {
format!("{} (stage {stage})", crates.join(", "))
}
TestSuiteMetadata::Compiletest { suite, stage, .. } => {
format!("{suite} (stage {stage})")
}
}
}
fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap<String, TestSuiteRecord> {
let mut records: BTreeMap<String, TestSuiteRecord> = BTreeMap::new();
for suite in suites {
let name = test_metadata_name(&suite.metadata);
let record = records.entry(name).or_default();
for test in &suite.tests {
match test.outcome {
TestOutcome::Passed => {
record.passed += 1;
}
TestOutcome::Failed => {
record.failed += 1;
}
TestOutcome::Ignored { .. } => {
record.ignored += 1;
}
}
}
}
records
}
pub type JobName = String;
pub fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> {
fn visit_test_suites<'a>(nodes: &'a [JsonNode], suites: &mut Vec<&'a TestSuite>) {
@ -163,10 +29,68 @@ pub fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> {
suites
}
fn load_metrics(path: &Path) -> anyhow::Result<JsonRoot> {
pub fn load_metrics(path: &Path) -> anyhow::Result<JsonRoot> {
let metrics = std::fs::read_to_string(path)
.with_context(|| format!("Cannot read JSON metrics from {path:?}"))?;
let metrics: JsonRoot = serde_json::from_str(&metrics)
.with_context(|| format!("Cannot deserialize JSON metrics from {path:?}"))?;
Ok(metrics)
}
pub struct JobMetrics {
pub parent: Option<JsonRoot>,
pub current: JsonRoot,
}
/// Download before/after metrics for all auto jobs in the job database.
/// `parent` and `current` should be commit SHAs.
pub fn download_auto_job_metrics(
job_db: &JobDatabase,
parent: &str,
current: &str,
) -> anyhow::Result<HashMap<JobName, JobMetrics>> {
let mut jobs = HashMap::default();
for job in &job_db.auto_jobs {
eprintln!("Downloading metrics of job {}", job.name);
let metrics_parent = match download_job_metrics(&job.name, parent) {
Ok(metrics) => Some(metrics),
Err(error) => {
eprintln!(
r#"Did not find metrics for job `{}` at `{parent}`: {error:?}.
Maybe it was newly added?"#,
job.name
);
None
}
};
let metrics_current = download_job_metrics(&job.name, current)?;
jobs.insert(
job.name.clone(),
JobMetrics { parent: metrics_parent, current: metrics_current },
);
}
Ok(jobs)
}
pub fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result<JsonRoot> {
let url = get_metrics_url(job_name, sha);
let mut response = ureq::get(&url).call()?;
if !response.status().is_success() {
return Err(anyhow::anyhow!(
"Cannot fetch metrics from {url}: {}\n{}",
response.status(),
response.body_mut().read_to_string()?
));
}
let data: JsonRoot = response
.body_mut()
.read_json()
.with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?;
Ok(data)
}
fn get_metrics_url(job_name: &str, sha: &str) -> String {
let suffix = if job_name.ends_with("-alt") { "-alt" } else { "" };
format!("https://ci-artifacts.rust-lang.org/rustc-builds{suffix}/{sha}/metrics-{job_name}.json")
}

View file

@ -9,3 +9,23 @@ pub fn load_env_var(name: &str) -> anyhow::Result<String> {
pub fn read_to_string<P: AsRef<Path>>(path: P) -> anyhow::Result<String> {
std::fs::read_to_string(&path).with_context(|| format!("Cannot read file {:?}", path.as_ref()))
}
pub fn pluralize(text: &str, count: usize) -> String {
if count == 1 { text.to_string() } else { format!("{text}s") }
}
/// Outputs a HTML <details> section with the provided summary.
/// Output printed by `func` will be contained within the section.
pub fn output_details<F>(summary: &str, func: F)
where
F: FnOnce(),
{
println!(
r"<details>
<summary>{summary}</summary>
"
);
func();
println!("</details>\n");
}

View file

@ -14,10 +14,10 @@ fn auto_jobs() {
#[test]
fn try_jobs() {
let stdout = get_matrix("push", "commit", "refs/heads/try");
insta::assert_snapshot!(stdout, @r#"
insta::assert_snapshot!(stdout, @r###"
jobs=[{"name":"dist-x86_64-linux","full_name":"try - dist-x86_64-linux","os":"ubuntu-22.04-16core-64gb","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_TRY_BUILD":1,"TOOLSTATE_PUBLISH":1}}]
run_type=try
"#);
"###);
}
#[test]
@ -30,10 +30,10 @@ try-job: aarch64-gnu
try-job: dist-i686-msvc"#,
"refs/heads/try",
);
insta::assert_snapshot!(stdout, @r#"
jobs=[{"name":"aarch64-gnu","full_name":"try - aarch64-gnu","os":"ubuntu-22.04-arm","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","DIST_TRY_BUILD":1,"TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"dist-i686-msvc","full_name":"try - dist-i686-msvc","os":"windows-2022","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_REQUIRE_ALL_TOOLS":1,"DIST_TRY_BUILD":1,"RUST_CONFIGURE_ARGS":"--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler","SCRIPT":"python x.py dist bootstrap --include-default-paths","TOOLSTATE_PUBLISH":1}}]
insta::assert_snapshot!(stdout, @r###"
jobs=[{"name":"aarch64-gnu","full_name":"try - aarch64-gnu","os":"ubuntu-22.04-arm","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"dist-i686-msvc","full_name":"try - dist-i686-msvc","os":"windows-2022","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_REQUIRE_ALL_TOOLS":1,"RUST_CONFIGURE_ARGS":"--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler","SCRIPT":"python x.py dist bootstrap --include-default-paths","TOOLSTATE_PUBLISH":1}}]
run_type=try
"#);
"###);
}
#[test]

View file

@ -53,13 +53,6 @@ envs:
try:
<<: *production
# The following env var activates faster `try` builds in `opt-dist` by, e.g.
# - building only the more commonly useful components (we rarely need e.g. rust-docs in try
# builds)
# - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain
#
# If you *want* these to happen however, temporarily comment it before triggering a try build.
DIST_TRY_BUILD: 1
auto:
<<: *production

View file

@ -82,15 +82,13 @@ envs:
AWS_REGION: us-west-1
TOOLSTATE_PUBLISH: 1
# Try builds started through `@bors try` (without specifying custom jobs
# in the PR description) will be passed the `DIST_TRY_BUILD` environment
# variable by citool.
# This tells the `opt-dist` tool to skip building certain components
# and skip running tests, so that the try build finishes faster.
try:
<<: *production
# The following env var activates faster `try` builds in `opt-dist` by, e.g.
# - building only the more commonly useful components (we rarely need e.g. rust-docs in try
# builds)
# - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain
#
# If you *want* these to happen however, temporarily comment it before triggering a try build.
DIST_TRY_BUILD: 1
auto:
<<: *production

View file

@ -180,6 +180,8 @@ their results can be seen [here](https://github.com/rust-lang-ci/rust/actions),
although usually you will be notified of the result by a comment made by bors on
the corresponding PR.
Note that if you start the default try job using `@bors try`, it will skip building several `dist` components and running post-optimization tests, to make the build duration shorter. If you want to execute the full build as it would happen before a merge, add an explicit `try-job` pattern with the name of the default try job (currently `dist-x86_64-linux`).
Multiple try builds can execute concurrently across different PRs.
<div class="warning">

View file

@ -125,7 +125,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
items.extend(doc.items.values().flat_map(|(item, renamed, _)| {
// Now we actually lower the imports, skipping everything else.
if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
let name = renamed.unwrap_or_else(|| cx.tcx.hir_name(item.hir_id()));
let name = renamed.unwrap_or(kw::Empty); // using kw::Empty is a bit of a hack
clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
} else {
// skip everything else
@ -1629,8 +1629,7 @@ fn first_non_private<'tcx>(
if let Some(use_def_id) = reexp.id()
&& let Some(local_use_def_id) = use_def_id.as_local()
&& let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_use_def_id)
&& !item.ident.name.is_empty()
&& let hir::ItemKind::Use(path, _) = item.kind
&& let hir::ItemKind::Use(path, hir::UseKind::Single(_)) = item.kind
{
for res in &path.res {
if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
@ -1775,7 +1774,7 @@ fn maybe_expand_private_type_alias<'tcx>(
} else {
return None;
};
let hir::ItemKind::TyAlias(ty, generics) = alias else { return None };
let hir::ItemKind::TyAlias(_, ty, generics) = alias else { return None };
let final_seg = &path.segments.last().expect("segments were empty");
let mut args = DefIdMap::default();
@ -2794,20 +2793,24 @@ fn clean_maybe_renamed_item<'tcx>(
use hir::ItemKind;
let def_id = item.owner_id.to_def_id();
let mut name = renamed.unwrap_or_else(|| cx.tcx.hir_name(item.hir_id()));
let mut name = renamed.unwrap_or_else(|| {
// FIXME: using kw::Empty is a bit of a hack
cx.tcx.hir_opt_name(item.hir_id()).unwrap_or(kw::Empty)
});
cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
ItemKind::Static(ty, mutability, body_id) => StaticItem(Static {
ItemKind::Static(_, ty, mutability, body_id) => StaticItem(Static {
type_: Box::new(clean_ty(ty, cx)),
mutability,
expr: Some(body_id),
}),
ItemKind::Const(ty, generics, body_id) => ConstantItem(Box::new(Constant {
ItemKind::Const(_, ty, generics, body_id) => ConstantItem(Box::new(Constant {
generics: clean_generics(generics, cx),
type_: clean_ty(ty, cx),
kind: ConstantKind::Local { body: body_id, def_id },
})),
ItemKind::TyAlias(hir_ty, generics) => {
ItemKind::TyAlias(_, hir_ty, generics) => {
*cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
let rustdoc_ty = clean_ty(hir_ty, cx);
let type_ =
@ -2840,34 +2843,34 @@ fn clean_maybe_renamed_item<'tcx>(
));
return ret;
}
ItemKind::Enum(ref def, generics) => EnumItem(Enum {
ItemKind::Enum(_, ref def, generics) => EnumItem(Enum {
variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(),
generics: clean_generics(generics, cx),
}),
ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias {
ItemKind::TraitAlias(_, generics, bounds) => TraitAliasItem(TraitAlias {
generics: clean_generics(generics, cx),
bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
}),
ItemKind::Union(ref variant_data, generics) => UnionItem(Union {
ItemKind::Union(_, ref variant_data, generics) => UnionItem(Union {
generics: clean_generics(generics, cx),
fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
}),
ItemKind::Struct(ref variant_data, generics) => StructItem(Struct {
ItemKind::Struct(_, ref variant_data, generics) => StructItem(Struct {
ctor_kind: variant_data.ctor_kind(),
generics: clean_generics(generics, cx),
fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
}),
ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
ItemKind::Macro(macro_def, MacroKind::Bang) => MacroItem(Macro {
ItemKind::Macro(_, macro_def, MacroKind::Bang) => MacroItem(Macro {
source: display_macro_source(cx, name, macro_def),
macro_rules: macro_def.macro_rules,
}),
ItemKind::Macro(_, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx),
ItemKind::Macro(_, _, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx),
// proc macros can have a name set by attributes
ItemKind::Fn { ref sig, generics, body: body_id, .. } => {
clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
}
ItemKind::Trait(_, _, generics, bounds, item_ids) => {
ItemKind::Trait(_, _, _, generics, bounds, item_ids) => {
let items = item_ids
.iter()
.map(|ti| clean_trait_item(cx.tcx.hir_trait_item(ti.id), cx))
@ -2880,7 +2883,7 @@ fn clean_maybe_renamed_item<'tcx>(
bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
}))
}
ItemKind::ExternCrate(orig_name) => {
ItemKind::ExternCrate(orig_name, _) => {
return clean_extern_crate(item, name, orig_name, cx);
}
ItemKind::Use(path, kind) => {

View file

@ -4,8 +4,8 @@ use rustc_ast_pretty::pprust::PrintState;
use rustc_ast_pretty::pprust::state::State as Printer;
use rustc_middle::ty::TyCtxt;
use rustc_session::parse::ParseSess;
use rustc_span::Span;
use rustc_span::symbol::{Ident, Symbol, kw};
use rustc_span::{FileName, Span};
/// Render a macro matcher in a format suitable for displaying to the user
/// as part of an item declaration.
@ -63,7 +63,7 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String
// Create a Parser.
let psess = ParseSess::new(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec());
let file_name = source_map.span_to_filename(span);
let file_name = FileName::macro_expansion_source_code(&snippet);
let mut parser =
match rustc_parse::new_parser_from_source_str(&psess, file_name, snippet.clone()) {
Ok(parser) => parser,

View file

@ -226,7 +226,7 @@ impl ExternalCrate {
.filter_map(|&id| {
let item = tcx.hir_item(id);
match item.kind {
hir::ItemKind::Mod(_) => {
hir::ItemKind::Mod(..) => {
as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
}
_ => None,
@ -282,7 +282,7 @@ impl ExternalCrate {
.filter_map(|&id| {
let item = tcx.hir_item(id);
match item.kind {
hir::ItemKind::Mod(_) => {
hir::ItemKind::Mod(..) => {
as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
}
_ => None,

View file

@ -80,7 +80,7 @@ impl<'tcx> HirCollector<'tcx> {
pub fn collect_crate(mut self) -> Vec<ScrapedDocTest> {
let tcx = self.tcx;
self.visit_testable("".to_string(), CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), |this| {
self.visit_testable(None, CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), |this| {
tcx.hir_walk_toplevel_module(this)
});
self.collector.tests
@ -90,7 +90,7 @@ impl<'tcx> HirCollector<'tcx> {
impl HirCollector<'_> {
fn visit_testable<F: FnOnce(&mut Self)>(
&mut self,
name: String,
name: Option<String>,
def_id: LocalDefId,
sp: Span,
nested: F,
@ -103,9 +103,10 @@ impl HirCollector<'_> {
return;
}
let has_name = !name.is_empty();
if has_name {
let mut has_name = false;
if let Some(name) = name {
self.collector.cur_path.push(name);
has_name = true;
}
// The collapse-docs pass won't combine sugared/raw doc attributes, or included files with
@ -153,9 +154,9 @@ impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'_>) {
let name = match &item.kind {
hir::ItemKind::Impl(impl_) => {
rustc_hir_pretty::id_to_string(&self.tcx, impl_.self_ty.hir_id)
Some(rustc_hir_pretty::id_to_string(&self.tcx, impl_.self_ty.hir_id))
}
_ => item.ident.to_string(),
_ => item.kind.ident().map(|ident| ident.to_string()),
};
self.visit_testable(name, item.owner_id.def_id, item.span, |this| {
@ -164,31 +165,46 @@ impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> {
}
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'_>) {
self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| {
intravisit::walk_trait_item(this, item);
});
self.visit_testable(
Some(item.ident.to_string()),
item.owner_id.def_id,
item.span,
|this| {
intravisit::walk_trait_item(this, item);
},
);
}
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'_>) {
self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| {
intravisit::walk_impl_item(this, item);
});
self.visit_testable(
Some(item.ident.to_string()),
item.owner_id.def_id,
item.span,
|this| {
intravisit::walk_impl_item(this, item);
},
);
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'_>) {
self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| {
intravisit::walk_foreign_item(this, item);
});
self.visit_testable(
Some(item.ident.to_string()),
item.owner_id.def_id,
item.span,
|this| {
intravisit::walk_foreign_item(this, item);
},
);
}
fn visit_variant(&mut self, v: &'tcx hir::Variant<'_>) {
self.visit_testable(v.ident.to_string(), v.def_id, v.span, |this| {
self.visit_testable(Some(v.ident.to_string()), v.def_id, v.span, |this| {
intravisit::walk_variant(this, v);
});
}
fn visit_field_def(&mut self, f: &'tcx hir::FieldDef<'_>) {
self.visit_testable(f.ident.to_string(), f.def_id, f.span, |this| {
self.visit_testable(Some(f.ident.to_string()), f.def_id, f.span, |this| {
intravisit::walk_field_def(this, f);
});
}

View file

@ -242,10 +242,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
// Now that we confirmed it's a file import, we want to get the span for the module
// name only and not all the "mod foo;".
if let Node::Item(item) = self.tcx.hir_node(id) {
self.matches.insert(
item.ident.span,
LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)),
);
let (ident, _) = item.expect_mod();
self.matches
.insert(ident.span, LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)));
}
} else {
// If it's a "mod foo {}", we want to look to its documentation page.
@ -273,22 +272,22 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
match item.kind {
ItemKind::Static(..)
| ItemKind::Const(_, _, _)
| ItemKind::Const(..)
| ItemKind::Fn { .. }
| ItemKind::Macro(_, _)
| ItemKind::TyAlias(_, _)
| ItemKind::Enum(_, _)
| ItemKind::Struct(_, _)
| ItemKind::Union(_, _)
| ItemKind::Trait(_, _, _, _, _)
| ItemKind::TraitAlias(_, _) => self.extract_info_from_hir_id(item.hir_id()),
| ItemKind::Macro(..)
| ItemKind::TyAlias(..)
| ItemKind::Enum(..)
| ItemKind::Struct(..)
| ItemKind::Union(..)
| ItemKind::Trait(..)
| ItemKind::TraitAlias(..) => self.extract_info_from_hir_id(item.hir_id()),
ItemKind::Impl(_)
| ItemKind::Use(_, _)
| ItemKind::ExternCrate(_)
| ItemKind::Use(..)
| ItemKind::ExternCrate(..)
| ItemKind::ForeignMod { .. }
| ItemKind::GlobalAsm { .. }
// We already have "visit_mod" above so no need to check it here.
| ItemKind::Mod(_) => {}
| ItemKind::Mod(..) => {}
}
intravisit::walk_item(self, item);
}

View file

@ -240,7 +240,7 @@ impl DocVisitor<'_> for CoverageCalculator<'_, '_> {
data: hir::VariantData::Tuple(_, _, _),
..
}) | hir::Node::Item(hir::Item {
kind: hir::ItemKind::Struct(hir::VariantData::Tuple(_, _, _), _),
kind: hir::ItemKind::Struct(_, hir::VariantData::Tuple(_, _, _), _),
..
})
)

View file

@ -144,9 +144,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
&& inserted.insert(def_id)
{
let item = self.cx.tcx.hir_expect_item(local_def_id);
top_level_module
.items
.insert((local_def_id, Some(item.ident.name)), (item, None, None));
let (ident, _, _) = item.expect_macro();
top_level_module.items.insert((local_def_id, Some(ident.name)), (item, None, None));
}
}
@ -224,11 +223,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
def_id: LocalDefId,
res: Res,
renamed: Option<Symbol>,
glob: bool,
please_inline: bool,
) -> bool {
debug!("maybe_inline_local (renamed: {renamed:?}) res: {res:?}");
let glob = renamed.is_none();
if renamed == Some(kw::Underscore) {
// We never inline `_` reexports.
return false;
@ -286,7 +285,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
is_hidden &&
// If it's a doc hidden module, we need to keep it in case some of its inner items
// are re-exported.
!matches!(item, Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_), .. }))
!matches!(item, Node::Item(&hir::Item { kind: hir::ItemKind::Mod(..), .. }))
) ||
// The imported item is public and not `doc(hidden)` so no need to inline it.
self.reexport_public_and_not_hidden(def_id, res_did)
@ -297,7 +296,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
let is_bang_macro = matches!(
item,
Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, MacroKind::Bang), .. })
Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, _, MacroKind::Bang), .. })
);
if !self.view_item_stack.insert(res_did) && !is_bang_macro {
@ -311,7 +310,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
Node::Item(_) if is_bang_macro && !please_inline && renamed.is_some() && is_hidden => {
return false;
}
Node::Item(&hir::Item { kind: hir::ItemKind::Mod(m), .. }) if glob => {
Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_, m), .. }) if glob => {
let prev = mem::replace(&mut self.inlining, true);
for &i in m.item_ids {
let i = tcx.hir_item(i);
@ -378,7 +377,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
// attribute can still be visible.
|| match item.kind {
hir::ItemKind::Impl(..) => true,
hir::ItemKind::Macro(_, MacroKind::Bang) => {
hir::ItemKind::Macro(_, _, MacroKind::Bang) => {
self.cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export)
}
_ => false,
@ -419,7 +418,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
}
return;
}
let name = renamed.unwrap_or(item.ident.name);
let get_name = || renamed.unwrap_or(item.kind.ident().unwrap().name);
let tcx = self.cx.tcx;
let def_id = item.owner_id.to_def_id();
@ -459,15 +458,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
}
_ => false,
});
let is_glob = kind == hir::UseKind::Glob;
let ident = if is_glob { None } else { Some(name) };
if self.maybe_inline_local(
item.owner_id.def_id,
res,
ident,
is_glob,
please_inline,
) {
let ident = match kind {
hir::UseKind::Single(ident) => Some(renamed.unwrap_or(ident.name)),
hir::UseKind::Glob => None,
hir::UseKind::ListStem => unreachable!(),
};
if self.maybe_inline_local(item.owner_id.def_id, res, ident, please_inline)
{
debug!("Inlining {:?}", item.owner_id.def_id);
continue;
}
@ -475,7 +472,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
self.add_to_current_mod(item, renamed, import_id);
}
}
hir::ItemKind::Macro(macro_def, _) => {
hir::ItemKind::Macro(_, macro_def, _) => {
// `#[macro_export] macro_rules!` items are handled separately in `visit()`,
// above, since they need to be documented at the module top level. Accordingly,
// we only want to handle macros if one of three conditions holds:
@ -495,8 +492,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
self.add_to_current_mod(item, renamed, import_id);
}
}
hir::ItemKind::Mod(m) => {
self.enter_mod(item.owner_id.def_id, m, name, renamed, import_id);
hir::ItemKind::Mod(_, m) => {
self.enter_mod(item.owner_id.def_id, m, get_name(), renamed, import_id);
}
hir::ItemKind::Fn { .. }
| hir::ItemKind::ExternCrate(..)
@ -512,7 +509,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
hir::ItemKind::Const(..) => {
// Underscore constants do not correspond to a nameable item and
// so are never useful in documentation.
if name != kw::Underscore {
if get_name() != kw::Underscore {
self.add_to_current_mod(item, renamed, import_id);
}
}

View file

@ -5,7 +5,7 @@ use clippy_config::types::{
};
use clippy_utils::diagnostics::span_lint_and_note;
use rustc_hir::{
AssocItemKind, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind, UseKind,
AssocItemKind, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind,
Variant, VariantData,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
@ -178,8 +178,8 @@ impl ArbitrarySourceItemOrdering {
/// Produces a linting warning for incorrectly ordered item members.
fn lint_member_name<T: LintContext>(
cx: &T,
ident: &rustc_span::symbol::Ident,
before_ident: &rustc_span::symbol::Ident,
ident: &rustc_span::Ident,
before_ident: &rustc_span::Ident,
) {
span_lint_and_note(
cx,
@ -192,21 +192,21 @@ impl ArbitrarySourceItemOrdering {
}
fn lint_member_item<T: LintContext>(cx: &T, item: &Item<'_>, before_item: &Item<'_>) {
let span = if item.ident.as_str().is_empty() {
&item.span
let span = if let Some(ident) = item.kind.ident() {
ident.span
} else {
&item.ident.span
item.span
};
let (before_span, note) = if before_item.ident.as_str().is_empty() {
let (before_span, note) = if let Some(ident) = before_item.kind.ident() {
(
&before_item.span,
"should be placed before the following item".to_owned(),
ident.span,
format!("should be placed before `{}`", ident.as_str(),),
)
} else {
(
&before_item.ident.span,
format!("should be placed before `{}`", before_item.ident.as_str(),),
before_item.span,
"should be placed before the following item".to_owned(),
)
};
@ -218,9 +218,9 @@ impl ArbitrarySourceItemOrdering {
span_lint_and_note(
cx,
ARBITRARY_SOURCE_ITEM_ORDERING,
*span,
span,
"incorrect ordering of items (must be alphabetically ordered)",
Some(*before_span),
Some(before_span),
note,
);
}
@ -244,7 +244,7 @@ impl ArbitrarySourceItemOrdering {
impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
match &item.kind {
ItemKind::Enum(enum_def, _generics) if self.enable_ordering_for_enum => {
ItemKind::Enum(_, enum_def, _generics) if self.enable_ordering_for_enum => {
let mut cur_v: Option<&Variant<'_>> = None;
for variant in enum_def.variants {
if variant.span.in_external_macro(cx.sess().source_map()) {
@ -259,7 +259,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
cur_v = Some(variant);
}
},
ItemKind::Struct(VariantData::Struct { fields, .. }, _generics) if self.enable_ordering_for_struct => {
ItemKind::Struct(_, VariantData::Struct { fields, .. }, _generics) if self.enable_ordering_for_struct => {
let mut cur_f: Option<&FieldDef<'_>> = None;
for field in *fields {
if field.span.in_external_macro(cx.sess().source_map()) {
@ -274,7 +274,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
cur_f = Some(field);
}
},
ItemKind::Trait(is_auto, _safety, _generics, _generic_bounds, item_ref)
ItemKind::Trait(is_auto, _safety, _ident, _generics, _generic_bounds, item_ref)
if self.enable_ordering_for_trait && *is_auto == IsAuto::No =>
{
let mut cur_t: Option<&TraitItemRef> = None;
@ -351,50 +351,24 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
continue;
}
// The following exceptions (skipping with `continue;`) may not be
// complete, edge cases have not been explored further than what
// appears in the existing code base.
if item.ident.name == rustc_span::symbol::kw::Empty {
if let ItemKind::Impl(_) = item.kind {
// Sorting trait impls for unnamed types makes no sense.
if get_item_name(item).is_empty() {
continue;
}
} else if let ItemKind::ForeignMod { .. } = item.kind {
continue;
} else if let ItemKind::GlobalAsm { .. } = item.kind {
continue;
} else if let ItemKind::Use(path, use_kind) = item.kind {
if path.segments.is_empty() {
// Use statements that contain braces get caught here.
// They will still be linted internally.
continue;
} else if path.segments.len() >= 2
&& (path.segments[0].ident.name == rustc_span::sym::std
|| path.segments[0].ident.name == rustc_span::sym::core)
&& path.segments[1].ident.name == rustc_span::sym::prelude
{
// Filters the autogenerated prelude use statement.
// e.g. `use std::prelude::rustc_2021`
} else if use_kind == UseKind::Glob {
// Filters glob kinds of uses.
// e.g. `use std::sync::*`
} else {
// This can be used for debugging.
// println!("Unknown autogenerated use statement: {:?}", item);
}
continue;
}
}
let ident = if let Some(ident) = item.kind.ident() {
ident
} else if let ItemKind::Impl(_) = item.kind
&& !get_item_name(item).is_empty()
{
rustc_span::Ident::empty() // FIXME: a bit strange, is there a better way to do it?
} else {
continue;
};
if item.ident.name.as_str().starts_with('_') {
if ident.name.as_str().starts_with('_') {
// Filters out unnamed macro-like impls for various derives,
// e.g. serde::Serialize or num_derive::FromPrimitive.
continue;
}
if item.ident.name == rustc_span::sym::std && item.span.is_dummy() {
if let ItemKind::ExternCrate(None) = item.kind {
if ident.name == rustc_span::sym::std && item.span.is_dummy() {
if let ItemKind::ExternCrate(None, _) = item.kind {
// Filters the auto-included Rust standard library.
continue;
}
@ -525,6 +499,8 @@ fn get_item_name(item: &Item<'_>) -> String {
String::new()
}
},
_ => item.ident.name.as_str().to_owned(),
// FIXME: `Ident::empty` for anonymous items is a bit strange, is there
// a better way to do it?
_ => item.kind.ident().unwrap_or(rustc_span::Ident::empty()).name.as_str().to_owned(),
}
}

View file

@ -16,7 +16,7 @@ mod utils;
use clippy_config::Conf;
use clippy_utils::msrvs::{self, Msrv, MsrvStack};
use rustc_ast::{self as ast, Attribute, MetaItemInner, MetaItemKind};
use rustc_hir::{ImplItem, Item, TraitItem};
use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
use rustc_span::sym;
@ -466,8 +466,8 @@ impl Attributes {
impl<'tcx> LateLintPass<'tcx> for Attributes {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
let attrs = cx.tcx.hir_attrs(item.hir_id());
if is_relevant_item(cx, item) {
inline_always::check(cx, item.span, item.ident.name, attrs);
if let ItemKind::Fn { ident, .. } = item.kind && is_relevant_item(cx, item) {
inline_always::check(cx, item.span, ident.name, attrs);
}
repr_attributes::check(cx, item.span, attrs, self.msrv);
}

View file

@ -24,7 +24,7 @@ pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
if let ItemKind::Fn { body: eid, .. } = item.kind {
is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir_body(eid).value)
} else {
true
false
}
}

View file

@ -99,7 +99,7 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if let ItemKind::Use(path, UseKind::Single) = &item.kind {
if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind {
for res in &path.res {
self.check_res_emit(cx, res, item.span);
}

View file

@ -38,7 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
if cx.tcx.data_layout.pointer_size.bits() != 64 {
return;
}
if let ItemKind::Enum(def, _) = &item.kind {
if let ItemKind::Enum(_, def, _) = &item.kind {
for var in def.variants {
if let Some(anon_const) = &var.disr_expr {
let def_id = cx.tcx.hir_body_owner_def_id(anon_const.body);

View file

@ -37,8 +37,8 @@ declare_lint_pass!(ErrorImplError => [ERROR_IMPL_ERROR]);
impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
match item.kind {
ItemKind::TyAlias(..)
if item.ident.name == sym::Error
ItemKind::TyAlias(ident, ..)
if ident.name == sym::Error
&& is_visible_outside_module(cx, item.owner_id.def_id)
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
&& let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error)
@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
span_lint(
cx,
ERROR_IMPL_ERROR,
item.ident.span,
ident.span,
"exported type alias named `Error` that implements `Error`",
);
},

View file

@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
}
// find `self` ty for this trait if relevant
if let ItemKind::Trait(_, _, _, _, items) = item.kind {
if let ItemKind::Trait(_, _, _, _, _, items) = item.kind {
for trait_item in items {
if trait_item.id.owner_id.def_id == fn_def_id {
// be sure we have `self` parameter in this function

View file

@ -122,7 +122,7 @@ fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, sp: Span, max: u64) {
impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if let ItemKind::Struct(variant_data, _) = &item.kind
if let ItemKind::Struct(_, variant_data, _) = &item.kind
&& variant_data.fields().len() as u64 > self.max_struct_bools
&& has_n_bools(
variant_data.fields().iter().map(|field| field.ty),

View file

@ -76,7 +76,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
"exported enums should not be exhaustive",
[].as_slice(),
),
ItemKind::Struct(v, ..) => (
ItemKind::Struct(_, v, ..) => (
EXHAUSTIVE_STRUCTS,
"exported structs should not be exhaustive",
v.fields(),

View file

@ -103,7 +103,7 @@ fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty
.did()
.as_local()
&& let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_def_id)
&& let hir::ItemKind::Enum(ref def, _) = item.kind
&& let hir::ItemKind::Enum(_, ref def, _) = item.kind
{
let variants_size = AdtVariantInfo::new(cx, *adt, subst);
if let Some((first_variant, variants)) = variants_size.split_first()

View file

@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
use rustc_span::Span;
use rustc_span::{Ident, Span};
use rustc_span::symbol::Symbol;
declare_clippy_lint! {
@ -196,16 +196,16 @@ fn have_no_extra_prefix(prefixes: &[&str]) -> bool {
prefixes.iter().all(|p| p == &"" || p == &"_")
}
fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &[FieldDef<'_>]) {
fn check_fields(cx: &LateContext<'_>, threshold: u64, ident: Ident, span: Span, fields: &[FieldDef<'_>]) {
if (fields.len() as u64) < threshold {
return;
}
check_struct_name_repetition(cx, item, fields);
check_struct_name_repetition(cx, ident, fields);
// if the SyntaxContext of the identifiers of the fields and struct differ dont lint them.
// this prevents linting in macros in which the location of the field identifier names differ
if !fields.iter().all(|field| item.ident.span.eq_ctxt(field.ident.span)) {
if !fields.iter().all(|field| ident.span.eq_ctxt(field.ident.span)) {
return;
}
@ -256,7 +256,7 @@ fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &
span_lint_and_help(
cx,
STRUCT_FIELD_NAMES,
item.span,
span,
format!("all fields have the same {what}fix: `{value}`"),
None,
format!("remove the {what}fixes"),
@ -264,11 +264,11 @@ fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &
}
}
fn check_struct_name_repetition(cx: &LateContext<'_>, item: &Item<'_>, fields: &[FieldDef<'_>]) {
let snake_name = to_snake_case(item.ident.name.as_str());
fn check_struct_name_repetition(cx: &LateContext<'_>, ident: Ident, fields: &[FieldDef<'_>]) {
let snake_name = to_snake_case(ident.name.as_str());
let item_name_words: Vec<&str> = snake_name.split('_').collect();
for field in fields {
if field.ident.span.eq_ctxt(item.ident.span) {
if field.ident.span.eq_ctxt(ident.span) {
//consider linting only if the field identifier has the same SyntaxContext as the item(struct)
let field_words: Vec<&str> = field.ident.name.as_str().split('_').collect();
if field_words.len() >= item_name_words.len() {
@ -397,19 +397,23 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
}
impl LateLintPass<'_> for ItemNameRepetitions {
fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
fn check_item_post(&mut self, _cx: &LateContext<'_>, item: &Item<'_>) {
let Some(_ident) = item.kind.ident() else { return };
let last = self.modules.pop();
assert!(last.is_some());
}
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
let item_name = item.ident.name.as_str();
let Some(ident) = item.kind.ident() else { return };
let item_name = ident.name.as_str();
let item_camel = to_camel_case(item_name);
if !item.span.from_expansion() && is_present_in_source(cx, item.span) {
if let [.., (mod_name, mod_camel, mod_owner_id)] = &*self.modules {
// constants don't have surrounding modules
if !mod_camel.is_empty() {
if mod_name == &item.ident.name
if mod_name == &ident.name
&& let ItemKind::Mod(..) = item.kind
&& (!self.allow_private_module_inception || cx.tcx.visibility(mod_owner_id.def_id).is_public())
{
@ -438,7 +442,7 @@ impl LateLintPass<'_> for ItemNameRepetitions {
Some(c) if is_word_beginning(c) => span_lint(
cx,
MODULE_NAME_REPETITIONS,
item.ident.span,
ident.span,
"item name starts with its containing module's name",
),
_ => (),
@ -450,7 +454,7 @@ impl LateLintPass<'_> for ItemNameRepetitions {
span_lint(
cx,
MODULE_NAME_REPETITIONS,
item.ident.span,
ident.span,
"item name ends with its containing module's name",
);
}
@ -462,13 +466,13 @@ impl LateLintPass<'_> for ItemNameRepetitions {
&& span_is_local(item.span)
{
match item.kind {
ItemKind::Enum(def, _) => check_variant(cx, self.enum_threshold, &def, item_name, item.span),
ItemKind::Struct(VariantData::Struct { fields, .. }, _) => {
check_fields(cx, self.struct_threshold, item, fields);
ItemKind::Enum(_, def, _) => check_variant(cx, self.enum_threshold, &def, item_name, item.span),
ItemKind::Struct(_, VariantData::Struct { fields, .. }, _) => {
check_fields(cx, self.struct_threshold, ident, item.span, fields);
},
_ => (),
}
}
self.modules.push((item.ident.name, item_camel, item.owner_id));
self.modules.push((ident.name, item_camel, item.owner_id));
}
}

View file

@ -44,7 +44,7 @@ declare_clippy_lint! {
declare_lint_pass!(ItemsAfterTestModule => [ITEMS_AFTER_TEST_MODULE]);
fn cfg_test_module<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
if let ItemKind::Mod(test_mod) = item.kind
if let ItemKind::Mod(_, test_mod) = item.kind
&& item.span.hi() == test_mod.spans.inner_span.hi()
&& is_cfg_test(cx.tcx, item.hir_id())
&& !item.span.from_expansion()
@ -67,14 +67,20 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
let after: Vec<_> = items
.filter(|item| {
// Ignore the generated test main function
!(item.ident.name == sym::main
&& item.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::TestHarness))
if let ItemKind::Fn { ident, .. } = item.kind
&& ident.name == sym::main
&& item.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::TestHarness)
{
false
} else {
true
}
})
.collect();
if let Some(last) = after.last()
&& after.iter().all(|&item| {
!matches!(item.kind, ItemKind::Mod(_)) && !item.span.from_expansion() && !is_from_proc_macro(cx, item)
!matches!(item.kind, ItemKind::Mod(..)) && !item.span.from_expansion() && !is_from_proc_macro(cx, item)
})
&& !fulfill_or_allowed(cx, ITEMS_AFTER_TEST_MODULE, after.iter().map(|item| item.hir_id()))
{

View file

@ -48,7 +48,7 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]);
impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Const(_, generics, _) = &item.kind
if let ItemKind::Const(ident, _, generics, _) = &item.kind
// Since static items may not have generics, skip generic const items.
// FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it
// doesn't account for empty where-clauses that only consist of keyword `where` IINM.
@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
&& let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
&& u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
{
let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
let hi_pos = ident.span.lo() - BytePos::from_usize(1);
let sugg_span = Span::new(
hi_pos - BytePos::from_usize("const".len()),
hi_pos,

View file

@ -73,7 +73,7 @@ impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
if let ItemKind::Enum(ref def, _) = item.kind
if let ItemKind::Enum(ident, ref def, _) = item.kind
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
&& let ty::Adt(adt, subst) = ty.kind()
&& adt.variants().len() > 1
@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
let mut applicability = Applicability::MaybeIncorrect;
if is_copy(cx, ty) || maybe_copy(cx, ty) {
diag.span_note(
item.ident.span,
ident.span,
"boxing a variant would require the type no longer be `Copy`",
);
} else {

View file

@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
// Integer modules are "TBD" deprecated, and the contents are too,
// so lint on the `use` statement directly.
if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind
if let ItemKind::Use(path, kind @ (UseKind::Single(_) | UseKind::Glob)) = item.kind
&& !item.span.in_external_macro(cx.sess().source_map())
&& let Some(def_id) = path.res[0].opt_def_id()
&& self.msrv.meets(cx, msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
"importing a legacy numeric constant"
},
|diag| {
if item.ident.name == kw::Underscore {
if let UseKind::Single(ident) = kind && ident.name == kw::Underscore {
diag.help("remove this import");
return;
}

View file

@ -17,7 +17,7 @@ use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
use rustc_span::{Ident, Span, Symbol};
use rustc_trait_selection::traits::supertrait_def_ids;
declare_clippy_lint! {
@ -123,10 +123,10 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMP
impl<'tcx> LateLintPass<'tcx> for LenZero {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind
if let ItemKind::Trait(_, _, ident, _, _, trait_items) = item.kind
&& !item.span.from_expansion()
{
check_trait_items(cx, item, trait_items);
check_trait_items(cx, item, ident, trait_items);
}
}
@ -150,10 +150,10 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
let (name, kind) = match cx.tcx.hir_node(ty_hir_id) {
Node::ForeignItem(x) => (x.ident.name, "extern type"),
Node::Item(x) => match x.kind {
ItemKind::Struct(..) => (x.ident.name, "struct"),
ItemKind::Enum(..) => (x.ident.name, "enum"),
ItemKind::Union(..) => (x.ident.name, "union"),
_ => (x.ident.name, "type"),
ItemKind::Struct(ident, ..) => (ident.name, "struct"),
ItemKind::Enum(ident, ..) => (ident.name, "enum"),
ItemKind::Union(ident, ..) => (ident.name, "union"),
_ => (x.kind.ident().unwrap().name, "type"),
},
_ => return,
};
@ -250,7 +250,7 @@ fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span {
}
}
fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items: &[TraitItemRef]) {
fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Ident, trait_items: &[TraitItemRef]) {
fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool {
item.ident.name == name
&& if let AssocItemKind::Fn { has_self } = item.kind {
@ -300,7 +300,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
visited_trait.span,
format!(
"trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
visited_trait.ident.name
ident.name
),
);
}

View file

@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
}
match item.kind {
ItemKind::Enum(def, _) if def.variants.len() > 1 => {
ItemKind::Enum(_, def, _) if def.variants.len() > 1 => {
let iter = def.variants.iter().filter_map(|v| {
(matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir_attrs(v.hir_id)))
.then_some((v.def_id, v.span))
@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
}
},
ItemKind::Struct(variant_data, _) => {
ItemKind::Struct(_, variant_data, _) => {
let fields = variant_data.fields();
let private_fields = fields
.iter()

View file

@ -192,17 +192,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
match it.kind {
hir::ItemKind::Fn { .. } => {
hir::ItemKind::Fn { ident, .. } => {
// ignore main()
if it.ident.name == sym::main {
if ident.name == sym::main {
let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID;
if at_root {
note_prev_span_then_ret!(self.prev_span, it.span);
}
}
},
hir::ItemKind::Const(..) => {
if it.ident.name == kw::Underscore {
hir::ItemKind::Const(ident, ..) => {
if ident.name == kw::Underscore {
note_prev_span_then_ret!(self.prev_span, it.span);
}
},

View file

@ -67,7 +67,7 @@ impl_lint_pass!(ImportRename => [MISSING_ENFORCED_IMPORT_RENAMES]);
impl LateLintPass<'_> for ImportRename {
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if let ItemKind::Use(path, UseKind::Single) = &item.kind {
if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind {
for &res in &path.res {
if let Res::Def(_, id) = res
&& let Some(name) = self.renames.get(&id)

View file

@ -226,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug {
&& should_lint(cx, typeck_results, block)
{
// we intentionally only lint structs, see lint description
if let ItemKind::Struct(data, _) = &self_item.kind {
if let ItemKind::Struct(_, data, _) = &self_item.kind {
check_struct(cx, typeck_results, block, self_ty, item, data);
}
}

View file

@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
let attrs = cx.tcx.hir_attrs(it.hir_id());
check_missing_inline_attrs(cx, attrs, it.span, desc);
},
hir::ItemKind::Trait(ref _is_auto, ref _unsafe, _generics, _bounds, trait_items) => {
hir::ItemKind::Trait(ref _is_auto, ref _unsafe, _ident, _generics, _bounds, trait_items) => {
// note: we need to check if the trait is exported so we can't use
// `LateLintPass::check_trait_item` here.
for tit in trait_items {

View file

@ -37,12 +37,12 @@ declare_lint_pass!(NoMangleWithRustAbi => [NO_MANGLE_WITH_RUST_ABI]);
impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if let ItemKind::Fn { sig: fn_sig, .. } = &item.kind
if let ItemKind::Fn { ident, sig: fn_sig, .. } = &item.kind
&& !item.span.from_expansion()
{
let attrs = cx.tcx.hir_attrs(item.hir_id());
let mut app = Applicability::MaybeIncorrect;
let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(item.ident.span.lo()), "..", &mut app);
let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(ident.span.lo()), "..", &mut app);
for attr in attrs {
if let Some(ident) = attr.ident()
&& ident.name == rustc_span::sym::no_mangle

View file

@ -192,7 +192,7 @@ struct LazyInfo {
impl LazyInfo {
fn from_item(state: &NonStdLazyStatic, cx: &LateContext<'_>, item: &Item<'_>) -> Option<Self> {
// Check if item is a `once_cell:sync::Lazy` static.
if let ItemKind::Static(ty, _, body_id) = item.kind
if let ItemKind::Static(_, ty, _, body_id) = item.kind
&& let Some(path_def_id) = path_def_id(cx, ty)
&& let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
&& state.once_cell_sync_lazy.contains(&path_def_id)

View file

@ -58,7 +58,7 @@ impl PubUnderscoreFields {
impl<'tcx> LateLintPass<'tcx> for PubUnderscoreFields {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
// This lint only pertains to structs.
let ItemKind::Struct(variant_data, _) = &item.kind else {
let ItemKind::Struct(_, variant_data, _) = &item.kind else {
return;
};

View file

@ -52,7 +52,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
&& is_not_macro_export(item)
&& !item.span.in_external_macro(cx.sess().source_map())
{
let span = item.span.with_hi(item.ident.span.hi());
// FIXME: `DUMMY_SP` isn't right here, because it causes the
// resulting span to begin at the start of the file.
let span = item.span.with_hi(
item.kind.ident().map(|ident| ident.span.hi()).unwrap_or(rustc_span::DUMMY_SP.hi())
);
let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id());
span_lint_and_then(
cx,

View file

@ -73,7 +73,8 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
if let Some(self_def) = self_ty.ty_adt_def()
&& let Some(self_local_did) = self_def.did().as_local()
&& let Node::Item(x) = cx.tcx.hir_node_by_def_id(self_local_did)
&& let type_name = x.ident.name.as_str().to_lowercase()
&& let Some(type_ident) = x.kind.ident()
&& let type_name = type_ident.name.as_str().to_lowercase()
&& (impl_item.ident.name.as_str() == type_name
|| impl_item.ident.name.as_str().replace('_', "") == type_name)
{

View file

@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
}
fn is_struct_with_trailing_zero_sized_array<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
if let ItemKind::Struct(data, _) = &item.kind
if let ItemKind::Struct(_, data, _) = &item.kind
&& let Some(last_field) = data.fields().last()
&& let field_ty = cx.tcx.normalize_erasing_regions(
cx.typing_env(),

View file

@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
// special handling for self trait bounds as these are not considered generics
// ie. trait Foo: Display {}
if let Item {
kind: ItemKind::Trait(_, _, _, bounds, ..),
kind: ItemKind::Trait(_, _, _, _, bounds, ..),
..
} = item
{
@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
..
}) = segments.first()
&& let Some(Node::Item(Item {
kind: ItemKind::Trait(_, _, _, self_bounds, _),
kind: ItemKind::Trait(_, _, _, _, self_bounds, _),
..
})) = cx.tcx.hir_get_if_local(*def_id)
{

View file

@ -451,7 +451,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
match item.kind {
ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(
ItemKind::Static(_, ty, _, _) | ItemKind::Const(_, ty, _, _) => self.check_ty(
cx,
ty,
CheckTyContext {

View file

@ -454,7 +454,7 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
let comment_start = match cx.tcx.parent_hir_node(item.hir_id()) {
Node::Crate(parent_mod) => comment_start_before_item_in_mod(cx, parent_mod, parent_mod.spans.inner_span, item),
Node::Item(parent_item) => {
if let ItemKind::Mod(parent_mod) = &parent_item.kind {
if let ItemKind::Mod(_, parent_mod) = &parent_item.kind {
comment_start_before_item_in_mod(cx, parent_mod, parent_item.span, item)
} else {
// Doesn't support impls in this position. Pretend a comment was found.
@ -614,7 +614,7 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
..
}) => maybe_global_var = true,
Node::Item(hir::Item {
kind: ItemKind::Mod(_),
kind: ItemKind::Mod(..),
span: item_span,
..
}) => {

View file

@ -130,9 +130,9 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns {
}
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
let ItemKind::Fn { sig, .. } = &item.kind else {
let ItemKind::Fn { ident, sig, .. } = &item.kind else {
return;
};
self.check_fn_item(cx, sig.decl, item.owner_id.def_id, item.ident.name);
self.check_fn_item(cx, sig.decl, item.owner_id.def_id, ident.name);
}
}

Some files were not shown because too many files have changed in this diff Show more