This is an archive of the discontinued LLVM Phabricator instance.

Allow `__attribute__((warn_unused))` on individual constructors
Needs ReviewPublic

Authored by sberg on Apr 17 2023, 2:09 AM.

Details

Summary

This takes inspiration from the standard nodiscard attribute, which can also be declared on individual constructors. (I have used this change locally for about a year on the LibreOffice code base, marking various compilers as warn_unused, without any positive or negative effects. Until I happened to notice an additional constructor that would benefit from warn_unused, and which found about 20 unused variables across the LibreOffice code base, see e.g., https://git.libreoffice.org/core/+/7cdbe504ff3b59d3aec1b1e86caf7f24223dce72%5E! "Fix what looks like copy/paste typos".)

(The changes in clang/test/Misc/pragma-attribute-strict-subjects.c, clang/test/Parser/pragma-attribute.cpp, and clang/test/Sema/pragma-attribute-strict-subjects.c are necessary to make those tests not fail after adding SubRuleForCXXConstructor to SubjectMatcherForFunction in clang/include/clang/Basic/Attr.td. It appears that the exact diagnostic output that is generated is somewhat brittle, depending on implementation details.)

Diff Detail

Event Timeline

sberg created this revision.Apr 17 2023, 2:09 AM
Herald added a project: Restricted Project. · View Herald Transcript
Herald added a subscriber: jdoerfert. · View Herald Transcript
sberg requested review of this revision.Apr 17 2023, 2:09 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 17 2023, 2:09 AM

I don't see a problem with this, but the changes to the pragma tests concern me a bit, so I'd like aaron to scroll through. The Expr.cpp and Sema changes both look right to me.

aaron.ballman added inline comments.Apr 17 2023, 8:07 AM
clang/docs/ReleaseNotes.rst
189–190
clang/include/clang/Basic/Attr.td
2996

I'm confused -- if you want this to behave like nodiscard, why aren't these changes for warn_unused_result (which is what implements nodiscard)? I don't think this should go on warn_unused because that's for the declaration of the type as a unit and not written on functions.

I think you don't need any changes to Attr.td for this functionality.

sberg added inline comments.Apr 17 2023, 8:54 AM
clang/include/clang/Basic/Attr.td
2996

[[nodiscard]] and __attribute__((warn_unused)) already have different semantics when applied to a class: While both warn about unused expression results (-Wunused-value), only the latter warns about unused variables (-Wunused-variable). This patch keeps that difference, just extends it to individual constructors:

$ cat test.cc
struct [[nodiscard]] S1 {
  S1(int) {}
  S1(double) {}
};
struct S2 {
  [[nodiscard]] S2(int) {}
  S2(double) {}
};
struct __attribute__((warn_unused)) S3 {
  S3(int) {}
  S3(double) {}
};
struct S4 {
  __attribute__((warn_unused)) S4(int) {}
  S4(double) {}
};
int main() {
  S1(0); // expected-warning {{ignoring temporary}}
  S1(0.0); // expected-warning {{ignoring temporary}}
  S2(0); // expected-warning {{ignoring temporary}}
  S2(0.0);
  S3(0); // expected-warning {{expression result unused}}
  S3(0.0); // expected-warning {{expression result unused}}
  S4(0); // expected-warning {{expression result unused}}
  S4(0.0);
  S1 s1a(0);
  S1 s1b(0.0);
  S2 s2a(0);
  S2 s2b(0.0);
  S3 s3a(0); // expected-warning {{unused variable}}
  S3 s3b(0.0); // expected-warning {{unused variable}}
  S4 s4a(0); // expected-warning {{unused variable}}
  S4 s4b(0.0);
}
$ clang++ -Wunused-value -Wunused-variable -fsyntax-only -Xclang -verify test.cc
aaron.ballman added inline comments.Apr 17 2023, 12:51 PM
clang/include/clang/Basic/Attr.td
2996

Hmmm, well, that's compelling and now I don't know what I think.

I'm worried that this further muddies the water between warn_unused and warn_unused_result which are already pretty murky to begin with. warn_unused_result goes on functions, warn_unused goes on the declaration of a type. That symmetry is something I think people can understand and remember despite the attribute names. With this patch, now it's warn_unused_result goes on functions, and warn_unused goes on constructor functions or the declaration of a type. It's not the worst thing ever (constructors don't really have "results" for example). But the fact that these two attributes already confuse users (AND we've got unused as an attribute in the mix as well, which doesn't help) means we should proceed with caution (and likely coordinate with GCC given that all three of these attributes came from their implementation).

I'm not certain what the best design approach is yet, but I'll think about the problem a bit more over the next few days to see if my thoughts crystalize on this.

(FWIW, if we do decide to go with warn_unused, I think it's no longer defensible to leave this attribute as undocumented in Clang -- we should take the opportunity to push up some documentation for this one.)

erichkeane added inline comments.Apr 17 2023, 12:54 PM
clang/include/clang/Basic/Attr.td
2996

To double-down on what Aaron says: He and I discussed this extensively offline, and we are both really quite unsure what to do here. I can make a reasonable/good argument to convince myself and Aaron in either direction (and he's been able to convince me both ways!), so I also think the ergonomics of these two needs to be defined/fleshed out for this.

sberg added a comment.Apr 26 2023, 3:12 PM

But the fact that these two attributes already confuse users (AND we've got unused as an attribute in the mix as well, which doesn't help) means we should proceed with caution (and likely coordinate with GCC given that all three of these attributes came from their implementation).

I've brought this up at https://gcc.gnu.org/pipermail/gcc/2023-April/241205.html "GCC/Clang attributes guiding warnings about unused entities" now. (I tried to cross-post that also to the Clang Frontend discourse category, but that probably didn't work.)

But the fact that these two attributes already confuse users (AND we've got unused as an attribute in the mix as well, which doesn't help) means we should proceed with caution (and likely coordinate with GCC given that all three of these attributes came from their implementation).

I've brought this up at https://gcc.gnu.org/pipermail/gcc/2023-April/241205.html "GCC/Clang attributes guiding warnings about unused entities" now. (I tried to cross-post that also to the Clang Frontend discourse category, but that probably didn't work.)

Thank you for poking on this! FWIW, I don't know that there's a way to cross-post to Discourse (but if I'm wrong and there is, I'd love to know how!).

Thank you for poking on this! FWIW, I don't know that there's a way to cross-post to Discourse (but if I'm wrong and there is, I'd love to know how!).

Ping, any further input from anybody?

(The cross-posting didn't work, but there was also almost no response on the GCC side, https://gcc.gnu.org/pipermail/gcc/2023-April/241220.html "Re: GCC/Clang attributes guiding warnings about unused entities".)

Thank you for poking on this! FWIW, I don't know that there's a way to cross-post to Discourse (but if I'm wrong and there is, I'd love to know how!).

Ping, any further input from anybody?

(The cross-posting didn't work, but there was also almost no response on the GCC side, https://gcc.gnu.org/pipermail/gcc/2023-April/241220.html "Re: GCC/Clang attributes guiding warnings about unused entities".)

I've thought about it a bit since the last time around, and I'm still kind of uncomfortable with the changes especially given that GCC folks don't seem to have an appetite to change the behavior. However, I'm also not firmly opposed to the idea either as there is some nice symmetry. Most of my concerns really boil down to the ergonomics of how all the various attributes in this space are slightly different from one another; unless GCC goes the same direction, this is one more difference between the attributes that you need to worry about. However, at least GCC warns that they're ignoring the attribute when written on a constructor: https://godbolt.org/z/bzTojhs1f so perhaps this difference is reasonable so long as we have some amazing documentation.

I'm not certain if @erichkeane has new thoughts or not.

I'm still on the fence. I think properly documenting all of this entire attribute would make me more comfortable here, particularly since it will allow GCC to follow us easily some day. I think that would move the needle for me.

clang/include/clang/Basic/Attr.td
2997

For this to go through, I think we'd want this properly documented.

I'm still on the fence. I think properly documenting all of this entire attribute would make me more comfortable here, particularly since it will allow GCC to follow us easily some day. I think that would move the needle for me.

I think I've got a slightly different idea there: let's add a new documentation section for all of the related attributes in this area and document (or update) all of them in a block. This way, users have a good way to answer "which one do I use in what circumstance?" as well as other compiler devs who want to match our behavior. I think if we can make the documentation sufficiently clear, then this is fine.