-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[ADT] Fix llvm::concat_iterator for ValueT == common_base_class *
#144744
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ADT] Fix llvm::concat_iterator for ValueT == common_base_class *
#144744
Conversation
@llvm/pr-subscribers-llvm-adt Author: Javier Lopez-Gomez (jalopezg-git) ChangesFix In particular, the case below was not working before this patch, but I see no particular reason why it shouldn't be supported.
Full diff: https://github.com/llvm/llvm-project/pull/144744.diff 2 Files Affected:
diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index eea06cfb99ba2..951da522a8aa2 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -1030,14 +1030,15 @@ class concat_iterator
std::forward_iterator_tag, ValueT> {
using BaseT = typename concat_iterator::iterator_facade_base;
- static constexpr bool ReturnsByValue =
- !(std::is_reference_v<decltype(*std::declval<IterTs>())> && ...);
+ static constexpr bool ReturnsValueOrPointer =
+ !(std::is_reference_v<decltype(*std::declval<IterTs>())> && ...)
+ || (std::is_pointer_v<IterTs> && ...);
using reference_type =
- typename std::conditional_t<ReturnsByValue, ValueT, ValueT &>;
+ typename std::conditional_t<ReturnsValueOrPointer, ValueT, ValueT &>;
using handle_type =
- typename std::conditional_t<ReturnsByValue, std::optional<ValueT>,
+ typename std::conditional_t<ReturnsValueOrPointer, std::optional<ValueT>,
ValueT *>;
/// We store both the current and end iterators for each concatenated
@@ -1088,7 +1089,7 @@ class concat_iterator
if (Begin == End)
return {};
- if constexpr (ReturnsByValue)
+ if constexpr (ReturnsValueOrPointer)
return *Begin;
else
return &*Begin;
diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp
index 286cfa745fd14..0e6b040a08f4a 100644
--- a/llvm/unittests/ADT/STLExtrasTest.cpp
+++ b/llvm/unittests/ADT/STLExtrasTest.cpp
@@ -398,6 +398,9 @@ struct some_struct {
std::string swap_val;
};
+struct derives_from_some_struct : some_struct {
+};
+
std::vector<int>::const_iterator begin(const some_struct &s) {
return s.data.begin();
}
@@ -532,6 +535,19 @@ TEST(STLExtrasTest, ConcatRangeADL) {
EXPECT_THAT(concat<const int>(S0, S1), ElementsAre(1, 2, 3, 4));
}
+TEST(STLExtrasTest, ConcatRangePtrToDerivedClass) {
+ auto S0 = std::make_unique<some_namespace::some_struct>();
+ auto S1 = std::make_unique<some_namespace::derives_from_some_struct>();
+ SmallVector<some_namespace::some_struct *> V0{S0.get()};
+ SmallVector<some_namespace::derives_from_some_struct *> V1{S1.get(), S1.get()};
+
+ // Use concat over ranges of pointers to different (but related) types.
+ EXPECT_THAT(concat<some_namespace::some_struct *>(V0, V1),
+ ElementsAre(S0.get(),
+ static_cast<some_namespace::some_struct *>(S1.get()),
+ static_cast<some_namespace::some_struct *>(S1.get())));
+}
+
TEST(STLExtrasTest, MakeFirstSecondRangeADL) {
// Make sure that we use the `begin`/`end` functions from `some_namespace`,
// using ADL.
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
ebdc2a3
to
560fccc
Compare
3d31e30
to
74331ed
Compare
74331ed
to
ca4ae15
Compare
55726cd
to
6af2cf5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took a closer look and I think I understand what the underlying issue was: with mixed pointer types, reference/handle type can no longer be T*&
/ T**
because while it's fine to cast derived pointers to T*
, we can't take an address off them using that base type.
I wonder if we should tighten this check to make sure that at least one input range type doesn't match the ValueT
pointer type, and with that having them be returned via the same logic as ReturnsByValue
doesn't sounds too bad to me. WDYT?
6af2cf5
to
7d7a6a6
Compare
Yeah, I have updated the PR description s.t. it is more clear about that.
The current definition of |
7d7a6a6
to
fd8d8e9
Compare
I think the two pieces of feedback in #144744 (comment) haven't been addressed yet:
|
b27e841
to
c7f9be2
Compare
Apologies for coming back to this w/ almost a 3-month delay 😅; it has been quite hectic due to work in a different project. @kuhar
Tests have been updated; in particular, PTAL at https://github.com/llvm/llvm-project/pull/144744/files#diff-3ec26250dd1ddfd2682b4abed65da0d8cbb509991fc1a7a3795bb29389e3da6cR548 and https://github.com/llvm/llvm-project/pull/144744/files#diff-3ec26250dd1ddfd2682b4abed65da0d8cbb509991fc1a7a3795bb29389e3da6cR569.
In case all |
@kuhar, thank you for your previous feedback -- much appreciated! @CarlosAlbertoEnciso , @jmorse , @kuhar This pull request is now ready for another round of review 👍. |
297dc4d
to
eb2d9ac
Compare
eb2d9ac
to
fec809b
Compare
9bdcf32
to
59312b7
Compare
59312b7
to
73384b5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, just a couple of minor issues
Simplify `llvm::concat_iterator::increment()` and `llvm::concat_iterator::get()`. This makes it possible to also get rid of `handle_type`, which was causing some additional complications.
Fix llvm::concat_iterator for the case of `ValueT` being a pointer to a common base class to which the result of dereferencing any iterator in `ItersT` can be casted to.
73384b5
to
17229ae
Compare
Thank you for the invaluable feedback, @kuhar! |
Fix
llvm::concat_iterator
for the case ofValueT
being a pointer to a common base class to which the result of dereferencing any iterator inItersT
can be casted to. In particular, the case below was not working before this patch, but I see no particular reason why it shouldn't be supported.Per https://en.cppreference.com/w/cpp/language/implicit_conversion.html, Sec. Pointer conversions,
I.e. conversion shall be possible, but the former implementation of
llvm::concat_iterator
forbids that, given thathandle_type
is pointer-to-pointer type, which is not convertible.