Skip to content

Commit

Permalink
Fix the features macro.
Browse files Browse the repository at this point in the history
The first rule of the `features` macro looks like this:
```
macro_rules! features {
    (
      @target: $target:ident;
      @cfg: $cfg:meta;
      @MACRO_NAME: $macro_name:ident;
      @MACRO_ATTRS: $(#[$macro_attrs:meta])*
      $(@BIND_FEATURE_NAME: $bind_feature:tt; $feature_impl:tt; $(#[$deprecate_attr:meta];)?)*
      $(@NO_RUNTIME_DETECTION: $nort_feature:tt; )*
      $(@feature: #[$stability_attr:meta] $feature:ident: $feature_lit:tt;
          $(without cfg check: $feature_cfg_check:literal;)?
          $(implied by target_features: [$($target_feature_lit:tt),*];)?
          $(#[$feature_comment:meta])*)*
    ) => {
```
Notice all the `tt` specifiers. They are used because they are forwarded
to another macro. Only `ident`, `lifetime`, and `tt` specifiers can be
forwarded this way.

But there is an exception: `$feature_lit:tt`, which was added recently.
In theory it should cause an error like this:
```
error: no rules expected `literal` metavariable
   --> /home/njn/dev/rust3/library/stdarch/crates/std_detect/src/detect/macros.rs:54:91
    |
51  | /         macro_rules! $macro_name {
52  | |             $(
53  | |                 ($feature_lit) => {
54  | |                     $crate::detect_feature!($feature, $feature_lit $(, without cfg check: $feature_cfg_check)? ...
    | |                                                                                           ^^^^^^^^^^^^^^^^^^ no rules expected this token in macro call
...   |
88  | |             };
89  | |         }
    | |_________- in this expansion of `is_x86_feature_detected!`
    |
   ::: std/tests/run-time-detect.rs:145:27
    |
145 |       println!("tsc: {:?}", is_x86_feature_detected!("tsc"));
    |                             ------------------------------- in this macro invocation
    |
note: while trying to match keyword `true`
   --> /home/njn/dev/rust3/library/stdarch/crates/std_detect/src/detect/macros.rs:12:55
    |
12  |     ($feature:tt, $feature_lit:tt, without cfg check: true) => {
    |                                                       ^^^^
    = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens
    = note: see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information
```
(The URL at the end of the error has more details about this forwarding
limitation.)

In practice it doesn't cause this error. I'm not sure why, but the
existing macro implementation in rustc is far from perfect, so it's
believable that it does the wrong thing here.

Why does this matter? Because rust-lang/rust#124141
is modifying the macro implementation, and when that PR is applied the
error *does* occur. (It's one of several cases I have found where the
existing compiler accepts code it shouldn't, but #124141 causes that
code to be rejected.)

Fortunately the fix is simple: replace the `literal` specifier with `tt`.
  • Loading branch information
nnethercote committed Nov 25, 2024
1 parent f3f4e1e commit a1a9b95
Showing 1 changed file with 1 addition and 1 deletion.
2 changes: 1 addition & 1 deletion crates/std_detect/src/detect/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ macro_rules! features {
$(@BIND_FEATURE_NAME: $bind_feature:tt; $feature_impl:tt; $(#[$deprecate_attr:meta];)?)*
$(@NO_RUNTIME_DETECTION: $nort_feature:tt; )*
$(@FEATURE: #[$stability_attr:meta] $feature:ident: $feature_lit:tt;
$(without cfg check: $feature_cfg_check:literal;)?
$(without cfg check: $feature_cfg_check:tt;)?
$(implied by target_features: [$($target_feature_lit:tt),*];)?
$(#[$feature_comment:meta])*)*
) => {
Expand Down

0 comments on commit a1a9b95

Please sign in to comment.