This is revealed in https://reviews.llvm.org/D141280
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
I think the diagnostic changes are improvements.
clang/test/SemaCXX/rdar42746401.cpp | ||
---|---|---|
7 | The removed diagnostic is "cannot combine with previous 'type-name' declaration specifier" which is bogus. |
I wonder if ActionResult needs a overload that takes std::nullptr_t the current interface seems easy to use wrong like we have seen here.
@aaron.ballman wdyt?
I don't think that'll help in this case because the ActionResult is being constructed from a pointer (which happens to be null) and not a nullptr constant.
clang/lib/Parse/ParseDeclCXX.cpp | ||
---|---|---|
2069–2078 ↗ | (On Diff #488526) | I think this is the wrong approach to fixing the issue. None of the other assignments to TagOrTempResult test for nullptr first, such as: https://github.com/llvm/llvm-project/blob/main/clang/lib/Parse/ParseDeclCXX.cpp#L2037 and https://github.com/llvm/llvm-project/blob/main/clang/lib/Parse/ParseDeclCXX.cpp#L2029. An ActionResult can be both valid/invalid *and* usable/unusable (and a DeclResult is a kind of ActionResult). When it's assigned *any pointer value* (including nullptr), it's a valid ActionResult but it's not a usable ActionResult (https://github.com/llvm/llvm-project/blob/main/clang/include/clang/Sema/Ownership.h#L166). I think the correct fix is to find the places assuming a valid ActionResult means a nonnull pointer from get(), such as https://github.com/llvm/llvm-project/blob/main/clang/lib/Parse/ParseDeclCXX.cpp#L2121 and switch them over to looking for a usable ActionResult instead. |
clang/lib/Parse/ParseDeclCXX.cpp | ||
---|---|---|
2069–2078 ↗ | (On Diff #488526) | Thanks for the comment!
I think the problem here is:
The first one is the other exception; the second one is not (ActOnExplicitInstantiation returns a DeclResult).
This is one of the solutions. But instead of justifying every places of DeclResult, I think we should fix the two exception places (by adding the nullptr check in |
clang/lib/Parse/ParseDeclCXX.cpp | ||
---|---|---|
2069–2078 ↗ | (On Diff #488526) | I have updated the patch to check nullptr for ActOnTemplatedFriendTag as well. Let me know what you think (I'm also happy to do the change). |
clang/lib/Parse/ParseDeclCXX.cpp | ||
---|---|---|
2069–2078 ↗ | (On Diff #488526) | Actually, I think the best solution is to make those APIs return a correctly constructed (invalid) DeclResult rather than a Decl * that turns into a valid-but-unusable DeclResult. I tried the change out locally and it seems to have the same fallout as your changes with only a small amount of extra work involved. I have this done locally, would you like me to go ahead and clean it up to commit it or hand a patch off to you to finish? Or do you think that's not a good approach? |
To offer the opposing argument: if DeclResult is just a bad idea, then using it consistently/right might be worse than using it as little as possible.
FWIW, I find every piece of code that produces/consumes the *Result to be extremely confusing (the semantics of the two different sentinel values are never obvious) and use of the type in more APIs means more callers have to deal with this tri-state logic and bugs like this one.
So spreading DeclResult around where it's not strictly needed feels like the wrong direction to be, and i find the original version of the patch easier to understand. It may even be possible to switch entirely to pointers here.
(Aaron, this is your call, just wanted to make sure you're aware of the cost)
clang/lib/Parse/ParseDeclCXX.cpp | ||
---|---|---|
2069 ↗ | (On Diff #488526) | just so I understand: initial state of TagOrTempResult is (null, invalid) ActOnTag returns null in error cases (diagnostic has been emitted). I can't really infer what the invariants here were originally meant to be, and obviously we're not crashing all over the place, and the diagnostics look like a wash to me. But the new logic seems much more sane. |
clang/test/SemaCXX/rdar42746401.cpp | ||
7 | That doesn't sound bogus to me: ::b<0> is a type name, struct c::d is a type name, and you can't combine two type-names in a decl-specifier-sequence. On the other hand it's a follow-on diagnostic in a situation where it's probably not useful. |
Sema::Act* have a mixed usage of returning {*Result`, void, a pointer, bool}, unclear the common practice there. Changing ActOnTemplatedFriendTag and ActOnTag return-type seems be more aligned with the other Sema::Act* methods used in the ParseClassSpecifier context. And these two APIs are not widely used, it is probably fine.
(Aaron, this is your call, just wanted to make sure you're aware of the cost)
To me, I don't have a strong preference, I'm fine with either solution.
clang/lib/Parse/ParseDeclCXX.cpp | ||
---|---|---|
2069–2078 ↗ | (On Diff #488526) |
Yeah, I considered this approach, but I was not convinced myself is significantly better than the current approach, and it requires some more changes.
Thanks, since you already have a patch, please go ahead (if you think it is better). I'm happy to review. |
FWIW, I also find the interface to be horribly confusing and would love to replace it with something better at some point. But we're horribly inconsistent with things at the moment (some return a pointer, some return a bool, some return a result, etc), so my thinking is that any amount of unification is probably a good thing if only because it makes it more likely we can (consistently) swap to something better in the future.
clang/lib/Parse/ParseDeclCXX.cpp | ||
---|---|---|
2069–2078 ↗ | (On Diff #488526) | heh, yeah, it's hard to know what the right approach is -- I suspect anything other than what we're doing today is a good step forward. I'll go ahead and make this change; it's straightforward enough I think post-commit review should suffice. |
apologies for reverting this, but https://reviews.llvm.org/rGf1f0a0d8e8fdd2e534d9423b2e64c6b8aaa53aee is broken and doesn't revert cleanly without this also being reverted, could you reland?
The removed diagnostic is "cannot combine with previous 'type-name' declaration specifier" which is bogus.