authorbors <bors@rust-lang.org> 2025-07-18 05:43:22 UTC
committerbors <bors@rust-lang.org> 2025-07-18 05:43:22 UTC
log6c0a912e5a45904cf537f34876b16ae71d899f86
treeca6f588353d028825a4f2b30d57013e310acda9d
parent1aa5b2246560ce85b42fa8b33e5927c5de3fa389
parentc22e2ead96c24fca3b20876c186a71d6184e4603

Auto merge of #144109 - matthiaskrgr:rollup-mz0mrww, r=matthiaskrgr

Rollup of 11 pull requests Successful merges: - rust-lang/rust#142300 (Disable `tests/run-make/mte-ffi` because no CI runners have MTE extensions enabled) - rust-lang/rust#143271 (Store the type of each GVN value) - rust-lang/rust#143293 (fix `-Zsanitizer=kcfi` on `#[naked]` functions) - rust-lang/rust#143719 (Emit warning when there is no space between `-o` and arg) - rust-lang/rust#143846 (pass --gc-sections if -Zexport-executable-symbols is enabled and improve tests) - rust-lang/rust#143891 (Port `#[coverage]` to the new attribute system) - rust-lang/rust#143967 (constify `Option` methods) - rust-lang/rust#144008 (Fix false positive double negations with macro invocation) - rust-lang/rust#144010 (Boostrap: add warning on `optimize = false`) - rust-lang/rust#144049 (rustc-dev-guide subtree update) - rust-lang/rust#144056 (Copy GCC sources into the build directory even outside CI) r? `@ghost` `@rustbot` modify labels: rollup

87 files changed, 1362 insertions(+), 1877 deletions(-)

