Skip to content

COUNT constant in join*! macros can collide with user's constant used in futures #7637

@robinhundt

Description

@robinhundt

Version

1.46

Platform
Linux nixos 6.12.45 #1-NixOS SMP PREEMPT_DYNAMIC Thu Sep 4 13:31:56 UTC 2025 x86_64 GNU/Linux

Description

The commit 8e999e3#diff-71d8f976620bd493969f9c0ecf5db22825ba06ca05acdcce17f400c5c6ae2c11 changed the scope of the COUNT constant of the join! and try_join! macros so that it is in the same scope as the expansion of the futures expressions $e. If a user of these macros has their own COUNT constant in scope, this leads to a compile error due to mismatching types (usize and u32 in my case) or in the worst case to a change in behavior if the types are compatible but the values are different (repro).

Apparently macros are not hygienic for items, which includes consts... :(

I tried this code:

In one of my projects I have a few test cases which look like this:

    #[tokio::test]
    async fn test_extension() {
        let _g = init_tracing();
        const COUNT: usize = 2 * DEFAULT_OT_BATCH_SIZE;
        let (c1, c2) = local_conn().await.unwrap();
        let rng1 = StdRng::seed_from_u64(42);
        let mut rng2 = StdRng::seed_from_u64(24);
        let choices = random_choices(COUNT, &mut rng2);
        let mut sender = SemiHonestOtExtensionSender::new_with_rng(c1, rng1);
        let mut receiver = SemiHonestOtExtensionReceiver::new_with_rng(c2, rng2);
        let (send_ots, recv_ots) =
            tokio::try_join!(sender.send(COUNT), receiver.receive(&choices)).unwrap();
        for ((r, s), c) in recv_ots.into_iter().zip(send_ots).zip(choices) {
            assert_eq!(r, s[c.unwrap_u8() as usize]);
        }
    }

source

I expected to see this happen:

The code should still compile after a minor version upgrade from 1.45 to 1.46.

Instead, this happened:

This code used to work but unexpectedly broke when upgrading Tokio from 1.45 to 1.46 (or later) with the following error:

error[E0308]: mismatched types
   --> cryprot-ot/src/extension.rs:809:42
    |
809 |             tokio::try_join!(sender.send(COUNT), receiver.receive(&choices)).unwrap();
    |                                     ---- ^^^^^ expected `usize`, found `u32`
    |                                     |
    |                                     arguments to this method are incorrect
    |

This confused me, as clearly the COUNT const is declared as usize and not u32. As explained above, this is due to the scope change of the COUNT constant in the join! and try_join! macros.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-tokioArea: The main tokio crateC-bugCategory: This is a bug.M-macrosModule: macros in the main Tokio crate

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions