Details
Diff Detail
Event Timeline
llvm/include/llvm/ADT/PointerUnion.h | ||
---|---|---|
219 | CastIsPossible inheritance is not necessary since you define isPossible below. | |
222 | Out of curiosity, does it make sense to implement PointerUnion::is<T> in terms of isa<T> rather than the other way around? And same for doCast below? | |
230 | You can inherit from the NullableValueCastFailed cast trait to get this | |
232 | You can inherit from the DefaultDoCastIfPossible cast trait to get this |
Given that I'm still young to C++ and llvm, every suggestion, even the
one you feel it's trivial, are very welcomed ;)
This diff comes with the following updates:
- Define PointerUnion::is and PointerUnion::get in terms of isa<T> and cast<T>.
- Add FIXME comment for PointerUnion::is(), PointerUnion::get() and PointerUnion::dyn_cast().
llvm/include/llvm/ADT/PointerUnion.h | ||
---|---|---|
222 | I'm feeling the same, too. |
Also, CastInfoPointerUnionImpl is defined and declared as a friend of PointerUnion to support isa<T> and cast<T> directly rather than calling into PointerUnion::is and PointerUnion::get.
Didn't notice the build failure. Remove the CastInfoPointerUnionImpl and revert
back to the original implementation.
Is there any way for CastInfo to directly access PointerUnion::Val, which is
a protected member ?
I can only come up with this :
Define CastInfoPointerUnionImpl as below :
template <typename... PTs> struct CastInfoPointerUnionImpl { using From = PointerUnion<PTs...>; template <typename To> static inline bool isPossible(From &F) { return F.Val.getInt() == FirstIndexOfType<To, PTs...>::value; } template <typename To> static To doCast(From &F) { assert(isPossible<To>(F) && "cast to an incompatible type !"); return PointerLikeTypeTraits<To>::getFromVoidPointer(F.Val.getPointer()); } };
and declared it as a friend of PointerUnion.
And then CastInfo:
template <typename To, typename... PTs> struct CastInfo<To, PointerUnion<PTs...>> : NullableValueCastFailed<To>, DefaultDoCastIfPossible<To, PointerUnion<PTs...>, CastInfo<To, PointerUnion<PTs...>>> { using From = PointerUnion<PTs...>; using Impl = CastInfoPointerUnionImpl<PTs...>; static inline bool isPossible(From &f) { return Impl::template isPossible<To>(f); } static To doCast(From &f) { return Impl::template doCast<To>(f); } };
By doing this we can implement PointerUnion::is and PointerUnion::get in this way:
/// Test if the Union currently holds the type matching T. template <typename T> bool is() const { return isa<T>(*this); } /// Returns the value of the specified pointer type. /// /// If the specified pointer type is incorrect, assert. template <typename T> T get() const { assert(isa<T>(*this) && "Invalid accessor called"); return cast<T>(*this); }
Does this make sense ?
Could you declare the CastInfo struct itself as a friend? something like template<typename To, typename...PTs> friend struct CastInfo<To, PointerUnion<PTs...>>? That way you don't need the impl struct so it cuts down on overall code. Truly asking here - I think it's doable but I may be wrong.
And then CastInfo:
template <typename To, typename... PTs> struct CastInfo<To, PointerUnion<PTs...>> : NullableValueCastFailed<To>, DefaultDoCastIfPossible<To, PointerUnion<PTs...>, CastInfo<To, PointerUnion<PTs...>>> { using From = PointerUnion<PTs...>; using Impl = CastInfoPointerUnionImpl<PTs...>; static inline bool isPossible(From &f) { return Impl::template isPossible<To>(f); } static To doCast(From &f) { return Impl::template doCast<To>(f); } };
This looks really nice - I think it still will even with the Impl::* methods inlined :)
By doing this we can implement PointerUnion::is and PointerUnion::get in this way:
/// Test if the Union currently holds the type matching T. template <typename T> bool is() const { return isa<T>(*this); } /// Returns the value of the specified pointer type. /// /// If the specified pointer type is incorrect, assert. template <typename T> T get() const { assert(isa<T>(*this) && "Invalid accessor called"); return cast<T>(*this); }Does this make sense ?
Comments inline :) Overall makes good sense to me though!
llvm/include/llvm/ADT/PointerUnion.h | ||
---|---|---|
219 | I think you'll need public inheritance here and below? Otherwise I'd expect that you get compiler errors saying this partial specialization doesn't define the functions you need. |
Thanks for feedback ;)
It seems that partial specialization struct can't be declared as a friend ?
:( I know you can have a templated friend declaration but I guess this doesn't work.
In that case this approach seems fine, thanks for working on it! Just a few more cleanups but overall I think it's looking really solid :)
llvm/include/llvm/ADT/PointerUnion.h | ||
---|---|---|
91 | nit: Full sentences, please. | |
129 | A quick comment to explain what's going on would be great, maybe /// This is needed to give the CastInfo implementation below access to protected members. or something like that? Just a quick one-liner so it's not confusing in the future. | |
216 | Please explain why this struct is needed with a /// comment. | |
249 | Public inheritance here too. Do you have checks that const is handled correctly? |
llvm/include/llvm/ADT/PointerUnion.h | ||
---|---|---|
249 | I've added some test for const case, but I'm not sure whether it's comprehensive enough or not. |
llvm/include/llvm/ADT/PointerUnion.h | ||
---|---|---|
249 | If you see the tests for the cast infra there are some spots where we have auto result = cast<T>(something); followed by a static_assert that decltype(result) must be a specific type. That was the kind of thing I meant here - i.e. if I have a const pointer union and I do cast<float *> (for example), should it return const float *? Or not? I guess what I was going for was to explicitly test "what happens when I have a const input to a cast? How explicit do I have to be? At the bottom there you're really close - it looks like you're on the right track but it would be great to get a static_assert for what the output type of a cast on PU4 is, just to make it explicit. |
llvm/include/llvm/ADT/PointerUnion.h | ||
---|---|---|
249 | What's your opinion about whether it should return a const or non-const pointer when casting from a const PointerUnion ? |
It seems that people are not always using a plain pointer in PointerUnion. Sometimes they seem to use a custom smart pointer ?
update diff
- define our own castFailed in the hope of fixing the build failure of clang.
- add static_assert for type check
Thank you for working on this!
llvm/include/llvm/ADT/PointerUnion.h | ||
---|---|---|
249 | Honestly I'm not sure! I think it comes down to the semantics of PointerUnion, sort of like const void const* where each const means slightly different things. I think the way that seems simplest is to say "yes, const comes out of a const union". The way that I think matches C++'s const rules is "no, const applies to the union, not the things inside". I think in this patch you're using the second way, which is totally fair (and you added tests to make it explicit, so thank you!) | |
llvm/unittests/ADT/PointerUnionTest.cpp | ||
283 | misspelling here, "misamatch" -> "mismatch" |
I'm excited to see this, thank you or working on it. +1 with the changes aman suggested.
Thanks @lattner @bzcheeseman ! I'll land this patch as soon as possible after making sure everything runs smoothly.
nit: Full sentences, please.