Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5d76a13

Browse files
committedJul 12, 2024
Auto merge of rust-lang#127653 - matthiaskrgr:rollup-72bqgvp, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - rust-lang#124980 (Generalize `fn allocator` for Rc/Arc.) - rust-lang#126639 (Add AMX target-features and `x86_amx_intrinsics` feature flag) - rust-lang#126827 (Use pidfd_spawn for faster process spawning when a PidFd is requested) - rust-lang#127433 (Stabilize const_cstr_from_ptr (CStr::from_ptr, CStr::count_bytes)) - rust-lang#127552 (remove unnecessary `git` usages) - rust-lang#127613 (Update dist-riscv64-linux to binutils 2.40) - rust-lang#127627 (generalize search graph to enable fuzzing) - rust-lang#127648 (Lower timeout of CI jobs to 4 hours) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 05eac57 + f11c2c8 commit 5d76a13

File tree

35 files changed

+1408
-807
lines changed

35 files changed

+1408
-807
lines changed
 

‎.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ jobs:
6565
defaults:
6666
run:
6767
shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}
68-
timeout-minutes: 600
68+
timeout-minutes: 240
6969
env:
7070
CI_JOB_NAME: ${{ matrix.image }}
7171
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse

‎compiler/rustc_codegen_ssa/src/target_features.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ pub fn from_target_feature(
8080
Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
8181
Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature,
8282
Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature,
83+
Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics,
8384
Some(name) => bug!("unknown target feature gate {}", name),
8485
None => true,
8586
};

‎compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,8 @@ declare_features! (
640640
(unstable, unsized_tuple_coercion, "1.20.0", Some(42877)),
641641
/// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
642642
(unstable, used_with_arg, "1.60.0", Some(93798)),
643+
/// Allows use of x86 `AMX` target-feature attributes and intrinsics
644+
(unstable, x86_amx_intrinsics, "CURRENT_RUSTC_VERSION", Some(126622)),
643645
/// Allows `do yeet` expressions
644646
(unstable, yeet_expr, "1.62.0", Some(96373)),
645647
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!

‎compiler/rustc_middle/src/traits/solve.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ use crate::ty::{
88
self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
99
};
1010

11-
mod cache;
12-
13-
pub use cache::EvaluationCache;
14-
1511
pub type Goal<'tcx, P> = ir::solve::Goal<TyCtxt<'tcx>, P>;
1612
pub type QueryInput<'tcx, P> = ir::solve::QueryInput<TyCtxt<'tcx>, P>;
1713
pub type QueryResult<'tcx> = ir::solve::QueryResult<TyCtxt<'tcx>>;

‎compiler/rustc_middle/src/traits/solve/cache.rs

Lines changed: 0 additions & 121 deletions
This file was deleted.

‎compiler/rustc_middle/src/ty/context.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ use rustc_hir::lang_items::LangItem;
5959
use rustc_hir::{HirId, Node, TraitCandidate};
6060
use rustc_index::IndexVec;
6161
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
62+
use rustc_query_system::cache::WithDepNode;
6263
use rustc_query_system::dep_graph::DepNodeIndex;
6364
use rustc_query_system::ich::StableHashingContext;
6465
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
@@ -75,7 +76,7 @@ use rustc_type_ir::fold::TypeFoldable;
7576
use rustc_type_ir::lang_items::TraitSolverLangItem;
7677
use rustc_type_ir::solve::SolverMode;
7778
use rustc_type_ir::TyKind::*;
78-
use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo};
79+
use rustc_type_ir::{search_graph, CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo};
7980
use tracing::{debug, instrument};
8081

8182
use std::assert_matches::assert_matches;
@@ -164,12 +165,26 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
164165
type Clause = Clause<'tcx>;
165166
type Clauses = ty::Clauses<'tcx>;
166167

167-
type EvaluationCache = &'tcx solve::EvaluationCache<'tcx>;
168+
type Tracked<T: fmt::Debug + Clone> = WithDepNode<T>;
169+
fn mk_tracked<T: fmt::Debug + Clone>(
170+
self,
171+
data: T,
172+
dep_node: DepNodeIndex,
173+
) -> Self::Tracked<T> {
174+
WithDepNode::new(dep_node, data)
175+
}
176+
fn get_tracked<T: fmt::Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T {
177+
tracked.get(self)
178+
}
168179

