1ae521e9d5
This example triggers an assertion failure: ``` fn f() -> u32 { #[cfg_eval] #[cfg(not(FALSE))] 0 } ``` The sequence of events: - `configure_annotatable` calls `parse_expr_force_collect`, which calls `collect_tokens`. - Within that, we end up in `parse_expr_dot_or_call`, which again calls `collect_tokens`. - The return value of the `f` call is the expression `0`. - This inner call collects tokens for `0` (parser range 10..11) and creates a replacement covering `#[cfg(not(FALSE))] 0` (parser range 0..11). - We return to the outer `collect_tokens` call. The return value of the `f` call is *again* the expression `0`, again with the range 10..11, but the replacement from earlier covers the range 0..11. The code mistakenly assumes that any attributes from an inner `collect_tokens` call fit entirely within the body of the result of an outer `collect_tokens` call. So it adjusts the replacement parser range 0..11 to a node range by subtracting 10, resulting in -10..1. This is an invalid range and triggers an assertion failure. It's tricky to follow, but basically things get complicated when an AST node is returned from an inner `collect_tokens` call and then returned again from an outer `collect_token` node without being wrapped in any kind of additional layer. This commit changes `collect_tokens` to return early in some extra cases, avoiding the construction of lazy tokens. In the example above, the outer `collect_tokens` returns earlier because the `0` token already has tokens and `self.capture_state.capturing` is `Capturing::No`. This early return avoids the creation of the invalid range and the assertion failure. Fixes #129166. Note: these invalid ranges have been happening for a long time. #128725 looks like it's at fault only because it introduced the assertion that catches the invalid ranges. |
||
---|---|---|
.. | ||
auxiliary | ||
cfg_accessible-bugs.rs | ||
cfg_accessible-bugs.stderr | ||
cfg_accessible-input-validation.rs | ||
cfg_accessible-input-validation.stderr | ||
cfg_accessible-not_sure.edition2015.stderr | ||
cfg_accessible-not_sure.edition2021.stderr | ||
cfg_accessible-not_sure.rs | ||
cfg_accessible-private.rs | ||
cfg_accessible-stuck.rs | ||
cfg_accessible-stuck.stderr | ||
cfg_accessible-unstable.rs | ||
cfg_accessible-unstable.stderr | ||
cfg_accessible.rs | ||
cfg_accessible.stderr | ||
cfg_attr_path.rs | ||
cfg-arg-invalid-1.rs | ||
cfg-arg-invalid-1.stderr | ||
cfg-arg-invalid-2.rs | ||
cfg-arg-invalid-2.stderr | ||
cfg-arg-invalid-3.rs | ||
cfg-arg-invalid-3.stderr | ||
cfg-arg-invalid-4.rs | ||
cfg-arg-invalid-4.stderr | ||
cfg-arg-invalid-5.rs | ||
cfg-arg-invalid-5.stderr | ||
cfg-arg-invalid-6.rs | ||
cfg-arg-invalid-6.stderr | ||
cfg-arg-invalid-7.rs | ||
cfg-arg-invalid-7.stderr | ||
cfg-arg-invalid-8.rs | ||
cfg-arg-invalid-8.stderr | ||
cfg-arg-invalid-9.rs | ||
cfg-arg-invalid-9.stderr | ||
cfg-attr-cfg-2.rs | ||
cfg-attr-cfg-2.stderr | ||
cfg-attr-crate-2.rs | ||
cfg-attr-crate-2.stderr | ||
cfg-attr-empty-is-unused.rs | ||
cfg-attr-empty-is-unused.stderr | ||
cfg-attr-invalid-predicate.rs | ||
cfg-attr-invalid-predicate.stderr | ||
cfg-attr-multi-false.rs | ||
cfg-attr-multi-invalid-1.rs | ||
cfg-attr-multi-invalid-1.stderr | ||
cfg-attr-multi-invalid-2.rs | ||
cfg-attr-multi-invalid-2.stderr | ||
cfg-attr-multi-true.rs | ||
cfg-attr-multi-true.stderr | ||
cfg-attr-parse.rs | ||
cfg-attr-parse.stderr | ||
cfg-attr-syntax-validation.rs | ||
cfg-attr-syntax-validation.stderr | ||
cfg-attr-unknown-attribute-macro-expansion.rs | ||
cfg-attr-unknown-attribute-macro-expansion.stderr | ||
cfg-empty-codemap.rs | ||
cfg-empty-codemap.stderr | ||
cfg-generic-params.rs | ||
cfg-generic-params.stderr | ||
cfg-in-crate-1.rs | ||
cfg-in-crate-1.stderr | ||
cfg-non-opt-expr.rs | ||
cfg-non-opt-expr.stderr | ||
inner-cfg-non-inline-mod.rs | ||
invalid-node-range-issue-129166.rs | ||
invalid-node-range-issue-129166.stderr | ||
issue-34028.rs | ||
module_with_cfg.rs | ||
test-cfg.rs | ||
test-cfg.stderr |