Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 8 pull requests #127549

Merged
merged 21 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
eb92923
Bump elided_lifetimes_in_associated_constant
compiler-errors Apr 20, 2024
90cbd0b
impl FusedIterator and a size hint for the error sources iter
Sky9x Jun 28, 2024
54aa9e8
[fuchsia-test-runner] Remove runner logs from stdout and stderr
c6c7 Jul 6, 2024
3d5b4d8
[fuchsia-test-runner] Reformat fuchsia-test-runner.py
c6c7 Jul 7, 2024
ec662e7
`#[doc(alias)]`'s doc: say that ASCII spaces are allowed
ShE3py Jul 8, 2024
7097dbc
exhaustively destructure external constraints
lcnr Jul 9, 2024
e38109d
use `update_parent_goal` for lazy updates
lcnr Jul 9, 2024
dd175fe
cycle_participants to nested_goals
lcnr Jul 9, 2024
4700b5b
Remove spastorino from SMIR
spastorino Jul 9, 2024
25637e2
Adds expr_2024 migration lit
vincenzopalazzo May 25, 2024
568e78f
tests: adds cargo fix tests
vincenzopalazzo May 25, 2024
dfac6fa
cmake version is from LLVM, link to LLVM docs
simonLeary42 Jul 9, 2024
479b0cd
Ignore fuchsia tests implicitly relying on a signal upon abort
c6c7 Jul 7, 2024
de143cf
Rollup merge of #124211 - compiler-errors:bump-elided_lifetimes_in_as…
jhpratt Jul 10, 2024
21a0e86
Rollup merge of #125627 - vincenzopalazzo:macros/cargo-fix-expr2024, …
jhpratt Jul 10, 2024
e71d3d5
Rollup merge of #127091 - Sky9x:fused-error-sources-iter, r=dtolnay
jhpratt Jul 10, 2024
7490729
Rollup merge of #127461 - c6c7:fixup-failing-fuchsia-tests, r=tmandry
jhpratt Jul 10, 2024
85bd32c
Rollup merge of #127484 - ShE3py:rustdoc-doc-alias-whitespace-doc, r=…
jhpratt Jul 10, 2024
64695ad
Rollup merge of #127508 - lcnr:search-graph-prep, r=compiler-errors
jhpratt Jul 10, 2024
103a772
Rollup merge of #127521 - spastorino:remove-myself-from-smir-pings, r…
jhpratt Jul 10, 2024
08cb462
Rollup merge of #127532 - simonLeary42:patch-1, r=Nilstrieb
jhpratt Jul 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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::*;
Expand Down Expand Up @@ -170,6 +172,7 @@ early_lint_methods!(
IncompleteInternalFeatures: IncompleteInternalFeatures,
RedundantSemicolons: RedundantSemicolons,
UnusedDocComment: UnusedDocComment,
Expr2024: Expr2024,
]
]
);
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,13 @@ pub struct BuiltinTypeAliasGenericBounds<'a, 'b> {
pub sub: Option<SuggestChangingAssocTypes<'a, 'b>>,
}

#[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)>,
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/macro-fragment-specifiers.html>",
};
}

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);
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4620,7 +4620,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,
Expand Down
14 changes: 11 additions & 3 deletions compiler/rustc_next_trait_solver/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<I: Interner>(
response: ty::Canonical<I, Response<I>>,
) -> 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>
Expand Down
52 changes: 21 additions & 31 deletions compiler/rustc_next_trait_solver/src/solve/search_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ struct StackEntry<I: Interner> {
/// C :- D
/// D :- C
/// ```
cycle_participants: HashSet<CanonicalInput<I>>,
nested_goals: HashSet<CanonicalInput<I>>,
/// Starts out as `None` and gets set when rerunning this
/// goal in case we encounter a cycle.
provisional_result: Option<QueryResult<I>>,
Expand Down Expand Up @@ -139,18 +139,11 @@ impl<I: Interner> SearchGraph<I> {
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<I> {
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 {
Expand Down Expand Up @@ -222,8 +215,8 @@ impl<I: Interner> SearchGraph<I> {
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));
}
}

Expand Down Expand Up @@ -342,7 +335,7 @@ impl<I: Interner> SearchGraph<I> {
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);
Expand All @@ -364,14 +357,16 @@ impl<I: Interner> SearchGraph<I> {
}

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)
});

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.
Expand All @@ -394,15 +389,15 @@ impl<I: Interner> SearchGraph<I> {
//
// 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,
input,
proof_tree,
reached_depth,
final_entry.encountered_overflow,
final_entry.cycle_participants,
final_entry.nested_goals,
dep_node,
result,
)
Expand Down Expand Up @@ -441,14 +436,9 @@ impl<I: Interner> SearchGraph<I> {
}
}

// 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)
}
Expand Down Expand Up @@ -477,7 +467,7 @@ impl<I: Interner> SearchGraph<I> {
F: FnMut(&mut Self, &mut ProofTreeBuilder<D>) -> QueryResult<I>,
{
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.
Expand Down Expand Up @@ -554,27 +544,27 @@ impl<I: Interner> SearchGraph<I> {
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);
}
}
}
Expand Down
Loading
Loading