Skip to content

Commit 4e3ce91

Browse files
committed
Auto merge of #155918 - jhpratt:rollup-61d5ugT, r=jhpratt
Rollup of 5 pull requests Successful merges: - #154325 (Tweak irrefutable let else warning output) - #155273 (Lock stable_crate_ids once in create_crate_num) - #155692 (disable naked-dead-code-elimination test if no RET mnemonic is available) - #155747 (Update documentation for `wasm32-wali-linux-musl` after integrating n…) - #155907 (Handle hkl const closures)
2 parents 03c609a + 8463b3a commit 4e3ce91

32 files changed

Lines changed: 375 additions & 173 deletions

File tree

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2350,6 +2350,7 @@ unsafe extern "C" {
23502350
pub(crate) fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString);
23512351

23522352
pub(crate) fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
2353+
pub(crate) fn LLVMRustTargetHasMnemonic(T: &TargetMachine, s: *const c_char) -> bool;
23532354

23542355
pub(crate) fn LLVMRustPrintTargetCPUs(TM: &TargetMachine, OutStr: &RustString);
23552356
pub(crate) fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t;

compiler/rustc_codegen_llvm/src/llvm_util.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,10 @@ pub(crate) fn print(req: &PrintRequest, out: &mut String, sess: &Session) {
480480
match req.kind {
481481
PrintKind::TargetCPUs => print_target_cpus(sess, tm.raw(), out),
482482
PrintKind::TargetFeatures => print_target_features(sess, tm.raw(), out),
483+
PrintKind::BackendHasMnemonic => {
484+
let mnemonic = req.arg.as_deref().expect("BackendHasMnemonic requires arg");
485+
print_target_has_mnemonic(tm.raw(), mnemonic, out)
486+
}
483487
_ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
484488
}
485489
}
@@ -738,3 +742,10 @@ pub(crate) fn tune_cpu(sess: &Session) -> Option<&str> {
738742
let name = sess.opts.unstable_opts.tune_cpu.as_ref()?;
739743
Some(handle_native(name))
740744
}
745+
746+
fn print_target_has_mnemonic(tm: &llvm::TargetMachine, mnemonic: &str, out: &mut String) {
747+
use std::fmt::Write;
748+
let cstr = SmallCStr::new(mnemonic);
749+
let has_mnemonic = unsafe { llvm::LLVMRustTargetHasMnemonic(tm, cstr.as_ptr()) };
750+
writeln!(out, "{}", has_mnemonic).unwrap();
751+
}

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,9 @@ fn print_crate_info(
804804
let calling_conventions = rustc_abi::all_names();
805805
println_info!("{}", calling_conventions.join("\n"));
806806
}
807+
BackendHasMnemonic => {
808+
codegen_backend.print(req, &mut crate_info, sess);
809+
}
807810
BackendHasZstd => {
808811
let has_zstd: bool = codegen_backend.has_zstd();
809812
println_info!("{has_zstd}");

compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/IR/Verifier.h"
2020
#include "llvm/IRPrinter/IRPrintingPasses.h"
2121
#include "llvm/LTO/LTO.h"
22+
#include "llvm/MC/MCInstrInfo.h"
2223
#include "llvm/MC/MCSubtargetInfo.h"
2324
#include "llvm/MC/TargetRegistry.h"
2425
#include "llvm/Object/ObjectFile.h"
@@ -94,6 +95,25 @@ extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM,
9495
return MCInfo->checkFeatures(std::string("+") + Feature);
9596
}
9697

