Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 8 pull requests #128000

Closed
wants to merge 37 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0d508bb
Introduce and provide a hook for `should_codegen_locally`
momvart Jul 15, 2024
14430e6
Use the hook on tcx instead of the local function
momvart Jul 15, 2024
9b80250
Move compiler_builtin check to the use case
momvart Jul 15, 2024
2b5a982
abstract merge-base commit logic
onur-ozkan Jul 17, 2024
9e354da
unix: Unsafe-wrap stack_overflow::signal_handler
workingjubilee Jul 17, 2024
357ba1f
unix: lift init of sigaltstack before sigaction
workingjubilee Jul 17, 2024
fa628ce
unix: Unsafe-wrap stack_overflow::cleanup
workingjubilee Jul 17, 2024
c1740ee
unix: Unsafe-wrap stack_overflow::{drop,make}_handler
workingjubilee Jul 17, 2024
529fcbc
unix: acquire-load NEED_ALTSTACK
workingjubilee Jul 18, 2024
ead6aad
Make command output capturing more explicit
Kobzol Jul 7, 2024
1984a46
Make it easier to detect when bootstrap tries to read uncaptured stdo…
Kobzol Jul 7, 2024
36ebf7a
run_make_support: skip rustfmt for lib.rs to preserve use ordering
jieyouxu Jul 19, 2024
5b1860a
rewrite return-non-c-like-enum-from-c to rmake
Oneirical Jul 12, 2024
5e55f07
rewrite and rename issue-28595 to rmake
Oneirical Jul 12, 2024
1ae1ab8
rewrite c-static-dylib to rmake
Oneirical Jul 12, 2024
1a4fba5
rewrite c-static-rlib to rmake
Oneirical Jul 12, 2024
8a09f22
rewrite extern-fn-generic to rmake
Oneirical Jul 12, 2024
01c7118
rewrite extern-fn-with-union to rmake
Oneirical Jul 12, 2024
db8398d
rewrite lto-no-link-whole-rlib to rmake
Oneirical Jul 12, 2024
1f976b4
rewrite linkage-attr-on-static to rmake
Oneirical Jul 12, 2024
fdc8d62
rewrite pass-non-c-like-enum-to-c to rmake
Oneirical Jul 17, 2024
1d83da8
kmc-solid: forbid(unsafe_op_in_unsafe_fn)
workingjubilee Jul 17, 2024
e9b3e9c
std: forbid unwrapped unsafe in unsupported_backslash
workingjubilee Jul 17, 2024
3b7e4bc
Split out `remove_never_subcandidates`
Zalathar Jul 18, 2024
e091c35
Improve `merge_trivial_subcandidates`
Zalathar Jul 18, 2024
e60c5c1
Split out `test_remaining_match_pairs_after_or`
Zalathar Jul 18, 2024
886668c
Improve `test_remaining_match_pairs_after_or`
Zalathar Jul 18, 2024
239037e
Inline `finalize_or_candidate`
Zalathar Jul 18, 2024
0636293
use precompiled rustdoc with CI rustc
onur-ozkan Jul 7, 2024
a40b294
Rollup merge of #127463 - onur-ozkan:precompiled-rustdoc, r=Kobzol
tgross35 Jul 20, 2024
27690c5
Rollup merge of #127663 - Oneirical:fuzzy-testure, r=jieyouxu
tgross35 Jul 20, 2024
2624e4f
Rollup merge of #127779 - momvart:should_codegen_hook, r=cjgillot
tgross35 Jul 20, 2024
ba33385
Rollup merge of #127799 - Kobzol:bootstrap-cmd-refactor-7, r=onur-ozkan
tgross35 Jul 20, 2024
ff9ed81
Rollup merge of #127843 - workingjubilee:break-up-big-ass-stack-overf…
tgross35 Jul 20, 2024
fa28851
Rollup merge of #127873 - workingjubilee:forbid-unsafe-ops-for-kmc-so…
tgross35 Jul 20, 2024
0ab64f9
Rollup merge of #127917 - Zalathar:after-or, r=Nadrieril
tgross35 Jul 20, 2024
bf972c7
Rollup merge of #127964 - jieyouxu:rmake-rustfmt-skip, r=nnethercote
tgross35 Jul 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ use std::mem;
use cranelift_codegen::ir::{ArgumentPurpose, SigRef};
use cranelift_codegen::isa::CallConv;
use cranelift_module::ModuleError;
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::TypeVisitableExt;
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_target::abi::call::{Conv, FnAbi, PassMode};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use cranelift_codegen::CodegenError;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use cranelift_module::ModuleError;
use rustc_ast::InlineAsmOptions;
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
use rustc_index::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::TypeVisitableExt;
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;