169-
fn evaluation_cache(self, mode: SolverMode) -> &'tcx solve::EvaluationCache<'tcx> {
180+
fn with_global_cache<R>(
181+
self,
182+
mode: SolverMode,
183+
f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
184+
) -> R {
170185
match mode {
171-
SolverMode::Normal => &self.new_solver_evaluation_cache,
172-
SolverMode::Coherence => &self.new_solver_coherence_evaluation_cache,
186+
SolverMode::Normal => f(&mut *self.new_solver_evaluation_cache.lock()),
187+
SolverMode::Coherence => f(&mut *self.new_solver_coherence_evaluation_cache.lock()),
173188
}
174189
}
175190

@@ -1283,8 +1298,8 @@ pub struct GlobalCtxt<'tcx> {
12831298
pub evaluation_cache: traits::EvaluationCache<'tcx>,
12841299

12851300
/// Caches the results of goal evaluation in the new solver.
1286-
pub new_solver_evaluation_cache: solve::EvaluationCache<'tcx>,
1287-
pub new_solver_coherence_evaluation_cache: solve::EvaluationCache<'tcx>,
1301+
pub new_solver_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>,
1302+
pub new_solver_coherence_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>,
12881303

12891304
pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>,
12901305

‎compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use crate::delegate::SolverDelegate;
1616
use crate::solve::inspect::{self, ProofTreeBuilder};
1717
use crate::solve::search_graph::SearchGraph;
1818
use crate::solve::{
19-
search_graph, CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind,
20-
GoalSource, MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData,
21-
QueryResult, SolverMode, FIXPOINT_STEP_LIMIT,
19+
CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, GoalSource, MaybeCause,
20+
NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, SolverMode,
21+
FIXPOINT_STEP_LIMIT,
2222
};
2323

2424
pub(super) mod canonical;
@@ -72,7 +72,7 @@ where
7272
/// new placeholders to the caller.
7373
pub(super) max_input_universe: ty::UniverseIndex,
7474

75-
pub(super) search_graph: &'a mut SearchGraph<I>,
75+
pub(super) search_graph: &'a mut SearchGraph<D>,
7676

7777
nested_goals: NestedGoals<I>,
7878

@@ -200,7 +200,7 @@ where
200200
generate_proof_tree: GenerateProofTree,
201201
f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R,
202202
) -> (R, Option<inspect::GoalEvaluation<I>>) {
203-
let mut search_graph = search_graph::SearchGraph::new(delegate.solver_mode());
203+
let mut search_graph = SearchGraph::new(delegate.solver_mode());
204204

205205
let mut ecx = EvalCtxt {
206206
delegate,
@@ -241,7 +241,7 @@ where
241241
/// and registering opaques from the canonicalized input.
242242
fn enter_canonical<R>(
243243
cx: I,
244-
search_graph: &'a mut search_graph::SearchGraph<I>,
244+
search_graph: &'a mut SearchGraph<D>,
245245
canonical_input: CanonicalInput<I>,
246246
canonical_goal_evaluation: &mut ProofTreeBuilder<D>,
247247
f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R,
@@ -296,7 +296,7 @@ where
296296
#[instrument(level = "debug", skip(cx, search_graph, goal_evaluation), ret)]
297297
fn evaluate_canonical_goal(
298298
cx: I,
299-
search_graph: &'a mut search_graph::SearchGraph<I>,
299+
search_graph: &'a mut SearchGraph<D>,
300300
canonical_input: CanonicalInput<I>,
301301
goal_evaluation: &mut ProofTreeBuilder<D>,
302302
) -> QueryResult<I> {

‎compiler/rustc_next_trait_solver/src/solve/inspect/build.rs

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::marker::PhantomData;
88
use std::mem;
99

1010
use rustc_type_ir::inherent::*;
11-
use rustc_type_ir::{self as ty, Interner};
11+
use rustc_type_ir::{self as ty, search_graph, Interner};
1212

1313
use crate::delegate::SolverDelegate;
1414
use crate::solve::eval_ctxt::canonical;
@@ -38,7 +38,7 @@ use crate::solve::{
3838
/// trees. At the end of trait solving `ProofTreeBuilder::finalize`
3939
/// is called to recursively convert the whole structure to a
4040
/// finished proof tree.
41-
pub(in crate::solve) struct ProofTreeBuilder<D, I = <D as SolverDelegate>::Interner>
41+
pub(crate) struct ProofTreeBuilder<D, I = <D as SolverDelegate>::Interner>
4242
where
4343
D: SolverDelegate<Interner = I>,
4444
I: Interner,
@@ -321,23 +321,6 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> {
321321
})
322322
}
323323

324-
pub fn finalize_canonical_goal_evaluation(
325-
&mut self,
326-
cx: I,
327-
) -> Option<I::CanonicalGoalEvaluationStepRef> {
328-
self.as_mut().map(|this| match this {
329-
DebugSolver::CanonicalGoalEvaluation(evaluation) => {
330-
let final_revision = mem::take(&mut evaluation.final_revision).unwrap();
331-
let final_revision =
332-
cx.intern_canonical_goal_evaluation_step(final_revision.finalize());
333-
let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision };
334-
assert_eq!(evaluation.kind.replace(kind), None);
335-
final_revision
336-
}
337-
_ => unreachable!(),
338-
})
339-
}
340-
341324
pub fn canonical_goal_evaluation(&mut self, canonical_goal_evaluation: ProofTreeBuilder<D>) {
342325
if let Some(this) = self.as_mut() {
343326
match (this, *canonical_goal_evaluation.state.unwrap()) {
@@ -571,3 +554,51 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> {
571554
}
572555
}
573556
}
557+
558+
impl<D, I> search_graph::ProofTreeBuilder<I> for ProofTreeBuilder<D>
559+
where
560+
D: SolverDelegate<Interner = I>,
561+
I: Interner,
562+
{
563+
fn try_apply_proof_tree(
564+
&mut self,
565+
proof_tree: Option<I::CanonicalGoalEvaluationStepRef>,
566+
) -> bool {
567+
if !self.is_noop() {
568+
if let Some(final_revision) = proof_tree {
569+
let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision };
570+
self.canonical_goal_evaluation_kind(kind);
571+
true
572+
} else {
573+
false
574+
}
575+
} else {
576+
true
577+
}
578+
}
579+
580+
fn on_provisional_cache_hit(&mut self) {
581+
self.canonical_goal_evaluation_kind(WipCanonicalGoalEvaluationKind::ProvisionalCacheHit);
582+
}
583+
584+
fn on_cycle_in_stack(&mut self) {
585+
self.canonical_goal_evaluation_kind(WipCanonicalGoalEvaluationKind::CycleInStack);
586+
}
587+
588+
fn finalize_canonical_goal_evaluation(
589+
&mut self,
590+
tcx: I,
591+
) -> Option<I::CanonicalGoalEvaluationStepRef> {
592+
self.as_mut().map(|this| match this {
593+
DebugSolver::CanonicalGoalEvaluation(evaluation) => {
594+
let final_revision = mem::take(&mut evaluation.final_revision).unwrap();
595+
let final_revision =
596+
tcx.intern_canonical_goal_evaluation_step(final_revision.finalize());
597+
let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision };
598+
assert_eq!(evaluation.kind.replace(kind), None);
599+
final_revision
600+
}
601+
_ => unreachable!(),
602+
})
603+
}
604+
}

‎compiler/rustc_next_trait_solver/src/solve/search_graph.rs

Lines changed: 57 additions & 566 deletions
Large diffs are not rendered by default.

‎compiler/rustc_query_system/src/cache.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl<Key: Eq + Hash, Value: Clone> Cache<Key, Value> {
4040
}
4141
}
4242

43-
#[derive(Clone, Eq, PartialEq)]
43+
#[derive(Debug, Clone, Eq, PartialEq)]
4444
pub struct WithDepNode<T> {
4545
dep_node: DepNodeIndex,
4646
cached_value: T,

‎compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,6 +2072,7 @@ symbols! {
20722072
write_str,
20732073
write_via_move,
20742074
writeln_macro,
2075+
x86_amx_intrinsics,
20752076
x87_reg,
20762077
xer,
20772078
xmm_reg,

‎compiler/rustc_target/src/target_features.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[
192192
// tidy-alphabetical-start
193193
("adx", Stable),
194194
("aes", Stable),
195+
("amx-bf16", Unstable(sym::x86_amx_intrinsics)),
196+
("amx-complex", Unstable(sym::x86_amx_intrinsics)),
197+
("amx-fp16", Unstable(sym::x86_amx_intrinsics)),
198+
("amx-int8", Unstable(sym::x86_amx_intrinsics)),
199+
("amx-tile", Unstable(sym::x86_amx_intrinsics)),
195200
("avx", Stable),
196201
("avx2", Stable),
197202
("avx512bf16", Unstable(sym::avx512_target_feature)),

‎compiler/rustc_type_ir/src/inherent.rs

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ use std::hash::Hash;
88

99
use rustc_ast_ir::Mutability;
1010

11-
use crate::data_structures::HashSet;
1211
use crate::elaborate::Elaboratable;
1312
use crate::fold::{TypeFoldable, TypeSuperFoldable};
1413
use crate::relate::Relate;
15-
use crate::solve::{CacheData, CanonicalInput, QueryResult, Reveal};
14+
use crate::solve::Reveal;
1615
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
1716
use crate::{self as ty, CollectAndApply, Interner, UpcastFrom};
1817

@@ -539,33 +538,6 @@ pub trait Features<I: Interner>: Copy {
539538
fn associated_const_equality(self) -> bool;
540539
}
541540

542-
pub trait EvaluationCache<I: Interner> {
543-
/// Insert a final result into the global cache.
544-
fn insert(
545-
&self,
546-
tcx: I,
547-
key: CanonicalInput<I>,
548-
proof_tree: Option<I::CanonicalGoalEvaluationStepRef>,
549-
additional_depth: usize,
550-
encountered_overflow: bool,
551-
cycle_participants: HashSet<CanonicalInput<I>>,
552-
dep_node: I::DepNodeIndex,
553-
result: QueryResult<I>,
554-
);
555-
556-
/// Try to fetch a cached result, checking the recursion limit
557-
/// and handling root goals of coinductive cycles.
558-
///
559-
/// If this returns `Some` the cache result can be used.
560-
fn get(
561-
&self,
562-
tcx: I,
563-
key: CanonicalInput<I>,
564-
stack_entries: impl IntoIterator<Item = CanonicalInput<I>>,
565-
available_depth: usize,
566-
) -> Option<CacheData<I>>;
567-
}
568-
569541
pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
570542
fn is_local(self) -> bool;
571543

‎compiler/rustc_type_ir/src/interner.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ use crate::inherent::*;
1010
use crate::ir_print::IrPrint;
1111
use crate::lang_items::TraitSolverLangItem;
1212
use crate::relate::Relate;
13+
use crate::search_graph;
1314
use crate::solve::inspect::CanonicalGoalEvaluationStep;
14-
use crate::solve::{ExternalConstraintsData, PredefinedOpaquesData, SolverMode};
15+
use crate::solve::{
16+
CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode,
17+
};
1518
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
1619
use crate::{self as ty};
1720

@@ -86,6 +89,13 @@ pub trait Interner:
8689
) -> Self::ExternalConstraints;
8790

8891
type DepNodeIndex;
92+
type Tracked<T: Debug + Clone>: Debug;
93+
fn mk_tracked<T: Debug + Clone>(
94+
self,
95+
data: T,
96+
dep_node: Self::DepNodeIndex,
97+
) -> Self::Tracked<T>;
98+
fn get_tracked<T: Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T;
8999
fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex);
90100

91101
// Kinds of tys
@@ -125,8 +135,11 @@ pub trait Interner:
125135
type Clause: Clause<Self>;
126136
type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
127137

128-
type EvaluationCache: EvaluationCache<Self>;
129-
fn evaluation_cache(self, mode: SolverMode) -> Self::EvaluationCache;
138+
fn with_global_cache<R>(
139+
self,
140+
mode: SolverMode,
141+
f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
142+
) -> R;
130143

131144
fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T;
132145

@@ -373,3 +386,32 @@ impl<T, R, E> CollectAndApply<T, R> for Result<T, E> {
373386
})
374387
}
375388
}
389+
390+
impl<I: Interner> search_graph::Cx for I {
391+
type ProofTree = Option<I::CanonicalGoalEvaluationStepRef>;
392+
type Input = CanonicalInput<I>;
393+
type Result = QueryResult<I>;
394+
395+
type DepNodeIndex = I::DepNodeIndex;
396+
type Tracked<T: Debug + Clone> = I::Tracked<T>;
397+
fn mk_tracked<T: Debug + Clone>(
398+
self,
399+
data: T,
400+
dep_node_index: I::DepNodeIndex,
401+
) -> I::Tracked<T> {
402+
I::mk_tracked(self, data, dep_node_index)
403+
}
404+
fn get_tracked<T: Debug + Clone>(self, tracked: &I::Tracked<T>) -> T {
405+
I::get_tracked(self, tracked)
406+
}
407+
fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, I::DepNodeIndex) {
408+
I::with_cached_task(self, task)
409+
}
410+
fn with_global_cache<R>(
411+
self,
412+
mode: SolverMode,
413+
f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
414+
) -> R {
415+
I::with_global_cache(self, mode, f)
416+
}
417+
}

‎compiler/rustc_type_ir/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub mod lang_items;
3030
pub mod lift;
3131
pub mod outlives;
3232
pub mod relate;
33+
pub mod search_graph;
3334
pub mod solve;
3435

3536
// These modules are not `pub` since they are glob-imported.
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use rustc_index::IndexVec;
2+
3+
use super::{AvailableDepth, Cx, StackDepth, StackEntry};
4+
use crate::data_structures::{HashMap, HashSet};
5+
6+
#[derive(derivative::Derivative)]
7+
#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))]
8+
struct QueryData<X: Cx> {
9+
result: X::Result,
10+
proof_tree: X::ProofTree,
11+
}
12+
13+
struct Success<X: Cx> {
14+
data: X::Tracked<QueryData<X>>,
15+
additional_depth: usize,
16+
}
17+
18+
/// The cache entry for a given input.
19+
///
20+
/// This contains results whose computation never hit the
21+
/// recursion limit in `success`, and all results which hit
22+
/// the recursion limit in `with_overflow`.
23+
#[derive(derivative::Derivative)]
24+
#[derivative(Default(bound = ""))]
25+
struct CacheEntry<X: Cx> {
26+
success: Option<Success<X>>,
27+
/// We have to be careful when caching roots of cycles.
28+
///
29+
/// See the doc comment of `StackEntry::cycle_participants` for more
30+
/// details.
31+
nested_goals: HashSet<X::Input>,
32+
with_overflow: HashMap<usize, X::Tracked<QueryData<X>>>,
33+
}
34+
35+
#[derive(derivative::Derivative)]
36+
#[derivative(Debug(bound = ""))]
37+
pub(super) struct CacheData<'a, X: Cx> {
38+
pub(super) result: X::Result,
39+
pub(super) proof_tree: X::ProofTree,
40+
pub(super) additional_depth: usize,
41+
pub(super) encountered_overflow: bool,
42+
// FIXME: This is currently unused, but impacts the design
43+
// by requiring a closure for `Cx::with_global_cache`.
44+
pub(super) nested_goals: &'a HashSet<X::Input>,
45+
}
46+
47+
#[derive(derivative::Derivative)]
48+
#[derivative(Default(bound = ""))]
49+
pub struct GlobalCache<X: Cx> {
50+
map: HashMap<X::Input, CacheEntry<X>>,
51+
}
52+
53+
impl<X: Cx> GlobalCache<X> {
54+
/// Insert a final result into the global cache.
55+
pub(super) fn insert(
56+
&mut self,
57+
cx: X,
58+
input: X::Input,
59+
60+
result: X::Result,
61+
proof_tree: X::ProofTree,
62+
dep_node: X::DepNodeIndex,
63+
64+
additional_depth: usize,
65+
encountered_overflow: bool,
66+
nested_goals: &HashSet<X::Input>,
67+
) {
68+
let data = cx.mk_tracked(QueryData { result, proof_tree }, dep_node);
69+
let entry = self.map.entry(input).or_default();
70+
entry.nested_goals.extend(nested_goals);
71+
if encountered_overflow {
72+
entry.with_overflow.insert(additional_depth, data);
73+
} else {
74+
entry.success = Some(Success { data, additional_depth });
75+
}
76+
}
77+
78+
/// Try to fetch a cached result, checking the recursion limit
79+
/// and handling root goals of coinductive cycles.
80+
///
81+
/// If this returns `Some` the cache result can be used.
82+
pub(super) fn get<'a>(
83+
&'a self,
84+
cx: X,
85+
input: X::Input,
86+
stack: &IndexVec<StackDepth, StackEntry<X>>,
87+
available_depth: AvailableDepth,
88+
) -> Option<CacheData<'a, X>> {
89+
let entry = self.map.get(&input)?;
90+
if stack.iter().any(|e| entry.nested_goals.contains(&e.input)) {
91+
return None;
92+
}
93+
94+
if let Some(ref success) = entry.success {
95+
if available_depth.cache_entry_is_applicable(success.additional_depth) {
96+
let QueryData { result, proof_tree } = cx.get_tracked(&success.data);
97+
return Some(CacheData {
98+
result,
99+
proof_tree,
100+
additional_depth: success.additional_depth,
101+
encountered_overflow: false,
102+
nested_goals: &entry.nested_goals,
103+
});
104+
}
105+
}
106+
107+
entry.with_overflow.get(&available_depth.0).map(|e| {
108+
let QueryData { result, proof_tree } = cx.get_tracked(e);
109+
CacheData {
110+
result,
111+
proof_tree,
112+
additional_depth: available_depth.0,
113+
encountered_overflow: true,
114+
nested_goals: &entry.nested_goals,
115+
}
116+
})
117+
}
118+
}

