Auto merge of #3727 - RalfJung:rustup, r=RalfJung

Rustup

To unblock https://github.com/rust-lang/miri/pull/3688
This commit is contained in:
bors 2024-07-02 06:29:31 +00:00
commit 3ca56a34bd
665 changed files with 9525 additions and 6702 deletions

2
.ignore Normal file
View file

@ -0,0 +1,2 @@
# Make vscode *not* count `config.toml` as ignored, so it is included in search
!/config.toml

View file

@ -36,6 +36,7 @@ Files: compiler/*
.gitignore
.gitmodules
.mailmap
.ignore
Copyright: The Rust Project Developers (see https://thanks.rust-lang.org)
License: MIT or Apache-2.0

View file

@ -3401,6 +3401,7 @@ name = "run_make_support"
version = "0.2.0"
dependencies = [
"ar",
"bstr",
"gimli 0.28.1",
"object 0.34.0",
"regex",
@ -3460,6 +3461,13 @@ dependencies = [
"stable_mir",
]
[[package]]
name = "rustc-perf-wrapper"
version = "0.1.0"
dependencies = [
"clap",
]
[[package]]
name = "rustc-rayon"
version = "0.5.0"
@ -4752,8 +4760,6 @@ checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
name = "rustc_trait_selection"
version = "0.0.0"
dependencies = [
"bitflags 2.5.0",
"derivative",
"itertools",
"rustc_ast",
"rustc_ast_ir",
@ -4762,7 +4768,6 @@ dependencies = [
"rustc_errors",
"rustc_fluent_macro",
"rustc_hir",
"rustc_index",
"rustc_infer",
"rustc_macros",
"rustc_middle",
@ -4775,7 +4780,6 @@ dependencies = [
"rustc_target",
"rustc_transmute",
"rustc_type_ir",
"rustc_type_ir_macros",
"smallvec",
"tracing",
]

View file

@ -44,6 +44,7 @@ members = [
"src/tools/rustdoc-gui-test",
"src/tools/opt-dist",
"src/tools/coverage-dump",
"src/tools/rustc-perf-wrapper",
]
exclude = [

View file

@ -103,7 +103,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
ParamMode::Optional,
ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
// Method calls can't have bound modifiers
None,
));

View file

@ -56,7 +56,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
owner: NodeId,
f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
) {
let mut lctx = LoweringContext::new(self.tcx, self.resolver);
let mut lctx = LoweringContext::new(self.tcx, self.resolver, self.ast_index);
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
for (def_id, info) in lctx.children {
@ -190,6 +190,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, (ty, body_id)) = self.lower_generics(
generics,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -221,7 +222,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let itctx = ImplTraitContext::Universal;
let (generics, decl) =
this.lower_generics(generics, header.constness, id, itctx, |this| {
this.lower_generics(generics, header.constness, false, id, itctx, |this| {
this.lower_fn_decl(
decl,
id,
@ -265,6 +266,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, ty) = self.lower_generics(
&generics,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty {
@ -293,6 +295,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, variants) = self.lower_generics(
generics,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -307,6 +310,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, struct_def) = self.lower_generics(
generics,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, struct_def),
@ -317,6 +321,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, vdata) = self.lower_generics(
generics,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, vdata),
@ -348,12 +353,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
// parent lifetime.
let itctx = ImplTraitContext::Universal;
let (generics, (trait_ref, lowered_ty)) =
self.lower_generics(ast_generics, *constness, id, itctx, |this| {
self.lower_generics(ast_generics, Const::No, false, id, itctx, |this| {
let modifiers = TraitBoundModifiers {
constness: match *constness {
Const::Yes(span) => BoundConstness::Maybe(span),
Const::No => BoundConstness::Never,
},
constness: BoundConstness::Never,
asyncness: BoundAsyncness::Normal,
// we don't use this in bound lowering
polarity: BoundPolarity::Positive,
@ -389,6 +391,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
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,
@ -400,15 +403,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
}))
}
ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => {
// FIXME(const_trait_impl, effects, fee1-dead) this should be simplified if possible
let constness = attrs
.unwrap_or(&[])
.iter()
.find(|x| x.has_name(sym::const_trait))
.map_or(Const::No, |x| Const::Yes(x.span));
let (generics, (safety, items, bounds)) = self.lower_generics(
generics,
constness,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -429,6 +427,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, bounds) = self.lower_generics(
generics,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -609,30 +608,45 @@ impl<'hir> LoweringContext<'_, 'hir> {
// This is used to track which lifetimes have already been defined,
// and which need to be replicated when lowering an async fn.
let generics = match parent_hir.node().expect_item().kind {
let parent_item = parent_hir.node().expect_item();
let constness = match parent_item.kind {
hir::ItemKind::Impl(impl_) => {
self.is_in_trait_impl = impl_.of_trait.is_some();
&impl_.generics
// N.B. the impl should always lower to methods that have `const host: bool` params if the trait
// is const. It doesn't matter whether the `impl` itself is const. Disallowing const fn from
// calling non-const impls are done through associated types.
if let Some(def_id) = impl_.of_trait.and_then(|tr| tr.trait_def_id()) {
if let Some(local_def) = def_id.as_local() {
match &self.ast_index[local_def] {
AstOwner::Item(ast::Item { attrs, .. }) => attrs
.iter()
.find(|attr| attr.has_name(sym::const_trait))
.map_or(Const::No, |attr| Const::Yes(attr.span)),
_ => Const::No,
}
} else {
self.tcx
.get_attr(def_id, sym::const_trait)
.map_or(Const::No, |attr| Const::Yes(attr.span))
}
} else {
Const::No
}
}
hir::ItemKind::Trait(_, _, generics, _, _) => generics,
hir::ItemKind::Trait(_, _, _, _, _) => parent_hir
.attrs
.get(parent_item.hir_id().local_id)
.iter()
.find(|attr| attr.has_name(sym::const_trait))
.map_or(Const::No, |attr| Const::Yes(attr.span)),
kind => {
span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr())
}
};
if self.tcx.features().effects {
self.host_param_id = generics
.params
.iter()
.find(|param| {
matches!(param.kind, hir::GenericParamKind::Const { is_host_effect: true, .. })
})
.map(|param| param.def_id);
}
match ctxt {
AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)),
AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item)),
AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item, constness)),
AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item, constness)),
}
}
@ -648,7 +662,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let fdec = &sig.decl;
let itctx = ImplTraitContext::Universal;
let (generics, (fn_dec, fn_args)) =
self.lower_generics(generics, Const::No, i.id, itctx, |this| {
self.lower_generics(generics, Const::No, false, i.id, itctx, |this| {
(
// Disallow `impl Trait` in foreign items.
this.lower_fn_decl(
@ -765,7 +779,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
fn lower_trait_item(
&mut self,
i: &AssocItem,
trait_constness: Const,
) -> &'hir hir::TraitItem<'hir> {
let hir_id = self.lower_node_id(i.id);
self.lower_attrs(hir_id, &i.attrs);
let trait_item_def_id = hir_id.expect_owner();
@ -775,6 +793,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, kind) = self.lower_generics(
generics,
Const::No,
false,
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -795,6 +814,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
i.id,
FnDeclKind::Trait,
sig.header.coroutine_kind,
trait_constness,
);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
}
@ -813,6 +833,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
i.id,
FnDeclKind::Trait,
sig.header.coroutine_kind,
trait_constness,
);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
}
@ -822,6 +843,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, kind) = self.lower_generics(
&generics,
Const::No,
false,
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -894,7 +916,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.expr(span, hir::ExprKind::Err(guar))
}
fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
fn lower_impl_item(
&mut self,
i: &AssocItem,
constness_of_trait: Const,
) -> &'hir hir::ImplItem<'hir> {
// Since `default impl` is not yet implemented, this is always true in impls.
let has_value = true;
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
@ -905,6 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
generics,
Const::No,
false,
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -930,6 +957,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
i.id,
if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
sig.header.coroutine_kind,
constness_of_trait,
);
(generics, hir::ImplItemKind::Fn(sig, body_id))
@ -940,6 +968,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_generics(
&generics,
Const::No,
false,
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty {
@ -1352,15 +1381,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
id: NodeId,
kind: FnDeclKind,
coroutine_kind: Option<CoroutineKind>,
parent_constness: Const,
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
let header = self.lower_fn_header(sig.header);
// Don't pass along the user-provided constness of trait associated functions; we don't want to
// synthesize a host effect param for them. We reject `const` on them during AST validation.
let constness = if kind == FnDeclKind::Inherent { sig.header.constness } else { Const::No };
let constness =
if kind == FnDeclKind::Inherent { sig.header.constness } else { parent_constness };
let itctx = ImplTraitContext::Universal;
let (generics, decl) = self.lower_generics(generics, constness, id, itctx, |this| {
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
});
let (generics, decl) =
self.lower_generics(generics, constness, kind == FnDeclKind::Impl, id, itctx, |this| {
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
});
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
}
@ -1436,6 +1468,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
generics: &Generics,
constness: Const,
force_append_constness: bool,
parent_node_id: NodeId,
itctx: ImplTraitContext,
f: impl FnOnce(&mut Self) -> T,
@ -1496,7 +1529,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
// if the effects feature is enabled. This needs to be done before we lower where
// clauses since where clauses need to bind to the DefId of the host param
let host_param_parts = if let Const::Yes(span) = constness
&& self.tcx.features().effects
// if this comes from implementing a `const` trait, we must force constness to be appended
// to the impl item, no matter whether effects is enabled.
&& (self.tcx.features().effects || force_append_constness)
{
let span = self.lower_span(span);
let param_node_id = self.next_node_id();
@ -1609,6 +1644,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}),
)),
)),
// FIXME(effects) we might not need a default.
default: Some(self.arena.alloc(hir::AnonConst {
def_id: anon_const,
hir_id: const_id,
@ -1616,6 +1652,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
span,
})),
is_host_effect: true,
synthetic: true,
},
colon_span: None,
pure_wrt_drop: false,

View file

@ -142,14 +142,19 @@ struct LoweringContext<'a, 'hir> {
generics_def_id_map: Vec<LocalDefIdMap<LocalDefId>>,
host_param_id: Option<LocalDefId>,
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
}
impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self {
fn new(
tcx: TyCtxt<'hir>,
resolver: &'a mut ResolverAstLowering,
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
) -> Self {
Self {
// Pseudo-globals.
tcx,
resolver: resolver,
resolver,
arena: tcx.hir_arena,
// HirId handling.
@ -185,6 +190,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
generics_def_id_map: Default::default(),
host_param_id: None,
ast_index,
}
}
@ -2135,7 +2141,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param: &GenericParam,
source: hir::GenericParamSource,
) -> hir::GenericParam<'hir> {
let (name, kind) = self.lower_generic_param_kind(param, source);
let (name, kind) = self.lower_generic_param_kind(
param,
source,
attr::contains_name(&param.attrs, sym::rustc_runtime),
);
let hir_id = self.lower_node_id(param.id);
self.lower_attrs(hir_id, &param.attrs);
@ -2155,6 +2165,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self,
param: &GenericParam,
source: hir::GenericParamSource,
is_host_effect: bool,
) -> (hir::ParamName, hir::GenericParamKind<'hir>) {
match &param.kind {
GenericParamKind::Lifetime => {
@ -2220,7 +2231,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
(
hir::ParamName::Plain(self.lower_ident(param.ident)),
hir::GenericParamKind::Const { ty, default, is_host_effect: false },
hir::GenericParamKind::Const { ty, default, is_host_effect, synthetic: false },
)
}
}
@ -2607,78 +2618,6 @@ struct GenericArgsCtor<'hir> {
}
impl<'hir> GenericArgsCtor<'hir> {
fn push_constness(
&mut self,
lcx: &mut LoweringContext<'_, 'hir>,
constness: ast::BoundConstness,
) {
if !lcx.tcx.features().effects {
return;
}
let (span, body) = match constness {
BoundConstness::Never => return,
BoundConstness::Always(span) => {
let span = lcx.lower_span(span);
let body = hir::ExprKind::Lit(
lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }),
);
(span, body)
}
BoundConstness::Maybe(span) => {
let span = lcx.lower_span(span);
let Some(host_param_id) = lcx.host_param_id else {
lcx.dcx().span_delayed_bug(
span,
"no host param id for call in const yet no errors reported",
);
return;
};
let hir_id = lcx.next_id();
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
let body = hir::ExprKind::Path(hir::QPath::Resolved(
None,
lcx.arena.alloc(hir::Path {
span,
res,
segments: arena_vec![
lcx;
hir::PathSegment::new(
Ident { name: sym::host, span },
hir_id,
res
)
],
}),
));
(span, body)
}
};
let body = lcx.lower_body(|lcx| (&[], lcx.expr(span, body)));
let id = lcx.next_node_id();
let hir_id = lcx.next_id();
let def_id = lcx.create_def(
lcx.current_hir_id_owner.def_id,
id,
kw::Empty,
DefKind::AnonConst,
span,
);
lcx.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
self.args.push(hir::GenericArg::Const(hir::ConstArg {
value: lcx.arena.alloc(hir::AnonConst { def_id, hir_id, body, span }),
is_desugared_from_effects: true,
}))
}
fn is_empty(&self) -> bool {
self.args.is_empty()
&& self.constraints.is_empty()

View file

@ -107,8 +107,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode,
parenthesized_generic_args,
itctx,
// if this is the last segment, add constness to the trait path
if i == proj_start - 1 { modifiers.map(|m| m.constness) } else { None },
bound_modifier_allowed_features.clone(),
)
},
@ -165,7 +163,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ParenthesizedGenericArgs::Err,
itctx,
None,
None,
));
let qpath = hir::QPath::TypeRelative(ty, hir_segment);
@ -208,7 +205,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
None,
)
})),
span: self.lower_span(p.span),
@ -222,7 +218,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode: ParamMode,
parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: ImplTraitContext,
constness: Option<ast::BoundConstness>,
// Additional features ungated with a bound modifier like `async`.
// This is passed down to the implicit associated type binding in
// parenthesized bounds.
@ -289,10 +284,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
};
if let Some(constness) = constness {
generic_args.push_constness(self, constness);
}
let has_lifetimes =
generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));

View file

@ -1,10 +1,20 @@
// Validate AST before lowering it to HIR.
//
// This pass is supposed to catch things that fit into AST data structures,
// but not permitted by the language. It runs after expansion when AST is frozen,
// so it can check for erroneous constructions produced by syntax extensions.
// This pass is supposed to perform only simple checks not requiring name resolution
// or type checking or some other kind of complex analysis.
//! Validate AST before lowering it to HIR.
//!
//! This pass intends to check that the constructed AST is *syntactically valid* to allow the rest
//! of the compiler to assume that the AST is valid. These checks cannot be performed during parsing
//! because attribute macros are allowed to accept certain pieces of invalid syntax such as a
//! function without body outside of a trait definition:
//!
//! ```ignore (illustrative)
//! #[my_attribute]
//! mod foo {
//! fn missing_body();
//! }
//! ```
//!
//! These checks are run post-expansion, after AST is frozen, to be able to check for erroneous
//! constructions produced by proc macros. This pass is only intended for simple checks that do not
//! require name resolution or type checking, or other kinds of complex analysis.
use itertools::{Either, Itertools};
use rustc_ast::ptr::P;
@ -459,13 +469,18 @@ impl<'a> AstValidator<'a> {
fn check_item_safety(&self, span: Span, safety: Safety) {
match self.extern_mod_safety {
Some(extern_safety) => {
if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_))
&& (extern_safety == Safety::Default || !self.features.unsafe_extern_blocks)
{
self.dcx().emit_err(errors::InvalidSafetyOnExtern {
item_span: span,
block: self.current_extern_span().shrink_to_lo(),
});
if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) {
if extern_safety == Safety::Default {
self.dcx().emit_err(errors::InvalidSafetyOnExtern {
item_span: span,
block: Some(self.current_extern_span().shrink_to_lo()),
});
} else if !self.features.unsafe_extern_blocks {
self.dcx().emit_err(errors::InvalidSafetyOnExtern {
item_span: span,
block: None,
});
}
}
}
None => {
@ -1088,7 +1103,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
}
} else if let &Safety::Unsafe(span) = safety {
this.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" });
let mut diag = this
.dcx()
.create_err(errors::UnsafeItem { span, kind: "extern block" });
rustc_session::parse::add_feature_diagnostics(
&mut diag,
self.session,
sym::unsafe_extern_blocks,
);
diag.emit();
}
if abi.is_none() {

View file

@ -222,7 +222,7 @@ pub struct InvalidSafetyOnExtern {
#[primary_span]
pub item_span: Span,
#[suggestion(code = "unsafe ", applicability = "machine-applicable", style = "verbose")]
pub block: Span,
pub block: Option<Span>,
}
#[derive(Diagnostic)]

View file

@ -6,8 +6,8 @@ use rustc_middle::span_bug;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
pub fn dcx(&self) -> DiagCtxtHandle<'tcx> {
impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
pub fn dcx(&self) -> DiagCtxtHandle<'infcx> {
self.infcx.dcx()
}
@ -18,7 +18,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
place: &str,
borrow_place: &str,
value_place: &str,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
self.dcx().create_err(crate::session_diagnostics::MoveBorrow {
place,
span,
@ -34,7 +34,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
desc: &str,
borrow_span: Span,
borrow_desc: &str,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
struct_span_code_err!(
self.dcx(),
span,
@ -54,7 +54,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
old_loan_span: Span,
old_opt_via: &str,
old_load_end_span: Option<Span>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
let mut err = struct_span_code_err!(
self.dcx(),
@ -101,7 +101,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
desc: &str,
old_loan_span: Span,
old_load_end_span: Option<Span>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let mut err = struct_span_code_err!(
self.dcx(),
new_loan_span,
@ -134,7 +134,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
noun_old: &str,
old_opt_via: &str,
previous_end_span: Option<Span>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let mut err = struct_span_code_err!(
self.dcx(),
new_loan_span,
@ -166,7 +166,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
old_opt_via: &str,
previous_end_span: Option<Span>,
second_borrow_desc: &str,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let mut err = struct_span_code_err!(
self.dcx(),
new_loan_span,
@ -198,7 +198,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
kind_old: &str,
msg_old: &str,
old_load_end_span: Option<Span>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
let mut err = struct_span_code_err!(
self.dcx(),
@ -239,7 +239,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
span: Span,
borrow_span: Span,
desc: &str,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
struct_span_code_err!(
self.dcx(),
span,
@ -256,12 +256,12 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
span: Span,
desc: &str,
is_arg: bool,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" };
struct_span_code_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc)
}
pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> Diag<'tcx> {
pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> Diag<'infcx> {
struct_span_code_err!(self.dcx(), span, E0594, "cannot assign to {}", desc)
}
@ -269,7 +269,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
&self,
move_from_span: Span,
move_from_desc: &str,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
struct_span_code_err!(
self.dcx(),
move_from_span,
@ -287,7 +287,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
move_from_span: Span,
ty: Ty<'_>,
is_index: Option<bool>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let type_name = match (&ty.kind(), is_index) {
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
(&ty::Slice(_), _) => "slice",
@ -308,7 +308,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
&self,
move_from_span: Span,
container_ty: Ty<'_>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
struct_span_code_err!(
self.dcx(),
move_from_span,
@ -325,7 +325,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
verb: &str,
optional_adverb_for_moved: &str,
moved_path: Option<String>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
struct_span_code_err!(
@ -344,7 +344,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
span: Span,
path: &str,
reason: &str,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
struct_span_code_err!(
self.dcx(),
span,
@ -362,7 +362,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
immutable_place: &str,
immutable_section: &str,
action: &str,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
struct_span_code_err!(
self.dcx(),
mutate_span,
@ -380,7 +380,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
&self,
span: Span,
yield_span: Span,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind;
struct_span_code_err!(
self.dcx(),
@ -391,7 +391,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
.with_span_label(yield_span, "possible yield occurs here")
}
pub(crate) fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> Diag<'tcx> {
pub(crate) fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> Diag<'infcx> {
struct_span_code_err!(
self.dcx(),
borrow_span,
@ -400,7 +400,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
)
}
pub(crate) fn path_does_not_live_long_enough(&self, span: Span, path: &str) -> Diag<'tcx> {
pub(crate) fn path_does_not_live_long_enough(&self, span: Span, path: &str) -> Diag<'infcx> {
struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,)
}
@ -410,7 +410,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
return_kind: &str,
reference_desc: &str,
path_desc: &str,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
struct_span_code_err!(
self.dcx(),
span,
@ -433,7 +433,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
borrowed_path: &str,
capture_span: Span,
scope: &str,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
struct_span_code_err!(
self.dcx(),
closure_span,
@ -445,7 +445,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
.with_span_label(closure_span, format!("may outlive borrowed value {borrowed_path}"))
}
pub(crate) fn thread_local_value_does_not_live_long_enough(&self, span: Span) -> Diag<'tcx> {
pub(crate) fn thread_local_value_does_not_live_long_enough(&self, span: Span) -> Diag<'infcx> {
struct_span_code_err!(
self.dcx(),
span,
@ -454,7 +454,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> {
)
}
pub(crate) fn temporary_value_borrowed_for_too_long(&self, span: Span) -> Diag<'tcx> {
pub(crate) fn temporary_value_borrowed_for_too_long(&self, span: Span) -> Diag<'infcx> {
struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",)
}
}

View file

@ -15,24 +15,24 @@ use std::fmt;
use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext};
/// The results of the dataflow analyses used by the borrow checker.
pub struct BorrowckResults<'mir, 'tcx> {
pub(crate) borrows: Results<'tcx, Borrows<'mir, 'tcx>>,
pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>,
pub struct BorrowckResults<'a, 'mir, 'tcx> {
pub(crate) borrows: Results<'tcx, Borrows<'a, 'mir, 'tcx>>,
pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'mir, 'tcx>>,
pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'a, 'mir, 'tcx>>,
}
/// The transient state of the dataflow analyses used by the borrow checker.
#[derive(Debug)]
pub struct BorrowckFlowState<'mir, 'tcx> {
pub(crate) borrows: <Borrows<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
pub(crate) uninits: <MaybeUninitializedPlaces<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
pub(crate) ever_inits: <EverInitializedPlaces<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
pub struct BorrowckFlowState<'a, 'mir, 'tcx> {
pub(crate) borrows: <Borrows<'a, 'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
pub(crate) ever_inits: <EverInitializedPlaces<'a, 'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
}
impl<'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'mir, 'tcx> {
impl<'a, 'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'mir, 'tcx> {
// All three analyses are forward, but we have to use just one here.
type Direction = <Borrows<'mir, 'tcx> as AnalysisDomain<'tcx>>::Direction;
type FlowState = BorrowckFlowState<'mir, 'tcx>;
type Direction = <Borrows<'a, 'mir, 'tcx> as AnalysisDomain<'tcx>>::Direction;
type FlowState = BorrowckFlowState<'a, 'mir, 'tcx>;
fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
BorrowckFlowState {
@ -106,11 +106,11 @@ rustc_index::newtype_index! {
/// `BorrowIndex`, and maps each such index to a `BorrowData`
/// describing the borrow. These indexes are used for representing the
/// borrows in compact bitvectors.
pub struct Borrows<'mir, 'tcx> {
pub struct Borrows<'a, 'mir, 'tcx> {
tcx: TyCtxt<'tcx>,
body: &'mir Body<'tcx>,
borrow_set: &'mir BorrowSet<'tcx>,
borrow_set: &'a BorrowSet<'tcx>,
borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
}
@ -389,12 +389,12 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
}
}
impl<'mir, 'tcx> Borrows<'mir, 'tcx> {
impl<'a, 'mir, 'tcx> Borrows<'a, 'mir, 'tcx> {
pub fn new(
tcx: TyCtxt<'tcx>,
body: &'mir Body<'tcx>,
regioncx: &'mir RegionInferenceContext<'tcx>,
borrow_set: &'mir BorrowSet<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
borrow_set: &'a BorrowSet<'tcx>,
) -> Self {
let mut borrows_out_of_scope_at_location =
calculate_borrows_out_of_scope_at_location(body, regioncx, borrow_set);
@ -494,7 +494,7 @@ impl<'mir, 'tcx> Borrows<'mir, 'tcx> {
}
}
impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, '_, 'tcx> {
type Domain = BitSet<BorrowIndex>;
const NAME: &'static str = "borrows";
@ -517,7 +517,7 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
/// region stops containing the CFG points reachable from the issuing location.
/// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of
/// `a.b.c` when `a` is overwritten.
impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, '_, 'tcx> {
type Idx = BorrowIndex;
fn domain_size(&self, _: &mir::Body<'tcx>) -> usize {
@ -617,8 +617,8 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
}
}
impl DebugWithContext<Borrows<'_, '_>> for BorrowIndex {
fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl DebugWithContext<Borrows<'_, '_, '_>> for BorrowIndex {
fn fmt_with(&self, ctxt: &Borrows<'_, '_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", ctxt.location(*self))
}
}

View file

@ -149,13 +149,13 @@ trait TypeOpInfo<'tcx> {
fn base_universe(&self) -> ty::UniverseIndex;
fn nice_error(
fn nice_error<'infcx>(
&self,
mbcx: &mut MirBorrowckCtxt<'_, '_, '_, 'tcx>,
mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>,
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<Diag<'tcx>>;
) -> Option<Diag<'infcx>>;
#[instrument(level = "debug", skip(self, mbcx))]
fn report_error(
@ -231,18 +231,25 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
self.base_universe
}
fn nice_error(
fn nice_error<'infcx>(
&self,
mbcx: &mut MirBorrowckCtxt<'_, '_, '_, 'tcx>,
mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>,
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<Diag<'tcx>> {
) -> Option<Diag<'infcx>> {
let (infcx, key, _) =
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
let ocx = ObligationCtxt::new(&infcx);
type_op_prove_predicate_with_cause(&ocx, key, cause);
try_extract_error_from_fulfill_cx(&ocx, mbcx.mir_def_id(), placeholder_region, error_region)
let diag = try_extract_error_from_fulfill_cx(
&ocx,
mbcx.mir_def_id(),
placeholder_region,
error_region,
)?
.with_dcx(mbcx.dcx());
Some(diag)
}
}
@ -268,13 +275,13 @@ where
self.base_universe
}
fn nice_error(
fn nice_error<'infcx>(
&self,
mbcx: &mut MirBorrowckCtxt<'_, '_, '_, 'tcx>,
mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>,
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<Diag<'tcx>> {
) -> Option<Diag<'infcx>> {
let (infcx, key, _) =
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
let ocx = ObligationCtxt::new(&infcx);
@ -288,7 +295,14 @@ where
let (param_env, value) = key.into_parts();
let _ = ocx.normalize(&cause, param_env, value.value);
try_extract_error_from_fulfill_cx(&ocx, mbcx.mir_def_id(), placeholder_region, error_region)
let diag = try_extract_error_from_fulfill_cx(
&ocx,
mbcx.mir_def_id(),
placeholder_region,
error_region,
)?
.with_dcx(mbcx.dcx());
Some(diag)
}
}
@ -308,18 +322,25 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
self.base_universe
}
fn nice_error(
fn nice_error<'infcx>(
&self,
mbcx: &mut MirBorrowckCtxt<'_, '_, '_, 'tcx>,
mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>,
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<Diag<'tcx>> {
) -> Option<Diag<'infcx>> {
let (infcx, key, _) =
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
let ocx = ObligationCtxt::new(&infcx);
type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?;
try_extract_error_from_fulfill_cx(&ocx, mbcx.mir_def_id(), placeholder_region, error_region)
let diag = try_extract_error_from_fulfill_cx(
&ocx,
mbcx.mir_def_id(),
placeholder_region,
error_region,
)?
.with_dcx(mbcx.dcx());
Some(diag)
}
}
@ -334,13 +355,13 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
self.base_universe.unwrap()
}
fn nice_error(
fn nice_error<'infcx>(
&self,
mbcx: &mut MirBorrowckCtxt<'_, '_, '_, 'tcx>,
mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>,
_cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<Diag<'tcx>> {
) -> Option<Diag<'infcx>> {
try_extract_error_from_region_constraints(
mbcx.infcx,
mbcx.mir_def_id(),
@ -358,12 +379,12 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
}
#[instrument(skip(ocx), level = "debug")]
fn try_extract_error_from_fulfill_cx<'tcx>(
ocx: &ObligationCtxt<'_, 'tcx>,
fn try_extract_error_from_fulfill_cx<'a, 'tcx>(
ocx: &ObligationCtxt<'a, 'tcx>,
generic_param_scope: LocalDefId,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<Diag<'tcx>> {
) -> Option<Diag<'a>> {
// We generally shouldn't have errors here because the query was
// already run, but there's no point using `span_delayed_bug`
// when we're going to emit an error here anyway.
@ -381,15 +402,15 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
}
#[instrument(level = "debug", skip(infcx, region_var_origin, universe_of_region))]
fn try_extract_error_from_region_constraints<'tcx>(
infcx: &InferCtxt<'tcx>,
fn try_extract_error_from_region_constraints<'a, 'tcx>(
infcx: &'a InferCtxt<'tcx>,
generic_param_scope: LocalDefId,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
region_constraints: &RegionConstraintData<'tcx>,
mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
) -> Option<Diag<'tcx>> {
) -> Option<Diag<'a>> {
let placeholder_universe = match placeholder_region.kind() {
ty::RePlaceholder(p) => p.universe,
ty::ReVar(vid) => universe_of_region(vid),

View file

@ -73,7 +73,7 @@ enum StorageDeadOrDrop<'tcx> {
Destructor(Ty<'tcx>),
}
impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
pub(crate) fn report_use_of_moved_or_uninitialized(
&mut self,
location: Location,
@ -341,7 +341,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
fn suggest_ref_or_clone(
&self,
mpi: MovePathIndex,
err: &mut Diag<'tcx>,
err: &mut Diag<'infcx>,
in_pattern: &mut bool,
move_spans: UseSpans<'tcx>,
) {
@ -517,7 +517,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
desired_action: InitializationRequiringAction,
span: Span,
use_spans: UseSpans<'tcx>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
// We need all statements in the body where the binding was assigned to later find all
// the branching code paths where the binding *wasn't* assigned to.
let inits = &self.move_data.init_path_map[mpi];
@ -1288,7 +1288,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
return false;
}
// Try to find predicates on *generic params* that would allow copying `ty`
let suggestion =
let mut suggestion =
if let Some(symbol) = tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
format!(": {symbol}.clone()")
} else {
@ -1296,6 +1296,8 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
};
let mut sugg = Vec::with_capacity(2);
let mut inner_expr = expr;
let mut is_raw_ptr = false;
let typeck_result = self.infcx.tcx.typeck(self.mir_def_id());
// Remove uses of `&` and `*` when suggesting `.clone()`.
while let hir::ExprKind::AddrOf(.., inner) | hir::ExprKind::Unary(hir::UnOp::Deref, inner) =
&inner_expr.kind
@ -1306,14 +1308,32 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
return false;
}
inner_expr = inner;
if let Some(inner_type) = typeck_result.node_type_opt(inner.hir_id) {
if matches!(inner_type.kind(), ty::RawPtr(..)) {
is_raw_ptr = true;
break;
}
}
}
if inner_expr.span.lo() != expr.span.lo() {
// Cloning the raw pointer doesn't make sense in some cases and would cause a type mismatch error. (see #126863)
if inner_expr.span.lo() != expr.span.lo() && !is_raw_ptr {
// Remove "(*" or "(&"
sugg.push((expr.span.with_hi(inner_expr.span.lo()), String::new()));
}
// Check whether `expr` is surrounded by parentheses or not.
let span = if inner_expr.span.hi() != expr.span.hi() {
// Account for `(*x)` to suggest `x.clone()`.
expr.span.with_lo(inner_expr.span.hi())
if is_raw_ptr {
expr.span.shrink_to_hi()
} else {
// Remove the close parenthesis ")"
expr.span.with_lo(inner_expr.span.hi())
}
} else {
if is_raw_ptr {
sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
suggestion = ").clone()".to_string();
}
expr.span.shrink_to_hi()
};
sugg.push((span, suggestion));
@ -1441,7 +1461,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
location: Location,
(place, _span): (Place<'tcx>, Span),
borrow: &BorrowData<'tcx>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let borrow_spans = self.retrieve_borrow_spans(borrow);
let borrow_span = borrow_spans.args_or_use();
@ -1491,7 +1511,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
(place, span): (Place<'tcx>, Span),
gen_borrow_kind: BorrowKind,
issued_borrow: &BorrowData<'tcx>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let issued_spans = self.retrieve_borrow_spans(issued_borrow);
let issued_span = issued_spans.args_or_use();
@ -1782,7 +1802,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
err
}
fn suggest_copy_for_type_in_cloned_ref(&self, err: &mut Diag<'tcx>, place: Place<'tcx>) {
fn suggest_copy_for_type_in_cloned_ref(&self, err: &mut Diag<'infcx>, place: Place<'tcx>) {
let tcx = self.infcx.tcx;
let hir = tcx.hir();
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
@ -2841,7 +2861,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
drop_span: Span,
borrow_spans: UseSpans<'tcx>,
explanation: BorrowExplanation<'tcx>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
debug!(
"report_local_value_does_not_live_long_enough(\
{:?}, {:?}, {:?}, {:?}, {:?}\
@ -3016,7 +3036,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
&self,
drop_span: Span,
borrow_span: Span,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
debug!(
"report_thread_local_value_does_not_live_long_enough(\
{:?}, {:?}\
@ -3041,7 +3061,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
borrow_spans: UseSpans<'tcx>,
proper_span: Span,
explanation: BorrowExplanation<'tcx>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
explanation
{
@ -3206,7 +3226,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
return_span: Span,
category: ConstraintCategory<'tcx>,
opt_place_desc: Option<&String>,
) -> Result<(), Diag<'tcx>> {
) -> Result<(), Diag<'infcx>> {
let return_kind = match category {
ConstraintCategory::Return(_) => "return",
ConstraintCategory::Yield => "yield",
@ -3299,7 +3319,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
constraint_span: Span,
captured_var: &str,
scope: &str,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let tcx = self.infcx.tcx;
let args_span = use_span.args_or_use();
@ -3411,7 +3431,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
upvar_span: Span,
upvar_name: Symbol,
escape_span: Span,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let tcx = self.infcx.tcx;
let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id());

View file

@ -69,7 +69,7 @@ pub(super) struct DescribePlaceOpt {
pub(super) struct IncludingTupleField(pub(super) bool);
impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
/// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
/// is moved after being invoked.
///
@ -86,7 +86,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
&self,
location: Location,
place: PlaceRef<'tcx>,
diag: &mut Diag<'_>,
diag: &mut Diag<'infcx>,
) -> bool {
debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
let mut target = place.local_or_deref_local();

View file

@ -93,7 +93,7 @@ enum GroupedMoveError<'tcx> {
},
}
impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
pub(crate) fn report_move_errors(&mut self) {
let grouped_errors = self.group_move_errors();
for error in grouped_errors {
@ -291,7 +291,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
self.buffer_error(err);
}
fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'tcx> {
fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'infcx> {
let description = if place.projection.len() == 1 {
format!("static item {}", self.describe_any_place(place.as_ref()))
} else {
@ -428,7 +428,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
deref_target_place: Place<'tcx>,
span: Span,
use_spans: Option<UseSpans<'tcx>>,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let tcx = self.infcx.tcx;
// Inspect the type of the content behind the
// borrow to provide feedback about why this
@ -639,12 +639,27 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
fn add_borrow_suggestions(&self, err: &mut Diag<'_>, span: Span) {
match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
Ok(snippet) if snippet.starts_with('*') => {
err.span_suggestion_verbose(
span.with_hi(span.lo() + BytePos(1)),
"consider removing the dereference here",
String::new(),
Applicability::MaybeIncorrect,
);
let sp = span.with_lo(span.lo() + BytePos(1));
let inner = self.find_expr(sp);
let mut is_raw_ptr = false;
if let Some(inner) = inner {
let typck_result = self.infcx.tcx.typeck(self.mir_def_id());
if let Some(inner_type) = typck_result.node_type_opt(inner.hir_id) {
if matches!(inner_type.kind(), ty::RawPtr(..)) {
is_raw_ptr = true;
}
}
}
// If the `inner` is a raw pointer, do not suggest removing the "*", see #126863
// FIXME: need to check whether the assigned object can be a raw pointer, see `tests/ui/borrowck/issue-20801.rs`.
if !is_raw_ptr {
err.span_suggestion_verbose(
span.with_hi(span.lo() + BytePos(1)),
"consider removing the dereference here",
String::new(),
Applicability::MaybeIncorrect,
);
}
}
_ => {
err.span_suggestion_verbose(

View file

@ -30,7 +30,7 @@ pub(crate) enum AccessKind {
Mutate,
}
impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
pub(crate) fn report_mutability_error(
&mut self,
access_place: Place<'tcx>,
@ -541,7 +541,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
}
/// Suggest `map[k] = v` => `map.insert(k, v)` and the like.
fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diag<'tcx>, span: Span) {
fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diag<'infcx>, span: Span) {
let Some(adt) = ty.ty_adt_def() else { return };
let did = adt.did();
if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
@ -550,13 +550,13 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
/// Walks through the HIR, looking for the corresponding span for this error.
/// When it finds it, see if it corresponds to assignment operator whose LHS
/// is an index expr.
struct SuggestIndexOperatorAlternativeVisitor<'a, 'tcx> {
struct SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> {
assign_span: Span,
err: &'a mut Diag<'tcx>,
err: &'a mut Diag<'infcx>,
ty: Ty<'tcx>,
suggested: bool,
}
impl<'a, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'tcx> {
impl<'a, 'cx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'cx, 'tcx> {
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
hir::intravisit::walk_stmt(self, stmt);
let expr = match stmt.kind {

View file

@ -160,7 +160,7 @@ pub struct ErrorConstraintInfo<'tcx> {
pub(super) span: Span,
}
impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
/// Converts a region inference variable into a `ty::Region` that
/// we can use for error reporting. If `r` is universally bound,
/// then we use the name that we have on record for it. If `r` is
@ -360,7 +360,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
let named_key = self.regioncx.name_regions(self.infcx.tcx, key);
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
let diag = unexpected_hidden_region_diagnostic(
self.infcx.tcx,
self.infcx,
self.mir_def_id(),
span,
named_ty,
@ -589,7 +589,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
&self,
errci: &ErrorConstraintInfo<'tcx>,
kind: ReturnConstraint,
) -> Diag<'tcx> {
) -> Diag<'infcx> {
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
@ -658,7 +658,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
/// | ^^^^^^^^^^ `x` escapes the function body here
/// ```
#[instrument(level = "debug", skip(self))]
fn report_escaping_data_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'tcx> {
fn report_escaping_data_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'infcx> {
let ErrorConstraintInfo { span, category, .. } = errci;
let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
@ -767,7 +767,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
/// | is returning data with lifetime `'b`
/// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'tcx> {
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'infcx> {
let ErrorConstraintInfo {
fr,
fr_is_local,

View file

@ -310,8 +310,8 @@ fn do_mir_borrowck<'tcx>(
promoted_mbcx.report_move_errors();
diags = promoted_mbcx.diags;
struct MoveVisitor<'a, 'b, 'mir, 'cx, 'tcx> {
ctxt: &'a mut MirBorrowckCtxt<'b, 'mir, 'cx, 'tcx>,
struct MoveVisitor<'a, 'b, 'mir, 'infcx, 'tcx> {
ctxt: &'a mut MirBorrowckCtxt<'b, 'mir, 'infcx, 'tcx>,
}
impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, '_, '_, 'tcx> {
@ -528,8 +528,8 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
}
}
struct MirBorrowckCtxt<'a, 'mir, 'cx, 'tcx> {
infcx: &'cx BorrowckInferCtxt<'tcx>,
struct MirBorrowckCtxt<'a, 'mir, 'infcx, 'tcx> {
infcx: &'infcx BorrowckInferCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
body: &'mir Body<'tcx>,
move_data: &'a MoveData<'tcx>,
@ -596,7 +596,7 @@ struct MirBorrowckCtxt<'a, 'mir, 'cx, 'tcx> {
/// Results of Polonius analysis.
polonius_output: Option<Rc<PoloniusOutput>>,
diags: diags::BorrowckDiags<'tcx>,
diags: diags::BorrowckDiags<'infcx, 'tcx>,
move_errors: Vec<MoveError<'tcx>>,
}
@ -605,15 +605,15 @@ struct MirBorrowckCtxt<'a, 'mir, 'cx, 'tcx> {
// 2. loans made in overlapping scopes do not conflict
// 3. assignments do not affect things loaned out as immutable
// 4. moves do not affect things loaned out in any way
impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R>
for MirBorrowckCtxt<'_, 'mir, '_, 'tcx>
impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R>
for MirBorrowckCtxt<'a, 'mir, '_, 'tcx>
{
type FlowState = Flows<'mir, 'tcx>;
type FlowState = Flows<'a, 'mir, 'tcx>;
fn visit_statement_before_primary_effect(
&mut self,
_results: &mut R,
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
stmt: &'mir Statement<'tcx>,
location: Location,
) {
@ -683,7 +683,7 @@ impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R>
fn visit_terminator_before_primary_effect(
&mut self,
_results: &mut R,
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
term: &'mir Terminator<'tcx>,
loc: Location,
) {
@ -794,7 +794,7 @@ impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R>
fn visit_terminator_after_primary_effect(
&mut self,
_results: &mut R,
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
term: &'mir Terminator<'tcx>,
loc: Location,
) {
@ -988,7 +988,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
place_span: (Place<'tcx>, Span),
kind: (AccessDepth, ReadOrWrite),
is_local_mutation_allowed: LocalMutationIsAllowed,
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
) {
let (sd, rw) = kind;
@ -1038,7 +1038,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
place_span: (Place<'tcx>, Span),
sd: AccessDepth,
rw: ReadOrWrite,
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
) -> bool {
let mut error_reported = false;
let borrow_set = Rc::clone(&self.borrow_set);
@ -1179,7 +1179,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
location: Location,
place_span: (Place<'tcx>, Span),
kind: AccessDepth,
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
) {
// Write of P[i] or *P requires P init'd.
self.check_if_assigned_path_is_moved(location, place_span, flow_state);
@ -1197,7 +1197,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
&mut self,
location: Location,
(rvalue, span): (&'mir Rvalue<'tcx>, Span),
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
) {
match rvalue {
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
@ -1455,7 +1455,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
&mut self,
location: Location,
(operand, span): (&'mir Operand<'tcx>, Span),
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
) {
match *operand {
Operand::Copy(place) => {
@ -1579,7 +1579,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
&mut self,
location: Location,
span: Span,
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
) {
// Two-phase borrow support: For each activation that is newly
// generated at this statement, check if it interferes with
@ -1743,7 +1743,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
location: Location,
desired_action: InitializationRequiringAction,
place_span: (PlaceRef<'tcx>, Span),
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
) {
let maybe_uninits = &flow_state.uninits;
@ -1848,7 +1848,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
location: Location,
desired_action: InitializationRequiringAction,
place_span: (PlaceRef<'tcx>, Span),
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
) {
let maybe_uninits = &flow_state.uninits;
@ -1947,7 +1947,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
&mut self,
location: Location,
(place, span): (Place<'tcx>, Span),
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
) {
debug!("check_if_assigned_path_is_moved place: {:?}", place);
@ -2013,7 +2013,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
location: Location,
base: PlaceRef<'tcx>,
span: Span,
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
) {
// rust-lang/rust#21232: Until Rust allows reads from the
// initialized parts of partially initialized structs, we
@ -2104,7 +2104,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
(place, span): (Place<'tcx>, Span),
kind: ReadOrWrite,
is_local_mutation_allowed: LocalMutationIsAllowed,
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
location: Location,
) -> bool {
debug!(
@ -2220,7 +2220,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
fn is_local_ever_initialized(
&self,
local: Local,
flow_state: &Flows<'mir, 'tcx>,
flow_state: &Flows<'_, 'mir, 'tcx>,
) -> Option<InitIndex> {
let mpi = self.move_data.rev_lookup.find_local(local)?;
let ii = &self.move_data.init_path_map[mpi];
@ -2228,7 +2228,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
}
/// Adds the place into the used mutable variables set
fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, flow_state: &Flows<'mir, 'tcx>) {
fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, flow_state: &Flows<'_, 'mir, 'tcx>) {
match root_place {
RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
// If the local may have been initialized, and it is now currently being
@ -2428,12 +2428,12 @@ mod diags {
use super::*;
enum BufferedDiag<'tcx> {
Error(Diag<'tcx>),
NonError(Diag<'tcx, ()>),
enum BufferedDiag<'infcx> {
Error(Diag<'infcx>),
NonError(Diag<'infcx, ()>),
}
impl<'tcx> BufferedDiag<'tcx> {
impl<'infcx> BufferedDiag<'infcx> {
fn sort_span(&self) -> Span {
match self {
BufferedDiag::Error(diag) => diag.sort_span,
@ -2442,7 +2442,7 @@ mod diags {
}
}
pub struct BorrowckDiags<'tcx> {
pub struct BorrowckDiags<'infcx, 'tcx> {
/// This field keeps track of move errors that are to be reported for given move indices.
///
/// There are situations where many errors can be reported for a single move out (see
@ -2457,15 +2457,15 @@ mod diags {
/// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
/// when errors in the map are being re-added to the error buffer so that errors with the
/// same primary span come out in a consistent order.
buffered_move_errors: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, Diag<'tcx>)>,
buffered_move_errors: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, Diag<'infcx>)>,
buffered_mut_errors: FxIndexMap<Span, (Diag<'tcx>, usize)>,
buffered_mut_errors: FxIndexMap<Span, (Diag<'infcx>, usize)>,
/// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics.
buffered_diags: Vec<BufferedDiag<'tcx>>,
buffered_diags: Vec<BufferedDiag<'infcx>>,
}
impl<'tcx> BorrowckDiags<'tcx> {
impl<'infcx, 'tcx> BorrowckDiags<'infcx, 'tcx> {
pub fn new() -> Self {
BorrowckDiags {
buffered_move_errors: BTreeMap::new(),
@ -2474,28 +2474,28 @@ mod diags {
}
}
pub fn buffer_error(&mut self, diag: Diag<'tcx>) {
pub fn buffer_error(&mut self, diag: Diag<'infcx>) {
self.buffered_diags.push(BufferedDiag::Error(diag));
}
pub fn buffer_non_error(&mut self, diag: Diag<'tcx, ()>) {
pub fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
self.buffered_diags.push(BufferedDiag::NonError(diag));
}
}
impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
pub fn buffer_error(&mut self, diag: Diag<'tcx>) {
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
pub fn buffer_error(&mut self, diag: Diag<'infcx>) {
self.diags.buffer_error(diag);
}
pub fn buffer_non_error(&mut self, diag: Diag<'tcx, ()>) {
pub fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
self.diags.buffer_non_error(diag);
}
pub fn buffer_move_error(
&mut self,
move_out_indices: Vec<MoveOutIndex>,
place_and_err: (PlaceRef<'tcx>, Diag<'tcx>),
place_and_err: (PlaceRef<'tcx>, Diag<'infcx>),
) -> bool {
if let Some((_, diag)) =
self.diags.buffered_move_errors.insert(move_out_indices, place_and_err)
@ -2508,12 +2508,12 @@ mod diags {
}
}
pub fn get_buffered_mut_error(&mut self, span: Span) -> Option<(Diag<'tcx>, usize)> {
pub fn get_buffered_mut_error(&mut self, span: Span) -> Option<(Diag<'infcx>, usize)> {
// FIXME(#120456) - is `swap_remove` correct?
self.diags.buffered_mut_errors.swap_remove(&span)
}
pub fn buffer_mut_error(&mut self, span: Span, diag: Diag<'tcx>, count: usize) {
pub fn buffer_mut_error(&mut self, span: Span, diag: Diag<'infcx>, count: usize) {
self.diags.buffered_mut_errors.insert(span, (diag, count));
}
@ -2554,7 +2554,7 @@ mod diags {
pub fn has_move_error(
&self,
move_out_indices: &[MoveOutIndex],
) -> Option<&(PlaceRef<'tcx>, Diag<'tcx>)> {
) -> Option<&(PlaceRef<'tcx>, Diag<'infcx>)> {
self.diags.buffered_move_errors.get(move_out_indices)
}
}

View file

@ -81,7 +81,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
promoted: &IndexSlice<Promoted, Body<'tcx>>,
location_table: &LocationTable,
param_env: ty::ParamEnv<'tcx>,
flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>,
flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'_, 'cx, 'tcx>>,
move_data: &MoveData<'tcx>,
borrow_set: &BorrowSet<'tcx>,
upvars: &[&ty::CapturedPlace<'tcx>],
@ -262,13 +262,13 @@ pub(super) fn dump_mir_results<'tcx>(
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
pub(super) fn dump_annotation<'tcx>(
infcx: &BorrowckInferCtxt<'tcx>,
pub(super) fn dump_annotation<'tcx, 'cx>(
infcx: &'cx BorrowckInferCtxt<'tcx>,
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
opaque_type_values: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
diags: &mut crate::diags::BorrowckDiags<'tcx>,
diags: &mut crate::diags::BorrowckDiags<'cx, 'tcx>,
) {
let tcx = infcx.tcx;
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
@ -285,7 +285,7 @@ pub(super) fn dump_annotation<'tcx>(
let def_span = tcx.def_span(body.source.def_id());
let mut err = if let Some(closure_region_requirements) = closure_region_requirements {
let mut err = tcx.dcx().struct_span_note(def_span, "external requirements");
let mut err = infcx.dcx().struct_span_note(def_span, "external requirements");
regioncx.annotate(tcx, &mut err);
@ -304,7 +304,7 @@ pub(super) fn dump_annotation<'tcx>(
err
} else {
let mut err = tcx.dcx().struct_span_note(def_span, "no external requirements");
let mut err = infcx.dcx().struct_span_note(def_span, "no external requirements");
regioncx.annotate(tcx, &mut err);
err

View file

@ -285,7 +285,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
if let Err(guar) =
check_opaque_type_parameter_valid(self.tcx, opaque_type_key, instantiated_ty.span)
check_opaque_type_parameter_valid(self, opaque_type_key, instantiated_ty.span)
{
return Ty::new_error(self.tcx, guar);
}
@ -294,6 +294,10 @@ impl<'tcx> InferCtxt<'tcx> {
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
.ty;
if let Err(e) = definition_ty.error_reported() {
return Ty::new_error(self.tcx, e);
}
// `definition_ty` does not live in of the current inference context,
// so lets make sure that we don't accidentally misuse our current `infcx`.
match check_opaque_type_well_formed(
@ -387,10 +391,11 @@ fn check_opaque_type_well_formed<'tcx>(
/// [rustc-dev-guide chapter]:
/// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html
fn check_opaque_type_parameter_valid<'tcx>(
tcx: TyCtxt<'tcx>,
infcx: &InferCtxt<'tcx>,
opaque_type_key: OpaqueTypeKey<'tcx>,
span: Span,
) -> Result<(), ErrorGuaranteed> {
let tcx = infcx.tcx;
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id);
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
@ -420,7 +425,7 @@ fn check_opaque_type_parameter_valid<'tcx>(
opaque_env.param_is_error(i)?;
return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam {
return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam {
ty: arg,
kind,
span,
@ -438,7 +443,7 @@ fn check_opaque_type_parameter_valid<'tcx>(
.collect();
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
return Err(tcx
return Err(infcx
.dcx()
.struct_span_err(span, "non-defining opaque type use in defining scope")
.with_span_note(spans, format!("{descr} used multiple times"))

View file

@ -34,7 +34,7 @@ pub(super) fn generate<'mir, 'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>,
body: &Body<'tcx>,
elements: &Rc<DenseLocationMap>,
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'_, 'mir, 'tcx>>,
move_data: &MoveData<'tcx>,
) {
debug!("liveness::generate");

View file

@ -43,7 +43,7 @@ pub(super) fn trace<'mir, 'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>,
body: &Body<'tcx>,
elements: &Rc<DenseLocationMap>,
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'_, 'mir, 'tcx>>,
move_data: &MoveData<'tcx>,
relevant_live_locals: Vec<Local>,
boring_locals: Vec<Local>,
@ -101,7 +101,7 @@ pub(super) fn trace<'mir, 'tcx>(
}
/// Contextual state for the type-liveness coroutine.
struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
struct LivenessContext<'a, 'me, 'typeck, 'flow, 'tcx> {
/// Current type-checker, giving us our inference context etc.
typeck: &'me mut TypeChecker<'typeck, 'tcx>,
@ -119,7 +119,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
/// Results of dataflow tracking which variables (and paths) have been
/// initialized.
flow_inits: &'me mut ResultsCursor<'flow, 'tcx, MaybeInitializedPlaces<'flow, 'tcx>>,
flow_inits: &'me mut ResultsCursor<'flow, 'tcx, MaybeInitializedPlaces<'a, 'flow, 'tcx>>,
/// Index indicating where each variable is assigned, used, or
/// dropped.
@ -131,8 +131,8 @@ struct DropData<'tcx> {
region_constraint_data: Option<&'tcx QueryRegionConstraints<'tcx>>,
}
struct LivenessResults<'me, 'typeck, 'flow, 'tcx> {
cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>,
struct LivenessResults<'a, 'me, 'typeck, 'flow, 'tcx> {
cx: LivenessContext<'a, 'me, 'typeck, 'flow, 'tcx>,
/// Set of points that define the current local.
defs: BitSet<PointIndex>,
@ -153,8 +153,8 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> {
stack: Vec<PointIndex>,
}
impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
fn new(cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>) -> Self {
impl<'a, 'me, 'typeck, 'flow, 'tcx> LivenessResults<'a, 'me, 'typeck, 'flow, 'tcx> {
fn new(cx: LivenessContext<'a, 'me, 'typeck, 'flow, 'tcx>) -> Self {
let num_points = cx.elements.num_points();
LivenessResults {
cx,
@ -507,7 +507,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
}
}
impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
impl<'tcx> LivenessContext<'_, '_, '_, '_, 'tcx> {
/// Returns `true` if the local variable (or some part of it) is initialized at the current
/// cursor position. Callers should call one of the `seek` methods immediately before to point
/// the cursor to the desired location.

View file

@ -129,7 +129,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
location_table: &LocationTable,
borrow_set: &BorrowSet<'tcx>,
all_facts: &mut Option<AllFacts>,
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'_, 'mir, 'tcx>>,
move_data: &MoveData<'tcx>,
elements: &Rc<DenseLocationMap>,
upvars: &[&ty::CapturedPlace<'tcx>],

View file

@ -45,10 +45,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
/// MIR visitor for collecting used mutable variables.
/// The 'visit lifetime represents the duration of the MIR walk.
struct GatherUsedMutsVisitor<'visit, 'a, 'mir, 'cx, 'tcx> {
struct GatherUsedMutsVisitor<'visit, 'a, 'mir, 'infcx, 'tcx> {
temporary_used_locals: FxIndexSet<Local>,
never_initialized_mut_locals: &'visit mut FxIndexSet<Local>,
mbcx: &'visit mut MirBorrowckCtxt<'a, 'mir, 'cx, 'tcx>,
mbcx: &'visit mut MirBorrowckCtxt<'a, 'mir, 'infcx, 'tcx>,
}
impl GatherUsedMutsVisitor<'_, '_, '_, '_, '_> {

View file

@ -55,10 +55,6 @@ jobs:
if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin'
run: rustup set default-host x86_64-apple-darwin
- name: Select XCode version
if: matrix.os == 'macos-latest'
run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
- name: Prepare dependencies
run: ./y.sh prepare

View file

@ -66,6 +66,9 @@ jobs:
env:
TARGET_TRIPLE: aarch64-unknown-linux-gnu
apt_deps: gcc-aarch64-linux-gnu qemu-user
- os: macos-latest
env:
TARGET_TRIPLE: aarch64-apple-darwin
- os: ubuntu-latest
env:
TARGET_TRIPLE: s390x-unknown-linux-gnu
@ -108,10 +111,6 @@ jobs:
sudo apt-get update
sudo apt-get install -y ${{ matrix.apt_deps }}
- name: Select XCode version
if: matrix.os == 'macos-latest'
run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
- name: Prepare dependencies
run: ./y.sh prepare
@ -214,6 +213,9 @@ jobs:
- os: macos-latest
env:
TARGET_TRIPLE: x86_64-apple-darwin
- os: macos-latest
env:
TARGET_TRIPLE: aarch64-apple-darwin
# cross-compile from Linux to Windows using mingw
- os: ubuntu-latest
env:
@ -248,10 +250,6 @@ jobs:
sudo apt-get update
sudo apt-get install -y gcc-mingw-w64-x86-64
- name: Select XCode version
if: matrix.os == 'macos-latest'
run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
- name: Prepare dependencies
run: ./y.sh prepare
@ -282,7 +280,8 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
if: ${{ github.ref == 'refs/heads/master' }}
needs: [rustfmt, test, bench, dist]
# FIXME add the bench job back to the dependency list once rust-lang/rust#125493 gets merged
needs: [rustfmt, test, dist]
permissions:
contents: write # for creating the dev tag and release

View file

@ -46,18 +46,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cranelift-bforest"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79b27922a6879b5b5361d0a084cb0b1941bf109a98540addcb932da13b68bed4"
checksum = "0b6b33d7e757a887989eb18b35712b2a67d96171ec3149d1bfb657b29b7b367c"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "304c455b28bf56372729acb356afbb55d622f2b0f2f7837aa5e57c138acaac4d"
checksum = "b9acf15cb22be42d07c3b57d7856329cb228b7315d385346149df2566ad5e4aa"
dependencies = [
"bumpalo",
"cranelift-bforest",
@ -70,45 +70,46 @@ dependencies = [
"hashbrown 0.14.3",
"log",
"regalloc2",
"rustc-hash",
"smallvec",
"target-lexicon",
]
[[package]]
name = "cranelift-codegen-meta"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1653c56b99591d07f67c5ca7f9f25888948af3f4b97186bff838d687d666f613"
checksum = "e934d301392b73b3f8b0540391fb82465a0f179a3cee7c726482ac4727efcc97"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5b6a9cf6b6eb820ee3f973a0db313c05dc12d370f37b4fe9630286e1672573f"
checksum = "8afb2a2566b3d54b854dfb288b3b187f6d3d17d6f762c92898207eba302931da"
[[package]]
name = "cranelift-control"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9d06e6bf30075fb6bed9e034ec046475093392eea1aff90eb5c44c4a033d19a"
checksum = "0100f33b704cdacd01ad66ff41f8c5030d57cbff078e2a4e49ab1822591299fa"
dependencies = [
"arbitrary",
]
[[package]]
name = "cranelift-entity"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29be04f931b73cdb9694874a295027471817f26f26d2f0ebe5454153176b6e3a"
checksum = "a8cfdc315e5d18997093e040a8d234bea1ac1e118a716d3e30f40d449e78207b"
[[package]]
name = "cranelift-frontend"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a07fd7393041d7faa2f37426f5dc7fc04003b70988810e8c063beefeff1cd8f9"
checksum = "0f74b84f16af2e982b0c0c72233503d9d55cbfe3865dbe807ca28dc6642a28b5"
dependencies = [
"cranelift-codegen",
"log",
@ -118,15 +119,15 @@ dependencies = [
[[package]]
name = "cranelift-isle"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f341d7938caa6dff8149dac05bb2b53fc680323826b83b4cf175ab9f5139a3c9"
checksum = "adf306d3dde705fb94bd48082f01d38c4ededc74293a4c007805f610bf08bc6e"
[[package]]
name = "cranelift-jit"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42733555e06433f1461570e09dbd756dafc228b4dac75c597cdbdc518de07522"
checksum = "f5c5cfb8bbd3339cd25cca30e7516ff8fe5cb1feeddde6980cc4d5ef34df97bb"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -144,9 +145,9 @@ dependencies = [
[[package]]
name = "cranelift-module"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84950af02bb85f3da764d53a953b43bb29a732e793d4fe24637a61591be9a024"
checksum = "7c9b0d4269b36fd858e6d8f20cd4938941186fb831488c361888cb2d6b33a9a6"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -155,9 +156,9 @@ dependencies = [
[[package]]
name = "cranelift-native"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82af6066e6448d26eeabb7aa26a43f7ff79f8217b06bade4ee6ef230aecc8880"
checksum = "1ea0ebdef7aff4a79bcbc8b6495f31315f16b3bf311152f472eaa8d679352581"
dependencies = [
"cranelift-codegen",
"libc",
@ -166,9 +167,9 @@ dependencies = [
[[package]]
name = "cranelift-object"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00af56107039ed150391df6f753298c7b08f2b6a2e0727d216b5fa599d684d8b"
checksum = "19e33439ec20db058bc7cc3410f9748ab1ad90a35cef713d625c736f43e3820d"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -278,9 +279,9 @@ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "object"
version = "0.33.0"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8dd6c0cdf9429bce006e1362bfce61fa1bfd8c898a643ed8d2b471934701d3d"
checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
dependencies = [
"crc32fast",
"hashbrown 0.14.3",
@ -410,10 +411,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasmtime-jit-icache-coherence"
version = "20.0.0"
version = "22.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a9f93a3289057b26dc75eb84d6e60d7694f7d169c7c09597495de6e016a13ff"
checksum = "5afe2f0499542f9a4bcfa1b55bfdda803b6ade4e7c93c6b99e0f39dba44b0a91"
dependencies = [
"anyhow",
"cfg-if",
"libc",
"windows-sys",

View file

@ -8,15 +8,15 @@ crate-type = ["dylib"]
[dependencies]
# These have to be in sync with each other
cranelift-codegen = { version = "0.107.0", default-features = false, features = ["std", "unwind", "all-arch"] }
cranelift-frontend = { version = "0.107.0" }
cranelift-module = { version = "0.107.0" }
cranelift-native = { version = "0.107.0" }
cranelift-jit = { version = "0.107.0", optional = true }
cranelift-object = { version = "0.107.0" }
cranelift-codegen = { version = "0.109.0", default-features = false, features = ["std", "unwind", "all-arch"] }
cranelift-frontend = { version = "0.109.0" }
cranelift-module = { version = "0.109.0" }
cranelift-native = { version = "0.109.0" }
cranelift-jit = { version = "0.109.0", optional = true }
cranelift-object = { version = "0.109.0" }
target-lexicon = "0.12.0"
gimli = { version = "0.28", default-features = false, features = ["write"]}
object = { version = "0.33", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
indexmap = "2.0.0"
libloading = { version = "0.8.0", optional = true }

View file

@ -70,7 +70,7 @@ For more docs on how to build and test see [build_system/usage.txt](build_system
|FreeBSD|✅[^no-rustup]|❓|❓|❓|
|AIX|❌[^xcoff]|N/A|N/A|❌[^xcoff]|
|Other unixes|❓|❓|❓|❓|
|macOS|✅|❌[^apple-silicon]|N/A|N/A|
|macOS|✅|✅[^no-rustup]|N/A|N/A|
|Windows|✅[^no-rustup]|❌|N/A|N/A|
✅: Fully supported and tested
@ -80,7 +80,6 @@ For more docs on how to build and test see [build_system/usage.txt](build_system
Not all targets are available as rustup component for nightly. See notes in the platform support matrix.
[^xcoff]: XCOFF object file format is not supported.
[^apple-silicon]: Tracked in [#1248](https://github.com/rust-lang/rustc_codegen_cranelift/issues/1248).
[^no-rustup]: Not available as rustup component for nightly. You can build it yourself.
## Usage

View file

@ -267,10 +267,6 @@ fn build_clif_sysroot_for_triple(
prefix.to_str().unwrap()
));
}
rustflags.push("-Zunstable-options".to_owned());
for (name, values) in EXTRA_CHECK_CFGS {
rustflags.push(check_cfg_arg(name, *values));
}
compiler.rustflags.extend(rustflags);
let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
if channel == "release" {
@ -330,34 +326,3 @@ fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> {
Some(target_libs)
}
// Copied from https://github.com/rust-lang/rust/blob/4fd98a4b1b100f5329c6efae18031791f64372d2/src/bootstrap/src/utils/helpers.rs#L569-L585
/// Create a `--check-cfg` argument invocation for a given name
/// and it's values.
fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String {
// Creating a string of the values by concatenating each value:
// ',values("tvos","watchos")' or '' (nothing) when there are no values.
let next = match values {
Some(values) => {
let mut tmp = values.iter().flat_map(|val| [",", "\"", val, "\""]).collect::<String>();
tmp.insert_str(1, "values(");
tmp.push(')');
tmp
}
None => "".to_string(),
};
format!("--check-cfg=cfg({name}{next})")
}
const EXTRA_CHECK_CFGS: &[(&str, Option<&[&str]>)] = &[
("bootstrap", None),
("stdarch_intel_sde", None),
("no_fp_fmt_parse", None),
("no_global_oom_handling", None),
("no_rc", None),
("no_sync", None),
("netbsd10", None),
("backtrace_in_libstd", None),
("target_arch", Some(&["xtensa"])),
];

View file

@ -329,7 +329,6 @@ pub(crate) fn run_tests(
struct TestRunner<'a> {
is_native: bool,
jit_supported: bool,
use_unstable_features: bool,
skip_tests: &'a [&'a str],
dirs: Dirs,
target_compiler: Compiler,
@ -361,15 +360,7 @@ impl<'a> TestRunner<'a> {
&& target_compiler.triple.contains("x86_64")
&& !target_compiler.triple.contains("windows");
Self {
is_native,
jit_supported,
use_unstable_features,
skip_tests,
dirs,
target_compiler,
stdlib_source,
}
Self { is_native, jit_supported, skip_tests, dirs, target_compiler, stdlib_source }
}
fn run_testsuite(&self, tests: &[TestCase]) {
@ -393,31 +384,13 @@ impl<'a> TestRunner<'a> {
match *cmd {
TestCaseCmd::Custom { func } => func(self),
TestCaseCmd::BuildLib { source, crate_types } => {
if self.use_unstable_features {
self.run_rustc([source, "--crate-type", crate_types]);
} else {
self.run_rustc([
source,
"--crate-type",
crate_types,
"--cfg",
"no_unstable_features",
]);
}
self.run_rustc([source, "--crate-type", crate_types]);
}
TestCaseCmd::BuildBin { source } => {
if self.use_unstable_features {
self.run_rustc([source]);
} else {
self.run_rustc([source, "--cfg", "no_unstable_features"]);
}
self.run_rustc([source]);
}
TestCaseCmd::BuildBinAndRun { source, args } => {
if self.use_unstable_features {
self.run_rustc([source]);
} else {
self.run_rustc([source, "--cfg", "no_unstable_features"]);
}
self.run_rustc([source]);
self.run_out_command(
source.split('/').last().unwrap().split('.').next().unwrap(),
args,
@ -472,7 +445,6 @@ impl<'a> TestRunner<'a> {
cmd.arg(&self.target_compiler.triple);
cmd.arg("-Cpanic=abort");
cmd.arg("-Zunstable-options");
cmd.arg("--check-cfg=cfg(no_unstable_features)");
cmd.arg("--check-cfg=cfg(jit)");
cmd.args(args);
cmd

View file

@ -333,12 +333,7 @@ fn main() {
#[cfg(all(not(jit), not(all(windows, target_env = "gnu"))))]
test_tls();
#[cfg(all(
not(jit),
not(no_unstable_features),
target_arch = "x86_64",
any(target_os = "linux", target_os = "macos")
))]
#[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "macos")))]
unsafe {
global_asm_test();
naked_test();
@ -367,17 +362,12 @@ fn stack_val_align() {
assert_eq!(&a as *const Foo as usize % 8192, 0);
}
#[cfg(all(
not(jit),
not(no_unstable_features),
target_arch = "x86_64",
any(target_os = "linux", target_os = "macos")
))]
#[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "macos")))]
extern "C" {
fn global_asm_test();
}
#[cfg(all(not(jit), not(no_unstable_features), target_arch = "x86_64", target_os = "linux"))]
#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
global_asm! {
"
.global global_asm_test
@ -387,7 +377,7 @@ global_asm! {
"
}
#[cfg(all(not(jit), not(no_unstable_features), target_arch = "x86_64", target_os = "macos"))]
#[cfg(all(not(jit), target_arch = "x86_64", target_os = "macos"))]
global_asm! {
"
.global _global_asm_test
@ -397,7 +387,7 @@ global_asm! {
"
}
#[cfg(all(not(jit), not(no_unstable_features), target_arch = "x86_64"))]
#[cfg(all(not(jit), target_arch = "x86_64"))]
#[naked]
extern "C" fn naked_test() {
unsafe {

View file

@ -251,6 +251,9 @@ unsafe fn test_simd() {
test_mm_add_epi8();
test_mm_add_pd();
test_mm_cvtepi8_epi16();
#[cfg(not(jit))]
test_mm_cvtps_epi32();
test_mm_cvttps_epi32();
test_mm_cvtsi128_si64();
test_mm_extract_epi8();
@ -476,6 +479,41 @@ unsafe fn test_mm256_permutevar8x32_epi32() {
assert_eq_m256i(r, e);
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2")]
#[cfg(not(jit))]
unsafe fn test_mm_cvtps_epi32() {
let floats: [f32; 4] = [1.5, -2.5, i32::MAX as f32 + 1.0, f32::NAN];
let float_vec = _mm_loadu_ps(floats.as_ptr());
let int_vec = _mm_cvtps_epi32(float_vec);
let mut ints: [i32; 4] = [0; 4];
_mm_storeu_si128(ints.as_mut_ptr() as *mut __m128i, int_vec);
// this is very different from `floats.map(|f| f as i32)`!
let expected_ints: [i32; 4] = [2, -2, i32::MIN, i32::MIN];
assert_eq!(ints, expected_ints);
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2")]
unsafe fn test_mm_cvttps_epi32() {
let floats: [f32; 4] = [1.5, -2.5, i32::MAX as f32 + 1.0, f32::NAN];
let float_vec = _mm_loadu_ps(floats.as_ptr());
let int_vec = _mm_cvttps_epi32(float_vec);
let mut ints: [i32; 4] = [0; 4];
_mm_storeu_si128(ints.as_mut_ptr() as *mut __m128i, int_vec);
// this is very different from `floats.map(|f| f as i32)`!
let expected_ints: [i32; 4] = [1, -2, i32::MIN, i32::MIN];
assert_eq!(ints, expected_ints);
}
fn test_checked_mul() {
let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
assert_eq!(u, None);

View file

@ -4,12 +4,12 @@ version = 3
[[package]]
name = "addr2line"
version = "0.21.0"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
dependencies = [
"compiler_builtins",
"gimli",
"gimli 0.29.0",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
@ -133,6 +133,17 @@ dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "gimli"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
@ -147,9 +158,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.3.9"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
@ -189,9 +200,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.32.1"
version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434"
dependencies = [
"compiler_builtins",
"memchr",
@ -286,9 +297,9 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.23"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
@ -396,8 +407,6 @@ dependencies = [
"core",
"getopts",
"libc",
"panic_abort",
"panic_unwind",
"std",
]
@ -430,7 +439,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b"
dependencies = [
"compiler_builtins",
"gimli",
"gimli 0.28.1",
"rustc-std-workspace-core",
]

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2024-05-13"
channel = "nightly-2024-06-30"
components = ["rust-src", "rustc-dev", "llvm-tools"]

View file

@ -36,9 +36,8 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR
rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic
# exotic linkages
rm tests/ui/issues/issue-33992.rs # unsupported linkages
rm tests/incremental/hashes/function_interfaces.rs # same
rm tests/incremental/hashes/statics.rs # same
rm tests/incremental/hashes/function_interfaces.rs
rm tests/incremental/hashes/statics.rs
# variadic arguments
rm tests/ui/abi/mir/mir_codegen_calls_variadic.rs # requires float varargs
@ -60,13 +59,20 @@ rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported
# requires LTO
rm -r tests/run-make/cdylib
rm -r tests/run-make/issue-14500
rm -r tests/run-make/issue-64153
rm -r tests/run-make/codegen-options-parsing
rm -r tests/run-make/lto-*
rm -r tests/run-make/reproducible-build-2
rm -r tests/run-make/issue-109934-lto-debuginfo
rm -r tests/run-make/no-builtins-lto
rm -r tests/run-make/reachable-extern-fn-available-lto
# coverage instrumentation
rm tests/ui/consts/precise-drop-with-coverage.rs
rm tests/ui/issues/issue-85461.rs
rm -r tests/ui/instrument-coverage/
# missing f16/f128 support
rm tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs
# optimization tests
# ==================
@ -74,6 +80,7 @@ rm tests/ui/codegen/issue-28950.rs # depends on stack size optimizations
rm tests/ui/codegen/init-large-type.rs # same
rm tests/ui/issues/issue-40883.rs # same
rm -r tests/run-make/fmt-write-bloat/ # tests an optimization
rm tests/ui/statics/const_generics.rs # same
# backend specific tests
# ======================
@ -85,6 +92,7 @@ rm -r tests/run-make/sepcomp-cci-copies # same
rm -r tests/run-make/volatile-intrinsics # same
rm -r tests/run-make/llvm-ident # same
rm -r tests/run-make/no-builtins-attribute # same
rm -r tests/run-make/pgo-gen-no-imp-symbols # same
rm tests/ui/abi/stack-protector.rs # requires stack protector support
rm -r tests/run-make/emit-stack-sizes # requires support for -Z emit-stack-sizes
rm -r tests/run-make/optimization-remarks-dir # remarks are LLVM specific
@ -93,13 +101,14 @@ rm -r tests/run-make/print-to-output # requires --print relocation-models
# requires asm, llvm-ir and/or llvm-bc emit support
# =============================================
rm -r tests/run-make/emit-named-files
rm -r tests/run-make/issue-30063
rm -r tests/run-make/multiple-emits
rm -r tests/run-make/output-type-permutations
rm -r tests/run-make/emit-to-stdout
rm -r tests/run-make/compressed-debuginfo
rm -r tests/run-make/symbols-include-type-name
rm -r tests/run-make/notify-all-emit-artifacts
rm -r tests/run-make/reset-codegen-1
rm -r tests/run-make/inline-always-many-cgu
# giving different but possibly correct results
# =============================================
@ -118,6 +127,7 @@ rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contain
# ============
rm -r tests/run-make/extern-fn-explicit-align # argument alignment not yet supported
rm -r tests/run-make/panic-abort-eh_frame # .eh_frame emitted with panic=abort
rm tests/ui/deprecation/deprecated_inline_threshold.rs # missing deprecation warning for -Cinline-threshold
# bugs in the test suite
# ======================
@ -148,12 +158,12 @@ index 9607ff02f96..b7d97caf9a2 100644
--- a/src/tools/run-make-support/src/rustdoc.rs
+++ b/src/tools/run-make-support/src/rustdoc.rs
@@ -34,8 +34,6 @@ pub fn bare() -> Self {
/// Construct a \`rustdoc\` invocation with \`-L \$(TARGET_RPATH_DIR)\` set.
#[track_caller]
pub fn new() -> Self {
let mut cmd = setup_common();
- let target_rpath_dir = env::var_os("TARGET_RPATH_DIR").unwrap();
- let target_rpath_dir = env_var_os("TARGET_RPATH_DIR");
- cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy()));
Self { cmd, stdin: None }
Self { cmd }
}
EOF

View file

@ -5,8 +5,9 @@ mod pass_mode;
mod returning;
use std::borrow::Cow;
use std::mem;
use cranelift_codegen::ir::SigRef;
use cranelift_codegen::ir::{ArgumentPurpose, SigRef};
use cranelift_codegen::isa::CallConv;
use cranelift_module::ModuleError;
use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
@ -17,7 +18,7 @@ use rustc_middle::ty::TypeVisitableExt;
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_target::abi::call::{Conv, FnAbi};
use rustc_target::abi::call::{Conv, FnAbi, PassMode};
use rustc_target::spec::abi::Abi;
use self::pass_mode::*;
@ -487,6 +488,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
let args = args;
assert_eq!(fn_abi.args.len(), args.len());
#[derive(Copy, Clone)]
enum CallTarget {
Direct(FuncRef),
Indirect(SigRef, Value),
@ -532,7 +534,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
};
self::returning::codegen_with_call_return_arg(fx, &fn_abi.ret, ret_place, |fx, return_ptr| {
let call_args = return_ptr
let mut call_args = return_ptr
.into_iter()
.chain(first_arg_override.into_iter())
.chain(
@ -545,40 +547,17 @@ pub(crate) fn codegen_terminator_call<'tcx>(
)
.collect::<Vec<Value>>();
let call_inst = match func_ref {
// FIXME: Find a cleaner way to support varargs.
if fn_abi.c_variadic {
adjust_call_for_c_variadic(fx, &fn_abi, source_info, func_ref, &mut call_args);
}
match func_ref {
CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args),
CallTarget::Indirect(sig, func_ptr) => {
fx.bcx.ins().call_indirect(sig, func_ptr, &call_args)
}
};
// FIXME find a cleaner way to support varargs
if fn_sig.c_variadic() {
if !matches!(fn_sig.abi(), Abi::C { .. }) {
fx.tcx.dcx().span_fatal(
source_info.span,
format!("Variadic call for non-C abi {:?}", fn_sig.abi()),
);
}
let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
let abi_params = call_args
.into_iter()
.map(|arg| {
let ty = fx.bcx.func.dfg.value_type(arg);
if !ty.is_int() {
// FIXME set %al to upperbound on float args once floats are supported
fx.tcx.dcx().span_fatal(
source_info.span,
format!("Non int ty {:?} for variadic call", ty),
);
}
AbiParam::new(ty)
})
.collect::<Vec<AbiParam>>();
fx.bcx.func.dfg.signatures[sig_ref].params = abi_params;
}
call_inst
});
if let Some(dest) = target {
@ -587,6 +566,100 @@ pub(crate) fn codegen_terminator_call<'tcx>(
} else {
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
}
fn adjust_call_for_c_variadic<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
source_info: mir::SourceInfo,
target: CallTarget,
call_args: &mut Vec<Value>,
) {
if fn_abi.conv != Conv::C {
fx.tcx.dcx().span_fatal(
source_info.span,
format!("Variadic call for non-C abi {:?}", fn_abi.conv),
);
}
let sig_ref = match target {
CallTarget::Direct(func_ref) => fx.bcx.func.dfg.ext_funcs[func_ref].signature,
CallTarget::Indirect(sig_ref, _) => sig_ref,
};
// `mem::take()` the `params` so that `fx.bcx` can be used below.
let mut abi_params = mem::take(&mut fx.bcx.func.dfg.signatures[sig_ref].params);
// Recalculate the parameters in the signature to ensure the signature contains the variadic arguments.
let has_return_arg = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
// Drop everything except the return argument (if there is one).
abi_params.truncate(if has_return_arg { 1 } else { 0 });
// Add the fixed arguments.
abi_params.extend(
fn_abi.args[..fn_abi.fixed_count as usize]
.iter()
.flat_map(|arg_abi| arg_abi.get_abi_param(fx.tcx).into_iter()),
);
let fixed_arg_count = abi_params.len();
// Add the variadic arguments.
abi_params.extend(
fn_abi.args[fn_abi.fixed_count as usize..]
.iter()
.flat_map(|arg_abi| arg_abi.get_abi_param(fx.tcx).into_iter()),
);
if fx.tcx.sess.target.is_like_osx && fx.tcx.sess.target.arch == "aarch64" {
// Add any padding arguments needed for Apple AArch64.
// There's no need to pad the argument list unless variadic arguments are actually being
// passed.
if abi_params.len() > fixed_arg_count {
// 128-bit integers take 2 registers, and everything else takes 1.
// FIXME: Add support for non-integer types
// This relies on the checks below to ensure all arguments are integer types and
// that the ABI is "C".
// The return argument isn't counted as it goes in its own dedicated register.
let integer_registers_used: usize = abi_params
[if has_return_arg { 1 } else { 0 }..fixed_arg_count]
.iter()
.map(|arg| if arg.value_type.bits() == 128 { 2 } else { 1 })
.sum();
// The ABI uses 8 registers before it starts pushing arguments to the stack. Pad out
// the registers if needed to ensure the variadic arguments are passed on the stack.
if integer_registers_used < 8 {
abi_params.splice(
fixed_arg_count..fixed_arg_count,
(integer_registers_used..8).map(|_| AbiParam::new(types::I64)),
);
call_args.splice(
fixed_arg_count..fixed_arg_count,
(integer_registers_used..8).map(|_| fx.bcx.ins().iconst(types::I64, 0)),
);
}
}
// `StructArgument` is not currently used by the `aarch64` ABI, and is therefore not
// handled when calculating how many padding arguments to use. Assert that this remains
// the case.
assert!(abi_params.iter().all(|param| matches!(
param.purpose,
// The only purposes used are `Normal` and `StructReturn`.
ArgumentPurpose::Normal | ArgumentPurpose::StructReturn
)));
}
// Check all parameters are integers.
for param in abi_params.iter() {
if !param.value_type.is_int() {
// FIXME: Set %al to upperbound on float args once floats are supported.
fx.tcx.dcx().span_fatal(
source_info.span,
format!("Non int ty {:?} for variadic call", param.value_type),
);
}
}
assert_eq!(abi_params.len(), call_args.len());
// Put the `AbiParam`s back in the signature.
fx.bcx.func.dfg.signatures[sig_ref].params = abi_params;
}
}
pub(crate) fn codegen_drop<'tcx>(

View file

@ -11,15 +11,10 @@ use rustc_session::config::OomStrategy;
use crate::prelude::*;
/// Returns whether an allocator shim was created
pub(crate) fn codegen(
tcx: TyCtxt<'_>,
module: &mut impl Module,
unwind_context: &mut UnwindContext,
) -> bool {
pub(crate) fn codegen(tcx: TyCtxt<'_>, module: &mut dyn Module) -> bool {
let Some(kind) = allocator_kind_for_codegen(tcx) else { return false };
codegen_inner(
module,
unwind_context,
kind,
tcx.alloc_error_handler_kind(()).unwrap(),
tcx.sess.opts.unstable_opts.oom,
@ -28,8 +23,7 @@ pub(crate) fn codegen(
}
fn codegen_inner(
module: &mut impl Module,
unwind_context: &mut UnwindContext,
module: &mut dyn Module,
kind: AllocatorKind,
alloc_error_handler_kind: AllocatorKind,
oom_strategy: OomStrategy,
@ -67,7 +61,6 @@ fn codegen_inner(
};
crate::common::create_wrapper_function(
module,
unwind_context,
sig,
&global_fn_name(method.name),
&default_fn_name(method.name),
@ -82,7 +75,6 @@ fn codegen_inner(
};
crate::common::create_wrapper_function(
module,
unwind_context,
sig,
"__rust_alloc_error_handler",
&alloc_error_handler_name(alloc_error_handler_kind),

View file

@ -249,9 +249,7 @@ pub(crate) fn compile_fn(
}
// Define debuginfo for function
let isa = module.isa();
let debug_context = &mut cx.debug_context;
let unwind_context = &mut cx.unwind_context;
cx.profiler.generic_activity("generate debug info").run(|| {
if let Some(debug_context) = debug_context {
codegened_func.func_debug_cx.unwrap().finalize(
@ -260,7 +258,6 @@ pub(crate) fn compile_fn(
context,
);
}
unwind_context.add_function(codegened_func.func_id, &context, isa);
});
}
@ -909,7 +906,7 @@ fn codegen_stmt<'tcx>(
| StatementKind::PlaceMention(..)
| StatementKind::AscribeUserType(..) => {}
StatementKind::Coverage { .. } => fx.tcx.dcx().fatal("-Zcoverage is unimplemented"),
StatementKind::Coverage { .. } => unreachable!(),
StatementKind::Intrinsic(ref intrinsic) => match &**intrinsic {
// We ignore `assume` intrinsics, they are only useful for optimizations
NonDivergingIntrinsic::Assume(_) => {}

View file

@ -247,7 +247,6 @@ pub(crate) fn type_sign(ty: Ty<'_>) -> bool {
pub(crate) fn create_wrapper_function(
module: &mut dyn Module,
unwind_context: &mut UnwindContext,
sig: Signature,
wrapper_name: &str,
callee_name: &str,
@ -280,7 +279,6 @@ pub(crate) fn create_wrapper_function(
bcx.finalize();
}
module.define_function(wrapper_func_id, &mut ctx).unwrap();
unwind_context.add_function(wrapper_func_id, &ctx, module.isa());
}
pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
@ -395,6 +393,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
// FIXME Don't force the size to a multiple of <abi_align> bytes once Cranelift gets
// a way to specify stack slot alignment.
size: (size + abi_align - 1) / abi_align * abi_align,
align_shift: 4,
});
Pointer::stack_slot(stack_slot)
} else {
@ -405,6 +404,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
// FIXME Don't force the size to a multiple of <abi_align> bytes once Cranelift gets
// a way to specify stack slot alignment.
size: (size + align) / abi_align * abi_align,
align_shift: 4,
});
let base_ptr = self.bcx.ins().stack_addr(self.pointer_type, stack_slot, 0);
let misalign_offset = self.bcx.ins().urem_imm(base_ptr, i64::from(align));

View file

@ -26,6 +26,7 @@ use rustc_session::Session;
use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken};
use crate::debuginfo::TypeDebugContext;
use crate::global_asm::GlobalAsmConfig;
use crate::unwind_module::UnwindModule;
use crate::{prelude::*, BackendConfig};
struct ModuleCodegenResult {
@ -318,7 +319,11 @@ fn produce_final_output_artifacts(
// These are used in linking steps and will be cleaned up afterward.
}
fn make_module(sess: &Session, backend_config: &BackendConfig, name: String) -> ObjectModule {
fn make_module(
sess: &Session,
backend_config: &BackendConfig,
name: String,
) -> UnwindModule<ObjectModule> {
let isa = crate::build_isa(sess, backend_config);
let mut builder =
@ -327,16 +332,15 @@ fn make_module(sess: &Session, backend_config: &BackendConfig, name: String) ->
// is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
// can easily double the amount of time necessary to perform linking.
builder.per_function_section(sess.opts.unstable_opts.function_sections.unwrap_or(false));
ObjectModule::new(builder)
UnwindModule::new(ObjectModule::new(builder), true)
}
fn emit_cgu(
output_filenames: &OutputFilenames,
prof: &SelfProfilerRef,
name: String,
module: ObjectModule,
module: UnwindModule<ObjectModule>,
debug: Option<DebugContext>,
unwind_context: UnwindContext,
global_asm_object_file: Option<PathBuf>,
producer: &str,
) -> Result<ModuleCodegenResult, String> {
@ -346,8 +350,6 @@ fn emit_cgu(
debug.emit(&mut product);
}
unwind_context.emit(&mut product);
let module_regular = emit_module(
output_filenames,
prof,
@ -494,7 +496,6 @@ fn module_codegen(
let mut cx = crate::CodegenCx::new(
tcx,
backend_config.clone(),
module.isa(),
tcx.sess.opts.debuginfo != DebugInfo::None,
cgu_name,
@ -531,13 +532,7 @@ fn module_codegen(
}
}
}
crate::main_shim::maybe_create_entry_wrapper(
tcx,
&mut module,
&mut cx.unwind_context,
false,
cgu.is_primary(),
);
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, false, cgu.is_primary());
let cgu_name = cgu.name().as_str().to_owned();
@ -571,7 +566,6 @@ fn module_codegen(
cgu_name,
module,
cx.debug_context,
cx.unwind_context,
global_asm_object_file,
&producer,
)
@ -665,13 +659,10 @@ pub(crate) fn run_aot(
});
let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string());
let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true);
let created_alloc_shim =
crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);
let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module);
let allocator_module = if created_alloc_shim {
let mut product = allocator_module.finish();
allocator_unwind_context.emit(&mut product);
let product = allocator_module.finish();
match emit_module(
tcx.output_filenames(()),

View file

@ -14,12 +14,12 @@ use rustc_session::Session;
use rustc_span::Symbol;
use crate::debuginfo::TypeDebugContext;
use crate::unwind_module::UnwindModule;
use crate::{prelude::*, BackendConfig};
use crate::{CodegenCx, CodegenMode};
struct JitState {
backend_config: BackendConfig,
jit_module: JITModule,
jit_module: UnwindModule<JITModule>,
}
thread_local! {
@ -63,7 +63,7 @@ fn create_jit_module(
tcx: TyCtxt<'_>,
backend_config: &BackendConfig,
hotswap: bool,
) -> (JITModule, CodegenCx) {
) -> (UnwindModule<JITModule>, CodegenCx) {
let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string());
let isa = crate::build_isa(tcx.sess, backend_config);
@ -72,17 +72,11 @@ fn create_jit_module(
crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info));
jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8);
let mut jit_module = JITModule::new(jit_builder);
let mut jit_module = UnwindModule::new(JITModule::new(jit_builder), false);
let mut cx = crate::CodegenCx::new(
tcx,
backend_config.clone(),
jit_module.isa(),
false,
Symbol::intern("dummy_cgu_name"),
);
let cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, Symbol::intern("dummy_cgu_name"));
crate::allocator::codegen(tcx, &mut jit_module, &mut cx.unwind_context);
crate::allocator::codegen(tcx, &mut jit_module);
(jit_module, cx)
}
@ -128,7 +122,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
);
}
CodegenMode::JitLazy => {
codegen_shim(tcx, &mut cx, &mut cached_context, &mut jit_module, inst)
codegen_shim(tcx, &mut cached_context, &mut jit_module, inst)
}
},
MonoItem::Static(def_id) => {
@ -146,18 +140,11 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
tcx.dcx().fatal("Inline asm is not supported in JIT mode");
}
crate::main_shim::maybe_create_entry_wrapper(
tcx,
&mut jit_module,
&mut cx.unwind_context,
true,
true,
);
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, true, true);
tcx.dcx().abort_if_errors();
jit_module.finalize_definitions().unwrap();
unsafe { cx.unwind_context.register_jit(&jit_module) };
jit_module.finalize_definitions();
println!(
"Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed"
@ -177,12 +164,12 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
call_conv: jit_module.target_config().default_call_conv,
};
let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap();
let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id);
let finalized_start: *const u8 = jit_module.module.get_finalized_function(start_func_id);
LAZY_JIT_STATE.with(|lazy_jit_state| {
let mut lazy_jit_state = lazy_jit_state.borrow_mut();
assert!(lazy_jit_state.is_none());
*lazy_jit_state = Some(JitState { backend_config, jit_module });
*lazy_jit_state = Some(JitState { jit_module });
});
let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
@ -268,7 +255,6 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
let mut lazy_jit_state = lazy_jit_state.borrow_mut();
let lazy_jit_state = lazy_jit_state.as_mut().unwrap();
let jit_module = &mut lazy_jit_state.jit_module;
let backend_config = lazy_jit_state.backend_config.clone();
let name = tcx.symbol_name(instance).name;
let sig = crate::abi::get_function_sig(
@ -278,7 +264,7 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
);
let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap();
let current_ptr = jit_module.read_got_entry(func_id);
let current_ptr = jit_module.module.read_got_entry(func_id);
// If the function's GOT entry has already been updated to point at something other
// than the shim trampoline, don't re-jit but just return the new pointer instead.
@ -288,11 +274,10 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
return current_ptr;
}
jit_module.prepare_for_function_redefine(func_id).unwrap();
jit_module.module.prepare_for_function_redefine(func_id).unwrap();
let mut cx = crate::CodegenCx::new(
tcx,
backend_config,
jit_module.isa(),
false,
Symbol::intern("dummy_cgu_name"),
@ -300,9 +285,8 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
codegen_and_compile_fn(tcx, &mut cx, &mut Context::new(), jit_module, instance);
assert!(cx.global_asm.is_empty());
jit_module.finalize_definitions().unwrap();
unsafe { cx.unwind_context.register_jit(&jit_module) };
jit_module.get_finalized_function(func_id)
jit_module.finalize_definitions();
jit_module.module.get_finalized_function(func_id)
})
})
}
@ -310,7 +294,7 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
fn dep_symbol_lookup_fn(
sess: &Session,
crate_info: CrateInfo,
) -> Box<dyn Fn(&str) -> Option<*const u8>> {
) -> Box<dyn Fn(&str) -> Option<*const u8> + Send> {
use rustc_middle::middle::dependency_format::Linkage;
let mut dylib_paths = Vec::new();
@ -362,9 +346,8 @@ fn dep_symbol_lookup_fn(
fn codegen_shim<'tcx>(
tcx: TyCtxt<'tcx>,
cx: &mut CodegenCx,
cached_context: &mut Context,
module: &mut JITModule,
module: &mut UnwindModule<JITModule>,
inst: Instance<'tcx>,
) {
let pointer_type = module.target_config().pointer_type();
@ -413,5 +396,4 @@ fn codegen_shim<'tcx>(
trampoline_builder.ins().return_(&ret_vals);
module.define_function(func_id, context).unwrap();
cx.unwind_context.add_function(func_id, context, module.isa());
}

View file

@ -113,13 +113,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
);
let sig =
get_function_sig(fx.tcx, fx.target_config.default_call_conv, instance);
create_wrapper_function(
fx.module,
&mut fx.cx.unwind_context,
sig,
&wrapper_name,
symbol.name,
);
create_wrapper_function(fx.module, sig, &wrapper_name, symbol.name);
CInlineAsmOperand::Symbol { symbol: wrapper_name }
} else {
@ -283,13 +277,7 @@ pub(crate) fn codegen_naked_asm<'tcx>(
);
let sig =
get_function_sig(tcx, module.target_config().default_call_conv, instance);
create_wrapper_function(
module,
&mut cx.unwind_context,
sig,
&wrapper_name,
symbol.name,
);
create_wrapper_function(module, sig, &wrapper_name, symbol.name);
CInlineAsmOperand::Symbol { symbol: wrapper_name }
} else {

View file

@ -459,11 +459,20 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
intrinsic_args!(fx, args => (a); intrinsic);
let a = a.load_scalar(fx);
let value = fx.bcx.ins().x86_cvtt2dq(types::I32X4, a);
let cvalue = CValue::by_val(value, ret.layout());
ret.write_cvalue(fx, cvalue);
}
"llvm.x86.sse2.cvtps2dq" => {
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtps_epi32
intrinsic_args!(fx, args => (a); intrinsic);
let a = a.load_scalar(fx);
// Using inline asm instead of fcvt_to_sint_sat as unrepresentable values are turned
// into 0x80000000 for which Cranelift doesn't have a native instruction.
codegen_inline_asm_inner(
fx,
&[InlineAsmTemplatePiece::String(format!("cvttps2dq xmm0, xmm0"))],
&[InlineAsmTemplatePiece::String(format!("cvtps2dq xmm0, xmm0"))],
&[CInlineAsmOperand::InOut {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
_late: true,
@ -1416,6 +1425,36 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
ret.write_cvalue(fx, res);
}
"llvm.x86.rdtsc" => {
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_rdtsc&ig_expand=5273
let res_place = CPlace::new_stack_slot(
fx,
fx.layout_of(Ty::new_tup(fx.tcx, &[fx.tcx.types.u32, fx.tcx.types.u32])),
);
let eax_place = res_place.place_field(fx, FieldIdx::new(0));
let edx_place = res_place.place_field(fx, FieldIdx::new(1));
codegen_inline_asm_inner(
fx,
&[InlineAsmTemplatePiece::String("rdtsc".to_string())],
&[
CInlineAsmOperand::Out {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
late: true,
place: Some(eax_place),
},
CInlineAsmOperand::Out {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
late: true,
place: Some(edx_place),
},
],
InlineAsmOptions::NOSTACK | InlineAsmOptions::NOMEM,
);
let res = res_place.to_cvalue(fx);
ret.write_cvalue_transmute(fx, res);
}
_ => {
fx.tcx
.dcx()

View file

@ -79,6 +79,7 @@ mod pretty_clif;
mod toolchain;
mod trap;
mod unsize;
mod unwind_module;
mod value_and_place;
mod vtable;
@ -130,22 +131,13 @@ struct CodegenCx {
global_asm: String,
inline_asm_index: Cell<usize>,
debug_context: Option<DebugContext>,
unwind_context: UnwindContext,
cgu_name: Symbol,
}
impl CodegenCx {
fn new(
tcx: TyCtxt<'_>,
backend_config: BackendConfig,
isa: &dyn TargetIsa,
debug_info: bool,
cgu_name: Symbol,
) -> Self {
fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, debug_info: bool, cgu_name: Symbol) -> Self {
assert_eq!(pointer_ty(tcx), isa.pointer_type());
let unwind_context =
UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
let debug_context = if debug_info && !tcx.sess.target.options.is_like_windows {
Some(DebugContext::new(tcx, isa, cgu_name.as_str()))
} else {
@ -158,7 +150,6 @@ impl CodegenCx {
global_asm: String::new(),
inline_asm_index: Cell::new(0),
debug_context,
unwind_context,
cgu_name,
}
}
@ -175,7 +166,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
}
fn init(&self, sess: &Session) {
use rustc_session::config::Lto;
use rustc_session::config::{InstrumentCoverage, Lto};
match sess.lto() {
Lto::No | Lto::ThinLocal => {}
Lto::Thin | Lto::Fat => {
@ -183,6 +174,11 @@ impl CodegenBackend for CraneliftCodegenBackend {
}
}
if sess.opts.cg.instrument_coverage() != InstrumentCoverage::No {
sess.dcx()
.fatal("`-Cinstrument-coverage` is LLVM specific and not supported by Cranelift");
}
let mut config = self.config.borrow_mut();
if config.is_none() {
let new_config = BackendConfig::from_opts(&sess.opts.cg.llvm_args)

View file

@ -11,8 +11,7 @@ use crate::prelude::*;
/// users main function.
pub(crate) fn maybe_create_entry_wrapper(
tcx: TyCtxt<'_>,
module: &mut impl Module,
unwind_context: &mut UnwindContext,
module: &mut dyn Module,
is_jit: bool,
is_primary_cgu: bool,
) {
@ -36,12 +35,11 @@ pub(crate) fn maybe_create_entry_wrapper(
return;
}
create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn, sigpipe);
create_entry_fn(tcx, module, main_def_id, is_jit, is_main_fn, sigpipe);
fn create_entry_fn(
tcx: TyCtxt<'_>,
m: &mut impl Module,
unwind_context: &mut UnwindContext,
m: &mut dyn Module,
rust_main_def_id: DefId,
ignore_lang_start_wrapper: bool,
is_main_fn: bool,
@ -170,7 +168,5 @@ pub(crate) fn maybe_create_entry_wrapper(
if let Err(err) = m.define_function(cmain_func_id, &mut ctx) {
tcx.dcx().fatal(format!("entry symbol `{entry_name}` defined multiple times: {err}"));
}
unwind_context.add_function(cmain_func_id, &ctx, m.isa());
}
}

View file

@ -0,0 +1,115 @@
use cranelift_codegen::control::ControlPlane;
use cranelift_codegen::ir::{Function, Signature};
use cranelift_codegen::isa::{TargetFrontendConfig, TargetIsa};
use cranelift_codegen::{Context, FinalizedMachReloc};
use cranelift_module::{
DataDescription, DataId, FuncId, FuncOrDataId, Linkage, Module, ModuleDeclarations,
ModuleResult,
};
use cranelift_object::{ObjectModule, ObjectProduct};
use crate::UnwindContext;
/// A wrapper around a [Module] which adds any defined function to the [UnwindContext].
pub(crate) struct UnwindModule<T> {
pub(crate) module: T,
unwind_context: UnwindContext,
}
impl<T: Module> UnwindModule<T> {
pub(crate) fn new(module: T, pic_eh_frame: bool) -> Self {
let unwind_context = UnwindContext::new(module.isa(), pic_eh_frame);
UnwindModule { module, unwind_context }
}
}
impl UnwindModule<ObjectModule> {
pub(crate) fn finish(self) -> ObjectProduct {
let mut product = self.module.finish();
self.unwind_context.emit(&mut product);
product
}
}
#[cfg(feature = "jit")]
impl UnwindModule<cranelift_jit::JITModule> {
pub(crate) fn finalize_definitions(&mut self) {
self.module.finalize_definitions().unwrap();
let prev_unwind_context = std::mem::replace(
&mut self.unwind_context,
UnwindContext::new(self.module.isa(), false),
);
unsafe { prev_unwind_context.register_jit(&self.module) };
}
}
impl<T: Module> Module for UnwindModule<T> {
fn isa(&self) -> &dyn TargetIsa {
self.module.isa()
}
fn declarations(&self) -> &ModuleDeclarations {
self.module.declarations()
}
fn get_name(&self, name: &str) -> Option<FuncOrDataId> {
self.module.get_name(name)
}
fn target_config(&self) -> TargetFrontendConfig {
self.module.target_config()
}
fn declare_function(
&mut self,
name: &str,
linkage: Linkage,
signature: &Signature,
) -> ModuleResult<FuncId> {
self.module.declare_function(name, linkage, signature)
}
fn declare_anonymous_function(&mut self, signature: &Signature) -> ModuleResult<FuncId> {
self.module.declare_anonymous_function(signature)
}
fn declare_data(
&mut self,
name: &str,
linkage: Linkage,
writable: bool,
tls: bool,
) -> ModuleResult<DataId> {
self.module.declare_data(name, linkage, writable, tls)
}
fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
self.module.declare_anonymous_data(writable, tls)
}
fn define_function_with_control_plane(
&mut self,
func: FuncId,
ctx: &mut Context,
ctrl_plane: &mut ControlPlane,
) -> ModuleResult<()> {
self.module.define_function_with_control_plane(func, ctx, ctrl_plane)?;
self.unwind_context.add_function(func, ctx, self.module.isa());
Ok(())
}
fn define_function_bytes(
&mut self,
_func_id: FuncId,
_func: &Function,
_alignment: u64,
_bytes: &[u8],
_relocs: &[FinalizedMachReloc],
) -> ModuleResult<()> {
unimplemented!()
}
fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()> {
self.module.define_data(data_id, data)
}
}

View file

@ -28,6 +28,19 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
global
// TODO(antoyo): set linkage.
}
pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> {
if value.get_type() == self.bool_type.make_pointer() {
if let Some(pointee) = typ.get_pointee() {
if pointee.dyncast_vector().is_some() {
panic!()
}
}
}
// NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some
// SIMD builtins require a constant value.
self.bitcast_if_needed(value, typ)
}
}
pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> {
@ -239,19 +252,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
const_alloc_to_gcc(self, alloc)
}
fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> {
if value.get_type() == self.bool_type.make_pointer() {
if let Some(pointee) = typ.get_pointee() {
if pointee.dyncast_vector().is_some() {
panic!()
}
}
}
// NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some
// SIMD builtins require a constant value.
self.bitcast_if_needed(value, typ)
}
fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {
self.context
.new_array_access(None, base_addr, self.const_usize(offset.bytes()))

View file

@ -27,7 +27,6 @@ use crate::callee::get_fn;
use crate::common::SignType;
pub struct CodegenCx<'gcc, 'tcx> {
pub check_overflow: bool,
pub codegen_unit: &'tcx CodegenUnit<'tcx>,
pub context: &'gcc Context<'gcc>,
@ -134,8 +133,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
tcx: TyCtxt<'tcx>,
supports_128bit_integers: bool,
) -> Self {
let check_overflow = tcx.sess.overflow_checks();
let create_type = |ctype, rust_type| {
let layout = tcx.layout_of(ParamEnv::reveal_all().and(rust_type)).unwrap();
let align = layout.align.abi.bytes();
@ -271,7 +268,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
}
let mut cx = Self {
check_overflow,
codegen_unit,
context,
current_func: RefCell::new(None),
@ -511,10 +507,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
&self.tcx.sess
}
fn check_overflow(&self) -> bool {
self.check_overflow
}
fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> {
self.codegen_unit
}

View file

@ -89,13 +89,34 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
ty::FloatTy::F128 => self.type_f128(),
}
}
}
impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
fn type_i1(&self) -> Type<'gcc> {
pub fn type_i1(&self) -> Type<'gcc> {
self.bool_type
}
pub fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> {
let types = fields.to_vec();
if let Some(typ) = self.struct_types.borrow().get(fields) {
return *typ;
}
let fields: Vec<_> = fields
.iter()
.enumerate()
.map(|(index, field)| {
self.context.new_field(None, *field, format!("field{}_TODO", index))
})
.collect();
let typ = self.context.new_struct_type(None, "struct", &fields).as_type();
if packed {
#[cfg(feature = "master")]
typ.set_packed();
}
self.struct_types.borrow_mut().insert(types, typ);
typ
}
}
impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
fn type_i8(&self) -> Type<'gcc> {
self.i8_type
}
@ -131,7 +152,7 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
fn type_f64(&self) -> Type<'gcc> {
self.double_type
}
fn type_f128(&self) -> Type<'gcc> {
unimplemented!("f16_f128")
}
@ -140,27 +161,6 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
self.context.new_function_pointer_type(None, return_type, params, false)
}
fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> {
let types = fields.to_vec();
if let Some(typ) = self.struct_types.borrow().get(fields) {
return *typ;
}
let fields: Vec<_> = fields
.iter()
.enumerate()
.map(|(index, field)| {
self.context.new_field(None, *field, format!("field{}_TODO", index))
})
.collect();
let typ = self.context.new_struct_type(None, "struct", &fields).as_type();
if packed {
#[cfg(feature = "master")]
typ.set_packed();
}
self.struct_types.borrow_mut().insert(types, typ);
typ
}
fn type_kind(&self, typ: Type<'gcc>) -> TypeKind {
if self.is_int_type_or_bool(typ) {
TypeKind::Integer

View file

@ -329,10 +329,6 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
const_alloc_to_llvm(self, alloc, /*static*/ false)
}
fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
self.const_bitcast(val, ty)
}
fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {
unsafe {
llvm::LLVMConstInBoundsGEP2(

View file

@ -3,6 +3,7 @@ use crate::back::write::to_llvm_code_model;
use crate::callee::get_fn;
use crate::coverageinfo;
use crate::debuginfo;
use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
use crate::llvm;
use crate::llvm_util;
use crate::type_::Type;
@ -43,7 +44,6 @@ use std::str;
/// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`.
pub struct CodegenCx<'ll, 'tcx> {
pub tcx: TyCtxt<'tcx>,
pub check_overflow: bool,
pub use_dll_storage_attrs: bool,
pub tls_model: llvm::ThreadLocalMode,
@ -441,8 +441,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
// start) and then strongly recommending static linkage on Windows!
let use_dll_storage_attrs = tcx.sess.target.is_like_windows;
let check_overflow = tcx.sess.overflow_checks();
let tls_model = to_llvm_tls_model(tcx.sess.tls_model());
let (llcx, llmod) = (&*llvm_module.llcx, llvm_module.llmod());
@ -466,7 +464,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
CodegenCx {
tcx,
check_overflow,
use_dll_storage_attrs,
tls_model,
llmod,
@ -522,6 +519,15 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
&self.vtables
}
fn apply_vcall_visibility_metadata(
&self,
ty: Ty<'tcx>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
vtable: &'ll Value,
) {
apply_vcall_visibility_metadata(self, ty, poly_trait_ref, vtable);
}
fn get_fn(&self, instance: Instance<'tcx>) -> &'ll Value {
get_fn(self, instance)
}
@ -596,10 +602,6 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
self.tcx.sess
}
fn check_overflow(&self) -> bool {
self.check_overflow
}
fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> {
self.codegen_unit
}

View file

@ -1449,12 +1449,18 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
.di_node
}
fn vcall_visibility_metadata<'ll, 'tcx>(
pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
ty: Ty<'tcx>,
trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
vtable: &'ll Value,
) {
// FIXME(flip1995): The virtual function elimination optimization only works with full LTO in
// LLVM at the moment.
if !cx.sess().opts.unstable_opts.virtual_function_elimination || cx.sess().lto() != Lto::Fat {
return;
}
enum VCallVisibility {
Public = 0,
LinkageUnit = 1,
@ -1531,12 +1537,6 @@ pub fn create_vtable_di_node<'ll, 'tcx>(
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
vtable: &'ll Value,
) {
// FIXME(flip1995): The virtual function elimination optimization only works with full LTO in
// LLVM at the moment.
if cx.sess().opts.unstable_opts.virtual_function_elimination && cx.sess().lto() == Lto::Fat {
vcall_visibility_metadata(cx, ty, poly_trait_ref, vtable);
}
if cx.dbg_cx.is_none() {
return;
}

View file

@ -274,10 +274,11 @@ impl CodegenBackend for LlvmCodegenBackend {
|tcx, ()| llvm_util::global_llvm_features(tcx.sess, true)
}
fn print(&self, req: &PrintRequest, out: &mut dyn PrintBackendInfo, sess: &Session) {
fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) {
use std::fmt::Write;
match req.kind {
PrintKind::RelocationModels => {
writeln!(out, "Available relocation models:");
writeln!(out, "Available relocation models:").unwrap();
for name in &[
"static",
"pic",
@ -288,25 +289,25 @@ impl CodegenBackend for LlvmCodegenBackend {
"ropi-rwpi",
"default",
] {
writeln!(out, " {name}");
writeln!(out, " {name}").unwrap();
}
writeln!(out);
writeln!(out).unwrap();
}
PrintKind::CodeModels => {
writeln!(out, "Available code models:");
writeln!(out, "Available code models:").unwrap();
for name in &["tiny", "small", "kernel", "medium", "large"] {
writeln!(out, " {name}");
writeln!(out, " {name}").unwrap();
}
writeln!(out);
writeln!(out).unwrap();
}
PrintKind::TlsModels => {
writeln!(out, "Available TLS models:");
writeln!(out, "Available TLS models:").unwrap();
for name in
&["global-dynamic", "local-dynamic", "initial-exec", "local-exec", "emulated"]
{
writeln!(out, " {name}");
writeln!(out, " {name}").unwrap();
}
writeln!(out);
writeln!(out).unwrap();
}
PrintKind::StackProtectorStrategies => {
writeln!(
@ -332,7 +333,8 @@ impl CodegenBackend for LlvmCodegenBackend {
none
Do not generate stack canaries.
"#
);
)
.unwrap();
}
_other => llvm_util::print(req, out, sess),
}

View file

@ -6,7 +6,6 @@ use crate::errors::{
use crate::llvm;
use libc::c_int;
use rustc_codegen_ssa::base::wants_wasm_eh;
use rustc_codegen_ssa::traits::PrintBackendInfo;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_fs_util::path_to_c_string;
@ -18,6 +17,7 @@ use rustc_target::spec::{MergeFunctions, PanicStrategy};
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
use std::ffi::{c_char, c_void, CStr, CString};
use std::fmt::Write;
use std::path::Path;
use std::ptr;
use std::slice;
@ -372,7 +372,7 @@ fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> {
ret
}
fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &llvm::TargetMachine) {
fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMachine) {
let mut llvm_target_features = llvm_target_features(tm);
let mut known_llvm_target_features = FxHashSet::<&'static str>::default();
let mut rustc_target_features = sess
@ -412,24 +412,26 @@ fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &ll
.max()
.unwrap_or(0);
writeln!(out, "Features supported by rustc for this target:");
writeln!(out, "Features supported by rustc for this target:").unwrap();
for (feature, desc) in &rustc_target_features {
writeln!(out, " {feature:max_feature_len$} - {desc}.");
writeln!(out, " {feature:max_feature_len$} - {desc}.").unwrap();
}
writeln!(out, "\nCode-generation features supported by LLVM for this target:");
writeln!(out, "\nCode-generation features supported by LLVM for this target:").unwrap();
for (feature, desc) in &llvm_target_features {
writeln!(out, " {feature:max_feature_len$} - {desc}.");
writeln!(out, " {feature:max_feature_len$} - {desc}.").unwrap();
}
if llvm_target_features.is_empty() {
writeln!(out, " Target features listing is not supported by this LLVM version.");
writeln!(out, " Target features listing is not supported by this LLVM version.")
.unwrap();
}
writeln!(out, "\nUse +feature to enable a feature, or -feature to disable it.");
writeln!(out, "For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n");
writeln!(out, "Code-generation features cannot be used in cfg or #[target_feature],");
writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n");
writeln!(out, "\nUse +feature to enable a feature, or -feature to disable it.").unwrap();
writeln!(out, "For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n")
.unwrap();
writeln!(out, "Code-generation features cannot be used in cfg or #[target_feature],").unwrap();
writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n").unwrap();
}
pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess: &Session) {
pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) {
require_inited();
let tm = create_informational_target_machine(sess);
match req.kind {
@ -440,9 +442,9 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess
let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref()))
.unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e));
unsafe extern "C" fn callback(out: *mut c_void, string: *const c_char, len: usize) {
let out = &mut *(out as *mut &mut dyn PrintBackendInfo);
let out = &mut *(out as *mut &mut String);
let bytes = slice::from_raw_parts(string as *const u8, len);
write!(out, "{}", String::from_utf8_lossy(bytes));
write!(out, "{}", String::from_utf8_lossy(bytes)).unwrap();
}
unsafe {
llvm::LLVMRustPrintTargetCPUs(

View file

@ -127,13 +127,24 @@ impl<'ll> CodegenCx<'ll, '_> {
pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) }
}
}
impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn type_i1(&self) -> &'ll Type {
pub(crate) fn type_i1(&self) -> &'ll Type {
unsafe { llvm::LLVMInt1TypeInContext(self.llcx) }
}
pub(crate) fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type {
unsafe {
llvm::LLVMStructTypeInContext(
self.llcx,
els.as_ptr(),
els.len() as c_uint,
packed as Bool,
)
}
}
}
impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn type_i8(&self) -> &'ll Type {
unsafe { llvm::LLVMInt8TypeInContext(self.llcx) }
}
@ -178,17 +189,6 @@ impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, False) }
}
fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type {
unsafe {
llvm::LLVMStructTypeInContext(
self.llcx,
els.as_ptr(),
els.len() as c_uint,
packed as Bool,
)
}
}
fn type_kind(&self, ty: &'ll Type) -> TypeKind {
unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() }
}