use crate::constant::ConstantCx;
use crate::debuginfo::{FunctionDebugContext, TypeDebugContext};
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_codegen_cranelift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ extern crate rustc_hir;
extern crate rustc_incremental;
extern crate rustc_index;
extern crate rustc_metadata;
extern crate rustc_monomorphize;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
Expand Down
28 changes: 28 additions & 0 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,34 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
ongoing_codegen
}

/// Returns whether a call from the current crate to the [`Instance`] would produce a call
/// from `compiler_builtins` to a symbol the linker must resolve.
///
/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some
/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
/// unlinkable calls.
///
/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker.
pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
) -> bool {
fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name {
name.as_str().starts_with("llvm.")
} else {
false
}
}

let def_id = instance.def_id();
!def_id.is_local()
&& tcx.is_compiler_builtins(LOCAL_CRATE)
&& !is_llvm_intrinsic(tcx, def_id)
&& !tcx.should_codegen_locally(instance)
}

impl CrateInfo {
pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
let crate_types = tcx.crate_types().to_vec();
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::operand::OperandValue::{Immediate, Pair, Ref, ZeroSized};
use super::place::{PlaceRef, PlaceValue};
use super::{CachedLlbb, FunctionCx, LocalRef};

use crate::base;
use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization};
use crate::common::{self, IntPredicate};
use crate::errors::CompilerBuiltinsCannotCall;
use crate::meth;
Expand All @@ -18,7 +18,6 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, span_bug};
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
use rustc_session::config::OptLevel;
use rustc_span::{source_map::Spanned, sym, Span};
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/hooks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ declare_hooks! {

/// Create a list-like THIR representation for debugging.
hook thir_flat(key: LocalDefId) -> String;

/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
/// can just link to the upstream crate and therefore don't need a mono item.
hook should_codegen_locally(instance: crate::ty::Instance<'tcx>) -> bool;
}

#[cold]
Expand Down
220 changes: 129 additions & 91 deletions compiler/rustc_mir_build/src/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1598,6 +1598,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
for subcandidate in candidate.subcandidates.iter_mut() {
expanded_candidates.push(subcandidate);
}
// Note that the subcandidates have been added to `expanded_candidates`,
// but `candidate` itself has not. If the last candidate has more match pairs,
// they are handled separately by `test_remaining_match_pairs_after_or`.
} else {
// A candidate that doesn't start with an or-pattern has nothing to
// expand, so it is included in the post-expansion list as-is.
Expand All @@ -1613,19 +1616,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expanded_candidates.as_mut_slice(),
);

// Simplify subcandidates and process any leftover match pairs.
for candidate in candidates_to_expand {
// Postprocess subcandidates, and process any leftover match pairs.
// (Only the last candidate can possibly have more match pairs.)
debug_assert!({
let mut all_except_last = candidates_to_expand.iter().rev().skip(1);
all_except_last.all(|candidate| candidate.match_pairs.is_empty())
});
for candidate in candidates_to_expand.iter_mut() {
if !candidate.subcandidates.is_empty() {
self.finalize_or_candidate(span, scrutinee_span, candidate);
self.merge_trivial_subcandidates(candidate);
self.remove_never_subcandidates(candidate);
}
}
if let Some(last_candidate) = candidates_to_expand.last_mut() {
self.test_remaining_match_pairs_after_or(span, scrutinee_span, last_candidate);
}

remainder_start.and(remaining_candidates)
}

/// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
/// subcandidate. Any candidate that has been expanded that way should be passed to
/// `finalize_or_candidate` after its subcandidates have been processed.
/// subcandidate. Any candidate that has been expanded this way should also be postprocessed
/// at the end of [`Self::expand_and_match_or_candidates`].
fn create_or_subcandidates<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
Expand All @@ -1642,7 +1654,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block;
}

/// Simplify subcandidates and process any leftover match pairs. The candidate should have been
/// Try to merge all of the subcandidates of the given candidate into one. This avoids
/// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been
/// expanded with `create_or_subcandidates`.
///
/// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like
Expand Down Expand Up @@ -1695,103 +1708,128 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// |
/// ...
/// ```
fn finalize_or_candidate(
&mut self,
span: Span,
scrutinee_span: Span,
candidate: &mut Candidate<'_, 'tcx>,
) {
if candidate.subcandidates.is_empty() {
///
/// Note that this takes place _after_ the subcandidates have participated
/// in match tree lowering.
fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
assert!(!candidate.subcandidates.is_empty());
if candidate.has_guard {
// FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
return;
}

self.merge_trivial_subcandidates(candidate);
// FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
let can_merge = candidate.subcandidates.iter().all(|subcandidate| {
subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty()
});
if !can_merge {
return;
}

if !candidate.match_pairs.is_empty() {
let or_span = candidate.or_span.unwrap_or(candidate.extra_data.span);
let source_info = self.source_info(or_span);
// If more match pairs remain, test them after each subcandidate.
// We could add them to the or-candidates before the call to `test_or_pattern` but this
// would make it impossible to detect simplifiable or-patterns. That would guarantee
// exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`.
let mut last_otherwise = None;
candidate.visit_leaves(|leaf_candidate| {
last_otherwise = leaf_candidate.otherwise_block;
});
let remaining_match_pairs = mem::take(&mut candidate.match_pairs);
candidate.visit_leaves(|leaf_candidate| {
assert!(leaf_candidate.match_pairs.is_empty());
leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned());
let or_start = leaf_candidate.pre_binding_block.unwrap();
let otherwise =
self.match_candidates(span, scrutinee_span, or_start, &mut [leaf_candidate]);
// In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q,
// R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching
// directly to `last_otherwise`. If there is a guard,
// `leaf_candidate.otherwise_block` can be reached by guard failure as well, so we
// can't skip `Q`.
let or_otherwise = if leaf_candidate.has_guard {
leaf_candidate.otherwise_block.unwrap()
} else {
last_otherwise.unwrap()
};
self.cfg.goto(otherwise, source_info, or_otherwise);
});
let mut last_otherwise = None;
let shared_pre_binding_block = self.cfg.start_new_block();
// This candidate is about to become a leaf, so unset `or_span`.
let or_span = candidate.or_span.take().unwrap();
let source_info = self.source_info(or_span);

if candidate.false_edge_start_block.is_none() {
candidate.false_edge_start_block = candidate.subcandidates[0].false_edge_start_block;
}

// Remove the (known-trivial) subcandidates from the candidate tree,
// so that they aren't visible after match tree lowering, and wire them
// all to join up at a single shared pre-binding block.
// (Note that the subcandidates have already had their part of the match
// tree lowered by this point, which is why we can add a goto to them.)
for subcandidate in mem::take(&mut candidate.subcandidates) {
let subcandidate_block = subcandidate.pre_binding_block.unwrap();
self.cfg.goto(subcandidate_block, source_info, shared_pre_binding_block);
last_otherwise = subcandidate.otherwise_block;
}
candidate.pre_binding_block = Some(shared_pre_binding_block);
assert!(last_otherwise.is_some());
candidate.otherwise_block = last_otherwise;
}

/// Try to merge all of the subcandidates of the given candidate into one. This avoids
/// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been
/// expanded with `create_or_subcandidates`.
fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
if candidate.subcandidates.is_empty() || candidate.has_guard {
// FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
/// Never subcandidates may have a set of bindings inconsistent with their siblings,
/// which would break later code. So we filter them out. Note that we can't filter out
/// top-level candidates this way.
fn remove_never_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
if candidate.subcandidates.is_empty() {
return;
}

// FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
let can_merge = candidate.subcandidates.iter().all(|subcandidate| {
subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty()
});
if can_merge {
let mut last_otherwise = None;
let any_matches = self.cfg.start_new_block();
let or_span = candidate.or_span.take().unwrap();
let source_info = self.source_info(or_span);
if candidate.false_edge_start_block.is_none() {
candidate.false_edge_start_block =
candidate.subcandidates[0].false_edge_start_block;
}
for subcandidate in mem::take(&mut candidate.subcandidates) {
let or_block = subcandidate.pre_binding_block.unwrap();
self.cfg.goto(or_block, source_info, any_matches);
last_otherwise = subcandidate.otherwise_block;
}
candidate.pre_binding_block = Some(any_matches);
assert!(last_otherwise.is_some());
candidate.otherwise_block = last_otherwise;
} else {
// Never subcandidates may have a set of bindings inconsistent with their siblings,
// which would break later code. So we filter them out. Note that we can't filter out
// top-level candidates this way.
candidate.subcandidates.retain_mut(|candidate| {
if candidate.extra_data.is_never {
candidate.visit_leaves(|subcandidate| {
let block = subcandidate.pre_binding_block.unwrap();
// That block is already unreachable but needs a terminator to make the MIR well-formed.
let source_info = self.source_info(subcandidate.extra_data.span);
self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
});
false
} else {
true
}
});
if candidate.subcandidates.is_empty() {
// If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`.
candidate.pre_binding_block = Some(self.cfg.start_new_block());
candidate.subcandidates.retain_mut(|candidate| {
if candidate.extra_data.is_never {
candidate.visit_leaves(|subcandidate| {
let block = subcandidate.pre_binding_block.unwrap();
// That block is already unreachable but needs a terminator to make the MIR well-formed.
let source_info = self.source_info(subcandidate.extra_data.span);
self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
});
false
} else {
true
}
});
if candidate.subcandidates.is_empty() {
// If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`.
candidate.pre_binding_block = Some(self.cfg.start_new_block());
}
}

/// If more match pairs remain, test them after each subcandidate.
/// We could have added them to the or-candidates during or-pattern expansion, but that
/// would make it impossible to detect simplifiable or-patterns. That would guarantee
/// exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`.
fn test_remaining_match_pairs_after_or(
&mut self,
span: Span,
scrutinee_span: Span,
candidate: &mut Candidate<'_, 'tcx>,
) {
if candidate.match_pairs.is_empty() {
return;
}

let or_span = candidate.or_span.unwrap_or(candidate.extra_data.span);
let source_info = self.source_info(or_span);
let mut last_otherwise = None;
candidate.visit_leaves(|leaf_candidate| {
last_otherwise = leaf_candidate.otherwise_block;
});

let remaining_match_pairs = mem::take(&mut candidate.match_pairs);
// We're testing match pairs that remained after an `Or`, so the remaining
// pairs should all be `Or` too, due to the sorting invariant.
debug_assert!(
remaining_match_pairs
.iter()
.all(|match_pair| matches!(match_pair.test_case, TestCase::Or { .. }))
);

candidate.visit_leaves(|leaf_candidate| {
// At this point the leaf's own match pairs have all been lowered
// and removed, so `extend` and assignment are equivalent,
// but extending can also recycle any existing vector capacity.
assert!(leaf_candidate.match_pairs.is_empty());
leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned());

let or_start = leaf_candidate.pre_binding_block.unwrap();
let otherwise =
self.match_candidates(span, scrutinee_span, or_start, &mut [leaf_candidate]);
// In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q,
// R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching
// directly to `last_otherwise`. If there is a guard,
// `leaf_candidate.otherwise_block` can be reached by guard failure as well, so we
// can't skip `Q`.
let or_otherwise = if leaf_candidate.has_guard {
leaf_candidate.otherwise_block.unwrap()
} else {
last_otherwise.unwrap()
};
self.cfg.goto(otherwise, source_info, or_otherwise);
});
}

/// Pick a test to run. Which test doesn't matter as long as it is guaranteed to fully match at
Expand Down
Loading
Loading