Skip to content

Collect lang items from AST, get rid of GenericBound::LangItemTrait #118396

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 16, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
@@ -2845,6 +2845,28 @@ impl Item {
pub fn span_with_attributes(&self) -> Span {
self.attrs.iter().fold(self.span, |acc, attr| acc.to(attr.span))
}

pub fn opt_generics(&self) -> Option<&Generics> {
match &self.kind {
ItemKind::ExternCrate(_)
| ItemKind::Use(_)
| ItemKind::Mod(_, _)
| ItemKind::ForeignMod(_)
| ItemKind::GlobalAsm(_)
| ItemKind::MacCall(_)
| ItemKind::MacroDef(_) => None,
ItemKind::Static(_) => None,
ItemKind::Const(i) => Some(&i.generics),
ItemKind::Fn(i) => Some(&i.generics),
ItemKind::TyAlias(i) => Some(&i.generics),
ItemKind::TraitAlias(generics, _)
| ItemKind::Enum(_, generics)
| ItemKind::Struct(_, generics)
| ItemKind::Union(_, generics) => Some(&generics),
ItemKind::Trait(i) => Some(&i.generics),
ItemKind::Impl(i) => Some(&i.generics),
}
}
}

/// `extern` qualifier on a function item or function type.
44 changes: 38 additions & 6 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
@@ -453,6 +453,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
tcx.ensure_with_value().output_filenames(());
tcx.ensure_with_value().early_lint_checks(());
tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE);
tcx.ensure_with_value().get_lang_items(());
let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();

let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
@@ -765,6 +766,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.resolver.get_import_res(id).present_items()
}

fn make_lang_item_path(
&mut self,
lang_item: hir::LangItem,
span: Span,
args: Option<&'hir hir::GenericArgs<'hir>>,
) -> &'hir hir::Path<'hir> {
let def_id = self.tcx.require_lang_item(lang_item, Some(span));
let def_kind = self.tcx.def_kind(def_id);
let res = Res::Def(def_kind, def_id);
self.arena.alloc(hir::Path {
span,
res,
segments: self.arena.alloc_from_iter([hir::PathSegment {
ident: Ident::new(lang_item.name(), span),
hir_id: self.next_id(),
res,
args,
infer_args: false,
}]),
})
}

/// Reuses the span but adds information like the kind of the desugaring and features that are
/// allowed inside this span.
fn mark_span_with_reason(
@@ -1976,18 +1999,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
CoroutineKind::AsyncGen { .. } => (sym::Item, hir::LangItem::AsyncIterator),
};

