Merge ref '1553adfe68' from rust-lang/rust

Pull recent changes from https://github.com/rust-lang/rust via Josh.

Upstream ref: 1553adfe68
Filtered ref: e5ee70aa5f36dacdc6df9490e867c45aa4e51c18

This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
The Miri Cronjob Bot 2025-08-13 05:05:41 +00:00
commit 4b5f667dc4
698 changed files with 11152 additions and 6367 deletions

View file

@ -1,5 +1,5 @@
name: Documentation problem
description: Create a report for a documentation problem.
description: Report an issue with documentation content.
labels: ["A-docs"]
body:
- type: markdown
@ -19,20 +19,20 @@ body:
- [The Rustonomicon](https://github.com/rust-lang/nomicon/issues)
- [The Embedded Book](https://github.com/rust-embedded/book/issues)
All other documentation issues should be filed here.
Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the rustdoc issue template instead.
Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
All other documentation issues should be filed here.
- type: textarea
id: location
attributes:
label: Location
label: Location (URL)
validations:
required: true
required: true
- type: textarea
id: summary
attributes:
label: Summary
validations:
required: true
required: true

View file

@ -5284,9 +5284,9 @@ dependencies = [
[[package]]
name = "sysinfo"
version = "0.36.1"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "252800745060e7b9ffb7b2badbd8b31cfa4aa2e61af879d0a3bf2a317c20217d"
checksum = "07cec4dc2d2e357ca1e610cfb07de2fa7a10fc3e9fe89f72545f3d244ea87753"
dependencies = [
"libc",
"objc2-core-foundation",

View file

@ -740,11 +740,19 @@
# result (broken, compiling, testing) into this JSON file.
#rust.save-toolstates = <none> (path)
# This is an array of the codegen backends that will be compiled for the rustc
# that's being compiled. The default is to only build the LLVM codegen backend,
# and currently the only standard options supported are `"llvm"`, `"cranelift"`
# and `"gcc"`. The first backend in this list will be used as default by rustc
# when no explicit backend is specified.
# This array serves three distinct purposes:
# - Backends in this list will be automatically compiled and included in the sysroot of each
# rustc compiled by bootstrap.
# - The first backend in this list will be configured as the **default codegen backend** by each
# rustc compiled by bootstrap. In other words, if the first backend is e.g. cranelift, then when
# we build a stage 1 rustc, it will by default compile Rust programs using the Cranelift backend.
# This also means that stage 2 rustc would get built by the Cranelift backend.
# - Running `x dist` (without additional arguments, or with `--include-default-paths`) will produce
# a dist component/tarball for the Cranelift backend if it is included in this array.
#
# Note that the LLVM codegen backend is special and will always be built and distributed.
#
# Currently, the only standard options supported here are `"llvm"`, `"cranelift"` and `"gcc"`.
#rust.codegen-backends = ["llvm"]
# Indicates whether LLD will be compiled and made available in the sysroot for rustc to execute, and

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,6 @@
use std::fmt;
use std::marker::PhantomData;
use crate::ptr::P;
use crate::tokenstream::LazyAttrTokenStream;
use crate::{
Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField,
@ -53,7 +52,7 @@ impl_has_node_id!(
WherePredicate,
);
impl<T: HasNodeId> HasNodeId for P<T> {
impl<T: HasNodeId> HasNodeId for Box<T> {
fn node_id(&self) -> NodeId {
(**self).node_id()
}
@ -119,7 +118,7 @@ impl<T: HasTokens> HasTokens for Option<T> {
}
}
impl<T: HasTokens> HasTokens for P<T> {
impl<T: HasTokens> HasTokens for Box<T> {
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
(**self).tokens()
}
@ -245,7 +244,7 @@ impl_has_attrs!(
);
impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility);
impl<T: HasAttrs> HasAttrs for P<T> {
impl<T: HasAttrs> HasAttrs for Box<T> {
const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
fn attrs(&self) -> &[Attribute] {
(**self).attrs()
@ -322,8 +321,8 @@ impl<Wrapped, Tag> AstNodeWrapper<Wrapped, Tag> {
}
// FIXME: remove after `stmt_expr_attributes` is stabilized.
impl<T, Tag> From<AstNodeWrapper<P<T>, Tag>> for AstNodeWrapper<T, Tag> {
fn from(value: AstNodeWrapper<P<T>, Tag>) -> Self {
impl<T, Tag> From<AstNodeWrapper<Box<T>, Tag>> for AstNodeWrapper<T, Tag> {
fn from(value: AstNodeWrapper<Box<T>, Tag>) -> Self {
AstNodeWrapper { wrapped: *value.wrapped, tag: value.tag }
}
}

View file

@ -13,7 +13,6 @@ use crate::ast::{
Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
PathSegment, Safety,
};
use crate::ptr::P;
use crate::token::{self, CommentKind, Delimiter, InvisibleOrigin, MetaVarKind, Token};
use crate::tokenstream::{
DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree,
@ -660,7 +659,7 @@ pub fn mk_attr_from_item(
span: Span,
) -> Attribute {
Attribute {
kind: AttrKind::Normal(P(NormalAttr { item, tokens })),
kind: AttrKind::Normal(Box::new(NormalAttr { item, tokens })),
id: g.mk_attr_id(),
style,
span,
@ -710,7 +709,7 @@ pub fn mk_attr_name_value_str(
span: Span,
) -> Attribute {
let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
let expr = P(Expr {
let expr = Box::new(Expr {
id: DUMMY_NODE_ID,
kind: ExprKind::Lit(lit),
span,

View file

@ -7,7 +7,6 @@ use std::fmt::{self, Display, Formatter};
use std::str::FromStr;
use crate::expand::{Decodable, Encodable, HashStable_Generic};
use crate::ptr::P;
use crate::{Ty, TyKind};
/// Forward and Reverse Mode are well known names for automatic differentiation implementations.
@ -162,7 +161,7 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool {
/// since Duplicated expects a mutable ref/ptr and we would thus end up with a shadow value
/// who is an indirect type, which doesn't match the primal scalar type. We can't prevent
/// users here from marking scalars as Duplicated, due to type aliases.
pub fn valid_ty_for_activity(ty: &P<Ty>, activity: DiffActivity) -> bool {
pub fn valid_ty_for_activity(ty: &Box<Ty>, activity: DiffActivity) -> bool {
use DiffActivity::*;
// It's always allowed to mark something as Const, since we won't compute derivatives wrt. it.
// Dual variants also support all types.

View file

@ -3,7 +3,6 @@ use rustc_macros::{Decodable, Encodable, Walkable};
use rustc_span::{Ident, Span, Symbol};
use crate::Expr;
use crate::ptr::P;
use crate::token::LitKind;
// Definitions:
@ -147,7 +146,7 @@ impl FormatArguments {
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct FormatArgument {
pub kind: FormatArgumentKind,
pub expr: P<Expr>,
pub expr: Box<Expr>,
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]

View file

@ -37,7 +37,6 @@ pub mod expand;
pub mod format;
pub mod mut_visit;
pub mod node_id;
pub mod ptr;
pub mod token;
pub mod tokenstream;
pub mod visit;

View file

@ -17,7 +17,6 @@ use smallvec::{SmallVec, smallvec};
use thin_vec::ThinVec;
use crate::ast::*;
use crate::ptr::P;
use crate::tokenstream::*;
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, LifetimeCtxt, VisitorResult, try_visit};
@ -41,7 +40,7 @@ pub(crate) trait MutVisitable<V: MutVisitor> {
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra);
}
impl<V: MutVisitor, T: ?Sized> MutVisitable<V> for P<T>
impl<V: MutVisitor, T: ?Sized> MutVisitable<V> for Box<T>
where
T: MutVisitable<V>,
{
@ -293,15 +292,15 @@ macro_rules! generate_flat_map_visitor_fns {
}
generate_flat_map_visitor_fns! {
visit_items, P<Item>, flat_map_item;
visit_foreign_items, P<ForeignItem>, flat_map_foreign_item;
visit_items, Box<Item>, flat_map_item;
visit_foreign_items, Box<ForeignItem>, flat_map_foreign_item;
visit_generic_params, GenericParam, flat_map_generic_param;
visit_stmts, Stmt, flat_map_stmt;
visit_exprs, P<Expr>, filter_map_expr;
visit_exprs, Box<Expr>, filter_map_expr;
visit_expr_fields, ExprField, flat_map_expr_field;
visit_pat_fields, PatField, flat_map_pat_field;
visit_variants, Variant, flat_map_variant;
visit_assoc_items, P<AssocItem>, flat_map_assoc_item, ctxt: AssocCtxt;
visit_assoc_items, Box<AssocItem>, flat_map_assoc_item, ctxt: AssocCtxt;
visit_where_predicates, WherePredicate, flat_map_where_predicate;
visit_params, Param, flat_map_param;
visit_field_defs, FieldDef, flat_map_field_def;
@ -333,12 +332,12 @@ generate_walk_flat_map_fns! {
walk_flat_map_where_predicate(WherePredicate) => visit_where_predicate;
walk_flat_map_field_def(FieldDef) => visit_field_def;
walk_flat_map_expr_field(ExprField) => visit_expr_field;
walk_flat_map_item(P<Item>) => visit_item;
walk_flat_map_foreign_item(P<ForeignItem>) => visit_foreign_item;
walk_flat_map_assoc_item(P<AssocItem>, ctxt: AssocCtxt) => visit_assoc_item;
walk_flat_map_item(Box<Item>) => visit_item;
walk_flat_map_foreign_item(Box<ForeignItem>) => visit_foreign_item;
walk_flat_map_assoc_item(Box<AssocItem>, ctxt: AssocCtxt) => visit_assoc_item;
}
pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Option<P<Expr>> {
pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: Box<Expr>) -> Option<Box<Expr>> {
vis.visit_expr(&mut e);
Some(e)
}

View file

@ -1,11 +0,0 @@
/// A pointer type that uniquely owns a heap allocation of type T.
///
/// This used to be its own type, but now it's just a typedef for `Box` and we are planning to
/// remove it soon.
pub type P<T> = Box<T>;
/// Construct a `P<T>` from a `T` value.
#[allow(non_snake_case)]
pub fn P<T>(value: T) -> P<T> {
Box::new(value)
}

View file

@ -20,7 +20,6 @@ use rustc_span::{Ident, Span, Symbol};
use thin_vec::ThinVec;
use crate::ast::*;
use crate::ptr::P;
use crate::tokenstream::DelimSpan;
#[derive(Copy, Clone, Debug, PartialEq)]
@ -82,7 +81,7 @@ pub(crate) trait Visitable<'a, V: Visitor<'a>> {
fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result;
}
impl<'a, V: Visitor<'a>, T: ?Sized> Visitable<'a, V> for P<T>
impl<'a, V: Visitor<'a>, T: ?Sized> Visitable<'a, V> for Box<T>
where
T: Visitable<'a, V>,
{
@ -322,7 +321,7 @@ macro_rules! common_visitor_and_walkers {
Fn(FnCtxt, &'a $($mut)? Visibility, &'a $($mut)? Fn),
/// E.g., `|x, y| body`.
Closure(&'a $($mut)? ClosureBinder, &'a $($mut)? Option<CoroutineKind>, &'a $($mut)? P<FnDecl>, &'a $($mut)? P<Expr>),
Closure(&'a $($mut)? ClosureBinder, &'a $($mut)? Option<CoroutineKind>, &'a $($mut)? Box<FnDecl>, &'a $($mut)? Box<Expr>),
}
impl<'a> FnKind<'a> {
@ -390,9 +389,9 @@ macro_rules! common_visitor_and_walkers {
ThinVec<(NodeId, Path)>,
ThinVec<PathSegment>,
ThinVec<PreciseCapturingArg>,
ThinVec<P<Pat>>,
ThinVec<P<Ty>>,
ThinVec<P<TyPat>>,
ThinVec<Box<Pat>>,
ThinVec<Box<Ty>>,
ThinVec<Box<TyPat>>,
);
// This macro generates `impl Visitable` and `impl MutVisitable` that forward to `Walkable`
@ -676,11 +675,11 @@ macro_rules! common_visitor_and_walkers {
// Do nothing.
}
fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> {
fn flat_map_foreign_item(&mut self, ni: Box<ForeignItem>) -> SmallVec<[Box<ForeignItem>; 1]> {
walk_flat_map_foreign_item(self, ni)
}
fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
fn flat_map_item(&mut self, i: Box<Item>) -> SmallVec<[Box<Item>; 1]> {
walk_flat_map_item(self, i)
}
@ -690,9 +689,9 @@ macro_rules! common_visitor_and_walkers {
fn flat_map_assoc_item(
&mut self,
i: P<AssocItem>,
i: Box<AssocItem>,
ctxt: AssocCtxt,
) -> SmallVec<[P<AssocItem>; 1]> {
) -> SmallVec<[Box<AssocItem>; 1]> {
walk_flat_map_assoc_item(self, i, ctxt)
}
@ -704,7 +703,7 @@ macro_rules! common_visitor_and_walkers {
walk_flat_map_arm(self, arm)
}
fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
fn filter_map_expr(&mut self, e: Box<Expr>) -> Option<Box<Expr>> {
walk_filter_map_expr(self, e)
}
@ -930,8 +929,13 @@ macro_rules! common_visitor_and_walkers {
}
impl_walkable!(|&$($mut)? $($lt)? self: Impl, vis: &mut V| {
let Impl { defaultness, safety, generics, constness, polarity, of_trait, self_ty, items } = self;
visit_visitable!($($mut)? vis, defaultness, safety, generics, constness, polarity, of_trait, self_ty);
let Impl { generics, of_trait, self_ty, items } = self;
try_visit!(vis.visit_generics(generics));
if let Some(box of_trait) = of_trait {
let TraitImplHeader { defaultness, safety, constness, polarity, trait_ref } = of_trait;
visit_visitable!($($mut)? vis, defaultness, safety, constness, polarity, trait_ref);
}
try_visit!(vis.visit_ty(self_ty));
visit_visitable_with!($($mut)? vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() });
V::Result::output()
});
@ -1144,15 +1148,15 @@ macro_rules! generate_list_visit_fns {
}
generate_list_visit_fns! {
visit_items, P<Item>, visit_item;
visit_foreign_items, P<ForeignItem>, visit_foreign_item;
visit_items, Box<Item>, visit_item;
visit_foreign_items, Box<ForeignItem>, visit_foreign_item;
visit_generic_params, GenericParam, visit_generic_param;
visit_stmts, Stmt, visit_stmt;
visit_exprs, P<Expr>, visit_expr;
visit_exprs, Box<Expr>, visit_expr;
visit_expr_fields, ExprField, visit_expr_field;
visit_pat_fields, PatField, visit_pat_field;
visit_variants, Variant, visit_variant;
visit_assoc_items, P<AssocItem>, visit_assoc_item, ctxt: AssocCtxt;
visit_assoc_items, Box<AssocItem>, visit_assoc_item, ctxt: AssocCtxt;
visit_where_predicates, WherePredicate, visit_where_predicate;
visit_params, Param, visit_param;
visit_field_defs, FieldDef, visit_field_def;

View file

@ -48,6 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
| asm::InlineAsmArch::Arm64EC
| asm::InlineAsmArch::RiscV32
| asm::InlineAsmArch::RiscV64
| asm::InlineAsmArch::LoongArch32
| asm::InlineAsmArch::LoongArch64
| asm::InlineAsmArch::S390x
);

View file

@ -1,7 +1,6 @@
use std::ops::ControlFlow;
use std::sync::Arc;
use rustc_ast::ptr::P as AstP;
use rustc_ast::*;
use rustc_ast_pretty::pprust::expr_to_string;
use rustc_data_structures::stack::ensure_sufficient_stack;
@ -53,7 +52,7 @@ impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor {
}
impl<'hir> LoweringContext<'_, 'hir> {
fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
fn lower_exprs(&mut self, exprs: &[Box<Expr>]) -> &'hir [hir::Expr<'hir>] {
self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
}
@ -455,7 +454,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_legacy_const_generics(
&mut self,
mut f: Expr,
args: ThinVec<AstP<Expr>>,
args: ThinVec<Box<Expr>>,
legacy_args_idx: &[usize],
) -> hir::ExprKind<'hir> {
let ExprKind::Path(None, path) = &mut f.kind else {
@ -495,7 +494,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.create_def(node_id, None, DefKind::AnonConst, f.span);
let mut visitor = WillCreateDefIdsVisitor {};
let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
AstP(Expr {
Box::new(Expr {
id: self.next_node_id(),
kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),
span: f.span,
@ -516,7 +515,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Add generic args to the last element of the path.
let last_segment = path.segments.last_mut().unwrap();
assert!(last_segment.args.is_none());
last_segment.args = Some(AstP(GenericArgs::AngleBracketed(AngleBracketedArgs {
last_segment.args = Some(Box::new(GenericArgs::AngleBracketed(AngleBracketedArgs {
span: DUMMY_SP,
args: generic_args,
})));
@ -812,7 +811,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_attrs(
inner_hir_id,
&[Attribute {
kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(
kind: AttrKind::Normal(Box::new(NormalAttr::from_ident(Ident::new(
sym::track_caller,
span,
)))),
@ -1285,7 +1284,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn extract_tuple_struct_path<'a>(
&mut self,
expr: &'a Expr,
) -> Option<(&'a Option<AstP<QSelf>>, &'a Path)> {
) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> {
if let ExprKind::Path(qself, path) = &expr.kind {
// Does the path resolve to something disallowed in a tuple struct/variant pattern?
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
@ -1307,7 +1306,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn extract_unit_struct_path<'a>(
&mut self,
expr: &'a Expr,
) -> Option<(&'a Option<AstP<QSelf>>, &'a Path)> {
) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> {
if let ExprKind::Path(qself, path) = &expr.kind {
// Does the path resolve to something disallowed in a unit struct/variant pattern?
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
@ -1478,7 +1477,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
/// Each sub-assignment is recorded in `assignments`.
fn destructure_sequence(
&mut self,
elements: &[AstP<Expr>],
elements: &[Box<Expr>],
ctx: &str,
eq_sign_span: Span,
assignments: &mut Vec<hir::Stmt<'hir>>,

View file

@ -1,5 +1,4 @@
use rustc_abi::ExternAbi;
use rustc_ast::ptr::P;
use rustc_ast::visit::AssocCtxt;
use rustc_ast::*;
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
@ -102,7 +101,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
impl<'hir> LoweringContext<'_, 'hir> {
pub(super) fn lower_mod(
&mut self,
items: &[P<Item>],
items: &[Box<Item>],
spans: &ModSpans,
) -> &'hir hir::Mod<'hir> {
self.arena.alloc(hir::Mod {
@ -341,13 +340,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
hir::ItemKind::Union(ident, generics, vdata)
}
ItemKind::Impl(box Impl {
safety,
polarity,
defaultness,
constness,
ItemKind::Impl(Impl {
generics: ast_generics,
of_trait: trait_ref,
of_trait,
self_ty: ty,
items: impl_items,
}) => {
@ -365,54 +360,30 @@ impl<'hir> LoweringContext<'_, 'hir> {
// lifetime to be added, but rather a reference to a
// parent lifetime.
let itctx = ImplTraitContext::Universal;
let (generics, (trait_ref, lowered_ty)) =
let (generics, (of_trait, lowered_ty)) =
self.lower_generics(ast_generics, id, itctx, |this| {
let modifiers = TraitBoundModifiers {
constness: BoundConstness::Never,
asyncness: BoundAsyncness::Normal,
// we don't use this in bound lowering
polarity: BoundPolarity::Positive,
};
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref(
modifiers,
trait_ref,
ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
)
});
let of_trait = of_trait
.as_deref()
.map(|of_trait| this.lower_trait_impl_header(of_trait));
let lowered_ty = this.lower_ty(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
);
(trait_ref, lowered_ty)
(of_trait, lowered_ty)
});
let new_impl_items = self
.arena
.alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item)));
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
// to not cause an assertion failure inside the `lower_defaultness` function.
let has_val = true;
let (defaultness, defaultness_span) = self.lower_defaultness(*defaultness, has_val);
let polarity = match polarity {
ImplPolarity::Positive => ImplPolarity::Positive,
ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)),
};
hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
constness: self.lower_constness(*constness),
safety: self.lower_safety(*safety, hir::Safety::Safe),
polarity,
defaultness,
defaultness_span,
hir::ItemKind::Impl(hir::Impl {
generics,
of_trait: trait_ref,
of_trait,
self_ty: lowered_ty,
items: new_impl_items,
}))
})
}
ItemKind::Trait(box Trait {
constness,
@ -462,7 +433,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => {
let ident = self.lower_ident(*ident);
let body = P(self.lower_delim_args(body));
let body = Box::new(self.lower_delim_args(body));
let def_id = self.local_def_id(id);
let def_kind = self.tcx.def_kind(def_id);
let DefKind::Macro(macro_kind) = def_kind else {
@ -983,6 +954,44 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.expr(span, hir::ExprKind::Err(guar))
}
fn lower_trait_impl_header(
&mut self,
trait_impl_header: &TraitImplHeader,
) -> &'hir hir::TraitImplHeader<'hir> {
let TraitImplHeader { constness, safety, polarity, defaultness, ref trait_ref } =
*trait_impl_header;
let constness = self.lower_constness(constness);
let safety = self.lower_safety(safety, hir::Safety::Safe);
let polarity = match polarity {
ImplPolarity::Positive => ImplPolarity::Positive,
ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)),
};
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
// to not cause an assertion failure inside the `lower_defaultness` function.
let has_val = true;
let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
let modifiers = TraitBoundModifiers {
constness: BoundConstness::Never,
asyncness: BoundAsyncness::Normal,
// we don't use this in bound lowering
polarity: BoundPolarity::Positive,
};
let trait_ref = self.lower_trait_ref(
modifiers,
trait_ref,
ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
);
self.arena.alloc(hir::TraitImplHeader {
constness,
safety,
polarity,
defaultness,
defaultness_span,
trait_ref,
})
}
fn lower_impl_item(
&mut self,
i: &AssocItem,

View file

@ -296,6 +296,7 @@ enum RelaxedBoundPolicy<'a> {
enum RelaxedBoundForbiddenReason {
TraitObjectTy,
SuperTrait,
AssocTyBounds,
LateBoundVarsInScope,
}
@ -1109,9 +1110,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar)));
hir::AssocItemConstraintKind::Equality { term: err_ty.into() }
} else {
// FIXME(#135229): These should be forbidden!
let bounds =
self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx);
let bounds = self.lower_param_bounds(
bounds,
RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::AssocTyBounds),
itctx,
);
hir::AssocItemConstraintKind::Bound { bounds }
}
}
@ -1217,7 +1220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_path_ty(
&mut self,
t: &Ty,
qself: &Option<ptr::P<QSelf>>,
qself: &Option<Box<QSelf>>,
path: &Path,
param_mode: ParamMode,
itctx: ImplTraitContext,
@ -2124,7 +2127,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
diag.emit();
return;
}
RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
RelaxedBoundForbiddenReason::AssocTyBounds
| RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
};
}
}

View file

@ -1,6 +1,5 @@
use std::sync::Arc;
use rustc_ast::ptr::P;
use rustc_ast::*;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::def::{DefKind, Res};
@ -154,7 +153,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_pat_tuple(
&mut self,
pats: &[P<Pat>],
pats: &[Box<Pat>],
ctx: &str,
) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) {
let mut elems = Vec::with_capacity(pats.len());
@ -209,7 +208,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// When encountering `($binding_mode $ident @)? ..` (`slice`),
/// this is interpreted as a sub-slice pattern semantically.
/// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
fn lower_pat_slice(&mut self, pats: &[P<Pat>]) -> hir::PatKind<'hir> {
fn lower_pat_slice(&mut self, pats: &[Box<Pat>]) -> hir::PatKind<'hir> {
let mut before = Vec::new();
let mut after = Vec::new();
let mut slice = None;

View file

@ -24,7 +24,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
pub(crate) fn lower_qpath(
&mut self,
id: NodeId,
qself: &Option<ptr::P<QSelf>>,
qself: &Option<Box<QSelf>>,
p: &Path,
param_mode: ParamMode,
allow_return_type_notation: AllowReturnTypeNotation,

View file

@ -175,11 +175,6 @@ ast_passes_generic_default_trailing = generic parameters with a default must be
ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
.help = remove one of these features
ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
.because = {$annotation} because of this
.type = inherent impl for this type
.only_trait = only trait implementations may be annotated with {$annotation}
ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot be declared with `safe` safety qualifier
.suggestion = remove safe from this item

View file

@ -22,7 +22,6 @@ use std::str::FromStr;
use itertools::{Either, Itertools};
use rustc_abi::{CanonAbi, ExternAbi, InterruptKind};
use rustc_ast::ptr::P;
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
use rustc_ast::*;
use rustc_ast_pretty::pprust::{self, State};
@ -719,7 +718,7 @@ impl<'a> AstValidator<'a> {
}
}
fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
fn deny_items(&self, trait_items: &[Box<AssocItem>], ident_span: Span) {
if !trait_items.is_empty() {
let spans: Vec<_> = trait_items.iter().map(|i| i.kind.ident().unwrap().span).collect();
let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
@ -955,13 +954,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
match &item.kind {
ItemKind::Impl(box Impl {
safety,
polarity,
defaultness: _,
constness,
ItemKind::Impl(Impl {
generics,
of_trait: Some(t),
of_trait:
Some(box TraitImplHeader {
safety,
polarity,
defaultness: _,
constness,
trait_ref: t,
}),
self_ty,
items,
}) => {
@ -993,46 +995,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true });
});
}
ItemKind::Impl(box Impl {
safety,
polarity,
defaultness,
constness,
generics,
of_trait: None,
self_ty,
items,
}) => {
let error = |annotation_span, annotation, only_trait| errors::InherentImplCannot {
span: self_ty.span,
annotation_span,
annotation,
self_ty: self_ty.span,
only_trait,
};
ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items }) => {
self.visit_attrs_vis(&item.attrs, &item.vis);
self.visibility_not_permitted(
&item.vis,
errors::VisibilityNotPermittedNote::IndividualImplItems,
);
if let &Safety::Unsafe(span) = safety {
self.dcx().emit_err(errors::InherentImplCannotUnsafe {
span: self_ty.span,
annotation_span: span,
annotation: "unsafe",
self_ty: self_ty.span,
});
}
if let &ImplPolarity::Negative(span) = polarity {
self.dcx().emit_err(error(span, "negative", false));
}
if let &Defaultness::Default(def_span) = defaultness {
self.dcx().emit_err(error(def_span, "`default`", true));
}
if let &Const::Yes(span) = constness {
self.dcx().emit_err(error(span, "`const`", true));
}
self.with_tilde_const(Some(TildeConstReason::Impl { span: item.span }), |this| {
this.visit_generics(generics)

View file

@ -464,32 +464,6 @@ pub(crate) struct UnsafeNegativeImpl {
pub r#unsafe: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_inherent_cannot_be)]
pub(crate) struct InherentImplCannot<'a> {
#[primary_span]
pub span: Span,
#[label(ast_passes_because)]
pub annotation_span: Span,
pub annotation: &'a str,
#[label(ast_passes_type)]
pub self_ty: Span,
#[note(ast_passes_only_trait)]
pub only_trait: bool,
}
#[derive(Diagnostic)]
#[diag(ast_passes_inherent_cannot_be, code = E0197)]
pub(crate) struct InherentImplCannotUnsafe<'a> {
#[primary_span]
pub span: Span,
#[label(ast_passes_because)]
pub annotation_span: Span,
pub annotation: &'a str,
#[label(ast_passes_type)]
pub self_ty: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_unsafe_item)]
pub(crate) struct UnsafeItem {

View file

@ -217,18 +217,18 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}
ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, of_trait, .. }) => {
if let &ast::ImplPolarity::Negative(span) = polarity {
ast::ItemKind::Impl(ast::Impl { of_trait: Some(of_trait), .. }) => {
if let ast::ImplPolarity::Negative(span) = of_trait.polarity {
gate!(
&self,
negative_impls,
span.to(of_trait.as_ref().map_or(span, |t| t.path.span)),
span.to(of_trait.trait_ref.path.span),
"negative trait bounds are not fully implemented; \
use marker types for now"
);
}
if let ast::Defaultness::Default(_) = defaultness {
if let ast::Defaultness::Default(_) = of_trait.defaultness {
gate!(&self, specialization, i.span, "specialization is unstable");
}
}

View file

@ -10,7 +10,6 @@ use std::borrow::Cow;
use std::sync::Arc;
use rustc_ast::attr::AttrIdGenerator;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
use rustc_ast::util::classify;
@ -1178,7 +1177,7 @@ impl<'a> State<'a> {
self.end(rb);
}
fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
fn commasep_exprs(&mut self, b: Breaks, exprs: &[Box<ast::Expr>]) {
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e, FixupContext::default()), |e| e.span)
}

View file

@ -2,7 +2,6 @@ use std::fmt::Write;
use ast::{ForLoopKind, MatchKind};
use itertools::{Itertools, Position};
use rustc_ast::ptr::P;
use rustc_ast::util::classify;
use rustc_ast::util::literal::escape_byte_str_symbol;
use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
@ -54,7 +53,7 @@ impl<'a> State<'a> {
self.print_else(elseopt)
}
fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
fn print_call_post(&mut self, args: &[Box<ast::Expr>]) {
self.popen();
self.commasep_exprs(Inconsistent, args);
self.pclose()
@ -111,7 +110,7 @@ impl<'a> State<'a> {
}
}
fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
fn print_expr_vec(&mut self, exprs: &[Box<ast::Expr>]) {
let ib = self.ibox(INDENT_UNIT);
self.word("[");
self.commasep_exprs(Inconsistent, exprs);
@ -149,7 +148,7 @@ impl<'a> State<'a> {
fn print_expr_struct(
&mut self,
qself: &Option<P<ast::QSelf>>,
qself: &Option<Box<ast::QSelf>>,
path: &ast::Path,
fields: &[ast::ExprField],
rest: &ast::StructRest,
@ -204,7 +203,7 @@ impl<'a> State<'a> {
self.word("}");
}
fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
fn print_expr_tup(&mut self, exprs: &[Box<ast::Expr>]) {
self.popen();
self.commasep_exprs(Inconsistent, exprs);
if exprs.len() == 1 {
@ -213,7 +212,7 @@ impl<'a> State<'a> {
self.pclose()
}
fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) {
fn print_expr_call(&mut self, func: &ast::Expr, args: &[Box<ast::Expr>], fixup: FixupContext) {
// Independent of parenthesization related to precedence, we must
// parenthesize `func` if this is a statement context in which without
// parentheses, a statement boundary would occur inside `func` or
@ -247,7 +246,7 @@ impl<'a> State<'a> {
&mut self,
segment: &ast::PathSegment,
receiver: &ast::Expr,
base_args: &[P<ast::Expr>],
base_args: &[Box<ast::Expr>],
fixup: FixupContext,
) {
// The fixup here is different than in `print_expr_call` because

View file

@ -2,7 +2,6 @@ use ast::StaticItem;
use itertools::{Itertools, Position};
use rustc_ast as ast;
use rustc_ast::ModKind;
use rustc_ast::ptr::P;
use rustc_span::Ident;
use crate::pp::BoxMarker;
@ -309,39 +308,41 @@ impl<'a> State<'a> {
let (cb, ib) = self.head(visibility_qualified(&item.vis, "union"));
self.print_struct(struct_def, generics, *ident, item.span, true, cb, ib);
}
ast::ItemKind::Impl(box ast::Impl {
safety,
polarity,
defaultness,
constness,
generics,
of_trait,
self_ty,
items,
}) => {
ast::ItemKind::Impl(ast::Impl { generics, of_trait, self_ty, items }) => {
let (cb, ib) = self.head("");
self.print_visibility(&item.vis);
self.print_defaultness(*defaultness);
self.print_safety(*safety);
self.word("impl");
if generics.params.is_empty() {
self.nbsp();
} else {
self.print_generic_params(&generics.params);
self.space();
}
let impl_generics = |this: &mut Self| {
this.word("impl");
self.print_constness(*constness);
if generics.params.is_empty() {
this.nbsp();
} else {
this.print_generic_params(&generics.params);
this.space();
}
};
if let ast::ImplPolarity::Negative(_) = polarity {
self.word("!");
}
if let Some(t) = of_trait {
self.print_trait_ref(t);
if let Some(box of_trait) = of_trait {
let ast::TraitImplHeader {
defaultness,
safety,
constness,
polarity,
ref trait_ref,
} = *of_trait;
self.print_defaultness(defaultness);
self.print_safety(safety);
impl_generics(self);
self.print_constness(constness);
if let ast::ImplPolarity::Negative(_) = polarity {
self.word("!");
}
self.print_trait_ref(trait_ref);
self.space();
self.word_space("for");
} else {
impl_generics(self);
}
self.print_type(self_ty);
@ -628,10 +629,10 @@ impl<'a> State<'a> {
&mut self,
attrs: &[ast::Attribute],
vis: &ast::Visibility,
qself: &Option<P<ast::QSelf>>,
qself: &Option<Box<ast::QSelf>>,
path: &ast::Path,
kind: DelegationKind<'_>,
body: &Option<P<ast::Block>>,
body: &Option<Box<ast::Block>>,
) {
let body_cb_ib = body.as_ref().map(|body| (body, self.head("")));
self.print_visibility(vis);

View file

@ -132,6 +132,7 @@ attr_parsing_unknown_version_literal =
attr_parsing_unrecognized_repr_hint =
unrecognized representation hint
.help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
.note = for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
attr_parsing_unstable_cfg_target_compact =
compact `cfg(target(..))` is experimental and subject to change

View file

@ -15,7 +15,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
type Item = (Symbol, Span);
const CONVERT: ConvertFn<Self::Item> =
|items, span| AttributeKind::AllowInternalUnstable(items, span);
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
@ -32,7 +32,7 @@ impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
type Item = (Symbol, Span);
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
@ -53,7 +53,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
type Item = Symbol;
const CONVERT: ConvertFn<Self::Item> =
|items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span);
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,

View file

@ -16,7 +16,10 @@ use crate::{
CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg,
};
pub const CFG_TEMPLATE: AttributeTemplate = template!(List: "predicate");
pub const CFG_TEMPLATE: AttributeTemplate = template!(
List: &["predicate"],
"https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute"
);
pub fn parse_cfg_attr<'c, S: Stage>(
cx: &'c mut AcceptContext<'_, '_, S>,

View file

@ -17,7 +17,7 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
const PATH: &[Symbol] = &[sym::optimize];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(List: "size|speed|none");
const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(list) = args.list() else {
@ -253,7 +253,7 @@ pub(crate) struct UsedParser {
impl<S: Stage> AttributeParser<S> for UsedParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
&[sym::used],
template!(Word, List: "compiler|linker"),
template!(Word, List: &["compiler", "linker"]),
|group: &mut Self, cx, args| {
let used_by = match args {
ArgParser::NoArgs => UsedBy::Linker,
@ -327,7 +327,7 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
type Item = (Symbol, Span);
const PATH: &[Symbol] = &[sym::target_feature];
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span);
const TEMPLATE: AttributeTemplate = template!(List: "enable = \"feat1, feat2\"");
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,

View file

@ -16,7 +16,7 @@ pub(crate) struct ConfusablesParser {
impl<S: Stage> AttributeParser<S> for ConfusablesParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
&[sym::rustc_confusables],
template!(List: r#""name1", "name2", ..."#),
template!(List: &[r#""name1", "name2", ..."#]),
|this, cx, args| {
let Some(list) = args.list() else {
cx.expected_list(cx.attr_span);

View file

@ -40,7 +40,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(
Word,
List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
List: &[r#"since = "version""#, r#"note = "reason""#, r#"since = "version", note = "reason""#],
NameValueStr: "reason"
);

View file

@ -18,7 +18,11 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
const PATH: &'static [Symbol] = &[sym::inline];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(Word, List: "always|never");
const TEMPLATE: AttributeTemplate = template!(
Word,
List: &["always", "never"],
"https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
match args {
@ -59,7 +63,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason");
const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let reason = match args {

View file

@ -16,7 +16,10 @@ impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
const PATH: &[Symbol] = &[sym::link_name];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
const TEMPLATE: AttributeTemplate = template!(
NameValueStr: "name",
"https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"
);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
@ -38,7 +41,10 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
const PATH: &[Symbol] = &[sym::link_section];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
const TEMPLATE: AttributeTemplate = template!(
NameValueStr: "name",
"https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
@ -94,7 +100,10 @@ impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
const PATH: &[Symbol] = &[sym::link_ordinal];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(List: "ordinal");
const TEMPLATE: AttributeTemplate = template!(
List: &["ordinal"],
"https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let ordinal = parse_single_integer(cx, args)?;

View file

@ -31,7 +31,10 @@ pub(crate) struct MacroUseParser {
first_span: Option<Span>,
}
const MACRO_USE_TEMPLATE: AttributeTemplate = template!(Word, List: "name1, name2, ...");
const MACRO_USE_TEMPLATE: AttributeTemplate = template!(
Word, List: &["name1, name2, ..."],
"https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"
);
impl<S: Stage> AttributeParser<S> for MacroUseParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
@ -113,3 +116,11 @@ impl<S: Stage> AttributeParser<S> for MacroUseParser {
Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state })
}
}
pub(crate) struct AllowInternalUnsafeParser;
impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser {
const PATH: &[Symbol] = &[sym::allow_internal_unsafe];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
}

View file

@ -14,7 +14,10 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
const PATH: &[Symbol] = &[sym::must_use];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(Word, NameValueStr: "reason");
const TEMPLATE: AttributeTemplate = template!(
Word, NameValueStr: "reason",
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"
);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
Some(AttributeKind::MustUse {

View file

@ -12,7 +12,10 @@ impl<S: Stage> SingleAttributeParser<S> for PathParser {
const PATH: &[Symbol] = &[sym::path];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "file");
const TEMPLATE: AttributeTemplate = template!(
NameValueStr: "file",
"https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"
);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {

View file

@ -28,8 +28,10 @@ impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
const PATH: &[Symbol] = &[sym::proc_macro_derive];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate =
template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
const TEMPLATE: AttributeTemplate = template!(
List: &["TraitName", "TraitName, attributes(name1, name2, ...)"],
"https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros"
);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let (trait_name, helper_attrs) = parse_derive_like(cx, args, true)?;
@ -47,7 +49,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate =
template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?;

View file

@ -26,8 +26,10 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
const CONVERT: ConvertFn<Self::Item> =
|items, first_span| AttributeKind::Repr { reprs: items, first_span };
// FIXME(jdonszelmann): never used
const TEMPLATE: AttributeTemplate =
template!(List: "C | Rust | align(...) | packed(...) | <integer type> | transparent");
const TEMPLATE: AttributeTemplate = template!(
List: &["C", "Rust", "transparent", "align(...)", "packed(...)", "<integer type>"],
"https://doc.rust-lang.org/reference/type-layout.html#representations"
);
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
@ -275,7 +277,7 @@ pub(crate) struct AlignParser(Option<(Align, Span)>);
impl AlignParser {
const PATH: &'static [Symbol] = &[sym::rustc_align];
const TEMPLATE: AttributeTemplate = template!(List: "<alignment in bytes>");
const TEMPLATE: AttributeTemplate = template!(List: &["<alignment in bytes>"]);
fn parse<'c, S: Stage>(
&mut self,

View file

@ -12,7 +12,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStart {
const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(List: "start");
const TEMPLATE: AttributeTemplate = template!(List: &["start"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
parse_single_integer(cx, args)
@ -26,7 +26,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEnd {
const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(List: "end");
const TEMPLATE: AttributeTemplate = template!(List: &["end"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
parse_single_integer(cx, args)

View file

@ -48,7 +48,7 @@ impl<S: Stage> AttributeParser<S> for StabilityParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[
(
&[sym::stable],
template!(List: r#"feature = "name", since = "version""#),
template!(List: &[r#"feature = "name", since = "version""#]),
|this, cx, args| {
reject_outside_std!(cx);
if !this.check_duplicate(cx)
@ -60,7 +60,7 @@ impl<S: Stage> AttributeParser<S> for StabilityParser {
),
(
&[sym::unstable],
template!(List: r#"feature = "name", reason = "...", issue = "N""#),
template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]),
|this, cx, args| {
reject_outside_std!(cx);
if !this.check_duplicate(cx)
@ -131,7 +131,7 @@ pub(crate) struct BodyStabilityParser {
impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
&[sym::rustc_default_body_unstable],
template!(List: r#"feature = "name", reason = "...", issue = "N""#),
template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]),
|this, cx, args| {
reject_outside_std!(cx);
if this.stability.is_some() {
@ -177,29 +177,37 @@ impl ConstStabilityParser {
impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[
(&[sym::rustc_const_stable], template!(List: r#"feature = "name""#), |this, cx, args| {
reject_outside_std!(cx);
(
&[sym::rustc_const_stable],
template!(List: &[r#"feature = "name""#]),
|this, cx, args| {
reject_outside_std!(cx);
if !this.check_duplicate(cx)
&& let Some((feature, level)) = parse_stability(cx, args)
{
this.stability = Some((
PartialConstStability { level, feature, promotable: false },
cx.attr_span,
));
}
}),
(&[sym::rustc_const_unstable], template!(List: r#"feature = "name""#), |this, cx, args| {
reject_outside_std!(cx);
if !this.check_duplicate(cx)
&& let Some((feature, level)) = parse_unstability(cx, args)
{
this.stability = Some((
PartialConstStability { level, feature, promotable: false },
cx.attr_span,
));
}
}),
if !this.check_duplicate(cx)
&& let Some((feature, level)) = parse_stability(cx, args)
{
this.stability = Some((
PartialConstStability { level, feature, promotable: false },
cx.attr_span,
));
}
},
),
(
&[sym::rustc_const_unstable],
template!(List: &[r#"feature = "name""#]),
|this, cx, args| {
reject_outside_std!(cx);
if !this.check_duplicate(cx)
&& let Some((feature, level)) = parse_unstability(cx, args)
{
this.stability = Some((
PartialConstStability { level, feature, promotable: false },
cx.attr_span,
));
}
},
),
(&[sym::rustc_promotable], template!(Word), |this, cx, _| {
reject_outside_std!(cx);
this.promotable = true;

View file

@ -13,7 +13,10 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
const PATH: &[Symbol] = &[sym::ignore];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const TEMPLATE: AttributeTemplate = template!(Word, NameValueStr: "reason");
const TEMPLATE: AttributeTemplate = template!(
Word, NameValueStr: "reason",
"https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
Some(AttributeKind::Ignore {
@ -51,8 +54,10 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
const PATH: &[Symbol] = &[sym::should_panic];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate =
template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason");
const TEMPLATE: AttributeTemplate = template!(
Word, List: &[r#"expected = "reason""#], NameValueStr: "reason",
"https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
Some(AttributeKind::ShouldPanic {

View file

@ -16,7 +16,7 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(List: "array, boxed_slice");
const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let mut array = false;

View file

@ -19,7 +19,7 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes");
});
const TEMPLATE: AttributeTemplate =
template!(NameValueStr: "transparent|semitransparent|opaque");
template!(NameValueStr: ["transparent", "semitransparent", "opaque"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {

View file

@ -33,7 +33,9 @@ use crate::attributes::lint_helpers::{
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
};
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::macro_attrs::{MacroEscapeParser, MacroUseParser};
use crate::attributes::macro_attrs::{
AllowInternalUnsafeParser, MacroEscapeParser, MacroUseParser,
};
use crate::attributes::must_use::MustUseParser;
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
use crate::attributes::non_exhaustive::NonExhaustiveParser;
@ -178,6 +180,7 @@ attribute_parsers!(
Single<SkipDuringMethodDispatchParser>,
Single<TransparencyParser>,
Single<WithoutArgs<AllowIncoherentImplParser>>,
Single<WithoutArgs<AllowInternalUnsafeParser>>,
Single<WithoutArgs<AsPtrParser>>,
Single<WithoutArgs<AutomaticallyDerivedParser>>,
Single<WithoutArgs<CoherenceIsCoreParser>>,

View file

@ -498,6 +498,7 @@ pub(crate) struct ReprIdent {
#[derive(Diagnostic)]
#[diag(attr_parsing_unrecognized_repr_hint, code = E0552)]
#[help]
#[note]
pub(crate) struct UnrecognizedReprHint {
#[primary_span]
pub span: Span,
@ -690,6 +691,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
}
}
if let Some(link) = self.template.docs {
diag.note(format!("for more information, visit <{link}>"));
}
let suggestions = self.template.suggestions(false, &name);
diag.span_suggestions(
self.attr_span,

View file

@ -410,18 +410,18 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
let typeck = self.infcx.tcx.typeck(self.mir_def_id());
let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);
let (def_id, call_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
{
let def_id = typeck.type_dependent_def_id(parent_expr.hir_id);
(def_id, Some(parent_expr.hir_id), args, 1)
(def_id, args, 1)
} else if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::Call(call, args) = parent_expr.kind
&& let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
{
(Some(*def_id), Some(call.hir_id), args, 0)
(Some(*def_id), args, 0)
} else {
(None, None, &[][..], 0)
(None, &[][..], 0)
};
let ty = place.ty(self.body, self.infcx.tcx).ty;
@ -459,11 +459,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
// If the moved place is used generically by the callee and a reference to it
// would still satisfy any bounds on its type, suggest borrowing.
if let Some(&param) = arg_param
&& let Some(generic_args) = call_id.and_then(|id| typeck.node_args_opt(id))
&& let hir::Node::Expr(call_expr) = parent
&& let Some(ref_mutability) = self.suggest_borrow_generic_arg(
err,
typeck,
call_expr,
def_id,
generic_args,
param,
moved_place,
pos + offset,
@ -627,8 +628,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
fn suggest_borrow_generic_arg(
&self,
err: &mut Diag<'_>,
typeck: &ty::TypeckResults<'tcx>,
call_expr: &hir::Expr<'tcx>,
callee_did: DefId,
generic_args: ty::GenericArgsRef<'tcx>,
param: ty::ParamTy,
moved_place: PlaceRef<'tcx>,
moved_arg_pos: usize,
@ -639,6 +641,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();
let clauses = tcx.predicates_of(callee_did);
let generic_args = match call_expr.kind {
// For method calls, generic arguments are attached to the call node.
hir::ExprKind::MethodCall(..) => typeck.node_args_opt(call_expr.hir_id)?,
// For normal calls, generic arguments are in the callee's type.
// This diagnostic is only run for `FnDef` callees.
hir::ExprKind::Call(callee, _)
if let &ty::FnDef(_, args) = typeck.node_type(callee.hir_id).kind() =>
{
args
}
_ => return None,
};
// First, is there at least one method on one of `param`'s trait bounds?
// This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.
if !clauses.instantiate_identity(tcx).predicates.iter().any(|clause| {

View file

@ -51,7 +51,7 @@ mod conflict_errors;
mod explain_borrow;
mod move_errors;
mod mutability_errors;
mod opaque_suggestions;
mod opaque_types;
mod region_errors;
pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo};

View file

@ -9,7 +9,8 @@ use rustc_middle::bug;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
use rustc_span::def_id::DefId;
use rustc_span::{BytePos, DUMMY_SP, ExpnKind, MacroKind, Span};
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
use rustc_trait_selection::infer::InferCtxtExt;
use tracing::debug;
@ -507,12 +508,18 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
);
let closure_span = tcx.def_span(def_id);
self.cannot_move_out_of(span, &place_description)
.with_span_label(upvar_span, "captured outer variable")
.with_span_label(
closure_span,
format!("captured by this `{closure_kind}` closure"),
)
.with_span_help(
self.get_closure_bound_clause_span(*def_id),
"`Fn` and `FnMut` closures require captured values to be able to be \
consumed multiple times, but an `FnOnce` consume them only once",
)
}
_ => {
let source = self.borrowed_content_source(deref_base);
@ -561,6 +568,47 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
err
}
fn get_closure_bound_clause_span(&self, def_id: DefId) -> Span {
let tcx = self.infcx.tcx;
let typeck_result = tcx.typeck(self.mir_def_id());
// Check whether the closure is an argument to a call, if so,
// get the instantiated where-bounds of that call.
let closure_hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return DUMMY_SP };
let predicates = match parent.kind {
hir::ExprKind::Call(callee, _) => {
let Some(ty) = typeck_result.node_type_opt(callee.hir_id) else { return DUMMY_SP };
let ty::FnDef(fn_def_id, args) = ty.kind() else { return DUMMY_SP };
tcx.predicates_of(fn_def_id).instantiate(tcx, args)
}
hir::ExprKind::MethodCall(..) => {
let Some((_, method)) = typeck_result.type_dependent_def(parent.hir_id) else {
return DUMMY_SP;
};
let args = typeck_result.node_args(parent.hir_id);
tcx.predicates_of(method).instantiate(tcx, args)
}
_ => return DUMMY_SP,
};
// Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`.
for (pred, span) in predicates.predicates.iter().zip(predicates.spans.iter()) {
if let Some(clause) = pred.as_trait_clause()
&& let ty::Closure(clause_closure_def_id, _) = clause.self_ty().skip_binder().kind()
&& *clause_closure_def_id == def_id
&& (tcx.lang_items().fn_mut_trait() == Some(clause.def_id())
|| tcx.lang_items().fn_trait() == Some(clause.def_id()))
{
// Found `<TyOfCapturingClosure as FnMut>`
// We point at the `Fn()` or `FnMut()` bound that coerced the closure, which
// could be changed to `FnOnce()` to avoid the move error.
return *span;
}
}
DUMMY_SP
}
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
match error {
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {

View file

@ -18,9 +18,28 @@ use rustc_trait_selection::errors::impl_trait_overcapture_suggestion;
use crate::MirBorrowckCtxt;
use crate::borrow_set::BorrowData;
use crate::consumers::RegionInferenceContext;
use crate::region_infer::opaque_types::DeferredOpaqueTypeError;
use crate::type_check::Locations;
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
pub(crate) fn report_opaque_type_errors(&mut self, errors: Vec<DeferredOpaqueTypeError<'tcx>>) {
if errors.is_empty() {
return;
}
let mut guar = None;
for error in errors {
guar = Some(match error {
DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err) => err.report(self.infcx),
DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(err) => {
self.infcx.dcx().emit_err(err)
}
});
}
let guar = guar.unwrap();
self.root_cx.set_tainted_by_errors(guar);
self.infcx.set_tainted_by_errors(guar);
}
/// Try to note when an opaque is involved in a borrowck error and that
/// opaque captures lifetimes due to edition 2024.
// FIXME: This code is otherwise somewhat general, and could easily be adapted

View file

@ -92,9 +92,6 @@ impl<'tcx> RegionErrors<'tcx> {
) -> impl Iterator<Item = (RegionErrorKind<'tcx>, ErrorGuaranteed)> {
self.0.into_iter()
}
pub(crate) fn has_errors(&self) -> Option<ErrorGuaranteed> {
self.0.get(0).map(|x| x.1)
}
}
impl std::fmt::Debug for RegionErrors<'_> {

View file

@ -157,7 +157,7 @@ fn region_definitions<'tcx>(
for info in var_infos.iter() {
let origin = match info.origin {
RegionVariableOrigin::Nll(origin) => origin,
_ => NllRegionVariableOrigin::Existential { from_forall: false },
_ => NllRegionVariableOrigin::Existential { name: None },
};
let definition = RegionDefinition { origin, universe: info.universe, external_name: None };
@ -216,22 +216,11 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
placeholder_index_to_region: _,
liveness_constraints,
mut outlives_constraints,
mut member_constraints,
member_constraints,
universe_causes,
type_tests,
} = constraints;
if let Some(guar) = universal_regions.tainted_by_errors() {
debug!("Universal regions tainted by errors; removing constraints!");
// Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all
// outlives bounds that we may end up checking.
outlives_constraints = Default::default();
member_constraints = Default::default();
// Also taint the entire scope.
infcx.set_tainted_by_errors(guar);
}
let fr_static = universal_regions.fr_static;
let compute_sccs =
|constraints: &OutlivesConstraintSet<'tcx>,

View file

@ -375,7 +375,7 @@ fn do_mir_borrowck<'tcx>(
polonius_context,
);
regioncx.infer_opaque_types(root_cx, &infcx, opaque_type_values);
let opaque_type_errors = regioncx.infer_opaque_types(root_cx, &infcx, opaque_type_values);
// Dump MIR results into a file, if that is enabled. This lets us
// write unit-tests, as well as helping with debugging.
@ -471,7 +471,11 @@ fn do_mir_borrowck<'tcx>(
};
// Compute and report region errors, if any.
mbcx.report_region_errors(nll_errors);
if nll_errors.is_empty() {
mbcx.report_opaque_type_errors(opaque_type_errors);
} else {
mbcx.report_region_errors(nll_errors);
}
let (mut flow_analysis, flow_entry_states) =
get_flow_results(tcx, body, &move_data, &borrow_set, &regioncx);

View file

@ -148,11 +148,6 @@ pub(crate) fn compute_regions<'tcx>(
let (closure_region_requirements, nll_errors) =
regioncx.solve(infcx, body, polonius_output.clone());
if let Some(guar) = nll_errors.has_errors() {
// Suppress unhelpful extra errors in `infer_opaque_types`.
infcx.set_tainted_by_errors(guar);
}
NllOutput {
regioncx,
polonius_input: polonius_facts.map(Box::new),

View file

@ -7,9 +7,7 @@ use rustc_mir_dataflow::points::PointIndex;
///
/// This models two sources of constraints:
/// - constraints that traverse the subsets between regions at a given point, `a@p: b@p`. These
/// depend on typeck constraints generated via assignments, calls, etc. (In practice there are
/// subtleties where a statement's effect only starts being visible at the successor point, via
/// the "result" of that statement).
/// depend on typeck constraints generated via assignments, calls, etc.
/// - constraints that traverse the CFG via the same region, `a@p: a@q`, where `p` is a predecessor
/// of `q`. These depend on the liveness of the regions at these points, as well as their
/// variance.

View file

@ -184,22 +184,6 @@ where
}
}
impl<A, B, C, D> FactRow for (A, B, C, D)
where
A: FactCell,
B: FactCell,
C: FactCell,
D: FactCell,
{
fn write(
&self,
out: &mut dyn Write,
location_table: &PoloniusLocationTable,
) -> Result<(), Box<dyn Error>> {
write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
}
}
fn write_row(
out: &mut dyn Write,
location_table: &PoloniusLocationTable,

View file

@ -105,22 +105,14 @@ fn propagate_loans_between_points(
});
}
let Some(current_live_regions) = live_regions.row(current_point) else {
// There are no constraints to add: there are no live regions at the current point.
return;
};
let Some(next_live_regions) = live_regions.row(next_point) else {
// There are no constraints to add: there are no live regions at the next point.
return;
};
for region in next_live_regions.iter() {
if !current_live_regions.contains(region) {
continue;
}
// `region` is indeed live at both points, add a constraint between them, according to
// variance.
// `region` could be live at the current point, and is live at the next point: add a
// constraint between them, according to variance.
if let Some(&direction) = live_region_variances.get(&region) {
add_liveness_constraint(
region,

View file

@ -1,27 +1,18 @@
use std::collections::{BTreeMap, BTreeSet};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{
Body, Local, Location, Place, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
};
use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_middle::ty::RegionVid;
use rustc_mir_dataflow::points::PointIndex;
use super::{LiveLoans, LocalizedOutlivesConstraintSet};
use crate::BorrowSet;
use crate::constraints::OutlivesConstraint;
use crate::dataflow::BorrowIndex;
use crate::region_infer::values::LivenessValues;
use crate::type_check::Locations;
use crate::{BorrowSet, PlaceConflictBias, places_conflict};
/// Compute loan reachability, stop at kills, and trace loan liveness throughout the CFG, by
/// Compute loan reachability to approximately trace loan liveness throughout the CFG, by
/// traversing the full graph of constraints that combines:
/// - the localized constraints (the physical edges),
/// - with the constraints that hold at all points (the logical edges).
pub(super) fn compute_loan_liveness<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
liveness: &LivenessValues,
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
borrow_set: &BorrowSet<'tcx>,
@ -29,11 +20,6 @@ pub(super) fn compute_loan_liveness<'tcx>(
) -> LiveLoans {
let mut live_loans = LiveLoans::new(borrow_set.len());
// FIXME: it may be preferable for kills to be encoded in the edges themselves, to simplify and
// likely make traversal (and constraint generation) more efficient. We also display kills on
// edges when visualizing the constraint graph anyways.
let kills = collect_kills(body, tcx, borrow_set);
// Create the full graph with the physical edges we've localized earlier, and the logical edges
// of constraints that hold at all points.
let logical_constraints =
@ -59,15 +45,15 @@ pub(super) fn compute_loan_liveness<'tcx>(
continue;
}
// Record the loan as being live on entry to this point.
live_loans.insert(node.point, loan_idx);
// Here, we have a conundrum. There's currently a weakness in our theory, in that
// we're using a single notion of reachability to represent what used to be _two_
// different transitive closures. It didn't seem impactful when coming up with the
// single-graph and reachability through space (regions) + time (CFG) concepts, but in
// practice the combination of time-traveling with kills is more impactful than
// initially anticipated.
// Record the loan as being live on entry to this point if it reaches a live region
// there.
//
// This is an approximation of liveness (which is the thing we want), in that we're
// using a single notion of reachability to represent what used to be _two_ different
// transitive closures. It didn't seem impactful when coming up with the single-graph
// and reachability through space (regions) + time (CFG) concepts, but in practice the
// combination of time-traveling with kills is more impactful than initially
// anticipated.
//
// Kills should prevent a loan from reaching its successor points in the CFG, but not
// while time-traveling: we're not actually at that CFG point, but looking for
@ -92,40 +78,20 @@ pub(super) fn compute_loan_liveness<'tcx>(
// two-step traversal described above: only kills encountered on exit via a backward
// edge are ignored.
//
// In our test suite, there are a couple of cases where kills are encountered while
// time-traveling, however as far as we can tell, always in cases where they would be
// unreachable. We have reason to believe that this is a property of the single-graph
// approach (but haven't proved it yet):
// - reachable kills while time-traveling would also be encountered via regular
// traversal
// - it makes _some_ sense to ignore unreachable kills, but subtleties around dead code
// in general need to be better thought through (like they were for NLLs).
// - ignoring kills is a conservative approximation: the loan is still live and could
// cause false positive errors at another place access. Soundness issues in this
// domain should look more like the absence of reachability instead.
// This version of the analysis, however, is enough in practice to pass the tests that
// we care about and NLLs reject, without regressions on crater, and is an actionable
// subset of the full analysis. It also naturally points to areas of improvement that we
// wish to explore later, namely handling kills appropriately during traversal, instead
// of continuing traversal to all the reachable nodes.
//
// This is enough in practice to pass tests, and therefore is what we have implemented
// for now.
//
// FIXME: all of the above. Analyze potential unsoundness, possibly in concert with a
// borrowck implementation in a-mir-formality, fuzzing, or manually crafting
// counter-examples.
// FIXME: analyze potential unsoundness, possibly in concert with a borrowck
// implementation in a-mir-formality, fuzzing, or manually crafting counter-examples.
// Continuing traversal will depend on whether the loan is killed at this point, and
// whether we're time-traveling.
let current_location = liveness.location_from_point(node.point);
let is_loan_killed =
kills.get(&current_location).is_some_and(|kills| kills.contains(&loan_idx));
if liveness.is_live_at(node.region, liveness.location_from_point(node.point)) {
live_loans.insert(node.point, loan_idx);
}
for succ in graph.outgoing_edges(node) {
// If the loan is killed at this point, it is killed _on exit_. But only during
// forward traversal.
if is_loan_killed {
let destination = liveness.location_from_point(succ.point);
if current_location.is_predecessor_of(destination, body) {
continue;
}
}
stack.push(succ);
}
}
@ -192,116 +158,3 @@ impl LocalizedConstraintGraph {
physical_edges.chain(materialized_edges)
}
}
/// Traverses the MIR and collects kills.
fn collect_kills<'tcx>(
body: &Body<'tcx>,
tcx: TyCtxt<'tcx>,
borrow_set: &BorrowSet<'tcx>,
) -> BTreeMap<Location, BTreeSet<BorrowIndex>> {
let mut collector = KillsCollector { borrow_set, tcx, body, kills: BTreeMap::default() };
for (block, data) in body.basic_blocks.iter_enumerated() {
collector.visit_basic_block_data(block, data);
}
collector.kills
}
struct KillsCollector<'a, 'tcx> {
body: &'a Body<'tcx>,
tcx: TyCtxt<'tcx>,
borrow_set: &'a BorrowSet<'tcx>,
/// The set of loans killed at each location.
kills: BTreeMap<Location, BTreeSet<BorrowIndex>>,
}
// This visitor has a similar structure to the `Borrows` dataflow computation with respect to kills,
// and the datalog polonius fact generation for the `loan_killed_at` relation.
impl<'tcx> KillsCollector<'_, 'tcx> {
/// Records the borrows on the specified place as `killed`. For example, when assigning to a
/// local, or on a call's return destination.
fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Location) {
// For the reasons described in graph traversal, we also filter out kills
// unreachable from the loan's introduction point, as they would stop traversal when
// e.g. checking for reachability in the subset graph through invariance constraints
// higher up.
let filter_unreachable_kills = |loan| {
let introduction = self.borrow_set[loan].reserve_location;
let reachable = introduction.is_predecessor_of(location, self.body);
reachable
};
let other_borrows_of_local = self
.borrow_set
.local_map
.get(&place.local)
.into_iter()
.flat_map(|bs| bs.iter())
.copied();
// If the borrowed place is a local with no projections, all other borrows of this
// local must conflict. This is purely an optimization so we don't have to call
// `places_conflict` for every borrow.
if place.projection.is_empty() {
if !self.body.local_decls[place.local].is_ref_to_static() {
self.kills
.entry(location)
.or_default()
.extend(other_borrows_of_local.filter(|&loan| filter_unreachable_kills(loan)));
}
return;
}
// By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
// pair of array indices are not equal, so that when `places_conflict` returns true, we
// will be assured that two places being compared definitely denotes the same sets of
// locations.
let definitely_conflicting_borrows = other_borrows_of_local
.filter(|&i| {
places_conflict(
self.tcx,
self.body,
self.borrow_set[i].borrowed_place,
place,
PlaceConflictBias::NoOverlap,
)
})
.filter(|&loan| filter_unreachable_kills(loan));
self.kills.entry(location).or_default().extend(definitely_conflicting_borrows);
}
/// Records the borrows on the specified local as `killed`.
fn record_killed_borrows_for_local(&mut self, local: Local, location: Location) {
if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
self.kills.entry(location).or_default().extend(borrow_indices.iter());
}
}
}
impl<'tcx> Visitor<'tcx> for KillsCollector<'_, 'tcx> {
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
// Make sure there are no remaining borrows for locals that have gone out of scope.
if let StatementKind::StorageDead(local) = statement.kind {
self.record_killed_borrows_for_local(local, location);
}
self.super_statement(statement, location);
}
fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
// When we see `X = ...`, then kill borrows of `(*X).foo` and so forth.
self.record_killed_borrows_for_place(*place, location);
self.super_assign(place, rvalue, location);
}
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
// A `Call` terminator's return value can be a local which has borrows, so we need to record
// those as killed as well.
if let TerminatorKind::Call { destination, .. } = terminator.kind {
self.record_killed_borrows_for_place(destination, location);
}
self.super_terminator(terminator, location);
}
}

View file

@ -146,8 +146,8 @@ impl PoloniusContext {
/// - converting NLL typeck constraints to be localized
/// - encoding liveness constraints
///
/// Then, this graph is traversed, and combined with kills, reachability is recorded as loan
/// liveness, to be used by the loan scope and active loans computations.
/// Then, this graph is traversed, reachability is recorded as loan liveness, to be used by the
/// loan scope and active loans computations.
///
/// The constraint data will be used to compute errors and diagnostics.
pub(crate) fn compute_loan_liveness<'tcx>(
@ -182,8 +182,6 @@ impl PoloniusContext {
// Now that we have a complete graph, we can compute reachability to trace the liveness of
// loans for the next step in the chain, the NLL loan scope and active loans computations.
let live_loans = compute_loan_liveness(
tcx,
body,
regioncx.liveness_constraints(),
regioncx.outlives_constraints(),
borrow_set,

View file

@ -47,9 +47,7 @@ pub(super) fn convert_typeck_constraints<'tcx>(
tcx,
body,
stmt,
liveness,
&outlives_constraint,
location,
point,
universal_regions,
)
@ -78,9 +76,7 @@ fn localize_statement_constraint<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
stmt: &Statement<'tcx>,
liveness: &LivenessValues,
outlives_constraint: &OutlivesConstraint<'tcx>,
current_location: Location,
current_point: PointIndex,
universal_regions: &UniversalRegions<'tcx>,
) -> LocalizedOutlivesConstraint {
@ -98,8 +94,8 @@ fn localize_statement_constraint<'tcx>(
// - and that should be impossible in MIR
//
// When we have a more complete implementation in the future, tested with crater, etc,
// we can relax this to a debug assert instead, or remove it.
assert!(
// we can remove this assertion. It's a debug assert because it can be expensive.
debug_assert!(
{
let mut lhs_regions = FxHashSet::default();
tcx.for_each_free_region(lhs, |region| {
@ -119,16 +115,8 @@ fn localize_statement_constraint<'tcx>(
"there should be no common regions between the LHS and RHS of an assignment"
);
// As mentioned earlier, we should be tracking these better upstream but: we want to
// relate the types on entry to the type of the place on exit. That is, outlives
// constraints on the RHS are on entry, and outlives constraints to/from the LHS are on
// exit (i.e. on entry to the successor location).
let lhs_ty = body.local_decls[lhs.local].ty;
let successor_location = Location {
block: current_location.block,
statement_index: current_location.statement_index + 1,
};
let successor_point = liveness.point_from_location(successor_location);
let successor_point = current_point;
compute_constraint_direction(
tcx,
outlives_constraint,
@ -195,6 +183,7 @@ fn localize_terminator_constraint<'tcx>(
}
}
}
/// For a given outlives constraint and CFG edge, returns the localized constraint with the
/// appropriate `from`-`to` direction. This is computed according to whether the constraint flows to
/// or from a free region in the given `value`, some kind of result for an effectful operation, like

View file

@ -41,7 +41,22 @@ fn render_region_vid<'tcx>(
"".to_string()
};
format!("{:?}{universe_str}{external_name_str}", rvid)
let extra_info = match regioncx.region_definition(rvid).origin {
NllRegionVariableOrigin::FreeRegion => "".to_string(),
NllRegionVariableOrigin::Placeholder(p) => match p.bound.kind {
ty::BoundRegionKind::Named(def_id) => {
format!(" (for<{}>)", tcx.item_name(def_id))
}
ty::BoundRegionKind::ClosureEnv | ty::BoundRegionKind::Anon => " (for<'_>)".to_string(),
ty::BoundRegionKind::NamedAnon(_) => {
bug!("only used for pretty printing")
}
},
NllRegionVariableOrigin::Existential { name: Some(name), .. } => format!(" (ex<{name}>)"),
NllRegionVariableOrigin::Existential { .. } => format!(" (ex<'_>)"),
};
format!("{:?}{universe_str}{external_name_str}{extra_info}", rvid)
}
impl<'tcx> RegionInferenceContext<'tcx> {

View file

@ -44,7 +44,7 @@ use crate::{
mod dump_mir;
mod graphviz;
mod opaque_types;
pub(crate) mod opaque_types;
mod reverse_sccs;
pub(crate) mod values;
@ -1939,10 +1939,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
//
// and here we prefer to blame the source (the y = x statement).
let blame_source = match from_region_origin {
NllRegionVariableOrigin::FreeRegion
| NllRegionVariableOrigin::Existential { from_forall: false } => true,
NllRegionVariableOrigin::Placeholder(_)
| NllRegionVariableOrigin::Existential { from_forall: true } => false,
NllRegionVariableOrigin::FreeRegion => true,
NllRegionVariableOrigin::Placeholder(_) => false,
// `'existential: 'whatever` never results in a region error by itself.
// We may always infer it to `'static` afterall. This means while an error
// path may go through an existential, these existentials are never the
// `from_region`.
NllRegionVariableOrigin::Existential { name: _ } => {
unreachable!("existentials can outlive everything")
}
};
// To pick a constraint to blame, we organize constraints by how interesting we expect them

View file

@ -6,7 +6,9 @@ use rustc_middle::ty::{
TypeVisitableExt, fold_regions,
};
use rustc_span::Span;
use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid;
use rustc_trait_selection::opaque_types::{
InvalidOpaqueTypeArgs, check_opaque_type_parameter_valid,
};
use tracing::{debug, instrument};
use super::RegionInferenceContext;
@ -14,6 +16,11 @@ use crate::BorrowCheckRootCtxt;
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
use crate::universal_regions::RegionClassification;
pub(crate) enum DeferredOpaqueTypeError<'tcx> {
InvalidOpaqueTypeArgs(InvalidOpaqueTypeArgs<'tcx>),
LifetimeMismatchOpaqueParam(LifetimeMismatchOpaqueParam<'tcx>),
}
impl<'tcx> RegionInferenceContext<'tcx> {
/// Resolve any opaque types that were encountered while borrow checking
/// this item. This is then used to get the type in the `type_of` query.
@ -58,13 +65,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
///
/// [rustc-dev-guide chapter]:
/// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html
#[instrument(level = "debug", skip(self, root_cx, infcx), ret)]
#[instrument(level = "debug", skip(self, root_cx, infcx))]
pub(crate) fn infer_opaque_types(
&self,
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
infcx: &InferCtxt<'tcx>,
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
) {
) -> Vec<DeferredOpaqueTypeError<'tcx>> {
let mut errors = Vec::new();
let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
FxIndexMap::default();
@ -124,8 +132,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
});
debug!(?concrete_type);
let ty =
infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type);
let ty = match infcx
.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type)
{
Ok(ty) => ty,
Err(err) => {
errors.push(DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err));
continue;
}
};
// Sometimes, when the hidden type is an inference variable, it can happen that
// the hidden type becomes the opaque type itself. In this case, this was an opaque
@ -149,25 +164,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// non-region parameters. This is necessary because within the new solver we perform
// various query operations modulo regions, and thus could unsoundly select some impls
// that don't hold.
if !ty.references_error()
&& let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
infcx.tcx.erase_regions(opaque_type_key),
(opaque_type_key, concrete_type.span),
)
&& let Some((arg1, arg2)) = std::iter::zip(
prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
)
.find(|(arg1, arg2)| arg1 != arg2)
if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
infcx.tcx.erase_regions(opaque_type_key),
(opaque_type_key, concrete_type.span),
) && let Some((arg1, arg2)) = std::iter::zip(
prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
)
.find(|(arg1, arg2)| arg1 != arg2)
{
infcx.dcx().emit_err(LifetimeMismatchOpaqueParam {
arg: arg1,
prev: arg2,
span: prev_span,
prev_span: concrete_type.span,
});
errors.push(DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(
LifetimeMismatchOpaqueParam {
arg: arg1,
prev: arg2,
span: prev_span,
prev_span: concrete_type.span,
},
));
}
}
errors
}
/// Map the regions in the type to named regions. This is similar to what
@ -260,19 +277,13 @@ impl<'tcx> InferCtxt<'tcx> {
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: OpaqueHiddenType<'tcx>,
) -> Ty<'tcx> {
if let Some(e) = self.tainted_by_errors() {
return Ty::new_error(self.tcx, e);
}
if let Err(err) = check_opaque_type_parameter_valid(
) -> Result<Ty<'tcx>, InvalidOpaqueTypeArgs<'tcx>> {
check_opaque_type_parameter_valid(
self,
opaque_type_key,
instantiated_ty.span,
DefiningScopeKind::MirBorrowck,
) {
return Ty::new_error(self.tcx, err.report(self));
}
)?;
let definition_ty = instantiated_ty
.remap_generic_params_to_declaration_params(
@ -282,10 +293,7 @@ impl<'tcx> InferCtxt<'tcx> {
)
.ty;
if let Err(e) = definition_ty.error_reported() {
return Ty::new_error(self.tcx, e);
}
definition_ty
definition_ty.error_reported()?;
Ok(definition_ty)
}
}

View file

@ -66,7 +66,7 @@ impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> {
T: TypeFoldable<TyCtxt<'tcx>>,
F: Fn() -> RegionCtxt,
{
let origin = NllRegionVariableOrigin::Existential { from_forall: false };
let origin = NllRegionVariableOrigin::Existential { name: None };
fold_regions(self.infcx.tcx, value, |_region, _depth| {
self.infcx.next_nll_region_var(origin, || region_ctxt_fn())
})

View file

@ -182,6 +182,17 @@ pub(crate) fn type_check<'tcx>(
)
});
// In case type check encountered an error region, we suppress unhelpful extra
// errors in by clearing out all outlives bounds that we may end up checking.
if let Some(guar) = universal_region_relations.universal_regions.encountered_re_error() {
debug!("encountered an error region; removing constraints!");
constraints.outlives_constraints = Default::default();
constraints.member_constraints = Default::default();
constraints.type_tests = Default::default();
root_cx.set_tainted_by_errors(guar);
infcx.set_tainted_by_errors(guar);
}
MirTypeckResults {
constraints,
universal_region_relations,

View file

@ -216,7 +216,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
*ex_reg_var
} else {
let ex_reg_var =
self.next_existential_region_var(true, br.kind.get_name(infcx.infcx.tcx));
self.next_existential_region_var(br.kind.get_name(infcx.infcx.tcx));
debug!(?ex_reg_var);
reg_map.insert(br, ex_reg_var);
@ -244,17 +244,9 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
}
#[instrument(skip(self), level = "debug")]
fn next_existential_region_var(
&mut self,
from_forall: bool,
name: Option<Symbol>,
) -> ty::Region<'tcx> {
let origin = NllRegionVariableOrigin::Existential { from_forall };
let reg_var =
self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name));
reg_var
fn next_existential_region_var(&mut self, name: Option<Symbol>) -> ty::Region<'tcx> {
let origin = NllRegionVariableOrigin::Existential { name };
self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name))
}
#[instrument(skip(self), level = "debug")]

View file

@ -217,7 +217,7 @@ struct UniversalRegionIndices<'tcx> {
/// Whether we've encountered an error region. If we have, cancel all
/// outlives errors, as they are likely bogus.
pub tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
pub encountered_re_error: Cell<Option<ErrorGuaranteed>>,
}
#[derive(Debug, PartialEq)]
@ -442,8 +442,8 @@ impl<'tcx> UniversalRegions<'tcx> {
self.fr_fn_body
}
pub(crate) fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
self.indices.tainted_by_errors.get()
pub(crate) fn encountered_re_error(&self) -> Option<ErrorGuaranteed> {
self.indices.encountered_re_error.get()
}
}
@ -706,7 +706,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
UniversalRegionIndices {
indices: global_mapping.chain(arg_mapping).collect(),
fr_static,
tainted_by_errors: Cell::new(None),
encountered_re_error: Cell::new(None),
}
}
@ -916,7 +916,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
match r.kind() {
ty::ReVar(..) => r.as_var(),
ty::ReError(guar) => {
self.tainted_by_errors.set(Some(guar));
self.encountered_re_error.set(Some(guar));
// We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the
// `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if
// errors are being emitted and 2) it leaves the happy path unaffected.

View file

@ -1,4 +1,3 @@
use rustc_ast::ptr::P;
use rustc_ast::{
self as ast, Fn, FnHeader, FnSig, Generics, ItemKind, Safety, Stmt, StmtKind, TyKind,
};
@ -46,7 +45,7 @@ pub(crate) fn expand(
let const_body = ecx.expr_block(ecx.block(span, stmts));
let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
let const_item = if is_stmt {
Annotatable::Stmt(P(ecx.stmt_item(span, const_item)))
Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item)))
} else {
Annotatable::Item(const_item)
};

View file

@ -1,5 +1,4 @@
use lint::BuiltinLintDiag;
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AsmMacro, token};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
@ -19,7 +18,7 @@ use crate::{errors, fluent_generated as fluent};
/// Validated assembly arguments, ready for macro expansion.
struct ValidatedAsmArgs {
pub templates: Vec<P<ast::Expr>>,
pub templates: Vec<Box<ast::Expr>>,
pub operands: Vec<(ast::InlineAsmOperand, Span)>,
named_args: FxIndexMap<Symbol, usize>,
reg_args: GrowableBitSet<usize>,
@ -600,9 +599,9 @@ pub(super) fn expand_asm<'cx>(
return ExpandResult::Retry(());
};
let expr = match mac {
Ok(inline_asm) => P(ast::Expr {
Ok(inline_asm) => Box::new(ast::Expr {
id: ast::DUMMY_NODE_ID,
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
kind: ast::ExprKind::InlineAsm(Box::new(inline_asm)),
span: sp,
attrs: ast::AttrVec::new(),
tokens: None,
@ -630,9 +629,9 @@ pub(super) fn expand_naked_asm<'cx>(
return ExpandResult::Retry(());
};
let expr = match mac {
Ok(inline_asm) => P(ast::Expr {
Ok(inline_asm) => Box::new(ast::Expr {
id: ast::DUMMY_NODE_ID,
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
kind: ast::ExprKind::InlineAsm(Box::new(inline_asm)),
span: sp,
attrs: ast::AttrVec::new(),
tokens: None,
@ -660,7 +659,7 @@ pub(super) fn expand_global_asm<'cx>(
return ExpandResult::Retry(());
};
match mac {
Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item {
Ok(inline_asm) => MacEager::items(smallvec![Box::new(ast::Item {
attrs: ast::AttrVec::new(),
id: ast::DUMMY_NODE_ID,
kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),

View file

@ -1,6 +1,5 @@
mod context;
use rustc_ast::ptr::P;
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp, token};
@ -55,9 +54,9 @@ pub(crate) fn expand_assert<'cx>(
let expr = if let Some(tokens) = custom_message {
let then = cx.expr(
call_site_span,
ExprKind::MacCall(P(MacCall {
ExprKind::MacCall(Box::new(MacCall {
path: panic_path(),
args: P(DelimArgs {
args: Box::new(DelimArgs {
dspan: DelimSpan::from_single(call_site_span),
delim: Delimiter::Parenthesis,
tokens,
@ -96,7 +95,7 @@ pub(crate) fn expand_assert<'cx>(
}
struct Assert {
cond_expr: P<Expr>,
cond_expr: Box<Expr>,
custom_message: Option<TokenStream>,
}
@ -104,10 +103,10 @@ struct Assert {
fn expr_if_not(
cx: &ExtCtxt<'_>,
span: Span,
cond: P<Expr>,
then: P<Expr>,
els: Option<P<Expr>>,
) -> P<Expr> {
cond: Box<Expr>,
then: Box<Expr>,
els: Option<Box<Expr>>,
) -> Box<Expr> {
cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els)
}

View file

@ -1,4 +1,3 @@
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, IdentIsRaw};
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
use rustc_ast::{
@ -70,7 +69,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
/// }
/// }
/// ```
pub(super) fn build(mut self, mut cond_expr: P<Expr>, panic_path: Path) -> P<Expr> {
pub(super) fn build(mut self, mut cond_expr: Box<Expr>, panic_path: Path) -> Box<Expr> {
let expr_str = pprust::expr_to_string(&cond_expr);
self.manage_cond_expr(&mut cond_expr);
let initial_imports = self.build_initial_imports();
@ -129,7 +128,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
}
/// Takes the conditional expression of `assert!` and then wraps it inside `unlikely`
fn build_unlikely(&self, cond_expr: P<Expr>) -> P<Expr> {
fn build_unlikely(&self, cond_expr: Box<Expr>) -> Box<Expr> {
let unlikely_path = self.cx.std_path(&[sym::intrinsics, sym::unlikely]);
self.cx.expr_call(
self.span,
@ -145,7 +144,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
/// __capture0,
/// ...
/// );
fn build_panic(&self, expr_str: &str, panic_path: Path) -> P<Expr> {
fn build_panic(&self, expr_str: &str, panic_path: Path) -> Box<Expr> {
let escaped_expr_str = escape_to_fmt(expr_str);
let initial = [
TokenTree::token_joint(
@ -176,9 +175,9 @@ impl<'cx, 'a> Context<'cx, 'a> {
});
self.cx.expr(
self.span,
ExprKind::MacCall(P(MacCall {
ExprKind::MacCall(Box::new(MacCall {
path: panic_path,
args: P(DelimArgs {
args: Box::new(DelimArgs {
dspan: DelimSpan::from_single(self.span),
delim: Delimiter::Parenthesis,
tokens: initial.into_iter().chain(captures).collect::<TokenStream>(),
@ -190,7 +189,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
/// Recursive function called until `cond_expr` and `fmt_str` are fully modified.
///
/// See [Self::manage_initial_capture] and [Self::manage_try_capture]
fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
fn manage_cond_expr(&mut self, expr: &mut Box<Expr>) {
match &mut expr.kind {
ExprKind::AddrOf(_, mutability, local_expr) => {
self.with_is_consumed_management(matches!(mutability, Mutability::Mut), |this| {
@ -331,7 +330,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
///
/// `fmt_str`, the formatting string used for debugging, is constructed to show possible
/// captured variables.
fn manage_initial_capture(&mut self, expr: &mut P<Expr>, path_ident: Ident) {
fn manage_initial_capture(&mut self, expr: &mut Box<Expr>, path_ident: Ident) {
if self.paths.contains(&path_ident) {
return;
} else {
@ -360,7 +359,12 @@ impl<'cx, 'a> Context<'cx, 'a> {
/// (&Wrapper(__local_bindN)).try_capture(&mut __captureN);
/// __local_bindN
/// }
fn manage_try_capture(&mut self, capture: Ident, curr_capture_idx: usize, expr: &mut P<Expr>) {
fn manage_try_capture(
&mut self,
capture: Ident,
curr_capture_idx: usize,
expr: &mut Box<Expr>,
) {
let local_bind_string = format!("__local_bind{curr_capture_idx}");
let local_bind = Ident::new(Symbol::intern(&local_bind_string), self.span);
self.local_bind_decls.push(self.cx.stmt_let(
@ -441,20 +445,20 @@ fn escape_to_fmt(s: &str) -> String {
rslt
}
fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: Box<Expr>) -> Box<Expr> {
cx.expr(sp, ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, e))
}
fn expr_method_call(
cx: &ExtCtxt<'_>,
seg: PathSegment,
receiver: P<Expr>,
args: ThinVec<P<Expr>>,
receiver: Box<Expr>,
args: ThinVec<Box<Expr>>,
span: Span,
) -> P<Expr> {
) -> Box<Expr> {
cx.expr(span, ExprKind::MethodCall(Box::new(MethodCall { seg, receiver, args, span })))
}
fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: Box<Expr>) -> Box<Expr> {
cx.expr(sp, ExprKind::Paren(e))
}

View file

@ -11,7 +11,6 @@ mod llvm_enzyme {
AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity,
valid_ty_for_activity,
};
use rustc_ast::ptr::P;
use rustc_ast::token::{Lit, LitKind, Token, TokenKind};
use rustc_ast::tokenstream::*;
use rustc_ast::visit::AssocCtxt::*;
@ -27,7 +26,7 @@ mod llvm_enzyme {
use crate::errors;
pub(crate) fn outer_normal_attr(
kind: &P<rustc_ast::NormalAttr>,
kind: &Box<rustc_ast::NormalAttr>,
id: rustc_ast::AttrId,
span: Span,
) -> rustc_ast::Attribute {
@ -73,7 +72,7 @@ mod llvm_enzyme {
}
// Get information about the function the macro is applied to
fn extract_item_info(iitem: &P<ast::Item>) -> Option<(Visibility, FnSig, Ident, Generics)> {
fn extract_item_info(iitem: &Box<ast::Item>) -> Option<(Visibility, FnSig, Ident, Generics)> {
match &iitem.kind {
ItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => {
Some((iitem.vis.clone(), sig.clone(), ident.clone(), generics.clone()))
@ -346,7 +345,7 @@ mod llvm_enzyme {
define_opaque: None,
});
let mut rustc_ad_attr =
P(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff)));
Box::new(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff)));
let ts2: Vec<TokenTree> = vec![TokenTree::Token(
Token::new(TokenKind::Ident(sym::never, false.into()), span),
@ -363,7 +362,7 @@ mod llvm_enzyme {
args: ast::AttrArgs::Delimited(never_arg),
tokens: None,
};
let inline_never_attr = P(ast::NormalAttr { item: inline_item, tokens: None });
let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None });
let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id();
let attr = outer_normal_attr(&rustc_ad_attr, new_id, span);
let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id();
@ -433,7 +432,7 @@ mod llvm_enzyme {
let d_annotatable = match &item {
Annotatable::AssocItem(_, _) => {
let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf);
let d_fn = P(ast::AssocItem {
let d_fn = Box::new(ast::AssocItem {
attrs: thin_vec![d_attr, inline_never],
id: ast::DUMMY_NODE_ID,
span,
@ -453,7 +452,7 @@ mod llvm_enzyme {
let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf));
d_fn.vis = vis;
Annotatable::Stmt(P(ast::Stmt {
Annotatable::Stmt(Box::new(ast::Stmt {
id: ast::DUMMY_NODE_ID,
kind: ast::StmtKind::Item(d_fn),
span,
@ -506,7 +505,7 @@ mod llvm_enzyme {
idents: &[Ident],
errored: bool,
generics: &Generics,
) -> (P<ast::Block>, P<ast::Expr>, P<ast::Expr>, P<ast::Expr>) {
) -> (Box<ast::Block>, Box<ast::Expr>, Box<ast::Expr>, Box<ast::Expr>) {
let blackbox_path = ecx.std_path(&[sym::hint, sym::black_box]);
let noop = ast::InlineAsm {
asm_macro: ast::AsmMacro::Asm,
@ -517,7 +516,7 @@ mod llvm_enzyme {
options: ast::InlineAsmOptions::PURE | ast::InlineAsmOptions::NOMEM,
line_spans: vec![],
};
let noop_expr = ecx.expr_asm(span, P(noop));
let noop_expr = ecx.expr_asm(span, Box::new(noop));
let unsf = ast::BlockCheckMode::Unsafe(ast::UnsafeSource::CompilerGenerated);
let unsf_block = ast::Block {
stmts: thin_vec![ecx.stmt_semi(noop_expr)],
@ -526,7 +525,7 @@ mod llvm_enzyme {
rules: unsf,
span,
};
let unsf_expr = ecx.expr_block(P(unsf_block));
let unsf_expr = ecx.expr_block(Box::new(unsf_block));
let blackbox_call_expr = ecx.expr_path(ecx.path(span, blackbox_path));
let primal_call = gen_primal_call(ecx, span, primal, idents, generics);
let black_box_primal_call = ecx.expr_call(
@ -578,7 +577,7 @@ mod llvm_enzyme {
idents: Vec<Ident>,
errored: bool,
generics: &Generics,
) -> P<ast::Block> {
) -> Box<ast::Block> {
let new_decl_span = d_sig.span;
// Just adding some default inline-asm and black_box usages to prevent early inlining
@ -634,7 +633,7 @@ mod llvm_enzyme {
return body;
}
let mut exprs: P<ast::Expr> = primal_call;
let mut exprs: Box<ast::Expr> = primal_call;
let d_ret_ty = match d_sig.decl.output {
FnRetTy::Ty(ref ty) => ty.clone(),
FnRetTy::Default(span) => {
@ -653,7 +652,7 @@ mod llvm_enzyme {
} else {
let q = QSelf { ty: d_ret_ty, path_span: span, position: 0 };
let y = ExprKind::Path(
Some(P(q)),
Some(Box::new(q)),
ecx.path_ident(span, Ident::with_dummy_span(kw::Default)),
);
let default_call_expr = ecx.expr(span, y);
@ -703,7 +702,7 @@ mod llvm_enzyme {
primal: Ident,
idents: &[Ident],
generics: &Generics,
) -> P<ast::Expr> {
) -> Box<ast::Expr> {
let has_self = idents.len() > 0 && idents[0].name == kw::SelfLower;
if has_self {
@ -740,7 +739,7 @@ mod llvm_enzyme {
},
);
ast::AngleBracketedArg::Arg(ast::GenericArg::Type(P(ast::Ty {
ast::AngleBracketedArg::Arg(ast::GenericArg::Type(Box::new(ast::Ty {
id: type_param.id,
span,
kind: generic_param,
@ -750,7 +749,7 @@ mod llvm_enzyme {
.collect();
function_path.args =
Some(P(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs {
Some(Box::new(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs {
span,
args: generated_generic_types,
})));
@ -856,7 +855,7 @@ mod llvm_enzyme {
for i in 0..x.width {
let mut shadow_arg = arg.clone();
// We += into the shadow in reverse mode.
shadow_arg.ty = P(assure_mut_ref(&arg.ty));
shadow_arg.ty = Box::new(assure_mut_ref(&arg.ty));
let old_name = if let PatKind::Ident(_, ident, _) = arg.pat.kind {
ident.name
} else {
@ -866,7 +865,7 @@ mod llvm_enzyme {
let name: String = format!("d{}_{}", old_name, i);
new_inputs.push(name.clone());
let ident = Ident::from_str_and_span(&name, shadow_arg.pat.span);
shadow_arg.pat = P(ast::Pat {
shadow_arg.pat = Box::new(ast::Pat {
id: ast::DUMMY_NODE_ID,
kind: PatKind::Ident(BindingMode::NONE, ident, None),
span: shadow_arg.pat.span,
@ -898,7 +897,7 @@ mod llvm_enzyme {
let name: String = format!("b{}_{}", old_name, i);
new_inputs.push(name.clone());
let ident = Ident::from_str_and_span(&name, shadow_arg.pat.span);
shadow_arg.pat = P(ast::Pat {
shadow_arg.pat = Box::new(ast::Pat {
id: ast::DUMMY_NODE_ID,
kind: PatKind::Ident(BindingMode::NONE, ident, None),
span: shadow_arg.pat.span,
@ -942,7 +941,7 @@ mod llvm_enzyme {
let shadow_arg = ast::Param {
attrs: ThinVec::new(),
ty: ty.clone(),
pat: P(ast::Pat {
pat: Box::new(ast::Pat {
id: ast::DUMMY_NODE_ID,
kind: PatKind::Ident(BindingMode::NONE, ident, None),
span: ty.span,
@ -966,7 +965,12 @@ mod llvm_enzyme {
FnRetTy::Default(span) => {
// We want to return std::hint::black_box(()).
let kind = TyKind::Tup(ThinVec::new());
let ty = P(rustc_ast::Ty { kind, id: ast::DUMMY_NODE_ID, span, tokens: None });
let ty = Box::new(rustc_ast::Ty {
kind,
id: ast::DUMMY_NODE_ID,
span,
tokens: None,
});
d_decl.output = FnRetTy::Ty(ty.clone());
assert!(matches!(x.ret_activity, DiffActivity::None));
// this won't be used below, so any type would be fine.
@ -987,7 +991,7 @@ mod llvm_enzyme {
};
TyKind::Array(ty.clone(), anon_const)
};
let ty = P(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None });
let ty = Box::new(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None });
d_decl.output = FnRetTy::Ty(ty);
}
if matches!(x.ret_activity, DiffActivity::DualOnly | DiffActivity::DualvOnly) {
@ -1000,7 +1004,8 @@ mod llvm_enzyme {
value: ecx.expr_usize(span, x.width as usize),
};
let kind = TyKind::Array(ty.clone(), anon_const);
let ty = P(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None });
let ty =
Box::new(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None });
d_decl.output = FnRetTy::Ty(ty);
}
}
@ -1022,14 +1027,14 @@ mod llvm_enzyme {
act_ret.insert(0, ty.clone());
}
let kind = TyKind::Tup(act_ret);
P(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None })
Box::new(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None })
}
FnRetTy::Default(span) => {
if act_ret.len() == 1 {
act_ret[0].clone()
} else {
let kind = TyKind::Tup(act_ret.iter().map(|arg| arg.clone()).collect());
P(rustc_ast::Ty { kind, id: ast::DUMMY_NODE_ID, span, tokens: None })
Box::new(rustc_ast::Ty { kind, id: ast::DUMMY_NODE_ID, span, tokens: None })
}
}
};

View file

@ -44,7 +44,7 @@ impl MultiItemModifier for Expander {
item: Annotatable,
_is_derive_const: bool,
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
let template = AttributeTemplate { list: Some("path"), ..Default::default() };
let template = AttributeTemplate { list: Some(&["path"]), ..Default::default() };
validate_attr::check_builtin_meta_item(
&ecx.sess.psess,
meta_item,

View file

@ -2,7 +2,6 @@ use core::ops::ControlFlow;
use rustc_ast as ast;
use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::ptr::P;
use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_ast::{Attribute, HasAttrs, HasTokens, NodeId, mut_visit, visit};
use rustc_errors::PResult;
@ -132,7 +131,7 @@ impl CfgEval<'_> {
let stmt = parser
.parse_stmt_without_recovery(false, ForceCollect::Yes, false)?
.unwrap();
Annotatable::Stmt(P(self.flat_map_stmt(stmt).pop().unwrap()))
Annotatable::Stmt(Box::new(self.flat_map_stmt(stmt).pop().unwrap()))
}
Annotatable::Expr(_) => {
let mut expr = parser.parse_expr_force_collect()?;
@ -166,7 +165,7 @@ impl MutVisitor for CfgEval<'_> {
mut_visit::walk_expr(self, expr);
}
fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
fn filter_map_expr(&mut self, expr: Box<ast::Expr>) -> Option<Box<ast::Expr>> {
let mut expr = configure!(self, expr);
mut_visit::walk_expr(self, &mut expr);
Some(expr)
@ -185,24 +184,24 @@ impl MutVisitor for CfgEval<'_> {
mut_visit::walk_flat_map_stmt(self, stmt)
}
fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
fn flat_map_item(&mut self, item: Box<ast::Item>) -> SmallVec<[Box<ast::Item>; 1]> {
let item = configure!(self, item);
mut_visit::walk_flat_map_item(self, item)
}
fn flat_map_assoc_item(
&mut self,
item: P<ast::AssocItem>,
item: Box<ast::AssocItem>,
ctxt: AssocCtxt,
) -> SmallVec<[P<ast::AssocItem>; 1]> {
) -> SmallVec<[Box<ast::AssocItem>; 1]> {
let item = configure!(self, item);
mut_visit::walk_flat_map_assoc_item(self, item, ctxt)
}
fn flat_map_foreign_item(
&mut self,
foreign_item: P<ast::ForeignItem>,
) -> SmallVec<[P<ast::ForeignItem>; 1]> {
foreign_item: Box<ast::ForeignItem>,
) -> SmallVec<[Box<ast::ForeignItem>; 1]> {
let foreign_item = configure!(self, foreign_item);
mut_visit::walk_flat_map_foreign_item(self, foreign_item)
}

View file

@ -1,4 +1,3 @@
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{ExprKind, LitIntType, LitKind, StrStyle, UintTy, token};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
@ -90,7 +89,7 @@ fn handle_array_element(
cx: &ExtCtxt<'_>,
guar: &mut Option<ErrorGuaranteed>,
missing_literals: &mut Vec<rustc_span::Span>,
expr: &P<rustc_ast::Expr>,
expr: &Box<rustc_ast::Expr>,
) -> Option<u8> {
let dcx = cx.dcx();

View file

@ -34,8 +34,10 @@ impl MultiItemModifier for Expander {
let (sess, features) = (ecx.sess, ecx.ecfg.features);
let result =
ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
let template =
AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() };
let template = AttributeTemplate {
list: Some(&["Trait1, Trait2, ..."]),
..Default::default()
};
validate_attr::check_builtin_meta_item(
&sess.psess,
meta_item,

View file

@ -1,4 +1,3 @@
use rustc_ast::ptr::P;
use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::{Span, sym};
@ -119,7 +118,7 @@ fn get_substructure_equality_expr(
cx: &ExtCtxt<'_>,
span: Span,
substructure: &Substructure<'_>,
) -> P<Expr> {
) -> Box<Expr> {
use SubstructureFields::*;
match substructure.fields {
@ -180,7 +179,7 @@ fn get_substructure_equality_expr(
///
/// Panics if there are not exactly two arguments to compare (should be `self`
/// and `other`).
fn get_field_equality_expr(cx: &ExtCtxt<'_>, field: &FieldInfo) -> P<Expr> {
fn get_field_equality_expr(cx: &ExtCtxt<'_>, field: &FieldInfo) -> Box<Expr> {
let [rhs] = &field.other_selflike_exprs[..] else {
cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
};
@ -198,7 +197,7 @@ fn get_field_equality_expr(cx: &ExtCtxt<'_>, field: &FieldInfo) -> P<Expr> {
/// This is used to strip away any number of leading `&` from an expression
/// (e.g., `&&&T` becomes `T`). Only removes immutable references; mutable
/// references are preserved.
fn peel_refs(mut expr: &P<Expr>) -> P<Expr> {
fn peel_refs(mut expr: &Box<Expr>) -> Box<Expr> {
while let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = &expr.kind {
expr = &inner;
}
@ -210,7 +209,7 @@ fn peel_refs(mut expr: &P<Expr>) -> P<Expr> {
///
/// If the given expression is a block, it is wrapped in parentheses; otherwise,
/// it is returned unchanged.
fn wrap_block_expr(cx: &ExtCtxt<'_>, expr: P<Expr>) -> P<Expr> {
fn wrap_block_expr(cx: &ExtCtxt<'_>, expr: Box<Expr>) -> Box<Expr> {
if matches!(&expr.kind, ExprKind::Block(..)) {
return cx.expr_paren(expr.span, expr);
}

View file

@ -108,11 +108,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
cx.item(
span,
attrs.clone(),
ast::ItemKind::Impl(Box::new(ast::Impl {
safety: ast::Safety::Default,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: ast::Const::No,
ast::ItemKind::Impl(ast::Impl {
generics: Generics {
params: generics
.params
@ -137,10 +133,16 @@ pub(crate) fn expand_deriving_coerce_pointee(
where_clause: generics.where_clause.clone(),
span: generics.span,
},
of_trait: Some(trait_ref),
of_trait: Some(Box::new(ast::TraitImplHeader {
safety: ast::Safety::Default,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: ast::Const::No,
trait_ref,
})),
self_ty: self_type.clone(),
items: ThinVec::new(),
})),
}),
),
));
}
@ -152,16 +154,18 @@ pub(crate) fn expand_deriving_coerce_pointee(
let item = cx.item(
span,
attrs.clone(),
ast::ItemKind::Impl(Box::new(ast::Impl {
safety: ast::Safety::Default,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: ast::Const::No,
ast::ItemKind::Impl(ast::Impl {
generics,
of_trait: Some(trait_ref),
of_trait: Some(Box::new(ast::TraitImplHeader {
safety: ast::Safety::Default,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: ast::Const::No,
trait_ref,
})),
self_ty: self_type.clone(),
items: ThinVec::new(),
})),
}),
);
push(Annotatable::Item(item));
};

View file

@ -94,7 +94,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) ->
field: &FieldInfo,
index: usize,
len: usize,
) -> ast::ptr::P<ast::Expr> {
) -> Box<ast::Expr> {
if index < len - 1 {
field.self_expr.clone()
} else {

View file

@ -56,7 +56,7 @@ pub(crate) fn expand_deriving_default(
trait_def.expand(cx, mitem, item, push)
}
fn default_call(cx: &ExtCtxt<'_>, span: Span) -> ast::ptr::P<ast::Expr> {
fn default_call(cx: &ExtCtxt<'_>, span: Span) -> Box<ast::Expr> {
// Note that `kw::Default` is "default" and `sym::Default` is "Default"!
let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]);
cx.expr_call_global(span, default_ident, ThinVec::new())

View file

@ -180,7 +180,6 @@ use std::{iter, vec};
pub(crate) use StaticFields::*;
pub(crate) use SubstructureFields::*;
use rustc_ast::ptr::P;
use rustc_ast::token::{IdentIsRaw, LitKind, Token, TokenKind};
use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree};
use rustc_ast::{
@ -272,7 +271,7 @@ pub(crate) struct Substructure<'a> {
pub type_ident: Ident,
/// Verbatim access to any non-selflike arguments, i.e. arguments that
/// don't have type `&Self`.
pub nonselflike_args: &'a [P<Expr>],
pub nonselflike_args: &'a [Box<Expr>],
pub fields: &'a SubstructureFields<'a>,
}
@ -284,10 +283,10 @@ pub(crate) struct FieldInfo {
pub name: Option<Ident>,
/// The expression corresponding to this field of `self`
/// (specifically, a reference to it).
pub self_expr: P<Expr>,
pub self_expr: Box<Expr>,
/// The expressions corresponding to references to this field in
/// the other selflike arguments.
pub other_selflike_exprs: Vec<P<Expr>>,
pub other_selflike_exprs: Vec<Box<Expr>>,
pub maybe_scalar: bool,
}
@ -323,7 +322,7 @@ pub(crate) enum SubstructureFields<'a> {
/// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as
/// if they were fields. The second field is the expression to combine the
/// discriminant expression with; it will be `None` if no match is necessary.
EnumDiscr(FieldInfo, Option<P<Expr>>),
EnumDiscr(FieldInfo, Option<Box<Expr>>),
/// A static method where `Self` is a struct.
StaticStruct(&'a ast::VariantData, StaticFields),
@ -345,7 +344,7 @@ pub(crate) fn combine_substructure(
struct TypeParameter {
bound_generic_params: ThinVec<ast::GenericParam>,
ty: P<ast::Ty>,
ty: Box<ast::Ty>,
}
/// The code snippets built up for derived code are sometimes used as blocks
@ -354,23 +353,23 @@ struct TypeParameter {
/// avoiding the insertion of any unnecessary blocks.
///
/// The statements come before the expression.
pub(crate) struct BlockOrExpr(ThinVec<ast::Stmt>, Option<P<Expr>>);
pub(crate) struct BlockOrExpr(ThinVec<ast::Stmt>, Option<Box<Expr>>);
impl BlockOrExpr {
pub(crate) fn new_stmts(stmts: ThinVec<ast::Stmt>) -> BlockOrExpr {
BlockOrExpr(stmts, None)
}
pub(crate) fn new_expr(expr: P<Expr>) -> BlockOrExpr {
pub(crate) fn new_expr(expr: Box<Expr>) -> BlockOrExpr {
BlockOrExpr(ThinVec::new(), Some(expr))
}
pub(crate) fn new_mixed(stmts: ThinVec<ast::Stmt>, expr: Option<P<Expr>>) -> BlockOrExpr {
pub(crate) fn new_mixed(stmts: ThinVec<ast::Stmt>, expr: Option<Box<Expr>>) -> BlockOrExpr {
BlockOrExpr(stmts, expr)
}
// Converts it into a block.
fn into_block(mut self, cx: &ExtCtxt<'_>, span: Span) -> P<ast::Block> {
fn into_block(mut self, cx: &ExtCtxt<'_>, span: Span) -> Box<ast::Block> {
if let Some(expr) = self.1 {
self.0.push(cx.stmt_expr(expr));
}
@ -378,7 +377,7 @@ impl BlockOrExpr {
}
// Converts it into an expression.
fn into_expr(self, cx: &ExtCtxt<'_>, span: Span) -> P<Expr> {
fn into_expr(self, cx: &ExtCtxt<'_>, span: Span) -> Box<Expr> {
if self.0.is_empty() {
match self.1 {
None => cx.expr_block(cx.block(span, ThinVec::new())),
@ -432,7 +431,7 @@ fn find_type_parameters(
{
self.type_params.push(TypeParameter {
bound_generic_params: self.bound_generic_params_stack.clone(),
ty: P(ty.clone()),
ty: Box::new(ty.clone()),
});
}
@ -544,7 +543,7 @@ impl<'a> TraitDef<'a> {
})
.cloned(),
);
push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() })))
push(Annotatable::Item(Box::new(ast::Item { attrs, ..(*newitem).clone() })))
}
_ => unreachable!(),
}
@ -590,15 +589,15 @@ impl<'a> TraitDef<'a> {
cx: &ExtCtxt<'_>,
type_ident: Ident,
generics: &Generics,
field_tys: Vec<P<ast::Ty>>,
methods: Vec<P<ast::AssocItem>>,
field_tys: Vec<Box<ast::Ty>>,
methods: Vec<Box<ast::AssocItem>>,
is_packed: bool,
) -> P<ast::Item> {
) -> Box<ast::Item> {
let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
// Transform associated types from `deriving::ty::Ty` into `ast::AssocItem`
let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| {
P(ast::AssocItem {
Box::new(ast::AssocItem {
id: ast::DUMMY_NODE_ID,
span: self.span,
vis: ast::Visibility {
@ -827,21 +826,25 @@ impl<'a> TraitDef<'a> {
)
}
let opt_trait_ref = Some(trait_ref);
cx.item(
self.span,
attrs,
ast::ItemKind::Impl(Box::new(ast::Impl {
safety: ast::Safety::Default,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
ast::ItemKind::Impl(ast::Impl {
generics: trait_generics,
of_trait: opt_trait_ref,
of_trait: Some(Box::new(ast::TraitImplHeader {
safety: ast::Safety::Default,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: if self.is_const {
ast::Const::Yes(DUMMY_SP)
} else {
ast::Const::No
},
trait_ref,
})),
self_ty: self_type,
items: methods.into_iter().chain(associated_types).collect(),
})),
}),
)
}
@ -853,8 +856,8 @@ impl<'a> TraitDef<'a> {
generics: &Generics,
from_scratch: bool,
is_packed: bool,
) -> P<ast::Item> {
let field_tys: Vec<P<ast::Ty>> =
) -> Box<ast::Item> {
let field_tys: Vec<Box<ast::Ty>> =
struct_def.fields().iter().map(|field| field.ty.clone()).collect();
let methods = self
@ -906,7 +909,7 @@ impl<'a> TraitDef<'a> {
type_ident: Ident,
generics: &Generics,
from_scratch: bool,
) -> P<ast::Item> {
) -> Box<ast::Item> {
let mut field_tys = Vec::new();
for variant in &enum_def.variants {
@ -962,7 +965,7 @@ impl<'a> MethodDef<'a> {
cx: &ExtCtxt<'_>,
trait_: &TraitDef<'_>,
type_ident: Ident,
nonselflike_args: &[P<Expr>],
nonselflike_args: &[Box<Expr>],
fields: &SubstructureFields<'_>,
) -> BlockOrExpr {
let span = trait_.span;
@ -978,7 +981,7 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'_>,
generics: &Generics,
type_ident: Ident,
) -> P<ast::Ty> {
) -> Box<ast::Ty> {
self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
}
@ -999,7 +1002,8 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'_>,
type_ident: Ident,
generics: &Generics,
) -> (Option<ast::ExplicitSelf>, ThinVec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
) -> (Option<ast::ExplicitSelf>, ThinVec<Box<Expr>>, Vec<Box<Expr>>, Vec<(Ident, Box<ast::Ty>)>)
{
let mut selflike_args = ThinVec::new();
let mut nonselflike_args = Vec::new();
let mut nonself_arg_tys = Vec::new();
@ -1036,9 +1040,9 @@ impl<'a> MethodDef<'a> {
type_ident: Ident,
generics: &Generics,
explicit_self: Option<ast::ExplicitSelf>,
nonself_arg_tys: Vec<(Ident, P<ast::Ty>)>,
nonself_arg_tys: Vec<(Ident, Box<ast::Ty>)>,
body: BlockOrExpr,
) -> P<ast::AssocItem> {
) -> Box<ast::AssocItem> {
let span = trait_.span;
// Create the generics that aren't for `Self`.
let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
@ -1065,7 +1069,7 @@ impl<'a> MethodDef<'a> {
let defaultness = ast::Defaultness::Final;
// Create the method.
P(ast::AssocItem {
Box::new(ast::AssocItem {
id: ast::DUMMY_NODE_ID,
attrs: self.attributes.clone(),
span,
@ -1128,8 +1132,8 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'b>,
struct_def: &'b VariantData,
type_ident: Ident,
selflike_args: &[P<Expr>],
nonselflike_args: &[P<Expr>],
selflike_args: &[Box<Expr>],
nonselflike_args: &[Box<Expr>],
is_packed: bool,
) -> BlockOrExpr {
assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
@ -1151,7 +1155,7 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'_>,
struct_def: &VariantData,
type_ident: Ident,
nonselflike_args: &[P<Expr>],
nonselflike_args: &[Box<Expr>],
) -> BlockOrExpr {
let summary = trait_.summarise_struct(cx, struct_def);
@ -1205,8 +1209,8 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'b>,
enum_def: &'b EnumDef,
type_ident: Ident,
mut selflike_args: ThinVec<P<Expr>>,
nonselflike_args: &[P<Expr>],
mut selflike_args: ThinVec<Box<Expr>>,
nonselflike_args: &[Box<Expr>],
) -> BlockOrExpr {
assert!(
!selflike_args.is_empty(),
@ -1418,7 +1422,7 @@ impl<'a> MethodDef<'a> {
// ...
// _ => ::core::intrinsics::unreachable(),
// }
let get_match_expr = |mut selflike_args: ThinVec<P<Expr>>| {
let get_match_expr = |mut selflike_args: ThinVec<Box<Expr>>| {
let match_arg = if selflike_args.len() == 1 {
selflike_args.pop().unwrap()
} else {
@ -1454,7 +1458,7 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'_>,
enum_def: &EnumDef,
type_ident: Ident,
nonselflike_args: &[P<Expr>],
nonselflike_args: &[Box<Expr>],
) -> BlockOrExpr {
self.call_substructure_method(
cx,
@ -1503,7 +1507,7 @@ impl<'a> TraitDef<'a> {
struct_def: &'a VariantData,
prefixes: &[String],
by_ref: ByRef,
) -> ThinVec<P<ast::Pat>> {
) -> ThinVec<Box<ast::Pat>> {
prefixes
.iter()
.map(|prefix| {
@ -1558,7 +1562,7 @@ impl<'a> TraitDef<'a> {
fn create_fields<F>(&self, struct_def: &'a VariantData, mk_exprs: F) -> Vec<FieldInfo>
where
F: Fn(usize, &ast::FieldDef, Span) -> Vec<P<ast::Expr>>,
F: Fn(usize, &ast::FieldDef, Span) -> Vec<Box<ast::Expr>>,
{
struct_def
.fields()
@ -1606,7 +1610,7 @@ impl<'a> TraitDef<'a> {
fn create_struct_field_access_fields(
&self,
cx: &ExtCtxt<'_>,
selflike_args: &[P<Expr>],
selflike_args: &[Box<Expr>],
struct_def: &'a VariantData,
is_packed: bool,
) -> Vec<FieldInfo> {
@ -1651,7 +1655,7 @@ pub(crate) enum CsFold<'a> {
/// The combination of two field expressions. E.g. for `PartialEq::eq` this
/// is something like `<field1 equality> && <field2 equality>`.
Combine(Span, P<Expr>, P<Expr>),
Combine(Span, Box<Expr>, Box<Expr>),
// The fallback case for a struct or enum variant with no fields.
Fieldless,
@ -1665,9 +1669,9 @@ pub(crate) fn cs_fold<F>(
trait_span: Span,
substructure: &Substructure<'_>,
mut f: F,
) -> P<Expr>
) -> Box<Expr>
where
F: FnMut(&ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
F: FnMut(&ExtCtxt<'_>, CsFold<'_>) -> Box<Expr>,
{
match substructure.fields {
EnumMatching(.., all_fields) | Struct(_, all_fields) => {

View file

@ -2,7 +2,6 @@
//! when specifying impls to be derived.
pub(crate) use Ty::*;
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind};
use rustc_expand::base::ExtCtxt;
use rustc_span::source_map::respan;
@ -41,7 +40,7 @@ impl Path {
span: Span,
self_ty: Ident,
self_generics: &Generics,
) -> P<ast::Ty> {
) -> Box<ast::Ty> {
cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
}
pub(crate) fn to_path(
@ -90,7 +89,7 @@ impl Ty {
span: Span,
self_ty: Ident,
self_generics: &Generics,
) -> P<ast::Ty> {
) -> Box<ast::Ty> {
match self {
Ref(ty, mutbl) => {
let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
@ -192,7 +191,7 @@ impl Bounds {
}
}
pub(crate) fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) {
pub(crate) fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (Box<Expr>, ast::ExplicitSelf) {
// This constructs a fresh `self` path.
let self_path = cx.expr_self(span);
let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not));

View file

@ -1,7 +1,6 @@
//! The compiler code necessary to implement the `#[derive]` extensions.
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::{GenericArg, MetaItem};
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
use rustc_span::{Span, Symbol, sym};
@ -66,7 +65,7 @@ impl MultiItemModifier for BuiltinDerive {
&mut |a| {
// Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx'
// to the function
items.push(Annotatable::Stmt(P(ast::Stmt {
items.push(Annotatable::Stmt(Box::new(ast::Stmt {
id: ast::DUMMY_NODE_ID,
kind: ast::StmtKind::Item(a.expect_item()),
span,
@ -91,20 +90,20 @@ fn call_intrinsic(
cx: &ExtCtxt<'_>,
span: Span,
intrinsic: Symbol,
args: ThinVec<P<ast::Expr>>,
) -> P<ast::Expr> {
args: ThinVec<Box<ast::Expr>>,
) -> Box<ast::Expr> {
let span = cx.with_def_site_ctxt(span);
let path = cx.std_path(&[sym::intrinsics, intrinsic]);
cx.expr_call_global(span, path, args)
}
/// Constructs an expression that calls the `unreachable` intrinsic.
fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> Box<ast::Expr> {
let span = cx.with_def_site_ctxt(span);
let path = cx.std_path(&[sym::intrinsics, sym::unreachable]);
let call = cx.expr_call_global(span, path, ThinVec::new());
cx.expr_block(P(ast::Block {
cx.expr_block(Box::new(ast::Block {
stmts: thin_vec![cx.stmt_expr(call)],
id: ast::DUMMY_NODE_ID,
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
@ -116,7 +115,7 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
fn assert_ty_bounds(
cx: &ExtCtxt<'_>,
stmts: &mut ThinVec<ast::Stmt>,
ty: P<ast::Ty>,
ty: Box<ast::Ty>,
span: Span,
assert_path: &[Symbol],
) {

View file

@ -1,4 +1,3 @@
use rustc_ast::ptr::P;
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
use rustc_ast::*;
@ -48,7 +47,7 @@ fn expand<'cx>(
ExpandResult::Ready(MacEager::expr(
cx.expr(
sp,
ExprKind::MacCall(P(MacCall {
ExprKind::MacCall(Box::new(MacCall {
path: Path {
span: sp,
segments: cx
@ -58,7 +57,7 @@ fn expand<'cx>(
.collect(),
tokens: None,
},
args: P(DelimArgs {
args: Box::new(DelimArgs {
dspan: DelimSpan::from_single(sp),
delim: Delimiter::Parenthesis,
tokens: tts,

View file

@ -1,7 +1,6 @@
use std::ops::Range;
use parse::Position::ArgumentNamed;
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{
Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs,
@ -45,7 +44,7 @@ use PositionUsedAs::*;
#[derive(Debug)]
struct MacroInput {
fmtstr: P<Expr>,
fmtstr: Box<Expr>,
args: FormatArguments,
/// Whether the first argument was a string literal or a result from eager macro expansion.
/// If it's not a string literal, we disallow implicit argument capturing.
@ -1018,7 +1017,7 @@ fn expand_format_args_impl<'cx>(
};
match mac {
Ok(format_args) => {
MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args))))
MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(Box::new(format_args))))
}
Err(guar) => MacEager::expr(DummyResult::raw_expr(sp, Some(guar))),
}

View file

@ -346,18 +346,18 @@ pub(crate) mod printf {
// ```regex
// (?x)
// ^ %
// (?: (?P<parameter> \d+) \$ )?
// (?P<flags> [-+ 0\#']* )
// (?P<width> \d+ | \* (?: (?P<widtha> \d+) \$ )? )?
// (?: \. (?P<precision> \d+ | \* (?: (?P<precisiona> \d+) \$ )? ) )?
// (?P<length>
// (?: (?Box<parameter> \d+) \$ )?
// (?Box<flags> [-+ 0\#']* )
// (?Box<width> \d+ | \* (?: (?Box<widtha> \d+) \$ )? )?
// (?: \. (?Box<precision> \d+ | \* (?: (?Box<precisiona> \d+) \$ )? ) )?
// (?Box<length>
// # Standard
// hh | h | ll | l | L | z | j | t
//
// # Other
// | I32 | I64 | I | q
// )?
// (?P<type> . )
// (?Box<type> . )
// ```
// Used to establish the full span at the end.

View file

@ -1,7 +1,6 @@
use rustc_ast::expand::allocator::{
ALLOCATOR_METHODS, AllocatorMethod, AllocatorMethodInput, AllocatorTy, global_fn_name,
};
use rustc_ast::ptr::P;
use rustc_ast::{
self as ast, AttrVec, Expr, Fn, FnHeader, FnSig, Generics, ItemKind, Mutability, Param, Safety,
Stmt, StmtKind, Ty, TyKind,
@ -51,7 +50,7 @@ pub(crate) fn expand(
let const_body = ecx.expr_block(ecx.block(span, stmts));
let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
let const_item = if is_stmt {
Annotatable::Stmt(P(ecx.stmt_item(span, const_item)))
Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item)))
} else {
Annotatable::Item(const_item)
};
@ -90,7 +89,7 @@ impl AllocFnFactory<'_, '_> {
self.cx.stmt_item(self.ty_span, item)
}
fn call_allocator(&self, method: Symbol, mut args: ThinVec<P<Expr>>) -> P<Expr> {
fn call_allocator(&self, method: Symbol, mut args: ThinVec<Box<Expr>>) -> Box<Expr> {
let method = self.cx.std_path(&[sym::alloc, sym::GlobalAlloc, method]);
let method = self.cx.expr_path(self.cx.path(self.ty_span, method));
let allocator = self.cx.path_ident(self.ty_span, self.global);
@ -105,7 +104,7 @@ impl AllocFnFactory<'_, '_> {
thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)]
}
fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec<Param>) -> P<Expr> {
fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec<Param>) -> Box<Expr> {
match input.ty {
AllocatorTy::Layout => {
// If an allocator method is ever introduced having multiple
@ -148,7 +147,7 @@ impl AllocFnFactory<'_, '_> {
}
}
fn ret_ty(&self, ty: &AllocatorTy) -> P<Ty> {
fn ret_ty(&self, ty: &AllocatorTy) -> Box<Ty> {
match *ty {
AllocatorTy::ResultPtr => self.ptr_u8(),
@ -160,12 +159,12 @@ impl AllocFnFactory<'_, '_> {
}
}
fn usize(&self) -> P<Ty> {
fn usize(&self) -> Box<Ty> {
let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span));
self.cx.ty_path(usize)
}
fn ptr_u8(&self) -> P<Ty> {
fn ptr_u8(&self) -> Box<Ty> {
let u8 = self.cx.path_ident(self.span, Ident::new(sym::u8, self.span));
let ty_u8 = self.cx.ty_path(u8);
self.cx.ty_ptr(self.span, ty_u8, Mutability::Mut)

View file

@ -1,4 +1,3 @@
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{CoroutineKind, DUMMY_NODE_ID, Expr, ast, token};
use rustc_errors::PResult;
@ -24,7 +23,7 @@ fn parse_closure<'a>(
cx: &mut ExtCtxt<'a>,
span: Span,
stream: TokenStream,
) -> PResult<'a, P<Expr>> {
) -> PResult<'a, Box<Expr>> {
let mut closure_parser = cx.new_parser_from_tts(stream);
let coroutine_kind = Some(CoroutineKind::Gen {

View file

@ -1,4 +1,3 @@
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token};
use rustc_errors::PResult;
@ -22,7 +21,10 @@ pub(crate) fn expand<'cx>(
ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::Pat(ty, pat))))
}
fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Ty>, P<TyPat>)> {
fn parse_pat_ty<'a>(
cx: &mut ExtCtxt<'a>,
stream: TokenStream,
) -> PResult<'a, (Box<Ty>, Box<TyPat>)> {
let mut parser = cx.new_parser_from_tts(stream);
let ty = parser.parse_ty()?;
@ -45,15 +47,15 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P
Ok((ty, pat))
}
fn ty_pat(kind: TyPatKind, span: Span) -> P<TyPat> {
P(TyPat { id: DUMMY_NODE_ID, kind, span, tokens: None })
fn ty_pat(kind: TyPatKind, span: Span) -> Box<TyPat> {
Box::new(TyPat { id: DUMMY_NODE_ID, kind, span, tokens: None })
}
fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> P<TyPat> {
fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> Box<TyPat> {
let kind = match pat.kind {
ast::PatKind::Range(start, end, include_end) => TyPatKind::Range(
start.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })),
end.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })),
start.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })),
end.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })),
include_end,
),
ast::PatKind::Or(variants) => {

View file

@ -1,6 +1,5 @@
use std::{mem, slice};
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{self as ast, HasNodeId, NodeId, attr};
use rustc_ast_pretty::pprust;
@ -286,7 +285,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
// // ...
// ];
// }
fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> Box<ast::Item> {
let expn_id = cx.resolver.expansion_for_ast_pass(
DUMMY_SP,
AstPass::ProcMacroHarness,

View file

@ -3,7 +3,6 @@ use std::rc::Rc;
use std::sync::Arc;
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{join_path_idents, token};
use rustc_ast_pretty::pprust;
@ -144,7 +143,7 @@ pub(crate) fn expand_include<'cx>(
node_id: ast::NodeId,
}
impl<'a> MacResult for ExpandInclude<'a> {
fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<P<ast::Expr>> {
fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<Box<ast::Expr>> {
let expr = parse_expr(&mut self.p).ok()?;
if self.p.token != token::Eof {
self.p.psess.buffer_lint(
@ -157,7 +156,7 @@ pub(crate) fn expand_include<'cx>(
Some(expr)
}
fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[Box<ast::Item>; 1]>> {
let mut ret = SmallVec::new();
loop {
match self.p.parse_item(ForceCollect::No) {

View file

@ -4,7 +4,6 @@
use std::assert_matches::assert_matches;
use std::iter;
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, GenericParamKind, HasNodeId, attr, join_path_idents};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::AttributeParser;
@ -78,7 +77,7 @@ pub(crate) fn expand_test_case(
}
let ret = if is_stmt {
Annotatable::Stmt(P(ecx.stmt_item(item.span, item)))
Annotatable::Stmt(Box::new(ecx.stmt_item(item.span, item)))
} else {
Annotatable::Item(item)
};
@ -131,7 +130,7 @@ pub(crate) fn expand_test_or_bench(
let ast::ItemKind::Fn(fn_) = &item.kind else {
not_testable_error(cx, attr_sp, Some(&item));
return if is_stmt {
vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))]
vec![Annotatable::Stmt(Box::new(cx.stmt_item(item.span, item)))]
} else {
vec![Annotatable::Item(item)]
};
@ -155,7 +154,7 @@ pub(crate) fn expand_test_or_bench(
};
if check_result.is_err() {
return if is_stmt {
vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))]
vec![Annotatable::Stmt(Box::new(cx.stmt_item(item.span, item)))]
} else {
vec![Annotatable::Item(item)]
};
@ -201,7 +200,7 @@ pub(crate) fn expand_test_or_bench(
// `-Cinstrument-coverage` builds.
// This requires `#[allow_internal_unstable(coverage_attribute)]` on the
// corresponding macro declaration in `core::macros`.
let coverage_off = |mut expr: P<ast::Expr>| {
let coverage_off = |mut expr: Box<ast::Expr>| {
assert_matches!(expr.kind, ast::ExprKind::Closure(_));
expr.attrs.push(cx.attr_nested_word(sym::coverage, sym::off, sp));
expr
@ -388,11 +387,11 @@ pub(crate) fn expand_test_or_bench(
if is_stmt {
vec![
// Access to libtest under a hygienic name
Annotatable::Stmt(P(cx.stmt_item(sp, test_extern))),
Annotatable::Stmt(Box::new(cx.stmt_item(sp, test_extern))),
// The generated test case
Annotatable::Stmt(P(cx.stmt_item(sp, test_const))),
Annotatable::Stmt(Box::new(cx.stmt_item(sp, test_const))),
// The original item
Annotatable::Stmt(P(cx.stmt_item(sp, item))),
Annotatable::Stmt(Box::new(cx.stmt_item(sp, item))),
]
} else {
vec![

View file

@ -5,7 +5,6 @@ use std::mem;
use rustc_ast as ast;
use rustc_ast::entry::EntryPointType;
use rustc_ast::mut_visit::*;
use rustc_ast::ptr::P;
use rustc_ast::visit::Visitor;
use rustc_ast::{ModKind, attr};
use rustc_errors::DiagCtxtHandle;
@ -284,7 +283,7 @@ fn generate_test_harness(
/// [`TestCtxt::reexport_test_harness_main`] provides a different name for the `main`
/// function and [`TestCtxt::test_runner`] provides a path that replaces
/// `test::test_main_static`.
fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
fn mk_main(cx: &mut TestCtxt<'_>) -> Box<ast::Item> {
let sp = cx.def_site;
let ecx = &cx.ext_cx;
let test_ident = Ident::new(sym::test, sp);
@ -348,7 +347,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
define_opaque: None,
}));
let main = P(ast::Item {
let main = Box::new(ast::Item {
attrs: thin_vec![main_attr, coverage_attr, doc_hidden_attr],
id: ast::DUMMY_NODE_ID,
kind: main,
@ -364,7 +363,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
/// Creates a slice containing every test like so:
/// &[&test1, &test2]
fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> Box<ast::Expr> {
debug!("building test vector from {} tests", cx.test_cases.len());
let ecx = &cx.ext_cx;

View file

@ -1,4 +1,3 @@
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{self as ast, AttrStyle, Attribute, MetaItem, attr, token};
use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
@ -83,7 +82,7 @@ type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), Err
#[allow(rustc::untranslatable_diagnostic)]
pub(crate) fn expr_to_spanned_string<'a>(
cx: &'a mut ExtCtxt<'_>,
expr: P<ast::Expr>,
expr: Box<ast::Expr>,
err_msg: &'static str,
) -> ExpandResult<ExprToSpannedStringResult<'a>, ()> {
if !cx.force_mode
@ -135,7 +134,7 @@ pub(crate) fn expr_to_spanned_string<'a>(
/// compilation on error, merely emits a non-fatal error and returns `Err`.
pub(crate) fn expr_to_string(
cx: &mut ExtCtxt<'_>,
expr: P<ast::Expr>,
expr: Box<ast::Expr>,
err_msg: &'static str,
) -> ExpandResult<Result<(Symbol, ast::StrStyle), ErrorGuaranteed>, ()> {
expr_to_spanned_string(cx, expr, err_msg).map(|res| {
@ -158,7 +157,7 @@ pub(crate) fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, nam
}
/// Parse an expression. On error, emit it, advancing to `Eof`, and return `Err`.
pub(crate) fn parse_expr(p: &mut parser::Parser<'_>) -> Result<P<ast::Expr>, ErrorGuaranteed> {
pub(crate) fn parse_expr(p: &mut parser::Parser<'_>) -> Result<Box<ast::Expr>, ErrorGuaranteed> {
let guar = match p.parse_expr() {
Ok(expr) => return Ok(expr),
Err(err) => err.emit(),
@ -209,7 +208,7 @@ pub(crate) fn get_single_expr_from_tts(
span: Span,
tts: TokenStream,
name: &str,
) -> ExpandResult<Result<P<ast::Expr>, ErrorGuaranteed>, ()> {
) -> ExpandResult<Result<Box<ast::Expr>, ErrorGuaranteed>, ()> {
let mut p = cx.new_parser_from_tts(tts);
if p.token == token::Eof {
let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
@ -232,7 +231,7 @@ pub(crate) fn get_single_expr_from_tts(
pub(crate) fn get_exprs_from_tts(
cx: &mut ExtCtxt<'_>,
tts: TokenStream,
) -> ExpandResult<Result<Vec<P<ast::Expr>>, ErrorGuaranteed>, ()> {
) -> ExpandResult<Result<Vec<Box<ast::Expr>>, ErrorGuaranteed>, ()> {
let mut p = cx.new_parser_from_tts(tts);
let mut es = Vec::new();
while p.token != token::Eof {

View file

@ -557,13 +557,25 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
let (size, signed) = ty.int_size_and_signed(self.tcx);
let width = size.bits();
if oop == OverflowOp::Sub && !signed {
// Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these
// to be the canonical form. It will attempt to reform llvm.usub.with.overflow
// in the backend if profitable.
let sub = self.sub(lhs, rhs);
let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs);
return (sub, cmp);
if !signed {
match oop {
OverflowOp::Sub => {
// Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these
// to be the canonical form. It will attempt to reform llvm.usub.with.overflow
// in the backend if profitable.
let sub = self.sub(lhs, rhs);
let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs);
return (sub, cmp);
}
OverflowOp::Add => {
// Like with sub above, using icmp is the preferred form. See
// <https://rust-lang.zulipchat.com/#narrow/channel/187780-t-compiler.2Fllvm/topic/.60uadd.2Ewith.2Eoverflow.60.20.28again.29/near/533041085>
let add = self.add(lhs, rhs);
let cmp = self.icmp(IntPredicate::IntULT, add, lhs);
return (add, cmp);
}
OverflowOp::Mul => {}
}
}
let oop_str = match oop {

View file

@ -180,6 +180,10 @@ codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented y
codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error}
codegen_ssa_link_exe_status_stack_buffer_overrun = 0xc0000409 is `STATUS_STACK_BUFFER_OVERRUN`
.abort_note = this may have been caused by a program abort and not a stack buffer overrun
.event_log_note = consider checking the Application Event Log for Windows Error Reporting events to see the fail fast error code
codegen_ssa_link_exe_unexpected_error = `link.exe` returned an unexpected error
codegen_ssa_link_script_unavailable = can only use link script when linking with GNU-like linker
@ -397,6 +401,9 @@ codegen_ssa_version_script_write_failure = failed to write version script: {$err
codegen_ssa_visual_studio_not_installed = you may need to install Visual Studio build tools with the "C++ build tools" workload
codegen_ssa_xcrun_about =
the SDK is needed by the linker to know where to find symbols in system libraries and for embedding the SDK version in the final object file
codegen_ssa_xcrun_command_line_tools_insufficient =
when compiling for iOS, tvOS, visionOS or watchOS, you need a full installation of Xcode

View file

@ -160,6 +160,10 @@ pub(super) fn add_version_to_llvm_target(
pub(super) fn get_sdk_root(sess: &Session) -> Option<PathBuf> {
let sdk_name = sdk_name(&sess.target);
// Attempt to invoke `xcrun` to find the SDK.
//
// Note that when cross-compiling from e.g. Linux, the `xcrun` binary may sometimes be provided
// as a shim by a cross-compilation helper tool. It usually isn't, but we still try nonetheless.
match xcrun_show_sdk_path(sdk_name, sess.verbose_internals()) {
Ok((path, stderr)) => {
// Emit extra stderr, such as if `-verbose` was passed, or if `xcrun` emitted a warning.
@ -169,7 +173,19 @@ pub(super) fn get_sdk_root(sess: &Session) -> Option<PathBuf> {
Some(path)
}
Err(err) => {
let mut diag = sess.dcx().create_err(err);
// Failure to find the SDK is not a hard error, since the user might have specified it
// in a manner unknown to us (moreso if cross-compiling):
// - A compiler driver like `zig cc` which links using an internally bundled SDK.
// - Extra linker arguments (`-Clink-arg=-syslibroot`).
// - A custom linker or custom compiler driver.
//
// Though we still warn, since such cases are uncommon, and it is very hard to debug if
// you do not know the details.
//
// FIXME(madsmtm): Make this a lint, to allow deny warnings to work.
// (Or fix <https://github.com/rust-lang/rust/issues/21204>).
let mut diag = sess.dcx().create_warn(err);
diag.note(fluent::codegen_ssa_xcrun_about);
// Recognize common error cases, and give more Rust-specific error messages for those.
if let Some(developer_dir) = xcode_select_developer_dir() {
@ -209,6 +225,8 @@ fn xcrun_show_sdk_path(
sdk_name: &'static str,
verbose: bool,
) -> Result<(PathBuf, String), XcrunError> {
// Intentionally invoke the `xcrun` in PATH, since e.g. nixpkgs provide an `xcrun` shim, so we
// don't want to require `/usr/bin/xcrun`.
let mut cmd = Command::new("xcrun");
if verbose {
cmd.arg("--verbose");
@ -280,7 +298,7 @@ fn stdout_to_path(mut stdout: Vec<u8>) -> PathBuf {
}
#[cfg(unix)]
let path = <OsString as std::os::unix::ffi::OsStringExt>::from_vec(stdout);
#[cfg(not(unix))] // Unimportant, this is only used on macOS
let path = OsString::from(String::from_utf8(stdout).unwrap());
#[cfg(not(unix))] // Not so important, this is mostly used on macOS
let path = OsString::from(String::from_utf8(stdout).expect("stdout must be UTF-8"));
PathBuf::from(path)
}

View file

@ -880,6 +880,14 @@ fn link_natively(
windows_registry::find_tool(&sess.target.arch, "link.exe").is_some();
sess.dcx().emit_note(errors::LinkExeUnexpectedError);
// STATUS_STACK_BUFFER_OVERRUN is also used for fast abnormal program termination, e.g. abort().
// Emit a special diagnostic to let people know that this most likely doesn't indicate a stack buffer overrun.
const STATUS_STACK_BUFFER_OVERRUN: i32 = 0xc0000409u32 as _;
if code == STATUS_STACK_BUFFER_OVERRUN {
sess.dcx().emit_note(errors::LinkExeStatusStackBufferOverrun);
}
if is_vs_installed && has_linker {
// the linker is broken
sess.dcx().emit_note(errors::RepairVSBuildTools);
@ -3186,39 +3194,60 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
}
fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> Option<PathBuf> {
let os = &sess.target.os;
if sess.target.vendor != "apple"
|| !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "visionos" | "macos")
|| !matches!(flavor, LinkerFlavor::Darwin(..))
{
if !sess.target.is_like_darwin {
return None;
}
if os == "macos" && !matches!(flavor, LinkerFlavor::Darwin(Cc::No, _)) {
let LinkerFlavor::Darwin(cc, _) = flavor else {
return None;
};
// The default compiler driver on macOS is at `/usr/bin/cc`. This is a trampoline binary that
// effectively invokes `xcrun cc` internally to look up both the compiler binary and the SDK
// root from the current Xcode installation. When cross-compiling, when `rustc` is invoked
// inside Xcode, or when invoking the linker directly, this default logic is unsuitable, so
// instead we invoke `xcrun` manually.
//
// (Note that this doesn't mean we get a duplicate lookup here - passing `SDKROOT` below will
// cause the trampoline binary to skip looking up the SDK itself).
let sdkroot = sess.time("get_apple_sdk_root", || get_apple_sdk_root(sess))?;
if cc == Cc::Yes {
// There are a few options to pass the SDK root when linking with a C/C++ compiler:
// - The `--sysroot` flag.
// - The `-isysroot` flag.
// - The `SDKROOT` environment variable.
//
// `--sysroot` isn't actually enough to get Clang to treat it as a platform SDK, you need
// to specify `-isysroot`. This is admittedly a bit strange, as on most targets `-isysroot`
// only applies to include header files, but on Apple targets it also applies to libraries
// and frameworks.
//
// This leaves the choice between `-isysroot` and `SDKROOT`. Both are supported by Clang and
// GCC, though they may not be supported by all compiler drivers. We choose `SDKROOT`,
// primarily because that is the same interface that is used when invoking the tool under
// `xcrun -sdk macosx $tool`.
//
// In that sense, if a given compiler driver does not support `SDKROOT`, the blame is fairly
// clearly in the tool in question, since they also don't support being run under `xcrun`.
//
// Additionally, `SDKROOT` is an environment variable and thus optional. It also has lower
// precedence than `-isysroot`, so a custom compiler driver that does not support it and
// instead figures out the SDK on their own can easily do so by using `-isysroot`.
//
// (This in particular affects Clang built with the `DEFAULT_SYSROOT` CMake flag, such as
// the one provided by some versions of Homebrew's `llvm` package. Those will end up
// ignoring the value we set here, and instead use their built-in sysroot).
cmd.cmd().env("SDKROOT", &sdkroot);
} else {
// When invoking the linker directly, we use the `-syslibroot` parameter. `SDKROOT` is not
// read by the linker, so it's really the only option.
//
// This is also what Clang does.
cmd.link_arg("-syslibroot");
cmd.link_arg(&sdkroot);
}
let sdk_root = sess.time("get_apple_sdk_root", || get_apple_sdk_root(sess))?;
match flavor {
LinkerFlavor::Darwin(Cc::Yes, _) => {
// Use `-isysroot` instead of `--sysroot`, as only the former
// makes Clang treat it as a platform SDK.
//
// This is admittedly a bit strange, as on most targets
// `-isysroot` only applies to include header files, but on Apple
// targets this also applies to libraries and frameworks.
cmd.cc_arg("-isysroot");
cmd.cc_arg(&sdk_root);
}
LinkerFlavor::Darwin(Cc::No, _) => {
cmd.link_arg("-syslibroot");
cmd.link_arg(&sdk_root);
}
_ => unreachable!(),
}
Some(sdk_root)
Some(sdkroot)
}
fn get_apple_sdk_root(sess: &Session) -> Option<PathBuf> {
@ -3247,7 +3276,13 @@ fn get_apple_sdk_root(sess: &Session) -> Option<PathBuf> {
}
"macosx"
if sdkroot.contains("iPhoneOS.platform")
|| sdkroot.contains("iPhoneSimulator.platform") => {}
|| sdkroot.contains("iPhoneSimulator.platform")
|| sdkroot.contains("AppleTVOS.platform")
|| sdkroot.contains("AppleTVSimulator.platform")
|| sdkroot.contains("WatchOS.platform")
|| sdkroot.contains("WatchSimulator.platform")
|| sdkroot.contains("XROS.platform")
|| sdkroot.contains("XRSimulator.platform") => {}
"watchos"
if sdkroot.contains("WatchSimulator.platform")
|| sdkroot.contains("MacOSX.platform") => {}

View file

@ -569,7 +569,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel
// core/std/allocators/etc. For example symbols used to hook up allocation
// are not considered for export
let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id);
let is_extern = codegen_fn_attrs.contains_extern_indicator();
let is_extern = codegen_fn_attrs.contains_extern_indicator(tcx, sym_def_id);
let std_internal =
codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);

View file

@ -443,6 +443,27 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code
if tcx.should_inherit_track_caller(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
}
// Foreign items by default use no mangling for their symbol name.
if tcx.is_foreign_item(did) {
// There's a few exceptions to this rule though:
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
// * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way
// both for exports and imports through foreign items. This is handled further,
// during symbol mangling logic.
} else if codegen_fn_attrs.link_name.is_some() {
// * This can be overridden with the `#[link_name]` attribute
} else {
// NOTE: there's one more exception that we cannot apply here. On wasm,
// some items cannot be `no_mangle`.
// However, we don't have enough information here to determine that.
// As such, no_mangle foreign items on wasm that have the same defid as some
// import will *still* be mangled despite this.
//
// if none of the exceptions apply; apply no_mangle
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
}
}
}
fn check_result(

View file

@ -550,6 +550,18 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
#[diag(codegen_ssa_link_exe_unexpected_error)]
pub(crate) struct LinkExeUnexpectedError;
pub(crate) struct LinkExeStatusStackBufferOverrun;
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for LinkExeStatusStackBufferOverrun {
fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
let mut diag =
Diag::new(dcx, level, fluent::codegen_ssa_link_exe_status_stack_buffer_overrun);
diag.note(fluent::codegen_ssa_abort_note);
diag.note(fluent::codegen_ssa_event_log_note);
diag
}
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_repair_vs_build_tools)]
pub(crate) struct RepairVSBuildTools;

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