Skip to content

Commit 76a030a

Browse files
committed
Auto merge of #135592 - matthiaskrgr:rollup-4t69l7i, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #134754 (Implement `use` associated items of traits) - #135481 (coverage: Completely overhaul counter assignment, using node-flow graphs) - #135504 (Allow coercing safe-to-call target_feature functions to safe fn pointers) - #135561 (Update docs for `-Clink-dead-code` to discourage its use) - #135574 (ci: mirror ubuntu:22.04 to ghcr.io) - #135585 (resolve symlinks of LLVM tool binaries before copying them) - #135588 (Add license-metadata.json to rustc-src tarball.) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 99db273 + f4bbe30 commit 76a030a

File tree

91 files changed

+2607
-2046
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+2607
-2046
lines changed

.github/workflows/ghcr.yml

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Mirror DockerHub images used by the Rust project to ghcr.io.
2+
# Images are available at https://github.com/orgs/rust-lang/packages.
3+
#
4+
# In some CI jobs, we pull images from ghcr.io instead of Docker Hub because
5+
# Docker Hub has a rate limit, while ghcr.io doesn't.
6+
# Those images are pushed to ghcr.io by this job.
7+
#
8+
# Note that authenticating to DockerHub or other registries isn't possible
9+
# for PR jobs, because forks can't access secrets.
10+
# That's why we use ghcr.io: it has no rate limit and it doesn't require authentication.
11+
12+
name: GHCR
13+
14+
on:
15+
workflow_dispatch:
16+
schedule:
17+
# Run daily at midnight UTC
18+
- cron: '0 0 * * *'
19+
20+
jobs:
21+
mirror:
22+
name: DockerHub mirror
23+
runs-on: ubuntu-24.04
24+
if: github.repository == 'rust-lang/rust'
25+
permissions:
26+
# Needed to write to the ghcr.io registry
27+
packages: write
28+
steps:
29+
- uses: actions/checkout@v4
30+
with:
31+
persist-credentials: false
32+
33+
- name: Log in to registry
34+
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
35+
36+
# Download crane in the current directory.
37+
# We use crane because it copies the docker image for all the architectures available in
38+
# DockerHub for the image.
39+
# Learn more about crane at
40+
# https://github.com/google/go-containerregistry/blob/main/cmd/crane/README.md
41+
- name: Download crane
42+
run: |
43+
curl -sL "https://github.com/google/go-containerregistry/releases/download/${VERSION}/go-containerregistry_${OS}_${ARCH}.tar.gz" | tar -xzf -
44+
env:
45+
VERSION: v0.20.2
46+
OS: Linux
47+
ARCH: x86_64
48+
49+
- name: Mirror DockerHub
50+
run: |
51+
# DockerHub image we want to mirror
52+
image="ubuntu:22.04"
53+
54+
# Mirror image from DockerHub to ghcr.io
55+
./crane copy \
56+
docker.io/${image} \
57+
ghcr.io/${{ github.repository_owner }}/${image}

compiler/rustc_borrowck/src/type_check/mod.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -1654,7 +1654,20 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
16541654
match *cast_kind {
16551655
CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, coercion_source) => {
16561656
let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
1657-
let src_sig = op.ty(body, tcx).fn_sig(tcx);
1657+
let src_ty = op.ty(body, tcx);
1658+
let mut src_sig = src_ty.fn_sig(tcx);
1659+
if let ty::FnDef(def_id, _) = src_ty.kind()
1660+
&& let ty::FnPtr(_, target_hdr) = *ty.kind()
1661+
&& tcx.codegen_fn_attrs(def_id).safe_target_features
1662+
&& target_hdr.safety.is_safe()
1663+
&& let Some(safe_sig) = tcx.adjust_target_feature_sig(
1664+
*def_id,
1665+
src_sig,
1666+
body.source.def_id(),
1667+
)
1668+
{
1669+
src_sig = safe_sig;
1670+
}
16581671

16591672
// HACK: This shouldn't be necessary... We can remove this when we actually
16601673
// get binders with where clauses, then elaborate implied bounds into that

compiler/rustc_data_structures/src/graph/iterate/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,16 @@ where
125125
pub fn visited(&self, node: G::Node) -> bool {
126126
self.visited.contains(node)
127127
}
128+
129+
/// Returns a reference to the set of nodes that have been visited, with
130+
/// the same caveats as [`Self::visited`].
131+
///
132+
/// When incorporating the visited nodes into another bitset, using bulk
133+
/// operations like `union` or `intersect` can be more efficient than
134+
/// processing each node individually.
135+
pub fn visited_set(&self) -> &DenseBitSet<G::Node> {
136+
&self.visited
137+
}
128138
}
129139

