rust-lang / rust-lang/rust

Weirdly placed derive attributes undesiredly accepted

Open
#119,116 6 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

A-proc-macros C-bug T-compiler T-lang
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Consider this ludicrous code:

use serde::Serialize;

#[derive(Serialize)]
struct Const<const X: i32>;

#[derive(Serialize)]
struct Struct {
    field: Const<{

        #[serde(absurd, transparent)]
        mod inner {}

        42
    }>,
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ef6a0f6dcbfb51c62d846e0d93da68aa

Currently this builds. I think it shouldn't. Essentially I'm sneaking random stuff into the scope of rustc's idea of where #[serde] is allowed and then applying #[serde] attributes to some of the random stuff. Obviously serde doesn't look in there so the misplaced attribute is ignored.

If we think it's the macro's job (serde in this case) to prevent this, then syn ought to have a handy function for "just doing it". Should we then call this function in every macro? That seems like an impractical prescription, both because we don't want to be changing every macro, and because not every macro uses syn.

So maybe this is a bug in Rust? I think you need const generics to do this (since that's how to get the block into the struct definition).I doubt that when const generics were stabilised this was intended.

But fixing it in Rust would have a backward compatibility problem. In theory someone might be doing something like this deliberately! So maybe the check needs to be opt-out?

I think the main points of the rustc built-in "unused attribute" warning are to spot (i) typoed attributes (ii) forgotten #[derive]. This situation can't arise from (i), since the attribute does exist. (ii) could only happen if the inner block contained a whole struct definition that someone was trying to derive on, and probably you'd notice another way since the derive's output would be missing (so the struct wouldn't implement the trait or whatever). So it doesn't seem a very serious problem, even though I guess some macros might have semantics that would encourage a user to try this syntax.

The derive macros in std aren't affected because they cheat: they use compiler magic for their attributes. I think Default is the only one that even has an attribute, and putting #[default] next to #[serde(absurd, transparent)] does produce an error.

Anyway, out of serde, syn, and rust, I have chosen to file this as a ticket against rust. CC @dtolnay

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the const-generic example in the linked Rust Playground and trace how rustc handles the misplaced attribute inside the const block. Compare whether the behavior belongs in rustc, serde, or syn, then establish whether the desired outcome is rejection, an opt-out check, or documented acceptance.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.