let future_args = self.arena.alloc(hir::GenericArgs {
let bound_args = self.arena.alloc(hir::GenericArgs {
args: &[],
bindings: arena_vec![self; self.assoc_ty_binding(assoc_ty_name, opaque_ty_span, output_ty)],
parenthesized: hir::GenericArgsParentheses::No,
span_ext: DUMMY_SP,
});

hir::GenericBound::LangItemTrait(
trait_lang_item,
opaque_ty_span,
self.next_id(),
future_args,
hir::GenericBound::Trait(
hir::PolyTraitRef {
bound_generic_params: &[],
trait_ref: hir::TraitRef {
path: self.make_lang_item_path(
trait_lang_item,
opaque_ty_span,
Some(bound_args),
),
hir_ref_id: self.next_id(),
},
span: opaque_ty_span,
},
hir::TraitBoundModifier::None,
)
}

30 changes: 10 additions & 20 deletions compiler/rustc_borrowck/src/diagnostics/region_name.rs
Original file line number Diff line number Diff line change
@@ -788,28 +788,18 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
};
let opaque_ty = hir.item(id);
if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
bounds:
[
hir::GenericBound::LangItemTrait(
hir::LangItem::Future,
_,
_,
hir::GenericArgs {
bindings:
[
hir::TypeBinding {
ident: Ident { name: sym::Output, .. },
kind:
hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) },
..
},
],
..
},
),
],
bounds: [hir::GenericBound::Trait(trait_ref, _)],
..
}) = opaque_ty.kind
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
&& let Some(args) = segment.args
&& let [
hir::TypeBinding {
ident: Ident { name: sym::Output, .. },
kind: hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) },
..
},
] = args.bindings
{
ty
} else {
3 changes: 0 additions & 3 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
@@ -435,8 +435,6 @@ pub enum TraitBoundModifier {
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub enum GenericBound<'hir> {
Trait(PolyTraitRef<'hir>, TraitBoundModifier),
// FIXME(davidtwco): Introduce `PolyTraitRef::LangItem`
LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>),
Outlives(&'hir Lifetime),
}

@@ -451,7 +449,6 @@ impl GenericBound<'_> {
pub fn span(&self) -> Span {
match self {
GenericBound::Trait(t, ..) => t.span,
GenericBound::LangItemTrait(_, span, ..) => *span,
GenericBound::Outlives(l) => l.ident.span,
}
}
4 changes: 0 additions & 4 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
@@ -1075,10 +1075,6 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericB
GenericBound::Trait(ref typ, _modifier) => {
visitor.visit_poly_trait_ref(typ);
}
GenericBound::LangItemTrait(_, _span, hir_id, args) => {
visitor.visit_id(hir_id);
visitor.visit_generic_args(args);
}
GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
}
}
36 changes: 36 additions & 0 deletions compiler/rustc_hir/src/target.rs
Original file line number Diff line number Diff line change
@@ -67,6 +67,42 @@ impl Display for Target {
}

impl Target {
pub fn is_associated_item(self) -> bool {
match self {
Target::AssocConst | Target::AssocTy | Target::Method(_) => true,
Target::ExternCrate
| Target::Use
| Target::Static
| Target::Const
| Target::Fn
| Target::Closure
| Target::Mod
| Target::ForeignMod
| Target::GlobalAsm
| Target::TyAlias
| Target::OpaqueTy
| Target::Enum
| Target::Variant
| Target::Struct
| Target::Field
| Target::Union
| Target::Trait
| Target::TraitAlias
| Target::Impl
| Target::Expression
| Target::Statement
| Target::Arm
| Target::ForeignFn
| Target::ForeignStatic
| Target::ForeignTy
| Target::GenericParam(_)
| Target::MacroDef
| Target::Param
| Target::PatField
| Target::ExprField => false,
}
}

pub fn from_item(item: &Item<'_>) -> Target {
match item.kind {
ItemKind::ExternCrate(..) => Target::ExternCrate,
11 changes: 0 additions & 11 deletions compiler/rustc_hir_analysis/src/astconv/bounds.rs
Original file line number Diff line number Diff line change
@@ -134,17 +134,6 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
only_self_bounds,
);
}
&hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
self.instantiate_lang_item_trait_ref(
lang_item,
span,
hir_id,
args,
param_ty,
bounds,
only_self_bounds,
);
}
hir::GenericBound::Outlives(lifetime) => {
let region = self.ast_region_to_region(lifetime, None);
bounds.push_region_bound(
145 changes: 35 additions & 110 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
@@ -675,36 +675,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
)
}