130140
impl<G> std::fmt::Debug for DepthFirstSearch<G>

compiler/rustc_data_structures/src/graph/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod dominators;
44
pub mod implementation;
55
pub mod iterate;
66
mod reference;
7+
pub mod reversed;
78
pub mod scc;
89
pub mod vec_graph;
910

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use crate::graph::{DirectedGraph, Predecessors, Successors};
2+
3+
/// View that reverses the direction of edges in its underlying graph, so that
4+
/// successors become predecessors and vice-versa.
5+
///
6+
/// Because of `impl<G: Graph> Graph for &G`, the underlying graph can be
7+
/// wrapped by-reference instead of by-value if desired.
8+
#[derive(Clone, Copy, Debug)]
9+
pub struct ReversedGraph<G> {
10+
pub inner: G,
11+
}
12+
13+
impl<G> ReversedGraph<G> {
14+
pub fn new(inner: G) -> Self {
15+
Self { inner }
16+
}
17+
}
18+
19+
impl<G: DirectedGraph> DirectedGraph for ReversedGraph<G> {
20+
type Node = G::Node;
21+
22+
fn num_nodes(&self) -> usize {
23+
self.inner.num_nodes()
24+
}
25+
}
26+
27+
// Implementing `StartNode` is not possible in general, because the start node
28+
// of an underlying graph is instead an _end_ node in the reversed graph.
29+
// But would be possible to define another wrapper type that adds an explicit
30+
// start node to its underlying graph, if desired.
31+
32+
impl<G: Predecessors> Successors for ReversedGraph<G> {
33+
fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
34+
self.inner.predecessors(node)
35+
}
36+
}
37+
38+
impl<G: Successors> Predecessors for ReversedGraph<G> {
39+
fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
40+
self.inner.successors(node)
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
Attempt was made to import an unimportable value. This can happen when trying
2-
to import a method from a trait.
1+
Attempt was made to import an unimportable type. This can happen when trying
2+
to import a type from a trait.
33

44
Erroneous code example:
55

66
```compile_fail,E0253
77
mod foo {
88
pub trait MyTrait {
9-
fn do_something();
9+
type SomeType;
1010
}
1111
}
1212
13-
use foo::MyTrait::do_something;
14-
// error: `do_something` is not directly importable
13+
use foo::MyTrait::SomeType;
14+
// error: `SomeType` is not directly importable
1515
1616
fn main() {}
1717
```
1818

19-
It's invalid to directly import methods belonging to a trait or concrete type.
19+
It's invalid to directly import types belonging to a trait.

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,8 @@ declare_features! (
521521
(unstable, impl_trait_in_bindings, "1.64.0", Some(63065)),
522522
/// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
523523
(unstable, impl_trait_in_fn_trait_return, "1.64.0", Some(99697)),
524+
/// Allows `use` associated functions from traits.
525+
(unstable, import_trait_associated_functions, "CURRENT_RUSTC_VERSION", Some(134691)),
524526
/// Allows associated types in inherent impls.
525527
(incomplete, inherent_associated_types, "1.52.0", Some(8995)),
526528
/// Allow anonymous constants from an inline `const` block in pattern position

compiler/rustc_hir_typeck/src/coercion.rs

+12-11
Original file line numberDiff line numberDiff line change
@@ -920,7 +920,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
920920

921921
match b.kind() {
922922
ty::FnPtr(_, b_hdr) => {
923-
let a_sig = a.fn_sig(self.tcx);
923+
let mut a_sig = a.fn_sig(self.tcx);
924924
if let ty::FnDef(def_id, _) = *a.kind() {
925925
// Intrinsics are not coercible to function pointers
926926
if self.tcx.intrinsic(def_id).is_some() {
@@ -932,19 +932,20 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
932932
return Err(TypeError::ForceInlineCast);
933933
}
934934

935-
let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
936-
if matches!(fn_attrs.inline, InlineAttr::Force { .. }) {
937-
return Err(TypeError::ForceInlineCast);
938-
}
939-
940-
// FIXME(target_feature): Safe `#[target_feature]` functions could be cast to safe fn pointers (RFC 2396),
941-
// as you can already write that "cast" in user code by wrapping a target_feature fn call in a closure,
942-
// which is safe. This is sound because you already need to be executing code that is satisfying the target
943-
// feature constraints..
944935
if b_hdr.safety.is_safe()
945936
&& self.tcx.codegen_fn_attrs(def_id).safe_target_features
946937
{
947-
return Err(TypeError::TargetFeatureCast(def_id));
938+
// Allow the coercion if the current function has all the features that would be
939+
// needed to call the coercee safely.
940+
if let Some(safe_sig) = self.tcx.adjust_target_feature_sig(
941+
def_id,
942+
a_sig,
943+
self.fcx.body_id.into(),
944+
) {
945+
a_sig = safe_sig;
946+
} else {
947+
return Err(TypeError::TargetFeatureCast(def_id));
948+
}
948949
}
949950
}
950951

compiler/rustc_index/src/bit_set.rs

+30
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,24 @@ impl<T: Idx> DenseBitSet<T> {
281281
}
282282

283283
bit_relations_inherent_impls! {}
284+
285+
/// Sets `self = self | !other`.
286+
///
287+
/// FIXME: Incorporate this into [`BitRelations`] and fill out
288+
/// implementations for other bitset types, if needed.
289+
pub fn union_not(&mut self, other: &DenseBitSet<T>) {
290+
assert_eq!(self.domain_size, other.domain_size);
291+
292+
// FIXME(Zalathar): If we were to forcibly _set_ all excess bits before
293+
// the bitwise update, and then clear them again afterwards, we could
294+
// quickly and accurately detect whether the update changed anything.
295+
// But that's only worth doing if there's an actual use-case.
296+
297+
bitwise(&mut self.words, &other.words, |a, b| a | !b);
298+
// The bitwise update `a | !b` can result in the last word containing
299+
// out-of-domain bits, so we need to clear them.
300+
self.clear_excess_bits();
301+
}
284302
}
285303

286304
// dense REL dense
@@ -1087,6 +1105,18 @@ impl<T: Idx> fmt::Debug for ChunkedBitSet<T> {
10871105
}
10881106
}
10891107

1108+
/// Sets `out_vec[i] = op(out_vec[i], in_vec[i])` for each index `i` in both
1109+
/// slices. The slices must have the same length.
1110+
///
1111+
/// Returns true if at least one bit in `out_vec` was changed.
1112+
///
1113+
/// ## Warning
1114+
/// Some bitwise operations (e.g. union-not, xor) can set output bits that were
1115+
/// unset in in both inputs. If this happens in the last word/chunk of a bitset,
1116+
/// it can cause the bitset to contain out-of-domain values, which need to
1117+
/// be cleared with `clear_excess_bits_in_final_word`. This also makes the
1118+
/// "changed" return value unreliable, because the change might have only
1119+
/// affected excess bits.
10901120
#[inline]
10911121
fn bitwise<Op>(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool
10921122
where

compiler/rustc_index/src/bit_set/tests.rs

+26
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,32 @@ fn union_two_sets() {
7575
assert!(set1.contains(64));
7676
}
7777

78+
#[test]
79+
fn union_not() {
80+
let mut a = DenseBitSet::<usize>::new_empty(100);
81+
let mut b = DenseBitSet::<usize>::new_empty(100);
82+
83+
a.insert(3);
84+
a.insert(5);
85+
a.insert(80);
86+
a.insert(81);
87+
88+
b.insert(5); // Already in `a`.
89+
b.insert(7);
90+
b.insert(63);
91+
b.insert(81); // Already in `a`.
92+
b.insert(90);
93+
94+
a.union_not(&b);
95+
96+
// After union-not, `a` should contain all values in the domain, except for
97+
// the ones that are in `b` and were _not_ already in `a`.
98+
assert_eq!(
99+
a.iter().collect::<Vec<_>>(),
100+
(0usize..100).filter(|&x| !matches!(x, 7 | 63 | 90)).collect::<Vec<_>>(),
101+
);
102+
}
103+
78104
#[test]
79105
fn chunked_bitset() {
80106
let mut b0 = ChunkedBitSet::<usize>::new_empty(0);

compiler/rustc_middle/src/ty/context.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ use crate::dep_graph::{DepGraph, DepKindStruct};
6060
use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarInfo, CanonicalVarInfos};
6161
use crate::lint::lint_level;
6262
use crate::metadata::ModChild;
63-
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
63+
use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature};
6464
use crate::middle::{resolve_bound_vars, stability};
6565
use crate::mir::interpret::{self, Allocation, ConstAllocation};
6666
use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted};
@@ -1776,6 +1776,37 @@ impl<'tcx> TyCtxt<'tcx> {
17761776
pub fn dcx(self) -> DiagCtxtHandle<'tcx> {
17771777
self.sess.dcx()
17781778
}
1779+
1780+
pub fn is_target_feature_call_safe(
1781+
self,
1782+
callee_features: &[TargetFeature],
1783+
body_features: &[TargetFeature],
1784+
) -> bool {
1785+
// If the called function has target features the calling function hasn't,
1786+
// the call requires `unsafe`. Don't check this on wasm
1787+
// targets, though. For more information on wasm see the
1788+
// is_like_wasm check in hir_analysis/src/collect.rs
1789+
self.sess.target.options.is_like_wasm
1790+
|| callee_features
1791+
.iter()
1792+
.all(|feature| body_features.iter().any(|f| f.name == feature.name))
1793+
}
1794+
1795+
/// Returns the safe version of the signature of the given function, if calling it
1796+
/// would be safe in the context of the given caller.
1797+
pub fn adjust_target_feature_sig(
1798+
self,
1799+
fun_def: DefId,
1800+
fun_sig: ty::Binder<'tcx, ty::FnSig<'tcx>>,
1801+
caller: DefId,
1802+
) -> Option<ty::Binder<'tcx, ty::FnSig<'tcx>>> {
1803+
let fun_features = &self.codegen_fn_attrs(fun_def).target_features;
1804+
let callee_features = &self.codegen_fn_attrs(caller).target_features;
1805+
if self.is_target_feature_call_safe(&fun_features, &callee_features) {
1806+
return Some(fun_sig.map_bound(|sig| ty::FnSig { safety: hir::Safety::Safe, ..sig }));
1807+
}
1808+
None
1809+
}
17791810
}
17801811

17811812
impl<'tcx> TyCtxtAt<'tcx> {

compiler/rustc_mir_build/src/check_unsafety.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -495,14 +495,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
495495
};
496496
self.requires_unsafe(expr.span, CallToUnsafeFunction(func_id));
497497
} else if let &ty::FnDef(func_did, _) = fn_ty.kind() {
498-
// If the called function has target features the calling function hasn't,
499-
// the call requires `unsafe`. Don't check this on wasm
500-
// targets, though. For more information on wasm see the
501-
// is_like_wasm check in hir_analysis/src/collect.rs
502-
if !self.tcx.sess.target.options.is_like_wasm
503-
&& !callee_features.iter().all(|feature| {
504-
self.body_target_features.iter().any(|f| f.name == feature.name)
505-
})
498+
if !self
499+
.tcx
500+
.is_target_feature_call_safe(callee_features, self.body_target_features)
506501
{
507502
let missing: Vec<_> = callee_features
508503
.iter()

0 commit comments

Comments
 (0)