[Pre-RFC] Allow attributes to be applied to generic arguments

Currently, rust allows the following.

struct MyStruct<#[cfg(feature)] Arg>();

This is useful in certain circumstances. For instance, suppose you wanted to make a crate with a custom collection. If the allocator_api was enabled, you could automatically support it in your struct.

struct MyCollection<#[cfg(feature = "allocator_api")] A: Allocator = Global> {
    // ..
    alloc: A
}

You can even use it in impl blocks:

impl<#[cfg(feature)] Arg> MyStruct

What you can't do, however, which makes the above nearly pointless, and what I want to change, is the following

impl<#[cfg(feature)] Arg> MyStruct<#[cfg(feature)] Arg>

This results in the error attributes cannot be applied to generic arguments

This has been a major headache for crate developers in the past. In many cases, the choice is between essentially duplicating all relevant code (I've seen recommendations to create duplicate modules that have identical-other-than-this code), choosing to whether to support nightly or stable, or evil macro hacks. (1) (2) (3)

As far as I know, implementing this shouldn't be too hard,as it would be quite similar to the current way the other inline attributes work. I think this would be a major ergonomics improvement for implementing collection crates.

(P. S. I searched, but if I missed a prior conversation where this option was discussed and rejected, I apologize. The pr that created that error was simply consolidating that error from a generic syntax error)

5 Likes

Yes please. Generics are the last set of "comma-terminated fragments" remaining that I would also like to see supported with cfg-attributes[1]. I have a full list of them on this HackMD page. Generally speaking, I believe if any token fragment terminates with a(n optional) comma in Rust, it should be possible to conditionally omit it with a cfg-attribute.

You might be interested in RFC 3399 (accepted) and RFC 3532 (in FCP, hopefully about to be accepted) for prior art on my personal RFC effort to support cfg-attributes in more places.


  1. Aside from braced multi-use statements, but that's not terribly important IMO â†Šī¸Ž

5 Likes

This is, I think, a bad motivating example because that's a non-additive feature when you're changing the generics.

(Compare private fields where adding or removing the field doesn't break the caller.)

Might as well just leave the type there all the time, and either ignore it or only support one particular type if the feature is off.

You're right. I've edited it to add a = Global default, like all the alloc collections. In that case, I think it is additive?

1 Like

Keep in mind that while features are intended to be additive, not all usage of cfg-attributes has to be. In particular, custom conditionals have no such requirement or implication.

Something like:

// Note, not #[cfg(feature = "foo")]
struct Foo<T, #[cfg(foo)] U> {
    // ..
}

could certainly happen in some codebases.

4 Likes