‎compiler/rustc_type_ir/src/search_graph/mod.rs

Lines changed: 605 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use super::*;
2+
3+
impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
4+
#[allow(rustc::potential_query_instability)]
5+
pub(super) fn check_invariants(&self) {
6+
if !cfg!(debug_assertions) {
7+
return;
8+
}
9+
10+
let SearchGraph { mode: _, stack, provisional_cache, _marker } = self;
11+
if stack.is_empty() {
12+
assert!(provisional_cache.is_empty());
13+
}
14+
15+
for (depth, entry) in stack.iter_enumerated() {
16+
let StackEntry {
17+
input,
18+
available_depth: _,
19+
reached_depth: _,
20+
non_root_cycle_participant,
21+
encountered_overflow: _,
22+
has_been_used,
23+
ref nested_goals,
24+
provisional_result,
25+
} = *entry;
26+
let cache_entry = provisional_cache.get(&entry.input).unwrap();
27+
assert_eq!(cache_entry.stack_depth, Some(depth));
28+
if let Some(head) = non_root_cycle_participant {
29+
assert!(head < depth);
30+
assert!(nested_goals.is_empty());
31+
assert_ne!(stack[head].has_been_used, None);
32+
33+
let mut current_root = head;
34+
while let Some(parent) = stack[current_root].non_root_cycle_participant {
35+
current_root = parent;
36+
}
37+
assert!(stack[current_root].nested_goals.contains(&input));
38+
}
39+
40+
if !nested_goals.is_empty() {
41+
assert!(provisional_result.is_some() || has_been_used.is_some());
42+
for entry in stack.iter().take(depth.as_usize()) {
43+
assert_eq!(nested_goals.get(&entry.input), None);
44+
}
45+
}
46+
}
47+
48+
for (&input, entry) in &self.provisional_cache {
49+
let ProvisionalCacheEntry { stack_depth, with_coinductive_stack, with_inductive_stack } =
50+
entry;
51+
assert!(
52+
stack_depth.is_some()
53+
|| with_coinductive_stack.is_some()
54+
|| with_inductive_stack.is_some()
55+
);
56+
57+
if let &Some(stack_depth) = stack_depth {
58+
assert_eq!(stack[stack_depth].input, input);
59+
}
60+
61+
let check_detached = |detached_entry: &DetachedEntry<X>| {
62+
let DetachedEntry { head, result: _ } = *detached_entry;
63+
assert_ne!(stack[head].has_been_used, None);
64+
};
65+
66+
if let Some(with_coinductive_stack) = with_coinductive_stack {
67+
check_detached(with_coinductive_stack);
68+
}
69+
70+
if let Some(with_inductive_stack) = with_inductive_stack {
71+
check_detached(with_inductive_stack);
72+
}
73+
}
74+
}
75+
}

‎library/alloc/src/rc.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -665,16 +665,6 @@ impl<T> Rc<T> {
665665
}
666666