fn instantiate_poly_trait_ref_inner(
/// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct
/// a full trait reference. The resulting trait reference is returned. This may also generate
/// auxiliary bounds, which are added to `bounds`.
///
/// Example:
///
/// ```ignore (illustrative)
/// poly_trait_ref = Iterator<Item = u32>
/// self_ty = Foo
/// ```
///
/// this would return `Foo: Iterator` and add `<Foo as Iterator>::Item = u32` into `bounds`.
///
/// **A note on binders:** against our usual convention, there is an implied binder around
/// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions.
/// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>`
/// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be
/// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly,
/// however.
#[instrument(level = "debug", skip(self, span, constness, bounds, speculative))]
pub(crate) fn instantiate_poly_trait_ref(
&self,
hir_id: hir::HirId,
trait_ref: &hir::TraitRef<'_>,
span: Span,
binding_span: Option<Span>,
constness: ty::BoundConstness,
polarity: ty::ImplPolarity,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
trait_ref_span: Span,
trait_def_id: DefId,
trait_segment: &hir::PathSegment<'_>,
args: &GenericArgs<'_>,
infer_args: bool,
self_ty: Ty<'tcx>,
only_self_bounds: OnlySelfBounds,
) -> GenericArgCountResult {
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
let trait_segment = trait_ref.path.segments.last().unwrap();
let args = trait_segment.args();

self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);

let (generic_args, arg_count) = self.create_args_for_ast_path(
trait_ref_span,
trait_ref.path.span,
trait_def_id,
&[],
trait_segment,
args,
infer_args,
trait_segment.infer_args,
Some(self_ty),
constness,
);

let tcx = self.tcx();
let bound_vars = tcx.late_bound_vars(hir_id);
let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
debug!(?bound_vars);

let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
@@ -732,13 +753,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {

// Specify type to assert that error was already reported in `Err` case.
let _: Result<_, ErrorGuaranteed> = self.add_predicates_for_ast_type_binding(
hir_id,
trait_ref.hir_ref_id,
poly_trait_ref,
binding,
bounds,
speculative,
&mut dup_bindings,
binding_span.unwrap_or(binding.span),
binding.span,
constness,
only_self_bounds,
polarity,
@@ -749,102 +770,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
arg_count
}

/// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct
/// a full trait reference. The resulting trait reference is returned. This may also generate
/// auxiliary bounds, which are added to `bounds`.
///
/// Example:
///
/// ```ignore (illustrative)
/// poly_trait_ref = Iterator<Item = u32>
/// self_ty = Foo
/// ```
///
/// this would return `Foo: Iterator` and add `<Foo as Iterator>::Item = u32` into `bounds`.
///
/// **A note on binders:** against our usual convention, there is an implied bounder around
/// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions.
/// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>`
/// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be
/// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly,
/// however.
#[instrument(level = "debug", skip(self, span, constness, bounds, speculative))]
pub(crate) fn instantiate_poly_trait_ref(
&self,
trait_ref: &hir::TraitRef<'_>,
span: Span,
constness: ty::BoundConstness,
polarity: ty::ImplPolarity,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
only_self_bounds: OnlySelfBounds,
) -> GenericArgCountResult {
let hir_id = trait_ref.hir_ref_id;
let binding_span = None;
let trait_ref_span = trait_ref.path.span;
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
let trait_segment = trait_ref.path.segments.last().unwrap();
let args = trait_segment.args();
let infer_args = trait_segment.infer_args;

self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);

self.instantiate_poly_trait_ref_inner(
hir_id,
span,
binding_span,
constness,
polarity,
bounds,
speculative,
trait_ref_span,
trait_def_id,
trait_segment,
args,
infer_args,
self_ty,
only_self_bounds,
)
}

pub(crate) fn instantiate_lang_item_trait_ref(
&self,
lang_item: hir::LangItem,
span: Span,
hir_id: hir::HirId,
args: &GenericArgs<'_>,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
only_self_bounds: OnlySelfBounds,
) {
let binding_span = Some(span);
let constness = ty::BoundConstness::NotConst;
let speculative = false;
let trait_ref_span = span;
let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span));
let trait_segment = &hir::PathSegment::invalid();
let infer_args = false;

self.instantiate_poly_trait_ref_inner(
hir_id,
span,
binding_span,
constness,
ty::ImplPolarity::Positive,
bounds,
speculative,
trait_ref_span,
trait_def_id,
trait_segment,
args,
infer_args,
self_ty,
only_self_bounds,
);
}

fn ast_path_to_mono_trait_ref(
&self,
span: Span,
26 changes: 0 additions & 26 deletions compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
Original file line number Diff line number Diff line change
@@ -938,32 +938,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
}

fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) {
match bound {
hir::GenericBound::LangItemTrait(_, _, hir_id, _) => {
// FIXME(jackh726): This is pretty weird. `LangItemTrait` doesn't go
// through the regular poly trait ref code, so we don't get another
// chance to introduce a binder. For now, I'm keeping the existing logic
// of "if there isn't a Binder scope above us, add one", but I
// imagine there's a better way to go about this.
let (binders, scope_type) = self.poly_trait_ref_binder_info();

self.record_late_bound_vars(*hir_id, binders);
let scope = Scope::Binder {
hir_id: *hir_id,
bound_vars: FxIndexMap::default(),
s: self.scope,
scope_type,
where_bound_origin: None,
};
self.with(scope, |this| {
intravisit::walk_param_bound(this, bound);
});
}
_ => intravisit::walk_param_bound(self, bound),
}
}

fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) {
self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow);
}
5 changes: 0 additions & 5 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
@@ -2088,11 +2088,6 @@ impl<'a> State<'a> {
}
self.print_poly_trait_ref(tref);
}
GenericBound::LangItemTrait(lang_item, span, ..) => {
self.word("#[lang = \"");
self.print_ident(Ident::new(lang_item.name(), *span));
self.word("\"]");
}
GenericBound::Outlives(lt) => {
self.print_lifetime(lt);
}
6 changes: 3 additions & 3 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
@@ -825,9 +825,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let hir::Node::Item(hir::Item {
kind: hir::ItemKind::OpaqueTy(op_ty), ..
}) = self.tcx.hir_node(item_id.hir_id())
&& let [
hir::GenericBound::LangItemTrait(hir::LangItem::Future, _, _, generic_args),
] = op_ty.bounds
&& let [hir::GenericBound::Trait(trait_ref, _)] = op_ty.bounds
&& let Some(hir::PathSegment { args: Some(generic_args), .. }) =
trait_ref.trait_ref.path.segments.last()
&& let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args
&& let hir::TypeBindingKind::Equality { term: hir::Term::Ty(term) } =
ty_binding.kind
26 changes: 8 additions & 18 deletions compiler/rustc_infer/src/infer/error_reporting/suggest.rs
Original file line number Diff line number Diff line change
@@ -668,26 +668,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
(
hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
) if std::iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| {
match (left, right) {
(
hir::GenericBound::Trait(tl, ml),
hir::GenericBound::Trait(tr, mr),
) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
) if std::iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| match (
left, right,
) {
(hir::GenericBound::Trait(tl, ml), hir::GenericBound::Trait(tr, mr))
if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
&& ml == mr =>
{
true
}
(
hir::GenericBound::LangItemTrait(langl, _, _, argsl),
hir::GenericBound::LangItemTrait(langr, _, _, argsr),
) if langl == langr => {
// FIXME: consider the bounds!
debug!("{:?} {:?}", argsl, argsr);
true
}
_ => false,
{
true
}
_ => false,
}) =>
{
StatementAsExpression::NeedsBoxing
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/hir_stats.rs
Original file line number Diff line number Diff line change
@@ -429,7 +429,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
fn visit_param_bound(&mut self, b: &'v hir::GenericBound<'v>) {
record_variants!(
(self, b, b, Id::None, hir, GenericBound, GenericBound),
[Trait, LangItemTrait, Outlives]
[Trait, Outlives]
);
hir_visit::walk_param_bound(self, b)
}
378 changes: 234 additions & 144 deletions compiler/rustc_passes/src/lang_items.rs

Large diffs are not rendered by default.

30 changes: 19 additions & 11 deletions compiler/rustc_passes/src/weak_lang_items.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Validity checking for weak lang items
use rustc_ast as ast;
use rustc_ast::visit;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::lang_items::{self, LangItem};
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
@@ -11,7 +13,7 @@ use crate::errors::{MissingLangItem, MissingPanicHandler, UnknownExternLangItem}

/// Checks the crate for usage of weak lang items, returning a vector of all the
/// language items required by this crate, but not defined yet.
pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems) {
pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems, krate: &ast::Crate) {
// These are never called by user code, they're generated by the compiler.
// They will never implicitly be added to the `missing` array unless we do
// so here.
@@ -22,24 +24,30 @@ pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems) {
items.missing.push(LangItem::EhCatchTypeinfo);
}