View file

@ -45,7 +45,7 @@ use tempfile::Builder as TempFileBuilder;
use itertools::Itertools;
use std::collections::BTreeSet;
use std::ffi::{OsStr, OsString};
use std::ffi::OsString;
use std::fs::{read, File, OpenOptions};
use std::io::{BufWriter, Write};
use std::ops::Deref;
@ -1306,12 +1306,12 @@ fn link_sanitizer_runtime(
let filename = format!("rustc{channel}_rt.{name}");
let path = find_sanitizer_runtime(sess, &filename);
let rpath = path.to_str().expect("non-utf8 component in path");
linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
linker.cc_args(&["-Wl,-rpath", "-Xlinker", rpath]);
linker.link_dylib_by_name(&filename, false, true);
} else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" {
// MSVC provides the `/INFERASANLIBS` argument to automatically find the
// compatible ASAN library.
linker.arg("/INFERASANLIBS");
linker.link_arg("/INFERASANLIBS");
} else {
let filename = format!("librustc{channel}_rt.{name}.a");
let path = find_sanitizer_runtime(sess, &filename).join(&filename);
@ -1888,9 +1888,9 @@ fn add_post_link_objects(
/// FIXME: Determine where exactly these args need to be inserted.
fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
if let Some(args) = sess.target.pre_link_args.get(&flavor) {
cmd.args(args.iter().map(Deref::deref));
cmd.verbatim_args(args.iter().map(Deref::deref));
}
cmd.args(&sess.opts.unstable_opts.pre_link_args);
cmd.verbatim_args(&sess.opts.unstable_opts.pre_link_args);
}
/// Add a link script embedded in the target, if applicable.
@ -1908,8 +1908,7 @@ fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_ty
sess.dcx().emit_fatal(errors::LinkScriptWriteFailure { path, error });
}
cmd.arg("--script");
cmd.arg(path);
cmd.link_arg("--script").link_arg(path);
}
_ => {}
}
@ -1918,7 +1917,7 @@ fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_ty
/// Add arbitrary "user defined" args defined from command line.
/// FIXME: Determine where exactly these args need to be inserted.
fn add_user_defined_link_args(cmd: &mut dyn Linker, sess: &Session) {
cmd.args(&sess.opts.cg.link_args);
cmd.verbatim_args(&sess.opts.cg.link_args);
}
/// Add arbitrary "late link" args defined by the target spec.
@ -1936,15 +1935,15 @@ fn add_late_link_args(
});
if any_dynamic_crate {
if let Some(args) = sess.target.late_link_args_dynamic.get(&flavor) {
cmd.args(args.iter().map(Deref::deref));
cmd.verbatim_args(args.iter().map(Deref::deref));
}
} else {
if let Some(args) = sess.target.late_link_args_static.get(&flavor) {
cmd.args(args.iter().map(Deref::deref));
cmd.verbatim_args(args.iter().map(Deref::deref));
}
}
if let Some(args) = sess.target.late_link_args.get(&flavor) {
cmd.args(args.iter().map(Deref::deref));
cmd.verbatim_args(args.iter().map(Deref::deref));
}
}
@ -1952,7 +1951,7 @@ fn add_late_link_args(
/// FIXME: Determine where exactly these args need to be inserted.
fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
if let Some(args) = sess.target.post_link_args.get(&flavor) {
cmd.args(args.iter().map(Deref::deref));
cmd.verbatim_args(args.iter().map(Deref::deref));
}
}
@ -2097,6 +2096,10 @@ fn add_rpath_args(
codegen_results: &CodegenResults,
out_filename: &Path,
) {
if !sess.target.has_rpath {
return;
}
// FIXME (#2397): At some point we want to rpath our guesses as to
// where extern libraries might live, based on the
// add_lib_search_paths
@ -2115,11 +2118,10 @@ fn add_rpath_args(
let rpath_config = RPathConfig {
libs: &*libs,
out_filename: out_filename.to_path_buf(),
has_rpath: sess.target.has_rpath,
is_like_osx: sess.target.is_like_osx,
linker_is_gnu: sess.target.linker_flavor.is_gnu(),
};
cmd.args(&rpath::get_rpath_flags(&rpath_config));
cmd.cc_args(&rpath::get_rpath_flags(&rpath_config));
}
}
@ -2378,7 +2380,7 @@ fn add_order_independent_options(
} else {
""
};
cmd.arg(format!("--dynamic-linker={prefix}ld.so.1"));
cmd.link_arg(format!("--dynamic-linker={prefix}ld.so.1"));
}
if sess.target.eh_frame_header {
@ -2393,8 +2395,7 @@ fn add_order_independent_options(
}
if sess.target.os == "emscripten" {
cmd.arg("-s");
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
cmd.cc_arg("-s").cc_arg(if sess.panic_strategy() == PanicStrategy::Abort {
"DISABLE_EXCEPTION_CATCHING=1"
} else {
"DISABLE_EXCEPTION_CATCHING=0"
@ -2402,22 +2403,21 @@ fn add_order_independent_options(
}
if flavor == LinkerFlavor::Llbc {
cmd.arg("--target");
cmd.arg(sess.target.llvm_target.as_ref());
cmd.arg("--target-cpu");
cmd.arg(&codegen_results.crate_info.target_cpu);
cmd.link_args(&[
"--target",
sess.target.llvm_target.as_ref(),
"--target-cpu",
&codegen_results.crate_info.target_cpu,
]);
} else if flavor == LinkerFlavor::Ptx {
cmd.arg("--fallback-arch");
cmd.arg(&codegen_results.crate_info.target_cpu);
cmd.link_args(&["--fallback-arch", &codegen_results.crate_info.target_cpu]);
} else if flavor == LinkerFlavor::Bpf {
cmd.arg("--cpu");
cmd.arg(&codegen_results.crate_info.target_cpu);
cmd.link_args(&["--cpu", &codegen_results.crate_info.target_cpu]);
if let Some(feat) = [sess.opts.cg.target_feature.as_str(), &sess.target.options.features]
.into_iter()
.find(|feat| !feat.is_empty())
{
cmd.arg("--cpu-features");
cmd.arg(feat);
cmd.link_args(&["--cpu-features", feat]);
}
}
@ -2618,7 +2618,11 @@ fn add_native_libs_from_crate(
NativeLibKind::WasmImportModule => {}
NativeLibKind::LinkArg => {
if link_static {
cmd.linker_arg(OsStr::new(name), verbatim);
if verbatim {
cmd.verbatim_arg(name);
} else {
cmd.link_arg(name);
}
}
}
}
@ -3012,10 +3016,10 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
// 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.args(&["-isysroot", &sdk_root]);
cmd.cc_args(&["-isysroot", &sdk_root]);
}
LinkerFlavor::Darwin(Cc::No, _) => {
cmd.args(&["-syslibroot", &sdk_root]);
cmd.link_args(&["-syslibroot", &sdk_root]);
}
_ => unreachable!(),
}
@ -3026,8 +3030,9 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
// search path.
// The flags are called `-L` and `-F` both in Clang, ld64 and ldd.
cmd.arg(format!("-L{sdk_root}/System/iOSSupport/usr/lib"));
cmd.arg(format!("-F{sdk_root}/System/iOSSupport/System/Library/Frameworks"));
let sdk_root = Path::new(&sdk_root);
cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib"));
cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"));
}
}
@ -3142,7 +3147,7 @@ fn add_lld_args(
for path in sess.get_tools_search_paths(false) {
let linker_path = path.join("gcc-ld");
linker_path_exists |= linker_path.exists();
cmd.arg({
cmd.cc_arg({
let mut arg = OsString::from("-B");
arg.push(linker_path);
arg
@ -3162,7 +3167,7 @@ fn add_lld_args(
// is to use LLD but the `wasm32-wasip2` target relies on a wrapper around
// this, `wasm-component-ld`, which is overridden if this option is passed.
if !sess.target.is_like_wasm {
cmd.arg("-fuse-ld=lld");
cmd.cc_arg("-fuse-ld=lld");
}
if !flavor.is_gnu() {
@ -3186,7 +3191,7 @@ fn add_lld_args(
// targeting a different linker flavor on macOS, and that's also always
// the case when targeting WASM.
if sess.target.linker_flavor != sess.host.linker_flavor {
cmd.arg(format!("--target={}", sess.target.llvm_target));
cmd.cc_arg(format!("--target={}", sess.target.llvm_target));
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -9,16 +9,10 @@ pub struct RPathConfig<'a> {
pub libs: &'a [&'a Path],
pub out_filename: PathBuf,
pub is_like_osx: bool,
pub has_rpath: bool,
pub linker_is_gnu: bool,
}
pub fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec<OsString> {
// No rpath on windows
if !config.has_rpath {
return Vec::new();
}
debug!("preparing the RPATH!");
let rpaths = get_rpaths(config);

View file

@ -37,7 +37,6 @@ fn test_rpath_relative() {
if cfg!(target_os = "macos") {
let config = &mut RPathConfig {
libs: &[],
has_rpath: true,
is_like_osx: true,
linker_is_gnu: false,
out_filename: PathBuf::from("bin/rustc"),
@ -48,7 +47,6 @@ fn test_rpath_relative() {
let config = &mut RPathConfig {
libs: &[],
out_filename: PathBuf::from("bin/rustc"),
has_rpath: true,
is_like_osx: false,
linker_is_gnu: true,
};
@ -62,7 +60,6 @@ fn test_rpath_relative_issue_119571() {
let config = &mut RPathConfig {
libs: &[],
out_filename: PathBuf::from("rustc"),
has_rpath: true,
is_like_osx: false,
linker_is_gnu: true,
};

View file

@ -133,6 +133,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
let align = cx.data_layout().pointer_align.abi;
let vtable = cx.static_addr_of(vtable_const, align, Some("vtable"));
cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable);
cx.create_vtable_debuginfo(ty, trait_ref, vtable);
cx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
vtable

View file

@ -658,7 +658,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// with #[rustc_inherit_overflow_checks] and inlined from
// another crate (mostly core::num generic/#[inline] fns),
// while the current crate doesn't use overflow checks.
if !bx.cx().check_overflow() && msg.is_optional_overflow_check() {
if !bx.sess().overflow_checks() && msg.is_optional_overflow_check() {
const_cond = Some(expected);
}
@ -751,7 +751,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&mut self,
helper: &TerminatorCodegenHelper<'tcx>,
bx: &mut Bx,
intrinsic: Option<ty::IntrinsicDef>,
intrinsic: ty::IntrinsicDef,
instance: Option<Instance<'tcx>>,
source_info: mir::SourceInfo,
target: Option<mir::BasicBlock>,
@ -761,8 +761,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// Emit a panic or a no-op for `assert_*` intrinsics.
// These are intrinsics that compile to panics so that we can get a message
// which mentions the offending type, even from a const context.
let panic_intrinsic = intrinsic.and_then(|i| ValidityRequirement::from_intrinsic(i.name));
if let Some(requirement) = panic_intrinsic {
if let Some(requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) {
let ty = instance.unwrap().args.type_at(0);
let do_panic = !bx
@ -869,12 +868,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let sig = callee.layout.ty.fn_sig(bx.tcx());
let abi = sig.abi();
// Handle intrinsics old codegen wants Expr's for, ourselves.
let intrinsic = match def {
Some(ty::InstanceKind::Intrinsic(def_id)) => Some(bx.tcx().intrinsic(def_id).unwrap()),
_ => None,
};
let extra_args = &args[sig.inputs().skip_binder().len()..];
let extra_args = bx.tcx().mk_type_list_from_iter(extra_args.iter().map(|op_arg| {
let op_ty = op_arg.node.ty(self.mir, bx.tcx());
@ -886,50 +879,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
None => bx.fn_abi_of_fn_ptr(sig, extra_args),
};
if let Some(merging_succ) = self.codegen_panic_intrinsic(
&helper,
bx,
intrinsic,
instance,
source_info,
target,
unwind,
mergeable_succ,
) {
return merging_succ;
}
// The arguments we'll be passing. Plus one to account for outptr, if used.
let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
if matches!(intrinsic, Some(ty::IntrinsicDef { name: sym::caller_location, .. })) {
return if let Some(target) = target {
let location =
self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info });
let mut llargs = Vec::with_capacity(arg_count);
let ret_dest = self.make_return_dest(
let instance = match def {
Some(ty::InstanceKind::Intrinsic(def_id)) => {
let intrinsic = bx.tcx().intrinsic(def_id).unwrap();
if let Some(merging_succ) = self.codegen_panic_intrinsic(
&helper,
bx,
destination,
&fn_abi.ret,
&mut llargs,
intrinsic,
Some(target),
);
assert_eq!(llargs, []);
if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
location.val.store(bx, tmp);
instance,
source_info,
target,
unwind,
mergeable_succ,
) {
return merging_succ;
}
self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate());
helper.funclet_br(self, bx, target, mergeable_succ)
} else {
MergingSucc::False
};
}
let instance = match intrinsic {
None => instance,
Some(intrinsic) => {
let mut llargs = Vec::with_capacity(1);
let ret_dest = self.make_return_dest(
bx,
@ -971,6 +939,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
})
.collect();
if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) {
let location = self
.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info });
assert_eq!(llargs, []);
if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
location.val.store(bx, tmp);
}
self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate());
return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ);
}
let instance = *instance.as_ref().unwrap();
match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) {
Ok(()) => {
@ -997,6 +977,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
}
_ => instance,
};
let mut llargs = Vec::with_capacity(arg_count);

View file

@ -22,8 +22,6 @@ use rustc_session::{
use rustc_span::symbol::Symbol;
use rustc_target::abi::call::FnAbi;
use std::fmt;
pub trait BackendTypes {
type Value: CodegenObject;
type Function: CodegenObject;
@ -62,7 +60,7 @@ pub trait CodegenBackend {
fn locale_resource(&self) -> &'static str;
fn init(&self, _sess: &Session) {}
fn print(&self, _req: &PrintRequest, _out: &mut dyn PrintBackendInfo, _sess: &Session) {}
fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {}
fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
vec![]
}
@ -150,19 +148,3 @@ pub trait ExtraBackendMethods:
std::thread::Builder::new().name(name).spawn(f)
}
}
pub trait PrintBackendInfo {
fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>);
}
impl PrintBackendInfo for String {
fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>) {
fmt::Write::write_fmt(self, args).unwrap();
}
}
impl dyn PrintBackendInfo + '_ {
pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) {
self.infallible_write_fmt(args);
}
}

View file

@ -37,6 +37,5 @@ pub trait ConstMethods<'tcx>: BackendTypes {
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
fn const_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value;
fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value;
}

View file

@ -9,7 +9,13 @@ pub trait MiscMethods<'tcx>: BackendTypes {
fn vtables(
&self,
) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Self::Value>>;
fn check_overflow(&self) -> bool;
fn apply_vcall_visibility_metadata(
&self,
_ty: Ty<'tcx>,
_poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
_vtable: Self::Value,
) {
}
fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function;
fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value;
fn eh_personality(&self) -> Self::Value;

View file

@ -30,9 +30,7 @@ mod write;
pub use self::abi::AbiBuilderMethods;
pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
pub use self::backend::{
Backend, BackendTypes, CodegenBackend, ExtraBackendMethods, PrintBackendInfo,
};
pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods};
pub use self::builder::{BuilderMethods, OverflowOp};
pub use self::consts::ConstMethods;
pub use self::coverageinfo::CoverageInfoBuilderMethods;

View file

@ -12,7 +12,6 @@ use rustc_target::abi::{AddressSpace, Float, Integer};
// This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use
// `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves.
pub trait BaseTypeMethods<'tcx>: Backend<'tcx> {
fn type_i1(&self) -> Self::Type;
fn type_i8(&self) -> Self::Type;
fn type_i16(&self) -> Self::Type;
fn type_i32(&self) -> Self::Type;
@ -27,7 +26,6 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> {
fn type_array(&self, ty: Self::Type, len: u64) -> Self::Type;
fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type;
fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type;
fn type_kind(&self, ty: Self::Type) -> TypeKind;
fn type_ptr(&self) -> Self::Type;
fn type_ptr_ext(&self, address_space: AddressSpace) -> Self::Type;
@ -115,8 +113,8 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
/// The backend type used for a rust type when it's in an SSA register.
///
/// For nearly all types this is the same as the [`Self::backend_type`], however
/// `bool` (and other `0`-or-`1` values) are kept as [`BaseTypeMethods::type_i1`]
/// in registers but as [`BaseTypeMethods::type_i8`] in memory.
/// `bool` (and other `0`-or-`1` values) are kept as `i1` in registers but as
/// [`BaseTypeMethods::type_i8`] in memory.
///
/// Converting values between the two different backend types is done using
/// [`from_immediate`](super::BuilderMethods::from_immediate) and

View file

@ -42,10 +42,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => {
hir::Constness::Const
}
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx
.generics_of(def_id)
.host_effect_index
.map_or(hir::Constness::NotConst, |_| hir::Constness::Const),
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness,
hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
// foreign items cannot be evaluated at compile-time.

View file

@ -1,6 +1,6 @@
use std::assert_matches::assert_matches;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_apfloat::{Float, FloatConvert};
use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
use rustc_middle::mir::CastKind;
@ -187,10 +187,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
bug!("FloatToFloat/FloatToInt cast: source type {} is not a float type", src.layout.ty)
};
let val = match fty {
FloatTy::F16 => unimplemented!("f16_f128"),
FloatTy::F16 => self.cast_from_float(src.to_scalar().to_f16()?, cast_to.ty),
FloatTy::F32 => self.cast_from_float(src.to_scalar().to_f32()?, cast_to.ty),
FloatTy::F64 => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty),
FloatTy::F128 => unimplemented!("f16_f128"),
FloatTy::F128 => self.cast_from_float(src.to_scalar().to_f128()?, cast_to.ty),
};
Ok(ImmTy::from_scalar(val, cast_to))
}
@ -296,18 +296,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
Float(fty) if signed => {
let v = v as i128;
match fty {
FloatTy::F16 => unimplemented!("f16_f128"),
FloatTy::F16 => Scalar::from_f16(Half::from_i128(v).value),
FloatTy::F32 => Scalar::from_f32(Single::from_i128(v).value),
FloatTy::F64 => Scalar::from_f64(Double::from_i128(v).value),
FloatTy::F128 => unimplemented!("f16_f128"),
FloatTy::F128 => Scalar::from_f128(Quad::from_i128(v).value),
}
}
// unsigned int -> float
Float(fty) => match fty {
FloatTy::F16 => unimplemented!("f16_f128"),
FloatTy::F16 => Scalar::from_f16(Half::from_u128(v).value),
FloatTy::F32 => Scalar::from_f32(Single::from_u128(v).value),
FloatTy::F64 => Scalar::from_f64(Double::from_u128(v).value),
FloatTy::F128 => unimplemented!("f16_f128"),
FloatTy::F128 => Scalar::from_f128(Quad::from_u128(v).value),
},
// u8 -> char
@ -321,7 +321,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Low-level cast helper function. Converts an apfloat `f` into int or float types.
fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance>
where
F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>,
F: Float
+ Into<Scalar<M::Provenance>>
+ FloatConvert<Half>
+ FloatConvert<Single>
+ FloatConvert<Double>
+ FloatConvert<Quad>,
{
use rustc_type_ir::TyKind::*;
@ -358,10 +363,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
// float -> float
Float(fty) => match fty {
FloatTy::F16 => unimplemented!("f16_f128"),
FloatTy::F16 => Scalar::from_f16(adjust_nan(self, f, f.convert(&mut false).value)),
FloatTy::F32 => Scalar::from_f32(adjust_nan(self, f, f.convert(&mut false).value)),
FloatTy::F64 => Scalar::from_f64(adjust_nan(self, f, f.convert(&mut false).value)),
FloatTy::F128 => unimplemented!("f16_f128"),
FloatTy::F128 => {
Scalar::from_f128(adjust_nan(self, f, f.convert(&mut false).value))
}
},
// That's it.
_ => span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty),

View file

@ -50,7 +50,7 @@ libc = "0.2"
memmap2 = "0.2.1"
# tidy-alphabetical-end
[target.'cfg(any(target_arch = "mips", target_arch = "powerpc", target_arch = "sparc"))'.dependencies]
[target.'cfg(not(target_has_atomic = "64"))'.dependencies]
portable-atomic = "1.5.1"
[features]

View file

@ -147,14 +147,13 @@ cfg_match! {
[crate::owned_slice::OwnedSlice]
);
// MIPS, PowerPC and SPARC platforms with 32-bit pointers do not
// have AtomicU64 type.
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc", target_arch = "sparc")))]
// Use portable AtomicU64 for targets without native 64-bit atomics
#[cfg(target_has_atomic = "64")]
already_sync!(
[std::sync::atomic::AtomicU64]
);
#[cfg(any(target_arch = "mips", target_arch = "powerpc", target_arch = "sparc"))]
#[cfg(not(target_has_atomic = "64"))]
already_sync!(
[portable_atomic::AtomicU64]
);

View file

@ -270,12 +270,11 @@ cfg_match! {
pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32};
// MIPS, PowerPC and SPARC platforms with 32-bit pointers do not
// have AtomicU64 type.
#[cfg(not(any(target_arch = "mips", target_arch = "powerpc", target_arch = "sparc")))]
// Use portable AtomicU64 for targets without native 64-bit atomics
#[cfg(target_has_atomic = "64")]
pub use std::sync::atomic::AtomicU64;
#[cfg(any(target_arch = "mips", target_arch = "powerpc", target_arch = "sparc"))]
#[cfg(not(target_has_atomic = "64"))]
pub use portable_atomic::AtomicU64;
pub use std::sync::Arc as Lrc;

View file

@ -510,7 +510,7 @@ pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> {
// would be bad.
impl<G> !Clone for Diag<'_, G> {}
rustc_data_structures::static_assert_size!(Diag<'_, ()>, 2 * std::mem::size_of::<usize>());
rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * std::mem::size_of::<usize>());
impl<G: EmissionGuarantee> Deref for Diag<'_, G> {
type Target = DiagInner;
@ -582,6 +582,11 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
Self::new_diagnostic(dcx, DiagInner::new(level, message))
}
/// Allow moving diagnostics between different error tainting contexts
pub fn with_dcx(mut self, dcx: DiagCtxtHandle<'_>) -> Diag<'_, G> {
Diag { dcx, diag: self.diag.take(), _marker: PhantomData }
}
/// Creates a new `Diag` with an already constructed diagnostic.
#[track_caller]
pub(crate) fn new_diagnostic(dcx: DiagCtxtHandle<'a>, diag: DiagInner) -> Self {

View file

@ -63,6 +63,7 @@ use rustc_span::source_map::SourceMap;
use rustc_span::{Loc, Span, DUMMY_SP};
use std::backtrace::{Backtrace, BacktraceStatus};
use std::borrow::Cow;
use std::cell::Cell;
use std::error::Report;
use std::fmt;
use std::hash::Hash;
@ -98,9 +99,9 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16);
rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
#[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
pub enum SuggestionStyle {
@ -417,6 +418,9 @@ pub struct DiagCtxt {
#[derive(Copy, Clone)]
pub struct DiagCtxtHandle<'a> {
dcx: &'a DiagCtxt,
/// Some contexts create `DiagCtxtHandle` with this field set, and thus all
/// errors emitted with it will automatically taint when emitting errors.
tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
}
impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
@ -752,7 +756,17 @@ impl DiagCtxt {
}
pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
DiagCtxtHandle { dcx: self }
DiagCtxtHandle { dcx: self, tainted_with_errors: None }
}
/// Link this to a taintable context so that emitting errors will automatically set
/// the `Option<ErrorGuaranteed>` instead of having to do that manually at every error
/// emission site.
pub fn taintable_handle<'a>(
&'a self,
tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
) -> DiagCtxtHandle<'a> {
DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
}
}
@ -795,7 +809,9 @@ impl<'a> DiagCtxtHandle<'a> {
// can be used to create a backtrace at the stashing site insted of whenever the
// diagnostic context is dropped and thus delayed bugs are emitted.
Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
DelayedBug => return self.inner.borrow_mut().emit_diagnostic(diag),
DelayedBug => {
return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
}
ForceWarning(_) | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
| Expect(_) => None,
};
@ -947,16 +963,19 @@ impl<'a> DiagCtxtHandle<'a> {
(0, _) => {
// Use `ForceWarning` rather than `Warning` to guarantee emission, e.g. with a
// configuration like `--cap-lints allow --force-warn bare_trait_objects`.
inner.emit_diagnostic(DiagInner::new(
ForceWarning(None),
DiagMessage::Str(warnings),
));
inner.emit_diagnostic(
DiagInner::new(ForceWarning(None), DiagMessage::Str(warnings)),
None,
);
}
(_, 0) => {
inner.emit_diagnostic(DiagInner::new(Error, errors));
inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
}
(_, _) => {
inner.emit_diagnostic(DiagInner::new(Error, format!("{errors}; {warnings}")));
inner.emit_diagnostic(
DiagInner::new(Error, format!("{errors}; {warnings}")),
self.tainted_with_errors,
);
}
}
@ -987,14 +1006,14 @@ impl<'a> DiagCtxtHandle<'a> {
"For more information about an error, try `rustc --explain {}`.",
&error_codes[0]
);
inner.emit_diagnostic(DiagInner::new(FailureNote, msg1));
inner.emit_diagnostic(DiagInner::new(FailureNote, msg2));
inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
} else {
let msg = format!(
"For more information about this error, try `rustc --explain {}`.",
&error_codes[0]
);
inner.emit_diagnostic(DiagInner::new(FailureNote, msg));
inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
}
}
}
@ -1020,7 +1039,7 @@ impl<'a> DiagCtxtHandle<'a> {
}
pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
self.inner.borrow_mut().emit_diagnostic(diagnostic)
self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
}
pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
@ -1080,7 +1099,7 @@ impl<'a> DiagCtxtHandle<'a> {
// Here the diagnostic is given back to `emit_diagnostic` where it was first
// intercepted. Now it should be processed as usual, since the unstable expectation
// id is now stable.
inner.emit_diagnostic(diag);
inner.emit_diagnostic(diag, self.tainted_with_errors);
}
}
@ -1430,13 +1449,17 @@ impl DiagCtxtInner {
continue;
}
}
guar = guar.or(self.emit_diagnostic(diag));
guar = guar.or(self.emit_diagnostic(diag, None));
}
guar
}
// Return value is only `Some` if the level is `Error` or `DelayedBug`.
fn emit_diagnostic(&mut self, mut diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
fn emit_diagnostic(
&mut self,
mut diagnostic: DiagInner,
taint: Option<&Cell<Option<ErrorGuaranteed>>>,
) -> Option<ErrorGuaranteed> {
match diagnostic.level {
Expect(expect_id) | ForceWarning(Some(expect_id)) => {
// The `LintExpectationId` can be stable or unstable depending on when it was
@ -1609,6 +1632,9 @@ impl DiagCtxtInner {
if is_lint {
self.lint_err_guars.push(guar);
} else {
if let Some(taint) = taint {
taint.set(Some(guar));
}
self.err_guars.push(guar);
}
self.panic_if_treat_err_as_bug();
@ -1718,8 +1744,8 @@ impl DiagCtxtInner {
// `-Ztreat-err-as-bug`, which we don't want.
let note1 = "no errors encountered even though delayed bugs were created";
let note2 = "those delayed bugs will now be shown as internal compiler errors";
self.emit_diagnostic(DiagInner::new(Note, note1));
self.emit_diagnostic(DiagInner::new(Note, note2));
self.emit_diagnostic(DiagInner::new(Note, note1), None);
self.emit_diagnostic(DiagInner::new(Note, note2), None);
for bug in bugs {
if let Some(out) = &mut out {
@ -1752,7 +1778,7 @@ impl DiagCtxtInner {
}
bug.level = Bug;
self.emit_diagnostic(bug);
self.emit_diagnostic(bug, None);
}
// Panic with `DelayedBugPanic` to avoid "unexpected panic" messages.

View file

@ -833,6 +833,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_const_panic_str, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
),
rustc_attr!(
rustc_runtime, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, INTERNAL_UNSTABLE
),
// ==========================================================================
// Internal attributes, Layout related:
@ -1113,6 +1117,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
TEST, rustc_dump_predicates, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_dump_def_parents, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_object_lifetime_default, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No

View file

@ -526,6 +526,7 @@ pub enum GenericParamKind<'hir> {
/// Optional default value for the const generic param
default: Option<&'hir AnonConst>,
is_host_effect: bool,
synthetic: bool,
},
}
@ -3364,6 +3365,7 @@ pub enum ItemKind<'hir> {
/// Refer to [`ImplItem`] for an associated item within an impl block.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Impl<'hir> {
pub constness: Constness,
pub safety: Safety,
pub polarity: ImplPolarity,
pub defaultness: Defaultness,

View file

@ -543,6 +543,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
try_visit!(visitor.visit_enum_def(enum_definition, item.hir_id()));
}
ItemKind::Impl(Impl {
constness: _,
safety: _,
defaultness: _,
polarity: _,
@ -915,7 +916,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
match param.kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { ref default, .. } => visit_opt!(visitor, visit_ty, default),
GenericParamKind::Const { ref ty, ref default, is_host_effect: _ } => {
GenericParamKind::Const { ref ty, ref default, is_host_effect: _, synthetic: _ } => {
try_visit!(visitor.visit_ty(ty));
if let Some(ref default) = default {
try_visit!(visitor.visit_const_param_default(param.hir_id, default));

View file

@ -393,6 +393,14 @@ language_item_table! {
String, sym::String, string, Target::Struct, GenericRequirement::None;
CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None;
EffectsRuntime, sym::EffectsRuntime, effects_runtime, Target::Struct, GenericRequirement::None;
EffectsNoRuntime, sym::EffectsNoRuntime, effects_no_runtime, Target::Struct, GenericRequirement::None;
EffectsMaybe, sym::EffectsMaybe, effects_maybe, Target::Struct, GenericRequirement::None;
EffectsIntersection, sym::EffectsIntersection, effects_intersection, Target::Trait, GenericRequirement::None;
EffectsIntersectionOutput, sym::EffectsIntersectionOutput, effects_intersection_output, Target::AssocTy, GenericRequirement::None;
EffectsCompat, sym::EffectsCompat, effects_compat, Target::Trait, GenericRequirement::Exact(1);
EffectsTyCompat, sym::EffectsTyCompat, effects_ty_compat, Target::Trait, GenericRequirement::Exact(1);
}
pub enum GenericRequirement {

View file

@ -120,6 +120,10 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
.label = parameter captured again here
hir_analysis_effects_without_next_solver = using `#![feature(effects)]` without enabling next trait solver globally
.note = the next trait solver must be enabled globally for the effects feature to work correctly
.help = use `-Znext-solver` to enable
hir_analysis_empty_specialization = specialization impl does not specialize any associated items
.note = impl is a specialization of this impl

View file

@ -1,9 +1,13 @@
//! Bounds are restrictions applied to some types after they've been lowered from the HIR to the
//! [`rustc_middle::ty`] form.
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::def::DefKind;
use rustc_hir::LangItem;
use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use rustc_span::{sym, Span};
/// Collects together a list of type bounds. These lists of bounds occur in many places
/// in Rust's syntax:
@ -24,6 +28,7 @@ use rustc_span::Span;
#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
clauses: Vec<(ty::Clause<'tcx>, Span)>,
effects_min_tys: FxIndexMap<Ty<'tcx>, Span>,
}
impl<'tcx> Bounds<'tcx> {
@ -40,12 +45,14 @@ impl<'tcx> Bounds<'tcx> {
pub fn push_trait_bound(
&mut self,
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
defining_def_id: DefId,
bound_trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
polarity: ty::PredicatePolarity,
constness: ty::BoundConstness,
) {
let clause = (
trait_ref
bound_trait_ref
.map_bound(|trait_ref| {
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
})
@ -53,11 +60,98 @@ impl<'tcx> Bounds<'tcx> {
span,
);
// FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) {
if tcx.is_lang_item(bound_trait_ref.def_id(), LangItem::Sized) {
self.clauses.insert(0, clause);
} else {
self.clauses.push(clause);
}
if !tcx.features().effects {
return;
}
// For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the
// associated type of `<T as Tr>` and make sure that the effect is compatible.
let compat_val = match (tcx.def_kind(defining_def_id), constness) {
// FIXME(effects): revisit the correctness of this
(_, ty::BoundConstness::Const) => tcx.consts.false_,
// body owners that can have trait bounds
(DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => {
tcx.expected_host_effect_param_for_body(defining_def_id)
}
(_, ty::BoundConstness::NotConst) => {
if !tcx.has_attr(bound_trait_ref.def_id(), sym::const_trait) {
return;
}
tcx.consts.true_
}
(
DefKind::Trait | DefKind::Impl { of_trait: true },
ty::BoundConstness::ConstIfConst,
) => {
// this is either a where clause on an impl/trait header or on a trait.
// push `<T as Tr>::Effects` into the set for the `Min` bound.
let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
return;
};
let ty = bound_trait_ref
.map_bound(|trait_ref| Ty::new_projection(tcx, assoc, trait_ref.args));
// When the user has written `for<'a, T> X<'a, T>: ~const Foo`, replace the
// binders to dummy ones i.e. `X<'static, ()>` so they can be referenced in
// the `Min` associated type properly (which doesn't allow using `for<>`)
// This should work for any bound variables as long as they don't have any
// bounds e.g. `for<T: Trait>`.
// FIXME(effects) reconsider this approach to allow compatibility with `for<T: Tr>`
let ty = tcx.replace_bound_vars_uncached(
ty,
FnMutDelegate {
regions: &mut |_| tcx.lifetimes.re_static,
types: &mut |_| tcx.types.unit,
consts: &mut |_| unimplemented!("`~const` does not support const binders"),
},
);
self.effects_min_tys.insert(ty, span);
return;
}
// for
// ```
// trait Foo { type Bar: ~const Trait }
// ```
// ensure that `<Self::Bar as Trait>::Effects: TyCompat<Self::Effects>`.
//
// FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor
// that uses a `Bar` that implements `Trait` with `Maybe` effects.
(DefKind::AssocTy, ty::BoundConstness::ConstIfConst) => {
// FIXME(effects): implement this
return;
}
// probably illegal in this position.
(_, ty::BoundConstness::ConstIfConst) => {
tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered");
return;
}
};
// create a new projection type `<T as Tr>::Effects`
let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
tcx.dcx().span_delayed_bug(
span,
"`~const` trait bound has no effect assoc yet no errors encountered?",
);
return;
};
let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args);
// make `<T as Tr>::Effects: Compat<runtime>`
let new_trait_ref = ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::EffectsCompat, Some(span)),
[ty::GenericArg::from(self_ty), compat_val.into()],
);
self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span));
}
pub fn push_projection_bound(
@ -79,7 +173,15 @@ impl<'tcx> Bounds<'tcx> {
self.clauses.insert(0, (trait_ref.upcast(tcx), span));
}
pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
pub fn clauses(
&self,
// FIXME(effects): remove tcx
_tcx: TyCtxt<'tcx>,
) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
self.clauses.iter().cloned()
}
pub fn effects_min_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
self.effects_min_tys.keys().copied()
}
}

View file

@ -879,7 +879,8 @@ pub(super) fn check_specialization_validity<'tcx>(
let result = opt_result.unwrap_or(Ok(()));
if let Err(parent_impl) = result {
if !tcx.is_impl_trait_in_trait(impl_item) {
// FIXME(effects) the associated type from effects could be specialized
if !tcx.is_impl_trait_in_trait(impl_item) && !tcx.is_effects_desugared_assoc_ty(impl_item) {
report_forbidden_specialization(tcx, impl_item, parent_impl);
} else {
tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default"));

View file

@ -1985,10 +1985,10 @@ pub(super) fn check_type_bounds<'tcx>(
let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
// A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the
// span for an impl's associated type. Instead, for these, use the def_span for the synthesized
// associated type.
let impl_ty_span = if impl_ty.is_impl_trait_in_trait() {
// A synthetic impl Trait for RPITIT desugaring or assoc type for effects desugaring has no HIR,
// which we currently use to get the span for an impl's associated type. Instead, for these,
// use the def_span for the synthesized associated type.
let impl_ty_span = if impl_ty.is_impl_trait_in_trait() || impl_ty.is_effects_desugaring {
tcx.def_span(impl_ty_def_id)
} else {
match tcx.hir_node_by_def_id(impl_ty_def_id) {

View file

@ -913,7 +913,12 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()),
// Const parameters are well formed if their type is structural match.
hir::GenericParamKind::Const { ty: hir_ty, default: _, is_host_effect: _ } => {
hir::GenericParamKind::Const {
ty: hir_ty,
default: _,
is_host_effect: _,
synthetic: _,
} => {
let ty = tcx.type_of(param.def_id).instantiate_identity();
if tcx.features().adt_const_params {

View file

@ -70,10 +70,10 @@ pub fn provide(providers: &mut Providers) {
predicates_of: predicates_of::predicates_of,
predicates_defined_on,
explicit_predicates_of: predicates_of::explicit_predicates_of,
super_predicates_of: predicates_of::super_predicates_of,
implied_predicates_of: predicates_of::implied_predicates_of,
super_predicates_that_define_assoc_item:
predicates_of::super_predicates_that_define_assoc_item,
explicit_super_predicates_of: predicates_of::explicit_super_predicates_of,
explicit_implied_predicates_of: predicates_of::explicit_implied_predicates_of,
explicit_supertraits_containing_assoc_item:
predicates_of::explicit_supertraits_containing_assoc_item,
trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
type_param_predicates: predicates_of::type_param_predicates,
trait_def,
@ -691,14 +691,14 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
hir::ItemKind::Trait(..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().trait_def(def_id);
tcx.at(it.span).super_predicates_of(def_id);
tcx.at(it.span).explicit_super_predicates_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure().associated_items(def_id);
}
hir::ItemKind::TraitAlias(..) => {
tcx.ensure().generics_of(def_id);
tcx.at(it.span).implied_predicates_of(def_id);
tcx.at(it.span).super_predicates_of(def_id);
tcx.at(it.span).explicit_implied_predicates_of(def_id);
tcx.at(it.span).explicit_super_predicates_of(def_id);
tcx.ensure().predicates_of(def_id);
}
hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => {
@ -1459,8 +1459,25 @@ fn infer_return_ty_for_fn_sig<'tcx>(
Some(ty) => {
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
// Typeck doesn't expect erased regions to be returned from `type_of`.
// This is a heuristic approach. If the scope has region paramters,
// we should change fn_sig's lifetime from `ReErased` to `ReError`,
// otherwise to `ReStatic`.
let has_region_params = generics.params.iter().any(|param| match param.kind {
GenericParamKind::Lifetime { .. } => true,
_ => false,
});
let fn_sig = tcx.fold_regions(fn_sig, |r, _| match *r {
ty::ReErased => tcx.lifetimes.re_static,
ty::ReErased => {
if has_region_params {
ty::Region::new_error_with_message(
tcx,
DUMMY_SP,
"erased region is not allowed here in return type",
)
} else {
tcx.lifetimes.re_static
}
}
_ => r,
});
@ -1638,44 +1655,19 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
let icx = ItemCtxt::new(tcx, def_id);
let item = tcx.hir().expect_item(def_id);
let impl_ = item.expect_impl();
impl_
.of_trait
.as_ref()
.map(|hir_trait_ref| {
let self_ty = tcx.type_of(def_id).instantiate_identity();
impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id).instantiate_identity();
let trait_ref = if let Some(ErrorGuaranteed { .. }) = check_impl_constness(
tcx,
tcx.is_const_trait_impl_raw(def_id.to_def_id()),
hir_trait_ref,
) {
// we have a const impl, but for a trait without `#[const_trait]`, so
// without the host param. If we continue with the HIR trait ref, we get
// ICEs for generic arg count mismatch. We do a little HIR editing to
// make HIR ty lowering happy.
let mut path_segments = hir_trait_ref.path.segments.to_vec();
let last_segment = path_segments.len() - 1;
let mut args = *path_segments[last_segment].args();
let last_arg = args.args.len() - 1;
assert!(matches!(args.args[last_arg], hir::GenericArg::Const(anon_const) if anon_const.is_desugared_from_effects));
args.args = &args.args[..args.args.len() - 1];
path_segments[last_segment].args = Some(tcx.hir_arena.alloc(args));
let path = hir::Path {
span: hir_trait_ref.path.span,
res: hir_trait_ref.path.res,
segments: tcx.hir_arena.alloc_slice(&path_segments),
};
let trait_ref = tcx.hir_arena.alloc(hir::TraitRef { path: tcx.hir_arena.alloc(path), hir_ref_id: hir_trait_ref.hir_ref_id });
icx.lowerer().lower_impl_trait_ref(trait_ref, self_ty)
} else {
icx.lowerer().lower_impl_trait_ref(hir_trait_ref, self_ty)
};
ty::ImplTraitHeader {
trait_ref: ty::EarlyBinder::bind(trait_ref),
safety: impl_.safety,
polarity: polarity_of_impl(tcx, def_id, impl_, item.span)
}
})
check_impl_constness(tcx, tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref);
let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty);
ty::ImplTraitHeader {
trait_ref: ty::EarlyBinder::bind(trait_ref),
safety: impl_.safety,
polarity: polarity_of_impl(tcx, def_id, impl_, item.span),
}
})
}
fn check_impl_constness(

View file

@ -1,5 +1,7 @@
use rustc_hir::def::DefKind;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::intravisit;
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::ty::TyCtxt;
use rustc_span::sym;
@ -41,3 +43,49 @@ pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) {
}
}
}
pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
for did in tcx.hir().body_owners() {
if tcx.has_attr(did, sym::rustc_dump_def_parents) {
struct AnonConstFinder<'tcx> {
tcx: TyCtxt<'tcx>,
anon_consts: Vec<LocalDefId>,
}
impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> {
type NestedFilter = OnlyBodies;
fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}
fn visit_anon_const(&mut self, c: &'tcx rustc_hir::AnonConst) {
self.anon_consts.push(c.def_id);
intravisit::walk_anon_const(self, c)
}
}
// Look for any anon consts inside of this body owner as there is no way to apply
// the `rustc_dump_def_parents` attribute to the anon const so it would not be possible
// to see what its def parent is.
let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: vec![] };
intravisit::walk_expr(&mut anon_ct_finder, tcx.hir().body_owned_by(did).value);
for did in [did].into_iter().chain(anon_ct_finder.anon_consts) {
let span = tcx.def_span(did);
let mut diag = tcx.dcx().struct_span_err(
span,
format!("{}: {did:?}", sym::rustc_dump_def_parents.as_str()),
);
let mut current_did = did.to_def_id();
while let Some(parent_did) = tcx.opt_parent(current_did) {
current_did = parent_did;
diag.span_note(tcx.def_span(parent_did), format!("{parent_did:?}"));
}
diag.emit();
}
}
}
}

View file

@ -354,7 +354,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
kind,
})
}
GenericParamKind::Const { ty: _, default, is_host_effect } => {
GenericParamKind::Const { ty: _, default, is_host_effect, synthetic } => {
if !matches!(allow_defaults, Defaults::Allowed)
&& default.is_some()
// `host` effect params are allowed to have defaults.
@ -388,6 +388,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
kind: ty::GenericParamDefKind::Const {
has_default: default.is_some(),
is_host_effect,
synthetic,
},
})
}
@ -541,7 +542,8 @@ struct AnonConstInParamTyDetector {
impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
if let GenericParamKind::Const { ty, default: _, is_host_effect: _ } = p.kind {
if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind
{
let prev = self.in_param_ty;
self.in_param_ty = true;
self.visit_ty(ty);

View file

@ -8,6 +8,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFold
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::Span;
use rustc_type_ir::Upcast;
/// For associated types we include both bounds written on the type
/// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`.
@ -46,7 +47,7 @@ fn associated_type_bounds<'tcx>(
}
});
let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent));
let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent));
debug!(
"associated_type_bounds({}) = {:?}",
tcx.def_path_str(assoc_item_def_id.to_def_id()),
@ -75,7 +76,7 @@ fn opaque_type_bounds<'tcx>(
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
debug!(?bounds);
tcx.arena.alloc_from_iter(bounds.clauses())
tcx.arena.alloc_from_iter(bounds.clauses(tcx))
})
}
@ -124,6 +125,32 @@ pub(super) fn explicit_item_bounds_with_filter(
None => {}
}
if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) {
let mut predicates = Vec::new();
let parent = tcx.local_parent(def_id);
let preds = tcx.explicit_predicates_of(parent);
if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container {
// for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>`
let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys));
// FIXME(effects) span
let span = tcx.def_span(def_id);
let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span));
let proj = Ty::new_projection(tcx, assoc, [tup]);
let self_proj = Ty::new_projection(
tcx,
def_id.to_def_id(),
ty::GenericArgs::identity_for_item(tcx, def_id),
);
let trait_ = tcx.require_lang_item(hir::LangItem::EffectsTyCompat, Some(span));
let trait_ref = ty::TraitRef::new(tcx, trait_, [self_proj, proj]);
predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span));
}
return ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(predicates));
}
let bounds = match tcx.hir_node_by_def_id(def_id) {
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Type(bounds, _),

View file

@ -57,6 +57,7 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
#[instrument(level = "trace", skip(tcx), ret)]
fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> {
use rustc_hir::*;
use rustc_middle::ty::Ty;
match tcx.opt_rpitit_info(def_id.to_def_id()) {
Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) => {
@ -84,6 +85,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
return ty::GenericPredicates {
parent: Some(tcx.parent(def_id.to_def_id())),
predicates: tcx.arena.alloc_from_iter(predicates),
effects_min_tys: ty::List::empty(),
};
}
@ -105,6 +107,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
return ty::GenericPredicates {
parent: Some(impl_def_id),
predicates: tcx.arena.alloc_from_iter(impl_predicates),
effects_min_tys: ty::List::empty(),
};
}
@ -124,6 +127,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// We use an `IndexSet` to preserve order of insertion.
// Preserving the order of insertion is important here so as not to break UI tests.
let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default();
let mut effects_min_tys = Vec::new();
let hir_generics = node.generics().unwrap_or(NO_GENERICS);
if let Node::Item(item) = node {
@ -150,11 +154,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// on a trait we must also consider the bounds that follow the trait's name,
// like `trait Foo: A + B + C`.
if let Some(self_bounds) = is_trait {
predicates.extend(
icx.lowerer()
.lower_mono_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All)
.clauses(),
let bounds = icx.lowerer().lower_mono_bounds(
tcx.types.self_param,
self_bounds,
PredicateFilter::All,
);
predicates.extend(bounds.clauses(tcx));
effects_min_tys.extend(bounds.effects_min_tys());
}
// In default impls, we can assume that the self type implements
@ -187,7 +193,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
param.span,
);
trace!(?bounds);
predicates.extend(bounds.clauses());
predicates.extend(bounds.clauses(tcx));
trace!(?predicates);
}
hir::GenericParamKind::Const { .. } => {
@ -238,7 +244,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
bound_vars,
OnlySelfBounds(false),
);
predicates.extend(bounds.clauses());
predicates.extend(bounds.clauses(tcx));
effects_min_tys.extend(bounds.effects_min_tys());
}
hir::WherePredicate::RegionPredicate(region_pred) => {
@ -297,7 +304,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// and the duplicated parameter, to ensure that they do not get out of sync.
if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
let opaque_ty_node = tcx.parent_hir_node(hir_id);
let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node
else {
bug!("unexpected {opaque_ty_node:?}")
};
debug!(?lifetimes);
@ -306,9 +314,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
debug!(?predicates);
}
// add `Self::Effects: Compat<HOST>` to ensure non-const impls don't get called
// in const contexts.
if let Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(..), .. }) = node
&& let Some(host_effect_index) = generics.host_effect_index
{
let parent = generics.parent.unwrap();
let Some(assoc_def_id) = tcx.associated_type_for_effects(parent) else {
bug!("associated_type_for_effects returned None when there is host effect in generics");
};
let effects =
Ty::new_projection(tcx, assoc_def_id, ty::GenericArgs::identity_for_item(tcx, parent));
let param = generics.param_at(host_effect_index, tcx);
let span = tcx.def_span(param.def_id);
let host = ty::Const::new_param(tcx, ty::ParamConst::for_def(param));
let compat = tcx.require_lang_item(LangItem::EffectsCompat, Some(span));
let trait_ref =
ty::TraitRef::new(tcx, compat, [ty::GenericArg::from(effects), host.into()]);
predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span));
}
ty::GenericPredicates {
parent: generics.parent,
predicates: tcx.arena.alloc_from_iter(predicates),
effects_min_tys: tcx.mk_type_list(&effects_min_tys),
}
}
@ -459,6 +488,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
ty::GenericPredicates {
parent: predicates_and_bounds.parent,
predicates: tcx.arena.alloc_slice(&predicates),
effects_min_tys: predicates_and_bounds.effects_min_tys,
}
}
} else {
@ -510,6 +540,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
return GenericPredicates {
parent: parent_preds.parent,
predicates: { tcx.arena.alloc_from_iter(filtered_predicates) },
effects_min_tys: parent_preds.effects_min_tys,
};
}
gather_explicit_predicates_of(tcx, def_id)
@ -519,21 +550,21 @@ pub(super) fn explicit_predicates_of<'tcx>(
/// Ensures that the super-predicates of the trait with a `DefId`
/// of `trait_def_id` are lowered and stored. This also ensures that
/// the transitive super-predicates are lowered.
pub(super) fn super_predicates_of(
pub(super) fn explicit_super_predicates_of(
tcx: TyCtxt<'_>,
trait_def_id: LocalDefId,
) -> ty::GenericPredicates<'_> {
implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::SelfOnly)
}
pub(super) fn super_predicates_that_define_assoc_item(
pub(super) fn explicit_supertraits_containing_assoc_item(
tcx: TyCtxt<'_>,
(trait_def_id, assoc_name): (DefId, Ident),
) -> ty::GenericPredicates<'_> {
implied_predicates_with_filter(tcx, trait_def_id, PredicateFilter::SelfThatDefines(assoc_name))
}
pub(super) fn implied_predicates_of(
pub(super) fn explicit_implied_predicates_of(
tcx: TyCtxt<'_>,
trait_def_id: LocalDefId,
) -> ty::GenericPredicates<'_> {
@ -560,7 +591,7 @@ pub(super) fn implied_predicates_with_filter(
// if `assoc_name` is None, then the query should've been redirected to an
// external provider
assert!(matches!(filter, PredicateFilter::SelfThatDefines(_)));
return tcx.super_predicates_of(trait_def_id);
return tcx.explicit_super_predicates_of(trait_def_id);
};
let Node::Item(item) = tcx.hir_node_by_def_id(trait_def_id) else {
@ -587,7 +618,7 @@ pub(super) fn implied_predicates_with_filter(
// Combine the two lists to form the complete set of superbounds:
let implied_bounds =
&*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match));
&*tcx.arena.alloc_from_iter(superbounds.clauses(tcx).chain(where_bounds_that_match));
debug!(?implied_bounds);
// Now require that immediate supertraits are lowered, which will, in
@ -601,7 +632,7 @@ pub(super) fn implied_predicates_with_filter(
if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder()
&& bound.polarity == ty::PredicatePolarity::Positive
{
tcx.at(span).super_predicates_of(bound.def_id());
tcx.at(span).explicit_super_predicates_of(bound.def_id());
}
}
}
@ -611,14 +642,18 @@ pub(super) fn implied_predicates_with_filter(
if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder()
&& bound.polarity == ty::PredicatePolarity::Positive
{
tcx.at(span).implied_predicates_of(bound.def_id());
tcx.at(span).explicit_implied_predicates_of(bound.def_id());
}
}
}
_ => {}
}
ty::GenericPredicates { parent: None, predicates: implied_bounds }
ty::GenericPredicates {
parent: None,
predicates: implied_bounds,
effects_min_tys: ty::List::empty(),
}
}
/// Returns the predicates defined on `item_def_id` of the form
@ -744,7 +779,7 @@ impl<'tcx> ItemCtxt<'tcx> {
);
}
bounds.clauses().collect()
bounds.clauses(self.tcx).collect()
}
#[instrument(level = "trace", skip(self))]

View file

@ -951,7 +951,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
self.visit_ty(ty);
}
}
GenericParamKind::Const { ty, default, is_host_effect: _ } => {
GenericParamKind::Const { ty, default, .. } => {
self.visit_ty(ty);
if let Some(default) = default {
self.visit_body(self.tcx.hir().body(default.body));
@ -1760,7 +1760,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
if let Some(assoc_item) = trait_defines_associated_item_named(def_id) {
break Some((bound_vars.into_iter().collect(), assoc_item));
}
let predicates = tcx.super_predicates_that_define_assoc_item((def_id, assoc_name));
let predicates = tcx.explicit_supertraits_containing_assoc_item((def_id, assoc_name));
let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
let bound_predicate = pred.kind();
match bound_predicate.skip_binder() {

View file

@ -1699,3 +1699,9 @@ pub struct InvalidReceiverTy<'tcx> {
pub span: Span,
pub receiver_ty: Ty<'tcx>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_effects_without_next_solver)]
#[note]
#[help]
pub struct EffectsWithoutNextSolver;

View file

@ -256,6 +256,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
| GenericParamDefKind::Lifetime,
_,
) => {
// FIXME(effects): this should be removed
// SPECIAL CASE FOR DESUGARED EFFECT PARAMS
// This comes from the following example:
//
@ -445,7 +446,7 @@ pub(crate) fn check_generic_arg_count(
.own_params
.iter()
.filter(|param| {
matches!(param.kind, ty::GenericParamDefKind::Const { is_host_effect: true, .. })
matches!(param.kind, ty::GenericParamDefKind::Const { synthetic: true, .. })
})
.count();
let named_const_param_count = param_counts.consts - synth_const_param_count;

View file

@ -698,7 +698,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
);
debug!(?poly_trait_ref);
bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
bounds.push_trait_bound(
tcx,
self.item_def_id().to_def_id(),
poly_trait_ref,
span,
polarity,
constness,
);
let mut dup_constraints = FxIndexMap::default();
for constraint in trait_segment.args().constraints {

View file

@ -59,7 +59,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut trait_bounds = vec![];
let mut projection_bounds = vec![];
for (pred, span) in bounds.clauses() {
for (pred, span) in bounds.clauses(tcx) {
let bound_pred = pred.kind();
match bound_pred.skip_binder() {
ty::ClauseKind::Trait(trait_pred) => {
@ -133,7 +133,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
tcx.associated_items(pred.def_id())
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| !item.is_impl_trait_in_trait())
.filter(|item| {
!item.is_impl_trait_in_trait() && !item.is_effects_desugaring
})
.map(|item| item.def_id),
);
}

View file

@ -151,6 +151,12 @@ pub fn provide(providers: &mut Providers) {
pub fn check_crate(tcx: TyCtxt<'_>) {
let _prof_timer = tcx.sess.timer("type_check_crate");
// FIXME(effects): remove once effects is implemented in old trait solver
// or if the next solver is stabilized.
if tcx.features().effects && !tcx.next_trait_solver_globally() {
tcx.dcx().emit_err(errors::EffectsWithoutNextSolver);
}
tcx.sess.time("coherence_checking", || {
tcx.hir().par_for_each_module(|module| {
let _ = tcx.ensure().check_mod_type_wf(module);
@ -169,6 +175,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
tcx.sess.time("variance_dumping", || variance::dump::variances(tcx));
collect::dump::opaque_hidden_types(tcx);
collect::dump::predicates_and_item_bounds(tcx);
collect::dump::def_parents(tcx);
}
// Make sure we evaluate all static and (non-associated) const items, even if unused.

View file

@ -585,6 +585,7 @@ impl<'a> State<'a> {
self.print_struct(struct_def, generics, item.ident.name, item.span, true);
}
hir::ItemKind::Impl(&hir::Impl {
constness,
safety,
polarity,
defaultness,
@ -599,6 +600,10 @@ impl<'a> State<'a> {
self.print_safety(safety);
self.word_nbsp("impl");
if let hir::Constness::Const = constness {
self.word_nbsp("const");
}
if !generics.params.is_empty() {
self.print_generic_params(generics.params);
self.space();
@ -2144,7 +2149,7 @@ impl<'a> State<'a> {
self.print_type(default);
}
}
GenericParamKind::Const { ty, ref default, is_host_effect: _ } => {
GenericParamKind::Const { ty, ref default, is_host_effect: _, synthetic: _ } => {
self.word_space(":");
self.print_type(ty);
if let Some(default) = default {

View file

@ -319,7 +319,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
} else {
errors::CannotCastToBoolHelp::Unsupported(self.span)
};
fcx.tcx.dcx().emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help });
fcx.dcx().emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help });
}
CastError::CastToChar => {
let mut err = type_error_struct!(

View file

@ -1797,16 +1797,16 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
err.subdiagnostic(SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends });
}
fn report_return_mismatched_types<'a>(
fn report_return_mismatched_types<'infcx>(
&self,
cause: &ObligationCause<'tcx>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
ty_err: TypeError<'tcx>,
fcx: &FnCtxt<'a, 'tcx>,
fcx: &'infcx FnCtxt<'_, 'tcx>,
block_or_return_id: hir::HirId,
expression: Option<&'tcx hir::Expr<'tcx>>,
) -> Diag<'a> {
) -> Diag<'infcx> {
let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
let due_to_block = matches!(fcx.tcx.hir_node(block_or_return_id), hir::Node::Block(..));

View file

@ -172,21 +172,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
pub fn demand_suptype_diag(
&self,
&'a self,
sp: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> Result<(), Diag<'tcx>> {
) -> Result<(), Diag<'a>> {
self.demand_suptype_with_origin(&self.misc(sp), expected, actual)
}
#[instrument(skip(self), level = "debug")]
pub fn demand_suptype_with_origin(
&self,
&'a self,
cause: &ObligationCause<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> Result<(), Diag<'tcx>> {
) -> Result<(), Diag<'a>> {
self.at(cause, self.param_env)
.sup(DefineOpaqueTypes::Yes, expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
@ -200,20 +200,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
pub fn demand_eqtype_diag(
&self,
&'a self,
sp: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> Result<(), Diag<'tcx>> {
) -> Result<(), Diag<'a>> {
self.demand_eqtype_with_origin(&self.misc(sp), expected, actual)
}
pub fn demand_eqtype_with_origin(
&self,
&'a self,
cause: &ObligationCause<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> Result<(), Diag<'tcx>> {
) -> Result<(), Diag<'a>> {
self.at(cause, self.param_env)
.eq(DefineOpaqueTypes::Yes, expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
@ -247,13 +247,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// will be permitted if the diverges flag is currently "always".
#[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
pub fn demand_coerce_diag(
&self,
&'a self,
mut expr: &'tcx hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
allow_two_phase: AllowTwoPhase,
) -> Result<Ty<'tcx>, Diag<'tcx>> {
) -> Result<Ty<'tcx>, Diag<'a>> {
let expected = self.resolve_vars_with_obligations(expected);
let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) {

View file

@ -638,7 +638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Set expectation to error in that case and set tainted
// by error (#114529)
let coerce_to = opt_coerce_to.unwrap_or_else(|| {
let guar = tcx.dcx().span_delayed_bug(
let guar = self.dcx().span_delayed_bug(
expr.span,
"illegal break with value found but no error reported",
);
@ -1716,7 +1716,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
error_happened = true;
let guar = if let Some(prev_span) = seen_fields.get(&ident) {
tcx.dcx().emit_err(FieldMultiplySpecifiedInInitializer {
self.dcx().emit_err(FieldMultiplySpecifiedInInitializer {
span: field.ident.span,
prev_span: *prev_span,
ident,
@ -1757,7 +1757,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if adt_kind == AdtKind::Union {
if hir_fields.len() != 1 {
struct_span_code_err!(
tcx.dcx(),
self.dcx(),
span,
E0784,
"union expressions should have exactly one field",

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