Auto merge of #136331 - jhpratt:rollup-curo1f4, r=jhpratt
Rollup of 8 pull requests Successful merges: - #135414 (Stabilize `const_black_box`) - #136150 (ci: use windows 2025 for i686-mingw) - #136258 (rustdoc: rename `issue-\d+.rs` tests to have meaningful names (part 11)) - #136270 (Remove `NamedVarMap`.) - #136278 (add constraint graph to polonius MIR dump) - #136287 (LLVM changed the nocapture attribute to captures(none)) - #136291 (some test suite cleanups) - #136296 (float::min/max: mention the non-determinism around signed 0) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
25a16572a3
51 changed files with 287 additions and 188 deletions
|
@ -1,17 +1,19 @@
|
|||
use std::io;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::pretty::{
|
||||
PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
|
||||
};
|
||||
use rustc_middle::mir::{Body, ClosureRegionRequirements};
|
||||
use rustc_middle::mir::{Body, ClosureRegionRequirements, Location};
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::points::PointIndex;
|
||||
use rustc_session::config::MirIncludeSpans;
|
||||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
|
||||
use crate::region_infer::values::LivenessValues;
|
||||
use crate::type_check::Locations;
|
||||
use crate::{BorrowckInferCtxt, RegionInferenceContext};
|
||||
|
||||
|
@ -80,14 +82,27 @@ fn emit_polonius_dump<'tcx>(
|
|||
body,
|
||||
regioncx,
|
||||
borrow_set,
|
||||
localized_outlives_constraints,
|
||||
&localized_outlives_constraints,
|
||||
closure_region_requirements,
|
||||
out,
|
||||
)?;
|
||||
writeln!(out, "</code></pre>")?;
|
||||
writeln!(out, "</div>")?;
|
||||
|
||||
// Section 2: mermaid visualization of the CFG.
|
||||
// Section 2: mermaid visualization of the polonius constraint graph.
|
||||
writeln!(out, "<div>")?;
|
||||
writeln!(out, "Polonius constraint graph")?;
|
||||
writeln!(out, "<pre class='mermaid'>")?;
|
||||
let edge_count = emit_mermaid_constraint_graph(
|
||||
borrow_set,
|
||||
regioncx.liveness_constraints(),
|
||||
&localized_outlives_constraints,
|
||||
out,
|
||||
)?;
|
||||
writeln!(out, "</pre>")?;
|
||||
writeln!(out, "</div>")?;
|
||||
|
||||
// Section 3: mermaid visualization of the CFG.
|
||||
writeln!(out, "<div>")?;
|
||||
writeln!(out, "Control-flow graph")?;
|
||||
writeln!(out, "<pre class='mermaid'>")?;
|
||||
|
@ -95,7 +110,7 @@ fn emit_polonius_dump<'tcx>(
|
|||
writeln!(out, "</pre>")?;
|
||||
writeln!(out, "</div>")?;
|
||||
|
||||
// Section 3: mermaid visualization of the NLL region graph.
|
||||
// Section 4: mermaid visualization of the NLL region graph.
|
||||
writeln!(out, "<div>")?;
|
||||
writeln!(out, "NLL regions")?;
|
||||
writeln!(out, "<pre class='mermaid'>")?;
|
||||
|
@ -103,7 +118,7 @@ fn emit_polonius_dump<'tcx>(
|
|||
writeln!(out, "</pre>")?;
|
||||
writeln!(out, "</div>")?;
|
||||
|
||||
// Section 4: mermaid visualization of the NLL SCC graph.
|
||||
// Section 5: mermaid visualization of the NLL SCC graph.
|
||||
writeln!(out, "<div>")?;
|
||||
writeln!(out, "NLL SCCs")?;
|
||||
writeln!(out, "<pre class='mermaid'>")?;
|
||||
|
@ -117,7 +132,11 @@ fn emit_polonius_dump<'tcx>(
|
|||
"<script src='https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js'></script>"
|
||||
)?;
|
||||
writeln!(out, "<script>")?;
|
||||
writeln!(out, "mermaid.initialize({{ startOnLoad: false, maxEdges: 100 }});")?;
|
||||
writeln!(
|
||||
out,
|
||||
"mermaid.initialize({{ startOnLoad: false, maxEdges: {} }});",
|
||||
edge_count.max(100),
|
||||
)?;
|
||||
writeln!(out, "mermaid.run({{ querySelector: '.mermaid' }})")?;
|
||||
writeln!(out, "</script>")?;
|
||||
writeln!(out, "</body>")?;
|
||||
|
@ -132,7 +151,7 @@ fn emit_html_mir<'tcx>(
|
|||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
localized_outlives_constraints: LocalizedOutlivesConstraintSet,
|
||||
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
|
@ -160,7 +179,7 @@ fn emit_html_mir<'tcx>(
|
|||
regioncx,
|
||||
closure_region_requirements,
|
||||
borrow_set,
|
||||
&localized_outlives_constraints,
|
||||
localized_outlives_constraints,
|
||||
pass_where,
|
||||
out,
|
||||
)
|
||||
|
@ -392,3 +411,76 @@ fn emit_mermaid_nll_sccs<'tcx>(
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits a mermaid flowchart of the polonius localized outlives constraints, with subgraphs per
|
||||
/// region, and loan introductions.
|
||||
fn emit_mermaid_constraint_graph<'tcx>(
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
liveness: &LivenessValues,
|
||||
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<usize> {
|
||||
let location_name = |location: Location| {
|
||||
// A MIR location looks like `bb5[2]`. As that is not a syntactically valid mermaid node id,
|
||||
// transform it into `BB5_2`.
|
||||
format!("BB{}_{}", location.block.index(), location.statement_index)
|
||||
};
|
||||
let region_name = |region: RegionVid| format!("'{}", region.index());
|
||||
let node_name = |region: RegionVid, point: PointIndex| {
|
||||
let location = liveness.location_from_point(point);
|
||||
format!("{}_{}", region_name(region), location_name(location))
|
||||
};
|
||||
|
||||
// The mermaid chart type: a top-down flowchart, which supports subgraphs.
|
||||
writeln!(out, "flowchart TD")?;
|
||||
|
||||
// The loans subgraph: a node per loan.
|
||||
writeln!(out, " subgraph \"Loans\"")?;
|
||||
for loan_idx in 0..borrow_set.len() {
|
||||
writeln!(out, " L{loan_idx}")?;
|
||||
}
|
||||
writeln!(out, " end\n")?;
|
||||
|
||||
// And an edge from that loan node to where it enters the constraint graph.
|
||||
for (loan_idx, loan) in borrow_set.iter_enumerated() {
|
||||
writeln!(
|
||||
out,
|
||||
" L{} --> {}_{}",
|
||||
loan_idx.index(),
|
||||
region_name(loan.region),
|
||||
location_name(loan.reserve_location),
|
||||
)?;
|
||||
}
|
||||
writeln!(out, "")?;
|
||||
|
||||
// The regions subgraphs containing the region/point nodes.
|
||||
let mut points_per_region: FxIndexMap<RegionVid, FxIndexSet<PointIndex>> =
|
||||
FxIndexMap::default();
|
||||
for constraint in &localized_outlives_constraints.outlives {
|
||||
points_per_region.entry(constraint.source).or_default().insert(constraint.from);
|
||||
points_per_region.entry(constraint.target).or_default().insert(constraint.to);
|
||||
}
|
||||
for (region, points) in points_per_region {
|
||||
writeln!(out, " subgraph \"{}\"", region_name(region))?;
|
||||
for point in points {
|
||||
writeln!(out, " {}", node_name(region, point))?;
|
||||
}
|
||||
writeln!(out, " end\n")?;
|
||||
}
|
||||
|
||||
// The constraint graph edges.
|
||||
for constraint in &localized_outlives_constraints.outlives {
|
||||
// FIXME: add killed loans and constraint kind as edge labels.
|
||||
writeln!(
|
||||
out,
|
||||
" {} --> {}",
|
||||
node_name(constraint.source, constraint.from),
|
||||
node_name(constraint.target, constraint.to),
|
||||
)?;
|
||||
}
|
||||
|
||||
// Return the number of edges: this is the biggest graph in the dump and its edge count will be
|
||||
// mermaid's max edge count to support.
|
||||
let edge_count = borrow_set.len() + localized_outlives_constraints.outlives.len();
|
||||
Ok(edge_count)
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
// Run-time:
|
||||
// status: 0
|
||||
|
||||
#![feature(const_black_box)]
|
||||
|
||||
/*
|
||||
* Code
|
||||
*/
|
||||
|
|
|
@ -12,13 +12,11 @@ use std::ops::ControlFlow;
|
|||
|
||||
use rustc_ast::visit::walk_list;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
|
||||
use rustc_hir::{
|
||||
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap,
|
||||
LifetimeName, Node,
|
||||
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeName, Node,
|
||||
};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
|
@ -26,7 +24,7 @@ use rustc_middle::middle::resolve_bound_vars::*;
|
|||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::def_id::{DefId, LocalDefId, LocalDefIdMap};
|
||||
use rustc_span::def_id::{DefId, LocalDefId};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use tracing::{debug, debug_span, instrument};
|
||||
|
||||
|
@ -62,33 +60,9 @@ impl ResolvedArg {
|
|||
}
|
||||
}
|
||||
|
||||
/// Maps the id of each bound variable reference to the variable decl
|
||||
/// that it corresponds to.
|
||||
///
|
||||
/// FIXME. This struct gets converted to a `ResolveBoundVars` for
|
||||
/// actual use. It has the same data, but indexed by `LocalDefId`. This
|
||||
/// is silly.
|
||||
#[derive(Debug, Default)]
|
||||
struct NamedVarMap {
|
||||
// maps from every use of a named (not anonymous) bound var to a
|
||||
// `ResolvedArg` describing how that variable is bound
|
||||
defs: ItemLocalMap<ResolvedArg>,
|
||||
|
||||
// Maps relevant hir items to the bound vars on them. These include:
|
||||
// - function defs
|
||||
// - function pointers
|
||||
// - closures
|
||||
// - trait refs
|
||||
// - bound types (like `T` in `for<'a> T<'a>: Foo`)
|
||||
late_bound_vars: ItemLocalMap<Vec<ty::BoundVariableKind>>,
|
||||
|
||||
// List captured variables for each opaque type.
|
||||
opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>,
|
||||
}
|
||||
|
||||
struct BoundVarContext<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
map: &'a mut NamedVarMap,
|
||||
rbv: &'a mut ResolveBoundVars,
|
||||
scope: ScopeRef<'a>,
|
||||
}
|
||||
|
||||
|
@ -267,19 +241,12 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
|
||||
/// Computes the `ResolveBoundVars` map that contains data for an entire `Item`.
|
||||
/// You should not read the result of this query directly, but rather use
|
||||
/// `named_variable_map`, `is_late_bound_map`, etc.
|
||||
/// `named_variable_map`, `late_bound_vars_map`, etc.
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars {
|
||||
let mut named_variable_map = NamedVarMap {
|
||||
defs: Default::default(),
|
||||
late_bound_vars: Default::default(),
|
||||
opaque_captured_lifetimes: Default::default(),
|
||||
};
|
||||
let mut visitor = BoundVarContext {
|
||||
tcx,
|
||||
map: &mut named_variable_map,
|
||||
scope: &Scope::Root { opt_parent_item: None },
|
||||
};
|
||||
let mut rbv = ResolveBoundVars::default();
|
||||
let mut visitor =
|
||||
BoundVarContext { tcx, rbv: &mut rbv, scope: &Scope::Root { opt_parent_item: None } };
|
||||
match tcx.hir_owner_node(local_def_id) {
|
||||
hir::OwnerNode::Item(item) => visitor.visit_item(item),
|
||||
hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
|
||||
|
@ -299,19 +266,10 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou
|
|||
hir::OwnerNode::Synthetic => unreachable!(),
|
||||
}
|
||||
|
||||
let defs = named_variable_map.defs.into_sorted_stable_ord();
|
||||
let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord();
|
||||
let opaque_captured_lifetimes = named_variable_map.opaque_captured_lifetimes;
|
||||
let rl = ResolveBoundVars {
|
||||
defs: SortedMap::from_presorted_elements(defs),
|
||||
late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars),
|
||||
opaque_captured_lifetimes,
|
||||
};
|
||||
|
||||
debug!(?rl.defs);
|
||||
debug!(?rl.late_bound_vars);
|
||||
debug!(?rl.opaque_captured_lifetimes);
|
||||
rl
|
||||
debug!(?rbv.defs);
|
||||
debug!(?rbv.late_bound_vars);
|
||||
debug!(?rbv.opaque_captured_lifetimes);
|
||||
rbv
|
||||
}
|
||||
|
||||
fn late_arg_as_bound_arg<'tcx>(
|
||||
|
@ -404,7 +362,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
Scope::Binder { hir_id, .. } => {
|
||||
// Nested poly trait refs have the binders concatenated
|
||||
let mut full_binders =
|
||||
self.map.late_bound_vars.entry(hir_id.local_id).or_default().clone();
|
||||
self.rbv.late_bound_vars.get_mut_or_insert_default(hir_id.local_id).clone();
|
||||
full_binders.extend(supertrait_bound_vars);
|
||||
break (full_binders, BinderScopeType::Concatenating);
|
||||
}
|
||||
|
@ -646,7 +604,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
|
||||
let captures = captures.into_inner().into_iter().collect();
|
||||
debug!(?captures);
|
||||
self.map.opaque_captured_lifetimes.insert(opaque.def_id, captures);
|
||||
self.rbv.opaque_captured_lifetimes.insert(opaque.def_id, captures);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
@ -848,7 +806,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
hir::TyKind::Ref(lifetime_ref, ref mt) => {
|
||||
self.visit_lifetime(lifetime_ref);
|
||||
let scope = Scope::ObjectLifetimeDefault {
|
||||
lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
|
||||
lifetime: self.rbv.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
|
||||
s: self.scope,
|
||||
};
|
||||
self.with(scope, |this| this.visit_ty_unambig(mt.ty));
|
||||
|
@ -966,7 +924,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
let bound_vars: Vec<_> =
|
||||
self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect();
|
||||
let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
|
||||
self.map.late_bound_vars.insert(hir_id.local_id, bound_vars);
|
||||
self.rbv.late_bound_vars.insert(hir_id.local_id, bound_vars);
|
||||
}
|
||||
self.visit_fn_like_elision(fd.inputs, output, matches!(fk, intravisit::FnKind::Closure));
|
||||
intravisit::walk_fn_kind(self, fk);
|
||||
|
@ -1140,8 +1098,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
where
|
||||
F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>),
|
||||
{
|
||||
let BoundVarContext { tcx, map, .. } = self;
|
||||
let mut this = BoundVarContext { tcx: *tcx, map, scope: &wrap_scope };
|
||||
let BoundVarContext { tcx, rbv, .. } = self;
|
||||
let mut this = BoundVarContext { tcx: *tcx, rbv, scope: &wrap_scope };
|
||||
let span = debug_span!("scope", scope = ?this.scope.debug_truncated());
|
||||
{
|
||||
let _enter = span.enter();
|
||||
|
@ -1150,10 +1108,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec<ty::BoundVariableKind>) {
|
||||
if let Some(old) = self.map.late_bound_vars.insert(hir_id.local_id, binder) {
|
||||
if let Some(old) = self.rbv.late_bound_vars.insert(hir_id.local_id, binder) {
|
||||
bug!(
|
||||
"overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}",
|
||||
self.map.late_bound_vars[&hir_id.local_id]
|
||||
self.rbv.late_bound_vars[&hir_id.local_id]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1597,9 +1555,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
kind.descr(param_def_id.to_def_id())
|
||||
),
|
||||
};
|
||||
self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
|
||||
self.rbv.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
|
||||
} else {
|
||||
self.map.defs.insert(hir_id.local_id, def);
|
||||
self.rbv.defs.insert(hir_id.local_id, def);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1632,7 +1590,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id()))
|
||||
}
|
||||
});
|
||||
self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
|
||||
self.rbv.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
|
||||
return;
|
||||
}
|
||||
Scope::Root { .. } => break,
|
||||
|
@ -1725,7 +1683,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let map = &self.map;
|
||||
let rbv = &self.rbv;
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
|
||||
// `type_def_id` points to an item, so there is nothing to inherit generics from.
|
||||
|
@ -1744,7 +1702,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
// This index can be used with `generic_args` since `parent_count == 0`.
|
||||
let index = generics.param_def_id_to_index[¶m_def_id] as usize;
|
||||
generic_args.args.get(index).and_then(|arg| match arg {
|
||||
GenericArg::Lifetime(lt) => map.defs.get(<.hir_id.local_id).copied(),
|
||||
GenericArg::Lifetime(lt) => rbv.defs.get(<.hir_id.local_id).copied(),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
@ -2042,7 +2000,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
#[instrument(level = "debug", skip(self))]
|
||||
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: ResolvedArg) {
|
||||
debug!(span = ?lifetime_ref.ident.span);
|
||||
self.map.defs.insert(lifetime_ref.hir_id.local_id, def);
|
||||
self.rbv.defs.insert(lifetime_ref.hir_id.local_id, def);
|
||||
}
|
||||
|
||||
// When we have a return type notation type in a where clause, like
|
||||
|
@ -2197,7 +2155,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
// See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`.
|
||||
// And this is exercised in:
|
||||
// `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`.
|
||||
let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id.local_id).unwrap();
|
||||
let existing_bound_vars = self.rbv.late_bound_vars.get_mut(&hir_id.local_id).unwrap();
|
||||
let existing_bound_vars_saved = existing_bound_vars.clone();
|
||||
existing_bound_vars.extend(bound_vars);
|
||||
self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved);
|
||||
|
|
|
@ -319,7 +319,11 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
|
|||
case LLVMRustAttributeKind::NoAlias:
|
||||
return Attribute::NoAlias;
|
||||
case LLVMRustAttributeKind::NoCapture:
|
||||
#if LLVM_VERSION_GE(21, 0)
|
||||
report_fatal_error("NoCapture doesn't exist in LLVM 21");
|
||||
#else
|
||||
return Attribute::NoCapture;
|
||||
#endif
|
||||
case LLVMRustAttributeKind::NoCfCheck:
|
||||
return Attribute::NoCfCheck;
|
||||
case LLVMRustAttributeKind::NoInline:
|
||||
|
@ -431,6 +435,12 @@ extern "C" void LLVMRustEraseInstFromParent(LLVMValueRef Instr) {
|
|||
|
||||
extern "C" LLVMAttributeRef
|
||||
LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
|
||||
#if LLVM_VERSION_GE(21, 0)
|
||||
// LLVM 21 replaced the NoCapture attribute with Captures(none).
|
||||
if (RustAttr == LLVMRustAttributeKind::NoCapture) {
|
||||
return wrap(Attribute::getWithCaptureInfo(*unwrap(C), CaptureInfo::none()));
|
||||
}
|
||||
#endif
|
||||
return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr)));
|
||||
}
|
||||
|
||||
|
|
|
@ -45,15 +45,22 @@ pub enum ObjectLifetimeDefault {
|
|||
Param(DefId),
|
||||
}
|
||||
|
||||
/// Maps the id of each lifetime reference to the lifetime decl
|
||||
/// Maps the id of each bound variable reference to the variable decl
|
||||
/// that it corresponds to.
|
||||
#[derive(HashStable, Debug)]
|
||||
#[derive(Debug, Default, HashStable)]
|
||||
pub struct ResolveBoundVars {
|
||||
/// Maps from every use of a named (not anonymous) lifetime to a
|
||||
/// `Region` describing how that region is bound
|
||||
// Maps from every use of a named (not anonymous) bound var to a
|
||||
// `ResolvedArg` describing how that variable is bound.
|
||||
pub defs: SortedMap<ItemLocalId, ResolvedArg>,
|
||||
|
||||
// Maps relevant hir items to the bound vars on them. These include:
|
||||
// - function defs
|
||||
// - function pointers
|
||||
// - closures
|
||||
// - trait refs
|
||||
// - bound types (like `T` in `for<'a> T<'a>: Foo`)
|
||||
pub late_bound_vars: SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>>,
|
||||
|
||||
// List captured variables for each opaque type.
|
||||
pub opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue