diff --git a/Cargo.lock b/Cargo.lock
index 7e4db4fdd53eb..e5b5543b367fc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -512,6 +512,28 @@ dependencies = [
"windows-targets 0.52.4",
]
+[[package]]
+name = "chrono-tz"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb"
+dependencies = [
+ "chrono",
+ "chrono-tz-build",
+ "phf 0.11.2",
+]
+
+[[package]]
+name = "chrono-tz-build"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1"
+dependencies = [
+ "parse-zoneinfo",
+ "phf 0.11.2",
+ "phf_codegen 0.11.2",
+]
+
[[package]]
name = "cipher"
version = "0.4.4"
@@ -2197,7 +2219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
dependencies = [
"cfg-if",
- "windows-targets 0.52.4",
+ "windows-targets 0.48.5",
]
[[package]]
@@ -2318,8 +2340,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016"
dependencies = [
"log",
- "phf",
- "phf_codegen",
+ "phf 0.10.1",
+ "phf_codegen 0.10.0",
"string_cache",
"string_cache_codegen",
"tendril",
@@ -2480,6 +2502,7 @@ version = "0.1.0"
dependencies = [
"aes",
"chrono",
+ "chrono-tz",
"colored",
"ctrlc",
"directories",
@@ -2835,6 +2858,15 @@ dependencies = [
"windows-targets 0.48.5",
]
+[[package]]
+name = "parse-zoneinfo"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24"
+dependencies = [
+ "regex",
+]
+
[[package]]
name = "pathdiff"
version = "0.2.1"
@@ -2907,7 +2939,16 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
dependencies = [
- "phf_shared",
+ "phf_shared 0.10.0",
+]
+
+[[package]]
+name = "phf"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
+dependencies = [
+ "phf_shared 0.11.2",
]
[[package]]
@@ -2916,8 +2957,18 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
dependencies = [
- "phf_generator",
- "phf_shared",
+ "phf_generator 0.10.0",
+ "phf_shared 0.10.0",
+]
+
+[[package]]
+name = "phf_codegen"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
+dependencies = [
+ "phf_generator 0.11.2",
+ "phf_shared 0.11.2",
]
[[package]]
@@ -2926,7 +2977,17 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
dependencies = [
- "phf_shared",
+ "phf_shared 0.10.0",
+ "rand",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
+dependencies = [
+ "phf_shared 0.11.2",
"rand",
]
@@ -2939,6 +3000,15 @@ dependencies = [
"siphasher",
]
+[[package]]
+name = "phf_shared"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
+dependencies = [
+ "siphasher",
+]
+
[[package]]
name = "pin-project-lite"
version = "0.2.14"
@@ -3354,9 +3424,9 @@ dependencies = [
[[package]]
name = "rustc-build-sysroot"
-version = "0.4.6"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9bf37423495cd3a6a9ef8c75fc4566de0d26de0ab75f36f67a426e58df5768c"
+checksum = "ab1dbbd1bdf65fdac44c885f6cca147ba179108ce284b60a08ccc04b1f1dbac0"
dependencies = [
"anyhow",
"rustc_version",
@@ -3824,7 +3894,6 @@ dependencies = [
"rustc_session",
"rustc_smir",
"rustc_span",
- "rustc_symbol_mangling",
"rustc_target",
"rustc_trait_selection",
"rustc_ty_utils",
@@ -3907,7 +3976,6 @@ dependencies = [
"rustc_session",
"rustc_span",
"smallvec",
- "termcolor",
"thin-vec",
"tracing",
]
@@ -4008,7 +4076,6 @@ dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
- "rustc_graphviz",
"rustc_hir",
"rustc_hir_analysis",
"rustc_hir_pretty",
@@ -4396,6 +4463,7 @@ dependencies = [
"rustc_macros",
"rustc_session",
"rustc_span",
+ "termcolor",
"thin-vec",
"tracing",
"unicode-normalization",
@@ -4468,7 +4536,6 @@ dependencies = [
"rustc_errors",
"rustc_fluent_macro",
"rustc_hir",
- "rustc_hir_analysis",
"rustc_macros",
"rustc_middle",
"rustc_session",
@@ -4515,7 +4582,6 @@ dependencies = [
"rustc_session",
"rustc_span",
"rustc_target",
- "rustc_type_ir",
"smallvec",
"thin-vec",
"tracing",
@@ -5289,7 +5355,7 @@ dependencies = [
"new_debug_unreachable",
"once_cell",
"parking_lot",
- "phf_shared",
+ "phf_shared 0.10.0",
"precomputed-hash",
"serde",
]
@@ -5300,8 +5366,8 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
dependencies = [
- "phf_generator",
- "phf_shared",
+ "phf_generator 0.10.0",
+ "phf_shared 0.10.0",
"proc-macro2",
"quote",
]
@@ -5601,9 +5667,9 @@ version = "0.1.0"
[[package]]
name = "time"
-version = "0.3.34"
+version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
@@ -5622,9 +5688,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
-version = "0.2.17"
+version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
+checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
diff --git a/RELEASES.md b/RELEASES.md
index 104ea497ba499..3080f03c7210b 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -102,6 +102,10 @@ Compatibility Notes
- [Change equality of higher ranked types to not rely on subtyping](https://github.com/rust-lang/rust/pull/118247)
- [When called, additionally check bounds on normalized function return type](https://github.com/rust-lang/rust/pull/118882)
- [Expand coverage for `arithmetic_overflow` lint](https://github.com/rust-lang/rust/pull/119432/)
+- [Fix detection of potential interior mutability in `const` initializers](https://github.com/rust-lang/rust/issues/121250)
+ This code was accidentally accepted. The fix can break generic code that borrows a value of unknown type,
+ as there is currently no way to declare "this type has no interior mutability". In the future, stabilizing
+ the [`Freeze` trait](https://github.com/rust-lang/rust/issues/121675) will allow proper support for such code.
diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs
index 434b978ae3151..7ba58406ef1ad 100644
--- a/compiler/rustc/src/main.rs
+++ b/compiler/rustc/src/main.rs
@@ -1,5 +1,3 @@
-#![feature(unix_sigpipe)]
-
// A note about jemalloc: rustc uses jemalloc when built for CI and
// distribution. The obvious way to do this is with the `#[global_allocator]`
// mechanism. However, for complicated reasons (see
@@ -34,7 +32,6 @@
// https://github.com/rust-lang/rust/commit/b90cfc887c31c3e7a9e6d462e2464db1fe506175#diff-43914724af6e464c1da2171e4a9b6c7e607d5bc1203fa95c0ab85be4122605ef
// for an example of how to do so.
-#[unix_sigpipe = "sig_dfl"]
fn main() {
// See the comment at the top of this file for an explanation of this.
#[cfg(feature = "jemalloc-sys")]
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 6a2943da4a3fb..5e3f64540e4aa 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -21,6 +21,8 @@ use rustc_macros::{Decodable_Generic, Encodable_Generic};
use std::iter::Step;
mod layout;
+#[cfg(test)]
+mod tests;
pub use layout::LayoutCalculator;
diff --git a/compiler/rustc_abi/src/tests.rs b/compiler/rustc_abi/src/tests.rs
new file mode 100644
index 0000000000000..d993012378c81
--- /dev/null
+++ b/compiler/rustc_abi/src/tests.rs
@@ -0,0 +1,7 @@
+use super::*;
+
+#[test]
+fn align_constants() {
+ assert_eq!(Align::ONE, Align::from_bytes(1).unwrap());
+ assert_eq!(Align::EIGHT, Align::from_bytes(8).unwrap());
+}
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 12dcbd6d17fd7..fa378e19f71ab 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1390,7 +1390,7 @@ pub struct StructExpr {
// Adding a new variant? Please update `test_expr` in `tests/ui/macros/stringify.rs`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum ExprKind {
- /// An array (`[a, b, c, d]`)
+ /// An array (e.g, `[a, b, c, d]`).
Array(ThinVec
>),
/// Allow anonymous constants from an inline `const` block
ConstBlock(AnonConst),
@@ -1401,7 +1401,7 @@ pub enum ExprKind {
/// This also represents calling the constructor of
/// tuple-like ADTs such as tuple structs and enum variants.
Call(P, ThinVec
>),
- /// A method call (e.g. `x.foo::(a, b, c)`).
+ /// A method call (e.g., `x.foo::(a, b, c)`).
MethodCall(Box),
/// A tuple (e.g., `(a, b, c, d)`).
Tup(ThinVec
>),
@@ -1413,7 +1413,10 @@ pub enum ExprKind {
Lit(token::Lit),
/// A cast (e.g., `foo as f64`).
Cast(P, P),
- /// A type ascription (e.g., `42: usize`).
+ /// A type ascription (e.g., `builtin # type_ascribe(42, usize)`).
+ ///
+ /// Usually not written directly in user code but
+ /// indirectly via the macro `type_ascribe!(...)`.
Type(P, P),
/// A `let pat = expr` expression that is only semantically allowed in the condition
/// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`).
@@ -1488,7 +1491,10 @@ pub enum ExprKind {
/// Output of the `asm!()` macro.
InlineAsm(P),
- /// Output of the `offset_of!()` macro.
+ /// An `offset_of` expression (e.g., `builtin # offset_of(Struct, field)`).
+ ///
+ /// Usually not written directly in user code but
+ /// indirectly via the macro `core::mem::offset_of!(...)`.
OffsetOf(P, P<[Ident]>),
/// A macro invocation; pre-expansion.
diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs
index cd8a5a6692000..dd231e286d591 100644
--- a/compiler/rustc_ast/src/entry.rs
+++ b/compiler/rustc_ast/src/entry.rs
@@ -4,11 +4,35 @@ use rustc_span::Symbol;
#[derive(Debug)]
pub enum EntryPointType {
+ /// This function is not an entrypoint.
None,
+ /// This is a function called `main` at the root level.
+ /// ```
+ /// fn main() {}
+ /// ```
MainNamed,
+ /// This is a function with the `#[rustc_main]` attribute.
+ /// Used by the testing harness to create the test entrypoint.
+ /// ```ignore (clashes with test entrypoint)
+ /// #[rustc_main]
+ /// fn main() {}
+ /// ```
RustcMainAttr,
+ /// This is a function with the `#[start]` attribute.
+ /// ```ignore (clashes with test entrypoint)
+ /// #[start]
+ /// fn main() {}
+ /// ```
Start,
- OtherMain, // Not an entry point, but some other function named main
+ /// This function is **not** an entrypoint but simply named `main` (not at the root).
+ /// This is only used for diagnostics.
+ /// ```
+ /// #[allow(dead_code)]
+ /// mod meow {
+ /// fn main() {}
+ /// }
+ /// ```
+ OtherMain,
}
pub fn entry_point_type(
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index be6c7da4108cb..7254be2b2f42a 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -62,7 +62,7 @@ pub(super) fn index_hir<'hir>(
if let Node::Err(span) = node.node {
let hir_id = HirId { owner: item.def_id(), local_id };
let msg = format!("ID {hir_id} not encountered when visiting item HIR");
- tcx.dcx().span_delayed_bug(*span, msg);
+ tcx.dcx().span_delayed_bug(span, msg);
}
}
@@ -376,7 +376,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
}
}
- fn visit_array_length(&mut self, len: &'hir ArrayLen) {
+ fn visit_array_length(&mut self, len: &'hir ArrayLen<'hir>) {
match len {
ArrayLen::Infer(inf) => self.insert(inf.span, inf.hir_id, Node::ArrayLenInfer(inf)),
ArrayLen::Body(..) => intravisit::walk_array_len(self, len),
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index dcd8f5d5f150c..156e369c45852 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1589,11 +1589,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
}),
)),
)),
- default: Some(hir::AnonConst {
+ default: Some(self.arena.alloc(hir::AnonConst {
def_id: anon_const,
hir_id: const_id,
body: const_body,
- }),
+ span,
+ })),
is_host_effect: true,
},
colon_span: None,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index dd8c09ce485e6..6c54363e306d0 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1178,14 +1178,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
tokens: None,
};
- let ct = self.with_new_scopes(span, |this| hir::AnonConst {
- def_id,
- hir_id: this.lower_node_id(node_id),
- body: this.lower_const_body(path_expr.span, Some(&path_expr)),
+ let ct = self.with_new_scopes(span, |this| {
+ self.arena.alloc(hir::AnonConst {
+ def_id,
+ hir_id: this.lower_node_id(node_id),
+ body: this
+ .lower_const_body(path_expr.span, Some(&path_expr)),
+ span,
+ })
});
return GenericArg::Const(ConstArg {
value: ct,
- span,
is_desugared_from_effects: false,
});
}
@@ -1197,7 +1200,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg {
value: self.lower_anon_const(ct),
- span: self.lower_span(ct.value.span),
is_desugared_from_effects: false,
}),
}
@@ -2315,7 +2317,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
- fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
+ fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> {
match c.value.kind {
ExprKind::Underscore => {
if self.tcx.features().generic_arg_infer {
@@ -2338,12 +2340,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
- fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
- self.with_new_scopes(c.value.span, |this| hir::AnonConst {
+ fn lower_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
+ self.arena.alloc(self.with_new_scopes(c.value.span, |this| hir::AnonConst {
def_id: this.local_def_id(c.id),
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
- })
+ span: this.lower_span(c.value.span),
+ }))
}
fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource {
@@ -2650,8 +2653,7 @@ impl<'hir> GenericArgsCtor<'hir> {
lcx.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
self.args.push(hir::GenericArg::Const(hir::ConstArg {
- value: hir::AnonConst { def_id, hir_id, body },
- span,
+ value: lcx.arena.alloc(hir::AnonConst { def_id, hir_id, body, span }),
is_desugared_from_effects: true,
}))
}
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index e0000e354ca5f..6622caaaab412 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -1,7 +1,7 @@
use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId};
-use rustc_ast::{token, PatKind, RangeEnd};
+use rustc_ast::{token, PatKind};
use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
use rustc_session::Session;
@@ -418,15 +418,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
PatKind::Box(..) => {
gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
}
- PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
- gate!(
- &self,
- exclusive_range_pattern,
- pattern.span,
- "exclusive range pattern syntax is experimental",
- "use an inclusive range pattern, like N..=M"
- );
- }
_ => {}
}
visit::walk_pat(self, pattern)
@@ -619,10 +610,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
// be too.
gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental");
gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
- gate_all_legacy_dont_use!(
- exclusive_range_pattern,
- "exclusive range pattern syntax is experimental"
- );
gate_all_legacy_dont_use!(try_blocks, "`try` blocks are unstable");
gate_all_legacy_dont_use!(auto_traits, "`auto` traits are unstable");
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index b5bb781acdfe0..93400c67949d9 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -422,7 +422,8 @@ impl<'a> State<'a> {
self.print_type(ty);
}
ast::ExprKind::Type(expr, ty) => {
- self.word("type_ascribe!(");
+ self.word("builtin # type_ascribe");
+ self.popen();
self.ibox(0);
self.print_expr(expr, FixupContext::default());
@@ -431,7 +432,7 @@ impl<'a> State<'a> {
self.print_type(ty);
self.end();
- self.word(")");
+ self.pclose();
}
ast::ExprKind::Let(pat, scrutinee, _, _) => {
self.print_let(pat, scrutinee, fixup);
@@ -657,15 +658,15 @@ impl<'a> State<'a> {
);
}
ast::ExprKind::InlineAsm(a) => {
- // FIXME: This should have its own syntax, distinct from a macro invocation.
+ // FIXME: Print `builtin # asm` once macro `asm` uses `builtin_syntax`.
self.word("asm!");
self.print_inline_asm(a);
}
ast::ExprKind::FormatArgs(fmt) => {
- // FIXME: This should have its own syntax, distinct from a macro invocation.
+ // FIXME: Print `builtin # format_args` once macro `format_args` uses `builtin_syntax`.
self.word("format_args!");
self.popen();
- self.rbox(0, Inconsistent);
+ self.ibox(0);
self.word(reconstruct_format_args_template_string(&fmt.template));
for arg in fmt.arguments.all_args() {
self.word_space(",");
@@ -677,7 +678,7 @@ impl<'a> State<'a> {
ast::ExprKind::OffsetOf(container, fields) => {
self.word("builtin # offset_of");
self.popen();
- self.rbox(0, Inconsistent);
+ self.ibox(0);
self.print_type(container);
self.word(",");
self.space();
@@ -690,8 +691,8 @@ impl<'a> State<'a> {
self.print_ident(field);
}
}
- self.pclose();
self.end();
+ self.pclose();
}
ast::ExprKind::MacCall(m) => self.print_mac(m),
ast::ExprKind::Paren(e) => {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index b90182c2b3e6b..61398f7d60579 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -238,6 +238,7 @@ impl<'a> State<'a> {
self.bclose(item.span, empty);
}
ast::ItemKind::GlobalAsm(asm) => {
+ // FIXME: Print `builtin # global_asm` once macro `global_asm` uses `builtin_syntax`.
self.head(visibility_qualified(&item.vis, "global_asm!"));
self.print_inline_asm(asm);
self.word(";");
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 2c717661a1c43..2450ac8f4b338 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -307,7 +307,7 @@ fn make_format_args(
return ExpandResult::Ready(Err(guar));
}
- let to_span = |inner_span: rustc_parse_format::InnerSpan| {
+ let to_span = |inner_span: parse::InnerSpan| {
is_source_literal.then(|| {
fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end })
})
@@ -577,7 +577,7 @@ fn make_format_args(
fn invalid_placeholder_type_error(
ecx: &ExtCtxt<'_>,
ty: &str,
- ty_span: Option,
+ ty_span: Option,
fmt_span: Span,
) {
let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end)));
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index a2015445b42c9..8cf431482ff73 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -266,7 +266,7 @@ fn generate_test_harness(
///
/// By default this expands to
///
-/// ```ignore UNSOLVED (I think I still need guidance for this one. Is it correct? Do we try to make it run? How do we nicely fill it out?)
+/// ```ignore (messes with test internals)
/// #[rustc_main]
/// pub fn main() {
/// extern crate test;
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 16a85b4e8fa09..4a1f5188a8013 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -6,7 +6,8 @@ use gccjit::{
use rustc_codegen_ssa::base::wants_msvc_seh;
use rustc_codegen_ssa::errors as ssa_errors;
use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, MiscMethods};
-use rustc_data_structures::base_n;
+use rustc_data_structures::base_n::ToBaseN;
+use rustc_data_structures::base_n::ALPHANUMERIC_ONLY;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_middle::mir::mono::CodegenUnit;
use rustc_middle::span_bug;
@@ -621,7 +622,7 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
let mut name = String::with_capacity(prefix.len() + 6);
name.push_str(prefix);
name.push_str(".");
- base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name);
+ name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY));
name
}
}
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 5c8f358d03a1f..1a1b4ae383133 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -17,7 +17,7 @@ use rustc_data_structures::small_c_str::SmallCStr;
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::ty::layout::{
- FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout,
+ FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_sanitizers::{cfi, kcfi};
@@ -27,7 +27,6 @@ use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target};
use smallvec::SmallVec;
use std::borrow::Cow;
-use std::ffi::CString;
use std::iter;
use std::ops::Deref;
use std::ptr;
@@ -1705,13 +1704,21 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
kcfi_bundle
}
+ /// Emits a call to `llvm.instrprof.mcdc.parameters`.
+ ///
+ /// This doesn't produce any code directly, but is used as input by
+ /// the LLVM pass that handles coverage instrumentation.
+ ///
+ /// (See clang's [`CodeGenPGO::emitMCDCParameters`] for comparison.)
+ ///
+ /// [`CodeGenPGO::emitMCDCParameters`]:
+ /// https://github.com/rust-lang/llvm-project/blob/5399a24/clang/lib/CodeGen/CodeGenPGO.cpp#L1124
pub(crate) fn mcdc_parameters(
&mut self,
fn_name: &'ll Value,
hash: &'ll Value,
bitmap_bytes: &'ll Value,
- max_decision_depth: u32,
- ) -> Vec<&'ll Value> {
+ ) {
debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bytes);
assert!(llvm_util::get_version() >= (18, 0, 0), "MCDC intrinsics require LLVM 18 or later");
@@ -1724,8 +1731,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
let args = &[fn_name, hash, bitmap_bytes];
let args = self.check_call("call", llty, llfn, args);
- let mut cond_bitmaps = vec![];
-
unsafe {
let _ = llvm::LLVMRustBuildCall(
self.llbuilder,
@@ -1736,23 +1741,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
[].as_ptr(),
0 as c_uint,
);
- // Create condition bitmap named `mcdc.addr`.
- for i in 0..=max_decision_depth {
- let mut bx = Builder::with_cx(self.cx);
- bx.position_at_start(llvm::LLVMGetFirstBasicBlock(self.llfn()));
-
- let name = CString::new(format!("mcdc.addr.{i}")).unwrap();
- let cond_bitmap = {
- let alloca =
- llvm::LLVMBuildAlloca(bx.llbuilder, bx.cx.type_i32(), name.as_ptr());
- llvm::LLVMSetAlignment(alloca, 4);
- alloca
- };
- bx.store(self.const_i32(0), cond_bitmap, self.tcx().data_layout.i32_align.abi);
- cond_bitmaps.push(cond_bitmap);
- }
}
- cond_bitmaps
}
pub(crate) fn mcdc_tvbitmap_update(
@@ -1794,8 +1783,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
0 as c_uint,
);
}
- let i32_align = self.tcx().data_layout.i32_align.abi;
- self.store(self.const_i32(0), mcdc_temp, i32_align);
+ self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi);
}
pub(crate) fn mcdc_condbitmap_update(
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index d32baa6dc02a6..653abb4e41b3d 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -11,7 +11,8 @@ use crate::value::Value;
use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
use rustc_codegen_ssa::errors as ssa_errors;
use rustc_codegen_ssa::traits::*;
-use rustc_data_structures::base_n;
+use rustc_data_structures::base_n::ToBaseN;
+use rustc_data_structures::base_n::ALPHANUMERIC_ONLY;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_hir::def_id::DefId;
@@ -1015,7 +1016,7 @@ impl CodegenCx<'_, '_> {
let mut name = String::with_capacity(prefix.len() + 6);
name.push_str(prefix);
name.push('.');
- base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name);
+ name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY));
name
}
}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 679c6e1a2ff83..c51a7744a30a3 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -13,10 +13,10 @@ use rustc_codegen_ssa::traits::{
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_llvm::RustString;
use rustc_middle::bug;
-use rustc_middle::mir::coverage::{CoverageKind, FunctionCoverageInfo};
+use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::Instance;
-use rustc_target::abi::Align;
+use rustc_target::abi::{Align, Size};
use std::cell::RefCell;
@@ -91,6 +91,42 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
}
impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
+ fn init_coverage(&mut self, instance: Instance<'tcx>) {
+ let Some(function_coverage_info) =
+ self.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
+ else {
+ return;
+ };
+
+ // If there are no MC/DC bitmaps to set up, return immediately.
+ if function_coverage_info.mcdc_bitmap_bytes == 0 {
+ return;
+ }
+
+ let fn_name = self.get_pgo_func_name_var(instance);
+ let hash = self.const_u64(function_coverage_info.function_source_hash);
+ let bitmap_bytes = self.const_u32(function_coverage_info.mcdc_bitmap_bytes);
+ self.mcdc_parameters(fn_name, hash, bitmap_bytes);
+
+ // Create pointers named `mcdc.addr.{i}` to stack-allocated condition bitmaps.
+ let mut cond_bitmaps = vec![];
+ for i in 0..function_coverage_info.mcdc_num_condition_bitmaps {
+ // MC/DC intrinsics will perform loads/stores that use the ABI default
+ // alignment for i32, so our variable declaration should match.
+ let align = self.tcx.data_layout.i32_align.abi;
+ let cond_bitmap = self.alloca(Size::from_bytes(4), align);
+ llvm::set_value_name(cond_bitmap, format!("mcdc.addr.{i}").as_bytes());
+ self.store(self.const_i32(0), cond_bitmap, align);
+ cond_bitmaps.push(cond_bitmap);
+ }
+
+ self.coverage_context()
+ .expect("always present when coverage is enabled")
+ .mcdc_condition_bitmap_map
+ .borrow_mut()
+ .insert(instance, cond_bitmaps);
+ }
+
#[instrument(level = "debug", skip(self))]
fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
// Our caller should have already taken care of inlining subtleties,
@@ -109,10 +145,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
return;
};
- if function_coverage_info.mcdc_bitmap_bytes > 0 {
- ensure_mcdc_parameters(bx, instance, function_coverage_info);
- }
-
let Some(coverage_context) = bx.coverage_context() else { return };
let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
let func_coverage = coverage_map
@@ -193,28 +225,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
}
}
-fn ensure_mcdc_parameters<'ll, 'tcx>(
- bx: &mut Builder<'_, 'll, 'tcx>,
- instance: Instance<'tcx>,
- function_coverage_info: &FunctionCoverageInfo,
-) {
- let Some(cx) = bx.coverage_context() else { return };
- if cx.mcdc_condition_bitmap_map.borrow().contains_key(&instance) {
- return;
- }
-
- let fn_name = bx.get_pgo_func_name_var(instance);
- let hash = bx.const_u64(function_coverage_info.function_source_hash);
- let bitmap_bytes = bx.const_u32(function_coverage_info.mcdc_bitmap_bytes);
- let max_decision_depth = function_coverage_info.mcdc_max_decision_depth;
- let cond_bitmap = bx.mcdc_parameters(fn_name, hash, bitmap_bytes, max_decision_depth as u32);
- bx.coverage_context()
- .expect("already checked above")
- .mcdc_condition_bitmap_map
- .borrow_mut()
- .insert(instance, cond_bitmap);
-}
-
/// Calls llvm::createPGOFuncNameVar() with the given function instance's
/// mangled function name. The LLVM API returns an llvm::GlobalVariable
/// containing the function name, with the specific variable name and linkage
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index be5458523d1ca..2f57695ac290e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -540,7 +540,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// \-------/
//
let virtual_drop = Instance {
- def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
+ def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function
args: drop_fn.args,
};
debug!("ty = {:?}", ty);
@@ -581,7 +581,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
//
// SO THEN WE CAN USE THE ABOVE CODE.
let virtual_drop = Instance {
- def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
+ def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function
args: drop_fn.args,
};
debug!("ty = {:?}", ty);
@@ -649,8 +649,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return helper.funclet_br(self, bx, target, mergeable_succ);
}
- // Pass the condition through llvm.expect for branch hinting.
- let cond = bx.expect(cond, expected);
+ // Because we're branching to a panic block (either a `#[cold]` one
+ // or an inlined abort), there's no need to `expect` it.
// Create the failure block and the conditional branch to it.
let lltarget = helper.llbb_with_cleanup(self, target);
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 0064c16f5d9f6..cf6e2e8d14c6c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -259,6 +259,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// Apply debuginfo to the newly allocated locals.
fx.debug_introduce_locals(&mut start_bx);
+ // If the backend supports coverage, and coverage is enabled for this function,
+ // do any necessary start-of-function codegen (e.g. locals for MC/DC bitmaps).
+ start_bx.init_coverage(instance);
+
// The builders will be created separately for each basic block at `codegen_block`.
// So drop the builder of `start_llbb` to avoid having two at the same time.
drop(start_bx);
diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
index d1d813bd38922..906d8b87d3bc9 100644
--- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
@@ -3,6 +3,11 @@ use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::ty::Instance;
pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
+ /// Performs any start-of-function codegen needed for coverage instrumentation.
+ ///
+ /// Can be a no-op in backends that don't support coverage instrumentation.
+ fn init_coverage(&mut self, _instance: Instance<'tcx>) {}
+
/// Handle the MIR coverage info in a backend-specific way.
///
/// This can potentially be a no-op in backends that don't support
diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
index 7b6828c6e1828..afc60d33647a7 100644
--- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
@@ -105,7 +105,7 @@ impl<'mir, 'tcx: 'mir> interpret::Machine<'mir, 'tcx> for DummyMachine {
_destination: &interpret::MPlaceTy<'tcx, Self::Provenance>,
_target: Option,
_unwind: UnwindAction,
- ) -> interpret::InterpResult<'tcx> {
+ ) -> interpret::InterpResult<'tcx, Option>> {
unimplemented!()
}
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index dd835279df331..6e6fa70107b7e 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -459,17 +459,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
dest: &MPlaceTy<'tcx, Self::Provenance>,
target: Option,
_unwind: mir::UnwindAction,
- ) -> InterpResult<'tcx> {
+ ) -> InterpResult<'tcx, Option>> {
// Shared intrinsics.
if ecx.emulate_intrinsic(instance, args, dest, target)? {
- return Ok(());
+ return Ok(None);
}
let intrinsic_name = ecx.tcx.item_name(instance.def_id());
// CTFE-specific intrinsics.
- let Some(ret) = target else {
- throw_unsup_format!("intrinsic `{intrinsic_name}` is not supported at compile-time");
- };
match intrinsic_name {
sym::ptr_guaranteed_cmp => {
let a = ecx.read_scalar(&args[0])?;
@@ -536,14 +533,22 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
// not the optimization stage.)
sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?,
_ => {
- throw_unsup_format!(
- "intrinsic `{intrinsic_name}` is not supported at compile-time"
- );
+ // We haven't handled the intrinsic, let's see if we can use a fallback body.
+ if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
+ throw_unsup_format!(
+ "intrinsic `{intrinsic_name}` is not supported at compile-time"
+ );
+ }
+ return Ok(Some(ty::Instance {
+ def: ty::InstanceDef::Item(instance.def_id()),
+ args: instance.args,
+ }));
}
}
- ecx.go_to_block(ret);
- Ok(())
+ // Intrinsic is done, jump to next block.
+ ecx.return_to_block(target)?;
+ Ok(None)
}
fn assert_panic(
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 4d37c3c22cd7c..88ce5a7cbebba 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -113,10 +113,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> InterpResult<'tcx, bool> {
let instance_args = instance.args;
let intrinsic_name = self.tcx.item_name(instance.def_id());
- let Some(ret) = ret else {
- // We don't support any intrinsic without return place.
- return Ok(false);
- };
match intrinsic_name {
sym::caller_location => {
@@ -376,7 +372,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
};
M::panic_nounwind(self, &msg)?;
- // Skip the `go_to_block` at the end.
+ // Skip the `return_to_block` at the end (we panicked, we do not return).
return Ok(true);
}
}
@@ -414,7 +410,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
self.copy_op(&self.project_index(&input, index)?, dest)?;
}
- sym::likely | sym::unlikely | sym::black_box => {
+ sym::black_box => {
// These just return their argument
self.copy_op(&args[0], dest)?;
}
@@ -437,11 +433,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
}
+ // Unsupported intrinsic: skip the return_to_block below.
_ => return Ok(false),
}
trace!("{:?}", self.dump_place(&dest.clone().into()));
- self.go_to_block(ret);
+ self.return_to_block(ret)?;
Ok(true)
}
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 8bc569bed54c5..8405d0746dfd1 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -216,6 +216,9 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
/// Directly process an intrinsic without pushing a stack frame. It is the hook's
/// responsibility to advance the instruction pointer as appropriate.
+ ///
+ /// Returns `None` if the intrinsic was fully handled.
+ /// Otherwise, returns an `Instance` of the function that implements the intrinsic.
fn call_intrinsic(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
@@ -223,7 +226,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
destination: &MPlaceTy<'tcx, Self::Provenance>,
target: Option,
unwind: mir::UnwindAction,
- ) -> InterpResult<'tcx>;
+ ) -> InterpResult<'tcx, Option>>;
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
fn assert_panic(
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 9c31532a9ce49..b474003087ba3 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -169,10 +169,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
Drop { place, target, unwind, replace: _ } => {
- let frame = self.frame();
- let ty = place.ty(&frame.body.local_decls, *self.tcx).ty;
- let ty = self.instantiate_from_frame_and_normalize_erasing_regions(frame, ty)?;
- let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
+ let place = self.eval_place(place)?;
+ let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
if let ty::InstanceDef::DropGlue(_, None) = instance.def {
// This is the branch we enter if and only if the dropped type has no drop glue
// whatsoever. This can happen as a result of monomorphizing a drop of a
@@ -181,8 +179,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.go_to_block(target);
return Ok(());
}
- let place = self.eval_place(place)?;
- trace!("TerminatorKind::drop: {:?}, type {}", place, ty);
+ trace!("TerminatorKind::drop: {:?}, type {}", place, place.layout.ty);
self.drop_in_place(&place, instance, target, unwind)?;
}
@@ -539,14 +536,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ty::InstanceDef::Intrinsic(def_id) => {
assert!(self.tcx.intrinsic(def_id).is_some());
// FIXME: Should `InPlace` arguments be reset to uninit?
- M::call_intrinsic(
+ if let Some(fallback) = M::call_intrinsic(
self,
instance,
&self.copy_fn_args(args),
destination,
target,
unwind,
- )
+ )? {
+ assert!(!self.tcx.intrinsic(fallback.def_id()).unwrap().must_be_overridden);
+ assert!(matches!(fallback.def, ty::InstanceDef::Item(_)));
+ return self.eval_fn_call(
+ FnVal::Instance(fallback),
+ (caller_abi, caller_fn_abi),
+ args,
+ with_caller_location,
+ destination,
+ target,
+ unwind,
+ );
+ } else {
+ Ok(())
+ }
}
ty::InstanceDef::VTableShim(..)
| ty::InstanceDef::ReifyShim(..)
@@ -938,6 +949,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// implementation fail -- a problem shared by rustc.
let place = self.force_allocation(place)?;
+ // We behave a bit different from codegen here.
+ // Codegen creates an `InstanceDef::Virtual` with index 0 (the slot of the drop method) and
+ // then dispatches that to the normal call machinery. However, our call machinery currently
+ // only supports calling `VtblEntry::Method`; it would choke on a `MetadataDropInPlace`. So
+ // instead we do the virtual call stuff ourselves. It's easier here than in `eval_fn_call`
+ // since we can just get a place of the underlying type and use `mplace_to_ref`.
let place = match place.layout.ty.kind() {
ty::Dynamic(data, _, ty::Dyn) => {
// Dropping a trait object. Need to find actual drop fn.
diff --git a/compiler/rustc_data_structures/src/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs
index a3eb2b9c416fc..aed89fadc4c86 100644
--- a/compiler/rustc_data_structures/src/base_n.rs
+++ b/compiler/rustc_data_structures/src/base_n.rs
@@ -1,6 +1,7 @@
/// Converts unsigned integers into a string representation with some base.
/// Bases up to and including 36 can be used for case-insensitive things.
-use std::str;
+use std::ascii;
+use std::fmt;
#[cfg(test)]
mod tests;
@@ -9,36 +10,101 @@ pub const MAX_BASE: usize = 64;
pub const ALPHANUMERIC_ONLY: usize = 62;
pub const CASE_INSENSITIVE: usize = 36;
-const BASE_64: &[u8; MAX_BASE] =
- b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$";
+const BASE_64: [ascii::Char; MAX_BASE] = {
+ let bytes = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$";
+ let Some(ascii) = bytes.as_ascii() else { panic!() };
+ *ascii
+};
-#[inline]
-pub fn push_str(mut n: u128, base: usize, output: &mut String) {
- debug_assert!(base >= 2 && base <= MAX_BASE);
- let mut s = [0u8; 128];
- let mut index = s.len();
+pub struct BaseNString {
+ start: usize,
+ buf: [ascii::Char; 128],
+}
+
+impl std::ops::Deref for BaseNString {
+ type Target = str;
- let base = base as u128;
+ fn deref(&self) -> &str {
+ self.buf[self.start..].as_str()
+ }
+}
+
+impl AsRef for BaseNString {
+ fn as_ref(&self) -> &str {
+ self.buf[self.start..].as_str()
+ }
+}
+
+impl fmt::Display for BaseNString {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self)
+ }
+}
+
+// This trait just lets us reserve the exact right amount of space when doing fixed-length
+// case-insensitve encoding. Add any impls you need.
+pub trait ToBaseN: Into {
+ fn encoded_len(base: usize) -> usize;
+
+ fn to_base_fixed_len(self, base: usize) -> BaseNString {
+ let mut encoded = self.to_base(base);
+ encoded.start = encoded.buf.len() - Self::encoded_len(base);
+ encoded
+ }
- loop {
- index -= 1;
- s[index] = BASE_64[(n % base) as usize];
- n /= base;
+ fn to_base(self, base: usize) -> BaseNString {
+ let mut output = [ascii::Char::Digit0; 128];
- if n == 0 {
- break;
+ let mut n: u128 = self.into();
+
+ let mut index = output.len();
+ loop {
+ index -= 1;
+ output[index] = BASE_64[(n % base as u128) as usize];
+ n /= base as u128;
+
+ if n == 0 {
+ break;
+ }
+ }
+ assert_eq!(n, 0);
+
+ BaseNString { start: index, buf: output }
+ }
+}
+
+impl ToBaseN for u128 {
+ fn encoded_len(base: usize) -> usize {
+ let mut max = u128::MAX;
+ let mut len = 0;
+ while max > 0 {
+ len += 1;
+ max /= base as u128;
}
+ len
}
+}
- output.push_str(unsafe {
- // SAFETY: `s` is populated using only valid utf8 characters from `BASE_64`
- str::from_utf8_unchecked(&s[index..])
- });
+impl ToBaseN for u64 {
+ fn encoded_len(base: usize) -> usize {
+ let mut max = u64::MAX;
+ let mut len = 0;
+ while max > 0 {
+ len += 1;
+ max /= base as u64;
+ }
+ len
+ }
}
-#[inline]
-pub fn encode(n: u128, base: usize) -> String {
- let mut s = String::new();
- push_str(n, base, &mut s);
- s
+impl ToBaseN for u32 {
+ fn encoded_len(base: usize) -> usize {
+ let mut max = u32::MAX;
+ let mut len = 0;
+ while max > 0 {
+ len += 1;
+ max /= base as u32;
+ }
+ len
+ }
}
diff --git a/compiler/rustc_data_structures/src/base_n/tests.rs b/compiler/rustc_data_structures/src/base_n/tests.rs
index 2be2f0532c99c..148d8dde02af1 100644
--- a/compiler/rustc_data_structures/src/base_n/tests.rs
+++ b/compiler/rustc_data_structures/src/base_n/tests.rs
@@ -1,9 +1,17 @@
use super::*;
#[test]
-fn test_encode() {
+fn limits() {
+ assert_eq!(Ok(u128::MAX), u128::from_str_radix(&u128::MAX.to_base(36), 36));
+ assert_eq!(Ok(u64::MAX), u64::from_str_radix(&u64::MAX.to_base(36), 36));
+ assert_eq!(Ok(u32::MAX), u32::from_str_radix(&u32::MAX.to_base(36), 36));
+}
+
+#[test]
+fn test_to_base() {
fn test(n: u128, base: usize) {
- assert_eq!(Ok(n), u128::from_str_radix(&encode(n, base), base as u32));
+ assert_eq!(Ok(n), u128::from_str_radix(&n.to_base(base), base as u32));
+ assert_eq!(Ok(n), u128::from_str_radix(&n.to_base_fixed_len(base), base as u32));
}
for base in 2..37 {
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index cf54e700e2b98..8dd85b25e0e21 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -16,6 +16,8 @@
#![doc(rust_logo)]
#![feature(allocator_api)]
#![feature(array_windows)]
+#![feature(ascii_char)]
+#![feature(ascii_char_variants)]
#![feature(auto_traits)]
#![feature(cfg_match)]
#![feature(core_intrinsics)]
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index a8bba3afb7e70..5f7504add8d6a 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -42,15 +42,14 @@ rustc_privacy = { path = "../rustc_privacy" }
rustc_query_system = { path = "../rustc_query_system" }
rustc_resolve = { path = "../rustc_resolve" }
rustc_session = { path = "../rustc_session" }
-rustc_smir ={ path = "../rustc_smir" }
+rustc_smir = { path = "../rustc_smir" }
rustc_span = { path = "../rustc_span" }
-rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
serde_json = "1.0.59"
shlex = "1.0"
-time = { version = "0.3", default-features = false, features = ["alloc", "formatting", "parsing", "macros"] }
+time = { version = "0.3.36", default-features = false, features = ["alloc", "formatting", "parsing", "macros"] }
tracing = { version = "0.1.35" }
# tidy-alphabetical-end
diff --git a/compiler/rustc_error_codes/src/error_codes/E0579.md b/compiler/rustc_error_codes/src/error_codes/E0579.md
index e7e6fb682566e..decf810b8c618 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0579.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0579.md
@@ -3,7 +3,6 @@ A lower range wasn't less than the upper range.
Erroneous code example:
```compile_fail,E0579
-#![feature(exclusive_range_pattern)]
fn main() {
match 5u32 {
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index b3a1e29f8e2cb..4696917554ffb 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -13,7 +13,7 @@ use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
use rustc_span::Span;
use rustc_target::abi::TargetDataLayoutErrors;
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
-use rustc_type_ir as type_ir;
+use rustc_type_ir::{ClosureKind, FloatTy};
use std::backtrace::Backtrace;
use std::borrow::Cow;
use std::fmt;
@@ -196,7 +196,7 @@ impl IntoDiagArg for ast::token::TokenKind {
}
}
-impl IntoDiagArg for type_ir::FloatTy {
+impl IntoDiagArg for FloatTy {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::Borrowed(self.name_str()))
}
@@ -252,7 +252,7 @@ impl IntoDiagArg for Level {
}
}
-impl IntoDiagArg for type_ir::ClosureKind {
+impl IntoDiagArg for ClosureKind {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(self.as_str().into())
}
diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml
index 63247f9d0519c..ce014364b0d01 100644
--- a/compiler/rustc_expand/Cargo.toml
+++ b/compiler/rustc_expand/Cargo.toml
@@ -25,7 +25,6 @@ rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-termcolor = "1.2"
thin-vec = "0.2.12"
tracing = "0.1"
# tidy-alphabetical-end
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 6fe74edbd70a8..12868a666056d 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -21,7 +21,7 @@ use rustc_session::config::CollapseMacroDebuginfo;
use rustc_session::{parse::ParseSess, Limit, Session};
use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
use rustc_span::edition::Edition;
-use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
+use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind};
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{FileName, Span, DUMMY_SP};
@@ -32,8 +32,6 @@ use std::path::{Path, PathBuf};
use std::rc::Rc;
use thin_vec::ThinVec;
-pub(crate) use rustc_span::hygiene::MacroKind;
-
// When adding new variants, make sure to
// adjust the `visit_*` / `flat_map_*` calls in `InvocationCollector`
// to use `assign_id!`
@@ -573,35 +571,6 @@ impl DummyResult {
tokens: None,
})
}
-
- /// A plain dummy pattern.
- pub fn raw_pat(sp: Span) -> ast::Pat {
- ast::Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Wild, span: sp, tokens: None }
- }
-
- /// A plain dummy type.
- pub fn raw_ty(sp: Span) -> P {
- // FIXME(nnethercote): you might expect `ast::TyKind::Dummy` to be used here, but some
- // values produced here end up being lowered to HIR, which `ast::TyKind::Dummy` does not
- // support, so we use an empty tuple instead.
- P(ast::Ty {
- id: ast::DUMMY_NODE_ID,
- kind: ast::TyKind::Tup(ThinVec::new()),
- span: sp,
- tokens: None,
- })
- }
-
- /// A plain dummy crate.
- pub fn raw_crate() -> ast::Crate {
- ast::Crate {
- attrs: Default::default(),
- items: Default::default(),
- spans: Default::default(),
- id: ast::DUMMY_NODE_ID,
- is_placeholder: Default::default(),
- }
- }
}
impl MacResult for DummyResult {
@@ -610,7 +579,12 @@ impl MacResult for DummyResult {
}
fn make_pat(self: Box) -> Option
> {
- Some(DummyResult::raw_ty(self.span))
+ // FIXME(nnethercote): you might expect `ast::TyKind::Dummy` to be used here, but some
+ // values produced here end up being lowered to HIR, which `ast::TyKind::Dummy` does not
+ // support, so we use an empty tuple instead.
+ Some(P(ast::Ty {
+ id: ast::DUMMY_NODE_ID,
+ kind: ast::TyKind::Tup(ThinVec::new()),
+ span: self.span,
+ tokens: None,
+ }))
}
fn make_arms(self: Box) -> Option> {
@@ -670,7 +652,13 @@ impl MacResult for DummyResult {
}
fn make_crate(self: Box) -> Option {
- Some(DummyResult::raw_crate())
+ Some(ast::Crate {
+ attrs: Default::default(),
+ items: Default::default(),
+ spans: Default::default(),
+ id: ast::DUMMY_NODE_ID,
+ is_placeholder: Default::default(),
+ })
}
}
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 83f120525bc5f..1b6e191c2eb09 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -175,20 +175,6 @@ impl<'a> ExtCtxt<'a> {
ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) }
}
- pub fn stmt_let_pat(&self, sp: Span, pat: P, ex: P) -> ast::Stmt {
- let local = P(ast::Local {
- pat,
- ty: None,
- id: ast::DUMMY_NODE_ID,
- kind: LocalKind::Init(ex),
- span: sp,
- colon_sp: None,
- attrs: AttrVec::new(),
- tokens: None,
- });
- self.stmt_local(local, sp)
- }
-
pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P) -> ast::Stmt {
self.stmt_let_ty(sp, mutbl, ident, None, ex)
}
@@ -278,10 +264,6 @@ impl<'a> ExtCtxt<'a> {
self.expr_ident(span, Ident::with_dummy_span(kw::SelfLower))
}
- pub fn expr_field(&self, span: Span, expr: P, field: Ident) -> P {
- self.expr(span, ast::ExprKind::Field(expr, field))
- }
-
pub fn expr_macro_call(&self, span: Span, call: P) -> P {
self.expr(span, ast::ExprKind::MacCall(call))
}
@@ -394,11 +376,6 @@ impl<'a> ExtCtxt<'a> {
self.expr(span, ast::ExprKind::Lit(lit))
}
- pub fn expr_char(&self, span: Span, ch: char) -> P {
- let lit = token::Lit::new(token::Char, literal::escape_char_symbol(ch), None);
- self.expr(span, ast::ExprKind::Lit(lit))
- }
-
pub fn expr_byte_str(&self, span: Span, bytes: Vec) -> P {
let lit = token::Lit::new(token::ByteStr, literal::escape_byte_str_symbol(&bytes), None);
self.expr(span, ast::ExprKind::Lit(lit))
@@ -414,10 +391,6 @@ impl<'a> ExtCtxt<'a> {
self.expr_addr_of(sp, self.expr_array(sp, exprs))
}
- pub fn expr_cast(&self, sp: Span, expr: P, ty: P) -> P {
- self.expr(sp, ast::ExprKind::Cast(expr, ty))
- }
-
pub fn expr_some(&self, sp: Span, expr: P) -> P {
let some = self.std_path(&[sym::option, sym::Option, sym::Some]);
self.expr_call_global(sp, some, thin_vec![expr])
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index b554a5ccd1961..897420a11cdfb 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -99,10 +99,11 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
// If the declared feature is unstable, record it.
if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) {
(f.set_enabled)(&mut features);
- // When the ICE comes from core, alloc or std (approximation of the standard library), there's a chance
- // that the person hitting the ICE may be using -Zbuild-std or similar with an untested target.
- // The bug is probably in the standard library and not the compiler in that case, but that doesn't
- // really matter - we want a bug report.
+ // When the ICE comes from core, alloc or std (approximation of the standard
+ // library), there's a chance that the person hitting the ICE may be using
+ // -Zbuild-std or similar with an untested target. The bug is probably in the
+ // standard library and not the compiler in that case, but that doesn't really
+ // matter - we want a bug report.
if features.internal(name)
&& ![sym::core, sym::alloc, sym::std].contains(&crate_name)
{
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 503c9170cab53..f61cebc02562a 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -4,7 +4,6 @@ use crate::errors::{
IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported,
UnsupportedKeyValue, WrongFragmentKind,
};
-use crate::hygiene::SyntaxContext;
use crate::mbe::diagnostics::annotate_err_with_kind;
use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
use crate::placeholders::{placeholder, PlaceholderExpander};
@@ -32,6 +31,7 @@ use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::parse::feature_err;
use rustc_session::{Limit, Session};
+use rustc_span::hygiene::SyntaxContext;
use rustc_span::symbol::{sym, Ident};
use rustc_span::{ErrorGuaranteed, FileName, LocalExpnId, Span};
@@ -87,7 +87,7 @@ macro_rules! ast_fragments {
}
impl AstFragment {
- pub fn add_placeholders(&mut self, placeholders: &[NodeId]) {
+ fn add_placeholders(&mut self, placeholders: &[NodeId]) {
if placeholders.is_empty() {
return;
}
@@ -100,14 +100,14 @@ macro_rules! ast_fragments {
}
}
- pub fn make_opt_expr(self) -> Option
> {
+ pub(crate) fn make_opt_expr(self) -> Option
> {
match self {
AstFragment::OptExpr(expr) => expr,
_ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
}
}
- pub fn make_method_receiver_expr(self) -> P {
+ pub(crate) fn make_method_receiver_expr(self) -> P {
match self {
AstFragment::MethodReceiverExpr(expr) => expr,
_ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
@@ -125,7 +125,7 @@ macro_rules! ast_fragments {
T::fragment_to_output(self)
}
- pub fn mut_visit_with(&mut self, vis: &mut F) {
+ pub(crate) fn mut_visit_with(&mut self, vis: &mut F) {
match self {
AstFragment::OptExpr(opt_expr) => {
visit_clobber(opt_expr, |opt_expr| {
@@ -372,6 +372,14 @@ impl Invocation {
InvocationKind::Derive { path, .. } => path.span,
}
}
+
+ fn span_mut(&mut self) -> &mut Span {
+ match &mut self.kind {
+ InvocationKind::Bang { span, .. } => span,
+ InvocationKind::Attr { attr, .. } => &mut attr.span,
+ InvocationKind::Derive { path, .. } => &mut path.span,
+ }
+ }
}
pub struct MacroExpander<'a, 'b> {
@@ -432,7 +440,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
break;
}
invocations = mem::take(&mut undetermined_invocations);
- force = !mem::replace(&mut progress, false);
+ force = !progress;
+ progress = false;
if force && self.monotonic {
self.cx.dcx().span_delayed_bug(
invocations.last().unwrap().0.span(),
@@ -471,7 +480,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
self.cx.force_mode = force;
let fragment_kind = invoc.fragment_kind;
- let (expanded_fragment, new_invocations) = match self.expand_invoc(invoc, &ext.kind) {
+ match self.expand_invoc(invoc, &ext.kind) {
ExpandResult::Ready(fragment) => {
let mut derive_invocations = Vec::new();
let derive_placeholders = self
@@ -503,12 +512,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
})
.unwrap_or_default();
- let (fragment, collected_invocations) =
+ let (expanded_fragment, collected_invocations) =
self.collect_invocations(fragment, &derive_placeholders);
- // We choose to expand any derive invocations associated with this macro invocation
- // *before* any macro invocations collected from the output fragment
+ // We choose to expand any derive invocations associated with this macro
+ // invocation *before* any macro invocations collected from the output
+ // fragment.
derive_invocations.extend(collected_invocations);
- (fragment, derive_invocations)
+
+ progress = true;
+ if expanded_fragments.len() < depth {
+ expanded_fragments.push(Vec::new());
+ }
+ expanded_fragments[depth - 1].push((expn_id, expanded_fragment));
+ invocations.extend(derive_invocations.into_iter().rev());
}
ExpandResult::Retry(invoc) => {
if force {
@@ -519,17 +535,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
} else {
// Cannot expand, will retry this invocation later.
undetermined_invocations.push((invoc, Some(ext)));
- continue;
}
}
- };
-
- progress = true;
- if expanded_fragments.len() < depth {
- expanded_fragments.push(Vec::new());
}
- expanded_fragments[depth - 1].push((expn_id, expanded_fragment));
- invocations.extend(new_invocations.into_iter().rev());
}
self.cx.current_expansion = orig_expansion_data;
@@ -590,11 +598,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
for (invoc, _) in invocations.iter_mut() {
let expn_id = invoc.expansion_data.id;
let parent_def = self.cx.resolver.invocation_parent(expn_id);
- let span = match &mut invoc.kind {
- InvocationKind::Bang { span, .. } => span,
- InvocationKind::Attr { attr, .. } => &mut attr.span,
- InvocationKind::Derive { path, .. } => &mut path.span,
- };
+ let span = invoc.span_mut();
*span = span.with_parent(Some(parent_def));
}
}
@@ -957,7 +961,7 @@ pub fn parse_ast_fragment<'a>(
})
}
-pub fn ensure_complete_parse<'a>(
+pub(crate) fn ensure_complete_parse<'a>(
parser: &Parser<'a>,
macro_path: &ast::Path,
kind_name: &str,
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 3c9d2e8706835..4222c9fe90616 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,61 +1,37 @@
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::diagnostic_outside_of_impl)]
#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
#![feature(array_windows)]
#![feature(associated_type_defaults)]
#![feature(if_let_guard)]
#![feature(let_chains)]
-#![feature(lint_reasons)]
#![feature(macro_metavar_expr)]
#![feature(map_try_insert)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
-#![feature(proc_macro_span)]
+#![feature(rustdoc_internals)]
#![feature(try_blocks)]
#![feature(yeet_expr)]
-#![allow(rustc::diagnostic_outside_of_impl)]
-#![allow(internal_features)]
+// tidy-alphabetical-end
extern crate proc_macro as pm;
+mod build;
+mod errors;
+// FIXME(Nilstrieb) Translate macro_rules diagnostics
+#[allow(rustc::untranslatable_diagnostic)]
+mod mbe;
mod placeholders;
mod proc_macro_server;
pub use mbe::macro_rules::compile_declarative_macro;
-pub(crate) use rustc_span::hygiene;
pub mod base;
-pub mod build;
-#[macro_use]
pub mod config;
-pub mod errors;
pub mod expand;
pub mod module;
-
// FIXME(Nilstrieb) Translate proc_macro diagnostics
#[allow(rustc::untranslatable_diagnostic)]
pub mod proc_macro;
-// FIXME(Nilstrieb) Translate macro_rules diagnostics
-#[allow(rustc::untranslatable_diagnostic)]
-pub(crate) mod mbe;
-
-// HACK(Centril, #64197): These shouldn't really be here.
-// Rather, they should be with their respective modules which are defined in other crates.
-// However, since for now constructing a `ParseSess` sorta requires `config` from this crate,
-// these tests will need to live here in the interim.
-
-#[cfg(test)]
-mod tests;
-#[cfg(test)]
-mod parse {
- mod tests;
-}
-#[cfg(test)]
-mod tokenstream {
- mod tests;
-}
-#[cfg(test)]
-mod mut_visit {
- mod tests;
-}
-
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs
index bd6a9b7cb07da..a805c4fcf7b97 100644
--- a/compiler/rustc_expand/src/mbe.rs
+++ b/compiler/rustc_expand/src/mbe.rs
@@ -4,12 +4,13 @@
//! official terminology: "declarative macros".
pub(crate) mod diagnostics;
-pub(crate) mod macro_check;
-pub(crate) mod macro_parser;
pub(crate) mod macro_rules;
-pub(crate) mod metavar_expr;
-pub(crate) mod quoted;
-pub(crate) mod transcribe;
+
+mod macro_check;
+mod macro_parser;
+mod metavar_expr;
+mod quoted;
+mod transcribe;
use metavar_expr::MetaVarExpr;
use rustc_ast::token::{Delimiter, NonterminalKind, Token, TokenKind};
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 5d6c3e8aa3a4a..464361cb4020b 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -28,7 +28,8 @@ pub(super) fn failed_to_match_macro<'cx>(
) -> Box {
let psess = &cx.sess.psess;
- // An error occurred, try the expansion again, tracking the expansion closely for better diagnostics.
+ // An error occurred, try the expansion again, tracking the expansion closely for better
+ // diagnostics.
let mut tracker = CollectTrackerAndEmitter::new(cx, sp);
let try_success_result = try_match_macro(psess, name, &arg, lhses, &mut tracker);
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index df2643ad1ddea..470bde232d723 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -157,8 +157,8 @@ pub(super) trait Tracker<'matcher> {
/// This is called before trying to match next MatcherLoc on the current token.
fn before_match_loc(&mut self, _parser: &TtParser, _matcher: &'matcher MatcherLoc) {}
- /// This is called after an arm has been parsed, either successfully or unsuccessfully. When this is called,
- /// `before_match_loc` was called at least once (with a `MatcherLoc::Eof`).
+ /// This is called after an arm has been parsed, either successfully or unsuccessfully. When
+ /// this is called, `before_match_loc` was called at least once (with a `MatcherLoc::Eof`).
fn after_arm(&mut self, _result: &NamedParseResult) {}
/// For tracing.
@@ -169,7 +169,8 @@ pub(super) trait Tracker<'matcher> {
}
}
-/// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to monomorphization.
+/// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to
+/// monomorphization.
pub(super) struct NoopTracker;
impl<'matcher> Tracker<'matcher> for NoopTracker {
@@ -492,7 +493,7 @@ pub fn compile_declarative_macro(
.pop()
.unwrap();
// We don't handle errors here, the driver will abort
- // after parsing/expansion. we can report every error in every macro this way.
+ // after parsing/expansion. We can report every error in every macro this way.
check_emission(check_lhs_nt_follows(sess, def, &tt));
return tt;
}
@@ -528,7 +529,7 @@ pub fn compile_declarative_macro(
check_emission(check_rhs(sess, rhs));
}
- // don't abort iteration early, so that errors for multiple lhses can be reported
+ // Don't abort iteration early, so that errors for multiple lhses can be reported.
for lhs in &lhses {
check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(lhs)));
}
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index dad83984c8b15..011aa95c8a116 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -39,26 +39,32 @@ impl MutVisitor for Marker {
}
/// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
-enum Frame<'a> {
- Delimited {
- tts: &'a [mbe::TokenTree],
- idx: usize,
- delim: Delimiter,
- span: DelimSpan,
- spacing: DelimSpacing,
- },
- Sequence {
- tts: &'a [mbe::TokenTree],
- idx: usize,
- sep: Option,
- kleene_op: KleeneOp,
- },
+struct Frame<'a> {
+ tts: &'a [mbe::TokenTree],
+ idx: usize,
+ kind: FrameKind,
+}
+
+enum FrameKind {
+ Delimited { delim: Delimiter, span: DelimSpan, spacing: DelimSpacing },
+ Sequence { sep: Option, kleene_op: KleeneOp },
}
impl<'a> Frame<'a> {
- /// Construct a new frame around the delimited set of tokens.
- fn new(src: &'a mbe::Delimited, span: DelimSpan, spacing: DelimSpacing) -> Frame<'a> {
- Frame::Delimited { tts: &src.tts, idx: 0, delim: src.delim, span, spacing }
+ fn new_delimited(src: &'a mbe::Delimited, span: DelimSpan, spacing: DelimSpacing) -> Frame<'a> {
+ Frame {
+ tts: &src.tts,
+ idx: 0,
+ kind: FrameKind::Delimited { delim: src.delim, span, spacing },
+ }
+ }
+
+ fn new_sequence(
+ src: &'a mbe::SequenceRepetition,
+ sep: Option,
+ kleene_op: KleeneOp,
+ ) -> Frame<'a> {
+ Frame { tts: &src.tts, idx: 0, kind: FrameKind::Sequence { sep, kleene_op } }
}
}
@@ -66,13 +72,9 @@ impl<'a> Iterator for Frame<'a> {
type Item = &'a mbe::TokenTree;
fn next(&mut self) -> Option<&'a mbe::TokenTree> {
- match self {
- Frame::Delimited { tts, idx, .. } | Frame::Sequence { tts, idx, .. } => {
- let res = tts.get(*idx);
- *idx += 1;
- res
- }
- }
+ let res = self.tts.get(self.idx);
+ self.idx += 1;
+ res
}
}
@@ -111,13 +113,16 @@ pub(super) fn transcribe<'a>(
// We descend into the RHS (`src`), expanding things as we go. This stack contains the things
// we have yet to expand/are still expanding. We start the stack off with the whole RHS. The
// choice of spacing values doesn't matter.
- let mut stack: SmallVec<[Frame<'_>; 1]> =
- smallvec![Frame::new(src, src_span, DelimSpacing::new(Spacing::Alone, Spacing::Alone))];
+ let mut stack: SmallVec<[Frame<'_>; 1]> = smallvec![Frame::new_delimited(
+ src,
+ src_span,
+ DelimSpacing::new(Spacing::Alone, Spacing::Alone)
+ )];
// As we descend in the RHS, we will need to be able to match nested sequences of matchers.
// `repeats` keeps track of where we are in matching at each level, with the last element being
// the most deeply nested sequence. This is used as a stack.
- let mut repeats = Vec::new();
+ let mut repeats: Vec<(usize, usize)> = Vec::new();
// `result` contains resulting token stream from the TokenTree we just finished processing. At
// the end, this will contain the full result of transcription, but at arbitrary points during
@@ -142,11 +147,12 @@ pub(super) fn transcribe<'a>(
// Otherwise, if we have just reached the end of a sequence and we can keep repeating,
// go back to the beginning of the sequence.
- if let Frame::Sequence { idx, sep, .. } = stack.last_mut().unwrap() {
+ let frame = stack.last_mut().unwrap();
+ if let FrameKind::Sequence { sep, .. } = &frame.kind {
let (repeat_idx, repeat_len) = repeats.last_mut().unwrap();
*repeat_idx += 1;
if repeat_idx < repeat_len {
- *idx = 0;
+ frame.idx = 0;
if let Some(sep) = sep {
result.push(TokenTree::Token(sep.clone(), Spacing::Alone));
}
@@ -157,16 +163,16 @@ pub(super) fn transcribe<'a>(
// We are done with the top of the stack. Pop it. Depending on what it was, we do
// different things. Note that the outermost item must be the delimited, wrapped RHS
// that was passed in originally to `transcribe`.
- match stack.pop().unwrap() {
+ match stack.pop().unwrap().kind {
// Done with a sequence. Pop from repeats.
- Frame::Sequence { .. } => {
+ FrameKind::Sequence { .. } => {
repeats.pop();
}
// We are done processing a Delimited. If this is the top-level delimited, we are
// done. Otherwise, we unwind the result_stack to append what we have produced to
// any previous results.
- Frame::Delimited { delim, span, mut spacing, .. } => {
+ FrameKind::Delimited { delim, span, mut spacing, .. } => {
// Hack to force-insert a space after `]` in certain case.
// See discussion of the `hex-literal` crate in #114571.
if delim == Delimiter::Bracket {
@@ -192,7 +198,7 @@ pub(super) fn transcribe<'a>(
// We are descending into a sequence. We first make sure that the matchers in the RHS
// and the matches in `interp` have the same shape. Otherwise, either the caller or the
// macro writer has made a mistake.
- seq @ mbe::TokenTree::Sequence(_, delimited) => {
+ seq @ mbe::TokenTree::Sequence(_, seq_rep) => {
match lockstep_iter_size(seq, interp, &repeats) {
LockstepIterSize::Unconstrained => {
return Err(cx
@@ -233,12 +239,11 @@ pub(super) fn transcribe<'a>(
// The first time we encounter the sequence we push it to the stack. It
// then gets reused (see the beginning of the loop) until we are done
// repeating.
- stack.push(Frame::Sequence {
- idx: 0,
- sep: seq.separator.clone(),
- tts: &delimited.tts,
- kleene_op: seq.kleene.op,
- });
+ stack.push(Frame::new_sequence(
+ seq_rep,
+ seq.separator.clone(),
+ seq.kleene.op,
+ ));
}
}
}
@@ -294,13 +299,7 @@ pub(super) fn transcribe<'a>(
// the previous results (from outside the Delimited).
mbe::TokenTree::Delimited(mut span, spacing, delimited) => {
mut_visit::visit_delim_span(&mut span, &mut marker);
- stack.push(Frame::Delimited {
- tts: &delimited.tts,
- delim: delimited.delim,
- idx: 0,
- span,
- spacing: *spacing,
- });
+ stack.push(Frame::new_delimited(delimited, span, *spacing));
result_stack.push(mem::take(&mut result));
}
@@ -358,10 +357,13 @@ fn maybe_use_metavar_location(
) -> TokenTree {
let undelimited_seq = matches!(
stack.last(),
- Some(Frame::Sequence {
+ Some(Frame {
tts: [_],
- sep: None,
- kleene_op: KleeneOp::ZeroOrMore | KleeneOp::OneOrMore,
+ kind: FrameKind::Sequence {
+ sep: None,
+ kleene_op: KleeneOp::ZeroOrMore | KleeneOp::OneOrMore,
+ ..
+ },
..
})
);
diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs
deleted file mode 100644
index 066afd7a41d28..0000000000000
--- a/compiler/rustc_expand/src/parse/tests.rs
+++ /dev/null
@@ -1,382 +0,0 @@
-use crate::tests::{
- matches_codepattern, psess, string_to_stream, with_error_checking_parse,
- with_expected_parse_error,
-};
-
-use ast::token::IdentIsRaw;
-use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Token};
-use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
-use rustc_ast::visit;
-use rustc_ast::{self as ast, PatKind};
-use rustc_ast_pretty::pprust::item_to_string;
-use rustc_errors::PResult;
-use rustc_parse::new_parser_from_source_str;
-use rustc_parse::parser::ForceCollect;
-use rustc_session::parse::ParseSess;
-use rustc_span::create_default_session_globals_then;
-use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::{BytePos, FileName, Pos, Span};
-use std::path::PathBuf;
-
-/// Parses an item.
-///
-/// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and `Err`
-/// when a syntax error occurred.
-fn parse_item_from_source_str(
- name: FileName,
- source: String,
- psess: &ParseSess,
-) -> PResult<'_, Option
>> {
- new_parser_from_source_str(psess, name, source).parse_item(ForceCollect::No)
-}
-
-// Produces a `rustc_span::span`.
-fn sp(a: u32, b: u32) -> Span {
- Span::with_root_ctxt(BytePos(a), BytePos(b))
-}
-
-/// Parses a string, return an expression.
-fn string_to_expr(source_str: String) -> P {
- with_error_checking_parse(source_str, &psess(), |p| p.parse_expr())
-}
-
-/// Parses a string, returns an item.
-fn string_to_item(source_str: String) -> Option
> {
- with_error_checking_parse(source_str, &psess(), |p| p.parse_item(ForceCollect::No))
-}
-
-#[test]
-fn bad_path_expr_1() {
- // This should trigger error: expected identifier, found keyword `return`
- create_default_session_globals_then(|| {
- with_expected_parse_error(
- "::abc::def::return",
- "expected identifier, found keyword `return`",
- |p| p.parse_expr(),
- );
- })
-}
-
-// Checks the token-tree-ization of macros.
-#[test]
-fn string_to_tts_macro() {
- create_default_session_globals_then(|| {
- let stream = string_to_stream("macro_rules! zip (($a)=>($a))".to_string());
- let tts = &stream.trees().collect::>()[..];
-
- match tts {
- [
- TokenTree::Token(
- Token { kind: token::Ident(name_macro_rules, IdentIsRaw::No), .. },
- _,
- ),
- TokenTree::Token(Token { kind: token::Not, .. }, _),
- TokenTree::Token(Token { kind: token::Ident(name_zip, IdentIsRaw::No), .. }, _),
- TokenTree::Delimited(.., macro_delim, macro_tts),
- ] if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" => {
- let tts = ¯o_tts.trees().collect::>();
- match &tts[..] {
- [
- TokenTree::Delimited(.., first_delim, first_tts),
- TokenTree::Token(Token { kind: token::FatArrow, .. }, _),
- TokenTree::Delimited(.., second_delim, second_tts),
- ] if macro_delim == &Delimiter::Parenthesis => {
- let tts = &first_tts.trees().collect::>();
- match &tts[..] {
- [
- TokenTree::Token(Token { kind: token::Dollar, .. }, _),
- TokenTree::Token(
- Token { kind: token::Ident(name, IdentIsRaw::No), .. },
- _,
- ),
- ] if first_delim == &Delimiter::Parenthesis && name.as_str() == "a" => {
- }
- _ => panic!("value 3: {:?} {:?}", first_delim, first_tts),
- }
- let tts = &second_tts.trees().collect::>();
- match &tts[..] {
- [
- TokenTree::Token(Token { kind: token::Dollar, .. }, _),
- TokenTree::Token(
- Token { kind: token::Ident(name, IdentIsRaw::No), .. },
- _,
- ),
- ] if second_delim == &Delimiter::Parenthesis
- && name.as_str() == "a" => {}
- _ => panic!("value 4: {:?} {:?}", second_delim, second_tts),
- }
- }
- _ => panic!("value 2: {:?} {:?}", macro_delim, macro_tts),
- }
- }
- _ => panic!("value: {:?}", tts),
- }
- })
-}
-
-#[test]
-fn string_to_tts_1() {
- create_default_session_globals_then(|| {
- let tts = string_to_stream("fn a(b: i32) { b; }".to_string());
-
- let expected = TokenStream::new(vec![
- TokenTree::token_alone(token::Ident(kw::Fn, IdentIsRaw::No), sp(0, 2)),
- TokenTree::token_joint_hidden(
- token::Ident(Symbol::intern("a"), IdentIsRaw::No),
- sp(3, 4),
- ),
- TokenTree::Delimited(
- DelimSpan::from_pair(sp(4, 5), sp(11, 12)),
- // `JointHidden` because the `(` is followed immediately by
- // `b`, `Alone` because the `)` is followed by whitespace.
- DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
- Delimiter::Parenthesis,
- TokenStream::new(vec![
- TokenTree::token_joint(
- token::Ident(Symbol::intern("b"), IdentIsRaw::No),
- sp(5, 6),
- ),
- TokenTree::token_alone(token::Colon, sp(6, 7)),
- // `JointHidden` because the `i32` is immediately followed by the `)`.
- TokenTree::token_joint_hidden(
- token::Ident(sym::i32, IdentIsRaw::No),
- sp(8, 11),
- ),
- ])
- .into(),
- ),
- TokenTree::Delimited(
- DelimSpan::from_pair(sp(13, 14), sp(18, 19)),
- // First `Alone` because the `{` is followed by whitespace,
- // second `Alone` because the `}` is followed immediately by
- // EOF.
- DelimSpacing::new(Spacing::Alone, Spacing::Alone),
- Delimiter::Brace,
- TokenStream::new(vec![
- TokenTree::token_joint(
- token::Ident(Symbol::intern("b"), IdentIsRaw::No),
- sp(15, 16),
- ),
- // `Alone` because the `;` is followed by whitespace.
- TokenTree::token_alone(token::Semi, sp(16, 17)),
- ])
- .into(),
- ),
- ]);
-
- assert_eq!(tts, expected);
- })
-}
-
-#[test]
-fn parse_use() {
- create_default_session_globals_then(|| {
- let use_s = "use foo::bar::baz;";
- let vitem = string_to_item(use_s.to_string()).unwrap();
- let vitem_s = item_to_string(&vitem);
- assert_eq!(&vitem_s[..], use_s);
-
- let use_s = "use foo::bar as baz;";
- let vitem = string_to_item(use_s.to_string()).unwrap();
- let vitem_s = item_to_string(&vitem);
- assert_eq!(&vitem_s[..], use_s);
- })
-}
-
-#[test]
-fn parse_extern_crate() {
- create_default_session_globals_then(|| {
- let ex_s = "extern crate foo;";
- let vitem = string_to_item(ex_s.to_string()).unwrap();
- let vitem_s = item_to_string(&vitem);
- assert_eq!(&vitem_s[..], ex_s);
-
- let ex_s = "extern crate foo as bar;";
- let vitem = string_to_item(ex_s.to_string()).unwrap();
- let vitem_s = item_to_string(&vitem);
- assert_eq!(&vitem_s[..], ex_s);
- })
-}
-
-fn get_spans_of_pat_idents(src: &str) -> Vec {
- let item = string_to_item(src.to_string()).unwrap();
-
- struct PatIdentVisitor {
- spans: Vec,
- }
- impl<'a> visit::Visitor<'a> for PatIdentVisitor {
- fn visit_pat(&mut self, p: &'a ast::Pat) {
- match &p.kind {
- PatKind::Ident(_, ident, _) => {
- self.spans.push(ident.span);
- }
- _ => {
- visit::walk_pat(self, p);
- }
- }
- }
- }
- let mut v = PatIdentVisitor { spans: Vec::new() };
- visit::walk_item(&mut v, &item);
- return v.spans;
-}
-
-#[test]
-fn span_of_self_arg_pat_idents_are_correct() {
- create_default_session_globals_then(|| {
- let srcs = [
- "impl z { fn a (&self, &myarg: i32) {} }",
- "impl z { fn a (&mut self, &myarg: i32) {} }",
- "impl z { fn a (&'a self, &myarg: i32) {} }",
- "impl z { fn a (self, &myarg: i32) {} }",
- "impl z { fn a (self: Foo, &myarg: i32) {} }",
- ];
-
- for src in srcs {
- let spans = get_spans_of_pat_idents(src);
- let (lo, hi) = (spans[0].lo(), spans[0].hi());
- assert!(
- "self" == &src[lo.to_usize()..hi.to_usize()],
- "\"{}\" != \"self\". src=\"{}\"",
- &src[lo.to_usize()..hi.to_usize()],
- src
- )
- }
- })
-}
-
-#[test]
-fn parse_exprs() {
- create_default_session_globals_then(|| {
- // just make sure that they parse....
- string_to_expr("3 + 4".to_string());
- string_to_expr("a::z.froob(b,&(987+3))".to_string());
- })
-}
-
-#[test]
-fn attrs_fix_bug() {
- create_default_session_globals_then(|| {
- string_to_item(
- "pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
- -> Result, String> {
-#[cfg(windows)]
-fn wb() -> c_int {
- (O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int
-}
-
-#[cfg(unix)]
-fn wb() -> c_int { O_WRONLY as c_int }
-
-let mut fflags: c_int = wb();
-}"
- .to_string(),
- );
- })
-}
-
-#[test]
-fn crlf_doc_comments() {
- create_default_session_globals_then(|| {
- let psess = psess();
-
- let name_1 = FileName::Custom("crlf_source_1".to_string());
- let source = "/// doc comment\r\nfn foo() {}".to_string();
- let item = parse_item_from_source_str(name_1, source, &psess).unwrap().unwrap();
- let doc = item.attrs.iter().filter_map(|at| at.doc_str()).next().unwrap();
- assert_eq!(doc.as_str(), " doc comment");
-
- let name_2 = FileName::Custom("crlf_source_2".to_string());
- let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string();
- let item = parse_item_from_source_str(name_2, source, &psess).unwrap().unwrap();
- let docs = item.attrs.iter().filter_map(|at| at.doc_str()).collect::>();
- let b: &[_] = &[Symbol::intern(" doc comment"), Symbol::intern(" line 2")];
- assert_eq!(&docs[..], b);
-
- let name_3 = FileName::Custom("clrf_source_3".to_string());
- let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string();
- let item = parse_item_from_source_str(name_3, source, &psess).unwrap().unwrap();
- let doc = item.attrs.iter().filter_map(|at| at.doc_str()).next().unwrap();
- assert_eq!(doc.as_str(), " doc comment\n * with CRLF ");
- });
-}
-
-#[test]
-fn ttdelim_span() {
- fn parse_expr_from_source_str(
- name: FileName,
- source: String,
- psess: &ParseSess,
- ) -> PResult<'_, P> {
- new_parser_from_source_str(psess, name, source).parse_expr()
- }
-
- create_default_session_globals_then(|| {
- let psess = psess();
- let expr = parse_expr_from_source_str(
- PathBuf::from("foo").into(),
- "foo!( fn main() { body } )".to_string(),
- &psess,
- )
- .unwrap();
-
- let ast::ExprKind::MacCall(mac) = &expr.kind else { panic!("not a macro") };
- let span = mac.args.tokens.trees().last().unwrap().span();
-
- match psess.source_map().span_to_snippet(span) {
- Ok(s) => assert_eq!(&s[..], "{ body }"),
- Err(_) => panic!("could not get snippet"),
- }
- });
-}
-
-// This tests that when parsing a string (rather than a file) we don't try
-// and read in a file for a module declaration and just parse a stub.
-// See `recurse_into_file_modules` in the parser.
-#[test]
-fn out_of_line_mod() {
- create_default_session_globals_then(|| {
- let item = parse_item_from_source_str(
- PathBuf::from("foo").into(),
- "mod foo { struct S; mod this_does_not_exist; }".to_owned(),
- &psess(),
- )
- .unwrap()
- .unwrap();
-
- let ast::ItemKind::Mod(_, mod_kind) = &item.kind else { panic!() };
- assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2));
- });
-}
-
-#[test]
-fn eqmodws() {
- assert_eq!(matches_codepattern("", ""), true);
- assert_eq!(matches_codepattern("", "a"), false);
- assert_eq!(matches_codepattern("a", ""), false);
- assert_eq!(matches_codepattern("a", "a"), true);
- assert_eq!(matches_codepattern("a b", "a \n\t\r b"), true);
- assert_eq!(matches_codepattern("a b ", "a \n\t\r b"), true);
- assert_eq!(matches_codepattern("a b", "a \n\t\r b "), false);
- assert_eq!(matches_codepattern("a b", "a b"), true);
- assert_eq!(matches_codepattern("ab", "a b"), false);
- assert_eq!(matches_codepattern("a b", "ab"), true);
- assert_eq!(matches_codepattern(" a b", "ab"), true);
-}
-
-#[test]
-fn pattern_whitespace() {
- assert_eq!(matches_codepattern("", "\x0C"), false);
- assert_eq!(matches_codepattern("a b ", "a \u{0085}\n\t\r b"), true);
- assert_eq!(matches_codepattern("a b", "a \u{0085}\n\t\r b "), false);
-}
-
-#[test]
-fn non_pattern_whitespace() {
- // These have the property 'White_Space' but not 'Pattern_White_Space'
- assert_eq!(matches_codepattern("a b", "a\u{2002}b"), false);
- assert_eq!(matches_codepattern("a b", "a\u{2002}b"), false);
- assert_eq!(matches_codepattern("\u{205F}a b", "ab"), false);
- assert_eq!(matches_codepattern("a \u{3000}b", "ab"), false);
-}
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 581d71875bd07..7026425e167c8 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -9,7 +9,7 @@ use rustc_span::DUMMY_SP;
use smallvec::{smallvec, SmallVec};
use thin_vec::ThinVec;
-pub fn placeholder(
+pub(crate) fn placeholder(
kind: AstFragmentKind,
id: ast::NodeId,
vis: Option,
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 943cc63285787..bb6a54fae7072 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -162,6 +162,8 @@ declare_features! (
(accepted, drop_types_in_const, "1.22.0", Some(33156)),
/// Allows using `dyn Trait` as a syntax for trait objects.
(accepted, dyn_trait, "1.27.0", Some(44662)),
+ /// Allows `X..Y` patterns.
+ (accepted, exclusive_range_pattern, "CURRENT_RUSTC_VERSION", Some(37854)),
/// Allows integer match exhaustiveness checking (RFC 2591).
(accepted, exhaustive_integer_patterns, "1.33.0", Some(50907)),
/// Allows explicit generic arguments specification with `impl Trait` present.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 9d3aac66c4103..dbb88e42a3eb9 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -396,10 +396,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
// Entry point:
- gated!(
- unix_sigpipe, Normal, template!(NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing,
- EncodeCrossCrate::Yes, experimental!(unix_sigpipe)
- ),
ungated!(start, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
@@ -522,7 +518,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// RFC 2397
gated!(
do_not_recommend, Normal, template!(Word), WarnFollowing,
- EncodeCrossCrate::No, experimental!(do_not_recommend)
+ EncodeCrossCrate::Yes, experimental!(do_not_recommend)
),
// `#[cfi_encoding = ""]`
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index e7d7a9f380b19..60b386acf9106 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -454,8 +454,6 @@ declare_features! (
(incomplete, dyn_star, "1.65.0", Some(102425)),
/// Uses generic effect parameters for ~const bounds
(unstable, effects, "1.72.0", Some(102090)),
- /// Allows `X..Y` patterns.
- (unstable, exclusive_range_pattern, "1.11.0", Some(37854)),
/// Allows exhaustive pattern matching on types that contain uninhabited types.
(unstable, exhaustive_patterns, "1.13.0", Some(51085)),
/// Allows explicit tail calls via `become` expression.
@@ -581,6 +579,9 @@ declare_features! (
(incomplete, repr128, "1.16.0", Some(56071)),
/// Allows `repr(simd)` and importing the various simd intrinsics.
(unstable, repr_simd, "1.4.0", Some(27731)),
+ /// Allows enums like Result to be used across FFI, if T's niche value can
+ /// be used to describe E or vise-versa.
+ (unstable, result_ffi_guarantees, "CURRENT_RUSTC_VERSION", Some(110503)),
/// Allows bounding the return type of AFIT/RPITIT.
(incomplete, return_type_notation, "1.70.0", Some(109417)),
/// Allows `extern "rust-cold"`.
@@ -619,8 +620,6 @@ declare_features! (
/// Allows creation of instances of a struct by moving fields that have
/// not changed from prior instances of the same struct (RFC #2528)
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
- /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
- (unstable, unix_sigpipe, "1.65.0", Some(97889)),
/// Allows unnamed fields of struct and union type
(incomplete, unnamed_fields, "1.74.0", Some(49804)),
/// Allows unsized fn parameters.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index fc8f7466694c7..244c479120dc2 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -229,9 +229,8 @@ impl<'hir> PathSegment<'hir> {
}
#[derive(Clone, Copy, Debug, HashStable_Generic)]
-pub struct ConstArg {
- pub value: AnonConst,
- pub span: Span,
+pub struct ConstArg<'hir> {
+ pub value: &'hir AnonConst,
/// Indicates whether this comes from a `~const` desugaring.
pub is_desugared_from_effects: bool,
}
@@ -252,7 +251,7 @@ impl InferArg {
pub enum GenericArg<'hir> {
Lifetime(&'hir Lifetime),
Type(&'hir Ty<'hir>),
- Const(ConstArg),
+ Const(ConstArg<'hir>),
Infer(InferArg),
}
@@ -261,7 +260,7 @@ impl GenericArg<'_> {
match self {
GenericArg::Lifetime(l) => l.ident.span,
GenericArg::Type(t) => t.span,
- GenericArg::Const(c) => c.span,
+ GenericArg::Const(c) => c.value.span,
GenericArg::Infer(i) => i.span,
}
}
@@ -490,7 +489,7 @@ pub enum GenericParamKind<'hir> {
Const {
ty: &'hir Ty<'hir>,
/// Optional default value for the const generic param
- default: Option,
+ default: Option<&'hir AnonConst>,
is_host_effect: bool,
},
}
@@ -1562,12 +1561,12 @@ impl fmt::Display for ConstContext {
pub type Lit = Spanned;
#[derive(Copy, Clone, Debug, HashStable_Generic)]
-pub enum ArrayLen {
+pub enum ArrayLen<'hir> {
Infer(InferArg),
- Body(AnonConst),
+ Body(&'hir AnonConst),
}
-impl ArrayLen {
+impl ArrayLen<'_> {
pub fn hir_id(&self) -> HirId {
match self {
ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(AnonConst { hir_id, .. }) => {
@@ -1590,6 +1589,7 @@ pub struct AnonConst {
pub hir_id: HirId,
pub def_id: LocalDefId,
pub body: BodyId,
+ pub span: Span,
}
/// An inline constant expression `const { something }`.
@@ -2002,7 +2002,7 @@ pub enum ExprKind<'hir> {
///
/// E.g., `[1; 5]`. The first expression is the element
/// to be repeated; the second is the number of times to repeat it.
- Repeat(&'hir Expr<'hir>, ArrayLen),
+ Repeat(&'hir Expr<'hir>, ArrayLen<'hir>),
/// A suspension point for coroutines (i.e., `yield `).
Yield(&'hir Expr<'hir>, YieldSource),
@@ -2382,7 +2382,7 @@ pub struct TypeBinding<'hir> {
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum Term<'hir> {
Ty(&'hir Ty<'hir>),
- Const(AnonConst),
+ Const(&'hir AnonConst),
}
impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
@@ -2391,8 +2391,8 @@ impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
}
}
-impl<'hir> From for Term<'hir> {
- fn from(c: AnonConst) -> Self {
+impl<'hir> From<&'hir AnonConst> for Term<'hir> {
+ fn from(c: &'hir AnonConst) -> Self {
Term::Const(c)
}
}
@@ -2683,7 +2683,7 @@ pub enum TyKind<'hir> {
/// A variable length slice (i.e., `[T]`).
Slice(&'hir Ty<'hir>),
/// A fixed length array (i.e., `[T; n]`).
- Array(&'hir Ty<'hir>, ArrayLen),
+ Array(&'hir Ty<'hir>, ArrayLen<'hir>),
/// A raw pointer (i.e., `*const T` or `*mut T`).
Ptr(MutTy<'hir>),
/// A reference (i.e., `&'a T` or `&'a mut T`).
@@ -2712,7 +2712,7 @@ pub enum TyKind<'hir> {
/// where `Bound` is a trait or a lifetime.
TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
/// Unused for now.
- Typeof(AnonConst),
+ Typeof(&'hir AnonConst),
/// `TyKind::Infer` means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
Infer,
@@ -2745,10 +2745,10 @@ pub enum InlineAsmOperand<'hir> {
out_expr: Option<&'hir Expr<'hir>>,
},
Const {
- anon_const: AnonConst,
+ anon_const: &'hir AnonConst,
},
SymFn {
- anon_const: AnonConst,
+ anon_const: &'hir AnonConst,
},
SymStatic {
path: QPath<'hir>,
@@ -2950,7 +2950,7 @@ pub struct Variant<'hir> {
/// Fields and constructor id of the variant.
pub data: VariantData<'hir>,
/// Explicit discriminant (e.g., `Foo = 1`).
- pub disr_expr: Option,
+ pub disr_expr: Option<&'hir AnonConst>,
/// Span
pub span: Span,
}
@@ -3479,15 +3479,13 @@ impl<'hir> OwnerNode<'hir> {
}
}
- // Span by reference to pass to `Node::Err`.
- #[allow(rustc::pass_by_value)]
- pub fn span(&self) -> &'hir Span {
+ pub fn span(&self) -> Span {
match self {
OwnerNode::Item(Item { span, .. })
| OwnerNode::ForeignItem(ForeignItem { span, .. })
| OwnerNode::ImplItem(ImplItem { span, .. })
- | OwnerNode::TraitItem(TraitItem { span, .. }) => span,
- OwnerNode::Crate(Mod { spans: ModSpans { inner_span, .. }, .. }) => inner_span,
+ | OwnerNode::TraitItem(TraitItem { span, .. }) => *span,
+ OwnerNode::Crate(Mod { spans: ModSpans { inner_span, .. }, .. }) => *inner_span,
OwnerNode::Synthetic => unreachable!(),
}
}
@@ -3632,9 +3630,7 @@ pub enum Node<'hir> {
PreciseCapturingNonLifetimeArg(&'hir PreciseCapturingNonLifetimeArg),
// Created by query feeding
Synthetic,
- // Span by reference to minimize `Node`'s size
- #[allow(rustc::pass_by_value)]
- Err(&'hir Span),
+ Err(Span),
}
impl<'hir> Node<'hir> {
@@ -3871,7 +3867,7 @@ mod size_asserts {
static_assert_size!(FnDecl<'_>, 40);
static_assert_size!(ForeignItem<'_>, 72);
static_assert_size!(ForeignItemKind<'_>, 40);
- static_assert_size!(GenericArg<'_>, 32);
+ static_assert_size!(GenericArg<'_>, 24);
static_assert_size!(GenericBound<'_>, 48);
static_assert_size!(Generics<'_>, 56);
static_assert_size!(Impl<'_>, 80);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index cd9f9ff9109c1..fa89a4a44ef5a 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -338,7 +338,7 @@ pub trait Visitor<'v>: Sized {
fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result {
walk_pat_field(self, f)
}
- fn visit_array_length(&mut self, len: &'v ArrayLen) -> Self::Result {
+ fn visit_array_length(&mut self, len: &'v ArrayLen<'v>) -> Self::Result {
walk_array_len(self, len)
}
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
@@ -703,7 +703,7 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'
visitor.visit_pat(field.pat)
}
-pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) -> V::Result {
+pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen<'v>) -> V::Result {
match len {
// FIXME: Use `visit_infer` here.
ArrayLen::Infer(InferArg { hir_id, span: _ }) => visitor.visit_id(*hir_id),
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index f2ceb4702643a..f101c595bdf35 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -1,6 +1,6 @@
use crate::errors::AutoDerefReachedRecursionLimit;
+use crate::traits;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
-use crate::traits::{self, TraitEngine, TraitEngineExt};
use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -8,7 +8,7 @@ use rustc_session::Limit;
use rustc_span::def_id::LocalDefId;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::Span;
-use rustc_trait_selection::traits::StructurallyNormalizeExt;
+use rustc_trait_selection::traits::ObligationCtxt;
#[derive(Copy, Clone, Debug)]
pub enum AutoderefKind {
@@ -167,25 +167,19 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
&self,
ty: Ty<'tcx>,
) -> Option<(Ty<'tcx>, Vec>)> {
- let mut fulfill_cx = >::new(self.infcx);
-
- let cause = traits::ObligationCause::misc(self.span, self.body_id);
- let normalized_ty = match self
- .infcx
- .at(&cause, self.param_env)
- .structurally_normalize(ty, &mut *fulfill_cx)
- {
- Ok(normalized_ty) => normalized_ty,
- Err(errors) => {
- // This shouldn't happen, except for evaluate/fulfill mismatches,
- // but that's not a reason for an ICE (`predicate_may_hold` is conservative
- // by design).
- debug!(?errors, "encountered errors while fulfilling");
- return None;
- }
+ let ocx = ObligationCtxt::new(self.infcx);
+ let Ok(normalized_ty) = ocx.structurally_normalize(
+ &traits::ObligationCause::misc(self.span, self.body_id),
+ self.param_env,
+ ty,
+ ) else {
+ // We shouldn't have errors here, except for evaluate/fulfill mismatches,
+ // but that's not a reason for an ICE (`predicate_may_hold` is conservative
+ // by design).
+ // FIXME(-Znext-solver): This *actually* shouldn't happen then.
+ return None;
};
-
- let errors = fulfill_cx.select_where_possible(self.infcx);
+ let errors = ocx.select_where_possible();
if !errors.is_empty() {
// This shouldn't happen, except for evaluate/fulfill mismatches,
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
@@ -194,7 +188,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
return None;
}
- Some((normalized_ty, fulfill_cx.pending_obligations()))
+ Some((normalized_ty, ocx.into_pending_obligations()))
}
/// Returns the final type we ended up with, which may be an inference
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index aafb5c1c0b4bc..5562b81871fc7 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -23,7 +23,7 @@ use rustc_span::Span;
/// include the self type (e.g., `trait_bounds`) but in others we do not
#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
- pub clauses: Vec<(ty::Clause<'tcx>, Span)>,
+ clauses: Vec<(ty::Clause<'tcx>, Span)>,
}
impl<'tcx> Bounds<'tcx> {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 0f0736f87568b..9198ceb8f59db 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -143,7 +143,7 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector {
_ => {}
}
}
- fn visit_array_length(&mut self, length: &'v hir::ArrayLen) {
+ fn visit_array_length(&mut self, length: &'v hir::ArrayLen<'v>) {
if let hir::ArrayLen::Infer(inf) = length {
self.0.push(inf.span);
}
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 9d7deebac48e4..5ccfd06f25822 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -24,7 +24,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
let hir_id = tcx.local_def_id_to_hir_id(def_id);
let node = tcx.hir_node(hir_id);
- let Node::AnonConst(_) = node else {
+ let Node::AnonConst(&AnonConst { span, .. }) = node else {
span_bug!(
tcx.def_span(def_id),
"expected anon const in `anon_const_type_of`, got {node:?}"
@@ -134,7 +134,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
// I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
"unexpected non-GAT usage of an anon const",
);
}
@@ -152,7 +152,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else {
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
format!("unable to find type-dependent def for {parent_node_id:?}"),
);
};
@@ -194,7 +194,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
} else {
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
format!("unable to find const parent for {hir_id} in pat {pat:?}"),
);
}
@@ -202,7 +202,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
_ => {
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
format!("unexpected const parent path {parent_node:?}"),
);
}
@@ -226,11 +226,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
.map(|idx| (idx, seg))
})
}) else {
- return Ty::new_error_with_message(
- tcx,
- tcx.def_span(def_id),
- "no arg matching AnonConst in path",
- );
+ return Ty::new_error_with_message(tcx, span, "no arg matching AnonConst in path");
};
let generics = match tcx.res_generics_def_id(segment.res) {
@@ -238,7 +234,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
None => {
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
);
}
@@ -250,7 +246,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
_ => {
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
format!("unexpected const parent in type_of(): {parent_node:?}"),
);
}
@@ -278,7 +274,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
} else {
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"),
);
}
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 285b99c2c69d5..4f5fbd024a998 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -968,7 +968,7 @@ impl<'a> State<'a> {
self.print_else(elseopt)
}
- fn print_array_length(&mut self, len: &hir::ArrayLen) {
+ fn print_array_length(&mut self, len: &hir::ArrayLen<'_>) {
match len {
hir::ArrayLen::Infer(..) => self.word("_"),
hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
@@ -1052,7 +1052,7 @@ impl<'a> State<'a> {
self.end()
}
- fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen) {
+ fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen<'_>) {
self.ibox(INDENT_UNIT);
self.word("[");
self.print_expr(element);
diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml
index 9e7f0776b6087..73a775690d66b 100644
--- a/compiler/rustc_hir_typeck/Cargo.toml
+++ b/compiler/rustc_hir_typeck/Cargo.toml
@@ -12,7 +12,6 @@ rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
-rustc_graphviz = { path = "../rustc_graphviz" }
rustc_hir = { path = "../rustc_hir" }
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 825276aef421c..df92af876f612 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -37,16 +37,13 @@
use crate::errors::SuggestBoxingForReturnImplTrait;
use crate::FnCtxt;
-use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
+use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::Expr;
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_infer::infer::type_variable::TypeVariableOrigin;
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
-use rustc_infer::traits::TraitEngineExt as _;
-use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause, TraitEngine};
+use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause};
use rustc_infer::traits::{Obligation, PredicateObligation};
use rustc_middle::lint::in_external_macro;
use rustc_middle::traits::BuiltinImplSource;
@@ -65,7 +62,6 @@ use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::TraitEngineExt as _;
use rustc_trait_selection::traits::{
self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt,
};
@@ -95,22 +91,6 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> {
type CoerceResult<'tcx> = InferResult<'tcx, (Vec>, Ty<'tcx>)>;
-struct CollectRetsVisitor<'tcx> {
- ret_exprs: Vec<&'tcx hir::Expr<'tcx>>,
-}
-
-impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> {
- fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
- match expr.kind {
- hir::ExprKind::Ret(_) => self.ret_exprs.push(expr),
- // `return` in closures does not return from the outer function
- hir::ExprKind::Closure(_) => return,
- _ => {}
- }
- intravisit::walk_expr(self, expr);
- }
-}
-
/// Coercing a mutable reference to an immutable works, while
/// coercing `&T` to `&mut T` should be forbidden.
fn coerce_mutbls<'tcx>(
@@ -164,11 +144,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Filter these cases out to make sure our coercion is more accurate.
match res {
Ok(InferOk { value, obligations }) if self.next_trait_solver() => {
- let mut fulfill_cx = >::new(self);
- fulfill_cx.register_predicate_obligations(self, obligations);
- let errs = fulfill_cx.select_where_possible(self);
- if errs.is_empty() {
- Ok(InferOk { value, obligations: fulfill_cx.pending_obligations() })
+ let ocx = ObligationCtxt::new(self);
+ ocx.register_obligations(obligations);
+ if ocx.select_where_possible().is_empty() {
+ Ok(InferOk { value, obligations: ocx.into_pending_obligations() })
} else {
Err(TypeError::Mismatch)
}
@@ -631,13 +610,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// but we need to constrain vars before processing goals mentioning
// them.
Some(ty::PredicateKind::AliasRelate(..)) => {
- let mut fulfill_cx = >::new(self);
- fulfill_cx.register_predicate_obligation(self, obligation);
- let errs = fulfill_cx.select_where_possible(self);
- if !errs.is_empty() {
+ let ocx = ObligationCtxt::new(self);
+ ocx.register_obligation(obligation);
+ if !ocx.select_where_possible().is_empty() {
return Err(TypeError::Mismatch);
}
- coercion.obligations.extend(fulfill_cx.pending_obligations());
+ coercion.obligations.extend(ocx.into_pending_obligations());
continue;
}
_ => {
@@ -1601,7 +1579,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
let mut err;
let mut unsized_return = false;
- let mut visitor = CollectRetsVisitor { ret_exprs: vec![] };
match *cause.code() {
ObligationCauseCode::ReturnNoExpression => {
err = struct_span_code_err!(
@@ -1636,11 +1613,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
if !fcx.tcx.features().unsized_locals {
unsized_return = self.is_return_ty_definitely_unsized(fcx);
}
- if let Some(expression) = expression
- && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind
- {
- intravisit::walk_block(&mut visitor, loop_blk);
- }
}
ObligationCauseCode::ReturnValue(id) => {
err = self.report_return_mismatched_types(
@@ -1741,6 +1713,22 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
augment_error(&mut err);
if let Some(expr) = expression {
+ if let hir::ExprKind::Loop(
+ _,
+ _,
+ loop_src @ (hir::LoopSource::While | hir::LoopSource::ForLoop),
+ _,
+ ) = expr.kind
+ {
+ let loop_type = if loop_src == hir::LoopSource::While {
+ "`while` loops"
+ } else {
+ "`for` loops"
+ };
+
+ err.note(format!("{loop_type} evaluate to unit type `()`"));
+ }
+
fcx.emit_coerce_suggestions(
&mut err,
expr,
@@ -1749,15 +1737,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
None,
Some(coercion_error),
);
- if visitor.ret_exprs.len() > 0 {
- self.note_unreachable_loop_return(
- &mut err,
- fcx.tcx,
- &expr,
- &visitor.ret_exprs,
- expected,
- );
- }
}
let reported = err.emit_unless(unsized_return);
@@ -1831,110 +1810,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
);
}
- fn note_unreachable_loop_return(
- &self,
- err: &mut Diag<'_>,
- tcx: TyCtxt<'tcx>,
- expr: &hir::Expr<'tcx>,
- ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>,
- ty: Ty<'tcx>,
- ) {
- let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else {
- return;
- };
- let mut span: MultiSpan = vec![loop_span].into();
- span.push_span_label(loop_span, "this might have zero elements to iterate on");
- const MAXITER: usize = 3;
- let iter = ret_exprs.iter().take(MAXITER);
- for ret_expr in iter {
- span.push_span_label(
- ret_expr.span,
- "if the loop doesn't execute, this value would never get returned",
- );
- }
- err.span_note(
- span,
- "the function expects a value to always be returned, but loops might run zero times",
- );
- if MAXITER < ret_exprs.len() {
- err.note(format!(
- "if the loop doesn't execute, {} other values would never get returned",
- ret_exprs.len() - MAXITER
- ));
- }
- let hir = tcx.hir();
- let item = hir.get_parent_item(expr.hir_id);
- let ret_msg = "return a value for the case when the loop has zero elements to iterate on";
- let ret_ty_msg =
- "otherwise consider changing the return type to account for that possibility";
- let node = tcx.hir_node(item.into());
- if let Some(body_id) = node.body_id()
- && let Some(sig) = node.fn_sig()
- && let hir::ExprKind::Block(block, _) = hir.body(body_id).value.kind
- && !ty.is_never()
- {
- let indentation = if let None = block.expr
- && let [.., last] = &block.stmts
- {
- tcx.sess.source_map().indentation_before(last.span).unwrap_or_else(String::new)
- } else if let Some(expr) = block.expr {
- tcx.sess.source_map().indentation_before(expr.span).unwrap_or_else(String::new)
- } else {
- String::new()
- };
- if let None = block.expr
- && let [.., last] = &block.stmts
- {
- err.span_suggestion_verbose(
- last.span.shrink_to_hi(),
- ret_msg,
- format!("\n{indentation}/* `{ty}` value */"),
- Applicability::MaybeIncorrect,
- );
- } else if let Some(expr) = block.expr {
- err.span_suggestion_verbose(
- expr.span.shrink_to_hi(),
- ret_msg,
- format!("\n{indentation}/* `{ty}` value */"),
- Applicability::MaybeIncorrect,
- );
- }
- let mut sugg = match sig.decl.output {
- hir::FnRetTy::DefaultReturn(span) => {
- vec![(span, " -> Option<()>".to_string())]
- }
- hir::FnRetTy::Return(ty) => {
- vec![
- (ty.span.shrink_to_lo(), "Option<".to_string()),
- (ty.span.shrink_to_hi(), ">".to_string()),
- ]
- }
- };
- for ret_expr in ret_exprs {
- match ret_expr.kind {
- hir::ExprKind::Ret(Some(expr)) => {
- sugg.push((expr.span.shrink_to_lo(), "Some(".to_string()));
- sugg.push((expr.span.shrink_to_hi(), ")".to_string()));
- }
- hir::ExprKind::Ret(None) => {
- sugg.push((ret_expr.span.shrink_to_hi(), " Some(())".to_string()));
- }
- _ => {}
- }
- }
- if let None = block.expr
- && let [.., last] = &block.stmts
- {
- sugg.push((last.span.shrink_to_hi(), format!("\n{indentation}None")));
- } else if let Some(expr) = block.expr {
- sugg.push((expr.span.shrink_to_hi(), format!("\n{indentation}None")));
- }
- err.multipart_suggestion(ret_ty_msg, sugg, Applicability::MaybeIncorrect);
- } else {
- err.help(format!("{ret_msg}, {ret_ty_msg}"));
- }
- }
-
fn report_return_mismatched_types<'a>(
&self,
cause: &ObligationCause<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 618d90a07ec29..60c0b1872fa03 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -57,7 +57,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| self.suggest_into(err, expr, expr_ty, expected)
|| self.suggest_floating_point_literal(err, expr, expected)
|| self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected)
- || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty);
+ || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty)
+ || self.suggest_returning_value_after_loop(err, expr, expected);
if !suggested {
self.note_source_of_type_mismatch_constraint(
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 8b1ea7c952cb1..7b552bb707743 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1444,7 +1444,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
};
if let hir::TyKind::Array(_, length) = ty.peel_refs().kind
- && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
+ && let hir::ArrayLen::Body(&hir::AnonConst { hir_id, .. }) = length
{
let span = self.tcx.hir().span(hir_id);
self.dcx().try_steal_modify_and_emit_err(
@@ -1483,7 +1483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_expr_repeat(
&self,
element: &'tcx hir::Expr<'tcx>,
- count: &'tcx hir::ArrayLen,
+ count: &'tcx hir::ArrayLen<'tcx>,
expected: Expectation<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 2060e08aacf97..552747bdc5272 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -438,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- pub fn lower_array_length(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
+ pub fn lower_array_length(&self, length: &hir::ArrayLen<'tcx>) -> ty::Const<'tcx> {
match length {
hir::ArrayLen::Infer(inf) => self.ct_infer(self.tcx.types.usize, None, inf.span),
hir::ArrayLen::Body(anon_const) => {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 133778a416cc2..d00fea4fae498 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -18,8 +18,8 @@ use rustc_hir::def::Res;
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
- CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node,
- Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
+ Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId,
+ Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
};
use rustc_hir_analysis::collect::suggest_impl_trait;
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
@@ -1942,6 +1942,91 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
+ // If the expr is a while or for loop and is the tail expr of its
+ // enclosing body suggest returning a value right after it
+ pub fn suggest_returning_value_after_loop(
+ &self,
+ err: &mut Diag<'_>,
+ expr: &hir::Expr<'tcx>,
+ expected: Ty<'tcx>,
+ ) -> bool {
+ let hir = self.tcx.hir();
+ let enclosing_scope =
+ hir.get_enclosing_scope(expr.hir_id).map(|hir_id| self.tcx.hir_node(hir_id));
+
+ // Get tail expr of the enclosing block or body
+ let tail_expr = if let Some(Node::Block(hir::Block { expr, .. })) = enclosing_scope
+ && expr.is_some()
+ {
+ *expr
+ } else {
+ let body_def_id = hir.enclosing_body_owner(expr.hir_id);
+ let body_id = hir.body_owned_by(body_def_id);
+ let body = hir.body(body_id);
+
+ // Get tail expr of the body
+ match body.value.kind {
+ // Regular function body etc.
+ hir::ExprKind::Block(block, _) => block.expr,
+ // Anon const body (there's no block in this case)
+ hir::ExprKind::DropTemps(expr) => Some(expr),
+ _ => None,
+ }
+ };
+
+ let Some(tail_expr) = tail_expr else {
+ return false; // Body doesn't have a tail expr we can compare with
+ };
+
+ // Get the loop expr within the tail expr
+ let loop_expr_in_tail = match expr.kind {
+ hir::ExprKind::Loop(_, _, hir::LoopSource::While, _) => tail_expr,
+ hir::ExprKind::Loop(_, _, hir::LoopSource::ForLoop, _) => {
+ match tail_expr.peel_drop_temps() {
+ Expr { kind: ExprKind::Match(_, [Arm { body, .. }], _), .. } => body,
+ _ => return false, // Not really a for loop
+ }
+ }
+ _ => return false, // Not a while or a for loop
+ };
+
+ // If the expr is the loop expr in the tail
+ // then make the suggestion
+ if expr.hir_id == loop_expr_in_tail.hir_id {
+ let span = expr.span;
+
+ let (msg, suggestion) = if expected.is_never() {
+ (
+ "consider adding a diverging expression here",
+ "`loop {}` or `panic!(\"...\")`".to_string(),
+ )
+ } else {
+ ("consider returning a value here", format!("`{expected}` value"))
+ };
+
+ let src_map = self.tcx.sess.source_map();
+ let suggestion = if src_map.is_multiline(expr.span) {
+ let indentation = src_map.indentation_before(span).unwrap_or_else(String::new);
+ format!("\n{indentation}/* {suggestion} */")
+ } else {
+ // If the entire expr is on a single line
+ // put the suggestion also on the same line
+ format!(" /* {suggestion} */")
+ };
+
+ err.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ msg,
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+
+ true
+ } else {
+ false
+ }
+ }
+
/// If the expected type is an enum (Issue #55250) with any variants whose
/// sole field is of the found type, suggest such variants. (Issue #42764)
pub(crate) fn suggest_compatible_variants(
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 382dba5f95fb9..8c7ae7f8e980d 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -10,7 +10,6 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, Pat, PatKind};
use rustc_infer::infer;
use rustc_infer::infer::type_variable::TypeVariableOrigin;
-use rustc_lint as lint;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
@@ -684,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
// `mut x` resets the binding mode in edition <= 2021.
self.tcx.emit_node_span_lint(
- lint::builtin::DEREFERENCING_MUT_BINDING,
+ rustc_lint::builtin::DEREFERENCING_MUT_BINDING,
pat.hir_id,
pat.span,
errors::DereferencingMutBinding { span: pat.span },
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 3d7c0cfc30aa3..193042b8cdf25 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -104,10 +104,14 @@
//! implemented.
use crate::errors;
+use rustc_data_structures::base_n;
+use rustc_data_structures::base_n::BaseNString;
+use rustc_data_structures::base_n::ToBaseN;
+use rustc_data_structures::base_n::CASE_INSENSITIVE;
+use rustc_data_structures::flock;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_data_structures::svh::Svh;
use rustc_data_structures::unord::{UnordMap, UnordSet};
-use rustc_data_structures::{base_n, flock};
use rustc_errors::ErrorGuaranteed;
use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy};
use rustc_middle::bug;
@@ -333,31 +337,24 @@ pub fn finalize_session_directory(sess: &Session, svh: Option) {
debug!("finalize_session_directory() - session directory: {}", incr_comp_session_dir.display());
- let old_sub_dir_name = incr_comp_session_dir
+ let mut sub_dir_name = incr_comp_session_dir
.file_name()
.unwrap()
.to_str()
- .expect("malformed session dir name: contains non-Unicode characters");
+ .expect("malformed session dir name: contains non-Unicode characters")
+ .to_string();
- // Keep the 's-{timestamp}-{random-number}' prefix, but replace the
- // '-working' part with the SVH of the crate
- let dash_indices: Vec<_> = old_sub_dir_name.match_indices('-').map(|(idx, _)| idx).collect();
- if dash_indices.len() != 3 {
- bug!(
- "Encountered incremental compilation session directory with \
- malformed name: {}",
- incr_comp_session_dir.display()
- )
- }
-
- // State: "s-{timestamp}-{random-number}-"
- let mut new_sub_dir_name = String::from(&old_sub_dir_name[..=dash_indices[2]]);
+ // Keep the 's-{timestamp}-{random-number}' prefix, but replace "working" with the SVH of the crate
+ sub_dir_name.truncate(sub_dir_name.len() - "working".len());
+ // Double-check that we kept this: "s-{timestamp}-{random-number}-"
+ assert!(sub_dir_name.ends_with('-'), "{:?}", sub_dir_name);
+ assert!(sub_dir_name.as_bytes().iter().filter(|b| **b == b'-').count() == 3);
- // Append the svh
- base_n::push_str(svh.as_u128(), INT_ENCODE_BASE, &mut new_sub_dir_name);
+ // Append the SVH
+ sub_dir_name.push_str(&svh.as_u128().to_base_fixed_len(CASE_INSENSITIVE));
// Create the full path
- let new_path = incr_comp_session_dir.parent().unwrap().join(new_sub_dir_name);
+ let new_path = incr_comp_session_dir.parent().unwrap().join(&*sub_dir_name);
debug!("finalize_session_directory() - new path: {}", new_path.display());
match rename_path_with_retry(&*incr_comp_session_dir, &new_path, 3) {
@@ -453,11 +450,11 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf {
let random_number = thread_rng().next_u32();
debug!("generate_session_dir_path: random_number = {}", random_number);
- let directory_name = format!(
- "s-{}-{}-working",
- timestamp,
- base_n::encode(random_number as u128, INT_ENCODE_BASE)
- );
+ // Chop the first 3 characters off the timestamp. Those 3 bytes will be zero for a while.
+ let (zeroes, timestamp) = timestamp.split_at(3);
+ assert_eq!(zeroes, "000");
+ let directory_name =
+ format!("s-{}-{}-working", timestamp, random_number.to_base_fixed_len(CASE_INSENSITIVE));
debug!("generate_session_dir_path: directory_name = {}", directory_name);
let directory_path = crate_dir.join(directory_name);
debug!("generate_session_dir_path: directory_path = {}", directory_path.display());
@@ -588,10 +585,10 @@ fn extract_timestamp_from_session_dir(directory_name: &str) -> Result String {
+fn timestamp_to_string(timestamp: SystemTime) -> BaseNString {
let duration = timestamp.duration_since(UNIX_EPOCH).unwrap();
let micros = duration.as_secs() * 1_000_000 + (duration.subsec_nanos() as u64) / 1000;
- base_n::encode(micros as u128, INT_ENCODE_BASE)
+ micros.to_base_fixed_len(CASE_INSENSITIVE)
}
fn string_to_timestamp(s: &str) -> Result {
@@ -622,9 +619,8 @@ fn crate_path(sess: &Session) -> PathBuf {
sess.cfg_version,
);
- let stable_crate_id = base_n::encode(stable_crate_id.as_u64() as u128, INT_ENCODE_BASE);
-
- let crate_name = format!("{crate_name}-{stable_crate_id}");
+ let crate_name =
+ format!("{crate_name}-{}", stable_crate_id.as_u64().to_base_fixed_len(CASE_INSENSITIVE));
incr_dir.join(crate_name)
}
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index e3611ab28e532..f77a611586180 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -206,6 +206,18 @@ impl<'tcx> FulfillmentError<'tcx> {
) -> FulfillmentError<'tcx> {
FulfillmentError { obligation, code, root_obligation }
}
+
+ pub fn is_true_error(&self) -> bool {
+ match self.code {
+ FulfillmentErrorCode::SelectionError(_)
+ | FulfillmentErrorCode::ProjectionError(_)
+ | FulfillmentErrorCode::SubtypeError(_, _)
+ | FulfillmentErrorCode::ConstEquateError(_, _) => true,
+ FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => {
+ false
+ }
+ }
+ }
}
impl<'tcx> PolyTraitObligation<'tcx> {
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index b593c41a8eafa..76d5d7a3ac2fd 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -4,7 +4,6 @@ use crate::proc_macro_decls;
use crate::util;
use rustc_ast::{self as ast, visit};
-use rustc_borrowck as mir_borrowck;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::parallel;
use rustc_data_structures::steal::Steal;
@@ -20,7 +19,6 @@ use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt};
use rustc_middle::util::Providers;
-use rustc_mir_build as mir_build;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
use rustc_passes::{abi_test, hir_stats, layout_test};
use rustc_resolve::Resolver;
@@ -616,8 +614,8 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| {
proc_macro_decls::provide(providers);
rustc_const_eval::provide(providers);
rustc_middle::hir::provide(providers);
- mir_borrowck::provide(providers);
- mir_build::provide(providers);
+ rustc_borrowck::provide(providers);
+ rustc_mir_build::provide(providers);
rustc_mir_transform::provide(providers);
rustc_monomorphize::provide(providers);
rustc_privacy::provide(providers);
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index db150cc1f875d..36f9dda7250ca 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -20,7 +20,7 @@ use rustc_span::source_map::{RealFileLoader, SourceMapInputs};
use rustc_span::symbol::sym;
use rustc_span::{FileName, SourceFileHashAlgorithm};
use rustc_target::spec::{
- CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel, WasmCAbi,
+ CodeModel, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, WasmCAbi,
};
use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
use std::collections::{BTreeMap, BTreeSet};
@@ -809,6 +809,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(no_profiler_runtime, true);
tracked!(no_trait_vptr, true);
tracked!(no_unique_section_names, true);
+ tracked!(on_broken_pipe, OnBrokenPipe::Kill);
tracked!(oom, OomStrategy::Panic);
tracked!(osx_rpath_install_name, true);
tracked!(packed_bundled_libs, true);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 02dcfe9c8dffb..ce4d382501522 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -7,18 +7,16 @@ use rustc_data_structures::sync;
use rustc_metadata::{load_symbol_from_dylib, DylibError};
use rustc_middle::ty::CurrentGcx;
use rustc_parse::validate_attr;
-use rustc_session as session;
-use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes};
+use rustc_session::config::{host_triple, Cfg, OutFileName, OutputFilenames, OutputTypes};
use rustc_session::filesearch::sysroot_candidates;
use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
-use rustc_session::{filesearch, Session};
+use rustc_session::output::{categorize_crate_type, CRATE_TYPES};
+use rustc_session::{filesearch, EarlyDiagCtxt, Session};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
use rustc_span::source_map::SourceMapInputs;
use rustc_span::symbol::sym;
use rustc_target::spec::Target;
-use session::output::{categorize_crate_type, CRATE_TYPES};
-use session::EarlyDiagCtxt;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
@@ -286,7 +284,7 @@ fn get_codegen_sysroot(
"cannot load the default codegen backend twice"
);
- let target = session::config::host_triple();
+ let target = host_triple();
let sysroot_candidates = sysroot_candidates();
let sysroot = iter::once(sysroot)
diff --git a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
index e9a6276192e52..3c423b4e2aa6d 100644
--- a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
+++ b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
@@ -164,9 +164,9 @@ pub(super) fn unexpected_cfg_name(
if is_from_cargo {
if !is_feature_cfg {
- diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`"));
+ diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo::rustc-check-cfg={inst}\");` to the top of the `build.rs`"));
}
- diag.note("see for more information about checking conditional configuration");
+ diag.note("see for more information about checking conditional configuration");
} else {
diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
diag.note("see for more information about checking conditional configuration");
@@ -266,9 +266,9 @@ pub(super) fn unexpected_cfg_value(
diag.help("consider defining some features in `Cargo.toml`");
}
} else if !is_cfg_a_well_know_name {
- diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`"));
+ diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo::rustc-check-cfg={inst}\");` to the top of the `build.rs`"));
}
- diag.note("see for more information about checking conditional configuration");
+ diag.note("see for more information about checking conditional configuration");
} else {
if !is_cfg_a_well_know_name {
diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index 1f0a8a0b56783..c1f5cd45dc824 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -74,9 +74,12 @@ fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String {
GenericArg::Type(ty) => {
cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_else(|_| "_".into())
}
- GenericArg::Const(c) => {
- cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_else(|_| "_".into())
- }
+ GenericArg::Const(c) => cx
+ .tcx
+ .sess
+ .source_map()
+ .span_to_snippet(c.value.span)
+ .unwrap_or_else(|_| "_".into()),
GenericArg::Infer(_) => String::from("_"),
})
.collect::>();
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 13b6054586cd5..f9f766f832af7 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1101,6 +1101,32 @@ fn get_nullable_type<'tcx>(
})
}
+/// A type is niche-optimization candidate iff:
+/// - Is a zero-sized type with alignment 1 (a “1-ZSTâ€).
+/// - Has no fields.
+/// - Does not have the `#[non_exhaustive]` attribute.
+fn is_niche_optimization_candidate<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+) -> bool {
+ if tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| !layout.is_1zst()) {
+ return false;
+ }
+
+ match ty.kind() {
+ ty::Adt(ty_def, _) => {
+ let non_exhaustive = ty_def.is_variant_list_non_exhaustive();
+ let empty = (ty_def.is_struct() && ty_def.all_fields().next().is_none())
+ || (ty_def.is_enum() && ty_def.variants().is_empty());
+
+ !non_exhaustive && empty
+ }
+ ty::Tuple(tys) => tys.is_empty(),
+ _ => false,
+ }
+}
+
/// Check if this enum can be safely exported based on the "nullable pointer optimization". If it
/// can, return the type that `ty` can be safely converted to, otherwise return `None`.
/// Currently restricted to function pointers, boxes, references, `core::num::NonZero`,
@@ -1117,6 +1143,22 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
let field_ty = match &ty_def.variants().raw[..] {
[var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) {
([], [field]) | ([field], []) => field.ty(tcx, args),
+ ([field1], [field2]) => {
+ if !tcx.features().result_ffi_guarantees {
+ return None;
+ }
+
+ let ty1 = field1.ty(tcx, args);
+ let ty2 = field2.ty(tcx, args);
+
+ if is_niche_optimization_candidate(tcx, param_env, ty1) {
+ ty2
+ } else if is_niche_optimization_candidate(tcx, param_env, ty2) {
+ ty1
+ } else {
+ return None;
+ }
+ }
_ => return None,
},
_ => return None,
@@ -1202,7 +1244,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
args: GenericArgsRef<'tcx>,
) -> FfiResult<'tcx> {
use FfiResult::*;
-
let transparent_with_all_zst_fields = if def.repr().transparent() {
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
// Transparent newtypes have at most one non-ZST field which needs to be checked..
@@ -1329,27 +1370,29 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
return FfiSafe;
}
+ if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
+ return FfiUnsafe {
+ ty,
+ reason: fluent::lint_improper_ctypes_non_exhaustive,
+ help: None,
+ };
+ }
+
// Check for a repr() attribute to specify the size of the
// discriminant.
if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
{
- // Special-case types like `Option`.
- if repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
- .is_none()
+ // Special-case types like `Option` and `Result`
+ if let Some(ty) =
+ repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
{
- return FfiUnsafe {
- ty,
- reason: fluent::lint_improper_ctypes_enum_repr_reason,
- help: Some(fluent::lint_improper_ctypes_enum_repr_help),
- };
+ return self.check_type_for_ffi(cache, ty);
}
- }
- if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
return FfiUnsafe {
ty,
- reason: fluent::lint_improper_ctypes_non_exhaustive,
- help: None,
+ reason: fluent::lint_improper_ctypes_enum_repr_reason,
+ help: Some(fluent::lint_improper_ctypes_enum_repr_help),
};
}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index c7996c27c2f09..eea3ca44c48b2 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -844,7 +844,6 @@ declare_lint! {
/// ### Example
///
/// ```rust
- /// # #![feature(exclusive_range_pattern)]
/// let x = 123u32;
/// match x {
/// 0..100 => { println!("small"); }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index c0c773c6285c2..c7aea137b6841 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -885,7 +885,7 @@ impl<'hir> Map<'hir> {
Node::ImplItem(impl_item) => impl_item.span,
Node::Variant(variant) => variant.span,
Node::Field(field) => field.span,
- Node::AnonConst(constant) => self.body(constant.body).value.span,
+ Node::AnonConst(constant) => constant.span,
Node::ConstBlock(constant) => self.body(constant.body).value.span,
Node::Expr(expr) => expr.span,
Node::ExprField(field) => field.span,
@@ -912,7 +912,7 @@ impl<'hir> Map<'hir> {
Node::ArrayLenInfer(inf) => inf.span,
Node::PreciseCapturingNonLifetimeArg(param) => param.ident.span,
Node::Synthetic => unreachable!(),
- Node::Err(span) => *span,
+ Node::Err(span) => span,
}
}
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 9d9ca22247ad6..477303e2434f4 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -277,7 +277,7 @@ pub struct FunctionCoverageInfo {
pub mappings: Vec,
/// The depth of the deepest decision is used to know how many
/// temp condbitmaps should be allocated for the function.
- pub mcdc_max_decision_depth: u16,
+ pub mcdc_num_condition_bitmaps: usize,
}
/// Branch information recorded during THIR-to-MIR lowering, and stored in MIR.
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 9cc5c6a2ee940..791e87735f40b 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -29,9 +29,7 @@ use provenance_map::*;
pub use init_mask::{InitChunk, InitChunkIter};
/// Functionality required for the bytes of an `Allocation`.
-pub trait AllocBytes:
- Clone + fmt::Debug + Eq + PartialEq + Hash + Deref + DerefMut
-{
+pub trait AllocBytes: Clone + fmt::Debug + Deref + DerefMut {
/// Create an `AllocBytes` from a slice of `u8`.
fn from_bytes<'a>(slice: impl Into>, _align: Align) -> Self;
@@ -346,10 +344,10 @@ impl Allocation {
}
}
-impl Allocation {
+impl Allocation {
/// Adjust allocation from the ones in `tcx` to a custom Machine instance
- /// with a different `Provenance` and `Extra` type.
- pub fn adjust_from_tcx(
+ /// with a different `Provenance`, `Extra` and `Byte` type.
+ pub fn adjust_from_tcx(
self,
cx: &impl HasDataLayout,
extra: Extra,
@@ -371,7 +369,7 @@ impl Allocation {
}
// Create allocation.
Ok(Allocation {
- bytes,
+ bytes: AllocBytes::from_bytes(Cow::Owned(Vec::from(bytes)), self.align),
provenance: ProvenanceMap::from_presorted_ptrs(new_provenance),
init_mask: self.init_mask,
align: self.align,
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 6d4585cfbc66a..daab6c855819b 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -1,7 +1,9 @@
use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
use crate::ty::{GenericArgs, Instance, InstanceDef, SymbolName, TyCtxt};
use rustc_attr::InlineAttr;
-use rustc_data_structures::base_n;
+use rustc_data_structures::base_n::BaseNString;
+use rustc_data_structures::base_n::ToBaseN;
+use rustc_data_structures::base_n::CASE_INSENSITIVE;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::FxIndexMap;
@@ -337,14 +339,11 @@ impl<'tcx> CodegenUnit<'tcx> {
self.is_code_coverage_dead_code_cgu = true;
}
- pub fn mangle_name(human_readable_name: &str) -> String {
- // We generate a 80 bit hash from the name. This should be enough to
- // avoid collisions and is still reasonably short for filenames.
+ pub fn mangle_name(human_readable_name: &str) -> BaseNString {
let mut hasher = StableHasher::new();
human_readable_name.hash(&mut hasher);
let hash: Hash128 = hasher.finish();
- let hash = hash.as_u128() & ((1u128 << 80) - 1);
- base_n::encode(hash, base_n::CASE_INSENSITIVE)
+ hash.as_u128().to_base_fixed_len(CASE_INSENSITIVE)
}
pub fn compute_size_estimate(&mut self) {
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 4c34bf88c7f96..3ad6b68d1299b 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -273,6 +273,8 @@ pub enum GoalSource {
/// they are from an impl where-clause. This is necessary due to
/// backwards compatability, cc trait-system-refactor-initiatitive#70.
ImplWhereBound,
+ /// Instantiating a higher-ranked goal and re-proving it.
+ InstantiateHigherRanked,
}
/// Possible ways the given goal can be proven.
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index 2d73be387fdcd..11aa0e10931cb 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -127,6 +127,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
let source = match source {
GoalSource::Misc => "misc",
GoalSource::ImplWhereBound => "impl where-bound",
+ GoalSource::InstantiateHigherRanked => "higher-ranked goal",
};
writeln!(this.f, "ADDED GOAL ({source}): {goal:?}")?
}
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 15f048ab598c9..8d7489f5f7e60 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -330,20 +330,19 @@ impl DeepRejectCtxt {
}
pub fn consts_may_unify(self, obligation_ct: ty::Const<'_>, impl_ct: ty::Const<'_>) -> bool {
- match impl_ct.kind() {
+ let impl_val = match impl_ct.kind() {
ty::ConstKind::Expr(_)
| ty::ConstKind::Param(_)
| ty::ConstKind::Unevaluated(_)
| ty::ConstKind::Error(_) => {
return true;
}
- ty::ConstKind::Value(_) => {}
+ ty::ConstKind::Value(impl_val) => impl_val,
ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
bug!("unexpected impl arg: {:?}", impl_ct)
}
- }
+ };
- let k = impl_ct.kind();
match obligation_ct.kind() {
ty::ConstKind::Param(_) => match self.treat_obligation_params {
TreatParams::ForLookup => false,
@@ -358,10 +357,7 @@ impl DeepRejectCtxt {
ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => {
true
}
- ty::ConstKind::Value(obl) => match k {
- ty::ConstKind::Value(imp) => obl == imp,
- _ => true,
- },
+ ty::ConstKind::Value(obl_val) => obl_val == impl_val,
ty::ConstKind::Infer(_) => true,
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index d6e6cc957b4be..794e7ebb7b431 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -566,7 +566,8 @@ fn construct_const<'a, 'tcx>(
span,
..
}) => (*span, ty.span),
- Node::AnonConst(_) | Node::ConstBlock(_) => {
+ Node::AnonConst(ct) => (ct.span, ct.span),
+ Node::ConstBlock(_) => {
let span = tcx.def_span(def);
(span, span)
}
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
index 0119b95cced97..c1f9313a377de 100644
--- a/compiler/rustc_mir_transform/src/copy_prop.rs
+++ b/compiler/rustc_mir_transform/src/copy_prop.rs
@@ -3,7 +3,6 @@ use rustc_index::IndexSlice;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
-use rustc_mir_dataflow::impls::borrowed_locals;
use crate::ssa::SsaLocals;
@@ -32,8 +31,8 @@ impl<'tcx> MirPass<'tcx> for CopyProp {
}
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let borrowed_locals = borrowed_locals(body);
- let ssa = SsaLocals::new(body);
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+ let ssa = SsaLocals::new(tcx, body, param_env);
let fully_moved = fully_moved_locals(&ssa, body);
debug!(?fully_moved);
@@ -51,7 +50,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
tcx,
copy_classes: ssa.copy_classes(),
fully_moved,
- borrowed_locals,
+ borrowed_locals: ssa.borrowed_locals(),
storage_to_remove,
}
.visit_body_preserves_cfg(body);
@@ -101,7 +100,7 @@ struct Replacer<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
fully_moved: BitSet,
storage_to_remove: BitSet,
- borrowed_locals: BitSet,
+ borrowed_locals: &'a BitSet,
copy_classes: &'a IndexSlice,
}
@@ -112,6 +111,12 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
fn visit_local(&mut self, local: &mut Local, ctxt: PlaceContext, _: Location) {
let new_local = self.copy_classes[*local];
+ // We must not unify two locals that are borrowed. But this is fine if one is borrowed and
+ // the other is not. We chose to check the original local, and not the target. That way, if
+ // the original local is borrowed and the target is not, we do not pessimize the whole class.
+ if self.borrowed_locals.contains(*local) {
+ return;
+ }
match ctxt {
// Do not modify the local in storage statements.
PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => {}
@@ -122,32 +127,14 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
}
}
- fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
+ fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Location) {
if let Some(new_projection) = self.process_projection(place.projection, loc) {
place.projection = self.tcx().mk_place_elems(&new_projection);
}
- let observes_address = match ctxt {
- PlaceContext::NonMutatingUse(
- NonMutatingUseContext::SharedBorrow
- | NonMutatingUseContext::FakeBorrow
- | NonMutatingUseContext::AddressOf,
- ) => true,
- // For debuginfo, merging locals is ok.
- PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {
- self.borrowed_locals.contains(place.local)
- }
- _ => false,
- };
- if observes_address && !place.is_indirect() {
- // We observe the address of `place.local`. Do not replace it.
- } else {
- self.visit_local(
- &mut place.local,
- PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
- loc,
- )
- }
+ // Any non-mutating use context is ok.
+ let ctxt = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
+ self.visit_local(&mut place.local, ctxt, loc)
}
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs
index d364658efb6d6..ddbe1333c4b08 100644
--- a/compiler/rustc_mir_transform/src/coverage/mappings.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs
@@ -2,9 +2,8 @@ use std::collections::BTreeSet;
use rustc_data_structures::graph::DirectedGraph;
use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::coverage::{
- BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind, MCDCBranchSpan, MCDCDecisionSpan,
-};
+use rustc_index::IndexVec;
+use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind};
use rustc_middle::mir::{self, BasicBlock, StatementKind};
use rustc_span::Span;
@@ -13,55 +12,53 @@ use crate::coverage::spans::{
extract_refined_covspans, unexpand_into_body_span_with_visible_macro,
};
use crate::coverage::ExtractedHirInfo;
-use rustc_index::IndexVec;
-
-#[derive(Clone, Debug)]
-pub(super) enum BcbMappingKind {
- /// Associates an ordinary executable code span with its corresponding BCB.
- Code(BasicCoverageBlock),
-
- // Ordinary branch mappings are stored separately, so they don't have a
- // variant in this enum.
- //
- /// Associates a mcdc branch span with condition info besides fields for normal branch.
- MCDCBranch {
- true_bcb: BasicCoverageBlock,
- false_bcb: BasicCoverageBlock,
- /// If `None`, this actually represents a normal branch mapping inserted
- /// for code that was too complex for MC/DC.
- condition_info: Option,
- decision_depth: u16,
- },
- /// Associates a mcdc decision with its join BCB.
- MCDCDecision {
- end_bcbs: BTreeSet,
- bitmap_idx: u32,
- conditions_num: u16,
- decision_depth: u16,
- },
-}
+/// Associates an ordinary executable code span with its corresponding BCB.
#[derive(Debug)]
-pub(super) struct BcbMapping {
- pub(super) kind: BcbMappingKind,
+pub(super) struct CodeMapping {
pub(super) span: Span,
+ pub(super) bcb: BasicCoverageBlock,
}
-/// This is separate from [`BcbMappingKind`] to help prepare for larger changes
+/// This is separate from [`MCDCBranch`] to help prepare for larger changes
/// that will be needed for improved branch coverage in the future.
/// (See .)
#[derive(Debug)]
-pub(super) struct BcbBranchPair {
+pub(super) struct BranchPair {
pub(super) span: Span,
pub(super) true_bcb: BasicCoverageBlock,
pub(super) false_bcb: BasicCoverageBlock,
}
+/// Associates an MC/DC branch span with condition info besides fields for normal branch.
+#[derive(Debug)]
+pub(super) struct MCDCBranch {
+ pub(super) span: Span,
+ pub(super) true_bcb: BasicCoverageBlock,
+ pub(super) false_bcb: BasicCoverageBlock,
+ /// If `None`, this actually represents a normal branch mapping inserted
+ /// for code that was too complex for MC/DC.
+ pub(super) condition_info: Option,
+ pub(super) decision_depth: u16,
+}
+
+/// Associates an MC/DC decision with its join BCBs.
+#[derive(Debug)]
+pub(super) struct MCDCDecision {
+ pub(super) span: Span,
+ pub(super) end_bcbs: BTreeSet,
+ pub(super) bitmap_idx: u32,
+ pub(super) conditions_num: u16,
+ pub(super) decision_depth: u16,
+}
+
pub(super) struct CoverageSpans {
bcb_has_mappings: BitSet,
- pub(super) mappings: Vec,
- pub(super) branch_pairs: Vec,
+ pub(super) code_mappings: Vec,
+ pub(super) branch_pairs: Vec,
test_vector_bitmap_bytes: u32,
+ pub(super) mcdc_branches: Vec,
+ pub(super) mcdc_decisions: Vec,
}
impl CoverageSpans {
@@ -83,8 +80,10 @@ pub(super) fn generate_coverage_spans(
hir_info: &ExtractedHirInfo,
basic_coverage_blocks: &CoverageGraph,
) -> Option {
- let mut mappings = vec![];
+ let mut code_mappings = vec![];
let mut branch_pairs = vec![];
+ let mut mcdc_branches = vec![];
+ let mut mcdc_decisions = vec![];
if hir_info.is_async_fn {
// An async function desugars into a function that returns a future,
@@ -92,17 +91,27 @@ pub(super) fn generate_coverage_spans(
// outer function will be unhelpful, so just keep the signature span
// and ignore all of the spans in the MIR body.
if let Some(span) = hir_info.fn_sig_span_extended {
- mappings.push(BcbMapping { kind: BcbMappingKind::Code(START_BCB), span });
+ code_mappings.push(CodeMapping { span, bcb: START_BCB });
}
} else {
- extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut mappings);
+ extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings);
branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks));
- mappings.extend(extract_mcdc_mappings(mir_body, hir_info.body_span, basic_coverage_blocks));
+ extract_mcdc_mappings(
+ mir_body,
+ hir_info.body_span,
+ basic_coverage_blocks,
+ &mut mcdc_branches,
+ &mut mcdc_decisions,
+ );
}
- if mappings.is_empty() && branch_pairs.is_empty() {
+ if code_mappings.is_empty()
+ && branch_pairs.is_empty()
+ && mcdc_branches.is_empty()
+ && mcdc_decisions.is_empty()
+ {
return None;
}
@@ -111,29 +120,36 @@ pub(super) fn generate_coverage_spans(
let mut insert = |bcb| {
bcb_has_mappings.insert(bcb);
};
- let mut test_vector_bitmap_bytes = 0;
- for BcbMapping { kind, span: _ } in &mappings {
- match *kind {
- BcbMappingKind::Code(bcb) => insert(bcb),
- BcbMappingKind::MCDCBranch { true_bcb, false_bcb, .. } => {
- insert(true_bcb);
- insert(false_bcb);
- }
- BcbMappingKind::MCDCDecision { bitmap_idx, conditions_num, .. } => {
- // `bcb_has_mappings` is used for inject coverage counters
- // but they are not needed for decision BCBs.
- // While the length of test vector bitmap should be calculated here.
- test_vector_bitmap_bytes = test_vector_bitmap_bytes
- .max(bitmap_idx + (1_u32 << conditions_num as u32).div_ceil(8));
- }
- }
+
+ for &CodeMapping { span: _, bcb } in &code_mappings {
+ insert(bcb);
+ }
+ for &BranchPair { true_bcb, false_bcb, .. } in &branch_pairs {
+ insert(true_bcb);
+ insert(false_bcb);
}
- for &BcbBranchPair { true_bcb, false_bcb, .. } in &branch_pairs {
+ for &MCDCBranch { true_bcb, false_bcb, .. } in &mcdc_branches {
insert(true_bcb);
insert(false_bcb);
}
- Some(CoverageSpans { bcb_has_mappings, mappings, branch_pairs, test_vector_bitmap_bytes })
+ // Determine the length of the test vector bitmap.
+ let test_vector_bitmap_bytes = mcdc_decisions
+ .iter()
+ .map(|&MCDCDecision { bitmap_idx, conditions_num, .. }| {
+ bitmap_idx + (1_u32 << u32::from(conditions_num)).div_ceil(8)
+ })
+ .max()
+ .unwrap_or(0);
+
+ Some(CoverageSpans {
+ bcb_has_mappings,
+ code_mappings,
+ branch_pairs,
+ test_vector_bitmap_bytes,
+ mcdc_branches,
+ mcdc_decisions,
+ })
}
fn resolve_block_markers(
@@ -167,7 +183,7 @@ pub(super) fn extract_branch_pairs(
mir_body: &mir::Body<'_>,
hir_info: &ExtractedHirInfo,
basic_coverage_blocks: &CoverageGraph,
-) -> Vec {
+) -> Vec {
let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return vec![] };
let block_markers = resolve_block_markers(branch_info, mir_body);
@@ -190,7 +206,7 @@ pub(super) fn extract_branch_pairs(
let true_bcb = bcb_from_marker(true_marker)?;
let false_bcb = bcb_from_marker(false_marker)?;
- Some(BcbBranchPair { span, true_bcb, false_bcb })
+ Some(BranchPair { span, true_bcb, false_bcb })
})
.collect::>()
}
@@ -199,10 +215,10 @@ pub(super) fn extract_mcdc_mappings(
mir_body: &mir::Body<'_>,
body_span: Span,
basic_coverage_blocks: &CoverageGraph,
-) -> Vec {
- let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else {
- return vec![];
- };
+ mcdc_branches: &mut impl Extend,
+ mcdc_decisions: &mut impl Extend,
+) {
+ let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return };
let block_markers = resolve_block_markers(branch_info, mir_body);
@@ -223,53 +239,42 @@ pub(super) fn extract_mcdc_mappings(
Some((span, true_bcb, false_bcb))
};
- let mcdc_branch_filter_map = |&MCDCBranchSpan {
- span: raw_span,
- true_marker,
- false_marker,
- condition_info,
- decision_depth,
- }| {
- check_branch_bcb(raw_span, true_marker, false_marker).map(|(span, true_bcb, false_bcb)| {
- BcbMapping {
- kind: BcbMappingKind::MCDCBranch {
- true_bcb,
- false_bcb,
- condition_info,
- decision_depth,
- },
- span,
- }
- })
- };
+ mcdc_branches.extend(branch_info.mcdc_branch_spans.iter().filter_map(
+ |&mir::coverage::MCDCBranchSpan {
+ span: raw_span,
+ condition_info,
+ true_marker,
+ false_marker,
+ decision_depth,
+ }| {
+ let (span, true_bcb, false_bcb) =
+ check_branch_bcb(raw_span, true_marker, false_marker)?;
+ Some(MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth })
+ },
+ ));
let mut next_bitmap_idx = 0;
- let decision_filter_map = |decision: &MCDCDecisionSpan| {
- let (span, _) = unexpand_into_body_span_with_visible_macro(decision.span, body_span)?;
+ mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map(
+ |decision: &mir::coverage::MCDCDecisionSpan| {
+ let (span, _) = unexpand_into_body_span_with_visible_macro(decision.span, body_span)?;
- let end_bcbs = decision
- .end_markers
- .iter()
- .map(|&marker| bcb_from_marker(marker))
- .collect::