Auto merge of #84198 - mlodato517:patch-1, r=jyn514
Fix small typo in Drop documentation
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 04d0686..c8688fa 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -1094,7 +1094,7 @@
// only place where we have access to the compiler `Session`.
// - LLVM work can be done on any thread.
// - Codegen can only happen on the main thread.
- // - Each thread doing substantial work most be in possession of a `Token`
+ // - Each thread doing substantial work must be in possession of a `Token`
// from the `Jobserver`.
// - The compiler process always holds one `Token`. Any additional `Tokens`
// have to be requested from the `Jobserver`.
@@ -1146,7 +1146,7 @@
// if possible. These two goals are at odds with each other: If memory
// consumption were not an issue, we could just let the main thread produce
// LLVM WorkItems at full speed, assuring maximal utilization of
- // Tokens/LLVM worker threads. However, since codegen usual is faster
+ // Tokens/LLVM worker threads. However, since codegen is usually faster
// than LLVM processing, the queue of LLVM WorkItems would fill up and each
// WorkItem potentially holds on to a substantial amount of memory.
//
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index c4acaef..7f9e459 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1,3 +1,5 @@
+// ignore-tidy-filelength
+
//! Lints in the Rust compiler.
//!
//! This contains lints which can feasibly be implemented as their own
@@ -2964,3 +2966,88 @@
}
}
}
+
+declare_lint! {
+ /// The `deref_nullptr` lint detects when an null pointer is dereferenced,
+ /// which causes [undefined behavior].
+ ///
+ /// ### Example
+ ///
+ /// ```rust,no_run
+ /// # #![allow(unused)]
+ /// use std::ptr;
+ /// unsafe {
+ /// let x = &*ptr::null::<i32>();
+ /// let x = ptr::addr_of!(*ptr::null::<i32>());
+ /// let x = *(0 as *const i32);
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Dereferencing a null pointer causes [undefined behavior] even as a place expression,
+ /// like `&*(0 as *const i32)` or `addr_of!(*(0 as *const i32))`.
+ ///
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ pub DEREF_NULLPTR,
+ Warn,
+ "detects when an null pointer is dereferenced"
+}
+
+declare_lint_pass!(DerefNullPtr => [DEREF_NULLPTR]);
+
+impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
+ /// test if expression is a null ptr
+ fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+ match &expr.kind {
+ rustc_hir::ExprKind::Cast(ref expr, ref ty) => {
+ if let rustc_hir::TyKind::Ptr(_) = ty.kind {
+ return is_zero(expr) || is_null_ptr(cx, expr);
+ }
+ }
+ // check for call to `core::ptr::null` or `core::ptr::null_mut`
+ rustc_hir::ExprKind::Call(ref path, _) => {
+ if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
+ if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
+ return cx.tcx.is_diagnostic_item(sym::ptr_null, def_id)
+ || cx.tcx.is_diagnostic_item(sym::ptr_null_mut, def_id);
+ }
+ }
+ }
+ _ => {}
+ }
+ false
+ }
+
+ /// test if experssion is the literal `0`
+ fn is_zero(expr: &hir::Expr<'_>) -> bool {
+ match &expr.kind {
+ rustc_hir::ExprKind::Lit(ref lit) => {
+ if let LitKind::Int(a, _) = lit.node {
+ return a == 0;
+ }
+ }
+ _ => {}
+ }
+ false
+ }
+
+ if let rustc_hir::ExprKind::Unary(ref un_op, ref expr_deref) = expr.kind {
+ if let rustc_hir::UnOp::Deref = un_op {
+ if is_null_ptr(cx, expr_deref) {
+ cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
+ let mut err = lint.build("dereferencing a null pointer");
+ err.span_label(
+ expr.span,
+ "this code causes undefined behavior when executed",
+ );
+ err.emit();
+ });
+ }
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index e2724b5..2f46969 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -206,6 +206,7 @@
UnreachablePub: UnreachablePub,
ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
InvalidValue: InvalidValue,
+ DerefNullPtr: DerefNullPtr,
]
);
};
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 4b97c8b..ed95a56 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -930,15 +930,38 @@
}
let frame = &self.token_cursor.frame;
- match frame.tree_cursor.look_ahead(dist - 1) {
- Some(tree) => match tree {
- TokenTree::Token(token) => looker(token),
- TokenTree::Delimited(dspan, delim, _) => {
- looker(&Token::new(token::OpenDelim(*delim), dspan.open))
- }
- },
- None => looker(&Token::new(token::CloseDelim(frame.delim), frame.span.close)),
+ if frame.delim != DelimToken::NoDelim {
+ let all_normal = (0..dist).all(|i| {
+ let token = frame.tree_cursor.look_ahead(i);
+ !matches!(token, Some(TokenTree::Delimited(_, DelimToken::NoDelim, _)))
+ });
+ if all_normal {
+ return match frame.tree_cursor.look_ahead(dist - 1) {
+ Some(tree) => match tree {
+ TokenTree::Token(token) => looker(token),
+ TokenTree::Delimited(dspan, delim, _) => {
+ looker(&Token::new(token::OpenDelim(*delim), dspan.open))
+ }
+ },
+ None => looker(&Token::new(token::CloseDelim(frame.delim), frame.span.close)),
+ };
+ }
}
+
+ let mut cursor = self.token_cursor.clone();
+ let mut i = 0;
+ let mut token = Token::dummy();
+ while i < dist {
+ token = cursor.next().0;
+ if matches!(
+ token.kind,
+ token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim)
+ ) {
+ continue;
+ }
+ i += 1;
+ }
+ return looker(&token);
}
/// Returns whether any of the given keywords are `dist` tokens ahead of the current one.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ee1d206..42e521a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -900,6 +900,8 @@
profiler_runtime,
ptr_guaranteed_eq,
ptr_guaranteed_ne,
+ ptr_null,
+ ptr_null_mut,
ptr_offset_from,
pub_macro_rules,
pub_restricted,
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 6e20715..ad8696a 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -211,6 +211,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
+#[rustc_diagnostic_item = "ptr_null"]
pub const fn null<T>() -> *const T {
0 as *const T
}
@@ -229,6 +230,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
+#[rustc_diagnostic_item = "ptr_null_mut"]
pub const fn null_mut<T>() -> *mut T {
0 as *mut T
}
diff --git a/library/std/src/sys_common/alloc.rs b/library/std/src/sys/common/alloc.rs
similarity index 98%
rename from library/std/src/sys_common/alloc.rs
rename to library/std/src/sys/common/alloc.rs
index 6c1bc0d..2a54e99 100644
--- a/library/std/src/sys_common/alloc.rs
+++ b/library/std/src/sys/common/alloc.rs
@@ -1,5 +1,3 @@
-#![allow(dead_code)]
-
use crate::alloc::{GlobalAlloc, Layout, System};
use crate::cmp;
use crate::ptr;
diff --git a/library/std/src/sys/common/mod.rs b/library/std/src/sys/common/mod.rs
new file mode 100644
index 0000000..ff64d2a
--- /dev/null
+++ b/library/std/src/sys/common/mod.rs
@@ -0,0 +1,13 @@
+// This module contains code that is shared between all platforms, mostly utility or fallback code.
+// This explicitly does not include code that is shared between only a few platforms,
+// such as when reusing an implementation from `unix` or `unsupported`.
+// In those cases the desired code should be included directly using the #[path] attribute,
+// not moved to this module.
+//
+// Currently `sys_common` contains a lot of code that should live in this module,
+// ideally `sys_common` would only contain platform-independent abstractions on top of `sys`.
+// Progress on this is tracked in #84187.
+
+#![allow(dead_code)]
+
+pub mod alloc;
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 9b35939..50c2660 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -22,6 +22,8 @@
#![allow(missing_debug_implementations)]
+mod common;
+
cfg_if::cfg_if! {
if #[cfg(target_os = "vxworks")] {
mod vxworks;
diff --git a/library/std/src/sys/unix/alloc.rs b/library/std/src/sys/unix/alloc.rs
index 964abe8..1b71905 100644
--- a/library/std/src/sys/unix/alloc.rs
+++ b/library/std/src/sys/unix/alloc.rs
@@ -1,6 +1,6 @@
use crate::alloc::{GlobalAlloc, Layout, System};
use crate::ptr;
-use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN};
+use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN};
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 4a077e2..ce2c4e8 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -223,7 +223,7 @@
impl fmt::Display for JoinPathsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "path segment contains separator `{}`", PATH_SEPARATOR)
+ write!(f, "path segment contains separator `{}`", char::from(PATH_SEPARATOR))
}
}
diff --git a/library/std/src/sys/windows/alloc.rs b/library/std/src/sys/windows/alloc.rs
index af93cd7..2fe71f9 100644
--- a/library/std/src/sys/windows/alloc.rs
+++ b/library/std/src/sys/windows/alloc.rs
@@ -5,7 +5,7 @@
use crate::ptr;
use crate::sync::atomic::{AtomicPtr, Ordering};
use crate::sys::c;
-use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN};
+use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN};
#[cfg(test)]
mod tests;
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 660f0e0..23a3a0e 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -8,9 +8,11 @@
//! rest of `std` is complex, with dependencies going in all
//! directions: `std` depending on `sys_common`, `sys_common`
//! depending on `sys`, and `sys` depending on `sys_common` and `std`.
-//! Ideally `sys_common` would be split into two and the dependencies
-//! between them all would form a dag, facilitating the extraction of
-//! `std::sys` from the standard library.
+//! This is because `sys_common` not only contains platform-independent code,
+//! but also code that is shared between the different platforms in `sys`.
+//! Ideally all that shared code should be moved to `sys::common`,
+//! and the dependencies between `std`, `sys_common` and `sys` all would form a dag.
+//! Progress on this is tracked in #84187.
#![allow(missing_docs)]
#![allow(missing_debug_implementations)]
@@ -46,7 +48,6 @@
};
}
-pub mod alloc;
pub mod at_exit_imp;
pub mod backtrace;
pub mod bytestring;
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
index d3f2ace..569c339 160000
--- a/src/doc/embedded-book
+++ b/src/doc/embedded-book
@@ -1 +1 @@
-Subproject commit d3f2ace94d51610cf3e3c265705bb8416d37f8e4
+Subproject commit 569c3391f5c0cc43433bc77831d17f8ff4d76602
diff --git a/src/doc/nomicon b/src/doc/nomicon
index 6fe4769..8551afb 160000
--- a/src/doc/nomicon
+++ b/src/doc/nomicon
@@ -1 +1 @@
-Subproject commit 6fe476943afd53a9a6e91f38a6ea7bb48811d8ff
+Subproject commit 8551afbb2ca6f5ea37fe58380318b209785e4e02
diff --git a/src/doc/reference b/src/doc/reference
index fd97729..e1abb17 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit fd97729e2d82f8b08d68a31c9bfdf0c37a7fd542
+Subproject commit e1abb17cd94cd5a8a374b48e1bc8134a2208ed48
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
index 29d91f5..c80f0b0 160000
--- a/src/doc/rust-by-example
+++ b/src/doc/rust-by-example
@@ -1 +1 @@
-Subproject commit 29d91f591c90dd18fdca6d23f1a9caf9c139d0d7
+Subproject commit c80f0b09fc15b9251825343be910c08531938ab2
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
index 0687daa..a9bd2bb 160000
--- a/src/doc/rustc-dev-guide
+++ b/src/doc/rustc-dev-guide
@@ -1 +1 @@
-Subproject commit 0687daac28939c476df51778f5a1d1aff1a3fddf
+Subproject commit a9bd2bbf31e4f92b5d3d8e80b22839d0cc7a2022
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 6342110..4ce7c70 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1972,6 +1972,10 @@
if let Some(sp) = sp {
diag.span_label(sp, "contains invalid anchor");
}
+ if let AnchorFailure::RustdocAnchorConflict(Res::Primitive(_)) = failure {
+ diag.note("this restriction may be lifted in a future release");
+ diag.note("see https://github.com/rust-lang/rust/issues/83083 for more information");
+ }
});
}
diff --git a/src/test/rustdoc-ui/intra-doc/anchors.stderr b/src/test/rustdoc-ui/intra-doc/anchors.stderr
index 787a68e..42a8832 100644
--- a/src/test/rustdoc-ui/intra-doc/anchors.stderr
+++ b/src/test/rustdoc-ui/intra-doc/anchors.stderr
@@ -9,6 +9,8 @@
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: this restriction may be lifted in a future release
+ = note: see https://github.com/rust-lang/rust/issues/83083 for more information
error: `Foo::f#hola` contains an anchor, but links to fields are already anchored
--> $DIR/anchors.rs:25:15
@@ -33,6 +35,9 @@
|
LL | /// [u32#hello]
| ^^^^^^^^^ contains invalid anchor
+ |
+ = note: this restriction may be lifted in a future release
+ = note: see https://github.com/rust-lang/rust/issues/83083 for more information
error: aborting due to 5 previous errors
diff --git a/src/test/ui/cleanup-shortcircuit.rs b/src/test/ui/cleanup-shortcircuit.rs
index 4f5197a..fe867ce 100644
--- a/src/test/ui/cleanup-shortcircuit.rs
+++ b/src/test/ui/cleanup-shortcircuit.rs
@@ -3,6 +3,9 @@
// pretty-expanded FIXME #23616
+#![allow(deref_nullptr)]
+
+
use std::env;
pub fn main() {
diff --git a/src/test/ui/lint/lint-deref-nullptr.rs b/src/test/ui/lint/lint-deref-nullptr.rs
new file mode 100644
index 0000000..d052dbd
--- /dev/null
+++ b/src/test/ui/lint/lint-deref-nullptr.rs
@@ -0,0 +1,38 @@
+// test the deref_nullptr lint
+
+#![deny(deref_nullptr)]
+
+use std::ptr;
+
+struct Struct {
+ field: u8,
+}
+
+fn f() {
+ unsafe {
+ let a = 1;
+ let ub = *(a as *const i32);
+ let ub = *(0 as *const i32);
+ //~^ ERROR dereferencing a null pointer
+ let ub = *ptr::null::<i32>();
+ //~^ ERROR dereferencing a null pointer
+ let ub = *ptr::null_mut::<i32>();
+ //~^ ERROR dereferencing a null pointer
+ let ub = *(ptr::null::<i16>() as *const i32);
+ //~^ ERROR dereferencing a null pointer
+ let ub = *(ptr::null::<i16>() as *mut i32 as *mut usize as *const u8);
+ //~^ ERROR dereferencing a null pointer
+ let ub = &*ptr::null::<i32>();
+ //~^ ERROR dereferencing a null pointer
+ let ub = &*ptr::null_mut::<i32>();
+ //~^ ERROR dereferencing a null pointer
+ ptr::addr_of!(*ptr::null::<i32>());
+ //~^ ERROR dereferencing a null pointer
+ ptr::addr_of_mut!(*ptr::null_mut::<i32>());
+ //~^ ERROR dereferencing a null pointer
+ let offset = ptr::addr_of!((*ptr::null::<Struct>()).field);
+ //~^ ERROR dereferencing a null pointer
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-deref-nullptr.stderr b/src/test/ui/lint/lint-deref-nullptr.stderr
new file mode 100644
index 0000000..c6f432e
--- /dev/null
+++ b/src/test/ui/lint/lint-deref-nullptr.stderr
@@ -0,0 +1,68 @@
+error: dereferencing a null pointer
+ --> $DIR/lint-deref-nullptr.rs:15:18
+ |
+LL | let ub = *(0 as *const i32);
+ | ^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+ |
+note: the lint level is defined here
+ --> $DIR/lint-deref-nullptr.rs:3:9
+ |
+LL | #![deny(deref_nullptr)]
+ | ^^^^^^^^^^^^^
+
+error: dereferencing a null pointer
+ --> $DIR/lint-deref-nullptr.rs:17:18
+ |
+LL | let ub = *ptr::null::<i32>();
+ | ^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+
+error: dereferencing a null pointer
+ --> $DIR/lint-deref-nullptr.rs:19:18
+ |
+LL | let ub = *ptr::null_mut::<i32>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+
+error: dereferencing a null pointer
+ --> $DIR/lint-deref-nullptr.rs:21:18
+ |
+LL | let ub = *(ptr::null::<i16>() as *const i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+
+error: dereferencing a null pointer
+ --> $DIR/lint-deref-nullptr.rs:23:18
+ |
+LL | let ub = *(ptr::null::<i16>() as *mut i32 as *mut usize as *const u8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+
+error: dereferencing a null pointer
+ --> $DIR/lint-deref-nullptr.rs:25:19
+ |
+LL | let ub = &*ptr::null::<i32>();
+ | ^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+
+error: dereferencing a null pointer
+ --> $DIR/lint-deref-nullptr.rs:27:19
+ |
+LL | let ub = &*ptr::null_mut::<i32>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+
+error: dereferencing a null pointer
+ --> $DIR/lint-deref-nullptr.rs:29:23
+ |
+LL | ptr::addr_of!(*ptr::null::<i32>());
+ | ^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+
+error: dereferencing a null pointer
+ --> $DIR/lint-deref-nullptr.rs:31:27
+ |
+LL | ptr::addr_of_mut!(*ptr::null_mut::<i32>());
+ | ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+
+error: dereferencing a null pointer
+ --> $DIR/lint-deref-nullptr.rs:33:36
+ |
+LL | let offset = ptr::addr_of!((*ptr::null::<Struct>()).field);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+
+error: aborting due to 10 previous errors
+
diff --git a/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs b/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs
new file mode 100644
index 0000000..f5a97ec
--- /dev/null
+++ b/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs
@@ -0,0 +1,20 @@
+// edition:2021
+#![allow(unused_macros)]
+macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+macro_rules! qux { ($x:pat, $y:pat) => {} } // should be ok
+macro_rules! match_any {
+ ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { //~ ERROR `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments
+ match $expr {
+ $(
+ $( $pat => $expr_arm, )+
+ )+
+ }
+ };
+}
+
+fn main() {
+ let result: Result<i64, i32> = Err(42);
+ let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into());
+ assert_eq!(int, 42);
+}
diff --git a/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr b/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr
new file mode 100644
index 0000000..a5987a2
--- /dev/null
+++ b/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr
@@ -0,0 +1,26 @@
+error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+ --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:3:28
+ |
+LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
+ | ^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
+
+error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+ --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:4:32
+ |
+LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
+ | ^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
+
+error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments
+ --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:7:36
+ |
+LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
+ | ^ not allowed after `pat` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/macros/macro-pat-pattern-followed-by-or.rs b/src/test/ui/macros/macro-pat-pattern-followed-by-or.rs
new file mode 100644
index 0000000..54bd13d
--- /dev/null
+++ b/src/test/ui/macros/macro-pat-pattern-followed-by-or.rs
@@ -0,0 +1,20 @@
+// run-pass
+#![allow(unused_macros)]
+macro_rules! foo { ($x:pat | $y:pat) => {} } // should be ok
+macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } // should be ok
+macro_rules! qux { ($x:pat, $y:pat) => {} } // should be ok
+macro_rules! match_any {
+ ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { // should be ok
+ match $expr {
+ $(
+ $( $pat => $expr_arm, )+
+ )+
+ }
+ };
+}
+
+fn main() {
+ let result: Result<i64, i32> = Err(42);
+ let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into());
+ assert_eq!(int, 42);
+}
diff --git a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.rs b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.rs
new file mode 100644
index 0000000..edd3f3e
--- /dev/null
+++ b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.rs
@@ -0,0 +1,21 @@
+#![feature(edition_macro_pats)]
+#![allow(unused_macros)]
+macro_rules! foo { ($x:pat2021 | $y:pat2021) => {} } //~ ERROR `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments
+macro_rules! baz { ($x:pat2015 | $y:pat2015) => {} } // should be ok
+macro_rules! qux { ($x:pat2015 | $y:pat2021) => {} } // should be ok
+macro_rules! ogg { ($x:pat2021 | $y:pat2015) => {} } //~ ERROR `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments
+macro_rules! match_any {
+ ( $expr:expr , $( $( $pat:pat2021 )|+ => $expr_arm:pat2021 ),+ ) => { //~ ERROR `$pat:pat2021` may be followed by `|`, which is not allowed for `pat2021` fragments
+ match $expr {
+ $(
+ $( $pat => $expr_arm, )+
+ )+
+ }
+ };
+}
+
+fn main() {
+ let result: Result<i64, i32> = Err(42);
+ let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into());
+ assert_eq!(int, 42);
+}
diff --git a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
new file mode 100644
index 0000000..fe0b40c
--- /dev/null
+++ b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
@@ -0,0 +1,26 @@
+error: `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments
+ --> $DIR/macro-pat2021-pattern-followed-by-or.rs:3:32
+ |
+LL | macro_rules! foo { ($x:pat2021 | $y:pat2021) => {} }
+ | ^ not allowed after `pat2021` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
+
+error: `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments
+ --> $DIR/macro-pat2021-pattern-followed-by-or.rs:6:32
+ |
+LL | macro_rules! ogg { ($x:pat2021 | $y:pat2015) => {} }
+ | ^ not allowed after `pat2021` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
+
+error: `$pat:pat2021` may be followed by `|`, which is not allowed for `pat2021` fragments
+ --> $DIR/macro-pat2021-pattern-followed-by-or.rs:8:40
+ |
+LL | ( $expr:expr , $( $( $pat:pat2021 )|+ => $expr_arm:pat2021 ),+ ) => {
+ | ^ not allowed after `pat2021` fragments
+ |
+ = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/macros/none-delim-lookahead.rs b/src/test/ui/macros/none-delim-lookahead.rs
new file mode 100644
index 0000000..bf4fddea
--- /dev/null
+++ b/src/test/ui/macros/none-delim-lookahead.rs
@@ -0,0 +1,15 @@
+// check-pass
+
+macro_rules! make_struct {
+ ($name:ident) => {
+ #[derive(Debug)]
+ struct Foo {
+ #[cfg(not(FALSE))]
+ field: fn($name: bool)
+ }
+ }
+}
+
+make_struct!(param_name);
+
+fn main() {}
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
index 19e09a4..7be0613 160000
--- a/src/tools/rust-analyzer
+++ b/src/tools/rust-analyzer
@@ -1 +1 @@
-Subproject commit 19e09a4a54c75312aeaac04577f2d0e067463ab6
+Subproject commit 7be06139b632ee615fc18af04dd67947e2c794b2