98+
/// Check whether the target has a specific assembly mnemonic like `ret` or
99+
/// `nop`.
100+
/// This should be fast enough but if its not we have to look into another
101+
/// method of checking.
102+
extern "C" bool LLVMRustTargetHasMnemonic(LLVMTargetMachineRef TM,
103+
const char *Mnemonic) {
104+
TargetMachine *Target = unwrap(TM);
105+
const MCInstrInfo *MII = Target->getMCInstrInfo();
106+
StringRef MnemonicRef(Mnemonic);
107+
108+
for (unsigned i = 0; i < MII->getNumOpcodes(); i++) {
109+
StringRef Name = MII->getName(i);
110+
if (Name.equals_insensitive(MnemonicRef)) {
111+
return true;
112+
}
113+
}
114+
return false;
115+
}
116+
97117
enum class LLVMRustCodeModel {
98118
Tiny,
99119
Small,

compiler/rustc_middle/src/ty/context.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,12 +1416,12 @@ impl<'tcx> TyCtxt<'tcx> {
14161416
self,
14171417
stable_crate_id: StableCrateId,
14181418
) -> Result<TyCtxtFeed<'tcx, CrateNum>, CrateNum> {
1419-
if let Some(&existing) = self.untracked().stable_crate_ids.read().get(&stable_crate_id) {
1419+
let mut lock = self.untracked().stable_crate_ids.write();
1420+
if let Some(&existing) = lock.get(&stable_crate_id) {
14201421
return Err(existing);
14211422
}
1422-
1423-
let num = CrateNum::new(self.untracked().stable_crate_ids.read().len());
1424-
self.untracked().stable_crate_ids.write().insert(stable_crate_id, num);
1423+
let num = CrateNum::new(lock.len());
1424+
lock.insert(stable_crate_id, num);
14251425
Ok(TyCtxtFeed { key: num, tcx: self })
14261426
}
14271427

compiler/rustc_mir_build/src/errors.rs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -924,22 +924,24 @@ pub(crate) struct IrrefutableLetPatternsIfLetGuard {
924924
}
925925

926926
#[derive(Diagnostic)]
927-
#[diag(
928-
"irrefutable `let...else` {$count ->
929-
[one] pattern
930-
*[other] patterns
931-
}"
932-
)]
933-
#[note(
934-
"{$count ->
935-
[one] this pattern always matches, so the else clause is unreachable
936-
*[other] these patterns always match, so the else clause is unreachable
937-
}"
938-
)]
927+
#[diag("unreachable `else` clause")]
928+
#[note("this pattern always matches, so the else clause is unreachable")]
939929
pub(crate) struct IrrefutableLetPatternsLetElse {
940-
pub(crate) count: usize,
941-
#[help("remove this `else` block")]
942-
pub(crate) else_span: Option<Span>,
930+
#[subdiagnostic]
931+
pub(crate) be_replaced: Option<LetElseReplacementSuggestion>,
932+
}
933+
934+
#[derive(Subdiagnostic, Debug)]
935+
#[suggestion(
936+
"consider using `let {$lhs} = {$rhs}` to match on a specific variant",
937+
code = "let {lhs} = {rhs}",
938+
applicability = "machine-applicable"
939+
)]
940+
pub(crate) struct LetElseReplacementSuggestion {
941+
#[primary_span]
942+
pub(crate) span: Span,
943+
pub(crate) lhs: String,
944+
pub(crate) rhs: String,
943945
}
944946

945947
#[derive(Diagnostic)]

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
168168
let Ok(()) = self.visit_land(ex, &mut chain_refutabilities) else { return };
169169
// Lint only single irrefutable let binding.
170170
if let [Some((_, Irrefutable))] = chain_refutabilities[..] {
171-
self.lint_single_let(ex.span, None);
171+
self.lint_single_let(ex.span, None, None);
172172
}
173173
return;
174174
}
@@ -438,7 +438,45 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
438438
if let LetSource::PlainLet = self.let_source {
439439
self.check_binding_is_irrefutable(pat, "local binding", scrut, Some(span));
440440
} else if let Ok(Irrefutable) = self.is_let_irrefutable(pat, scrut) {
441-
self.lint_single_let(span, else_span);
441+
if span.from_expansion() {
442+
self.lint_single_let(span, None, None);
443+
return;
444+
}
445+
let let_else_span = self.check_irrefutable_option_some(pat, scrut, span);
446+
447+
let sm = self.tcx.sess.source_map();
448+
let next_token_start = sm.span_extend_while_whitespace(span.clone()).hi();
449+
let line_span = sm.span_extend_to_line(span.clone()).with_lo(next_token_start);
450+
let else_keyword_span = sm.span_until_whitespace(line_span);
451+
self.lint_single_let(span, Some(else_keyword_span), let_else_span);
452+
}
453+
}
454+
455+
/// Check case `let x = Some(y);`, user likely intended to destructure `Option`
456+
fn check_irrefutable_option_some(
457+
&self,
458+
pat: &'p Pat<'tcx>,
459+
initializer: Option<&Expr<'tcx>>,
460+
span: Span,
461+
) -> Option<LetElseReplacementSuggestion> {
462+
if let sm = self.tcx.sess.source_map()
463+
&& let Some(initializer) = initializer
464+
&& let Some(s_ty) = initializer.ty.ty_adt_def()
465+
&& self.tcx.is_diagnostic_item(rustc_span::sym::Option, s_ty.did())
466+
&& let ExprKind::Scope { value, .. } = initializer.kind
467+
&& let initializer_expr = &self.thir[value]
468+
&& let ExprKind::Adt(box AdtExpr { fields, .. }) = &initializer_expr.kind
469+
&& let Some(field) = fields.first()
470+
&& let inner = &self.thir[field.expr]
471+
&& let Some(inner_ty) = inner.ty.ty_adt_def()
472+
&& self.tcx.is_diagnostic_item(rustc_span::sym::Option, inner_ty.did())
473+
&& let Ok(rhs) = sm.span_to_snippet(inner.span)
474+
&& let Ok(lhs) = sm.span_to_snippet(pat.span)
475+
{
476+
let lhs = format!("Some({})", lhs);
477+
Some(LetElseReplacementSuggestion { span, lhs, rhs })
478+
} else {
479+
None
442480
}
443481
}
444482

@@ -559,14 +597,20 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
559597
}
560598

561599
#[instrument(level = "trace", skip(self))]
562-
fn lint_single_let(&mut self, let_span: Span, else_span: Option<Span>) {
600+
fn lint_single_let(
601+
&mut self,
602+
let_span: Span,
603+
else_keyword_span: Option<Span>,
604+
let_else_span: Option<LetElseReplacementSuggestion>,
605+
) {
563606
report_irrefutable_let_patterns(
564607
self.tcx,
565608
self.hir_source,
566609
self.let_source,
567610
1,
568611
let_span,
569-
else_span,
612+
else_keyword_span,
613+
let_else_span,
570614
);
571615
}
572616

@@ -862,7 +906,8 @@ fn report_irrefutable_let_patterns(
862906
source: LetSource,
863907
count: usize,
864908
span: Span,
865-
else_span: Option<Span>,
909+
else_keyword_span: Option<Span>,
910+
let_else_span: Option<LetElseReplacementSuggestion>,
866911
) {
867912
macro_rules! emit_diag {
868913
($lint:tt) => {{
@@ -875,11 +920,23 @@ fn report_irrefutable_let_patterns(
875920
LetSource::IfLet | LetSource::ElseIfLet => emit_diag!(IrrefutableLetPatternsIfLet),
876921
LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard),
877922
LetSource::LetElse => {
923+
let spans = match else_keyword_span {
924+
Some(else_keyword_span) => {
925+
let mut spans = MultiSpan::from_span(else_keyword_span);
926+
spans.push_span_label(
927+
span,
928+
msg!("assigning to binding pattern will always succeed"),
929+
);
930+
spans
931+
}
932+
None => span.into(),
933+
};
934+
878935
tcx.emit_node_span_lint(
879936
IRREFUTABLE_LET_PATTERNS,
880937
id,
881-
span,
882-
IrrefutableLetPatternsLetElse { count, else_span },
938+
spans,
939+
IrrefutableLetPatternsLetElse { be_replaced: let_else_span },
883940
);
884941
}
885942
LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet),

compiler/rustc_session/src/config/print_request.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ use crate::macros::AllVariants;
1515
pub struct PrintRequest {
1616
pub kind: PrintKind,
1717
pub out: OutFileName,
18+
pub arg: Option<String>,
1819
}
1920

2021
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2122
#[derive(AllVariants)]
2223
pub enum PrintKind {
2324
// tidy-alphabetical-start
2425
AllTargetSpecsJson,
26+
BackendHasMnemonic,
2527
BackendHasZstd,
2628
CallingConventions,
2729
Cfg,
@@ -55,6 +57,7 @@ impl PrintKind {
5557
match self {
5658
// tidy-alphabetical-start
5759
AllTargetSpecsJson => "all-target-specs-json",
60+
BackendHasMnemonic => "backend-has-mnemonic",
5861
BackendHasZstd => "backend-has-zstd",
5962
CallingConventions => "calling-conventions",
6063
Cfg => "cfg",
@@ -108,7 +111,8 @@ impl PrintKind {
108111

109112
// Unstable values:
110113
AllTargetSpecsJson => false,
111-
BackendHasZstd => false, // (perma-unstable, for use by compiletest)
114+
BackendHasMnemonic => false, // (perma-unstable, for use by compiletest)
115+
BackendHasZstd => false, // (perma-unstable, for use by compiletest)
112116
CheckCfg => false,
113117
CrateRootLintLevels => false,
114118
SupportedCrateTypes => false,
@@ -145,11 +149,19 @@ pub(crate) fn collect_print_requests(
145149
) -> Vec<PrintRequest> {
146150
let mut prints = Vec::<PrintRequest>::new();
147151
if cg.target_cpu.as_deref() == Some("help") {
148-
prints.push(PrintRequest { kind: PrintKind::TargetCPUs, out: OutFileName::Stdout });
152+
prints.push(PrintRequest {
153+
kind: PrintKind::TargetCPUs,
154+
out: OutFileName::Stdout,
155+
arg: None,
156+
});
149157
cg.target_cpu = None;
150158
};
151159
if cg.target_feature == "help" {
152-
prints.push(PrintRequest { kind: PrintKind::TargetFeatures, out: OutFileName::Stdout });
160+
prints.push(PrintRequest {
161+
kind: PrintKind::TargetFeatures,
162+
out: OutFileName::Stdout,
163+
arg: None,
164+
});
153165
cg.target_feature = String::new();
154166
}
155167

@@ -162,9 +174,22 @@ pub(crate) fn collect_print_requests(
162174
prints.extend(matches.opt_strs("print").into_iter().map(|req| {
163175
let (req, out) = split_out_file_name(&req);
164176

165-
let kind = if let Some(print_kind) = PrintKind::from_str(req) {
177+
let (kind, arg) = if let Some(mnemonic) = req.strip_prefix("backend-has-mnemonic") {
178+
check_print_request_stability(early_dcx, unstable_opts, PrintKind::BackendHasMnemonic);
179+
// BackendHasMnemonic requires a mnemonic argument
180+
if let Some(mnemonic) = mnemonic.strip_prefix(':')
181+
&& !mnemonic.is_empty()
182+
{
183+
(PrintKind::BackendHasMnemonic, Some(mnemonic.to_string()))
184+
} else {
185+
early_dcx.early_fatal(
186+
"expected mnemonic name after `--print=backend-has-mnemonic:`, \
187+
for example: `--print=backend-has-mnemonic:RET`",
188+
);
189+
}
190+
} else if let Some(print_kind) = PrintKind::from_str(req) {
166191
check_print_request_stability(early_dcx, unstable_opts, print_kind);
167-
print_kind
192+
(print_kind, None)
168193
} else {
169194
let is_nightly = nightly_options::match_is_nightly_build(matches);
170195
emit_unknown_print_request_help(early_dcx, req, is_nightly)
@@ -180,7 +205,7 @@ pub(crate) fn collect_print_requests(
180205
}
181206
}
182207

183-
PrintRequest { kind, out }
208+
PrintRequest { kind, out, arg }
184209
}));
185210

186211
prints

compiler/rustc_trait_selection/src/traits/effects.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -554,11 +554,7 @@ fn evaluate_host_effect_for_fn_goal<'tcx>(
554554
// but they don't really need to right now.
555555
ty::CoroutineClosure(_, _) => return Err(EvaluationFailure::NoSolution),
556556

557-
ty::Closure(def, args) => {
558-
// For now we limit ourselves to closures without binders. The next solver can handle them.
559-
args.as_closure().sig().no_bound_vars().ok_or(EvaluationFailure::NoSolution)?;
560-
(def, args)
561-
}
557+
ty::Closure(def, args) => (def, args),
562558

563559
// Everything else needs explicit impls or cannot have an impl
564560
_ => return Err(EvaluationFailure::NoSolution),

src/doc/rustc-dev-guide/src/tests/compiletest.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,17 @@ See also the [codegen tests](#codegen-tests) for a similar set of tests.
346346
If you need to work with `#![no_std]` cross-compiling tests, consult the
347347
[`minicore` test auxiliary](./minicore.md) chapter.
348348

349+
#### Conditional assembly tests based on instruction support
350+
351+
Tests that depend on specific assembly instructions being available can use the
352+
`//@ needs-asm-mnemonic: <MNEMONIC>` directive. This will skip the test if the
353+
target backend does not support the specified instruction mnemonic.
354+
355+
For example, a test that requires the `RET` instruction:
356+
```rust,ignore
357+
//@ needs-asm-mnemonic: RET
358+
```
359+
349360
[`tests/assembly-llvm`]: https://github.com/rust-lang/rust/tree/HEAD/tests/assembly-llvm
350361

351362

0 commit comments

Comments
 (0)