667667
impl<T, A: Allocator> Rc<T, A> {
668-
/// Returns a reference to the underlying allocator.
669-
///
670-
/// Note: this is an associated function, which means that you have
671-
/// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This
672-
/// is so that there is no conflict with a method on the inner type.
673-
#[inline]
674-
#[unstable(feature = "allocator_api", issue = "32838")]
675-
pub fn allocator(this: &Self) -> &A {
676-
&this.alloc
677-
}
678668
/// Constructs a new `Rc` in the provided allocator.
679669
///
680670
/// # Examples
@@ -1331,6 +1321,17 @@ impl<T: ?Sized> Rc<T> {
13311321
}
13321322

13331323
impl<T: ?Sized, A: Allocator> Rc<T, A> {
1324+
/// Returns a reference to the underlying allocator.
1325+
///
1326+
/// Note: this is an associated function, which means that you have
1327+
/// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This
1328+
/// is so that there is no conflict with a method on the inner type.
1329+
#[inline]
1330+
#[unstable(feature = "allocator_api", issue = "32838")]
1331+
pub fn allocator(this: &Self) -> &A {
1332+
&this.alloc
1333+
}
1334+
13341335
/// Consumes the `Rc`, returning the wrapped pointer.
13351336
///
13361337
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
@@ -2994,6 +2995,13 @@ impl<T: ?Sized> Weak<T> {
29942995
}
29952996

29962997
impl<T: ?Sized, A: Allocator> Weak<T, A> {
2998+
/// Returns a reference to the underlying allocator.
2999+
#[inline]
3000+
#[unstable(feature = "allocator_api", issue = "32838")]
3001+
pub fn allocator(&self) -> &A {
3002+
&self.alloc
3003+
}
3004+
29973005
/// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
29983006
///
29993007
/// The pointer is valid only if there are some strong references. The pointer may be dangling,

‎library/alloc/src/sync.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -677,16 +677,6 @@ impl<T> Arc<T> {
677677
}
678678

679679
impl<T, A: Allocator> Arc<T, A> {
680-
/// Returns a reference to the underlying allocator.
681-
///
682-
/// Note: this is an associated function, which means that you have
683-
/// to call it as `Arc::allocator(&a)` instead of `a.allocator()`. This
684-
/// is so that there is no conflict with a method on the inner type.
685-
#[inline]
686-
#[unstable(feature = "allocator_api", issue = "32838")]
687-
pub fn allocator(this: &Self) -> &A {
688-
&this.alloc
689-
}
690680
/// Constructs a new `Arc<T>` in the provided allocator.
691681
///
692682
/// # Examples
@@ -1470,6 +1460,17 @@ impl<T: ?Sized> Arc<T> {
14701460
}
14711461

14721462
impl<T: ?Sized, A: Allocator> Arc<T, A> {
1463+
/// Returns a reference to the underlying allocator.
1464+
///
1465+
/// Note: this is an associated function, which means that you have
1466+
/// to call it as `Arc::allocator(&a)` instead of `a.allocator()`. This
1467+
/// is so that there is no conflict with a method on the inner type.
1468+
#[inline]
1469+
#[unstable(feature = "allocator_api", issue = "32838")]
1470+
pub fn allocator(this: &Self) -> &A {
1471+
&this.alloc
1472+
}
1473+
14731474
/// Consumes the `Arc`, returning the wrapped pointer.
14741475
///
14751476
/// To avoid a memory leak the pointer must be converted back to an `Arc` using
@@ -2715,6 +2716,13 @@ impl<T: ?Sized> Weak<T> {
27152716
}
27162717

27172718
impl<T: ?Sized, A: Allocator> Weak<T, A> {
2719+
/// Returns a reference to the underlying allocator.
2720+
#[inline]
2721+
#[unstable(feature = "allocator_api", issue = "32838")]
2722+
pub fn allocator(&self) -> &A {
2723+
&self.alloc
2724+
}
2725+
27182726
/// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
27192727
///
27202728
/// The pointer is valid only if there are some strong references. The pointer may be dangling,

‎library/core/src/ffi/c_str.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,6 @@ impl CStr {
263263
/// ```
264264
///
265265
/// ```
266-
/// #![feature(const_cstr_from_ptr)]
267-
///
268266
/// use std::ffi::{c_char, CStr};
269267
///
270268
/// const HELLO_PTR: *const c_char = {
@@ -280,7 +278,7 @@ impl CStr {
280278
#[inline] // inline is necessary for codegen to see strlen.
281279
#[must_use]
282280
#[stable(feature = "rust1", since = "1.0.0")]
283-
#[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")]
281+
#[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")]
284282
pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
285283
// SAFETY: The caller has provided a pointer that points to a valid C
286284
// string with a NUL terminator less than `isize::MAX` from `ptr`.
@@ -542,7 +540,7 @@ impl CStr {
542540
#[must_use]
543541
#[doc(alias("len", "strlen"))]
544542
#[stable(feature = "cstr_count_bytes", since = "1.79.0")]
545-
#[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")]
543+
#[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")]
546544
pub const fn count_bytes(&self) -> usize {
547545
self.inner.len() - 1
548546
}
@@ -742,6 +740,9 @@ impl AsRef<CStr> for CStr {
742740
/// The pointer must point to a valid buffer that contains a NUL terminator. The NUL must be
743741
/// located within `isize::MAX` from `ptr`.
744742
#[inline]
743+
#[unstable(feature = "cstr_internals", issue = "none")]
744+
#[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")]
745+
#[rustc_allow_const_fn_unstable(const_eval_select)]
745746
const unsafe fn const_strlen(ptr: *const c_char) -> usize {
746747
const fn strlen_ct(s: *const c_char) -> usize {
747748
let mut len = 0;

‎library/std/src/sys/pal/unix/linux/pidfd/tests.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::assert_matches::assert_matches;
22
use crate::os::fd::{AsRawFd, RawFd};
3-
use crate::os::linux::process::{ChildExt, CommandExt};
4-
use crate::os::unix::process::ExitStatusExt;
3+
use crate::os::linux::process::{ChildExt, CommandExt as _};
4+
use crate::os::unix::process::{CommandExt as _, ExitStatusExt};
55
use crate::process::Command;
66

77
#[test]
@@ -21,6 +21,7 @@ fn test_command_pidfd() {
2121
let flags = super::cvt(unsafe { libc::fcntl(pidfd.as_raw_fd(), libc::F_GETFD) }).unwrap();
2222
assert!(flags & libc::FD_CLOEXEC != 0);
2323
}
24+
assert!(child.id() > 0 && child.id() < -1i32 as u32);
2425
let status = child.wait().expect("error waiting on pidfd");
2526
assert_eq!(status.code(), Some(1));
2627

@@ -42,6 +43,17 @@ fn test_command_pidfd() {
4243
.unwrap()
4344
.pidfd()
4445
.expect_err("pidfd should not have been created");
46+
47+
// exercise the fork/exec path since the earlier attempts may have used pidfd_spawnp()
48+
let mut child =
49+
unsafe { Command::new("false").pre_exec(|| Ok(())) }.create_pidfd(true).spawn().unwrap();
50+
51+
assert!(child.id() > 0 && child.id() < -1i32 as u32);
52+
53+
if pidfd_open_available {
54+
assert!(child.pidfd().is_ok())
55+
}
56+
child.wait().expect("error waiting on child");
4557
}
4658

4759
#[test]

‎library/std/src/sys/pal/unix/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,13 @@ macro_rules! impl_is_minus_one {
305305

306306
impl_is_minus_one! { i8 i16 i32 i64 isize }
307307

308+
/// Convert native return values to Result using the *-1 means error is in `errno`* convention.
309+
/// Non-error values are `Ok`-wrapped.
308310
pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
309311
if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
310312
}
311313

314+
/// `-1` → look at `errno` → retry on `EINTR`. Otherwise `Ok()`-wrap the closure return value.
312315
pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
313316
where
314317
T: IsMinusOne,
@@ -323,6 +326,7 @@ where
323326
}
324327

325328
#[allow(dead_code)] // Not used on all platforms.
329+
/// Zero means `Ok()`, all other values are treated as raw OS errors. Does not look at `errno`.
326330
pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
327331
if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) }
328332
}

‎library/std/src/sys/pal/unix/process/process_unix.rs

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -449,17 +449,82 @@ impl Command {
449449
use crate::mem::MaybeUninit;
450450
use crate::sys::weak::weak;
451451
use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used};
452+
#[cfg(target_os = "linux")]
453+
use core::sync::atomic::{AtomicU8, Ordering};
452454

453455
if self.get_gid().is_some()
454456
|| self.get_uid().is_some()
455457
|| (self.env_saw_path() && !self.program_is_path())
456458
|| !self.get_closures().is_empty()
457459
|| self.get_groups().is_some()
458-
|| self.get_create_pidfd()
459460
{
460461
return Ok(None);
461462
}
462463

464+
cfg_if::cfg_if! {
465+
if #[cfg(target_os = "linux")] {
466+
weak! {
467+
fn pidfd_spawnp(
468+
*mut libc::c_int,
469+
*const libc::c_char,
470+
*const libc::posix_spawn_file_actions_t,
471+
*const libc::posix_spawnattr_t,
472+
*const *mut libc::c_char,
473+
*const *mut libc::c_char
474+
) -> libc::c_int
475+
}
476+
477+
weak! { fn pidfd_getpid(libc::c_int) -> libc::c_int }
478+
479+
static PIDFD_SUPPORTED: AtomicU8 = AtomicU8::new(0);
480+
const UNKNOWN: u8 = 0;
481+
const SPAWN: u8 = 1;
482+
// Obtaining a pidfd via the fork+exec path might work
483+
const FORK_EXEC: u8 = 2;
484+
// Neither pidfd_spawn nor fork/exec will get us a pidfd.
485+
// Instead we'll just posix_spawn if the other preconditions are met.
486+
const NO: u8 = 3;
487+
488+
if self.get_create_pidfd() {
489+
let mut support = PIDFD_SUPPORTED.load(Ordering::Relaxed);
490+
if support == FORK_EXEC {
491+
return Ok(None);
492+
}
493+
if support == UNKNOWN {
494+
support = NO;
495+
let our_pid = crate::process::id();
496+
let pidfd = cvt(unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) } as c_int);
497+
match pidfd {
498+
Ok(pidfd) => {
499+
support = FORK_EXEC;
500+
if let Some(Ok(pid)) = pidfd_getpid.get().map(|f| cvt(unsafe { f(pidfd) } as i32)) {
501+
if pidfd_spawnp.get().is_some() && pid as u32 == our_pid {
502+
support = SPAWN
503+
}
504+
}
505+
unsafe { libc::close(pidfd) };
506+
}
507+
Err(e) if e.raw_os_error() == Some(libc::EMFILE) => {
508+
// We're temporarily(?) out of file descriptors. In this case obtaining a pidfd would also fail
509+
// Don't update the support flag so we can probe again later.
510+
return Err(e)
511+
}
512+
_ => {}
513+
}
514+
PIDFD_SUPPORTED.store(support, Ordering::Relaxed);
515+
if support == FORK_EXEC {
516+
return Ok(None);
517+
}
518+
}
519+
core::assert_matches::debug_assert_matches!(support, SPAWN | NO);
520+
}
521+
} else {
522+
if self.get_create_pidfd() {
523+
unreachable!("only implemented on linux")
524+
}
525+
}
526+
}
527+
463528
// Only glibc 2.24+ posix_spawn() supports returning ENOENT directly.
464529
#[cfg(all(target_os = "linux", target_env = "gnu"))]
465530
{
@@ -543,9 +608,6 @@ impl Command {
543608

544609
let pgroup = self.get_pgroup();
545610

546-
// Safety: -1 indicates we don't have a pidfd.
547-
let mut p = unsafe { Process::new(0, -1) };
548-
549611
struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit<libc::posix_spawn_file_actions_t>);
550612

551613
impl Drop for PosixSpawnFileActions<'_> {
@@ -640,6 +702,47 @@ impl Command {
640702
#[cfg(target_os = "nto")]
641703
let spawn_fn = retrying_libc_posix_spawnp;
642704

705+
#[cfg(target_os = "linux")]
706+
if self.get_create_pidfd() && PIDFD_SUPPORTED.load(Ordering::Relaxed) == SPAWN {
707+
let mut pidfd: libc::c_int = -1;
708+
let spawn_res = pidfd_spawnp.get().unwrap()(
709+
&mut pidfd,
710+
self.get_program_cstr().as_ptr(),
711+
file_actions.0.as_ptr(),
712+
attrs.0.as_ptr(),
713+
self.get_argv().as_ptr() as *const _,
714+
envp as *const _,
715+
);
716+
717+
let spawn_res = cvt_nz(spawn_res);
718+
if let Err(ref e) = spawn_res
719+
&& e.raw_os_error() == Some(libc::ENOSYS)
720+
{
721+
PIDFD_SUPPORTED.store(FORK_EXEC, Ordering::Relaxed);
722+
return Ok(None);
723+
}
724+
spawn_res?;
725+
726+
let pid = match cvt(pidfd_getpid.get().unwrap()(pidfd)) {
727+
Ok(pid) => pid,
728+
Err(e) => {
729+
// The child has been spawned and we are holding its pidfd.
730+
// But we cannot obtain its pid even though pidfd_getpid support was verified earlier.
731+
// This might happen if libc can't open procfs because the file descriptor limit has been reached.
732+
libc::close(pidfd);
733+
return Err(Error::new(
734+
e.kind(),
735+
"pidfd_spawnp succeeded but the child's PID could not be obtained",
736+
));
737+
}
738+
};
739+
740+
return Ok(Some(Process::new(pid, pidfd)));
741+
}
742+
743+
// Safety: -1 indicates we don't have a pidfd.
744+
let mut p = Process::new(0, -1);
745+
643746
let spawn_res = spawn_fn(
644747
&mut p.pid,
645748
self.get_program_cstr().as_ptr(),
@@ -786,6 +889,12 @@ pub struct Process {
786889

787890
impl Process {
788891
#[cfg(target_os = "linux")]
892+
/// # Safety
893+
///
894+
/// `pidfd` must either be -1 (representing no file descriptor) or a valid, exclusively owned file
895+
/// descriptor (See [I/O Safety]).
896+
///
897+
/// [I/O Safety]: crate::io#io-safety
789898
unsafe fn new(pid: pid_t, pidfd: pid_t) -> Self {
790899
use crate::os::unix::io::FromRawFd;
791900
use crate::sys_common::FromInner;

‎src/bootstrap/src/core/config/config.rs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2466,14 +2466,6 @@ impl Config {
24662466
}
24672467
};
24682468

2469-
// Handle running from a directory other than the top level
2470-
let top_level = output(
2471-
&mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command,
2472-
);
2473-
let top_level = top_level.trim_end();
2474-
let compiler = format!("{top_level}/compiler/");
2475-
let library = format!("{top_level}/library/");
2476-
24772469
// Look for a version to compare to based on the current commit.
24782470
// Only commits merged by bors will have CI artifacts.
24792471
let merge_base = output(
@@ -2494,7 +2486,9 @@ impl Config {
24942486

24952487
// Warn if there were changes to the compiler or standard library since the ancestor commit.
24962488
let has_changes = !t!(helpers::git(Some(&self.src))
2497-
.args(["diff-index", "--quiet", commit, "--", &compiler, &library])
2489+
.args(["diff-index", "--quiet", commit])
2490+
.arg("--")
2491+
.args([self.src.join("compiler"), self.src.join("library")])
24982492
.command
24992493
.status())
25002494
.success();
@@ -2566,12 +2560,6 @@ impl Config {
25662560
option_name: &str,
25672561
if_unchanged: bool,
25682562
) -> Option<String> {
2569-
// Handle running from a directory other than the top level
2570-
let top_level = output(
2571-
&mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command,
2572-
);
2573-
let top_level = top_level.trim_end();
2574-
25752563
// Look for a version to compare to based on the current commit.
25762564
// Only commits merged by bors will have CI artifacts.
25772565
let merge_base = output(
@@ -2594,8 +2582,11 @@ impl Config {
25942582
let mut git = helpers::git(Some(&self.src));
25952583
git.args(["diff-index", "--quiet", commit, "--"]);
25962584

2585+
// Handle running from a directory other than the top level
2586+
let top_level = &self.src;
2587+
25972588
for path in modified_paths {
2598-
git.arg(format!("{top_level}/{path}"));
2589+
git.arg(top_level.join(path));
25992590
}
26002591

26012592
let has_changes = !t!(git.command.status()).success();

‎src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ RUN sh /scripts/rustbuild-setup.sh
1111
WORKDIR /tmp
1212

1313
COPY scripts/crosstool-ng-build.sh /scripts/
14+
COPY host-x86_64/dist-riscv64-linux/patches/ /tmp/patches/
1415
COPY host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig /tmp/crosstool.defconfig
1516
RUN /scripts/crosstool-ng-build.sh
1617

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
From 4013baf99c38f7bca06a51f8301e8fb195ccfa33 Mon Sep 17 00:00:00 2001
2+
From: Jim Wilson <jimw@sifive.com>
3+
Date: Tue, 2 Jun 2020 11:19:39 -0700
4+
Subject: [PATCH] RISC-V: Make __divdi3 handle div by zero same as hardware.
5+
6+
The ISA manual specifies that divide by zero always returns -1 as the result.
7+
We were failing to do that when the dividend was negative.
8+
9+
Original patch from Virginie Moser.
10+
11+
libgcc/
12+
* config/riscv/div.S (__divdi3): For negative arguments, change bgez
13+
to bgtz.
14+
---
15+
libgcc/config/riscv/div.S | 8 +++++---
16+
1 file changed, 5 insertions(+), 3 deletions(-)
17+
18+
diff --git a/libgcc/config/riscv/div.S b/libgcc/config/riscv/div.S
19+
index 151f8e273ac77..17234324c1e41 100644
20+
--- a/libgcc/config/riscv/div.S
21+
+++ b/libgcc/config/riscv/div.S
22+
@@ -107,10 +107,12 @@ FUNC_END (__umoddi3)
23+
/* Handle negative arguments to __divdi3. */
24+
.L10:
25+
neg a0, a0
26+
- bgez a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */
27+
+ /* Zero is handled as a negative so that the result will not be inverted. */
28+
+ bgtz a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */
29+
+
30+
neg a1, a1
31+
- j __udivdi3 /* Compute __udivdi3(-a0, -a1). */
32+
-.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */
33+
+ j __udivdi3 /* Compute __udivdi3(-a0, -a1). */
34+
+.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */
35+
neg a1, a1
36+
.L12:
37+
move t0, ra
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
From 45116f342057b7facecd3d05c2091ce3a77eda59 Mon Sep 17 00:00:00 2001
2+
From: Nelson Chu <nelson.chu@sifive.com>
3+
Date: Mon, 29 Nov 2021 04:48:20 -0800
4+
Subject: [PATCH] RISC-V: jal cannot refer to a default visibility symbol for
5+
shared object.
6+
7+
This is the original binutils bugzilla report,
8+
https://sourceware.org/bugzilla/show_bug.cgi?id=28509
9+
10+
And this is the first version of the proposed binutils patch,
11+
https://sourceware.org/pipermail/binutils/2021-November/118398.html
12+
13+
After applying the binutils patch, I get the the unexpected error when
14+
building libgcc,
15+
16+
/scratch/nelsonc/riscv-gnu-toolchain/riscv-gcc/libgcc/config/riscv/div.S:42:
17+
/scratch/nelsonc/build-upstream/rv64gc-linux/build-install/riscv64-unknown-linux-gnu/bin/ld: relocation R_RISCV_JAL against `__udivdi3' which may bind externally can not be used when making a shared object; recompile with -fPIC
18+
19+
Therefore, this patch add an extra hidden alias symbol for __udivdi3, and
20+
then use HIDDEN_JUMPTARGET to target a non-preemptible symbol instead.
21+
The solution is similar to glibc as follows,
22+
https://sourceware.org/git/?p=glibc.git;a=commit;h=68389203832ab39dd0dbaabbc4059e7fff51c29b
23+
24+
libgcc/ChangeLog:
25+
26+
* config/riscv/div.S: Add the hidden alias symbol for __udivdi3, and
27+
then use HIDDEN_JUMPTARGET to target it since it is non-preemptible.
28+
* config/riscv/riscv-asm.h: Added new macros HIDDEN_JUMPTARGET and
29+
HIDDEN_DEF.
30+
---
31+
libgcc/config/riscv/div.S | 15 ++++++++-------
32+
libgcc/config/riscv/riscv-asm.h | 6 ++++++
33+
2 files changed, 14 insertions(+), 7 deletions(-)
34+
35+
diff --git a/libgcc/config/riscv/div.S b/libgcc/config/riscv/div.S
36+
index c9bd7879c1e36..723c3b82e48c6 100644
37+
--- a/libgcc/config/riscv/div.S
38+
+++ b/libgcc/config/riscv/div.S
39+
@@ -40,7 +40,7 @@ FUNC_BEGIN (__udivsi3)
40+
sll a0, a0, 32
41+
sll a1, a1, 32
42+
move t0, ra
43+
- jal __udivdi3
44+
+ jal HIDDEN_JUMPTARGET(__udivdi3)
45+
sext.w a0, a0
46+
jr t0
47+
FUNC_END (__udivsi3)
48+
@@ -52,7 +52,7 @@ FUNC_BEGIN (__umodsi3)
49+
srl a0, a0, 32
50+
srl a1, a1, 32
51+
move t0, ra
52+
- jal __udivdi3
53+
+ jal HIDDEN_JUMPTARGET(__udivdi3)
54+
sext.w a0, a1
55+
jr t0
56+
FUNC_END (__umodsi3)
57+
@@ -95,11 +95,12 @@ FUNC_BEGIN (__udivdi3)
58+
.L5:
59+
ret
60+
FUNC_END (__udivdi3)
61+
+HIDDEN_DEF (__udivdi3)
62+
63+
FUNC_BEGIN (__umoddi3)
64+
/* Call __udivdi3(a0, a1), then return the remainder, which is in a1. */
65+
move t0, ra
66+
- jal __udivdi3
67+
+ jal HIDDEN_JUMPTARGET(__udivdi3)
68+
move a0, a1
69+
jr t0
70+
FUNC_END (__umoddi3)
71+
@@ -111,12 +112,12 @@ FUNC_END (__umoddi3)
72+
bgtz a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */
73+
74+
neg a1, a1
75+
- j __udivdi3 /* Compute __udivdi3(-a0, -a1). */
76+
+ j HIDDEN_JUMPTARGET(__udivdi3) /* Compute __udivdi3(-a0, -a1). */
77+
.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */
78+
neg a1, a1
79+
.L12:
80+
move t0, ra
81+
- jal __udivdi3
82+
+ jal HIDDEN_JUMPTARGET(__udivdi3)
83+
neg a0, a0
84+
jr t0
85+
FUNC_END (__divdi3)
86+
@@ -126,7 +127,7 @@ FUNC_BEGIN (__moddi3)
87+
bltz a1, .L31
88+
bltz a0, .L32
89+
.L30:
90+
- jal __udivdi3 /* The dividend is not negative. */
91+
+ jal HIDDEN_JUMPTARGET(__udivdi3) /* The dividend is not negative. */
92+
move a0, a1
93+
jr t0
94+
.L31:
95+
@@ -134,7 +135,7 @@ FUNC_BEGIN (__moddi3)
96+
bgez a0, .L30
97+
.L32:
98+
neg a0, a0
99+
- jal __udivdi3 /* The dividend is hella negative. */
100+
+ jal HIDDEN_JUMPTARGET(__udivdi3) /* The dividend is hella negative. */
101+
neg a0, a1
102+
jr t0
103+
FUNC_END (__moddi3)
104+
diff --git a/libgcc/config/riscv/riscv-asm.h b/libgcc/config/riscv/riscv-asm.h
105+
index 8550707a4a26a..96dd85b0df2e5 100644
106+
--- a/libgcc/config/riscv/riscv-asm.h
107+
+++ b/libgcc/config/riscv/riscv-asm.h
108+
@@ -33,3 +33,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
109+
#define FUNC_ALIAS(X,Y) \
110+
.globl X; \
111+
X = Y
112+
+
113+
+#define CONCAT1(a, b) CONCAT2(a, b)
114+
+#define CONCAT2(a, b) a ## b
115+
+#define HIDDEN_JUMPTARGET(X) CONCAT1(__hidden_, X)
116+
+#define HIDDEN_DEF(X) FUNC_ALIAS(HIDDEN_JUMPTARGET(X), X); \
117+
+ .hidden HIDDEN_JUMPTARGET(X)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
From 68389203832ab39dd0dbaabbc4059e7fff51c29b Mon Sep 17 00:00:00 2001
2+
From: Fangrui Song <maskray@google.com>
3+
Date: Thu, 28 Oct 2021 11:39:49 -0700
4+
Subject: [PATCH] riscv: Fix incorrect jal with HIDDEN_JUMPTARGET
5+
6+
A non-local STV_DEFAULT defined symbol is by default preemptible in a
7+
shared object. j/jal cannot target a preemptible symbol. On other
8+
architectures, such a jump instruction either causes PLT [BZ #18822], or
9+
if short-ranged, sometimes rejected by the linker (but not by GNU ld's
10+
riscv port [ld PR/28509]).
11+
12+
Use HIDDEN_JUMPTARGET to target a non-preemptible symbol instead.
13+
14+
With this patch, ld.so and libc.so can be linked with LLD if source
15+
files are compiled/assembled with -mno-relax/-Wa,-mno-relax.
16+
17+
Acked-by: Palmer Dabbelt <palmer@dabbelt.com>
18+
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
19+
---
20+
sysdeps/riscv/setjmp.S | 2 +-
21+
sysdeps/unix/sysv/linux/riscv/setcontext.S | 5 +++--
22+
2 files changed, 4 insertions(+), 3 deletions(-)
23+
24+
diff --git a/sysdeps/riscv/setjmp.S b/sysdeps/riscv/setjmp.S
25+
index 0b92016b311..bec7ff80f49 100644
26+
--- a/sysdeps/riscv/setjmp.S
27+
+++ b/sysdeps/riscv/setjmp.S
28+
@@ -21,7 +21,7 @@
29+
30+
ENTRY (_setjmp)
31+
li a1, 0
32+
- j __sigsetjmp
33+
+ j HIDDEN_JUMPTARGET (__sigsetjmp)
34+
END (_setjmp)
35+
ENTRY (setjmp)
36+
li a1, 1
37+
diff --git a/sysdeps/unix/sysv/linux/riscv/setcontext.S b/sysdeps/unix/sysv/linux/riscv/setcontext.S
38+
index 9510518750a..e44a68aad47 100644
39+
--- a/sysdeps/unix/sysv/linux/riscv/setcontext.S
40+
+++ b/sysdeps/unix/sysv/linux/riscv/setcontext.S
41+
@@ -95,6 +95,7 @@ LEAF (__setcontext)
42+
99: j __syscall_error
43+
44+
END (__setcontext)
45+
+libc_hidden_def (__setcontext)
46+
weak_alias (__setcontext, setcontext)
47+
48+
LEAF (__start_context)
49+
@@ -108,7 +109,7 @@ LEAF (__start_context)
50+
/* Invoke subsequent context if present, else exit(0). */
51+
mv a0, s2
52+
beqz s2, 1f
53+
- jal __setcontext
54+
-1: j exit
55+
+ jal HIDDEN_JUMPTARGET (__setcontext)
56+
+1: j HIDDEN_JUMPTARGET (exit)
57+
58+
END (__start_context)

‎src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ CT_EXPERIMENTAL=y
33
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
44
CT_USE_MIRROR=y
55
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
6+
CT_PATCH_BUNDLED_LOCAL=y
7+
CT_LOCAL_PATCH_DIR="/tmp/patches"
68
CT_ARCH_RISCV=y
79
# CT_DEMULTILIB is not set
810
CT_ARCH_USE_MMU=y
911
CT_ARCH_64=y
1012
CT_ARCH_ARCH="rv64gc"
1113
CT_KERNEL_LINUX=y
1214
CT_LINUX_V_4_20=y
13-
CT_BINUTILS_V_2_36=y
15+
CT_BINUTILS_V_2_40=y
1416
CT_GLIBC_V_2_29=y
1517
CT_GCC_V_8=y
1618
CT_CC_LANG_CXX=y

‎tests/ui/check-cfg/mix.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra`
251251
LL | cfg!(target_feature = "zebra");
252252
| ^^^^^^^^^^^^^^^^^^^^^^^^
253253
|
254-
= note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, and `avxvnniint8` and 191 more
254+
= note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 196 more
255255
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
256256

257257
warning: 27 warnings emitted

‎tests/ui/check-cfg/well-known-values.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
165165
LL | target_feature = "_UNEXPECTED_VALUE",
166166
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
167167
|
168-
= note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
168+
= note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
169169
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
170170

171171
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//@ only-x86_64
2+
#[target_feature(enable = "amx-tile")]
3+
//~^ ERROR: currently unstable
4+
unsafe fn foo() {}
5+
6+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0658]: the target feature `amx-tile` is currently unstable
2+
--> $DIR/feature-gate-x86_amx_intrinsics.rs:2:18
3+
|
4+
LL | #[target_feature(enable = "amx-tile")]
5+
| ^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #126622 <https://github.com/rust-lang/rust/issues/126622> for more information
8+
= help: add `#![feature(x86_amx_intrinsics)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error: aborting due to 1 previous error
12+
13+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)
Please sign in to comment.