From eb9292327612fda86d0e34528a5cf4045688d002 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 20 Apr 2024 18:14:19 -0400 Subject: [PATCH 01/13] Bump elided_lifetimes_in_associated_constant --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 472e93d202d76..504707bb5a1a6 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4617,7 +4617,7 @@ declare_lint! { /// [against]: https://github.com/rust-lang/rust/issues/38831 /// [future-incompatible]: ../index.md#future-incompatible-lints pub ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, - Warn, + Deny, "elided lifetimes cannot be used in associated constants in impls", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, From 90cbd0bfb4dd973b69cbea9509073eba4a33f6ce Mon Sep 17 00:00:00 2001 From: Sky Date: Fri, 28 Jun 2024 14:05:45 -0400 Subject: [PATCH 02/13] impl FusedIterator and a size hint for the error sources iter --- library/core/src/error.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 150e4f3f31857..ca8983d4cbcfe 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -1008,8 +1008,15 @@ impl<'a> Iterator for Source<'a> { self.current = self.current.and_then(Error::source); current } + + fn size_hint(&self) -> (usize, Option) { + if self.current.is_some() { (1, None) } else { (0, Some(0)) } + } } +#[unstable(feature = "error_iter", issue = "58520")] +impl<'a> crate::iter::FusedIterator for Source<'a> {} + #[stable(feature = "error_by_ref", since = "1.51.0")] impl<'a, T: Error + ?Sized> Error for &'a T { #[allow(deprecated, deprecated_in_future)] From 54aa9e8ba2efe68bfcf5c407a5a9cf1a8d17b354 Mon Sep 17 00:00:00 2001 From: Charles Celerier Date: Sat, 6 Jul 2024 05:15:38 +0000 Subject: [PATCH 03/13] [fuchsia-test-runner] Remove runner logs from stdout and stderr Many tests use stdout and stderr to validate whether the test emitted the correct output. Because fuchsia-test-runner.py was sending all logs, including test output, to stdout, tests could not validate output properly. This change removes the runner logs from stdout and stderr entirely with the exception of output from the test. All runner logs are still available in the "log" file. Fixed: https://fxbug.dev/351356417 --- src/ci/docker/scripts/fuchsia-test-runner.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 6db25ff1a809e..1a2e69712a92f 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -271,13 +271,6 @@ def setup_logging(self, log_to_file=False): logfile_handler.setLevel(logging.DEBUG) logfile_handler.setFormatter(fs) logging.getLogger().addHandler(logfile_handler) - stream_handler = logging.StreamHandler(sys.stdout) - stream_handler.setFormatter(fs) - if self.verbose: - stream_handler.setLevel(logging.DEBUG) - else: - stream_handler.setLevel(logging.INFO) - logging.getLogger().addHandler(stream_handler) logging.getLogger().setLevel(logging.DEBUG) @property @@ -927,7 +920,7 @@ def run(self, args): ) else: with open(stdout_path, encoding="utf-8", errors="ignore") as f: - runner_logger.info(f.read()) + sys.stdout.write(f.read()) if stderr_path is not None: if not os.path.exists(stderr_path): runner_logger.error( @@ -935,7 +928,7 @@ def run(self, args): ) else: with open(stderr_path, encoding="utf-8", errors="ignore") as f: - runner_logger.error(f.read()) + sys.stderr.write(f.read()) runner_logger.info("Done!") return return_code From 3d5b4d8f7cd721ded6589edc2e6e350a8575848f Mon Sep 17 00:00:00 2001 From: Charles Celerier Date: Sun, 7 Jul 2024 15:33:31 +0000 Subject: [PATCH 04/13] [fuchsia-test-runner] Reformat fuchsia-test-runner.py Applied formatting suggestions from isort and black via pylsp. --- src/ci/docker/scripts/fuchsia-test-runner.py | 52 ++++++-------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 1a2e69712a92f..00269e68422d3 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -8,8 +8,6 @@ """ import argparse -from concurrent.futures import ThreadPoolExecutor -from dataclasses import dataclass import glob import io import json @@ -20,6 +18,8 @@ import shutil import subprocess import sys +from concurrent.futures import ThreadPoolExecutor +from dataclasses import dataclass from pathlib import Path from typing import ClassVar, List, Optional @@ -42,12 +42,8 @@ def exhaust_pipe(handler, pipe): for line in pipe: handler(line.rstrip()) - executor_out = executor.submit( - exhaust_pipe, stdout_handler, process.stdout - ) - executor_err = executor.submit( - exhaust_pipe, stderr_handler, process.stderr - ) + executor_out = executor.submit(exhaust_pipe, stdout_handler, process.stdout) + executor_err = executor.submit(exhaust_pipe, stderr_handler, process.stderr) executor_out.result() executor_err.result() retcode = process.poll() @@ -203,9 +199,7 @@ def build_id(self, binary): raise Exception(f"Unreadable build-id for binary {binary}") data = json.loads(process.stdout) if len(data) != 1: - raise Exception( - f"Unreadable output from llvm-readelf for binary {binary}" - ) + raise Exception(f"Unreadable output from llvm-readelf for binary {binary}") notes = data[0]["Notes"] for note in notes: note_section = note["NoteSection"] @@ -265,9 +259,7 @@ def write_to_file(self): def setup_logging(self, log_to_file=False): fs = logging.Formatter("%(asctime)s %(levelname)s:%(name)s:%(message)s") if log_to_file: - logfile_handler = logging.FileHandler( - self.tmp_dir().joinpath("log") - ) + logfile_handler = logging.FileHandler(self.tmp_dir().joinpath("log")) logfile_handler.setLevel(logging.DEBUG) logfile_handler.setFormatter(fs) logging.getLogger().addHandler(logfile_handler) @@ -447,9 +439,7 @@ def start(self): # Initialize temp directory os.makedirs(self.tmp_dir(), exist_ok=True) if len(os.listdir(self.tmp_dir())) != 0: - raise Exception( - f"Temp directory is not clean (in {self.tmp_dir()})" - ) + raise Exception(f"Temp directory is not clean (in {self.tmp_dir()})") self.setup_logging(log_to_file=True) os.mkdir(self.output_dir) @@ -486,9 +476,7 @@ def start(self): shutil.rmtree(self.local_pb_path, ignore_errors=True) # Look up the product bundle transfer manifest. - self.env_logger.info( - "Looking up the product bundle transfer manifest..." - ) + self.env_logger.info("Looking up the product bundle transfer manifest...") product_name = "minimal." + self.triple_to_arch(self.target) sdk_version = self.read_sdk_version() @@ -510,9 +498,7 @@ def start(self): ) try: - transfer_manifest_url = json.loads(output)[ - "transfer_manifest_url" - ] + transfer_manifest_url = json.loads(output)["transfer_manifest_url"] except Exception as e: print(e) raise Exception("Unable to parse transfer manifest") from e @@ -762,9 +748,7 @@ def run(self, args): # Use /tmp as the test temporary directory env_vars += '\n "RUST_TEST_TMPDIR=/tmp",' - cml.write( - self.CML_TEMPLATE.format(env_vars=env_vars, exe_name=exe_name) - ) + cml.write(self.CML_TEMPLATE.format(env_vars=env_vars, exe_name=exe_name)) runner_logger.info("Compiling CML...") @@ -915,17 +899,13 @@ def run(self, args): if stdout_path is not None: if not os.path.exists(stdout_path): - runner_logger.error( - f"stdout file {stdout_path} does not exist." - ) + runner_logger.error(f"stdout file {stdout_path} does not exist.") else: with open(stdout_path, encoding="utf-8", errors="ignore") as f: sys.stdout.write(f.read()) if stderr_path is not None: if not os.path.exists(stderr_path): - runner_logger.error( - f"stderr file {stderr_path} does not exist." - ) + runner_logger.error(f"stderr file {stderr_path} does not exist.") else: with open(stderr_path, encoding="utf-8", errors="ignore") as f: sys.stderr.write(f.read()) @@ -1030,7 +1010,7 @@ def debug(self, args): f"--symbol-path={self.rust_dir}/lib/rustlib/{self.target}/lib", ] - # Add rust source if it's available + # Add rust source if it's available rust_src_map = None if args.rust_src is not None: # This matches the remapped prefix used by compiletest. There's no @@ -1203,7 +1183,7 @@ def print_help(args): start_parser.add_argument( "--use-local-product-bundle-if-exists", help="if the product bundle already exists in the local path, use " - "it instead of downloading it again", + "it instead of downloading it again", action="store_true", ) start_parser.set_defaults(func=start) @@ -1239,9 +1219,7 @@ def print_help(args): ) cleanup_parser.set_defaults(func=cleanup) - syslog_parser = subparsers.add_parser( - "syslog", help="prints the device syslog" - ) + syslog_parser = subparsers.add_parser("syslog", help="prints the device syslog") syslog_parser.set_defaults(func=syslog) debug_parser = subparsers.add_parser( From ec662e7606c9d03de536bbf46dbdeb0d6140bc85 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:12:31 +0200 Subject: [PATCH 05/13] `#[doc(alias)]`'s doc: say that ASCII spaces are allowed --- src/doc/rustdoc/src/advanced-features.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index 1733c8fc9a246..4a1c091625320 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -80,7 +80,8 @@ pub struct BigX; Then, when looking for it through the `rustdoc` search, if you enter "x" or "big", search will show the `BigX` struct first. -There are some limitations on the doc alias names though: you can't use `"` or whitespace. +There are some limitations on the doc alias names though: they cannot contain quotes (`'`, `"`) +or most whitespace. ASCII space is allowed if it does not start or end the alias. You can add multiple aliases at the same time by using a list: From 7097dbc50c086b652c37374cfbed6a40bf30efaf Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 9 Jul 2024 09:10:19 +0200 Subject: [PATCH 06/13] exhaustively destructure external constraints --- compiler/rustc_next_trait_solver/src/solve/mod.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 24055d6cd832b..c65c5851e9b4f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -48,12 +48,20 @@ enum GoalEvaluationKind { Nested, } +// FIXME(trait-system-refactor-initiative#117): we don't detect whether a response +// ended up pulling down any universes. fn has_no_inference_or_external_constraints( response: ty::Canonical>, ) -> bool { - response.value.external_constraints.region_constraints.is_empty() - && response.value.var_values.is_identity() - && response.value.external_constraints.opaque_types.is_empty() + let ExternalConstraintsData { + ref region_constraints, + ref opaque_types, + ref normalization_nested_goals, + } = *response.value.external_constraints; + response.value.var_values.is_identity() + && region_constraints.is_empty() + && opaque_types.is_empty() + && normalization_nested_goals.is_empty() } impl<'a, D, I> EvalCtxt<'a, D> From e38109d7f0e48a995c73a70a084630560bbcbcc0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 9 Jul 2024 09:22:58 +0200 Subject: [PATCH 07/13] use `update_parent_goal` for lazy updates --- .../src/solve/search_graph.rs | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 2cd3b10f56adb..f8a50913f05f8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -139,18 +139,11 @@ impl SearchGraph { self.mode } - /// Pops the highest goal from the stack, lazily updating the - /// the next goal in the stack. - /// - /// Directly popping from the stack instead of using this method - /// would cause us to not track overflow and recursion depth correctly. - fn pop_stack(&mut self) -> StackEntry { - let elem = self.stack.pop().unwrap(); - if let Some(last) = self.stack.raw.last_mut() { - last.reached_depth = last.reached_depth.max(elem.reached_depth); - last.encountered_overflow |= elem.encountered_overflow; + fn update_parent_goal(&mut self, reached_depth: StackDepth, encountered_overflow: bool) { + if let Some(parent) = self.stack.raw.last_mut() { + parent.reached_depth = parent.reached_depth.max(reached_depth); + parent.encountered_overflow |= encountered_overflow; } - elem } pub(super) fn is_empty(&self) -> bool { @@ -364,7 +357,7 @@ impl SearchGraph { } debug!("canonical cycle overflow"); - let current_entry = self.pop_stack(); + let current_entry = self.stack.pop().unwrap(); debug_assert!(current_entry.has_been_used.is_empty()); let result = Self::response_no_constraints(cx, input, Certainty::overflow(false)); (current_entry, result) @@ -372,6 +365,8 @@ impl SearchGraph { let proof_tree = inspect.finalize_canonical_goal_evaluation(cx); + self.update_parent_goal(final_entry.reached_depth, final_entry.encountered_overflow); + // We're now done with this goal. In case this goal is involved in a larger cycle // do not remove it from the provisional cache and update its provisional result. // We only add the root of cycles to the global cache. @@ -441,14 +436,9 @@ impl SearchGraph { } } - // Update the reached depth of the current goal to make sure - // its state is the same regardless of whether we've used the - // global cache or not. + // Adjust the parent goal as if we actually computed this goal. let reached_depth = self.stack.next_index().plus(additional_depth); - if let Some(last) = self.stack.raw.last_mut() { - last.reached_depth = last.reached_depth.max(reached_depth); - last.encountered_overflow |= encountered_overflow; - } + self.update_parent_goal(reached_depth, encountered_overflow); Some(result) } @@ -477,7 +467,7 @@ impl SearchGraph { F: FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, { let result = prove_goal(self, inspect); - let stack_entry = self.pop_stack(); + let stack_entry = self.stack.pop().unwrap(); debug_assert_eq!(stack_entry.input, input); // If the current goal is not the root of a cycle, we are done. From dd175feb25bc09484a74994a1b80af290eeb6509 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 9 Jul 2024 09:39:13 +0200 Subject: [PATCH 08/13] cycle_participants to nested_goals --- .../src/solve/search_graph.rs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index f8a50913f05f8..69d52dcad7a59 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -71,7 +71,7 @@ struct StackEntry { /// C :- D /// D :- C /// ``` - cycle_participants: HashSet>, + nested_goals: HashSet>, /// Starts out as `None` and gets set when rerunning this /// goal in case we encounter a cycle. provisional_result: Option>, @@ -215,8 +215,8 @@ impl SearchGraph { let current_cycle_root = &mut stack[current_root.as_usize()]; for entry in cycle_participants { entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head)); - current_cycle_root.cycle_participants.insert(entry.input); - current_cycle_root.cycle_participants.extend(mem::take(&mut entry.cycle_participants)); + current_cycle_root.nested_goals.insert(entry.input); + current_cycle_root.nested_goals.extend(mem::take(&mut entry.nested_goals)); } } @@ -335,7 +335,7 @@ impl SearchGraph { non_root_cycle_participant: None, encountered_overflow: false, has_been_used: HasBeenUsed::empty(), - cycle_participants: Default::default(), + nested_goals: Default::default(), provisional_result: None, }; assert_eq!(self.stack.push(entry), depth); @@ -389,7 +389,7 @@ impl SearchGraph { // // We must not use the global cache entry of a root goal if a cycle // participant is on the stack. This is necessary to prevent unstable - // results. See the comment of `StackEntry::cycle_participants` for + // results. See the comment of `StackEntry::nested_goals` for // more details. self.global_cache(cx).insert( cx, @@ -397,7 +397,7 @@ impl SearchGraph { proof_tree, reached_depth, final_entry.encountered_overflow, - final_entry.cycle_participants, + final_entry.nested_goals, dep_node, result, ) @@ -544,27 +544,27 @@ impl SearchGraph { non_root_cycle_participant, encountered_overflow: _, has_been_used, - ref cycle_participants, + ref nested_goals, provisional_result, } = *entry; let cache_entry = provisional_cache.get(&entry.input).unwrap(); assert_eq!(cache_entry.stack_depth, Some(depth)); if let Some(head) = non_root_cycle_participant { assert!(head < depth); - assert!(cycle_participants.is_empty()); + assert!(nested_goals.is_empty()); assert_ne!(stack[head].has_been_used, HasBeenUsed::empty()); let mut current_root = head; while let Some(parent) = stack[current_root].non_root_cycle_participant { current_root = parent; } - assert!(stack[current_root].cycle_participants.contains(&input)); + assert!(stack[current_root].nested_goals.contains(&input)); } - if !cycle_participants.is_empty() { + if !nested_goals.is_empty() { assert!(provisional_result.is_some() || !has_been_used.is_empty()); for entry in stack.iter().take(depth.as_usize()) { - assert_eq!(cycle_participants.get(&entry.input), None); + assert_eq!(nested_goals.get(&entry.input), None); } } } From 4700b5b01f51d2436b0cf1674f22eb6a72bb66c9 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 9 Jul 2024 12:50:47 -0300 Subject: [PATCH 09/13] Remove spastorino from SMIR --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 8ae454d412a6f..351ae1642f0e0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1051,7 +1051,6 @@ project-const-traits = [ project-stable-mir = [ "@celinval", "@oli-obk", - "@spastorino", "@ouz-a", ] From 25637e2c8e69317d61e25acd0bf2129b3507693d Mon Sep 17 00:00:00 2001 From: Vincenzo Palazzo Date: Sat, 25 May 2024 08:44:24 +0000 Subject: [PATCH 10/13] Adds expr_2024 migration lit This is adding a migration lint for the current (in the 2021 edition and previous) to move expr to expr_2021 from expr Co-Developed-by: Eric Holk Signed-off-by: Vincenzo Palazzo --- compiler/rustc_lint/messages.ftl | 3 + compiler/rustc_lint/src/lib.rs | 3 + compiler/rustc_lint/src/lints.rs | 7 + ..._expr_fragment_specifier_2024_migration.rs | 155 ++++++++++++++++++ 4 files changed, 168 insertions(+) create mode 100644 compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 3e952558d29d3..f048f6fe8ad4b 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -439,6 +439,9 @@ lint_lintpass_by_hand = implementing `LintPass` by hand lint_macro_expanded_macro_exports_accessed_by_absolute_paths = macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths .note = the macro is defined here +lint_macro_expr_fragment_specifier_2024_migration = + the `expr` fragment specifier will accept more expressions in the 2024 edition + .suggestion = to keep the existing behavior, use the `expr_2021` fragment specifier lint_macro_is_private = macro `{$ident}` is private lint_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 17f9d4421aef2..868a44a980a0f 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -60,6 +60,7 @@ mod late; mod let_underscore; mod levels; mod lints; +mod macro_expr_fragment_specifier_2024_migration; mod map_unit_fn; mod methods; mod multiple_supertrait_upcastable; @@ -97,6 +98,7 @@ use impl_trait_overcaptures::ImplTraitOvercaptures; use internal::*; use invalid_from_utf8::*; use let_underscore::*; +use macro_expr_fragment_specifier_2024_migration::*; use map_unit_fn::*; use methods::*; use multiple_supertrait_upcastable::*; @@ -170,6 +172,7 @@ early_lint_methods!( IncompleteInternalFeatures: IncompleteInternalFeatures, RedundantSemicolons: RedundantSemicolons, UnusedDocComment: UnusedDocComment, + Expr2024: Expr2024, ] ] ); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 7c5640f5959a0..54c73710eca6f 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -317,6 +317,13 @@ pub struct BuiltinTypeAliasGenericBounds<'a, 'b> { pub sub: Option>, } +#[derive(LintDiagnostic)] +#[diag(lint_macro_expr_fragment_specifier_2024_migration)] +pub struct MacroExprFragment2024 { + #[suggestion(code = "expr_2021", applicability = "machine-applicable")] + pub suggestion: Span, +} + pub struct BuiltinTypeAliasGenericBoundsSuggestion { pub suggestions: Vec<(Span, String)>, } diff --git a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs new file mode 100644 index 0000000000000..867e132b1063e --- /dev/null +++ b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs @@ -0,0 +1,155 @@ +//! Migration code for the `expr_fragment_specifier_2024` +//! rule. +use tracing::debug; + +use rustc_ast::token::Token; +use rustc_ast::token::TokenKind; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::tokenstream::TokenTree; +use rustc_session::declare_lint; +use rustc_session::declare_lint_pass; +use rustc_session::lint::FutureIncompatibilityReason; +use rustc_span::edition::Edition; +use rustc_span::sym; + +use crate::lints::MacroExprFragment2024; +use crate::EarlyLintPass; + +declare_lint! { + /// The `edition_2024_expr_fragment_specifier` lint detects the use of + /// `expr` fragments in macros during migration to the 2024 edition. + /// + /// The `expr` fragment specifier will accept more expressions in the 2024 + /// edition. To maintain the behavior from the 2021 edition and earlier, use + /// the `expr_2021` fragment specifier. + /// + /// ### Example + /// + /// ```rust,edition2021,compile_fail + /// #![deny(edition_2024_expr_fragment_specifier)] + /// macro_rules! m { + /// ($e:expr) => { + /// $e + /// } + /// } + /// + /// fn main() { + /// m!(1); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Rust [editions] allow the language to evolve without breaking backwards + /// compatibility. This lint catches code that uses [macro matcher fragment + /// specifiers] that have changed meaning in the 2024 edition. If you switch + /// to the new edition without updating the code, your macros may behave + /// differently. + /// + /// In the 2024 edition, the `expr` fragment specifier `expr` will also + /// match `const { ... }` blocks. This means if a macro had a pattern that + /// matched `$e:expr` and another that matches `const { $e: expr }`, for + /// example, that under the 2024 edition the first pattern would match while + /// in the 2021 and earlier editions the second pattern would match. To keep + /// the old behavior, use the `expr_2021` fragment specifier. + /// + /// This lint detects macros whose behavior might change due to the changing + /// meaning of the `expr` fragment specifier. It is "allow" by default + /// because the code is perfectly valid in older editions. The [`cargo fix`] + /// tool with the `--edition` flag will switch this lint to "warn" and + /// automatically apply the suggested fix from the compiler. This provides a + /// completely automated way to update old code for a new edition. + /// + /// Using `cargo fix --edition` with this lint will ensure that your code + /// retains the same behavior. This may not be the desired, as macro authors + /// often will want their macros to use the latest grammar for matching + /// expressions. Be sure to carefully review changes introduced by this lint + /// to ensure the macros implement the desired behavior. + /// + /// [editions]: https://doc.rust-lang.org/edition-guide/ + /// [macro matcher fragment specifiers]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/macro-fragment-specifiers.html + /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html + pub EDITION_2024_EXPR_FRAGMENT_SPECIFIER, + Allow, + "The `expr` fragment specifier will accept more expressions in the 2024 edition. \ + To keep the existing behavior, use the `expr_2021` fragment specifier.", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), + reference: "Migration Guide ", + }; +} + +declare_lint_pass!(Expr2024 => [EDITION_2024_EXPR_FRAGMENT_SPECIFIER,]); + +impl Expr2024 { + fn check_tokens(&mut self, cx: &crate::EarlyContext<'_>, tokens: &TokenStream) { + let mut prev_colon = false; + let mut prev_identifier = false; + let mut prev_dollar = false; + for tt in tokens.trees() { + debug!( + "check_tokens: {:?} - colon {prev_dollar} - ident {prev_identifier} - colon {prev_colon}", + tt + ); + match tt { + TokenTree::Token(token, _) => match token.kind { + TokenKind::Dollar => { + prev_dollar = true; + continue; + } + TokenKind::Ident(..) | TokenKind::NtIdent(..) => { + if prev_colon && prev_identifier && prev_dollar { + self.check_ident_token(cx, token); + } else if prev_dollar { + prev_identifier = true; + continue; + } + } + TokenKind::Colon => { + if prev_dollar && prev_identifier { + prev_colon = true; + continue; + } + } + _ => {} + }, + TokenTree::Delimited(.., tts) => self.check_tokens(cx, tts), + } + prev_colon = false; + prev_identifier = false; + prev_dollar = false; + } + } + + fn check_ident_token(&mut self, cx: &crate::EarlyContext<'_>, token: &Token) { + debug!("check_ident_token: {:?}", token); + let (sym, edition) = match token.kind { + TokenKind::Ident(sym, _) => (sym, Edition::Edition2024), + _ => return, + }; + + debug!("token.span.edition(): {:?}", token.span.edition()); + if token.span.edition() >= edition { + return; + } + + if sym != sym::expr { + return; + } + + debug!("emitting lint"); + cx.builder.emit_span_lint( + &EDITION_2024_EXPR_FRAGMENT_SPECIFIER, + token.span.into(), + MacroExprFragment2024 { suggestion: token.span }, + ); + } +} + +impl EarlyLintPass for Expr2024 { + fn check_mac_def(&mut self, cx: &crate::EarlyContext<'_>, mc: &rustc_ast::MacroDef) { + self.check_tokens(cx, &mc.body.tokens); + } +} From 568e78f36653b6c336a278e252cc08d2088937c0 Mon Sep 17 00:00:00 2001 From: Vincenzo Palazzo Date: Sat, 25 May 2024 10:50:25 +0200 Subject: [PATCH 11/13] tests: adds cargo fix tests Co-Developed-by: Eric Holk Signed-off-by: Vincenzo Palazzo --- .../macros/expr_2021_cargo_fix_edition.fixed | 24 ++++++++++++++ .../ui/macros/expr_2021_cargo_fix_edition.rs | 24 ++++++++++++++ .../macros/expr_2021_cargo_fix_edition.stderr | 33 +++++++++++++++++++ .../expr_2021_inline_const.edi2021.stderr | 4 +-- .../expr_2021_inline_const.edi2024.stderr | 2 +- tests/ui/macros/expr_2021_inline_const.rs | 7 ++++ 6 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 tests/ui/macros/expr_2021_cargo_fix_edition.fixed create mode 100644 tests/ui/macros/expr_2021_cargo_fix_edition.rs create mode 100644 tests/ui/macros/expr_2021_cargo_fix_edition.stderr diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.fixed b/tests/ui/macros/expr_2021_cargo_fix_edition.fixed new file mode 100644 index 0000000000000..1becd8a92d62e --- /dev/null +++ b/tests/ui/macros/expr_2021_cargo_fix_edition.fixed @@ -0,0 +1,24 @@ +//@ run-rustfix +//@ check-pass +//@ compile-flags: --edition=2021 +#![allow(incomplete_features)] +#![feature(expr_fragment_specifier_2024)] +#![warn(edition_2024_expr_fragment_specifier)] + +macro_rules! m { + ($e:expr_2021) => { //~ WARN: the `expr` fragment specifier will accept more expressions in the 2024 edition + //~^ WARN: this changes meaning in Rust 2024 + $e + }; + ($($i:expr_2021)*) => { }; //~ WARN: the `expr` fragment specifier will accept more expressions in the 2024 edition + //~^ WARN: this changes meaning in Rust 2024 +} + +macro_rules! test { + (expr) => {} +} + +fn main() { + m!(()); + test!(expr); +} diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.rs b/tests/ui/macros/expr_2021_cargo_fix_edition.rs new file mode 100644 index 0000000000000..ec0b86d2c2332 --- /dev/null +++ b/tests/ui/macros/expr_2021_cargo_fix_edition.rs @@ -0,0 +1,24 @@ +//@ run-rustfix +//@ check-pass +//@ compile-flags: --edition=2021 +#![allow(incomplete_features)] +#![feature(expr_fragment_specifier_2024)] +#![warn(edition_2024_expr_fragment_specifier)] + +macro_rules! m { + ($e:expr) => { //~ WARN: the `expr` fragment specifier will accept more expressions in the 2024 edition + //~^ WARN: this changes meaning in Rust 2024 + $e + }; + ($($i:expr)*) => { }; //~ WARN: the `expr` fragment specifier will accept more expressions in the 2024 edition + //~^ WARN: this changes meaning in Rust 2024 +} + +macro_rules! test { + (expr) => {} +} + +fn main() { + m!(()); + test!(expr); +} diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.stderr b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr new file mode 100644 index 0000000000000..e8a44fed322f9 --- /dev/null +++ b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr @@ -0,0 +1,33 @@ +warning: the `expr` fragment specifier will accept more expressions in the 2024 edition + --> $DIR/expr_2021_cargo_fix_edition.rs:9:9 + | +LL | ($e:expr) => { + | ^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see Migration Guide +note: the lint level is defined here + --> $DIR/expr_2021_cargo_fix_edition.rs:6:9 + | +LL | #![warn(edition_2024_expr_fragment_specifier)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to keep the existing behavior, use the `expr_2021` fragment specifier + | +LL | ($e:expr_2021) => { + | ~~~~~~~~~ + +warning: the `expr` fragment specifier will accept more expressions in the 2024 edition + --> $DIR/expr_2021_cargo_fix_edition.rs:13:11 + | +LL | ($($i:expr)*) => { }; + | ^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see Migration Guide +help: to keep the existing behavior, use the `expr_2021` fragment specifier + | +LL | ($($i:expr_2021)*) => { }; + | ~~~~~~~~~ + +warning: 2 warnings emitted + diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr index 5e88096445473..b55ae62030c56 100644 --- a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr +++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr @@ -1,5 +1,5 @@ error: no rules expected the token `const` - --> $DIR/expr_2021_inline_const.rs:21:12 + --> $DIR/expr_2021_inline_const.rs:26:12 | LL | macro_rules! m2021 { | ------------------ when calling this macro @@ -14,7 +14,7 @@ LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ error: no rules expected the token `const` - --> $DIR/expr_2021_inline_const.rs:22:12 + --> $DIR/expr_2021_inline_const.rs:27:12 | LL | macro_rules! m2024 { | ------------------ when calling this macro diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr index 237ecb2cc192a..285db53d6c834 100644 --- a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr +++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr @@ -1,5 +1,5 @@ error: no rules expected the token `const` - --> $DIR/expr_2021_inline_const.rs:21:12 + --> $DIR/expr_2021_inline_const.rs:26:12 | LL | macro_rules! m2021 { | ------------------ when calling this macro diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs index ebc5ea3642108..06b74a466d6e2 100644 --- a/tests/ui/macros/expr_2021_inline_const.rs +++ b/tests/ui/macros/expr_2021_inline_const.rs @@ -17,7 +17,14 @@ macro_rules! m2024 { $e }; } + +macro_rules! test { + (expr) => {} +} + fn main() { m2021!(const { 1 }); //~ ERROR: no rules expected the token `const` m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected the token `const` + + test!(expr); } From dfac6fa5c6b0ca99002f08e99b30c462b72f861d Mon Sep 17 00:00:00 2001 From: simonLeary42 <71396965+simonLeary42@users.noreply.github.com> Date: Tue, 9 Jul 2024 15:23:59 -0400 Subject: [PATCH 12/13] cmake version is from LLVM, link to LLVM docs --- INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 9619ec2ce5cfa..1c2cecf8ef9b3 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -48,7 +48,7 @@ If building LLVM from source, you'll need additional tools: [LLVM's documentation](https://llvm.org/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library) * `ninja`, or GNU `make` 3.81 or later (Ninja is recommended, especially on Windows) -* `cmake` 3.13.4 or later +* `cmake` version listed on [LLVM's documentation](https://llvm.org/docs/GettingStarted.html#software) * `libstdc++-static` may be required on some Linux distributions such as Fedora and Ubuntu From 479b0cdb8957255716fc8158f06a1cb0aba5ad1a Mon Sep 17 00:00:00 2001 From: Charles Celerier Date: Sun, 7 Jul 2024 05:03:59 +0000 Subject: [PATCH 13/13] Ignore fuchsia tests implicitly relying on a signal upon abort Both test-panic-abort-nocapture.rs and test-panic-abort.rs assert the stderr output of the test. On Fuchsia, if a test fails an assertion, this output will contain a line noting the process returned the code -1028 (ZX_TASK_RETCODE_EXCEPTION_KILL). But the asserted stderr output lacks this note. Presumably this is because other platforms implement -Cpanic=abort by killing the process instead of returned a status code. --- tests/ui/test-attrs/test-panic-abort-nocapture.rs | 1 + tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr | 4 ++-- tests/ui/test-attrs/test-panic-abort.rs | 1 + tests/ui/test-attrs/test-panic-abort.run.stdout | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.rs b/tests/ui/test-attrs/test-panic-abort-nocapture.rs index 03c175a2a49ff..8c9e222a40d3e 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.rs +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.rs @@ -10,6 +10,7 @@ //@ ignore-wasm no panic or subprocess support //@ ignore-emscripten no panic or subprocess support //@ ignore-sgx no subprocess support +//@ ignore-fuchsia code returned as ZX_TASK_RETCODE_EXCEPTION_KILL, FIXME (#127539) #![cfg(test)] diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr index 16001b3eecd4d..4c94518d4d197 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr @@ -1,9 +1,9 @@ -thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:34:5: +thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:35:5: assertion `left == right` failed left: 2 right: 4 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:28:5: +thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:29:5: assertion `left == right` failed left: 2 right: 4 diff --git a/tests/ui/test-attrs/test-panic-abort.rs b/tests/ui/test-attrs/test-panic-abort.rs index 77efaf05bbc0d..c9f6439ef8946 100644 --- a/tests/ui/test-attrs/test-panic-abort.rs +++ b/tests/ui/test-attrs/test-panic-abort.rs @@ -10,6 +10,7 @@ //@ ignore-wasm no panic or subprocess support //@ ignore-emscripten no panic or subprocess support //@ ignore-sgx no subprocess support +//@ ignore-fuchsia code returned as ZX_TASK_RETCODE_EXCEPTION_KILL, FIXME (#127539) #![cfg(test)] #![feature(test)] diff --git a/tests/ui/test-attrs/test-panic-abort.run.stdout b/tests/ui/test-attrs/test-panic-abort.run.stdout index f5d14e77da963..25105f38fcf78 100644 --- a/tests/ui/test-attrs/test-panic-abort.run.stdout +++ b/tests/ui/test-attrs/test-panic-abort.run.stdout @@ -17,7 +17,7 @@ hello, world testing123 ---- it_fails stderr ---- testing321 -thread 'main' panicked at $DIR/test-panic-abort.rs:39:5: +thread 'main' panicked at $DIR/test-panic-abort.rs:40:5: assertion `left == right` failed left: 2 right: 5