Skip to content

Assignment inside format_args! is ignored #45256

@nikolads

Description

@nikolads

Assignments inside format_args! are ignored. Instead only the right-hand side of the expression is used.

I tried this code:

fn main() {
    let mut x = 1;
    println!("first: {}", x = 3);
    println!("second: {}", x);
}

or a similar one, using directly format_args:

use std::io::{self, Write};

fn main() {
    let mut x = 1; 
    io::stdout().write_fmt(format_args!("first: {}\n", x = 3));
    io::stdout().write_fmt(format_args!("second: {}\n", x));
}

I expected to see this:

first: ()
second: 3

Instead the output was:

first: 3
second: 1

It looks like the the assignment x = 3 is ignored and is instead treated as if it was just 3.
I could only replicate this with format_args! and macros that use it. Other macros, like assert_eq!, work as expected.

Meta

rustc --version --verbose:

rustc 1.22.0-nightly (dcbbfb6e8 2017-10-12)
binary: rustc
commit-hash: dcbbfb6e807fdff9c9ba80073bb755f9d9d95e31
commit-date: 2017-10-12
host: x86_64-unknown-linux-gnu
release: 1.22.0-nightly
LLVM version: 4.0

(also tried on rustc 1.20.0-stable and rustc 1.21.0-stable)

Activity

added
C-bugCategory: This is a bug.
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
on Oct 13, 2017
sinkuu

sinkuu commented on Oct 13, 2017

@sinkuu
Contributor

format_args supports named arguments with name = value syntax. Assignments can be written as {x = 3} so that they won't be treated as named argument.

What's odd is that {} formats arguments just in the sequence of arguments, ignoring if they are named or positional. Is this intended behavior?

println!("{x} {} {} {}", 1, x = 2, y= 3);
// => 2 1 2 3
kennytm

kennytm commented on Oct 13, 2017

@kennytm
Member

The x = 3 is not parsed as assignment, but named parameters.

The bug here is that println!("first: {}", x = 3); should not compile since parameter 0 is missing.

added
T-langRelevant to the language team
and removed
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
on Oct 13, 2017
nagisa

nagisa commented on Oct 13, 2017

@nagisa
Member

What @kennytm and @sinku said is correct, but I’m not sure it (the behaviour of how named arguments are considered in context of positional arguments) can be considered a bug anymore. At least I can easily see somebody using this, intentionally or not, even if it wasn’t documented to have specifically this behaviour. Therefore nominating it for T-lang (since format_args! is a part of language) to decide what the intended behaviour is.

ollie27

ollie27 commented on Oct 13, 2017

@ollie27
Member

From Positional parameters:

Each formatting argument is allowed to specify which value argument it's referencing, and if omitted it is assumed to be "the next argument".

Which suggests this is working as intended.

If anything I'd say there should be a warning if you name a parameter but never reference it by its name.

sinkuu

sinkuu commented on Oct 13, 2017

@sinkuu
Contributor

@ollie27 Isn't that talking only about positional parameters?

The behavior in question have been introduced in Rust 1.12. I speculate that #33642 (which seems to have added internal translation of named args into positional args) unintentionally did it.

Example:

fn main() {
    println!("{}", x = 1);
}

Rust 1.11.0:

<std macros>:3:11: 3:36 error: invalid reference to argument `0` (no arguments given)
<std macros>:3 print ! ( concat ! ( $ fmt , "\n" ) , $ ( $ arg ) * ) ) ;
                         ^~~~~~~~~~~~~~~~~~~~~~~~~
<std macros>:3:11: 3:36 note: in this expansion of concat!
<std macros>:2:27: 2:58 note: in this expansion of format_args!
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std macros>)
test.rs:2:5: 2:27 note: in this expansion of println! (defined in <std macros>)
test.rs:2:24: 2:25 error: named argument never used
test.rs:2     println!("{}", x = 1);
                                 ^
error: aborting due to 2 previous errors

Rust 1.12.0

(compiles fine, and the program prints "1")
joshtriplett

joshtriplett commented on Oct 19, 2017

@joshtriplett
Member

Consensus in the lang team meeting is that we should reintroduce a lint for "named argument never used". And if it's just a lint, we don't need a full crater run.

added
A-diagnosticsArea: Messages for errors, warnings, and lints
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
and removed
T-langRelevant to the language team
on Sep 1, 2019
added
A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
on Feb 13, 2020
estebank

estebank commented on Jul 8, 2022

@estebank
Contributor

#98580 will lint against this as warn-by-default.

PrestonFrom

PrestonFrom commented on Jul 14, 2022

@PrestonFrom
Contributor

#98580 has been merged -- should this issue be closed?

added
A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
and removed
A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
on Dec 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @kennytm@joshtriplett@nagisa@aturon@estebank

        Issue actions

          Assignment inside format_args! is ignored · Issue #45256 · rust-lang/rust