compiler/rustc_attr_data_structures/src/attributes.rs+19
......@@ -110,6 +110,22 @@ pub enum DeprecatedSince {
110110 Err,
111111}
112112
113#[derive(
114 Copy,
115 Debug,
116 Eq,
117 PartialEq,
118 Encodable,
119 Decodable,
120 Clone,
121 HashStable_Generic,
122 PrintAttribute
123)]
124pub enum CoverageStatus {
125 On,
126 Off,
127}
128
113129impl Deprecation {
114130 /// Whether an item marked with #[deprecated(since = "X")] is currently
115131 /// deprecated (i.e., whether X is not greater than the current rustc
......@@ -274,6 +290,9 @@ pub enum AttributeKind {
274290 /// Represents `#[const_trait]`.
275291 ConstTrait(Span),
276292
293 /// Represents `#[coverage]`.
294 Coverage(Span, CoverageStatus),
295
277296 ///Represents `#[rustc_deny_explicit_impl]`.
278297 DenyExplicitImpl(Span),
279298
compiler/rustc_attr_data_structures/src/encode_cross_crate.rs+1
......@@ -28,6 +28,7 @@ impl AttributeKind {
2828 ConstStability { .. } => Yes,
2929 ConstStabilityIndirect => No,
3030 ConstTrait(..) => No,
31 Coverage(..) => No,
3132 DenyExplicitImpl(..) => No,
3233 Deprecation { .. } => Yes,
3334 DoNotImplementViaObject(..) => No,
compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs+40-1
......@@ -1,4 +1,4 @@
1use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy};
1use rustc_attr_data_structures::{AttributeKind, CoverageStatus, OptimizeAttr, UsedBy};
22use rustc_feature::{AttributeTemplate, template};
33use rustc_session::parse::feature_err;
44use rustc_span::{Span, Symbol, sym};
......@@ -52,6 +52,45 @@ impl<S: Stage> NoArgsAttributeParser<S> for ColdParser {
5252 const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold;
5353}
5454
55pub(crate) struct CoverageParser;
56
57impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
58 const PATH: &[Symbol] = &[sym::coverage];
59 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
60 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
61 const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]);
62
63 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
64 let Some(args) = args.list() else {
65 cx.expected_specific_argument_and_list(cx.attr_span, vec!["on", "off"]);
66 return None;
67 };
68
69 let Some(arg) = args.single() else {
70 cx.expected_single_argument(args.span);
71 return None;
72 };
73
74 let fail_incorrect_argument = |span| cx.expected_specific_argument(span, vec!["on", "off"]);
75
76 let Some(arg) = arg.meta_item() else {
77 fail_incorrect_argument(args.span);
78 return None;
79 };
80
81 let status = match arg.path().word_sym() {
82 Some(sym::off) => CoverageStatus::Off,
83 Some(sym::on) => CoverageStatus::On,
84 None | Some(_) => {
85 fail_incorrect_argument(arg.span());
86 return None;
87 }
88 };
89
90 Some(AttributeKind::Coverage(cx.attr_span, status))
91 }
92}
93
5594pub(crate) struct ExportNameParser;
5695
5796impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
compiler/rustc_attr_parsing/src/context.rs+24-2
......@@ -17,8 +17,9 @@ use crate::attributes::allow_unstable::{
1717 AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
1818};
1919use crate::attributes::codegen_attrs::{
20 ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser,
21 OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser,
20 ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser,
21 OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser,
22 UsedParser,
2223};
2324use crate::attributes::confusables::ConfusablesParser;
2425use crate::attributes::deprecation::DeprecationParser;
......@@ -139,6 +140,7 @@ attribute_parsers!(
139140 // tidy-alphabetical-end
140141
141142 // tidy-alphabetical-start
143 Single<CoverageParser>,
142144 Single<DeprecationParser>,
143145 Single<DummyParser>,
144146 Single<ExportNameParser>,
......@@ -452,6 +454,25 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
452454 reason: AttributeParseErrorReason::ExpectedSpecificArgument {
453455 possibilities,
454456 strings: false,
457 list: false,
458 },
459 })
460 }
461
462 pub(crate) fn expected_specific_argument_and_list(
463 &self,
464 span: Span,
465 possibilities: Vec<&'static str>,
466 ) -> ErrorGuaranteed {
467 self.emit_err(AttributeParseError {
468 span,
469 attr_span: self.attr_span,
470 template: self.template.clone(),
471 attribute: self.attr_path.clone(),
472 reason: AttributeParseErrorReason::ExpectedSpecificArgument {
473 possibilities,
474 strings: false,
475 list: true,
455476 },
456477 })
457478 }
......@@ -469,6 +490,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
469490 reason: AttributeParseErrorReason::ExpectedSpecificArgument {
470491 possibilities,
471492 strings: true,
493 list: false,
472494 },
473495 })
474496 }
compiler/rustc_attr_parsing/src/session_diagnostics.rs+46-3
......@@ -533,7 +533,9 @@ pub(crate) struct LinkOrdinalOutOfRange {
533533
534534pub(crate) enum AttributeParseErrorReason {
535535 ExpectedNoArgs,
536 ExpectedStringLiteral { byte_string: Option<Span> },
536 ExpectedStringLiteral {
537 byte_string: Option<Span>,
538 },
537539 ExpectedIntegerLiteral,
538540 ExpectedAtLeastOneArgument,
539541 ExpectedSingleArgument,
......@@ -541,7 +543,12 @@ pub(crate) enum AttributeParseErrorReason {
541543 UnexpectedLiteral,
542544 ExpectedNameValue(Option<Symbol>),
543545 DuplicateKey(Symbol),
544 ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool },
546 ExpectedSpecificArgument {
547 possibilities: Vec<&'static str>,
548 strings: bool,
549 /// Should we tell the user to write a list when they didn't?
550 list: bool,
551 },
545552}
546553
547554pub(crate) struct AttributeParseError {
......@@ -615,7 +622,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
615622 format!("expected this to be of the form `{name} = \"...\"`"),
616623 );
617624 }
618 AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings } => {
625 AttributeParseErrorReason::ExpectedSpecificArgument {
626 possibilities,
627 strings,
628 list: false,
629 } => {
619630 let quote = if strings { '"' } else { '`' };
620631 match possibilities.as_slice() {
621632 &[] => {}
......@@ -641,6 +652,38 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
641652 }
642653 }
643654 }
655 AttributeParseErrorReason::ExpectedSpecificArgument {
656 possibilities,
657 strings,
658 list: true,
659 } => {
660 let quote = if strings { '"' } else { '`' };
661 match possibilities.as_slice() {
662 &[] => {}
663 &[x] => {
664 diag.span_label(
665 self.span,
666 format!(
667 "this attribute is only valid with {quote}{x}{quote} as an argument"
668 ),
669 );
670 }
671 [first, second] => {
672 diag.span_label(self.span, format!("this attribute is only valid with either {quote}{first}{quote} or {quote}{second}{quote} as an argument"));
673 }
674 [first @ .., second_to_last, last] => {
675 let mut res = String::new();
676 for i in first {
677 res.push_str(&format!("{quote}{i}{quote}, "));
678 }
679 res.push_str(&format!(
680 "{quote}{second_to_last}{quote} or {quote}{last}{quote}"
681 ));
682
683 diag.span_label(self.span, format!("this attribute is only valid with one of the following arguments: {res}"));
684 }
685 }
686 }
644687 }
645688
646689 let suggestions = self.template.suggestions(false, &name);
compiler/rustc_codegen_cranelift/src/driver/aot.rs+2-2
......@@ -530,8 +530,8 @@ fn codegen_cgu_content(
530530 for (mono_item, item_data) in mono_items {
531531 match mono_item {
532532 MonoItem::Fn(instance) => {
533 if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED)
534 {
533 let flags = tcx.codegen_instance_attrs(instance.def).flags;
534 if flags.contains(CodegenFnAttrFlags::NAKED) {
535535 rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm(
536536 &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm },
537537 instance,
compiler/rustc_codegen_cranelift/src/driver/jit.rs+1-1
......@@ -127,7 +127,7 @@ fn codegen_and_compile_fn<'tcx>(
127127 module: &mut dyn Module,
128128 instance: Instance<'tcx>,
129129) {
130 if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
130 if tcx.codegen_instance_attrs(instance.def).flags.contains(CodegenFnAttrFlags::NAKED) {
131131 tcx.dcx()
132132 .span_fatal(tcx.def_span(instance.def_id()), "Naked asm is not supported in JIT mode");
133133 }
compiler/rustc_codegen_cranelift/src/driver/mod.rs+1-1
......@@ -35,7 +35,7 @@ fn predefine_mono_items<'tcx>(
3535 is_compiler_builtins,
3636 );
3737 let is_naked = tcx
38 .codegen_fn_attrs(instance.def_id())
38 .codegen_instance_attrs(instance.def)
3939 .flags
4040 .contains(CodegenFnAttrFlags::NAKED);
4141 module
compiler/rustc_codegen_gcc/src/attributes.rs+1-1
......@@ -87,7 +87,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
8787 #[cfg_attr(not(feature = "master"), allow(unused_variables))] func: Function<'gcc>,
8888 instance: ty::Instance<'tcx>,
8989) {
90 let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
90 let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def);
9191
9292 #[cfg(feature = "master")]
9393 {
compiler/rustc_codegen_gcc/src/callee.rs+1-1
......@@ -105,7 +105,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
105105 let is_hidden = if is_generic {
106106 // This is a monomorphization of a generic function.
107107 if !(cx.tcx.sess.opts.share_generics()
108 || tcx.codegen_fn_attrs(instance_def_id).inline
108 || tcx.codegen_instance_attrs(instance.def).inline
109109 == rustc_attr_data_structures::InlineAttr::Never)
110110 {
111111 // When not sharing generics, all instances are in the same
compiler/rustc_codegen_gcc/src/mono_item.rs+1-1
......@@ -53,7 +53,7 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
5353 let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
5454 self.linkage.set(base::linkage_to_gcc(linkage));
5555 let decl = self.declare_fn(symbol_name, fn_abi);
56 //let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
56 //let attrs = self.tcx.codegen_instance_attrs(instance.def);
5757
5858 attributes::from_fn_attrs(self, decl, instance);
5959
compiler/rustc_codegen_llvm/src/attributes.rs+1-1
......@@ -344,7 +344,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
344344 llfn: &'ll Value,
345345 instance: ty::Instance<'tcx>,
346346) {
347 let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
347 let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def);
348348
349349 let mut to_add = SmallVec::<[_; 16]>::new();
350350
compiler/rustc_codegen_llvm/src/callee.rs+1-1
......@@ -102,7 +102,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
102102 let is_hidden = if is_generic {
103103 // This is a monomorphization of a generic function.
104104 if !(cx.tcx.sess.opts.share_generics()
105 || tcx.codegen_fn_attrs(instance_def_id).inline
105 || tcx.codegen_instance_attrs(instance.def).inline
106106 == rustc_attr_data_structures::InlineAttr::Never)
107107 {
108108 // When not sharing generics, all instances are in the same
compiler/rustc_codegen_llvm/src/mono_item.rs+2-2
......@@ -55,8 +55,8 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
5555 let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
5656 let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance));
5757 llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage));
58 let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
59 base::set_link_section(lldecl, attrs);
58 let attrs = self.tcx.codegen_instance_attrs(instance.def);
59 base::set_link_section(lldecl, &attrs);
6060 if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR)
6161 && self.tcx.sess.target.supports_comdat()
6262 {
compiler/rustc_codegen_ssa/src/back/link.rs+1-6
......@@ -2542,12 +2542,7 @@ fn add_order_independent_options(
25422542 // sections to ensure we have all the data for PGO.
25432543 let keep_metadata =
25442544 crate_type == CrateType::Dylib || sess.opts.cg.profile_generate.enabled();
2545 if crate_type != CrateType::Executable || !sess.opts.unstable_opts.export_executable_symbols
2546 {
2547 cmd.gc_sections(keep_metadata);
2548 } else {
2549 cmd.no_gc_sections();
2550 }
2545 cmd.gc_sections(keep_metadata);
25512546 }
25522547
25532548 cmd.set_output_kind(link_output_kind, crate_type, out_filename);
compiler/rustc_codegen_ssa/src/back/linker.rs-33
......@@ -326,7 +326,6 @@ pub(crate) trait Linker {
326326 link_or_cc_args(self, &[path]);
327327 }
328328 fn gc_sections(&mut self, keep_metadata: bool);
329 fn no_gc_sections(&mut self);
330329 fn full_relro(&mut self);
331330 fn partial_relro(&mut self);
332331 fn no_relro(&mut self);
......@@ -688,12 +687,6 @@ impl<'a> Linker for GccLinker<'a> {
688687 }
689688 }
690689
691 fn no_gc_sections(&mut self) {
692 if self.is_gnu || self.sess.target.is_like_wasm {
693 self.link_arg("--no-gc-sections");
694 }
695 }
696
697690 fn optimize(&mut self) {
698691 if !self.is_gnu && !self.sess.target.is_like_wasm {
699692 return;
......@@ -1010,10 +1003,6 @@ impl<'a> Linker for MsvcLinker<'a> {
10101003 }
10111004 }
10121005
1013 fn no_gc_sections(&mut self) {
1014 self.link_arg("/OPT:NOREF,NOICF");
1015 }
1016
10171006 fn full_relro(&mut self) {
10181007 // noop
10191008 }
......@@ -1243,10 +1232,6 @@ impl<'a> Linker for EmLinker<'a> {
12431232 // noop
12441233 }
12451234
1246 fn no_gc_sections(&mut self) {
1247 // noop
1248 }
1249
12501235 fn optimize(&mut self) {
12511236 // Emscripten performs own optimizations
12521237 self.cc_arg(match self.sess.opts.optimize {
......@@ -1418,10 +1403,6 @@ impl<'a> Linker for WasmLd<'a> {
14181403 self.link_arg("--gc-sections");
14191404 }
14201405
1421 fn no_gc_sections(&mut self) {
1422 self.link_arg("--no-gc-sections");
1423 }
1424
14251406 fn optimize(&mut self) {
14261407 // The -O flag is, as of late 2023, only used for merging of strings and debuginfo, and
14271408 // only differentiates -O0 and -O1. It does not apply to LTO.
......@@ -1567,10 +1548,6 @@ impl<'a> Linker for L4Bender<'a> {
15671548 }
15681549 }
15691550
1570 fn no_gc_sections(&mut self) {
1571 self.link_arg("--no-gc-sections");
1572 }
1573
15741551 fn optimize(&mut self) {
15751552 // GNU-style linkers support optimization with -O. GNU ld doesn't
15761553 // need a numeric argument, but other linkers do.
......@@ -1734,10 +1711,6 @@ impl<'a> Linker for AixLinker<'a> {
17341711 self.link_arg("-bgc");
17351712 }
17361713
1737 fn no_gc_sections(&mut self) {
1738 self.link_arg("-bnogc");
1739 }
1740
17411714 fn optimize(&mut self) {}
17421715
17431716 fn pgo_gen(&mut self) {
......@@ -1982,8 +1955,6 @@ impl<'a> Linker for PtxLinker<'a> {
19821955
19831956 fn gc_sections(&mut self, _keep_metadata: bool) {}
19841957
1985 fn no_gc_sections(&mut self) {}
1986
19871958 fn pgo_gen(&mut self) {}
19881959
19891960 fn no_crt_objects(&mut self) {}
......@@ -2057,8 +2028,6 @@ impl<'a> Linker for LlbcLinker<'a> {
20572028
20582029 fn gc_sections(&mut self, _keep_metadata: bool) {}
20592030
2060 fn no_gc_sections(&mut self) {}
2061
20622031 fn pgo_gen(&mut self) {}
20632032
20642033 fn no_crt_objects(&mut self) {}
......@@ -2139,8 +2108,6 @@ impl<'a> Linker for BpfLinker<'a> {
21392108
21402109 fn gc_sections(&mut self, _keep_metadata: bool) {}
21412110
2142 fn no_gc_sections(&mut self) {}
2143
21442111 fn pgo_gen(&mut self) {}
21452112
21462113 fn no_crt_objects(&mut self) {}
compiler/rustc_codegen_ssa/src/mir/debuginfo.rs+1-1
......@@ -356,7 +356,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
356356 LocalRef::Operand(operand) => {
357357 // Don't spill operands onto the stack in naked functions.
358358 // See: https://github.com/rust-lang/rust/issues/42779
359 let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id());
359 let attrs = bx.tcx().codegen_instance_attrs(self.instance.def);
360360 if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
361361 return;
362362 }
compiler/rustc_codegen_ssa/src/mir/mod.rs+2-3
......@@ -390,9 +390,8 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
390390
391391 let mut num_untupled = None;
392392
393 let codegen_fn_attrs = bx.tcx().codegen_fn_attrs(fx.instance.def_id());
394 let naked = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED);
395 if naked {
393 let codegen_fn_attrs = bx.tcx().codegen_instance_attrs(fx.instance.def);
394 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
396395 return vec![];
397396 }
398397
compiler/rustc_codegen_ssa/src/mir/naked_asm.rs+1-1
......@@ -128,7 +128,7 @@ fn prefix_and_suffix<'tcx>(
128128 let is_arm = tcx.sess.target.arch == "arm";
129129 let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode);
130130
131 let attrs = tcx.codegen_fn_attrs(instance.def_id());
131 let attrs = tcx.codegen_instance_attrs(instance.def);
132132 let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string());
133133
134134 // If no alignment is specified, an alignment of 4 bytes is used.
compiler/rustc_codegen_ssa/src/mir/rvalue.rs+10-2
......@@ -611,11 +611,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
611611 let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
612612 let fn_ty = bx.fn_decl_backend_type(fn_abi);
613613 let fn_attrs = if bx.tcx().def_kind(instance.def_id()).has_codegen_attrs() {
614 Some(bx.tcx().codegen_fn_attrs(instance.def_id()))
614 Some(bx.tcx().codegen_instance_attrs(instance.def))
615615 } else {
616616 None
617617 };
618 bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None, Some(instance))
618 bx.call(
619 fn_ty,
620 fn_attrs.as_deref(),
621 Some(fn_abi),
622 fn_ptr,
623 &[],
624 None,
625 Some(instance),
626 )
619627 } else {
620628 bx.get_static(def_id)
621629 };
compiler/rustc_codegen_ssa/src/mono_item.rs+3-7
......@@ -41,12 +41,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
4141 base::codegen_global_asm(cx, item_id);
4242 }
4343 MonoItem::Fn(instance) => {
44 if cx
45 .tcx()
46 .codegen_fn_attrs(instance.def_id())
47 .flags
48 .contains(CodegenFnAttrFlags::NAKED)
49 {
44 let flags = cx.tcx().codegen_instance_attrs(instance.def).flags;
45 if flags.contains(CodegenFnAttrFlags::NAKED) {
5046 naked_asm::codegen_naked_asm::<Bx::CodegenCx>(cx, instance, item_data);
5147 } else {
5248 base::codegen_instance::<Bx>(cx, instance);
......@@ -75,7 +71,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
7571 cx.predefine_static(def_id, linkage, visibility, symbol_name);
7672 }
7773 MonoItem::Fn(instance) => {
78 let attrs = cx.tcx().codegen_fn_attrs(instance.def_id());
74 let attrs = cx.tcx().codegen_instance_attrs(instance.def);
7975
8076 if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
8177 // do not define this function; it will become a global assembly block
compiler/rustc_const_eval/src/interpret/memory.rs+1-1
......@@ -936,7 +936,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
936936 if let Some(fn_val) = self.get_fn_alloc(id) {
937937 let align = match fn_val {
938938 FnVal::Instance(instance) => {
939 self.tcx.codegen_fn_attrs(instance.def_id()).alignment.unwrap_or(Align::ONE)
939 self.tcx.codegen_instance_attrs(instance.def).alignment.unwrap_or(Align::ONE)
940940 }
941941 // Machine-specific extra functions currently do not support alignment restrictions.
942942 FnVal::Other(_) => Align::ONE,
compiler/rustc_driver_impl/src/lib.rs+46
......@@ -1237,9 +1237,55 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
12371237 return None;
12381238 }
12391239
1240 warn_on_confusing_output_filename_flag(early_dcx, &matches, args);
1241
12401242 Some(matches)
12411243}
12421244
1245/// Warn if `-o` is used without a space between the flag name and the value
1246/// and the value is a high-value confusables,
1247/// e.g. `-optimize` instead of `-o optimize`, see issue #142812.
1248fn warn_on_confusing_output_filename_flag(
1249 early_dcx: &EarlyDiagCtxt,
1250 matches: &getopts::Matches,
1251 args: &[String],
1252) {
1253 fn eq_ignore_separators(s1: &str, s2: &str) -> bool {
1254 let s1 = s1.replace('-', "_");
1255 let s2 = s2.replace('-', "_");
1256 s1 == s2
1257 }
1258
1259 if let Some(name) = matches.opt_str("o")
1260 && let Some(suspect) = args.iter().find(|arg| arg.starts_with("-o") && *arg != "-o")
1261 {
1262 let filename = suspect.strip_prefix("-").unwrap_or(suspect);
1263 let optgroups = config::rustc_optgroups();
1264 let fake_args = ["optimize", "o0", "o1", "o2", "o3", "ofast", "og", "os", "oz"];
1265
1266 // Check if provided filename might be confusing in conjunction with `-o` flag,
1267 // i.e. consider `-o{filename}` such as `-optimize` with `filename` being `ptimize`.
1268 // There are high-value confusables, for example:
1269 // - Long name of flags, e.g. `--out-dir` vs `-out-dir`
1270 // - C compiler flag, e.g. `optimize`, `o0`, `o1`, `o2`, `o3`, `ofast`.
1271 // - Codegen flags, e.g. `pt-level` of `-opt-level`.
1272 if optgroups.iter().any(|option| eq_ignore_separators(option.long_name(), filename))
1273 || config::CG_OPTIONS.iter().any(|option| eq_ignore_separators(option.name(), filename))
1274 || fake_args.iter().any(|arg| eq_ignore_separators(arg, filename))
1275 {
1276 early_dcx.early_warn(
1277 "option `-o` has no space between flag name and value, which can be confusing",
1278 );
1279 early_dcx.early_note(format!(
1280 "output filename `-o {name}` is applied instead of a flag named `o{name}`"
1281 ));
1282 early_dcx.early_help(format!(
1283 "insert a space between `-o` and `{name}` if this is intentional: `-o {name}`"
1284 ));
1285 }
1286 }
1287}
1288
12431289fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> {
12441290 let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
12451291 Input::File(file) => new_parser_from_file(&sess.psess, file, None),
compiler/rustc_lint/src/builtin.rs+2
......@@ -1585,6 +1585,8 @@ impl EarlyLintPass for DoubleNegations {
15851585 if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind
15861586 && let ExprKind::Unary(UnOp::Neg, ref inner2) = inner.kind
15871587 && !matches!(inner2.kind, ExprKind::Unary(UnOp::Neg, _))
1588 // Don't lint if this jumps macro expansion boundary (Issue #143980)
1589 && expr.span.eq_ctxt(inner.span)
15881590 {
15891591 cx.emit_span_lint(
15901592 DOUBLE_NEGATIONS,
compiler/rustc_middle/src/middle/codegen_fn_attrs.rs+22
......@@ -1,3 +1,5 @@
1use std::borrow::Cow;
2
13use rustc_abi::Align;
24use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs;
35use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr};
......@@ -6,6 +8,26 @@ use rustc_span::Symbol;
68use rustc_target::spec::SanitizerSet;
79
810use crate::mir::mono::Linkage;
11use crate::ty::{InstanceKind, TyCtxt};
12
13impl<'tcx> TyCtxt<'tcx> {
14 pub fn codegen_instance_attrs(
15 self,
16 instance_kind: InstanceKind<'_>,
17 ) -> Cow<'tcx, CodegenFnAttrs> {
18 let mut attrs = Cow::Borrowed(self.codegen_fn_attrs(instance_kind.def_id()));
19
20 // Drop the `#[naked]` attribute on non-item `InstanceKind`s, like the shims that
21 // are generated for indirect function calls.
22 if !matches!(instance_kind, InstanceKind::Item(_)) {
23 if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
24 attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED);
25 }
26 }
27
28 attrs
29 }
30}
931
1032#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
1133pub struct CodegenFnAttrs {
compiler/rustc_middle/src/mir/mono.rs+6-7
......@@ -152,7 +152,7 @@ impl<'tcx> MonoItem<'tcx> {
152152 // If the function is #[naked] or contains any other attribute that requires exactly-once
153153 // instantiation:
154154 // We emit an unused_attributes lint for this case, which should be kept in sync if possible.
155 let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
155 let codegen_fn_attrs = tcx.codegen_instance_attrs(instance.def);
156156 if codegen_fn_attrs.contains_extern_indicator()
157157 || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
158158 {
......@@ -219,7 +219,7 @@ impl<'tcx> MonoItem<'tcx> {
219219 // functions the same as those that unconditionally get LocalCopy codegen. It's only when
220220 // we get here that we can at least not codegen a #[inline(never)] generic function in all
221221 // of our CGUs.
222 if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline
222 if let InlineAttr::Never = codegen_fn_attrs.inline
223223 && self.is_generic_fn()
224224 {
225225 return InstantiationMode::GloballyShared { may_conflict: true };
......@@ -234,14 +234,13 @@ impl<'tcx> MonoItem<'tcx> {
234234 }
235235
236236 pub fn explicit_linkage(&self, tcx: TyCtxt<'tcx>) -> Option<Linkage> {
237 let def_id = match *self {
238 MonoItem::Fn(ref instance) => instance.def_id(),
239 MonoItem::Static(def_id) => def_id,
237 let instance_kind = match *self {
238 MonoItem::Fn(ref instance) => instance.def,
239 MonoItem::Static(def_id) => InstanceKind::Item(def_id),
240240 MonoItem::GlobalAsm(..) => return None,
241241 };
242242
243 let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
244 codegen_fn_attrs.linkage
243 tcx.codegen_instance_attrs(instance_kind).linkage
245244 }
246245
247246 /// Returns `true` if this instance is instantiable - whether it has no unsatisfied
compiler/rustc_middle/src/query/mod.rs+9
......@@ -1505,6 +1505,15 @@ rustc_queries! {
15051505 separate_provide_extern
15061506 }
15071507
1508 /// Returns the `CodegenFnAttrs` for the item at `def_id`.
1509 ///
1510 /// If possible, use `tcx.codegen_instance_attrs` instead. That function takes the
1511 /// instance kind into account.
1512 ///
1513 /// For example, the `#[naked]` attribute should be applied for `InstanceKind::Item`,
1514 /// but should not be applied if the instance kind is `InstanceKind::ReifyShim`.
1515 /// Using this query would include the attribute regardless of the actual instance
1516 /// kind at the call site.
15081517 query codegen_fn_attrs(def_id: DefId) -> &'tcx CodegenFnAttrs {
15091518 desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) }
15101519 arena_cache
compiler/rustc_mir_transform/src/coverage/query.rs+13-19
......@@ -1,3 +1,4 @@
1use rustc_attr_data_structures::{AttributeKind, CoverageStatus, find_attr};
12use rustc_index::bit_set::DenseBitSet;
23use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
34use rustc_middle::mir::coverage::{BasicCoverageBlock, CoverageIdsInfo, CoverageKind, MappingKind};
......@@ -5,7 +6,6 @@ use rustc_middle::mir::{Body, Statement, StatementKind};
56use rustc_middle::ty::{self, TyCtxt};
67use rustc_middle::util::Providers;
78use rustc_span::def_id::LocalDefId;
8use rustc_span::sym;
99use tracing::trace;
1010
1111use crate::coverage::counters::node_flow::make_node_counters;
......@@ -58,26 +58,20 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
5858/// Query implementation for `coverage_attr_on`.
5959fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
6060 // Check for annotations directly on this def.
61 if let Some(attr) = tcx.get_attr(def_id, sym::coverage) {
62 match attr.meta_item_list().as_deref() {
63 Some([item]) if item.has_name(sym::off) => return false,
64 Some([item]) if item.has_name(sym::on) => return true,
65 Some(_) | None => {
66 // Other possibilities should have been rejected by `rustc_parse::validate_attr`.
67 // Use `span_delayed_bug` to avoid an ICE in failing builds (#127880).
68 tcx.dcx().span_delayed_bug(attr.span(), "unexpected value of coverage attribute");
69 }
61 if let Some(coverage_status) =
62 find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Coverage(_, status) => status)
63 {
64 *coverage_status == CoverageStatus::On
65 } else {
66 match tcx.opt_local_parent(def_id) {
67 // Check the parent def (and so on recursively) until we find an
68 // enclosing attribute or reach the crate root.
69 Some(parent) => tcx.coverage_attr_on(parent),
70 // We reached the crate root without seeing a coverage attribute, so
71 // allow coverage instrumentation by default.
72 None => true,
7073 }
7174 }
72
73 match tcx.opt_local_parent(def_id) {
74 // Check the parent def (and so on recursively) until we find an
75 // enclosing attribute or reach the crate root.
76 Some(parent) => tcx.coverage_attr_on(parent),
77 // We reached the crate root without seeing a coverage attribute, so
78 // allow coverage instrumentation by default.
79 None => true,
80 }
8175}
8276
8377/// Query implementation for `coverage_ids_info`.
compiler/rustc_mir_transform/src/gvn.rs+255-298
......@@ -105,7 +105,6 @@ use rustc_middle::mir::*;
105105use rustc_middle::ty::layout::HasTypingEnv;
106106use rustc_middle::ty::{self, Ty, TyCtxt};
107107use rustc_span::DUMMY_SP;
108use rustc_span::def_id::DefId;
109108use smallvec::SmallVec;
110109use tracing::{debug, instrument, trace};
111110
......@@ -130,7 +129,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
130129 let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls);
131130
132131 for local in body.args_iter().filter(|&local| ssa.is_ssa(local)) {
133 let opaque = state.new_opaque();
132 let opaque = state.new_opaque(body.local_decls[local].ty);
134133 state.assign(local, opaque);
135134 }
136135
......@@ -155,22 +154,6 @@ newtype_index! {
155154 struct VnIndex {}
156155}
157156
158/// Computing the aggregate's type can be quite slow, so we only keep the minimal amount of
159/// information to reconstruct it when needed.
160#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
161enum AggregateTy<'tcx> {
162 /// Invariant: this must not be used for an empty array.
163 Array,
164 Tuple,
165 Def(DefId, ty::GenericArgsRef<'tcx>),
166 RawPtr {
167 /// Needed for cast propagation.
168 data_pointer_ty: Ty<'tcx>,
169 /// The data pointer can be anything thin, so doesn't determine the output.
170 output_pointer_ty: Ty<'tcx>,
171 },
172}
173
174157#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
175158enum AddressKind {
176159 Ref(BorrowKind),
......@@ -193,7 +176,14 @@ enum Value<'tcx> {
193176 },
194177 /// An aggregate value, either tuple/closure/struct/enum.
195178 /// This does not contain unions, as we cannot reason with the value.
196 Aggregate(AggregateTy<'tcx>, VariantIdx, Vec<VnIndex>),
179 Aggregate(VariantIdx, Vec<VnIndex>),
180 /// A raw pointer aggregate built from a thin pointer and metadata.
181 RawPtr {
182 /// Thin pointer component. This is field 0 in MIR.
183 pointer: VnIndex,
184 /// Metadata component. This is field 1 in MIR.
185 metadata: VnIndex,
186 },
197187 /// This corresponds to a `[value; count]` expression.
198188 Repeat(VnIndex, ty::Const<'tcx>),
199189 /// The address of a place.
......@@ -206,7 +196,7 @@ enum Value<'tcx> {
206196
207197 // Extractions.
208198 /// This is the *value* obtained by projecting another value.
209 Projection(VnIndex, ProjectionElem<VnIndex, Ty<'tcx>>),
199 Projection(VnIndex, ProjectionElem<VnIndex, ()>),
210200 /// Discriminant of the given value.
211201 Discriminant(VnIndex),
212202 /// Length of an array or slice.
......@@ -219,8 +209,6 @@ enum Value<'tcx> {
219209 Cast {
220210 kind: CastKind,
221211 value: VnIndex,
222 from: Ty<'tcx>,
223 to: Ty<'tcx>,
224212 },
225213}
226214
......@@ -228,12 +216,13 @@ struct VnState<'body, 'tcx> {
228216 tcx: TyCtxt<'tcx>,
229217 ecx: InterpCx<'tcx, DummyMachine>,
230218 local_decls: &'body LocalDecls<'tcx>,
219 is_coroutine: bool,
231220 /// Value stored in each local.
232221 locals: IndexVec<Local, Option<VnIndex>>,
233222 /// Locals that are assigned that value.
234223 // This vector does not hold all the values of `VnIndex` that we create.
235224 rev_locals: IndexVec<VnIndex, SmallVec<[Local; 1]>>,
236 values: FxIndexSet<Value<'tcx>>,
225 values: FxIndexSet<(Value<'tcx>, Ty<'tcx>)>,
237226 /// Values evaluated as constants if possible.
238227 evaluated: IndexVec<VnIndex, Option<OpTy<'tcx>>>,
239228 /// Counter to generate different values.
......@@ -265,6 +254,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
265254 tcx,
266255 ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine),
267256 local_decls,
257 is_coroutine: body.coroutine.is_some(),
268258 locals: IndexVec::from_elem(None, local_decls),
269259 rev_locals: IndexVec::with_capacity(num_values),
270260 values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
......@@ -282,8 +272,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
282272 }
283273
284274 #[instrument(level = "trace", skip(self), ret)]
285 fn insert(&mut self, value: Value<'tcx>) -> VnIndex {
286 let (index, new) = self.values.insert_full(value);
275 fn insert(&mut self, ty: Ty<'tcx>, value: Value<'tcx>) -> VnIndex {
276 let (index, new) = self.values.insert_full((value, ty));
287277 let index = VnIndex::from_usize(index);
288278 if new {
289279 // Grow `evaluated` and `rev_locals` here to amortize the allocations.
......@@ -305,20 +295,33 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
305295 /// Create a new `Value` for which we have no information at all, except that it is distinct
306296 /// from all the others.
307297 #[instrument(level = "trace", skip(self), ret)]
308 fn new_opaque(&mut self) -> VnIndex {
298 fn new_opaque(&mut self, ty: Ty<'tcx>) -> VnIndex {
309299 let value = Value::Opaque(self.next_opaque());
310 self.insert(value)
300 self.insert(ty, value)
311301 }
312302
313303 /// Create a new `Value::Address` distinct from all the others.
314304 #[instrument(level = "trace", skip(self), ret)]
315305 fn new_pointer(&mut self, place: Place<'tcx>, kind: AddressKind) -> VnIndex {
306 let pty = place.ty(self.local_decls, self.tcx).ty;
307 let ty = match kind {
308 AddressKind::Ref(bk) => {
309 Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, pty, bk.to_mutbl_lossy())
310 }
311 AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, pty, mutbl.to_mutbl_lossy()),
312 };
316313 let value = Value::Address { place, kind, provenance: self.next_opaque() };
317 self.insert(value)
314 self.insert(ty, value)
318315 }
319316
317 #[inline]
320318 fn get(&self, index: VnIndex) -> &Value<'tcx> {
321 self.values.get_index(index.as_usize()).unwrap()
319 &self.values.get_index(index.as_usize()).unwrap().0
320 }
321
322 #[inline]
323 fn ty(&self, index: VnIndex) -> Ty<'tcx> {
324 self.values.get_index(index.as_usize()).unwrap().1
322325 }
323326
324327 /// Record that `local` is assigned `value`. `local` must be SSA.
......@@ -341,29 +344,29 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
341344 debug_assert_ne!(disambiguator, 0);
342345 disambiguator
343346 };
344 self.insert(Value::Constant { value, disambiguator })
347 self.insert(value.ty(), Value::Constant { value, disambiguator })
345348 }
346349
347350 fn insert_bool(&mut self, flag: bool) -> VnIndex {
348351 // Booleans are deterministic.
349352 let value = Const::from_bool(self.tcx, flag);
350353 debug_assert!(value.is_deterministic());
351 self.insert(Value::Constant { value, disambiguator: 0 })
354 self.insert(self.tcx.types.bool, Value::Constant { value, disambiguator: 0 })
352355 }
353356
354 fn insert_scalar(&mut self, scalar: Scalar, ty: Ty<'tcx>) -> VnIndex {
357 fn insert_scalar(&mut self, ty: Ty<'tcx>, scalar: Scalar) -> VnIndex {
355358 // Scalars are deterministic.
356359 let value = Const::from_scalar(self.tcx, scalar, ty);
357360 debug_assert!(value.is_deterministic());
358 self.insert(Value::Constant { value, disambiguator: 0 })
361 self.insert(ty, Value::Constant { value, disambiguator: 0 })
359362 }
360363
361 fn insert_tuple(&mut self, values: Vec<VnIndex>) -> VnIndex {
362 self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::ZERO, values))
364 fn insert_tuple(&mut self, ty: Ty<'tcx>, values: Vec<VnIndex>) -> VnIndex {
365 self.insert(ty, Value::Aggregate(VariantIdx::ZERO, values))
363366 }
364367
365 fn insert_deref(&mut self, value: VnIndex) -> VnIndex {
366 let value = self.insert(Value::Projection(value, ProjectionElem::Deref));
368 fn insert_deref(&mut self, ty: Ty<'tcx>, value: VnIndex) -> VnIndex {
369 let value = self.insert(ty, Value::Projection(value, ProjectionElem::Deref));
367370 self.derefs.push(value);
368371 value
369372 }
......@@ -371,14 +374,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
371374 fn invalidate_derefs(&mut self) {
372375 for deref in std::mem::take(&mut self.derefs) {
373376 let opaque = self.next_opaque();
374 *self.values.get_index_mut2(deref.index()).unwrap() = Value::Opaque(opaque);
377 self.values.get_index_mut2(deref.index()).unwrap().0 = Value::Opaque(opaque);
375378 }
376379 }
377380
378381 #[instrument(level = "trace", skip(self), ret)]
379382 fn eval_to_const(&mut self, value: VnIndex) -> Option<OpTy<'tcx>> {
380383 use Value::*;
384 let ty = self.ty(value);
385 // Avoid computing layouts inside a coroutine, as that can cause cycles.
386 let ty = if !self.is_coroutine || ty.is_scalar() {
387 self.ecx.layout_of(ty).ok()?
388 } else {
389 return None;
390 };
381391 let op = match *self.get(value) {
392 _ if ty.is_zst() => ImmTy::uninit(ty).into(),
393
382394 Opaque(_) => return None,
383395 // Do not bother evaluating repeat expressions. This would uselessly consume memory.
384396 Repeat(..) => return None,
......@@ -386,42 +398,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
386398 Constant { ref value, disambiguator: _ } => {
387399 self.ecx.eval_mir_constant(value, DUMMY_SP, None).discard_err()?
388400 }
389 Aggregate(kind, variant, ref fields) => {
401 Aggregate(variant, ref fields) => {
390402 let fields = fields
391403 .iter()
392404 .map(|&f| self.evaluated[f].as_ref())
393405 .collect::<Option<Vec<_>>>()?;
394 let ty = match kind {
395 AggregateTy::Array => {
396 assert!(fields.len() > 0);
397 Ty::new_array(self.tcx, fields[0].layout.ty, fields.len() as u64)
398 }
399 AggregateTy::Tuple => {
400 Ty::new_tup_from_iter(self.tcx, fields.iter().map(|f| f.layout.ty))
401 }
402 AggregateTy::Def(def_id, args) => {
403 self.tcx.type_of(def_id).instantiate(self.tcx, args)
404 }
405 AggregateTy::RawPtr { output_pointer_ty, .. } => output_pointer_ty,
406 };
407 let variant = if ty.is_enum() { Some(variant) } else { None };
408 let ty = self.ecx.layout_of(ty).ok()?;
409 if ty.is_zst() {
410 ImmTy::uninit(ty).into()
411 } else if matches!(kind, AggregateTy::RawPtr { .. }) {
412 // Pointers don't have fields, so don't `project_field` them.
413 let data = self.ecx.read_pointer(fields[0]).discard_err()?;
414 let meta = if fields[1].layout.is_zst() {
415 MemPlaceMeta::None
416 } else {
417 MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).discard_err()?)
418 };
419 let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx);
420 ImmTy::from_immediate(ptr_imm, ty).into()
421 } else if matches!(
422 ty.backend_repr,
423 BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)
424 ) {
406 let variant = if ty.ty.is_enum() { Some(variant) } else { None };
407 if matches!(ty.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..))
408 {
425409 let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
426410 let variant_dest = if let Some(variant) = variant {
427411 self.ecx.project_downcast(&dest, variant).discard_err()?
......@@ -446,32 +430,46 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
446430 return None;
447431 }
448432 }
433 RawPtr { pointer, metadata } => {
434 let pointer = self.evaluated[pointer].as_ref()?;
435 let metadata = self.evaluated[metadata].as_ref()?;
436
437 // Pointers don't have fields, so don't `project_field` them.
438 let data = self.ecx.read_pointer(pointer).discard_err()?;
439 let meta = if metadata.layout.is_zst() {
440 MemPlaceMeta::None
441 } else {
442 MemPlaceMeta::Meta(self.ecx.read_scalar(metadata).discard_err()?)
443 };
444 let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx);
445 ImmTy::from_immediate(ptr_imm, ty).into()
446 }
449447
450448 Projection(base, elem) => {
451 let value = self.evaluated[base].as_ref()?;
449 let base = self.evaluated[base].as_ref()?;
452450 let elem = match elem {
453451 ProjectionElem::Deref => ProjectionElem::Deref,
454452 ProjectionElem::Downcast(name, read_variant) => {
455453 ProjectionElem::Downcast(name, read_variant)
456454 }
457 ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty),
455 ProjectionElem::Field(f, ()) => ProjectionElem::Field(f, ty.ty),
458456 ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
459457 ProjectionElem::ConstantIndex { offset, min_length, from_end }
460458 }
461459 ProjectionElem::Subslice { from, to, from_end } => {
462460 ProjectionElem::Subslice { from, to, from_end }
463461 }
464 ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
465 ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
466 ProjectionElem::UnwrapUnsafeBinder(ty) => {
467 ProjectionElem::UnwrapUnsafeBinder(ty)
462 ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty.ty),
463 ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty.ty),
464 ProjectionElem::UnwrapUnsafeBinder(()) => {
465 ProjectionElem::UnwrapUnsafeBinder(ty.ty)
468466 }
469467 // This should have been replaced by a `ConstantIndex` earlier.
470468 ProjectionElem::Index(_) => return None,
471469 };
472 self.ecx.project(value, elem).discard_err()?
470 self.ecx.project(base, elem).discard_err()?
473471 }
474 Address { place, kind, provenance: _ } => {
472 Address { place, kind: _, provenance: _ } => {
475473 if !place.is_indirect_first_projection() {
476474 return None;
477475 }
......@@ -487,19 +485,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
487485 mplace = self.ecx.project(&mplace, proj).discard_err()?;
488486 }
489487 let pointer = mplace.to_ref(&self.ecx);
490 let ty = match kind {
491 AddressKind::Ref(bk) => Ty::new_ref(
492 self.tcx,
493 self.tcx.lifetimes.re_erased,
494 mplace.layout.ty,
495 bk.to_mutbl_lossy(),
496 ),
497 AddressKind::Address(mutbl) => {
498 Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl.to_mutbl_lossy())
499 }
500 };
501 let layout = self.ecx.layout_of(ty).ok()?;
502 ImmTy::from_immediate(pointer, layout).into()
488 ImmTy::from_immediate(pointer, ty).into()
503489 }
504490
505491 Discriminant(base) => {
......@@ -511,32 +497,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
511497 }
512498 Len(slice) => {
513499 let slice = self.evaluated[slice].as_ref()?;
514 let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
515500 let len = slice.len(&self.ecx).discard_err()?;
516 let imm = ImmTy::from_uint(len, usize_layout);
517 imm.into()
501 ImmTy::from_uint(len, ty).into()
518502 }
519 NullaryOp(null_op, ty) => {
520 let layout = self.ecx.layout_of(ty).ok()?;
503 NullaryOp(null_op, arg_ty) => {
504 let arg_layout = self.ecx.layout_of(arg_ty).ok()?;
521505 if let NullOp::SizeOf | NullOp::AlignOf = null_op
522 && layout.is_unsized()
506 && arg_layout.is_unsized()
523507 {
524508 return None;
525509 }
526510 let val = match null_op {
527 NullOp::SizeOf => layout.size.bytes(),
528 NullOp::AlignOf => layout.align.abi.bytes(),
511 NullOp::SizeOf => arg_layout.size.bytes(),
512 NullOp::AlignOf => arg_layout.align.abi.bytes(),
529513 NullOp::OffsetOf(fields) => self
530514 .ecx
531515 .tcx
532 .offset_of_subfield(self.typing_env(), layout, fields.iter())
516 .offset_of_subfield(self.typing_env(), arg_layout, fields.iter())
533517 .bytes(),
534518 NullOp::UbChecks => return None,
535519 NullOp::ContractChecks => return None,
536520 };
537 let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
538 let imm = ImmTy::from_uint(val, usize_layout);
539 imm.into()
521 ImmTy::from_uint(val, ty).into()
540522 }
541523 UnaryOp(un_op, operand) => {
542524 let operand = self.evaluated[operand].as_ref()?;
......@@ -552,30 +534,27 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
552534 let val = self.ecx.binary_op(bin_op, &lhs, &rhs).discard_err()?;
553535 val.into()
554536 }
555 Cast { kind, value, from: _, to } => match kind {
537 Cast { kind, value } => match kind {
556538 CastKind::IntToInt | CastKind::IntToFloat => {
557539 let value = self.evaluated[value].as_ref()?;
558540 let value = self.ecx.read_immediate(value).discard_err()?;
559 let to = self.ecx.layout_of(to).ok()?;
560 let res = self.ecx.int_to_int_or_float(&value, to).discard_err()?;
541 let res = self.ecx.int_to_int_or_float(&value, ty).discard_err()?;
561542 res.into()
562543 }
563544 CastKind::FloatToFloat | CastKind::FloatToInt => {
564545 let value = self.evaluated[value].as_ref()?;
565546 let value = self.ecx.read_immediate(value).discard_err()?;
566 let to = self.ecx.layout_of(to).ok()?;
567 let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?;
547 let res = self.ecx.float_to_float_or_int(&value, ty).discard_err()?;
568548 res.into()
569549 }
570550 CastKind::Transmute => {
571551 let value = self.evaluated[value].as_ref()?;
572 let to = self.ecx.layout_of(to).ok()?;
573552 // `offset` for immediates generally only supports projections that match the
574553 // type of the immediate. However, as a HACK, we exploit that it can also do
575554 // limited transmutes: it only works between types with the same layout, and
576555 // cannot transmute pointers to integers.
577556 if value.as_mplace_or_imm().is_right() {
578 let can_transmute = match (value.layout.backend_repr, to.backend_repr) {
557 let can_transmute = match (value.layout.backend_repr, ty.backend_repr) {
579558 (BackendRepr::Scalar(s1), BackendRepr::Scalar(s2)) => {
580559 s1.size(&self.ecx) == s2.size(&self.ecx)
581560 && !matches!(s1.primitive(), Primitive::Pointer(..))
......@@ -595,13 +574,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
595574 return None;
596575 }
597576 }
598 value.offset(Size::ZERO, to, &self.ecx).discard_err()?
577 value.offset(Size::ZERO, ty, &self.ecx).discard_err()?
599578 }
600579 CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) => {
601580 let src = self.evaluated[value].as_ref()?;
602 let to = self.ecx.layout_of(to).ok()?;
603 let dest = self.ecx.allocate(to, MemoryKind::Stack).discard_err()?;
604 self.ecx.unsize_into(src, to, &dest.clone().into()).discard_err()?;
581 let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
582 self.ecx.unsize_into(src, ty, &dest.clone().into()).discard_err()?;
605583 self.ecx
606584 .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
607585 .discard_err()?;
......@@ -610,15 +588,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
610588 CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
611589 let src = self.evaluated[value].as_ref()?;
612590 let src = self.ecx.read_immediate(src).discard_err()?;
613 let to = self.ecx.layout_of(to).ok()?;
614 let ret = self.ecx.ptr_to_ptr(&src, to).discard_err()?;
591 let ret = self.ecx.ptr_to_ptr(&src, ty).discard_err()?;
615592 ret.into()
616593 }
617594 CastKind::PointerCoercion(ty::adjustment::PointerCoercion::UnsafeFnPointer, _) => {
618595 let src = self.evaluated[value].as_ref()?;
619596 let src = self.ecx.read_immediate(src).discard_err()?;
620 let to = self.ecx.layout_of(to).ok()?;
621 ImmTy::from_immediate(*src, to).into()
597 ImmTy::from_immediate(*src, ty).into()
622598 }
623599 _ => return None,
624600 },
......@@ -628,31 +604,30 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
628604
629605 fn project(
630606 &mut self,
631 place: PlaceRef<'tcx>,
607 place_ty: PlaceTy<'tcx>,
632608 value: VnIndex,
633609 proj: PlaceElem<'tcx>,
634610 from_non_ssa_index: &mut bool,
635 ) -> Option<VnIndex> {
611 ) -> Option<(PlaceTy<'tcx>, VnIndex)> {
612 let projection_ty = place_ty.projection_ty(self.tcx, proj);
636613 let proj = match proj {
637614 ProjectionElem::Deref => {
638 let ty = place.ty(self.local_decls, self.tcx).ty;
639 if let Some(Mutability::Not) = ty.ref_mutability()
640 && let Some(pointee_ty) = ty.builtin_deref(true)
641 && pointee_ty.is_freeze(self.tcx, self.typing_env())
615 if let Some(Mutability::Not) = place_ty.ty.ref_mutability()
616 && projection_ty.ty.is_freeze(self.tcx, self.typing_env())
642617 {
643618 // An immutable borrow `_x` always points to the same value for the
644619 // lifetime of the borrow, so we can merge all instances of `*_x`.
645 return Some(self.insert_deref(value));
620 return Some((projection_ty, self.insert_deref(projection_ty.ty, value)));
646621 } else {
647622 return None;
648623 }
649624 }
650625 ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index),
651 ProjectionElem::Field(f, ty) => {
652 if let Value::Aggregate(_, _, fields) = self.get(value) {
653 return Some(fields[f.as_usize()]);
626 ProjectionElem::Field(f, _) => {
627 if let Value::Aggregate(_, fields) = self.get(value) {
628 return Some((projection_ty, fields[f.as_usize()]));
654629 } else if let Value::Projection(outer_value, ProjectionElem::Downcast(_, read_variant)) = self.get(value)
655 && let Value::Aggregate(_, written_variant, fields) = self.get(*outer_value)
630 && let Value::Aggregate(written_variant, fields) = self.get(*outer_value)
656631 // This pass is not aware of control-flow, so we do not know whether the
657632 // replacement we are doing is actually reachable. We could be in any arm of
658633 // ```
......@@ -670,14 +645,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
670645 // a downcast to an inactive variant.
671646 && written_variant == read_variant
672647 {
673 return Some(fields[f.as_usize()]);
648 return Some((projection_ty, fields[f.as_usize()]));
674649 }
675 ProjectionElem::Field(f, ty)
650 ProjectionElem::Field(f, ())
676651 }
677652 ProjectionElem::Index(idx) => {
678653 if let Value::Repeat(inner, _) = self.get(value) {
679654 *from_non_ssa_index |= self.locals[idx].is_none();
680 return Some(*inner);
655 return Some((projection_ty, *inner));
681656 }
682657 let idx = self.locals[idx]?;
683658 ProjectionElem::Index(idx)
......@@ -685,15 +660,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
685660 ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
686661 match self.get(value) {
687662 Value::Repeat(inner, _) => {
688 return Some(*inner);
663 return Some((projection_ty, *inner));
689664 }
690 Value::Aggregate(AggregateTy::Array, _, operands) => {
665 Value::Aggregate(_, operands) => {
691666 let offset = if from_end {
692667 operands.len() - offset as usize
693668 } else {
694669 offset as usize
695670 };
696 return operands.get(offset).copied();
671 let value = operands.get(offset).copied()?;
672 return Some((projection_ty, value));
697673 }
698674 _ => {}
699675 };
......@@ -702,12 +678,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
702678 ProjectionElem::Subslice { from, to, from_end } => {
703679 ProjectionElem::Subslice { from, to, from_end }
704680 }
705 ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
706 ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
707 ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty),
681 ProjectionElem::OpaqueCast(_) => ProjectionElem::OpaqueCast(()),
682 ProjectionElem::Subtype(_) => ProjectionElem::Subtype(()),
683 ProjectionElem::UnwrapUnsafeBinder(_) => ProjectionElem::UnwrapUnsafeBinder(()),
708684 };
709685
710 Some(self.insert(Value::Projection(value, proj)))
686 let value = self.insert(projection_ty.ty, Value::Projection(value, proj));
687 Some((projection_ty, value))
711688 }
712689
713690 /// Simplify the projection chain if we know better.
......@@ -769,6 +746,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
769746
770747 // Invariant: `value` holds the value up-to the `index`th projection excluded.
771748 let mut value = self.locals[place.local]?;
749 // Invariant: `value` has type `place_ty`, with optional downcast variant if needed.
750 let mut place_ty = PlaceTy::from_ty(self.local_decls[place.local].ty);
772751 let mut from_non_ssa_index = false;
773752 for (index, proj) in place.projection.iter().enumerate() {
774753 if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value)
......@@ -786,8 +765,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
786765 place_ref = PlaceRef { local, projection: &place.projection[index..] };
787766 }
788767
789 let base = PlaceRef { local: place.local, projection: &place.projection[..index] };
790 value = self.project(base, value, proj, &mut from_non_ssa_index)?;
768 (place_ty, value) = self.project(place_ty, value, proj, &mut from_non_ssa_index)?;
791769 }
792770
793771 if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value)
......@@ -864,14 +842,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
864842 self.simplify_place_projection(place, location);
865843 return Some(self.new_pointer(*place, AddressKind::Address(mutbl)));
866844 }
867 Rvalue::WrapUnsafeBinder(ref mut op, ty) => {
845 Rvalue::WrapUnsafeBinder(ref mut op, _) => {
868846 let value = self.simplify_operand(op, location)?;
869 Value::Cast {
870 kind: CastKind::Transmute,
871 value,
872 from: op.ty(self.local_decls, self.tcx),
873 to: ty,
874 }
847 Value::Cast { kind: CastKind::Transmute, value }
875848 }
876849
877850 // Operations.
......@@ -896,18 +869,17 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
896869 // Unsupported values.
897870 Rvalue::ThreadLocalRef(..) | Rvalue::ShallowInitBox(..) => return None,
898871 };
899 debug!(?value);
900 Some(self.insert(value))
872 let ty = rvalue.ty(self.local_decls, self.tcx);
873 Some(self.insert(ty, value))
901874 }
902875
903876 fn simplify_discriminant(&mut self, place: VnIndex) -> Option<VnIndex> {
904 if let Value::Aggregate(enum_ty, variant, _) = *self.get(place)
905 && let AggregateTy::Def(enum_did, enum_args) = enum_ty
906 && let DefKind::Enum = self.tcx.def_kind(enum_did)
877 let enum_ty = self.ty(place);
878 if enum_ty.is_enum()
879 && let Value::Aggregate(variant, _) = *self.get(place)
907880 {
908 let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_args);
909881 let discr = self.ecx.discriminant_for_variant(enum_ty, variant).discard_err()?;
910 return Some(self.insert_scalar(discr.to_scalar(), discr.layout.ty));
882 return Some(self.insert_scalar(discr.layout.ty, discr.to_scalar()));
911883 }
912884
913885 None
......@@ -915,12 +887,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
915887
916888 fn try_as_place_elem(
917889 &mut self,
918 proj: ProjectionElem<VnIndex, Ty<'tcx>>,
890 ty: Ty<'tcx>,
891 proj: ProjectionElem<VnIndex, ()>,
919892 loc: Location,
920893 ) -> Option<PlaceElem<'tcx>> {
921894 Some(match proj {
922895 ProjectionElem::Deref => ProjectionElem::Deref,
923 ProjectionElem::Field(idx, ty) => ProjectionElem::Field(idx, ty),
896 ProjectionElem::Field(idx, ()) => ProjectionElem::Field(idx, ty),
924897 ProjectionElem::Index(idx) => {
925898 let Some(local) = self.try_as_local(idx, loc) else {
926899 return None;
......@@ -935,9 +908,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
935908 ProjectionElem::Subslice { from, to, from_end }
936909 }
937910 ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx),
938 ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx),
939 ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(idx),
940 ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty),
911 ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty),
912 ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty),
913 ProjectionElem::UnwrapUnsafeBinder(()) => ProjectionElem::UnwrapUnsafeBinder(ty),
941914 })
942915 }
943916
......@@ -983,8 +956,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
983956
984957 // Allow introducing places with non-constant offsets, as those are still better than
985958 // reconstructing an aggregate.
986 if let Some(place) = self.try_as_place(copy_from_local_value, location, true)
987 && rvalue.ty(self.local_decls, self.tcx) == place.ty(self.local_decls, self.tcx).ty
959 if self.ty(copy_from_local_value) == rvalue.ty(self.local_decls, self.tcx)
960 && let Some(place) = self.try_as_place(copy_from_local_value, location, true)
988961 {
989962 // Avoid creating `*a = copy (*b)`, as they might be aliases resulting in overlapping assignments.
990963 // FIXME: This also avoids any kind of projection, not just derefs. We can add allowed projections.
......@@ -1004,9 +977,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1004977 rvalue: &mut Rvalue<'tcx>,
1005978 location: Location,
1006979 ) -> Option<VnIndex> {
980 let tcx = self.tcx;
981 let ty = rvalue.ty(self.local_decls, tcx);
982
1007983 let Rvalue::Aggregate(box ref kind, ref mut field_ops) = *rvalue else { bug!() };
1008984
1009 let tcx = self.tcx;
1010985 if field_ops.is_empty() {
1011986 let is_zst = match *kind {
1012987 AggregateKind::Array(..)
......@@ -1021,87 +996,72 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1021996 };
1022997
1023998 if is_zst {
1024 let ty = rvalue.ty(self.local_decls, tcx);
1025999 return Some(self.insert_constant(Const::zero_sized(ty)));
10261000 }
10271001 }
10281002
1029 let (mut ty, variant_index) = match *kind {
1030 AggregateKind::Array(..) => {
1031 assert!(!field_ops.is_empty());
1032 (AggregateTy::Array, FIRST_VARIANT)
1033 }
1034 AggregateKind::Tuple => {
1003 let fields: Vec<_> = field_ops
1004 .iter_mut()
1005 .map(|op| {
1006 self.simplify_operand(op, location)
1007 .unwrap_or_else(|| self.new_opaque(op.ty(self.local_decls, self.tcx)))
1008 })
1009 .collect();
1010
1011 let variant_index = match *kind {
1012 AggregateKind::Array(..) | AggregateKind::Tuple => {
10351013 assert!(!field_ops.is_empty());
1036 (AggregateTy::Tuple, FIRST_VARIANT)
1037 }
1038 AggregateKind::Closure(did, args)
1039 | AggregateKind::CoroutineClosure(did, args)
1040 | AggregateKind::Coroutine(did, args) => (AggregateTy::Def(did, args), FIRST_VARIANT),
1041 AggregateKind::Adt(did, variant_index, args, _, None) => {
1042 (AggregateTy::Def(did, args), variant_index)
1014 FIRST_VARIANT
10431015 }
1016 AggregateKind::Closure(..)
1017 | AggregateKind::CoroutineClosure(..)
1018 | AggregateKind::Coroutine(..) => FIRST_VARIANT,
1019 AggregateKind::Adt(_, variant_index, _, _, None) => variant_index,
10441020 // Do not track unions.
10451021 AggregateKind::Adt(_, _, _, _, Some(_)) => return None,
1046 AggregateKind::RawPtr(pointee_ty, mtbl) => {
1022 AggregateKind::RawPtr(..) => {
10471023 assert_eq!(field_ops.len(), 2);
1048 let data_pointer_ty = field_ops[FieldIdx::ZERO].ty(self.local_decls, self.tcx);
1049 let output_pointer_ty = Ty::new_ptr(self.tcx, pointee_ty, mtbl);
1050 (AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty }, FIRST_VARIANT)
1051 }
1052 };
1053
1054 let mut fields: Vec<_> = field_ops
1055 .iter_mut()
1056 .map(|op| self.simplify_operand(op, location).unwrap_or_else(|| self.new_opaque()))
1057 .collect();
1058
1059 if let AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty } = &mut ty {
1060 let mut was_updated = false;
1024 let [mut pointer, metadata] = fields.try_into().unwrap();
1025
1026 // Any thin pointer of matching mutability is fine as the data pointer.
1027 let mut was_updated = false;
1028 while let Value::Cast { kind: CastKind::PtrToPtr, value: cast_value } =
1029 self.get(pointer)
1030 && let ty::RawPtr(from_pointee_ty, from_mtbl) = self.ty(*cast_value).kind()
1031 && let ty::RawPtr(_, output_mtbl) = ty.kind()
1032 && from_mtbl == output_mtbl
1033 && from_pointee_ty.is_sized(self.tcx, self.typing_env())
1034 {
1035 pointer = *cast_value;
1036 was_updated = true;
1037 }
10611038
1062 // Any thin pointer of matching mutability is fine as the data pointer.
1063 while let Value::Cast {
1064 kind: CastKind::PtrToPtr,
1065 value: cast_value,
1066 from: cast_from,
1067 to: _,
1068 } = self.get(fields[0])
1069 && let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind()
1070 && let ty::RawPtr(_, output_mtbl) = output_pointer_ty.kind()
1071 && from_mtbl == output_mtbl
1072 && from_pointee_ty.is_sized(self.tcx, self.typing_env())
1073 {
1074 fields[0] = *cast_value;
1075 *data_pointer_ty = *cast_from;
1076 was_updated = true;
1077 }
1039 if was_updated && let Some(op) = self.try_as_operand(pointer, location) {
1040 field_ops[FieldIdx::ZERO] = op;
1041 }
10781042
1079 if was_updated && let Some(op) = self.try_as_operand(fields[0], location) {
1080 field_ops[FieldIdx::ZERO] = op;
1043 return Some(self.insert(ty, Value::RawPtr { pointer, metadata }));
10811044 }
1082 }
1045 };
10831046
1084 if let AggregateTy::Array = ty
1085 && fields.len() > 4
1086 {
1047 if ty.is_array() && fields.len() > 4 {
10871048 let first = fields[0];
10881049 if fields.iter().all(|&v| v == first) {
10891050 let len = ty::Const::from_target_usize(self.tcx, fields.len().try_into().unwrap());
10901051 if let Some(op) = self.try_as_operand(first, location) {
10911052 *rvalue = Rvalue::Repeat(op, len);
10921053 }
1093 return Some(self.insert(Value::Repeat(first, len)));
1054 return Some(self.insert(ty, Value::Repeat(first, len)));
10941055 }
10951056 }
10961057
1097 if let AggregateTy::Def(_, _) = ty
1098 && let Some(value) =
1099 self.simplify_aggregate_to_copy(lhs, rvalue, location, &fields, variant_index)
1058 if let Some(value) =
1059 self.simplify_aggregate_to_copy(lhs, rvalue, location, &fields, variant_index)
11001060 {
11011061 return Some(value);
11021062 }
11031063
1104 Some(self.insert(Value::Aggregate(ty, variant_index, fields)))
1064 Some(self.insert(ty, Value::Aggregate(variant_index, fields)))
11051065 }
11061066
11071067 #[instrument(level = "trace", skip(self), ret)]
......@@ -1112,6 +1072,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
11121072 location: Location,
11131073 ) -> Option<VnIndex> {
11141074 let mut arg_index = self.simplify_operand(arg_op, location)?;
1075 let arg_ty = self.ty(arg_index);
1076 let ret_ty = op.ty(self.tcx, arg_ty);
11151077
11161078 // PtrMetadata doesn't care about *const vs *mut vs & vs &mut,
11171079 // so start by removing those distinctions so we can update the `Operand`
......@@ -1127,8 +1089,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
11271089 // we can't always know exactly what the metadata are.
11281090 // To allow things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`,
11291091 // it's fine to get a projection as the type.
1130 Value::Cast { kind: CastKind::PtrToPtr, value: inner, from, to }
1131 if self.pointers_have_same_metadata(*from, *to) =>
1092 Value::Cast { kind: CastKind::PtrToPtr, value: inner }
1093 if self.pointers_have_same_metadata(self.ty(*inner), arg_ty) =>
11321094 {
11331095 arg_index = *inner;
11341096 was_updated = true;
......@@ -1165,26 +1127,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
11651127 (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => {
11661128 Value::BinaryOp(BinOp::Eq, *lhs, *rhs)
11671129 }
1168 (UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => {
1169 return Some(fields[1]);
1170 }
1130 (UnOp::PtrMetadata, Value::RawPtr { metadata, .. }) => return Some(*metadata),
11711131 // We have an unsizing cast, which assigns the length to wide pointer metadata.
11721132 (
11731133 UnOp::PtrMetadata,
11741134 Value::Cast {
11751135 kind: CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _),
1176 from,
1177 to,
1178 ..
1136 value: inner,
11791137 },
1180 ) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind()
1181 && let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() =>
1138 ) if let ty::Slice(..) = arg_ty.builtin_deref(true).unwrap().kind()
1139 && let ty::Array(_, len) = self.ty(*inner).builtin_deref(true).unwrap().kind() =>
11821140 {
11831141 return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
11841142 }
11851143 _ => Value::UnaryOp(op, arg_index),
11861144 };
1187 Some(self.insert(value))
1145 Some(self.insert(ret_ty, value))
11881146 }
11891147
11901148 #[instrument(level = "trace", skip(self), ret)]
......@@ -1197,25 +1155,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
11971155 ) -> Option<VnIndex> {
11981156 let lhs = self.simplify_operand(lhs_operand, location);
11991157 let rhs = self.simplify_operand(rhs_operand, location);
1158
12001159 // Only short-circuit options after we called `simplify_operand`
12011160 // on both operands for side effect.
12021161 let mut lhs = lhs?;
12031162 let mut rhs = rhs?;
12041163
1205 let lhs_ty = lhs_operand.ty(self.local_decls, self.tcx);
1164 let lhs_ty = self.ty(lhs);
12061165
12071166 // If we're comparing pointers, remove `PtrToPtr` casts if the from
12081167 // types of both casts and the metadata all match.
12091168 if let BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge = op
12101169 && lhs_ty.is_any_ptr()
1211 && let Value::Cast {
1212 kind: CastKind::PtrToPtr, value: lhs_value, from: lhs_from, ..
1213 } = self.get(lhs)
1214 && let Value::Cast {
1215 kind: CastKind::PtrToPtr, value: rhs_value, from: rhs_from, ..
1216 } = self.get(rhs)
1217 && lhs_from == rhs_from
1218 && self.pointers_have_same_metadata(*lhs_from, lhs_ty)
1170 && let Value::Cast { kind: CastKind::PtrToPtr, value: lhs_value } = self.get(lhs)
1171 && let Value::Cast { kind: CastKind::PtrToPtr, value: rhs_value } = self.get(rhs)
1172 && let lhs_from = self.ty(*lhs_value)
1173 && lhs_from == self.ty(*rhs_value)
1174 && self.pointers_have_same_metadata(lhs_from, lhs_ty)
12191175 {
12201176 lhs = *lhs_value;
12211177 rhs = *rhs_value;
......@@ -1230,8 +1186,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
12301186 if let Some(value) = self.simplify_binary_inner(op, lhs_ty, lhs, rhs) {
12311187 return Some(value);
12321188 }
1189 let ty = op.ty(self.tcx, lhs_ty, self.ty(rhs));
12331190 let value = Value::BinaryOp(op, lhs, rhs);
1234 Some(self.insert(value))
1191 Some(self.insert(ty, value))
12351192 }
12361193
12371194 fn simplify_binary_inner(
......@@ -1323,19 +1280,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
13231280 | BinOp::Shr,
13241281 Left(0),
13251282 _,
1326 ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty),
1283 ) => self.insert_scalar(lhs_ty, Scalar::from_uint(0u128, layout.size)),
13271284 // Attempt to simplify `x | ALL_ONES` to `ALL_ONES`.
13281285 (BinOp::BitOr, _, Left(ones)) | (BinOp::BitOr, Left(ones), _)
13291286 if ones == layout.size.truncate(u128::MAX)
13301287 || (layout.ty.is_bool() && ones == 1) =>
13311288 {
1332 self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty)
1289 self.insert_scalar(lhs_ty, Scalar::from_uint(ones, layout.size))
13331290 }
13341291 // Sub/Xor with itself.
13351292 (BinOp::Sub | BinOp::SubWithOverflow | BinOp::SubUnchecked | BinOp::BitXor, a, b)
13361293 if a == b =>
13371294 {
1338 self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty)
1295 self.insert_scalar(lhs_ty, Scalar::from_uint(0u128, layout.size))
13391296 }
13401297 // Comparison:
13411298 // - if both operands can be computed as bits, just compare the bits;
......@@ -1349,8 +1306,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
13491306 };
13501307
13511308 if op.is_overflowing() {
1309 let ty = Ty::new_tup(self.tcx, &[self.ty(result), self.tcx.types.bool]);
13521310 let false_val = self.insert_bool(false);
1353 Some(self.insert_tuple(vec![result, false_val]))
1311 Some(self.insert_tuple(ty, vec![result, false_val]))
13541312 } else {
13551313 Some(result)
13561314 }
......@@ -1366,9 +1324,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
13661324 use CastKind::*;
13671325 use rustc_middle::ty::adjustment::PointerCoercion::*;
13681326
1369 let mut from = initial_operand.ty(self.local_decls, self.tcx);
13701327 let mut kind = *initial_kind;
13711328 let mut value = self.simplify_operand(initial_operand, location)?;
1329 let mut from = self.ty(value);
13721330 if from == to {
13731331 return Some(value);
13741332 }
......@@ -1376,7 +1334,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
13761334 if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_), _) = kind {
13771335 // Each reification of a generic fn may get a different pointer.
13781336 // Do not try to merge them.
1379 return Some(self.new_opaque());
1337 return Some(self.new_opaque(to));
13801338 }
13811339
13821340 let mut was_ever_updated = false;
......@@ -1399,23 +1357,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
13991357 // If a cast just casts away the metadata again, then we can get it by
14001358 // casting the original thin pointer passed to `from_raw_parts`
14011359 if let PtrToPtr = kind
1402 && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) =
1403 self.get(value)
1360 && let Value::RawPtr { pointer, .. } = self.get(value)
14041361 && let ty::RawPtr(to_pointee, _) = to.kind()
14051362 && to_pointee.is_sized(self.tcx, self.typing_env())
14061363 {
1407 from = *data_pointer_ty;
1408 value = fields[0];
1364 from = self.ty(*pointer);
1365 value = *pointer;
14091366 was_updated_this_iteration = true;
1410 if *data_pointer_ty == to {
1411 return Some(fields[0]);
1367 if from == to {
1368 return Some(*pointer);
14121369 }
14131370 }
14141371
14151372 // Aggregate-then-Transmute can just transmute the original field value,
14161373 // so long as the bytes of a value from only from a single field.
14171374 if let Transmute = kind
1418 && let Value::Aggregate(_aggregate_ty, variant_idx, field_values) = self.get(value)
1375 && let Value::Aggregate(variant_idx, field_values) = self.get(value)
14191376 && let Some((field_idx, field_ty)) =
14201377 self.value_is_all_in_one_field(from, *variant_idx)
14211378 {
......@@ -1428,13 +1385,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
14281385 }
14291386
14301387 // Various cast-then-cast cases can be simplified.
1431 if let Value::Cast {
1432 kind: inner_kind,
1433 value: inner_value,
1434 from: inner_from,
1435 to: inner_to,
1436 } = *self.get(value)
1437 {
1388 if let Value::Cast { kind: inner_kind, value: inner_value } = *self.get(value) {
1389 let inner_from = self.ty(inner_value);
14381390 let new_kind = match (inner_kind, kind) {
14391391 // Even if there's a narrowing cast in here that's fine, because
14401392 // things like `*mut [i32] -> *mut i32 -> *const i32` and
......@@ -1443,9 +1395,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
14431395 // PtrToPtr-then-Transmute is fine so long as the pointer cast is identity:
14441396 // `*const T -> *mut T -> NonNull<T>` is fine, but we need to check for narrowing
14451397 // to skip things like `*const [i32] -> *const i32 -> NonNull<T>`.
1446 (PtrToPtr, Transmute)
1447 if self.pointers_have_same_metadata(inner_from, inner_to) =>
1448 {
1398 (PtrToPtr, Transmute) if self.pointers_have_same_metadata(inner_from, from) => {
14491399 Some(Transmute)
14501400 }
14511401 // Similarly, for Transmute-then-PtrToPtr. Note that we need to check different
......@@ -1456,7 +1406,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
14561406 // If would be legal to always do this, but we don't want to hide information
14571407 // from the backend that it'd otherwise be able to use for optimizations.
14581408 (Transmute, Transmute)
1459 if !self.type_may_have_niche_of_interest_to_backend(inner_to) =>
1409 if !self.type_may_have_niche_of_interest_to_backend(from) =>
14601410 {
14611411 Some(Transmute)
14621412 }
......@@ -1485,7 +1435,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
14851435 *initial_kind = kind;
14861436 }
14871437
1488 Some(self.insert(Value::Cast { kind, value, from, to }))
1438 Some(self.insert(to, Value::Cast { kind, value }))
14891439 }
14901440
14911441 fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> {
......@@ -1507,18 +1457,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
15071457 }
15081458
15091459 // We have an unsizing cast, which assigns the length to wide pointer metadata.
1510 if let Value::Cast { kind, from, to, .. } = self.get(inner)
1460 if let Value::Cast { kind, value: from } = self.get(inner)
15111461 && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind
1512 && let Some(from) = from.builtin_deref(true)
1462 && let Some(from) = self.ty(*from).builtin_deref(true)
15131463 && let ty::Array(_, len) = from.kind()
1514 && let Some(to) = to.builtin_deref(true)
1464 && let Some(to) = self.ty(inner).builtin_deref(true)
15151465 && let ty::Slice(..) = to.kind()
15161466 {
15171467 return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
15181468 }
15191469
15201470 // Fallback: a symbolic `Len`.
1521 Some(self.insert(Value::Len(inner)))
1471 Some(self.insert(self.tcx.types.usize, Value::Len(inner)))
15221472 }
15231473
15241474 fn pointers_have_same_metadata(&self, left_ptr_ty: Ty<'tcx>, right_ptr_ty: Ty<'tcx>) -> bool {
......@@ -1727,7 +1677,7 @@ impl<'tcx> VnState<'_, 'tcx> {
17271677 return Some(place);
17281678 } else if let Value::Projection(pointer, proj) = *self.get(index)
17291679 && (allow_complex_projection || proj.is_stable_offset())
1730 && let Some(proj) = self.try_as_place_elem(proj, loc)
1680 && let Some(proj) = self.try_as_place_elem(self.ty(index), proj, loc)
17311681 {
17321682 projection.push(proj);
17331683 index = pointer;
......@@ -1755,7 +1705,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
17551705
17561706 fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
17571707 self.simplify_place_projection(place, location);
1758 if context.is_mutating_use() && !place.projection.is_empty() {
1708 if context.is_mutating_use() && place.is_indirect() {
17591709 // Non-local mutation maybe invalidate deref.
17601710 self.invalidate_derefs();
17611711 }
......@@ -1767,36 +1717,42 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
17671717 self.super_operand(operand, location);
17681718 }
17691719
1770 fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) {
1771 if let StatementKind::Assign(box (ref mut lhs, ref mut rvalue)) = stmt.kind {
1772 self.simplify_place_projection(lhs, location);
1773
1774 let value = self.simplify_rvalue(lhs, rvalue, location);
1775 let value = if let Some(local) = lhs.as_local()
1776 && self.ssa.is_ssa(local)
1777 // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
1778 // `local` as reusable if we have an exact type match.
1779 && self.local_decls[local].ty == rvalue.ty(self.local_decls, self.tcx)
1720 fn visit_assign(
1721 &mut self,
1722 lhs: &mut Place<'tcx>,
1723 rvalue: &mut Rvalue<'tcx>,
1724 location: Location,
1725 ) {
1726 self.simplify_place_projection(lhs, location);
1727
1728 let value = self.simplify_rvalue(lhs, rvalue, location);
1729 if let Some(value) = value {
1730 if let Some(const_) = self.try_as_constant(value) {
1731 *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
1732 } else if let Some(place) = self.try_as_place(value, location, false)
1733 && *rvalue != Rvalue::Use(Operand::Move(place))
1734 && *rvalue != Rvalue::Use(Operand::Copy(place))
17801735 {
1781 let value = value.unwrap_or_else(|| self.new_opaque());
1782 self.assign(local, value);
1783 Some(value)
1784 } else {
1785 value
1786 };
1787 if let Some(value) = value {
1788 if let Some(const_) = self.try_as_constant(value) {
1789 *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
1790 } else if let Some(place) = self.try_as_place(value, location, false)
1791 && *rvalue != Rvalue::Use(Operand::Move(place))
1792 && *rvalue != Rvalue::Use(Operand::Copy(place))
1793 {
1794 *rvalue = Rvalue::Use(Operand::Copy(place));
1795 self.reused_locals.insert(place.local);
1796 }
1736 *rvalue = Rvalue::Use(Operand::Copy(place));
1737 self.reused_locals.insert(place.local);
17971738 }
17981739 }
1799 self.super_statement(stmt, location);
1740
1741 if lhs.is_indirect() {
1742 // Non-local mutation maybe invalidate deref.
1743 self.invalidate_derefs();
1744 }
1745
1746 if let Some(local) = lhs.as_local()
1747 && self.ssa.is_ssa(local)
1748 && let rvalue_ty = rvalue.ty(self.local_decls, self.tcx)
1749 // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
1750 // `local` as reusable if we have an exact type match.
1751 && self.local_decls[local].ty == rvalue_ty
1752 {
1753 let value = value.unwrap_or_else(|| self.new_opaque(rvalue_ty));
1754 self.assign(local, value);
1755 }
18001756 }
18011757
18021758 fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
......@@ -1804,7 +1760,8 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
18041760 if let Some(local) = destination.as_local()
18051761 && self.ssa.is_ssa(local)
18061762 {
1807 let opaque = self.new_opaque();
1763 let ty = self.local_decls[local].ty;
1764 let opaque = self.new_opaque(ty);
18081765 self.assign(local, opaque);
18091766 }
18101767 }
compiler/rustc_parse/src/validate_attr.rs+1
......@@ -318,6 +318,7 @@ pub fn check_builtin_meta_item(
318318 | sym::rustc_layout_scalar_valid_range_end
319319 | sym::no_implicit_prelude
320320 | sym::automatically_derived
321 | sym::coverage
321322 ) {
322323 return;
323324 }
compiler/rustc_passes/src/check_attr.rs+5-3
......@@ -288,6 +288,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
288288 &Attribute::Parsed(AttributeKind::StdInternalSymbol(attr_span)) => {
289289 self.check_rustc_std_internal_symbol(attr_span, span, target)
290290 }
291 &Attribute::Parsed(AttributeKind::Coverage(attr_span, _)) => {
292 self.check_coverage(attr_span, span, target)
293 }
291294 Attribute::Unparsed(attr_item) => {
292295 style = Some(attr_item.style);
293296 match attr.path().as_slice() {
......@@ -297,7 +300,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
297300 [sym::diagnostic, sym::on_unimplemented, ..] => {
298301 self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target)
299302 }
300 [sym::coverage, ..] => self.check_coverage(attr, span, target),
301303 [sym::no_sanitize, ..] => {
302304 self.check_no_sanitize(attr, span, target)
303305 }
......@@ -588,7 +590,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
588590
589591 /// Checks that `#[coverage(..)]` is applied to a function/closure/method,
590592 /// or to an impl block or module.
591 fn check_coverage(&self, attr: &Attribute, target_span: Span, target: Target) {
593 fn check_coverage(&self, attr_span: Span, target_span: Span, target: Target) {
592594 let mut not_fn_impl_mod = None;
593595 let mut no_body = None;
594596
......@@ -611,7 +613,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
611613 }
612614
613615 self.dcx().emit_err(errors::CoverageAttributeNotAllowed {
614 attr_span: attr.span(),
616 attr_span,
615617 not_fn_impl_mod,
616618 no_body,
617619 help: (),
compiler/rustc_session/src/config.rs+5
......@@ -1708,6 +1708,11 @@ impl RustcOptGroup {
17081708 OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc),
17091709 };
17101710 }
1711
1712 /// This is for diagnostics-only.
1713 pub fn long_name(&self) -> &str {
1714 self.long_name
1715 }
17111716}
17121717
17131718pub fn make_opt(
compiler/rustc_symbol_mangling/src/lib.rs+1-1
......@@ -180,7 +180,7 @@ fn compute_symbol_name<'tcx>(
180180
181181 // FIXME(eddyb) Precompute a custom symbol name based on attributes.
182182 let attrs = if tcx.def_kind(def_id).has_codegen_attrs() {
183 tcx.codegen_fn_attrs(def_id)
183 &tcx.codegen_instance_attrs(instance.def)
184184 } else {
185185 CodegenFnAttrs::EMPTY
186186 };
library/core/src/option.rs+97-40
......@@ -577,6 +577,7 @@
577577#![stable(feature = "rust1", since = "1.0.0")]
578578
579579use crate::iter::{self, FusedIterator, TrustedLen};
580use crate::marker::Destruct;
580581use crate::ops::{self, ControlFlow, Deref, DerefMut};
581582use crate::panicking::{panic, panic_display};
582583use crate::pin::Pin;
......@@ -649,7 +650,8 @@ impl<T> Option<T> {
649650 #[must_use]
650651 #[inline]
651652 #[stable(feature = "is_some_and", since = "1.70.0")]
652 pub fn is_some_and(self, f: impl FnOnce(T) -> bool) -> bool {
653 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
654 pub const fn is_some_and(self, f: impl ~const FnOnce(T) -> bool + ~const Destruct) -> bool {
653655 match self {
654656 None => false,
655657 Some(x) => f(x),
......@@ -697,7 +699,8 @@ impl<T> Option<T> {
697699 #[must_use]
698700 #[inline]
699701 #[stable(feature = "is_none_or", since = "1.82.0")]
700 pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool {
702 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
703 pub const fn is_none_or(self, f: impl ~const FnOnce(T) -> bool + ~const Destruct) -> bool {
701704 match self {
702705 None => true,
703706 Some(x) => f(x),
......@@ -1023,7 +1026,12 @@ impl<T> Option<T> {
10231026 /// ```
10241027 #[inline]
10251028 #[stable(feature = "rust1", since = "1.0.0")]
1026 pub fn unwrap_or(self, default: T) -> T {
1029 #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
1030 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1031 pub const fn unwrap_or(self, default: T) -> T
1032 where
1033 T: ~const Destruct,
1034 {
10271035 match self {
10281036 Some(x) => x,
10291037 None => default,
......@@ -1042,9 +1050,10 @@ impl<T> Option<T> {
10421050 #[inline]
10431051 #[track_caller]
10441052 #[stable(feature = "rust1", since = "1.0.0")]
1045 pub fn unwrap_or_else<F>(self, f: F) -> T
1053 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1054 pub const fn unwrap_or_else<F>(self, f: F) -> T
10461055 where
1047 F: FnOnce() -> T,
1056 F: ~const FnOnce() -> T + ~const Destruct,
10481057 {
10491058 match self {
10501059 Some(x) => x,
......@@ -1073,9 +1082,10 @@ impl<T> Option<T> {
10731082 /// [`FromStr`]: crate::str::FromStr
10741083 #[inline]
10751084 #[stable(feature = "rust1", since = "1.0.0")]
1076 pub fn unwrap_or_default(self) -> T
1085 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1086 pub const fn unwrap_or_default(self) -> T
10771087 where
1078 T: Default,
1088 T: ~const Default,
10791089 {
10801090 match self {
10811091 Some(x) => x,
......@@ -1139,9 +1149,10 @@ impl<T> Option<T> {
11391149 /// ```
11401150 #[inline]
11411151 #[stable(feature = "rust1", since = "1.0.0")]
1142 pub fn map<U, F>(self, f: F) -> Option<U>
1152 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1153 pub const fn map<U, F>(self, f: F) -> Option<U>
11431154 where
1144 F: FnOnce(T) -> U,
1155 F: ~const FnOnce(T) -> U + ~const Destruct,
11451156 {
11461157 match self {
11471158 Some(x) => Some(f(x)),
......@@ -1169,7 +1180,11 @@ impl<T> Option<T> {
11691180 /// ```
11701181 #[inline]
11711182 #[stable(feature = "result_option_inspect", since = "1.76.0")]
1172 pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self {
1183 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1184 pub const fn inspect<F>(self, f: F) -> Self
1185 where
1186 F: ~const FnOnce(&T) + ~const Destruct,
1187 {
11731188 if let Some(ref x) = self {
11741189 f(x);
11751190 }
......@@ -1198,9 +1213,11 @@ impl<T> Option<T> {
11981213 #[inline]
11991214 #[stable(feature = "rust1", since = "1.0.0")]
12001215 #[must_use = "if you don't need the returned value, use `if let` instead"]
1201 pub fn map_or<U, F>(self, default: U, f: F) -> U
1216 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1217 pub const fn map_or<U, F>(self, default: U, f: F) -> U
12021218 where
1203 F: FnOnce(T) -> U,
1219 F: ~const FnOnce(T) -> U + ~const Destruct,
1220 U: ~const Destruct,
12041221 {
12051222 match self {
12061223 Some(t) => f(t),
......@@ -1243,10 +1260,11 @@ impl<T> Option<T> {
12431260 /// ```
12441261 #[inline]
12451262 #[stable(feature = "rust1", since = "1.0.0")]
1246 pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
1263 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1264 pub const fn map_or_else<U, D, F>(self, default: D, f: F) -> U
12471265 where
1248 D: FnOnce() -> U,
1249 F: FnOnce(T) -> U,
1266 D: ~const FnOnce() -> U + ~const Destruct,
1267 F: ~const FnOnce(T) -> U + ~const Destruct,
12501268 {
12511269 match self {
12521270 Some(t) => f(t),
......@@ -1273,10 +1291,11 @@ impl<T> Option<T> {
12731291 /// [default value]: Default::default
12741292 #[inline]
12751293 #[unstable(feature = "result_option_map_or_default", issue = "138099")]
1276 pub fn map_or_default<U, F>(self, f: F) -> U
1294 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1295 pub const fn map_or_default<U, F>(self, f: F) -> U
12771296 where
1278 U: Default,
1279 F: FnOnce(T) -> U,
1297 U: ~const Default,
1298 F: ~const FnOnce(T) -> U + ~const Destruct,
12801299 {
12811300 match self {
12821301 Some(t) => f(t),
......@@ -1307,7 +1326,8 @@ impl<T> Option<T> {
13071326 /// ```
13081327 #[inline]
13091328 #[stable(feature = "rust1", since = "1.0.0")]
1310 pub fn ok_or<E>(self, err: E) -> Result<T, E> {
1329 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1330 pub const fn ok_or<E: ~const Destruct>(self, err: E) -> Result<T, E> {
13111331 match self {
13121332 Some(v) => Ok(v),
13131333 None => Err(err),
......@@ -1332,9 +1352,10 @@ impl<T> Option<T> {
13321352 /// ```
13331353 #[inline]
13341354 #[stable(feature = "rust1", since = "1.0.0")]
1335 pub fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
1355 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1356 pub const fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
13361357 where
1337 F: FnOnce() -> E,
1358 F: ~const FnOnce() -> E + ~const Destruct,
13381359 {
13391360 match self {
13401361 Some(v) => Ok(v),
......@@ -1463,7 +1484,12 @@ impl<T> Option<T> {
14631484 /// ```
14641485 #[inline]
14651486 #[stable(feature = "rust1", since = "1.0.0")]
1466 pub fn and<U>(self, optb: Option<U>) -> Option<U> {
1487 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1488 pub const fn and<U>(self, optb: Option<U>) -> Option<U>
1489 where
1490 T: ~const Destruct,
1491 U: ~const Destruct,
1492 {
14671493 match self {
14681494 Some(_) => optb,
14691495 None => None,
......@@ -1502,9 +1528,10 @@ impl<T> Option<T> {
15021528 #[inline]
15031529 #[stable(feature = "rust1", since = "1.0.0")]
15041530 #[rustc_confusables("flat_map", "flatmap")]
1505 pub fn and_then<U, F>(self, f: F) -> Option<U>
1531 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1532 pub const fn and_then<U, F>(self, f: F) -> Option<U>
15061533 where
1507 F: FnOnce(T) -> Option<U>,
1534 F: ~const FnOnce(T) -> Option<U> + ~const Destruct,
15081535 {
15091536 match self {
15101537 Some(x) => f(x),
......@@ -1538,9 +1565,11 @@ impl<T> Option<T> {
15381565 /// [`Some(t)`]: Some
15391566 #[inline]
15401567 #[stable(feature = "option_filter", since = "1.27.0")]
1541 pub fn filter<P>(self, predicate: P) -> Self
1568 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1569 pub const fn filter<P>(self, predicate: P) -> Self
15421570 where
1543 P: FnOnce(&T) -> bool,
1571 P: ~const FnOnce(&T) -> bool + ~const Destruct,
1572 T: ~const Destruct,
15441573 {
15451574 if let Some(x) = self {
15461575 if predicate(&x) {
......@@ -1579,7 +1608,11 @@ impl<T> Option<T> {
15791608 /// ```
15801609 #[inline]
15811610 #[stable(feature = "rust1", since = "1.0.0")]
1582 pub fn or(self, optb: Option<T>) -> Option<T> {
1611 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1612 pub const fn or(self, optb: Option<T>) -> Option<T>
1613 where
1614 T: ~const Destruct,
1615 {
15831616 match self {
15841617 x @ Some(_) => x,
15851618 None => optb,
......@@ -1601,9 +1634,13 @@ impl<T> Option<T> {
16011634 /// ```
16021635 #[inline]
16031636 #[stable(feature = "rust1", since = "1.0.0")]
1604 pub fn or_else<F>(self, f: F) -> Option<T>
1637 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1638 pub const fn or_else<F>(self, f: F) -> Option<T>
16051639 where
1606 F: FnOnce() -> Option<T>,
1640 F: ~const FnOnce() -> Option<T> + ~const Destruct,
1641 //FIXME(const_hack): this `T: ~const Destruct` is unnecessary, but even precise live drops can't tell
1642 // no value of type `T` gets dropped here
1643 T: ~const Destruct,
16071644 {
16081645 match self {
16091646 x @ Some(_) => x,
......@@ -1634,7 +1671,11 @@ impl<T> Option<T> {
16341671 /// ```
16351672 #[inline]
16361673 #[stable(feature = "option_xor", since = "1.37.0")]
1637 pub fn xor(self, optb: Option<T>) -> Option<T> {
1674 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1675 pub const fn xor(self, optb: Option<T>) -> Option<T>
1676 where
1677 T: ~const Destruct,
1678 {
16381679 match (self, optb) {
16391680 (a @ Some(_), None) => a,
16401681 (None, b @ Some(_)) => b,
......@@ -1668,7 +1709,11 @@ impl<T> Option<T> {
16681709 #[must_use = "if you intended to set a value, consider assignment instead"]
16691710 #[inline]
16701711 #[stable(feature = "option_insert", since = "1.53.0")]
1671 pub fn insert(&mut self, value: T) -> &mut T {
1712 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1713 pub const fn insert(&mut self, value: T) -> &mut T
1714 where
1715 T: ~const Destruct,
1716 {
16721717 *self = Some(value);
16731718
16741719 // SAFETY: the code above just filled the option
......@@ -1720,9 +1765,10 @@ impl<T> Option<T> {
17201765 /// ```
17211766 #[inline]
17221767 #[stable(feature = "option_get_or_insert_default", since = "1.83.0")]
1723 pub fn get_or_insert_default(&mut self) -> &mut T
1768 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1769 pub const fn get_or_insert_default(&mut self) -> &mut T
17241770 where
1725 T: Default,
1771 T: ~const Default + ~const Destruct,
17261772 {
17271773 self.get_or_insert_with(T::default)
17281774 }
......@@ -1746,9 +1792,11 @@ impl<T> Option<T> {
17461792 /// ```
17471793 #[inline]
17481794 #[stable(feature = "option_entry", since = "1.20.0")]
1749 pub fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
1795 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1796 pub const fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
17501797 where
1751 F: FnOnce() -> T,
1798 F: ~const FnOnce() -> T + ~const Destruct,
1799 T: ~const Destruct,
17521800 {
17531801 if let None = self {
17541802 *self = Some(f());
......@@ -1812,9 +1860,10 @@ impl<T> Option<T> {
18121860 /// ```
18131861 #[inline]
18141862 #[stable(feature = "option_take_if", since = "1.80.0")]
1815 pub fn take_if<P>(&mut self, predicate: P) -> Option<T>
1863 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1864 pub const fn take_if<P>(&mut self, predicate: P) -> Option<T>
18161865 where
1817 P: FnOnce(&mut T) -> bool,
1866 P: ~const FnOnce(&mut T) -> bool + ~const Destruct,
18181867 {
18191868 if self.as_mut().map_or(false, predicate) { self.take() } else { None }
18201869 }
......@@ -1859,7 +1908,12 @@ impl<T> Option<T> {
18591908 /// assert_eq!(x.zip(z), None);
18601909 /// ```
18611910 #[stable(feature = "option_zip_option", since = "1.46.0")]
1862 pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> {
1911 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1912 pub const fn zip<U>(self, other: Option<U>) -> Option<(T, U)>
1913 where
1914 T: ~const Destruct,
1915 U: ~const Destruct,
1916 {
18631917 match (self, other) {
18641918 (Some(a), Some(b)) => Some((a, b)),
18651919 _ => None,
......@@ -1895,9 +1949,12 @@ impl<T> Option<T> {
18951949 /// assert_eq!(x.zip_with(None, Point::new), None);
18961950 /// ```
18971951 #[unstable(feature = "option_zip", issue = "70086")]
1898 pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
1952 #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
1953 pub const fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
18991954 where
1900 F: FnOnce(T, U) -> R,
1955 F: ~const FnOnce(T, U) -> R + ~const Destruct,
1956 T: ~const Destruct,
1957 U: ~const Destruct,
19011958 {
19021959 match (self, other) {
19031960 (Some(a), Some(b)) => Some(f(a, b)),
src/bootstrap/src/core/build_steps/gcc.rs+11-14
......@@ -220,21 +220,18 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) {
220220 t!(fs::create_dir_all(install_dir));
221221
222222 // GCC creates files (e.g. symlinks to the downloaded dependencies)
223 // in the source directory, which does not work with our CI setup, where we mount
223 // in the source directory, which does not work with our CI/Docker setup, where we mount
224224 // source directories as read-only on Linux.
225 // Therefore, as a part of the build in CI, we first copy the whole source directory
226 // to the build directory, and perform the build from there.
227 let src_dir = if builder.config.is_running_on_ci {
228 let src_dir = builder.gcc_out(target).join("src");
229 if src_dir.exists() {
230 builder.remove_dir(&src_dir);
231 }
232 builder.create_dir(&src_dir);
233 builder.cp_link_r(root, &src_dir);
234 src_dir
235 } else {
236 root.clone()
237 };
225 // And in general, we shouldn't be modifying the source directories if possible, even for local
226 // builds.
227 // Therefore, we first copy the whole source directory to the build directory, and perform the
228 // build from there.
229 let src_dir = builder.gcc_out(target).join("src");
230 if src_dir.exists() {
231 builder.remove_dir(&src_dir);
232 }
233 builder.create_dir(&src_dir);
234 builder.cp_link_r(root, &src_dir);
238235
239236 command(src_dir.join("contrib/download_prerequisites")).current_dir(&src_dir).run(builder);
240237 let mut configure_cmd = command(src_dir.join("configure"));
src/bootstrap/src/core/config/toml/rust.rs+8
......@@ -531,6 +531,14 @@ impl Config {
531531 lld_enabled = lld_enabled_toml;
532532 std_features = std_features_toml;
533533
534 if optimize_toml.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) {
535 eprintln!(
536 "WARNING: setting `optimize` to `false` is known to cause errors and \
537 should be considered unsupported. Refer to `bootstrap.example.toml` \
538 for more details."
539 );
540 }
541
534542 optimize = optimize_toml;
535543 self.rust_new_symbol_mangling = new_symbol_mangling;
536544 set(&mut self.rust_optimize_tests, optimize_tests);
src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml+9-103
......@@ -9,106 +9,12 @@ on:
99jobs:
1010 pull:
1111 if: github.repository == 'rust-lang/rustc-dev-guide'
12 runs-on: ubuntu-latest
13 outputs:
14 pr_url: ${{ steps.update-pr.outputs.pr_url }}
15 permissions:
16 contents: write
17 pull-requests: write
18 steps:
19 - uses: actions/checkout@v4
20 with:
21 # We need the full history for josh to work
22 fetch-depth: '0'
23 - name: Install stable Rust toolchain
24 run: rustup update stable
25 - uses: Swatinem/rust-cache@v2
26 with:
27 workspaces: "josh-sync"
28 # Cache the josh directory with checked out rustc
29 cache-directories: "/home/runner/.cache/rustc-dev-guide-josh"
30 - name: Install josh
31 run: RUSTFLAGS="--cap-lints warn" cargo install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04
32 - name: Setup bot git name and email
33 run: |
34 git config --global user.name 'The rustc-dev-guide Cronjob Bot'
35 git config --global user.email 'github-actions@github.com'
36 - name: Perform rustc-pull
37 id: rustc-pull
38 # Turn off -e to disable early exit
39 shell: bash {0}
40 run: |
41 cargo run --manifest-path josh-sync/Cargo.toml -- rustc-pull
42 exitcode=$?
43
44 # If no pull was performed, we want to mark this job as successful,
45 # but we do not want to perform the follow-up steps.
46 if [ $exitcode -eq 0 ]; then
47 echo "pull_result=pull-finished" >> $GITHUB_OUTPUT
48 elif [ $exitcode -eq 2 ]; then
49 echo "pull_result=skipped" >> $GITHUB_OUTPUT
50 exitcode=0
51 fi
52
53 exit ${exitcode}
54 - name: Push changes to a branch
55 if: ${{ steps.rustc-pull.outputs.pull_result == 'pull-finished' }}
56 run: |
57 # Update a sticky branch that is used only for rustc pulls
58 BRANCH="rustc-pull"
59 git switch -c $BRANCH
60 git push -u origin $BRANCH --force
61 - name: Create pull request
62 id: update-pr
63 if: ${{ steps.rustc-pull.outputs.pull_result == 'pull-finished' }}
64 env:
65 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
66 run: |
67 # Check if an open pull request for an rustc pull update already exists
68 # If it does, the previous push has just updated it
69 # If not, we create it now
70 RESULT=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | length' --json title`
71 if [[ "$RESULT" -eq 0 ]]; then
72 echo "Creating new pull request"
73 PR_URL=`gh pr create -B master --title 'Rustc pull update' --body 'Latest update from rustc.'`
74 echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
75 else
76 PR_URL=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].url' --json url,title`
77 echo "Updating pull request ${PR_URL}"
78 echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
79 fi
80 send-zulip-message:
81 needs: [pull]
82 if: ${{ !cancelled() }}
83 runs-on: ubuntu-latest
84 steps:
85 - uses: actions/checkout@v4
86 - name: Compute message
87 id: create-message
88 env:
89 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
90 run: |
91 if [ "${{ needs.pull.result }}" == "failure" ]; then
92 WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
93 echo "message=Rustc pull sync failed. Check out the [workflow URL]($WORKFLOW_URL)." >> $GITHUB_OUTPUT
94 else
95 CREATED_AT=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].createdAt' --json createdAt,title`
96 PR_URL=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].url' --json url,title`
97 week_ago=$(date +%F -d '7 days ago')
98
99 # If there is an open PR that is at least a week old, post a message about it
100 if [[ -n $DATE_GH && $DATE_GH < $week_ago ]]; then
101 echo "message=A PR with a Rustc pull has been opened for more a week. Check out the [PR](${PR_URL})." >> $GITHUB_OUTPUT
102 fi
103 fi
104 - name: Send a Zulip message about updated PR
105 if: ${{ steps.create-message.outputs.message != '' }}
106 uses: zulip/github-actions-zulip/send-message@e4c8f27c732ba9bd98ac6be0583096dea82feea5
107 with:
108 api-key: ${{ secrets.ZULIP_API_TOKEN }}
109 email: "rustc-dev-guide-gha-notif-bot@rust-lang.zulipchat.com"
110 organization-url: "https://rust-lang.zulipchat.com"
111 to: 196385
112 type: "stream"
113 topic: "Subtree sync automation"
114 content: ${{ steps.create-message.outputs.message }}
12 uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main
13 with:
14 zulip-stream-id: 196385
15 zulip-bot-email: "rustc-dev-guide-gha-notif-bot@rust-lang.zulipchat.com"
16 pr-base-branch: master
17 branch-name: rustc-pull
18 secrets:
19 zulip-api-token: ${{ secrets.ZULIP_API_TOKEN }}
20 token: ${{ secrets.GITHUB_TOKEN }}
src/doc/rustc-dev-guide/README.md+2-45
......@@ -72,49 +72,6 @@ including the `<!-- toc -->` marker at the place where you want the TOC.
7272
7373## Synchronizing josh subtree with rustc
7474
75This repository is linked to `rust-lang/rust` as a [josh](https://josh-project.github.io/josh/intro.html) subtree. You can use the following commands to synchronize the subtree in both directions.
75This repository is linked to `rust-lang/rust` as a [josh](https://josh-project.github.io/josh/intro.html) subtree. You can use the [rustc-josh-sync](https://github.com/rust-lang/josh-sync) tool to perform synchronization.
7676
77You'll need to install `josh-proxy` locally via
78
79```
80cargo install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04
81```
82Older versions of `josh-proxy` may not round trip commits losslessly so it is important to install this exact version.
83
84### Pull changes from `rust-lang/rust` into this repository
85
861) Checkout a new branch that will be used to create a PR into `rust-lang/rustc-dev-guide`
872) Run the pull command
88 ```
89 cargo run --manifest-path josh-sync/Cargo.toml rustc-pull
90 ```
913) Push the branch to your fork and create a PR into `rustc-dev-guide`
92
93### Push changes from this repository into `rust-lang/rust`
94
95NOTE: If you use Git protocol to push to your fork of `rust-lang/rust`,
96ensure that you have this entry in your Git config,
97else the 2 steps that follow would prompt for a username and password:
98
99```
100[url "git@github.com:"]
101insteadOf = "https://github.com/"
102```
103
1041) Run the push command to create a branch named `<branch-name>` in a `rustc` fork under the `<gh-username>` account
105 ```
106 cargo run --manifest-path josh-sync/Cargo.toml rustc-push <branch-name> <gh-username>
107 ```
1082) Create a PR from `<branch-name>` into `rust-lang/rust`
109
110#### Minimal git config
111
112For simplicity (ease of implementation purposes), the josh-sync script simply calls out to system git. This means that the git invocation may be influenced by global (or local) git configuration.
113
114You may observe "Nothing to pull" even if you *know* rustc-pull has something to pull if your global git config sets `fetch.prunetags = true` (and possibly other configurations may cause unexpected outcomes).
115
116To minimize the likelihood of this happening, you may wish to keep a separate *minimal* git config that *only* has `[user]` entries from global git config, then repoint system git to use the minimal git config instead. E.g.
117
118```
119GIT_CONFIG_GLOBAL=/path/to/minimal/gitconfig GIT_CONFIG_SYSTEM='' cargo run --manifest-path josh-sync/Cargo.toml -- rustc-pull
120```
77You can find a guide on how to perform the synchronization [here](./src/external-repos.md#synchronizing-a-josh-subtree).
src/doc/rustc-dev-guide/josh-sync/Cargo.lock deleted-430
......@@ -1,430 +0,0 @@
1# This file is automatically @generated by Cargo.
2# It is not intended for manual editing.
3version = 4
4
5[[package]]
6name = "anstream"
7version = "0.6.18"
8source = "registry+https://github.com/rust-lang/crates.io-index"
9checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
10dependencies = [
11 "anstyle",
12 "anstyle-parse",
13 "anstyle-query",
14 "anstyle-wincon",
15 "colorchoice",
16 "is_terminal_polyfill",
17 "utf8parse",
18]
19
20[[package]]
21name = "anstyle"
22version = "1.0.10"
23source = "registry+https://github.com/rust-lang/crates.io-index"
24checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
25
26[[package]]
27name = "anstyle-parse"
28version = "0.2.6"
29source = "registry+https://github.com/rust-lang/crates.io-index"
30checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
31dependencies = [
32 "utf8parse",
33]
34
35[[package]]
36name = "anstyle-query"
37version = "1.1.2"
38source = "registry+https://github.com/rust-lang/crates.io-index"
39checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
40dependencies = [
41 "windows-sys 0.59.0",
42]
43
44[[package]]
45name = "anstyle-wincon"
46version = "3.0.6"
47source = "registry+https://github.com/rust-lang/crates.io-index"
48checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
49dependencies = [
50 "anstyle",
51 "windows-sys 0.59.0",
52]
53
54[[package]]
55name = "anyhow"
56version = "1.0.95"
57source = "registry+https://github.com/rust-lang/crates.io-index"
58checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
59
60[[package]]
61name = "bitflags"
62version = "2.6.0"
63source = "registry+https://github.com/rust-lang/crates.io-index"
64checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
65
66[[package]]
67name = "cfg-if"
68version = "1.0.0"
69source = "registry+https://github.com/rust-lang/crates.io-index"
70checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
71
72[[package]]
73name = "clap"
74version = "4.5.23"
75source = "registry+https://github.com/rust-lang/crates.io-index"
76checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
77dependencies = [
78 "clap_builder",
79 "clap_derive",
80]
81
82[[package]]
83name = "clap_builder"
84version = "4.5.23"
85source = "registry+https://github.com/rust-lang/crates.io-index"
86checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
87dependencies = [
88 "anstream",
89 "anstyle",
90 "clap_lex",
91 "strsim",
92]
93
94[[package]]
95name = "clap_derive"
96version = "4.5.18"
97source = "registry+https://github.com/rust-lang/crates.io-index"
98checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
99dependencies = [
100 "heck",
101 "proc-macro2",
102 "quote",
103 "syn",
104]
105
106[[package]]
107name = "clap_lex"
108version = "0.7.4"
109source = "registry+https://github.com/rust-lang/crates.io-index"
110checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
111
112[[package]]
113name = "colorchoice"
114version = "1.0.3"
115source = "registry+https://github.com/rust-lang/crates.io-index"
116checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
117
118[[package]]
119name = "directories"
120version = "5.0.1"
121source = "registry+https://github.com/rust-lang/crates.io-index"
122checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
123dependencies = [
124 "dirs-sys",
125]
126
127[[package]]
128name = "dirs-sys"
129version = "0.4.1"
130source = "registry+https://github.com/rust-lang/crates.io-index"
131checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
132dependencies = [
133 "libc",
134 "option-ext",
135 "redox_users",
136 "windows-sys 0.48.0",
137]
138
139[[package]]
140name = "getrandom"
141version = "0.2.15"
142source = "registry+https://github.com/rust-lang/crates.io-index"
143checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
144dependencies = [
145 "cfg-if",
146 "libc",
147 "wasi",
148]
149
150[[package]]
151name = "heck"
152version = "0.5.0"
153source = "registry+https://github.com/rust-lang/crates.io-index"
154checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
155
156[[package]]
157name = "is_terminal_polyfill"
158version = "1.70.1"
159source = "registry+https://github.com/rust-lang/crates.io-index"
160checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
161
162[[package]]
163name = "josh-sync"
164version = "0.0.0"
165dependencies = [
166 "anyhow",
167 "clap",
168 "directories",
169 "xshell",
170]
171
172[[package]]
173name = "libc"
174version = "0.2.169"
175source = "registry+https://github.com/rust-lang/crates.io-index"
176checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
177
178[[package]]
179name = "libredox"
180version = "0.1.3"
181source = "registry+https://github.com/rust-lang/crates.io-index"
182checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
183dependencies = [
184 "bitflags",
185 "libc",
186]
187
188[[package]]
189name = "option-ext"
190version = "0.2.0"
191source = "registry+https://github.com/rust-lang/crates.io-index"
192checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
193
194[[package]]
195name = "proc-macro2"
196version = "1.0.92"
197source = "registry+https://github.com/rust-lang/crates.io-index"
198checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
199dependencies = [
200 "unicode-ident",
201]
202
203[[package]]
204name = "quote"
205version = "1.0.38"
206source = "registry+https://github.com/rust-lang/crates.io-index"
207checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
208dependencies = [
209 "proc-macro2",
210]
211
212[[package]]
213name = "redox_users"
214version = "0.4.6"
215source = "registry+https://github.com/rust-lang/crates.io-index"
216checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
217dependencies = [
218 "getrandom",
219 "libredox",
220 "thiserror",
221]
222
223[[package]]
224name = "strsim"
225version = "0.11.1"
226source = "registry+https://github.com/rust-lang/crates.io-index"
227checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
228
229[[package]]
230name = "syn"
231version = "2.0.93"
232source = "registry+https://github.com/rust-lang/crates.io-index"
233checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
234dependencies = [
235 "proc-macro2",
236 "quote",
237 "unicode-ident",
238]
239
240[[package]]
241name = "thiserror"
242version = "1.0.69"
243source = "registry+https://github.com/rust-lang/crates.io-index"
244checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
245dependencies = [
246 "thiserror-impl",
247]
248
249[[package]]
250name = "thiserror-impl"
251version = "1.0.69"
252source = "registry+https://github.com/rust-lang/crates.io-index"
253checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
254dependencies = [
255 "proc-macro2",
256 "quote",
257 "syn",
258]
259
260[[package]]
261name = "unicode-ident"
262version = "1.0.14"
263source = "registry+https://github.com/rust-lang/crates.io-index"
264checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
265
266[[package]]
267name = "utf8parse"
268version = "0.2.2"
269source = "registry+https://github.com/rust-lang/crates.io-index"
270checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
271
272[[package]]
273name = "wasi"
274version = "0.11.0+wasi-snapshot-preview1"
275source = "registry+https://github.com/rust-lang/crates.io-index"
276checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
277
278[[package]]
279name = "windows-sys"
280version = "0.48.0"
281source = "registry+https://github.com/rust-lang/crates.io-index"
282checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
283dependencies = [
284 "windows-targets 0.48.5",
285]
286
287[[package]]
288name = "windows-sys"
289version = "0.59.0"
290source = "registry+https://github.com/rust-lang/crates.io-index"
291checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
292dependencies = [
293 "windows-targets 0.52.6",
294]
295
296[[package]]
297name = "windows-targets"
298version = "0.48.5"
299source = "registry+https://github.com/rust-lang/crates.io-index"
300checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
301dependencies = [
302 "windows_aarch64_gnullvm 0.48.5",
303 "windows_aarch64_msvc 0.48.5",
304 "windows_i686_gnu 0.48.5",
305 "windows_i686_msvc 0.48.5",
306 "windows_x86_64_gnu 0.48.5",
307 "windows_x86_64_gnullvm 0.48.5",
308 "windows_x86_64_msvc 0.48.5",
309]
310
311[[package]]
312name = "windows-targets"
313version = "0.52.6"
314source = "registry+https://github.com/rust-lang/crates.io-index"
315checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
316dependencies = [
317 "windows_aarch64_gnullvm 0.52.6",
318 "windows_aarch64_msvc 0.52.6",
319 "windows_i686_gnu 0.52.6",
320 "windows_i686_gnullvm",
321 "windows_i686_msvc 0.52.6",
322 "windows_x86_64_gnu 0.52.6",
323 "windows_x86_64_gnullvm 0.52.6",
324 "windows_x86_64_msvc 0.52.6",
325]
326
327[[package]]
328name = "windows_aarch64_gnullvm"
329version = "0.48.5"
330source = "registry+https://github.com/rust-lang/crates.io-index"
331checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
332
333[[package]]
334name = "windows_aarch64_gnullvm"
335version = "0.52.6"
336source = "registry+https://github.com/rust-lang/crates.io-index"
337checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
338
339[[package]]
340name = "windows_aarch64_msvc"
341version = "0.48.5"
342source = "registry+https://github.com/rust-lang/crates.io-index"
343checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
344
345[[package]]
346name = "windows_aarch64_msvc"
347version = "0.52.6"
348source = "registry+https://github.com/rust-lang/crates.io-index"
349checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
350
351[[package]]
352name = "windows_i686_gnu"
353version = "0.48.5"
354source = "registry+https://github.com/rust-lang/crates.io-index"
355checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
356
357[[package]]
358name = "windows_i686_gnu"
359version = "0.52.6"
360source = "registry+https://github.com/rust-lang/crates.io-index"
361checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
362
363[[package]]
364name = "windows_i686_gnullvm"
365version = "0.52.6"
366source = "registry+https://github.com/rust-lang/crates.io-index"
367checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
368
369[[package]]
370name = "windows_i686_msvc"
371version = "0.48.5"
372source = "registry+https://github.com/rust-lang/crates.io-index"
373checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
374
375[[package]]
376name = "windows_i686_msvc"
377version = "0.52.6"
378source = "registry+https://github.com/rust-lang/crates.io-index"
379checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
380
381[[package]]
382name = "windows_x86_64_gnu"
383version = "0.48.5"
384source = "registry+https://github.com/rust-lang/crates.io-index"
385checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
386
387[[package]]
388name = "windows_x86_64_gnu"
389version = "0.52.6"
390source = "registry+https://github.com/rust-lang/crates.io-index"
391checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
392
393[[package]]
394name = "windows_x86_64_gnullvm"
395version = "0.48.5"
396source = "registry+https://github.com/rust-lang/crates.io-index"
397checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
398
399[[package]]
400name = "windows_x86_64_gnullvm"
401version = "0.52.6"
402source = "registry+https://github.com/rust-lang/crates.io-index"
403checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
404
405[[package]]
406name = "windows_x86_64_msvc"
407version = "0.48.5"
408source = "registry+https://github.com/rust-lang/crates.io-index"
409checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
410
411[[package]]
412name = "windows_x86_64_msvc"
413version = "0.52.6"
414source = "registry+https://github.com/rust-lang/crates.io-index"
415checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
416
417[[package]]
418name = "xshell"
419version = "0.2.7"
420source = "registry+https://github.com/rust-lang/crates.io-index"
421checksum = "9e7290c623014758632efe00737145b6867b66292c42167f2ec381eb566a373d"
422dependencies = [
423 "xshell-macros",
424]
425
426[[package]]
427name = "xshell-macros"
428version = "0.2.7"
429source = "registry+https://github.com/rust-lang/crates.io-index"
430checksum = "32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547"
src/doc/rustc-dev-guide/josh-sync/Cargo.toml deleted-9
......@@ -1,9 +0,0 @@
1[package]
2name = "josh-sync"
3edition = "2024"
4
5[dependencies]
6anyhow = "1.0.95"
7clap = { version = "4.5.21", features = ["derive"] }
8directories = "5"
9xshell = "0.2.6"
src/doc/rustc-dev-guide/josh-sync/README.md deleted-4
......@@ -1,4 +0,0 @@
1# Git josh sync
2This utility serves for syncing the josh git subtree to and from the rust-lang/rust repository.
3
4See CLI help for usage.
src/doc/rustc-dev-guide/josh-sync/src/main.rs deleted-41
......@@ -1,41 +0,0 @@
1use clap::Parser;
2
3use crate::sync::{GitSync, RustcPullError};
4
5mod sync;
6
7#[derive(clap::Parser)]
8enum Args {
9 /// Pull changes from the main `rustc` repository.
10 /// This creates new commits that should be then merged into `rustc-dev-guide`.
11 RustcPull,
12 /// Push changes from `rustc-dev-guide` to the given `branch` of a `rustc` fork under the given
13 /// GitHub `username`.
14 /// The pushed branch should then be merged into the `rustc` repository.
15 RustcPush { branch: String, github_username: String },
16}
17
18fn main() -> anyhow::Result<()> {
19 let args = Args::parse();
20 let sync = GitSync::from_current_dir()?;
21 match args {
22 Args::RustcPull => {
23 if let Err(error) = sync.rustc_pull(None) {
24 match error {
25 RustcPullError::NothingToPull => {
26 eprintln!("Nothing to pull");
27 std::process::exit(2);
28 }
29 RustcPullError::PullFailed(error) => {
30 eprintln!("Pull failure: {error:?}");
31 std::process::exit(1);
32 }
33 }
34 }
35 }
36 Args::RustcPush { github_username, branch } => {
37 sync.rustc_push(github_username, branch)?;
38 }
39 }
40 Ok(())
41}
src/doc/rustc-dev-guide/josh-sync/src/sync.rs deleted-275
......@@ -1,275 +0,0 @@
1use std::io::Write;
2use std::ops::Not;
3use std::path::PathBuf;
4use std::time::Duration;
5use std::{env, net, process};
6
7use anyhow::{Context, anyhow, bail};
8use xshell::{Shell, cmd};
9
10/// Used for rustc syncs.
11const JOSH_FILTER: &str = ":/src/doc/rustc-dev-guide";
12const JOSH_PORT: u16 = 42042;
13const UPSTREAM_REPO: &str = "rust-lang/rust";
14
15pub enum RustcPullError {
16 /// No changes are available to be pulled.
17 NothingToPull,
18 /// A rustc-pull has failed, probably a git operation error has occurred.
19 PullFailed(anyhow::Error),
20}
21
22impl<E> From<E> for RustcPullError
23where
24 E: Into<anyhow::Error>,
25{
26 fn from(error: E) -> Self {
27 Self::PullFailed(error.into())
28 }
29}
30
31pub struct GitSync {
32 dir: PathBuf,
33}
34
35/// This code was adapted from the miri repository
36/// (https://github.com/rust-lang/miri/blob/6a68a79f38064c3bc30617cca4bdbfb2c336b140/miri-script/src/commands.rs#L236).
37impl GitSync {
38 pub fn from_current_dir() -> anyhow::Result<Self> {
39 Ok(Self { dir: std::env::current_dir()? })
40 }
41
42 pub fn rustc_pull(&self, commit: Option<String>) -> Result<(), RustcPullError> {
43 let sh = Shell::new()?;
44 sh.change_dir(&self.dir);
45 let commit = commit.map(Ok).unwrap_or_else(|| {
46 let rust_repo_head =
47 cmd!(sh, "git ls-remote https://github.com/{UPSTREAM_REPO}/ HEAD").read()?;
48 rust_repo_head
49 .split_whitespace()
50 .next()
51 .map(|front| front.trim().to_owned())
52 .ok_or_else(|| anyhow!("Could not obtain Rust repo HEAD from remote."))
53 })?;
54 // Make sure the repo is clean.
55 if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() {
56 return Err(anyhow::anyhow!(
57 "working directory must be clean before performing rustc pull"
58 )
59 .into());
60 }
61 // Make sure josh is running.
62 let josh = Self::start_josh()?;
63 let josh_url =
64 format!("http://localhost:{JOSH_PORT}/{UPSTREAM_REPO}.git@{commit}{JOSH_FILTER}.git");
65
66 let previous_base_commit = sh.read_file("rust-version")?.trim().to_string();
67 if previous_base_commit == commit {
68 return Err(RustcPullError::NothingToPull);
69 }
70
71 // Update rust-version file. As a separate commit, since making it part of
72 // the merge has confused the heck out of josh in the past.
73 // We pass `--no-verify` to avoid running git hooks.
74 // We do this before the merge so that if there are merge conflicts, we have
75 // the right rust-version file while resolving them.
76 sh.write_file("rust-version", format!("{commit}\n"))?;
77 const PREPARING_COMMIT_MESSAGE: &str = "Preparing for merge from rustc";
78 cmd!(sh, "git commit rust-version --no-verify -m {PREPARING_COMMIT_MESSAGE}")
79 .run()
80 .context("FAILED to commit rust-version file, something went wrong")?;
81
82 // Fetch given rustc commit.
83 cmd!(sh, "git fetch {josh_url}")
84 .run()
85 .inspect_err(|_| {
86 // Try to un-do the previous `git commit`, to leave the repo in the state we found it.
87 cmd!(sh, "git reset --hard HEAD^")
88 .run()
89 .expect("FAILED to clean up again after failed `git fetch`, sorry for that");
90 })
91 .context("FAILED to fetch new commits, something went wrong (committing the rust-version file has been undone)")?;
92
93 // This should not add any new root commits. So count those before and after merging.
94 let num_roots = || -> anyhow::Result<u32> {
95 Ok(cmd!(sh, "git rev-list HEAD --max-parents=0 --count")
96 .read()
97 .context("failed to determine the number of root commits")?
98 .parse::<u32>()?)
99 };
100 let num_roots_before = num_roots()?;
101
102 let sha =
103 cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout;
104
105 // Merge the fetched commit.
106 const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc";
107 cmd!(sh, "git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}")
108 .run()
109 .context("FAILED to merge new commits, something went wrong")?;
110
111 let current_sha =
112 cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout;
113 if current_sha == sha {
114 cmd!(sh, "git reset --hard HEAD^")
115 .run()
116 .expect("FAILED to clean up after creating the preparation commit");
117 eprintln!(
118 "No merge was performed, no changes to pull were found. Rolled back the preparation commit."
119 );
120 return Err(RustcPullError::NothingToPull);
121 }
122
123 // Check that the number of roots did not increase.
124 if num_roots()? != num_roots_before {
125 return Err(anyhow::anyhow!(
126 "Josh created a new root commit. This is probably not the history you want."
127 )
128 .into());
129 }
130
131 drop(josh);
132 Ok(())
133 }
134
135 pub fn rustc_push(&self, github_user: String, branch: String) -> anyhow::Result<()> {
136 let sh = Shell::new()?;
137 sh.change_dir(&self.dir);
138 let base = sh.read_file("rust-version")?.trim().to_owned();
139 // Make sure the repo is clean.
140 if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() {
141 bail!("working directory must be clean before running `rustc-push`");
142 }
143 // Make sure josh is running.
144 let josh = Self::start_josh()?;
145 let josh_url =
146 format!("http://localhost:{JOSH_PORT}/{github_user}/rust.git{JOSH_FILTER}.git");
147
148 // Find a repo we can do our preparation in.
149 if let Ok(rustc_git) = env::var("RUSTC_GIT") {
150 // If rustc_git is `Some`, we'll use an existing fork for the branch updates.
151 sh.change_dir(rustc_git);
152 } else {
153 // Otherwise, do this in the local repo.
154 println!(
155 "This will pull a copy of the rust-lang/rust history into this checkout, growing it by about 1GB."
156 );
157 print!(
158 "To avoid that, abort now and set the `RUSTC_GIT` environment variable to an existing rustc checkout. Proceed? [y/N] "
159 );
160 std::io::stdout().flush()?;
161 let mut answer = String::new();
162 std::io::stdin().read_line(&mut answer)?;
163 if answer.trim().to_lowercase() != "y" {
164 std::process::exit(1);
165 }
166 };
167 // Prepare the branch. Pushing works much better if we use as base exactly
168 // the commit that we pulled from last time, so we use the `rust-version`
169 // file to find out which commit that would be.
170 println!("Preparing {github_user}/rust (base: {base})...");
171 if cmd!(sh, "git fetch https://github.com/{github_user}/rust {branch}")
172 .ignore_stderr()
173 .read()
174 .is_ok()
175 {
176 println!(
177 "The branch '{branch}' seems to already exist in 'https://github.com/{github_user}/rust'. Please delete it and try again."
178 );
179 std::process::exit(1);
180 }
181 cmd!(sh, "git fetch https://github.com/{UPSTREAM_REPO} {base}").run()?;
182 cmd!(sh, "git push https://github.com/{github_user}/rust {base}:refs/heads/{branch}")
183 .ignore_stdout()
184 .ignore_stderr() // silence the "create GitHub PR" message
185 .run()?;
186 println!();
187
188 // Do the actual push.
189 sh.change_dir(&self.dir);
190 println!("Pushing changes...");
191 cmd!(sh, "git push {josh_url} HEAD:{branch}").run()?;
192 println!();
193
194 // Do a round-trip check to make sure the push worked as expected.
195 cmd!(sh, "git fetch {josh_url} {branch}").ignore_stderr().read()?;
196 let head = cmd!(sh, "git rev-parse HEAD").read()?;
197 let fetch_head = cmd!(sh, "git rev-parse FETCH_HEAD").read()?;
198 if head != fetch_head {
199 bail!(
200 "Josh created a non-roundtrip push! Do NOT merge this into rustc!\n\
201 Expected {head}, got {fetch_head}."
202 );
203 }
204 println!(
205 "Confirmed that the push round-trips back to rustc-dev-guide properly. Please create a rustc PR:"
206 );
207 println!(
208 // Open PR with `subtree update` title to silence the `no-merges` triagebot check
209 " https://github.com/{UPSTREAM_REPO}/compare/{github_user}:{branch}?quick_pull=1&title=rustc-dev-guide+subtree+update&body=r?+@ghost"
210 );
211
212 drop(josh);
213 Ok(())
214 }
215
216 fn start_josh() -> anyhow::Result<impl Drop> {
217 // Determine cache directory.
218 let local_dir = {
219 let user_dirs =
220 directories::ProjectDirs::from("org", "rust-lang", "rustc-dev-guide-josh").unwrap();
221 user_dirs.cache_dir().to_owned()
222 };
223
224 // Start josh, silencing its output.
225 let mut cmd = process::Command::new("josh-proxy");
226 cmd.arg("--local").arg(local_dir);
227 cmd.arg("--remote").arg("https://github.com");
228 cmd.arg("--port").arg(JOSH_PORT.to_string());
229 cmd.arg("--no-background");
230 cmd.stdout(process::Stdio::null());
231 cmd.stderr(process::Stdio::null());
232 let josh = cmd.spawn().context("failed to start josh-proxy, make sure it is installed")?;
233
234 // Create a wrapper that stops it on drop.
235 struct Josh(process::Child);
236 impl Drop for Josh {
237 fn drop(&mut self) {
238 #[cfg(unix)]
239 {
240 // Try to gracefully shut it down.
241 process::Command::new("kill")
242 .args(["-s", "INT", &self.0.id().to_string()])
243 .output()
244 .expect("failed to SIGINT josh-proxy");
245 // Sadly there is no "wait with timeout"... so we just give it some time to finish.
246 std::thread::sleep(Duration::from_millis(100));
247 // Now hopefully it is gone.
248 if self.0.try_wait().expect("failed to wait for josh-proxy").is_some() {
249 return;
250 }
251 }
252 // If that didn't work (or we're not on Unix), kill it hard.
253 eprintln!(
254 "I have to kill josh-proxy the hard way, let's hope this does not break anything."
255 );
256 self.0.kill().expect("failed to SIGKILL josh-proxy");
257 }
258 }
259
260 // Wait until the port is open. We try every 10ms until 1s passed.
261 for _ in 0..100 {
262 // This will generally fail immediately when the port is still closed.
263 let josh_ready = net::TcpStream::connect_timeout(
264 &net::SocketAddr::from(([127, 0, 0, 1], JOSH_PORT)),
265 Duration::from_millis(1),
266 );
267 if josh_ready.is_ok() {
268 return Ok(Josh(josh));
269 }
270 // Not ready yet.
271 std::thread::sleep(Duration::from_millis(10));
272 }
273 bail!("Even after waiting for 1s, josh-proxy is still not available.")
274 }
275}
src/doc/rustc-dev-guide/rust-version+1-1
......@@ -1 +1 @@
1c96a69059ecc618b519da385a6ccd03155aa0237
1fd2eb391d032181459773f3498c17b198513e0d0
src/doc/rustc-dev-guide/src/autodiff/installation.md+9-9
......@@ -6,14 +6,14 @@ In the near future, `std::autodiff` should become available in nightly builds fo
66
77First you need to clone and configure the Rust repository:
88```bash
9git clone --depth=1 git@github.com:rust-lang/rust.git
9git clone git@github.com:rust-lang/rust
1010cd rust
1111./configure --enable-llvm-link-shared --enable-llvm-plugins --enable-llvm-enzyme --release-channel=nightly --enable-llvm-assertions --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs
1212```
1313
1414Afterwards you can build rustc using:
1515```bash
16./x.py build --stage 1 library
16./x build --stage 1 library
1717```
1818
1919Afterwards rustc toolchain link will allow you to use it through cargo:
......@@ -25,10 +25,10 @@ rustup toolchain install nightly # enables -Z unstable-options
2525You can then run our test cases:
2626
2727```bash
28./x.py test --stage 1 tests/codegen/autodiff
29./x.py test --stage 1 tests/pretty/autodiff
30./x.py test --stage 1 tests/ui/autodiff
31./x.py test --stage 1 tests/ui/feature-gates/feature-gate-autodiff.rs
28./x test --stage 1 tests/codegen/autodiff
29./x test --stage 1 tests/pretty/autodiff
30./x test --stage 1 tests/ui/autodiff
31./x test --stage 1 tests/ui/feature-gates/feature-gate-autodiff.rs
3232```
3333
3434Autodiff is still experimental, so if you want to use it in your own projects, you will need to add `lto="fat"` to your Cargo.toml
......@@ -45,7 +45,7 @@ apt install wget vim python3 git curl libssl-dev pkg-config lld ninja-build cmak
4545```
4646Then build rustc in a slightly altered way:
4747```bash
48git clone --depth=1 https://github.com/rust-lang/rust.git
48git clone https://github.com/rust-lang/rust
4949cd rust
5050./configure --enable-llvm-link-shared --enable-llvm-plugins --enable-llvm-enzyme --release-channel=nightly --enable-llvm-assertions --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs
5151./x dist
......@@ -66,7 +66,7 @@ We recommend that approach, if you just want to use any of them and have no expe
6666However, if you prefer to just build Enzyme without Rust, then these instructions might help.
6767
6868```bash
69git clone --depth=1 git@github.com:llvm/llvm-project.git
69git clone git@github.com:llvm/llvm-project
7070cd llvm-project
7171mkdir build
7272cd build
......@@ -77,7 +77,7 @@ ninja install
7777This gives you a working LLVM build, now we can continue with building Enzyme.
7878Leave the `llvm-project` folder, and execute the following commands:
7979```bash
80git clone git@github.com:EnzymeAD/Enzyme.git
80git clone git@github.com:EnzymeAD/Enzyme
8181cd Enzyme/enzyme
8282mkdir build
8383cd build
src/doc/rustc-dev-guide/src/external-repos.md+55-11
......@@ -9,7 +9,7 @@ There are three main ways we use dependencies:
99As a general rule:
1010- Use crates.io for libraries that could be useful for others in the ecosystem
1111- Use subtrees for tools that depend on compiler internals and need to be updated if there are breaking
12changes
12 changes
1313- Use submodules for tools that are independent of the compiler
1414
1515## External Dependencies (subtrees)
......@@ -23,6 +23,8 @@ The following external projects are managed using some form of a `subtree`:
2323* [rust-analyzer](https://github.com/rust-lang/rust-analyzer)
2424* [rustc_codegen_cranelift](https://github.com/rust-lang/rustc_codegen_cranelift)
2525* [rustc-dev-guide](https://github.com/rust-lang/rustc-dev-guide)
26* [compiler-builtins](https://github.com/rust-lang/compiler-builtins)
27* [stdarch](https://github.com/rust-lang/stdarch)
2628
2729In contrast to `submodule` dependencies
2830(see below for those), the `subtree` dependencies are just regular files and directories which can
......@@ -34,20 +36,61 @@ implement a new tool feature or test, that should happen in one collective rustc
3436`subtree` dependencies are currently managed by two distinct approaches:
3537
3638* Using `git subtree`
37 * `clippy` ([sync guide](https://doc.rust-lang.org/nightly/clippy/development/infrastructure/sync.html#performing-the-sync-from-rust-langrust-to-clippy))
38 * `portable-simd` ([sync script](https://github.com/rust-lang/portable-simd/blob/master/subtree-sync.sh))
39 * `rustfmt`
40 * `rustc_codegen_cranelift` ([sync script](https://github.com/rust-lang/rustc_codegen_cranelift/blob/113af154d459e41b3dc2c5d7d878e3d3a8f33c69/scripts/rustup.sh#L7))
39 * `clippy` ([sync guide](https://doc.rust-lang.org/nightly/clippy/development/infrastructure/sync.html#performing-the-sync-from-rust-langrust-to-clippy))
40 * `portable-simd` ([sync script](https://github.com/rust-lang/portable-simd/blob/master/subtree-sync.sh))
41 * `rustfmt`
42 * `rustc_codegen_cranelift` ([sync script](https://github.com/rust-lang/rustc_codegen_cranelift/blob/113af154d459e41b3dc2c5d7d878e3d3a8f33c69/scripts/rustup.sh#L7))
4143* Using the [josh] tool
42 * `miri` ([sync guide](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#advanced-topic-syncing-with-the-rustc-repo))
43 * `rust-analyzer` ([sync script](https://github.com/rust-lang/rust-analyzer/blob/2e13684be123eca7181aa48e043e185d8044a84a/xtask/src/release.rs#L147))
44 * `rustc-dev-guide` ([sync guide](https://github.com/rust-lang/rustc-dev-guide#synchronizing-josh-subtree-with-rustc))
44 * `miri` ([sync guide](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#advanced-topic-syncing-with-the-rustc-repo))
45 * `rust-analyzer` ([sync script](https://github.com/rust-lang/rust-analyzer/blob/2e13684be123eca7181aa48e043e185d8044a84a/xtask/src/release.rs#L147))
46 * `rustc-dev-guide` ([josh sync](#synchronizing-a-josh-subtree))
47 * `compiler-builtins` ([josh sync](#synchronizing-a-josh-subtree))
48 * `stdarch` ([josh sync](#synchronizing-a-josh-subtree))
4549
46The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh, you can check out the `miri` or `rust-analyzer` scripts linked above for inspiration. If you want to migrate a repository dependency from `git subtree` or `git submodule` to josh, you can check out [this guide](https://hackmd.io/7pOuxnkdQDaL1Y1FQr65xg).
50### Josh subtrees
4751
48Below you can find a guide on how to perform push and pull synchronization with the main rustc repo using `git subtree`, although these instructions might differ repo from repo.
52The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh; you can check out the `miri` or `rust-analyzer` scripts linked above for inspiration. We provide a helper [`rustc-josh-sync`][josh-sync] tool to help with the synchronization, described [below](#synchronizing-a-josh-subtree).
4953
50### Synchronizing a subtree
54### Synchronizing a Josh subtree
55
56We use a dedicated tool called [`rustc-josh-sync`][josh-sync] for performing Josh subtree updates.
57Currently, we are migrating Josh repositories to it. So far, it is used in:
58
59- compiler-builtins
60- rustc-dev-guide
61- stdarch
62
63To install the tool:
64```
65cargo install --locked --git https://github.com/rust-lang/josh-sync
66```
67
68Both pulls (synchronize changes from rust-lang/rust into the subtree) and pushes (synchronize
69changes from the subtree to rust-lang/rust) are performed from the subtree repository (so first
70switch to its repository checkout directory in your terminal).
71
72#### Performing pull
731) Checkout a new branch that will be used to create a PR into the subtree
742) Run the pull command
75 ```
76 rustc-josh-sync pull
77 ```
783) Push the branch to your fork and create a PR into the subtree repository
79 - If you have `gh` CLI installed, `rustc-josh-sync` can create the PR for you.
80
81#### Performing push
82
831) Run the push command to create a branch named `<branch-name>` in a `rustc` fork under the `<gh-username>` account
84 ```
85 rustc-josh-sync push <branch-name> <gh-username>
86 ```
872) Create a PR from `<branch-name>` into `rust-lang/rust`
88
89### Creating a new Josh subtree dependency
90
91If you want to migrate a repository dependency from `git subtree` or `git submodule` to josh, you can check out [this guide](https://hackmd.io/7pOuxnkdQDaL1Y1FQr65xg).
92
93### Synchronizing a git subtree
5194
5295Periodically the changes made to subtree based dependencies need to be synchronized between this
5396repository and the upstream tool repositories.
......@@ -129,3 +172,4 @@ the week leading up to the beta cut.
129172[toolstate website]: https://rust-lang-nursery.github.io/rust-toolstate/
130173[Toolstate chapter]: https://forge.rust-lang.org/infra/toolstate.html
131174[josh]: https://josh-project.github.io/josh/intro.html
175[josh-sync]: https://github.com/rust-lang/josh-sync
src/doc/rustc-dev-guide/src/offload/installation.md+4-4
......@@ -6,14 +6,14 @@ In the future, `std::offload` should become available in nightly builds for user
66
77First you need to clone and configure the Rust repository:
88```bash
9git clone --depth=1 git@github.com:rust-lang/rust.git
9git clone git@github.com:rust-lang/rust
1010cd rust
1111./configure --enable-llvm-link-shared --release-channel=nightly --enable-llvm-assertions --enable-offload --enable-enzyme --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs
1212```
1313
1414Afterwards you can build rustc using:
1515```bash
16./x.py build --stage 1 library
16./x build --stage 1 library
1717```
1818
1919Afterwards rustc toolchain link will allow you to use it through cargo:
......@@ -26,7 +26,7 @@ rustup toolchain install nightly # enables -Z unstable-options
2626
2727## Build instruction for LLVM itself
2828```bash
29git clone --depth=1 git@github.com:llvm/llvm-project.git
29git clone git@github.com:llvm/llvm-project
3030cd llvm-project
3131mkdir build
3232cd build
......@@ -40,7 +40,7 @@ This gives you a working LLVM build.
4040## Testing
4141run
4242```
43./x.py test --stage 1 tests/codegen/gpu_offload
43./x test --stage 1 tests/codegen/gpu_offload
4444```
4545
4646## Usage
src/doc/rustc-dev-guide/src/solve/invariants.md+65-47
......@@ -4,17 +4,15 @@ FIXME: This file talks about invariants of the type system as a whole, not only
44
55There are a lot of invariants - things the type system guarantees to be true at all times -
66which are desirable or expected from other languages and type systems. Unfortunately, quite
7a few of them do not hold in Rust right now. This is either a fundamental to its design or
8caused by bugs and something that may change in the future.
7a few of them do not hold in Rust right now. This is either fundamental to its design or
8caused by bugs, and something that may change in the future.
99
10It is important to know about the things you can assume while working on - and with - the
10It is important to know about the things you can assume while working on, and with, the
1111type system, so here's an incomplete and unofficial list of invariants of
1212the core type system:
1313
14- ✅: this invariant mostly holds, with some weird exceptions, you can rely on it outside
15of these cases
16- ❌: this invariant does not hold, either due to bugs or by design, you must not rely on
17it for soundness or have to be incredibly careful when doing so
14- ✅: this invariant mostly holds, with some weird exceptions or current bugs
15- ❌: this invariant does not hold, and is unlikely to do so in the future; do not rely on it for soundness or have to be incredibly careful when doing so
1816
1917### `wf(X)` implies `wf(normalize(X))` ✅
2018
......@@ -23,20 +21,23 @@ well-formed after normalizing said aliases. We rely on this as
2321otherwise we would have to re-check for well-formedness for these
2422types.
2523
24This currently does not hold due to a type system unsoundness: [#84533](https://github.com/rust-lang/rust/issues/84533).
25
2626### Structural equality modulo regions implies semantic equality ✅
2727
2828If you have a some type and equate it to itself after replacing any regions with unique
2929inference variables in both the lhs and rhs, the now potentially structurally different
3030types should still be equal to each other.
3131
32Needed to prevent goals from succeeding in HIR typeck and then failing in MIR borrowck.
33If this invariant is broken MIR typeck ends up failing with an ICE.
32This is needed to prevent goals from succeeding in HIR typeck and then failing in MIR borrowck.
33If this invariant is broken, MIR typeck ends up failing with an ICE.
3434
3535### Applying inference results from a goal does not change its result ❌
3636
3737TODO: this invariant is formulated in a weird way and needs to be elaborated.
3838Pretty much: I would like this check to only fail if there's a solver bug:
39https://github.com/rust-lang/rust/blob/2ffeb4636b4ae376f716dc4378a7efb37632dc2d/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs#L391-L407
39<https://github.com/rust-lang/rust/blob/2ffeb4636b4ae376f716dc4378a7efb37632dc2d/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs#L391-L407>.
40We should readd this check and see where it breaks :3
4041
4142If we prove some goal/equate types/whatever, apply the resulting inference constraints,
4243and then redo the original action, the result should be the same.
......@@ -73,82 +74,99 @@ Many of the currently known unsound issues end up relying on this invariant bein
7374It is however very difficult to imagine a sound type system without this invariant, so
7475the issue is that the invariant is broken, not that we incorrectly rely on it.
7576
76### Generic goals and their instantiations have the same result ✅
77### The type system is complete ❌
78
79The type system is not complete.
80It often adds unnecessary inference constraints, and errors even though the goal could hold.
81
82- method selection
83- opaque type inference
84- handling type outlives constraints
85- preferring `ParamEnv` candidates over `Impl` candidates during candidate selection
86in the trait solver
87
88### Goals keep their result from HIR typeck afterwards ✅
89
90Having a goal which succeeds during HIR typeck but fails when being reevaluated during MIR borrowck causes ICE, e.g. [#140211](https://github.com/rust-lang/rust/issues/140211).
7791
78Pretty much: If we successfully typecheck a generic function concrete instantiations
79of that function should also typeck. We should not get errors post-monomorphization.
80We can however get overflow errors at that point.
92Having a goal which succeeds during HIR typeck but fails after being instantiated is unsound, e.g. [#140212](https://github.com/rust-lang/rust/issues/140212).
8193
82TODO: example for overflow error post-monomorphization
94It is interesting that we allow some incompleteness in the trait solver while still maintaining this limitation. It would be nice if there was a clear way to separate the "allowed incompleteness" from behavior which would break this invariant.
95
96#### Normalization must not change results
8397
8498This invariant is relied on to allow the normalization of generic aliases. Breaking
85it can easily result in unsoundness, e.g. [#57893](https://github.com/rust-lang/rust/issues/57893)
99it can easily result in unsoundness, e.g. [#57893](https://github.com/rust-lang/rust/issues/57893).
100
101#### Goals may still overflow after instantiation
102
103This happens they start to hit the recursion limit.
104We also have diverging aliases which are scuffed.
105It's unclear how these should be handled :3
86106
87107### Trait goals in empty environments are proven by a unique impl ✅
88108
89109If a trait goal holds with an empty environment, there should be a unique `impl`,
90110either user-defined or builtin, which is used to prove that goal. This is
91necessary to select a unique method.
111necessary to select unique methods and associated items.
92112
93We do however break this invariant in few cases, some of which are due to bugs,
94some by design:
113We do however break this invariant in a few cases, some of which are due to bugs, some by design:
95114- *marker traits* are allowed to overlap as they do not have associated items
96115- *specialization* allows specializing impls to overlap with their parent
97116- the builtin trait object trait implementation can overlap with a user-defined impl:
98[#57893]
117[#57893](https://github.com/rust-lang/rust/issues/57893)
99118
100### The type system is complete ❌
101
102The type system is not complete, it often adds unnecessary inference constraints, and errors
103even though the goal could hold.
104
105- method selection
106- opaque type inference
107- handling type outlives constraints
108- preferring `ParamEnv` candidates over `Impl` candidates during candidate selection
109in the trait solver
110119
111120#### The type system is complete during the implicit negative overlap check in coherence ✅
112121
113For more on overlap checking: [coherence]
122For more on overlap checking, see [Coherence chapter].
114123
115During the implicit negative overlap check in coherence we must never return *error* for
116goals which can be proven. This would allow for overlapping impls with potentially different
117associated items, breaking a bunch of other invariants.
124During the implicit negative overlap check in coherence,
125we must never return *error* for goals which can be proven.
126This would allow for overlapping impls with potentially different associated items,
127breaking a bunch of other invariants.
118128
119129This invariant is currently broken in many different ways while actually something we rely on.
120130We have to be careful as it is quite easy to break:
121131- generalization of aliases
122132- generalization during subtyping binders (luckily not exploitable in coherence)
123133
124### Trait solving must be (free) lifetime agnostic ✅
134### Trait solving must not depend on lifetimes being different ✅
135
136If a goal holds with lifetimes being different, it must also hold with these lifetimes being the same. We otherwise get post-monomorphization errors during codegen or unsoundness due to invalid vtables.
125137
126Trait solving during codegen should have the same result as during typeck. As we erase
127all free regions during codegen we must not rely on them during typeck. A noteworthy example
128is special behavior for `'static`.
138We could also just get inconsistent behavior when first proving a goal with different lifetimes which are later constrained to be equal.
139
140### Trait solving in bodies must not depend on lifetimes being equal ✅
129141
130142We also have to be careful with relying on equality of regions in the trait solver.
131143This is fine for codegen, as we treat all erased regions as equal. We can however
132144lose equality information from HIR to MIR typeck.
133145
134The new solver "uniquifies regions" during canonicalization, canonicalizing `u32: Trait<'x, 'x>`
135as `exists<'0, '1> u32: Trait<'0, '1>`, to make it harder to rely on this property.
146This currently does not hold with the new solver: [trait-system-refactor-initiative#27](https://github.com/rust-lang/trait-system-refactor-initiative/issues/27).
136147
137148### Removing ambiguity makes strictly more things compile ❌
138149
139150Ideally we *should* not rely on ambiguity for things to compile.
140151Not doing that will cause future improvements to be breaking changes.
141152
142Due to *incompleteness* this is not the case and improving inference can result in inference
143changes, breaking existing projects.
153Due to *incompleteness* this is not the case,
154and improving inference can result in inference changes, breaking existing projects.
144155
145156### Semantic equality implies structural equality ✅
146157
147158Two types being equal in the type system must mean that they have the
148159same `TypeId` after instantiating their generic parameters with concrete
149arguments. This currently does not hold: [#97156].
160arguments. We can otherwise use their different `TypeId`s to impact trait selection.
161
162We lookup types using structural equality during codegen, but this shouldn't necessarily be unsound
163- may result in redundant method codegen or backend type check errors?
164- we also rely on it in CTFE assertions
165
166### Semantically different types have different `TypeId`s ✅
167
168Semantically different `'static` types need different `TypeId`s to avoid transmutes,
169for example `for<'a> fn(&'a str)` vs `fn(&'static str)` must have a different `TypeId`.
170
150171
151[#57893]: https://github.com/rust-lang/rust/issues/57893
152[#97156]: https://github.com/rust-lang/rust/issues/97156
153[#114936]: https://github.com/rust-lang/rust/issues/114936
154[coherence]: ../coherence.md
172[coherence chapter]: ../coherence.md
src/doc/rustc-dev-guide/src/tests/directives.md+1-1
......@@ -59,7 +59,7 @@ not be exhaustive. Directives can generally be found by browsing the
5959| `aux-crate` | Like `aux-build` but makes available as extern prelude | All except `run-make` | `<extern_prelude_name>=<path/to/aux/file.rs>` |
6060| `aux-codegen-backend` | Similar to `aux-build` but pass the compiled dylib to `-Zcodegen-backend` when building the main file | `ui-fulldeps` | Path to codegen backend file |
6161| `proc-macro` | Similar to `aux-build`, but for aux forces host and don't use `-Cprefer-dynamic`[^pm]. | All except `run-make` | Path to auxiliary proc-macro `.rs` file |
62| `build-aux-docs` | Build docs for auxiliaries as well | All except `run-make` | N/A |
62| `build-aux-docs` | Build docs for auxiliaries as well. Note that this only works with `aux-build`, not `aux-crate`. | All except `run-make` | N/A |
6363
6464[^pm]: please see the Auxiliary proc-macro section in the
6565 [compiletest](./compiletest.md) chapter for specifics.
src/doc/rustc-dev-guide/src/tests/intro.md+4-2
......@@ -111,12 +111,14 @@ and it can be invoked so:
111111
112112This requires building all of the documentation, which might take a while.
113113
114### Dist check
114### `distcheck`
115115
116116`distcheck` verifies that the source distribution tarball created by the build
117117system will unpack, build, and run all tests.
118118
119> Example: `./x test distcheck`
119```console
120./x test distcheck
121```
120122
121123### Tool tests
122124
src/doc/rustc-dev-guide/src/tests/misc.md+1-1
......@@ -9,7 +9,7 @@ for testing:
99
1010- `RUSTC_BOOTSTRAP=1` will "cheat" and bypass usual stability checking, allowing
1111 you to use unstable features and cli flags on a stable `rustc`.
12- `RUSTC_BOOTSTRAP=-1` will force a given `rustc` to pretend that is a stable
12- `RUSTC_BOOTSTRAP=-1` will force a given `rustc` to pretend it is a stable
1313 compiler, even if it's actually a nightly `rustc`. This is useful because some
1414 behaviors of the compiler (e.g. diagnostics) can differ depending on whether
1515 the compiler is nightly or not.
src/tools/miri/src/machine.rs+2-2
......@@ -1086,7 +1086,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
10861086 ecx: &MiriInterpCx<'tcx>,
10871087 instance: ty::Instance<'tcx>,
10881088 ) -> InterpResult<'tcx> {
1089 let attrs = ecx.tcx.codegen_fn_attrs(instance.def_id());
1089 let attrs = ecx.tcx.codegen_instance_attrs(instance.def);
10901090 if attrs
10911091 .target_features
10921092 .iter()
......@@ -1790,7 +1790,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
17901790 ecx.tcx.sess.opts.unstable_opts.cross_crate_inline_threshold,
17911791 InliningThreshold::Always
17921792 ) || !matches!(
1793 ecx.tcx.codegen_fn_attrs(instance.def_id()).inline,
1793 ecx.tcx.codegen_instance_attrs(instance.def).inline,
17941794 InlineAttr::Never
17951795 );
17961796 !is_generic && !can_be_inlined
tests/codegen/sanitizer/kcfi/naked-function.rs created+47
......@@ -0,0 +1,47 @@
1//@ add-core-stubs
2//@ revisions: aarch64 x86_64
3//@ [aarch64] compile-flags: --target aarch64-unknown-none
4//@ [aarch64] needs-llvm-components: aarch64
5//@ [x86_64] compile-flags: --target x86_64-unknown-none
6//@ [x86_64] needs-llvm-components: x86
7//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Cno-prepopulate-passes -Copt-level=0
8
9#![feature(no_core, lang_items)]
10#![crate_type = "lib"]
11#![no_core]
12
13extern crate minicore;
14use minicore::*;
15
16struct Thing;
17trait MyTrait {
18 #[unsafe(naked)]
19 extern "C" fn my_naked_function() {
20 // the real function is defined
21 // CHECK: .globl
22 // CHECK-SAME: my_naked_function
23 naked_asm!("ret")
24 }
25}
26impl MyTrait for Thing {}
27
28// the shim calls the real function
29// CHECK-LABEL: define
30// CHECK-SAME: my_naked_function
31// CHECK-SAME: reify.shim.fnptr
32
33// CHECK-LABEL: main
34#[unsafe(no_mangle)]
35pub fn main() {
36 // Trick the compiler into generating an indirect call.
37 const F: extern "C" fn() = Thing::my_naked_function;
38
39 // main calls the shim function
40 // CHECK: call void
41 // CHECK-SAME: my_naked_function
42 // CHECK-SAME: reify.shim.fnptr
43 (F)();
44}
45
46// CHECK: declare !kcfi_type
47// CHECK-SAME: my_naked_function
tests/crashes/128094.rs deleted-15
......@@ -1,15 +0,0 @@
1//@ known-bug: rust-lang/rust#128094
2//@ compile-flags: -Zmir-enable-passes=+GVN
3//@ edition: 2018
4
5pub enum Request {
6 TestSome(T),
7}
8
9pub async fn handle_event(event: Request) {
10 async move {
11 static instance: Request = Request { bar: 17 };
12 &instance
13 }
14 .await;
15}
tests/crashes/135128.rs deleted-13
......@@ -1,13 +0,0 @@
1//@ known-bug: #135128
2//@ compile-flags: -Copt-level=1
3//@ edition: 2021
4
5#![feature(trivial_bounds)]
6
7async fn return_str() -> str
8where
9 str: Sized,
10{
11 *"Sized".to_string().into_boxed_str()
12}
13fn main() {}
tests/mir-opt/const_prop/transmute.rs+1-1
......@@ -56,7 +56,7 @@ pub unsafe fn undef_union_as_integer() -> u32 {
5656pub unsafe fn unreachable_direct() -> ! {
5757 // CHECK-LABEL: fn unreachable_direct(
5858 // CHECK: = const ();
59 // CHECK: = const () as Never (Transmute);
59 // CHECK: = const ZeroSized: Never;
6060 let x: Never = unsafe { transmute(()) };
6161 match x {}
6262}
tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff+1-1
......@@ -15,7 +15,7 @@
1515- _2 = ();
1616- _1 = move _2 as Never (Transmute);
1717+ _2 = const ();
18+ _1 = const () as Never (Transmute);
18+ _1 = const ZeroSized: Never;
1919 unreachable;
2020 }
2121 }
tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff+1-1
......@@ -15,7 +15,7 @@
1515- _2 = ();
1616- _1 = move _2 as Never (Transmute);
1717+ _2 = const ();
18+ _1 = const () as Never (Transmute);
18+ _1 = const ZeroSized: Never;
1919 unreachable;
2020 }
2121 }
tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff+2-1
......@@ -18,7 +18,8 @@
1818
1919 bb0: {
2020 _4 = copy _1 as *const T (PtrToPtr);
21 _5 = PtrMetadata(copy _4);
21- _5 = PtrMetadata(copy _4);
22+ _5 = const ();
2223 _6 = copy _1 as *const (&A, [T]) (PtrToPtr);
2324- _7 = PtrMetadata(copy _6);
2425+ _7 = PtrMetadata(copy _1);
tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff+2-1
......@@ -18,7 +18,8 @@
1818
1919 bb0: {
2020 _4 = copy _1 as *const T (PtrToPtr);
21 _5 = PtrMetadata(copy _4);
21- _5 = PtrMetadata(copy _4);
22+ _5 = const ();
2223 _6 = copy _1 as *const (&A, [T]) (PtrToPtr);
2324- _7 = PtrMetadata(copy _6);
2425+ _7 = PtrMetadata(copy _1);
tests/mir-opt/gvn.rs+1-1
......@@ -869,7 +869,7 @@ fn generic_cast_metadata<T, A: ?Sized, B: ?Sized>(ps: *const [T], pa: *const A,
869869
870870 // Metadata usize -> (), do not optimize.
871871 // CHECK: [[T:_.+]] = copy _1 as
872 // CHECK-NEXT: PtrMetadata(copy [[T]])
872 // CHECK-NEXT: const ();
873873 let t1 = CastPtrToPtr::<_, *const T>(ps);
874874 let m1 = PtrMetadata(t1);
875875
tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir+1-4
......@@ -109,7 +109,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
109109 }
110110
111111 bb4: {
112 StorageLive(_15);
113112 _14 = &mut _13;
114113 _15 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _14) -> [return: bb5, unwind: bb11];
115114 }
......@@ -120,7 +119,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
120119 }
121120
122121 bb6: {
123 StorageDead(_15);
124122 StorageDead(_13);
125123 drop(_2) -> [return: bb7, unwind continue];
126124 }
......@@ -135,14 +133,13 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
135133 StorageLive(_19);
136134 _19 = &_2;
137135 StorageLive(_20);
138 _20 = (copy _17, copy _18);
136 _20 = copy ((_15 as Some).0: (usize, &T));
139137 _21 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _19, move _20) -> [return: bb9, unwind: bb11];
140138 }
141139
142140 bb9: {
143141 StorageDead(_20);
144142 StorageDead(_19);
145 StorageDead(_15);
146143 goto -> bb4;
147144 }
148145
tests/run-make/export-executable-symbols/rmake.rs+14-12
......@@ -4,20 +4,22 @@
44// symbol.
55// See https://github.com/rust-lang/rust/pull/85673
66
7//@ only-unix
8// Reason: the export-executable-symbols flag only works on Unix
9// due to hardcoded platform-specific implementation
10// (See #85673)
11//@ ignore-cross-compile
127//@ ignore-wasm
8//@ ignore-cross-compile
139
14use run_make_support::{bin_name, llvm_readobj, rustc};
10use run_make_support::object::Object;
11use run_make_support::{bin_name, is_darwin, object, rustc};
1512
1613fn main() {
17 rustc().arg("-Zexport-executable-symbols").input("main.rs").crate_type("bin").run();
18 llvm_readobj()
19 .symbols()
20 .input(bin_name("main"))
21 .run()
22 .assert_stdout_contains("exported_symbol");
14 rustc()
15 .arg("-Ctarget-feature=-crt-static")
16 .arg("-Zexport-executable-symbols")
17 .input("main.rs")
18 .crate_type("bin")
19 .run();
20 let name: &[u8] = if is_darwin() { b"_exported_symbol" } else { b"exported_symbol" };
21 let contents = std::fs::read(bin_name("main")).unwrap();
22 let object = object::File::parse(contents.as_slice()).unwrap();
23 let found = object.exports().unwrap().iter().any(|x| x.name() == name);
24 assert!(found);
2325}
tests/run-make/mte-ffi/bar.h-2
......@@ -1,5 +1,3 @@
1// FIXME(#141600) the mte-ffi test doesn't fail in aarch64-gnu
2
31#ifndef __BAR_H
42#define __BAR_H
53
tests/run-make/mte-ffi/bar_float.c+2-2
......@@ -3,9 +3,9 @@
33#include <stdint.h>
44#include "bar.h"
55
6extern void foo(float*);
6extern void foo(char*);
77
8void bar(float *ptr) {
8void bar(char *ptr) {
99 if (((uintptr_t)ptr >> 56) != 0x1f) {
1010 fprintf(stderr, "Top byte corrupted on Rust -> C FFI boundary!\n");
1111 exit(1);
tests/run-make/mte-ffi/bar_int.c+1-1
......@@ -5,7 +5,7 @@
55
66extern void foo(unsigned int *);
77
8void bar(unsigned int *ptr) {
8void bar(char *ptr) {
99 if (((uintptr_t)ptr >> 56) != 0x1f) {
1010 fprintf(stderr, "Top byte corrupted on Rust -> C FFI boundary!\n");
1111 exit(1);
tests/run-make/mte-ffi/bar_string.c+1-2
......@@ -1,7 +1,6 @@
11#include <stdio.h>
22#include <stdlib.h>
33#include <stdint.h>
4#include <string.h>
54#include "bar.h"
65
76extern void foo(char*);
......@@ -33,7 +32,7 @@ int main(void)
3332
3433 // Store an arbitrary tag in bits 56-59 of the pointer (where an MTE tag may be),
3534 // and a different value in the ignored top 4 bits.
36 ptr = (char *)((uintptr_t)ptr | 0x1fl << 56);
35 ptr = (unsigned int *)((uintptr_t)ptr | 0x1fl << 56);
3736
3837 if (mte_enabled()) {
3938 set_tag(ptr);
tests/run-make/mte-ffi/rmake.rs+7
......@@ -2,6 +2,13 @@
22//! FFI boundaries (C <-> Rust). This test does not require MTE: whilst the test will use MTE if
33//! available, if it is not, arbitrary tag bits are set using TBI.
44
5//@ ignore-test (FIXME #141600)
6//
7// FIXME(#141600): this test is broken in two ways:
8// 1. This test triggers `-Wincompatible-pointer-types` on GCC 14.
9// 2. This test requires ARMv8.5+ w/ MTE extensions enabled, but GHA CI runner hardware do not have
10// this enabled.
11
512//@ only-aarch64-unknown-linux-gnu
613// Reason: this test is only valid for AArch64 with `gcc`. The linker must be explicitly specified
714// when cross-compiling, so it is limited to `aarch64-unknown-linux-gnu`.
tests/run-make/option-output-no-space/main.rs created+1
......@@ -0,0 +1 @@
1fn main() {}
tests/run-make/option-output-no-space/rmake.rs created+95
......@@ -0,0 +1,95 @@
1// This test is to check if the warning is emitted when no space
2// between `-o` and arg is applied, see issue #142812
3
4//@ ignore-cross-compile
5use run_make_support::rustc;
6
7fn main() {
8 // test fake args
9 rustc()
10 .input("main.rs")
11 .arg("-optimize")
12 .run()
13 .assert_stderr_contains(
14 "warning: option `-o` has no space between flag name and value, which can be confusing",
15 )
16 .assert_stderr_contains(
17 "note: output filename `-o ptimize` is applied instead of a flag named `optimize`",
18 );
19 rustc()
20 .input("main.rs")
21 .arg("-o0")
22 .run()
23 .assert_stderr_contains(
24 "warning: option `-o` has no space between flag name and value, which can be confusing",
25 )
26 .assert_stderr_contains(
27 "note: output filename `-o 0` is applied instead of a flag named `o0`",
28 );
29 rustc().input("main.rs").arg("-o1").run();
30 // test real args by iter optgroups
31 rustc()
32 .input("main.rs")
33 .arg("-out-dir")
34 .run()
35 .assert_stderr_contains(
36 "warning: option `-o` has no space between flag name and value, which can be confusing",
37 )
38 .assert_stderr_contains(
39 "note: output filename `-o ut-dir` is applied instead of a flag named `out-dir`",
40 )
41 .assert_stderr_contains(
42 "help: insert a space between `-o` and `ut-dir` if this is intentional: `-o ut-dir`",
43 );
44 // test real args by iter CG_OPTIONS
45 rustc()
46 .input("main.rs")
47 .arg("-opt_level")
48 .run()
49 .assert_stderr_contains(
50 "warning: option `-o` has no space between flag name and value, which can be confusing",
51 )
52 .assert_stderr_contains(
53 "note: output filename `-o pt_level` is applied instead of a flag named `opt_level`",
54 )
55 .assert_stderr_contains(
56 "help: insert a space between `-o` and `pt_level` if this is intentional: `-o pt_level`"
57 );
58 // separater in-sensitive
59 rustc()
60 .input("main.rs")
61 .arg("-opt-level")
62 .run()
63 .assert_stderr_contains(
64 "warning: option `-o` has no space between flag name and value, which can be confusing",
65 )
66 .assert_stderr_contains(
67 "note: output filename `-o pt-level` is applied instead of a flag named `opt-level`",
68 )
69 .assert_stderr_contains(
70 "help: insert a space between `-o` and `pt-level` if this is intentional: `-o pt-level`"
71 );
72 rustc()
73 .input("main.rs")
74 .arg("-overflow-checks")
75 .run()
76 .assert_stderr_contains(
77 "warning: option `-o` has no space between flag name and value, which can be confusing",
78 )
79 .assert_stderr_contains(
80 "note: output filename `-o verflow-checks` \
81 is applied instead of a flag named `overflow-checks`",
82 )
83 .assert_stderr_contains(
84 "help: insert a space between `-o` and `verflow-checks` \
85 if this is intentional: `-o verflow-checks`",
86 );
87
88 // No warning for Z_OPTIONS
89 rustc().input("main.rs").arg("-oom").run().assert_stderr_equals("");
90
91 // test no warning when there is space between `-o` and arg
92 rustc().input("main.rs").arg("-o").arg("ptimize").run().assert_stderr_equals("");
93 rustc().input("main.rs").arg("--out-dir").arg("xxx").run().assert_stderr_equals("");
94 rustc().input("main.rs").arg("-o").arg("out-dir").run().assert_stderr_equals("");
95}
tests/ui/asm/naked-function-shim.rs created+31
......@@ -0,0 +1,31 @@
1// The indirect call will generate a shim that then calls the actual function. Test that
2// this is handled correctly. See also https://github.com/rust-lang/rust/issues/143266.
3
4//@ build-pass
5//@ add-core-stubs
6//@ revisions: aarch64 x86_64
7//@ [aarch64] compile-flags: --target aarch64-unknown-none
8//@ [aarch64] needs-llvm-components: aarch64
9//@ [x86_64] compile-flags: --target x86_64-unknown-none
10//@ [x86_64] needs-llvm-components: x86
11
12#![feature(no_core, lang_items)]
13#![crate_type = "lib"]
14#![no_core]
15
16extern crate minicore;
17use minicore::*;
18
19trait MyTrait {
20 #[unsafe(naked)]
21 extern "C" fn foo(&self) {
22 naked_asm!("ret")
23 }
24}
25
26impl MyTrait for i32 {}
27
28fn main() {
29 let x: extern "C" fn(&_) = <dyn MyTrait as MyTrait>::foo;
30 x(&1);
31}
tests/ui/attributes/malformed-attrs.stderr+13-13
......@@ -37,19 +37,6 @@ error: malformed `crate_name` attribute input
3737LL | #[crate_name]
3838 | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]`
3939
40error: malformed `coverage` attribute input
41 --> $DIR/malformed-attrs.rs:90:1
42 |
43LL | #[coverage]
44 | ^^^^^^^^^^^
45 |
46help: the following are the possible correct uses
47 |
48LL | #[coverage(off)]
49 | +++++
50LL | #[coverage(on)]
51 | ++++
52
5340error: malformed `no_sanitize` attribute input
5441 --> $DIR/malformed-attrs.rs:92:1
5542 |
......@@ -460,6 +447,19 @@ error[E0539]: malformed `link_section` attribute input
460447LL | #[link_section]
461448 | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]`
462449
450error[E0539]: malformed `coverage` attribute input
451 --> $DIR/malformed-attrs.rs:90:1
452 |
453LL | #[coverage]
454 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
455 |
456help: try changing it to one of the following valid forms of the attribute
457 |
458LL | #[coverage(off)]
459 | +++++
460LL | #[coverage(on)]
461 | ++++
462
463463error[E0565]: malformed `no_implicit_prelude` attribute input
464464 --> $DIR/malformed-attrs.rs:97:1
465465 |
tests/ui/coverage-attr/bad-attr-ice.feat.stderr+4-3
......@@ -1,10 +1,10 @@
1error: malformed `coverage` attribute input
1error[E0539]: malformed `coverage` attribute input
22 --> $DIR/bad-attr-ice.rs:11:1
33 |
44LL | #[coverage]
5 | ^^^^^^^^^^^
5 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
66 |
7help: the following are the possible correct uses
7help: try changing it to one of the following valid forms of the attribute
88 |
99LL | #[coverage(off)]
1010 | +++++
......@@ -13,3 +13,4 @@ LL | #[coverage(on)]
1313
1414error: aborting due to 1 previous error
1515
16For more information about this error, try `rustc --explain E0539`.
tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr+14-13
......@@ -1,26 +1,27 @@
1error: malformed `coverage` attribute input
1error[E0658]: the `#[coverage]` attribute is an experimental feature
22 --> $DIR/bad-attr-ice.rs:11:1
33 |
44LL | #[coverage]
55 | ^^^^^^^^^^^
66 |
7help: the following are the possible correct uses
8 |
9LL | #[coverage(off)]
10 | +++++
11LL | #[coverage(on)]
12 | ++++
7 = note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information
8 = help: add `#![feature(coverage_attribute)]` 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
1310
14error[E0658]: the `#[coverage]` attribute is an experimental feature
11error[E0539]: malformed `coverage` attribute input
1512 --> $DIR/bad-attr-ice.rs:11:1
1613 |
1714LL | #[coverage]
18 | ^^^^^^^^^^^
15 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
1916 |
20 = note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information
21 = help: add `#![feature(coverage_attribute)]` to the crate attributes to enable
22 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
17help: try changing it to one of the following valid forms of the attribute
18 |
19LL | #[coverage(off)]
20 | +++++
21LL | #[coverage(on)]
22 | ++++
2323
2424error: aborting due to 2 previous errors
2525
26For more information about this error, try `rustc --explain E0658`.
26Some errors have detailed explanations: E0539, E0658.
27For more information about an error, try `rustc --explain E0539`.
tests/ui/coverage-attr/bad-syntax.stderr+74-60
......@@ -1,23 +1,59 @@
1error: malformed `coverage` attribute input
1error: expected identifier, found `,`
2 --> $DIR/bad-syntax.rs:44:12
3 |
4LL | #[coverage(,off)]
5 | ^ expected identifier
6 |
7help: remove this comma
8 |
9LL - #[coverage(,off)]
10LL + #[coverage(off)]
11 |
12
13error: multiple `coverage` attributes
14 --> $DIR/bad-syntax.rs:9:1
15 |
16LL | #[coverage(off)]
17 | ^^^^^^^^^^^^^^^^ help: remove this attribute
18 |
19note: attribute also specified here
20 --> $DIR/bad-syntax.rs:10:1
21 |
22LL | #[coverage(off)]
23 | ^^^^^^^^^^^^^^^^
24
25error: multiple `coverage` attributes
26 --> $DIR/bad-syntax.rs:13:1
27 |
28LL | #[coverage(off)]
29 | ^^^^^^^^^^^^^^^^ help: remove this attribute
30 |
31note: attribute also specified here
32 --> $DIR/bad-syntax.rs:14:1
33 |
34LL | #[coverage(on)]
35 | ^^^^^^^^^^^^^^^
36
37error[E0539]: malformed `coverage` attribute input
238 --> $DIR/bad-syntax.rs:17:1
339 |
440LL | #[coverage]
5 | ^^^^^^^^^^^
41 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
642 |
7help: the following are the possible correct uses
43help: try changing it to one of the following valid forms of the attribute
844 |
945LL | #[coverage(off)]
1046 | +++++
1147LL | #[coverage(on)]
1248 | ++++
1349
14error: malformed `coverage` attribute input
50error[E0539]: malformed `coverage` attribute input
1551 --> $DIR/bad-syntax.rs:20:1
1652 |
1753LL | #[coverage = true]
18 | ^^^^^^^^^^^^^^^^^^
54 | ^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
1955 |
20help: the following are the possible correct uses
56help: try changing it to one of the following valid forms of the attribute
2157 |
2258LL - #[coverage = true]
2359LL + #[coverage(off)]
......@@ -26,26 +62,30 @@ LL - #[coverage = true]
2662LL + #[coverage(on)]
2763 |
2864
29error: malformed `coverage` attribute input
65error[E0805]: malformed `coverage` attribute input
3066 --> $DIR/bad-syntax.rs:23:1
3167 |
3268LL | #[coverage()]
33 | ^^^^^^^^^^^^^
69 | ^^^^^^^^^^--^
70 | |
71 | expected a single argument here
3472 |
35help: the following are the possible correct uses
73help: try changing it to one of the following valid forms of the attribute
3674 |
3775LL | #[coverage(off)]
3876 | +++
3977LL | #[coverage(on)]
4078 | ++
4179
42error: malformed `coverage` attribute input
80error[E0805]: malformed `coverage` attribute input
4381 --> $DIR/bad-syntax.rs:26:1
4482 |
4583LL | #[coverage(off, off)]
46 | ^^^^^^^^^^^^^^^^^^^^^
84 | ^^^^^^^^^^----------^
85 | |
86 | expected a single argument here
4787 |
48help: the following are the possible correct uses
88help: try changing it to one of the following valid forms of the attribute
4989 |
5090LL - #[coverage(off, off)]
5191LL + #[coverage(off)]
......@@ -54,13 +94,15 @@ LL - #[coverage(off, off)]
5494LL + #[coverage(on)]
5595 |
5696
57error: malformed `coverage` attribute input
97error[E0805]: malformed `coverage` attribute input
5898 --> $DIR/bad-syntax.rs:29:1
5999 |
60100LL | #[coverage(off, on)]
61 | ^^^^^^^^^^^^^^^^^^^^
101 | ^^^^^^^^^^---------^
102 | |
103 | expected a single argument here
62104 |
63help: the following are the possible correct uses
105help: try changing it to one of the following valid forms of the attribute
64106 |
65107LL - #[coverage(off, on)]
66108LL + #[coverage(off)]
......@@ -69,13 +111,15 @@ LL - #[coverage(off, on)]
69111LL + #[coverage(on)]
70112 |
71113
72error: malformed `coverage` attribute input
114error[E0539]: malformed `coverage` attribute input
73115 --> $DIR/bad-syntax.rs:32:1
74116 |
75117LL | #[coverage(bogus)]
76 | ^^^^^^^^^^^^^^^^^^
118 | ^^^^^^^^^^^-----^^
119 | |
120 | valid arguments are `on` or `off`
77121 |
78help: the following are the possible correct uses
122help: try changing it to one of the following valid forms of the attribute
79123 |
80124LL - #[coverage(bogus)]
81125LL + #[coverage(off)]
......@@ -84,13 +128,15 @@ LL - #[coverage(bogus)]
84128LL + #[coverage(on)]
85129 |
86130
87error: malformed `coverage` attribute input
131error[E0805]: malformed `coverage` attribute input
88132 --> $DIR/bad-syntax.rs:35:1
89133 |
90134LL | #[coverage(bogus, off)]
91 | ^^^^^^^^^^^^^^^^^^^^^^^
135 | ^^^^^^^^^^------------^
136 | |
137 | expected a single argument here
92138 |
93help: the following are the possible correct uses
139help: try changing it to one of the following valid forms of the attribute
94140 |
95141LL - #[coverage(bogus, off)]
96142LL + #[coverage(off)]
......@@ -99,13 +145,15 @@ LL - #[coverage(bogus, off)]
99145LL + #[coverage(on)]
100146 |
101147
102error: malformed `coverage` attribute input
148error[E0805]: malformed `coverage` attribute input
103149 --> $DIR/bad-syntax.rs:38:1
104150 |
105151LL | #[coverage(off, bogus)]
106 | ^^^^^^^^^^^^^^^^^^^^^^^
152 | ^^^^^^^^^^------------^
153 | |
154 | expected a single argument here
107155 |
108help: the following are the possible correct uses
156help: try changing it to one of the following valid forms of the attribute
109157 |
110158LL - #[coverage(off, bogus)]
111159LL + #[coverage(off)]
......@@ -114,41 +162,7 @@ LL - #[coverage(off, bogus)]
114162LL + #[coverage(on)]
115163 |
116164
117error: expected identifier, found `,`
118 --> $DIR/bad-syntax.rs:44:12
119 |
120LL | #[coverage(,off)]
121 | ^ expected identifier
122 |
123help: remove this comma
124 |
125LL - #[coverage(,off)]
126LL + #[coverage(off)]
127 |
128
129error: multiple `coverage` attributes
130 --> $DIR/bad-syntax.rs:9:1
131 |
132LL | #[coverage(off)]
133 | ^^^^^^^^^^^^^^^^ help: remove this attribute
134 |
135note: attribute also specified here
136 --> $DIR/bad-syntax.rs:10:1
137 |
138LL | #[coverage(off)]
139 | ^^^^^^^^^^^^^^^^
140
141error: multiple `coverage` attributes
142 --> $DIR/bad-syntax.rs:13:1
143 |
144LL | #[coverage(off)]
145 | ^^^^^^^^^^^^^^^^ help: remove this attribute
146 |
147note: attribute also specified here
148 --> $DIR/bad-syntax.rs:14:1
149 |
150LL | #[coverage(on)]
151 | ^^^^^^^^^^^^^^^
152
153165error: aborting due to 11 previous errors
154166
167Some errors have detailed explanations: E0539, E0805.
168For more information about an error, try `rustc --explain E0539`.
tests/ui/coverage-attr/name-value.rs-7
......@@ -20,7 +20,6 @@ mod my_mod_inner {
2020
2121#[coverage = "off"]
2222//~^ ERROR malformed `coverage` attribute input
23//~| ERROR [E0788]
2423struct MyStruct;
2524
2625#[coverage = "off"]
......@@ -28,22 +27,18 @@ struct MyStruct;
2827impl MyStruct {
2928 #[coverage = "off"]
3029 //~^ ERROR malformed `coverage` attribute input
31 //~| ERROR [E0788]
3230 const X: u32 = 7;
3331}
3432
3533#[coverage = "off"]
3634//~^ ERROR malformed `coverage` attribute input
37//~| ERROR [E0788]
3835trait MyTrait {
3936 #[coverage = "off"]
4037 //~^ ERROR malformed `coverage` attribute input
41 //~| ERROR [E0788]
4238 const X: u32;
4339
4440 #[coverage = "off"]
4541 //~^ ERROR malformed `coverage` attribute input
46 //~| ERROR [E0788]
4742 type T;
4843}
4944
......@@ -52,12 +47,10 @@ trait MyTrait {
5247impl MyTrait for MyStruct {
5348 #[coverage = "off"]
5449 //~^ ERROR malformed `coverage` attribute input
55 //~| ERROR [E0788]
5650 const X: u32 = 8;
5751
5852 #[coverage = "off"]
5953 //~^ ERROR malformed `coverage` attribute input
60 //~| ERROR [E0788]
6154 type T = ();
6255}
6356
tests/ui/coverage-attr/name-value.stderr+49-130
......@@ -1,10 +1,10 @@
1error: malformed `coverage` attribute input
1error[E0539]: malformed `coverage` attribute input
22 --> $DIR/name-value.rs:12:1
33 |
44LL | #[coverage = "off"]
5 | ^^^^^^^^^^^^^^^^^^^
5 | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
66 |
7help: the following are the possible correct uses
7help: try changing it to one of the following valid forms of the attribute
88 |
99LL - #[coverage = "off"]
1010LL + #[coverage(off)]
......@@ -13,28 +13,28 @@ LL - #[coverage = "off"]
1313LL + #[coverage(on)]
1414 |
1515
16error: malformed `coverage` attribute input
16error[E0539]: malformed `coverage` attribute input
1717 --> $DIR/name-value.rs:17:5
1818 |
1919LL | #![coverage = "off"]
20 | ^^^^^^^^^^^^^^^^^^^^
20 | ^^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
2121 |
22help: the following are the possible correct uses
22help: try changing it to one of the following valid forms of the attribute
2323 |
2424LL - #![coverage = "off"]
25LL + #![coverage(off)]
25LL + #[coverage(off)]
2626 |
2727LL - #![coverage = "off"]
28LL + #![coverage(on)]
28LL + #[coverage(on)]
2929 |
3030
31error: malformed `coverage` attribute input
31error[E0539]: malformed `coverage` attribute input
3232 --> $DIR/name-value.rs:21:1
3333 |
3434LL | #[coverage = "off"]
35 | ^^^^^^^^^^^^^^^^^^^
35 | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
3636 |
37help: the following are the possible correct uses
37help: try changing it to one of the following valid forms of the attribute
3838 |
3939LL - #[coverage = "off"]
4040LL + #[coverage(off)]
......@@ -43,13 +43,13 @@ LL - #[coverage = "off"]
4343LL + #[coverage(on)]
4444 |
4545
46error: malformed `coverage` attribute input
47 --> $DIR/name-value.rs:26:1
46error[E0539]: malformed `coverage` attribute input
47 --> $DIR/name-value.rs:25:1
4848 |
4949LL | #[coverage = "off"]
50 | ^^^^^^^^^^^^^^^^^^^
50 | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
5151 |
52help: the following are the possible correct uses
52help: try changing it to one of the following valid forms of the attribute
5353 |
5454LL - #[coverage = "off"]
5555LL + #[coverage(off)]
......@@ -58,13 +58,13 @@ LL - #[coverage = "off"]
5858LL + #[coverage(on)]
5959 |
6060
61error: malformed `coverage` attribute input
62 --> $DIR/name-value.rs:29:5
61error[E0539]: malformed `coverage` attribute input
62 --> $DIR/name-value.rs:28:5
6363 |
6464LL | #[coverage = "off"]
65 | ^^^^^^^^^^^^^^^^^^^
65 | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
6666 |
67help: the following are the possible correct uses
67help: try changing it to one of the following valid forms of the attribute
6868 |
6969LL - #[coverage = "off"]
7070LL + #[coverage(off)]
......@@ -73,13 +73,13 @@ LL - #[coverage = "off"]
7373LL + #[coverage(on)]
7474 |
7575
76error: malformed `coverage` attribute input
77 --> $DIR/name-value.rs:35:1
76error[E0539]: malformed `coverage` attribute input
77 --> $DIR/name-value.rs:33:1
7878 |
7979LL | #[coverage = "off"]
80 | ^^^^^^^^^^^^^^^^^^^
80 | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
8181 |
82help: the following are the possible correct uses
82help: try changing it to one of the following valid forms of the attribute
8383 |
8484LL - #[coverage = "off"]
8585LL + #[coverage(off)]
......@@ -88,13 +88,13 @@ LL - #[coverage = "off"]
8888LL + #[coverage(on)]
8989 |
9090
91error: malformed `coverage` attribute input
92 --> $DIR/name-value.rs:39:5
91error[E0539]: malformed `coverage` attribute input
92 --> $DIR/name-value.rs:36:5
9393 |
9494LL | #[coverage = "off"]
95 | ^^^^^^^^^^^^^^^^^^^
95 | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
9696 |
97help: the following are the possible correct uses
97help: try changing it to one of the following valid forms of the attribute
9898 |
9999LL - #[coverage = "off"]
100100LL + #[coverage(off)]
......@@ -103,13 +103,13 @@ LL - #[coverage = "off"]
103103LL + #[coverage(on)]
104104 |
105105
106error: malformed `coverage` attribute input
107 --> $DIR/name-value.rs:44:5
106error[E0539]: malformed `coverage` attribute input
107 --> $DIR/name-value.rs:40:5
108108 |
109109LL | #[coverage = "off"]
110 | ^^^^^^^^^^^^^^^^^^^
110 | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
111111 |
112help: the following are the possible correct uses
112help: try changing it to one of the following valid forms of the attribute
113113 |
114114LL - #[coverage = "off"]
115115LL + #[coverage(off)]
......@@ -118,13 +118,13 @@ LL - #[coverage = "off"]
118118LL + #[coverage(on)]
119119 |
120120
121error: malformed `coverage` attribute input
122 --> $DIR/name-value.rs:50:1
121error[E0539]: malformed `coverage` attribute input
122 --> $DIR/name-value.rs:45:1
123123 |
124124LL | #[coverage = "off"]
125 | ^^^^^^^^^^^^^^^^^^^
125 | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
126126 |
127help: the following are the possible correct uses
127help: try changing it to one of the following valid forms of the attribute
128128 |
129129LL - #[coverage = "off"]
130130LL + #[coverage(off)]
......@@ -133,13 +133,13 @@ LL - #[coverage = "off"]
133133LL + #[coverage(on)]
134134 |
135135
136error: malformed `coverage` attribute input
137 --> $DIR/name-value.rs:53:5
136error[E0539]: malformed `coverage` attribute input
137 --> $DIR/name-value.rs:48:5
138138 |
139139LL | #[coverage = "off"]
140 | ^^^^^^^^^^^^^^^^^^^
140 | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
141141 |
142help: the following are the possible correct uses
142help: try changing it to one of the following valid forms of the attribute
143143 |
144144LL - #[coverage = "off"]
145145LL + #[coverage(off)]
......@@ -148,13 +148,13 @@ LL - #[coverage = "off"]
148148LL + #[coverage(on)]
149149 |
150150
151error: malformed `coverage` attribute input
152 --> $DIR/name-value.rs:58:5
151error[E0539]: malformed `coverage` attribute input
152 --> $DIR/name-value.rs:52:5
153153 |
154154LL | #[coverage = "off"]
155 | ^^^^^^^^^^^^^^^^^^^
155 | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
156156 |
157help: the following are the possible correct uses
157help: try changing it to one of the following valid forms of the attribute
158158 |
159159LL - #[coverage = "off"]
160160LL + #[coverage(off)]
......@@ -163,13 +163,13 @@ LL - #[coverage = "off"]
163163LL + #[coverage(on)]
164164 |
165165
166error: malformed `coverage` attribute input
167 --> $DIR/name-value.rs:64:1
166error[E0539]: malformed `coverage` attribute input
167 --> $DIR/name-value.rs:57:1
168168 |
169169LL | #[coverage = "off"]
170 | ^^^^^^^^^^^^^^^^^^^
170 | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
171171 |
172help: the following are the possible correct uses
172help: try changing it to one of the following valid forms of the attribute
173173 |
174174LL - #[coverage = "off"]
175175LL + #[coverage(off)]
......@@ -178,87 +178,6 @@ LL - #[coverage = "off"]
178178LL + #[coverage(on)]
179179 |
180180
181error[E0788]: coverage attribute not allowed here
182 --> $DIR/name-value.rs:21:1
183 |
184LL | #[coverage = "off"]
185 | ^^^^^^^^^^^^^^^^^^^
186...
187LL | struct MyStruct;
188 | ---------------- not a function, impl block, or module
189 |
190 = help: coverage attribute can be applied to a function (with body), impl block, or module
191
192error[E0788]: coverage attribute not allowed here
193 --> $DIR/name-value.rs:35:1
194 |
195LL | #[coverage = "off"]
196 | ^^^^^^^^^^^^^^^^^^^
197...
198LL | / trait MyTrait {
199LL | | #[coverage = "off"]
200... |
201LL | | type T;
202LL | | }
203 | |_- not a function, impl block, or module
204 |
205 = help: coverage attribute can be applied to a function (with body), impl block, or module
206
207error[E0788]: coverage attribute not allowed here
208 --> $DIR/name-value.rs:39:5
209 |
210LL | #[coverage = "off"]
211 | ^^^^^^^^^^^^^^^^^^^
212...
213LL | const X: u32;
214 | ------------- not a function, impl block, or module
215 |
216 = help: coverage attribute can be applied to a function (with body), impl block, or module
217
218error[E0788]: coverage attribute not allowed here
219 --> $DIR/name-value.rs:44:5
220 |
221LL | #[coverage = "off"]
222 | ^^^^^^^^^^^^^^^^^^^
223...
224LL | type T;
225 | ------- not a function, impl block, or module
226 |
227 = help: coverage attribute can be applied to a function (with body), impl block, or module
228
229error[E0788]: coverage attribute not allowed here
230 --> $DIR/name-value.rs:29:5
231 |
232LL | #[coverage = "off"]
233 | ^^^^^^^^^^^^^^^^^^^
234...
235LL | const X: u32 = 7;
236 | ----------------- not a function, impl block, or module
237 |
238 = help: coverage attribute can be applied to a function (with body), impl block, or module
239
240error[E0788]: coverage attribute not allowed here
241 --> $DIR/name-value.rs:53:5
242 |
243LL | #[coverage = "off"]
244 | ^^^^^^^^^^^^^^^^^^^
245...
246LL | const X: u32 = 8;
247 | ----------------- not a function, impl block, or module
248 |
249 = help: coverage attribute can be applied to a function (with body), impl block, or module
250
251error[E0788]: coverage attribute not allowed here
252 --> $DIR/name-value.rs:58:5
253 |
254LL | #[coverage = "off"]
255 | ^^^^^^^^^^^^^^^^^^^
256...
257LL | type T = ();
258 | ------------ not a function, impl block, or module
259 |
260 = help: coverage attribute can be applied to a function (with body), impl block, or module
261
262error: aborting due to 19 previous errors
181error: aborting due to 12 previous errors
263182
264For more information about this error, try `rustc --explain E0788`.
183For more information about this error, try `rustc --explain E0539`.
tests/ui/coverage-attr/subword.stderr+21-12
......@@ -1,10 +1,12 @@
1error: malformed `coverage` attribute input
1error[E0539]: malformed `coverage` attribute input
22 --> $DIR/subword.rs:8:1
33 |
44LL | #[coverage(yes(milord))]
5 | ^^^^^^^^^^^^^^^^^^^^^^^^
5 | ^^^^^^^^^^^-----------^^
6 | |
7 | valid arguments are `on` or `off`
68 |
7help: the following are the possible correct uses
9help: try changing it to one of the following valid forms of the attribute
810 |
911LL - #[coverage(yes(milord))]
1012LL + #[coverage(off)]
......@@ -13,13 +15,15 @@ LL - #[coverage(yes(milord))]
1315LL + #[coverage(on)]
1416 |
1517
16error: malformed `coverage` attribute input
18error[E0539]: malformed `coverage` attribute input
1719 --> $DIR/subword.rs:11:1
1820 |
1921LL | #[coverage(no(milord))]
20 | ^^^^^^^^^^^^^^^^^^^^^^^
22 | ^^^^^^^^^^^----------^^
23 | |
24 | valid arguments are `on` or `off`
2125 |
22help: the following are the possible correct uses
26help: try changing it to one of the following valid forms of the attribute
2327 |
2428LL - #[coverage(no(milord))]
2529LL + #[coverage(off)]
......@@ -28,13 +32,15 @@ LL - #[coverage(no(milord))]
2832LL + #[coverage(on)]
2933 |
3034
31error: malformed `coverage` attribute input
35error[E0539]: malformed `coverage` attribute input
3236 --> $DIR/subword.rs:14:1
3337 |
3438LL | #[coverage(yes = "milord")]
35 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
39 | ^^^^^^^^^^^--------------^^
40 | |
41 | valid arguments are `on` or `off`
3642 |
37help: the following are the possible correct uses
43help: try changing it to one of the following valid forms of the attribute
3844 |
3945LL - #[coverage(yes = "milord")]
4046LL + #[coverage(off)]
......@@ -43,13 +49,15 @@ LL - #[coverage(yes = "milord")]
4349LL + #[coverage(on)]
4450 |
4551
46error: malformed `coverage` attribute input
52error[E0539]: malformed `coverage` attribute input
4753 --> $DIR/subword.rs:17:1
4854 |
4955LL | #[coverage(no = "milord")]
50 | ^^^^^^^^^^^^^^^^^^^^^^^^^^
56 | ^^^^^^^^^^^-------------^^
57 | |
58 | valid arguments are `on` or `off`
5159 |
52help: the following are the possible correct uses
60help: try changing it to one of the following valid forms of the attribute
5361 |
5462LL - #[coverage(no = "milord")]
5563LL + #[coverage(off)]
......@@ -60,3 +68,4 @@ LL + #[coverage(on)]
6068
6169error: aborting due to 4 previous errors
6270
71For more information about this error, try `rustc --explain E0539`.
tests/ui/coverage-attr/word-only.rs-7
......@@ -20,7 +20,6 @@ mod my_mod_inner {
2020
2121#[coverage]
2222//~^ ERROR malformed `coverage` attribute input
23//~| ERROR [E0788]
2423struct MyStruct;
2524
2625#[coverage]
......@@ -28,22 +27,18 @@ struct MyStruct;
2827impl MyStruct {
2928 #[coverage]
3029 //~^ ERROR malformed `coverage` attribute input
31 //~| ERROR [E0788]
3230 const X: u32 = 7;
3331}
3432
3533#[coverage]
3634//~^ ERROR malformed `coverage` attribute input
37//~| ERROR [E0788]
3835trait MyTrait {
3936 #[coverage]
4037 //~^ ERROR malformed `coverage` attribute input
41 //~| ERROR [E0788]
4238 const X: u32;
4339
4440 #[coverage]
4541 //~^ ERROR malformed `coverage` attribute input
46 //~| ERROR [E0788]
4742 type T;
4843}
4944
......@@ -52,12 +47,10 @@ trait MyTrait {
5247impl MyTrait for MyStruct {
5348 #[coverage]
5449 //~^ ERROR malformed `coverage` attribute input
55 //~| ERROR [E0788]
5650 const X: u32 = 8;
5751
5852 #[coverage]
5953 //~^ ERROR malformed `coverage` attribute input
60 //~| ERROR [E0788]
6154 type T = ();
6255}
6356
tests/ui/coverage-attr/word-only.stderr+53-132
......@@ -1,240 +1,161 @@
1error: malformed `coverage` attribute input
1error[E0539]: malformed `coverage` attribute input
22 --> $DIR/word-only.rs:12:1
33 |
44LL | #[coverage]
5 | ^^^^^^^^^^^
5 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
66 |
7help: the following are the possible correct uses
7help: try changing it to one of the following valid forms of the attribute
88 |
99LL | #[coverage(off)]
1010 | +++++
1111LL | #[coverage(on)]
1212 | ++++
1313
14error: malformed `coverage` attribute input
14error[E0539]: malformed `coverage` attribute input
1515 --> $DIR/word-only.rs:17:5
1616 |
1717LL | #![coverage]
18 | ^^^^^^^^^^^^
18 | ^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
1919 |
20help: the following are the possible correct uses
20help: try changing it to one of the following valid forms of the attribute
21 |
22LL - #![coverage]
23LL + #[coverage(off)]
24 |
25LL - #![coverage]
26LL + #[coverage(on)]
2127 |
22LL | #![coverage(off)]
23 | +++++
24LL | #![coverage(on)]
25 | ++++
2628
27error: malformed `coverage` attribute input
29error[E0539]: malformed `coverage` attribute input
2830 --> $DIR/word-only.rs:21:1
2931 |
3032LL | #[coverage]
31 | ^^^^^^^^^^^
33 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
3234 |
33help: the following are the possible correct uses
35help: try changing it to one of the following valid forms of the attribute
3436 |
3537LL | #[coverage(off)]
3638 | +++++
3739LL | #[coverage(on)]
3840 | ++++
3941
40error: malformed `coverage` attribute input
41 --> $DIR/word-only.rs:26:1
42error[E0539]: malformed `coverage` attribute input
43 --> $DIR/word-only.rs:25:1
4244 |
4345LL | #[coverage]
44 | ^^^^^^^^^^^
46 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
4547 |
46help: the following are the possible correct uses
48help: try changing it to one of the following valid forms of the attribute
4749 |
4850LL | #[coverage(off)]
4951 | +++++
5052LL | #[coverage(on)]
5153 | ++++
5254
53error: malformed `coverage` attribute input
54 --> $DIR/word-only.rs:29:5
55error[E0539]: malformed `coverage` attribute input
56 --> $DIR/word-only.rs:28:5
5557 |
5658LL | #[coverage]
57 | ^^^^^^^^^^^
59 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
5860 |
59help: the following are the possible correct uses
61help: try changing it to one of the following valid forms of the attribute
6062 |
6163LL | #[coverage(off)]
6264 | +++++
6365LL | #[coverage(on)]
6466 | ++++
6567
66error: malformed `coverage` attribute input
67 --> $DIR/word-only.rs:35:1
68error[E0539]: malformed `coverage` attribute input
69 --> $DIR/word-only.rs:33:1
6870 |
6971LL | #[coverage]
70 | ^^^^^^^^^^^
72 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
7173 |
72help: the following are the possible correct uses
74help: try changing it to one of the following valid forms of the attribute
7375 |
7476LL | #[coverage(off)]
7577 | +++++
7678LL | #[coverage(on)]
7779 | ++++
7880
79error: malformed `coverage` attribute input
80 --> $DIR/word-only.rs:39:5
81error[E0539]: malformed `coverage` attribute input
82 --> $DIR/word-only.rs:36:5
8183 |
8284LL | #[coverage]
83 | ^^^^^^^^^^^
85 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
8486 |
85help: the following are the possible correct uses
87help: try changing it to one of the following valid forms of the attribute
8688 |
8789LL | #[coverage(off)]
8890 | +++++
8991LL | #[coverage(on)]
9092 | ++++
9193
92error: malformed `coverage` attribute input
93 --> $DIR/word-only.rs:44:5
94error[E0539]: malformed `coverage` attribute input
95 --> $DIR/word-only.rs:40:5
9496 |
9597LL | #[coverage]
96 | ^^^^^^^^^^^
98 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
9799 |
98help: the following are the possible correct uses
100help: try changing it to one of the following valid forms of the attribute
99101 |
100102LL | #[coverage(off)]
101103 | +++++
102104LL | #[coverage(on)]
103105 | ++++
104106
105error: malformed `coverage` attribute input
106 --> $DIR/word-only.rs:50:1
107error[E0539]: malformed `coverage` attribute input
108 --> $DIR/word-only.rs:45:1
107109 |
108110LL | #[coverage]
109 | ^^^^^^^^^^^
111 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
110112 |
111help: the following are the possible correct uses
113help: try changing it to one of the following valid forms of the attribute
112114 |
113115LL | #[coverage(off)]
114116 | +++++
115117LL | #[coverage(on)]
116118 | ++++
117119
118error: malformed `coverage` attribute input
119 --> $DIR/word-only.rs:53:5
120error[E0539]: malformed `coverage` attribute input
121 --> $DIR/word-only.rs:48:5
120122 |
121123LL | #[coverage]
122 | ^^^^^^^^^^^
124 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
123125 |
124help: the following are the possible correct uses
126help: try changing it to one of the following valid forms of the attribute
125127 |
126128LL | #[coverage(off)]
127129 | +++++
128130LL | #[coverage(on)]
129131 | ++++
130132
131error: malformed `coverage` attribute input
132 --> $DIR/word-only.rs:58:5
133error[E0539]: malformed `coverage` attribute input
134 --> $DIR/word-only.rs:52:5
133135 |
134136LL | #[coverage]
135 | ^^^^^^^^^^^
137 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
136138 |
137help: the following are the possible correct uses
139help: try changing it to one of the following valid forms of the attribute
138140 |
139141LL | #[coverage(off)]
140142 | +++++
141143LL | #[coverage(on)]
142144 | ++++
143145
144error: malformed `coverage` attribute input
145 --> $DIR/word-only.rs:64:1
146error[E0539]: malformed `coverage` attribute input
147 --> $DIR/word-only.rs:57:1
146148 |
147149LL | #[coverage]
148 | ^^^^^^^^^^^
150 | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
149151 |
150help: the following are the possible correct uses
152help: try changing it to one of the following valid forms of the attribute
151153 |
152154LL | #[coverage(off)]
153155 | +++++
154156LL | #[coverage(on)]
155157 | ++++
156158
157error[E0788]: coverage attribute not allowed here
158 --> $DIR/word-only.rs:21:1
159 |
160LL | #[coverage]
161 | ^^^^^^^^^^^
162...
163LL | struct MyStruct;
164 | ---------------- not a function, impl block, or module
165 |
166 = help: coverage attribute can be applied to a function (with body), impl block, or module
167
168error[E0788]: coverage attribute not allowed here
169 --> $DIR/word-only.rs:35:1
170 |
171LL | #[coverage]
172 | ^^^^^^^^^^^
173...
174LL | / trait MyTrait {
175LL | | #[coverage]
176... |
177LL | | type T;
178LL | | }
179 | |_- not a function, impl block, or module
180 |
181 = help: coverage attribute can be applied to a function (with body), impl block, or module
182
183error[E0788]: coverage attribute not allowed here
184 --> $DIR/word-only.rs:39:5
185 |
186LL | #[coverage]
187 | ^^^^^^^^^^^
188...
189LL | const X: u32;
190 | ------------- not a function, impl block, or module
191 |
192 = help: coverage attribute can be applied to a function (with body), impl block, or module
193
194error[E0788]: coverage attribute not allowed here
195 --> $DIR/word-only.rs:44:5
196 |
197LL | #[coverage]
198 | ^^^^^^^^^^^
199...
200LL | type T;
201 | ------- not a function, impl block, or module
202 |
203 = help: coverage attribute can be applied to a function (with body), impl block, or module
204
205error[E0788]: coverage attribute not allowed here
206 --> $DIR/word-only.rs:29:5
207 |
208LL | #[coverage]
209 | ^^^^^^^^^^^
210...
211LL | const X: u32 = 7;
212 | ----------------- not a function, impl block, or module
213 |
214 = help: coverage attribute can be applied to a function (with body), impl block, or module
215
216error[E0788]: coverage attribute not allowed here
217 --> $DIR/word-only.rs:53:5
218 |
219LL | #[coverage]
220 | ^^^^^^^^^^^
221...
222LL | const X: u32 = 8;
223 | ----------------- not a function, impl block, or module
224 |
225 = help: coverage attribute can be applied to a function (with body), impl block, or module
226
227error[E0788]: coverage attribute not allowed here
228 --> $DIR/word-only.rs:58:5
229 |
230LL | #[coverage]
231 | ^^^^^^^^^^^
232...
233LL | type T = ();
234 | ------------ not a function, impl block, or module
235 |
236 = help: coverage attribute can be applied to a function (with body), impl block, or module
237
238error: aborting due to 19 previous errors
159error: aborting due to 12 previous errors
239160
240For more information about this error, try `rustc --explain E0788`.
161For more information about this error, try `rustc --explain E0539`.
tests/ui/linking/export-executable-symbols.rs+25-5
......@@ -1,22 +1,22 @@
11//@ run-pass
2//@ only-linux
3//@ only-gnu
4//@ compile-flags: -Zexport-executable-symbols
2//@ compile-flags: -Ctarget-feature=-crt-static -Zexport-executable-symbols
3//@ ignore-wasm
4//@ ignore-cross-compile
55//@ edition: 2024
66
77// Regression test for <https://github.com/rust-lang/rust/issues/101610>.
88
99#![feature(rustc_private)]
1010
11extern crate libc;
12
1311#[unsafe(no_mangle)]
1412fn hack() -> u64 {
1513 998244353
1614}
1715
1816fn main() {
17 #[cfg(unix)]
1918 unsafe {
19 extern crate libc;
2020 let handle = libc::dlopen(std::ptr::null(), libc::RTLD_NOW);
2121 let ptr = libc::dlsym(handle, c"hack".as_ptr());
2222 let ptr: Option<unsafe fn() -> u64> = std::mem::transmute(ptr);
......@@ -27,4 +27,24 @@ fn main() {
2727 panic!("symbol `hack` is not found");
2828 }
2929 }
30 #[cfg(windows)]
31 unsafe {
32 type PCSTR = *const u8;
33 type HMODULE = *mut core::ffi::c_void;
34 type FARPROC = Option<unsafe extern "system" fn() -> isize>;
35 #[link(name = "kernel32", kind = "raw-dylib")]
36 unsafe extern "system" {
37 fn GetModuleHandleA(lpmodulename: PCSTR) -> HMODULE;
38 fn GetProcAddress(hmodule: HMODULE, lpprocname: PCSTR) -> FARPROC;
39 }
40 let handle = GetModuleHandleA(std::ptr::null_mut());
41 let ptr = GetProcAddress(handle, b"hack\0".as_ptr());
42 let ptr: Option<unsafe fn() -> u64> = std::mem::transmute(ptr);
43 if let Some(f) = ptr {
44 assert!(f() == 998244353);
45 println!("symbol `hack` is found successfully");
46 } else {
47 panic!("symbol `hack` is not found");
48 }
49 }
3050}
tests/ui/lint/lint-double-negations-macro.rs created+16
......@@ -0,0 +1,16 @@
1//@ check-pass
2macro_rules! neg {
3 ($e: expr) => {
4 -$e
5 };
6}
7macro_rules! bad_macro {
8 ($e: expr) => {
9 --$e //~ WARN use of a double negation
10 };
11}
12
13fn main() {
14 neg!(-1);
15 bad_macro!(1);
16}
tests/ui/lint/lint-double-negations-macro.stderr created+20
......@@ -0,0 +1,20 @@
1warning: use of a double negation
2 --> $DIR/lint-double-negations-macro.rs:9:9
3 |
4LL | --$e
5 | ^^^^
6...
7LL | bad_macro!(1);
8 | ------------- in this macro invocation
9 |
10 = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
11 = note: use `-= 1` if you meant to decrement the value
12 = note: `#[warn(double_negations)]` on by default
13 = note: this warning originates in the macro `bad_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
14help: add parentheses for clarity
15 |
16LL | -(-$e)
17 | + +
18
19warning: 1 warning emitted
20
tests/ui/mir/gvn-nonsensical-coroutine-layout.rs created+19
......@@ -0,0 +1,19 @@
1//! Verify that we do not ICE when a coroutine body is malformed.
2//@ compile-flags: -Zmir-enable-passes=+GVN
3//@ edition: 2018
4
5pub enum Request {
6 TestSome(T),
7 //~^ ERROR cannot find type `T` in this scope [E0412]
8}
9
10pub async fn handle_event(event: Request) {
11 async move {
12 static instance: Request = Request { bar: 17 };
13 //~^ ERROR expected struct, variant or union type, found enum `Request` [E0574]
14 &instance
15 }
16 .await;
17}
18
19fn main() {}
tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr created+26
......@@ -0,0 +1,26 @@
1error[E0412]: cannot find type `T` in this scope
2 --> $DIR/gvn-nonsensical-coroutine-layout.rs:6:14
3 |
4LL | TestSome(T),
5 | ^ not found in this scope
6 |
7help: you might be missing a type parameter
8 |
9LL | pub enum Request<T> {
10 | +++
11
12error[E0574]: expected struct, variant or union type, found enum `Request`
13 --> $DIR/gvn-nonsensical-coroutine-layout.rs:12:36
14 |
15LL | static instance: Request = Request { bar: 17 };
16 | ^^^^^^^ not a struct, variant or union type
17 |
18help: consider importing this struct instead
19 |
20LL + use std::error::Request;
21 |
22
23error: aborting due to 2 previous errors
24
25Some errors have detailed explanations: E0412, E0574.
26For more information about an error, try `rustc --explain E0412`.
tests/ui/mir/gvn-nonsensical-sized-str.rs created+16
......@@ -0,0 +1,16 @@
1//! Verify that we do not ICE when optimizing bodies with nonsensical bounds.
2//@ compile-flags: -Copt-level=1
3//@ edition: 2021
4//@ build-pass
5
6#![feature(trivial_bounds)]
7
8async fn return_str() -> str
9where
10 str: Sized,
11 //~^ WARN trait bound str: Sized does not depend on any type or lifetime parameters
12{
13 *"Sized".to_string().into_boxed_str()
14}
15
16fn main() {}
tests/ui/mir/gvn-nonsensical-sized-str.stderr created+10
......@@ -0,0 +1,10 @@
1warning: trait bound str: Sized does not depend on any type or lifetime parameters
2 --> $DIR/gvn-nonsensical-sized-str.rs:10:10
3 |
4LL | str: Sized,
5 | ^^^^^
6 |
7 = note: `#[warn(trivial_bounds)]` on by default
8
9warning: 1 warning emitted
10