let crate_items = tcx.hir_crate_items(());
for id in crate_items.foreign_items() {
let attrs = tcx.hir().attrs(id.hir_id());
if let Some((lang_item, _)) = lang_items::extract(attrs) {
visit::Visitor::visit_crate(&mut WeakLangItemVisitor { tcx, items }, krate);

verify(tcx, items);
}

struct WeakLangItemVisitor<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
items: &'a mut lang_items::LanguageItems,
}

impl<'ast> visit::Visitor<'ast> for WeakLangItemVisitor<'_, '_> {
fn visit_foreign_item(&mut self, i: &'ast ast::ForeignItem) {
if let Some((lang_item, _)) = lang_items::extract(&i.attrs) {
if let Some(item) = LangItem::from_name(lang_item)
&& item.is_weak()
{
if items.get(item).is_none() {
items.missing.push(item);
if self.items.get(item).is_none() {
self.items.missing.push(item);
}
} else {
let span = tcx.def_span(id.owner_id);
tcx.sess.emit_err(UnknownExternLangItem { span, lang_item });
self.tcx.sess.emit_err(UnknownExternLangItem { span: i.span, lang_item });
}
}
}

verify(tcx, items);
}

fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) {
Original file line number Diff line number Diff line change
@@ -4783,8 +4783,14 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
};

let future = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else {
// `async fn` should always lower to a lang item bound... but don't ICE.
let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else {
// `async fn` should always lower to a single bound... but don't ICE.
return None;
};
let Some(hir::PathSegment { args: Some(generics), .. }) =
trait_ref.trait_ref.path.segments.last()
else {
// desugaring to a single path segment for `Future<...>`.
return None;
};
let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) =
4 changes: 2 additions & 2 deletions library/std/src/panicking.rs
Original file line number Diff line number Diff line change
@@ -588,7 +588,7 @@ pub fn panicking() -> bool {
}

/// Entry point of panics from the core crate (`panic_impl` lang item).
#[cfg(not(test))]
#[cfg(not(any(test, doctest)))]
#[panic_handler]
pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
struct FormatStringPayload<'a> {
@@ -669,7 +669,7 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
/// panic!() and assert!(). In particular, this is the only entry point that supports
/// arbitrary payloads, not just format strings.
#[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")]
#[cfg_attr(not(test), lang = "begin_panic")]
#[cfg_attr(not(any(test, doctest)), lang = "begin_panic")]
// lang item for CTFE panic support
// never inline unless panic_immediate_abort to avoid code
// bloat at the call sites as much as possible
2 changes: 1 addition & 1 deletion library/std/src/process.rs
Original file line number Diff line number Diff line change
@@ -2311,7 +2311,7 @@ pub fn id() -> u32 {
/// of the `main` function, this trait is likely to be available only on
/// standard library's runtime for convenience. Other runtimes are not required
/// to provide similar functionality.
#[cfg_attr(not(test), lang = "termination")]
#[cfg_attr(not(any(test, doctest)), lang = "termination")]
#[stable(feature = "termination_trait_lib", since = "1.61.0")]
#[rustc_on_unimplemented(on(
cause = "MainFunctionType",
2 changes: 1 addition & 1 deletion library/std/src/rt.rs
Original file line number Diff line number Diff line change
@@ -154,7 +154,7 @@ fn lang_start_internal(
ret_code
}

#[cfg(not(test))]
#[cfg(not(any(test, doctest)))]
#[lang = "start"]
fn lang_start<T: crate::process::Termination + 'static>(
main: fn() -> T,
2 changes: 1 addition & 1 deletion library/std/src/sys/personality/mod.rs
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@
mod dwarf;

#[cfg(not(test))]
#[cfg(not(any(test, doctest)))]
cfg_if::cfg_if! {
if #[cfg(target_os = "emscripten")] {
mod emcc;
16 changes: 0 additions & 16 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
@@ -184,22 +184,6 @@ fn clean_generic_bound<'tcx>(
) -> Option<GenericBound> {
Some(match *bound {
hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
let def_id = cx.tcx.require_lang_item(lang_item, Some(span));

let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(cx.tcx, def_id));

let generic_args = clean_generic_args(generic_args, cx);
let GenericArgs::AngleBracketed { bindings, .. } = generic_args else {
bug!("clean: parenthesized `GenericBound::LangItemTrait`");
};

let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, bindings);
GenericBound::TraitBound(
PolyTrait { trait_, generic_params: vec![] },
hir::TraitBoundModifier::None,
)
}
hir::GenericBound::Trait(ref t, modifier) => {
// `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
if modifier == hir::TraitBoundModifier::MaybeConst
10 changes: 6 additions & 4 deletions src/tools/clippy/clippy_lints/src/len_zero.rs
Original file line number Diff line number Diff line change
@@ -8,8 +8,8 @@ use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::{
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
ImplicitSelfKind, Item, ItemKind, LangItem, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef,
TyKind, TypeBindingKind,
ImplicitSelfKind, Item, ItemKind, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef,
TyKind, TypeBindingKind, OpaqueTyOrigin,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
@@ -289,8 +289,10 @@ fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&
kind: ItemKind::OpaqueTy(opaque),
..
} = item
&& opaque.bounds.len() == 1
&& let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0]
&& let OpaqueTyOrigin::AsyncFn(_) = opaque.origin
&& let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
&& let Some(generic_args) = segment.args
&& generic_args.bindings.len() == 1
&& let TypeBindingKind::Equality {
term:
7 changes: 5 additions & 2 deletions tests/ui/duplicate_entry_error.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
error[E0152]: found duplicate lang item `panic_impl`
--> $DIR/duplicate_entry_error.rs:11:1
|
LL | fn panic_impl(info: &PanicInfo) -> ! {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | / fn panic_impl(info: &PanicInfo) -> ! {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old def_span logic is supposedly reproduced in this PR, so why do some spans change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't reproduce it fully -- I'm just caching the item span here.

In HIR, we do some special span creation to essentially compute the "head span" of each item:

pub fn opt_span(self, hir_id: HirId) -> Option<Span> {
fn until_within(outer: Span, end: Span) -> Span {
if let Some(end) = end.find_ancestor_inside(outer) {
outer.with_hi(end.hi())
} else {
outer
}
}
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 span = match self.find(hir_id)? {
// Function-like.
Node::Item(Item { kind: ItemKind::Fn(sig, ..), span: outer_span, .. })
| Node::TraitItem(TraitItem {
kind: TraitItemKind::Fn(sig, ..),
span: outer_span,
..
})
| Node::ImplItem(ImplItem {
kind: ImplItemKind::Fn(sig, ..), span: outer_span, ..
}) => {
// Ensure that the returned span has the item's SyntaxContext, and not the
// SyntaxContext of the visibility.
sig.span.find_ancestor_in_same_ctxt(*outer_span).unwrap_or(*outer_span)
}
// Impls, including their where clauses.
Node::Item(Item {
kind: ItemKind::Impl(Impl { generics, .. }),
span: outer_span,
..
}) => until_within(*outer_span, generics.where_clause_span),
// Constants and Statics.
Node::Item(Item {
kind: ItemKind::Const(ty, ..) | ItemKind::Static(ty, ..),
span: outer_span,
..
})
| Node::TraitItem(TraitItem {
kind: TraitItemKind::Const(ty, ..),
span: outer_span,
..
})
| Node::ImplItem(ImplItem {
kind: ImplItemKind::Const(ty, ..),
span: outer_span,
..
})
| Node::ForeignItem(ForeignItem {
kind: ForeignItemKind::Static(ty, ..),
span: outer_span,
..
}) => until_within(*outer_span, ty.span),
// With generics and bounds.
Node::Item(Item {
kind: ItemKind::Trait(_, _, generics, bounds, _),
span: outer_span,
..
})
| Node::TraitItem(TraitItem {
kind: TraitItemKind::Type(bounds, _),
generics,
span: outer_span,
..
}) => {
let end = if let Some(b) = bounds.last() { b.span() } else { generics.span };
until_within(*outer_span, end)
}
// Other cases.
Node::Item(item) => match &item.kind {
ItemKind::Use(path, _) => {
// Ensure that the returned span has the item's SyntaxContext, and not the
// 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()),
},
Node::Variant(variant) => named_span(variant.span, variant.ident, None),
Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)),
Node::ForeignItem(item) => match item.kind {
ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()),
_ => named_span(item.span, item.ident, None),
},
Node::Ctor(_) => return self.opt_span(self.parent_id(hir_id)),
Node::Expr(Expr {
kind: ExprKind::Closure(Closure { fn_decl_span, .. }),
span,
..
}) => {
// Ensure that the returned span has the item's SyntaxContext.
fn_decl_span.find_ancestor_inside(*span).unwrap_or(*span)
}
_ => self.span_with_body(hir_id),
};
debug_assert_eq!(span.ctxt(), self.span_with_body(hir_id).ctxt());
Some(span)
}

LL | |
LL | | loop {}
LL | | }
| |_^
|
= note: the lang item is first defined in crate `std` (which `duplicate_entry_error` depends on)
= note: first definition in `std` loaded from SYSROOT/libstd-*.rlib
2 changes: 1 addition & 1 deletion tests/ui/error-codes/E0152.stderr
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ error[E0152]: found duplicate lang item `owned_box`
--> $DIR/E0152.rs:5:1
|
LL | struct Foo<T>(T);
| ^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^
|
= note: the lang item is first defined in crate `alloc` (which `std` depends on)
= note: first definition in `alloc` loaded from SYSROOT/liballoc-*.rlib
2 changes: 1 addition & 1 deletion tests/ui/error-codes/E0264.stderr
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ error[E0264]: unknown external lang item: `cake`
--> $DIR/E0264.rs:5:5
|
LL | fn cake();
| ^^^^^^^^^
| ^^^^^^^^^^

error: aborting due to 1 previous error

3 changes: 3 additions & 0 deletions tests/ui/lang-items/lang-item-generic-requirements.rs
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@ trait MyIndex<'a, T> {}
#[lang = "phantom_data"]
//~^ ERROR `phantom_data` language item must be applied to a struct with 1 generic argument
struct MyPhantomData<T, U>;
//~^ ERROR parameter `T` is never used
//~| ERROR parameter `U` is never used

#[lang = "owned_box"]
//~^ ERROR `owned_box` language item must be applied to a struct with at least 1 generic argument
@@ -40,6 +42,7 @@ fn ice() {
let r = 5;
let a = 6;
r + a;
//~^ ERROR cannot add `{integer}` to `{integer}`

// Use drop in place
my_ptr_drop();
37 changes: 33 additions & 4 deletions tests/ui/lang-items/lang-item-generic-requirements.stderr
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ LL | struct MyPhantomData<T, U>;
| ------ this struct has 2 generic arguments

error[E0718]: `owned_box` language item must be applied to a struct with at least 1 generic argument
--> $DIR/lang-item-generic-requirements.rs:26:1
--> $DIR/lang-item-generic-requirements.rs:28:1
|
LL | #[lang = "owned_box"]
| ^^^^^^^^^^^^^^^^^^^^^
@@ -42,14 +42,43 @@ LL | struct Foo;
| - this struct has 0 generic arguments

error[E0718]: `start` language item must be applied to a function with 1 generic argument
--> $DIR/lang-item-generic-requirements.rs:32:1
--> $DIR/lang-item-generic-requirements.rs:34:1
|
LL | #[lang = "start"]
| ^^^^^^^^^^^^^^^^^
LL |
LL | fn start(_: *const u8, _: isize, _: *const *const u8) -> isize {
| - this function has 0 generic arguments

error: aborting due to 6 previous errors
error[E0392]: parameter `T` is never used
--> $DIR/lang-item-generic-requirements.rs:24:22
|
LL | struct MyPhantomData<T, U>;
| ^ unused parameter
|
= help: consider removing `T` or referring to it in a field
= help: if you intended `T` to be a const parameter, use `const T: usize` instead

error[E0392]: parameter `U` is never used
--> $DIR/lang-item-generic-requirements.rs:24:25
|
LL | struct MyPhantomData<T, U>;
| ^ unused parameter
|
= help: consider removing `U` or referring to it in a field
= help: if you intended `U` to be a const parameter, use `const U: usize` instead

error[E0369]: cannot add `{integer}` to `{integer}`
--> $DIR/lang-item-generic-requirements.rs:44:7
|
LL | r + a;
| - ^ - {integer}
| |
| {integer}

error: requires `copy` lang_item

error: aborting due to 10 previous errors

For more information about this error, try `rustc --explain E0718`.
Some errors have detailed explanations: E0369, E0392, E0718.
For more information about an error, try `rustc --explain E0369`.
12 changes: 8 additions & 4 deletions tests/ui/panic-handler/panic-handler-duplicate.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
error[E0152]: found duplicate lang item `panic_impl`
--> $DIR/panic-handler-duplicate.rs:15:1
|
LL | fn panic2(info: &PanicInfo) -> ! {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | / fn panic2(info: &PanicInfo) -> ! {
LL | | loop {}
LL | | }
| |_^
|
note: the lang item is first defined here
--> $DIR/panic-handler-duplicate.rs:10:1
|
LL | fn panic(info: &PanicInfo) -> ! {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | / fn panic(info: &PanicInfo) -> ! {
LL | | loop {}
LL | | }
| |_^

error: aborting due to 1 previous error

6 changes: 4 additions & 2 deletions tests/ui/panic-handler/panic-handler-std.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
error[E0152]: found duplicate lang item `panic_impl`
--> $DIR/panic-handler-std.rs:8:1
|
LL | fn panic(info: PanicInfo) -> ! {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | / fn panic(info: PanicInfo) -> ! {
LL | | loop {}
LL | | }
| |_^
|
= note: the lang item is first defined in crate `std` (which `panic_handler_std` depends on)
= note: first definition in `std` loaded from SYSROOT/libstd-*.rlib
1 change: 1 addition & 0 deletions tests/ui/traits/issue-102989.rs
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ trait Sized { } //~ ERROR found duplicate lang item `sized`
fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
//~^ ERROR `self` parameter is only allowed in associated functions
//~| ERROR cannot find type `Struct` in this scope
//~| ERROR mismatched types
let x = x << 1;
//~^ ERROR cannot find value `x` in this scope
}
22 changes: 18 additions & 4 deletions tests/ui/traits/issue-102989.stderr
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
| ^^^^^^ not found in this scope

error[E0425]: cannot find value `x` in this scope
--> $DIR/issue-102989.rs:10:13
--> $DIR/issue-102989.rs:11:13
|
LL | let x = x << 1;
| ^ help: a local variable with a similar name exists: `f`
@@ -22,13 +22,27 @@ error[E0152]: found duplicate lang item `sized`
--> $DIR/issue-102989.rs:5:1
|
LL | trait Sized { }
| ^^^^^^^^^^^
| ^^^^^^^^^^^^^^^
|
= note: the lang item is first defined in crate `core` (which `std` depends on)
= note: first definition in `core` loaded from SYSROOT/libcore-*.rlib
= note: second definition in the local crate (`issue_102989`)

error: aborting due to 4 previous errors
error[E0308]: mismatched types
--> $DIR/issue-102989.rs:7:42
|
LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
| ---------- ^^^^ expected `&u32`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
|
help: consider returning the local binding `f`
|
LL ~ let x = x << 1;
LL + f
|

error: aborting due to 5 previous errors

Some errors have detailed explanations: E0152, E0412, E0425.
Some errors have detailed explanations: E0152, E0308, E0412, E0425.
For more information about an error, try `rustc --explain E0152`.