Skip to content

[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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jalopezg-git
Copy link
Contributor

@jalopezg-git jalopezg-git commented Jun 18, 2025

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.

In particular, the case below was not working before this patch, but I see no particular reason why it shouldn't be supported.

namespace some_namespace {
struct some_struct {
  std::vector<int> data;
  std::string swap_val;
};

struct derives_from_some_struct : some_struct {
};
} // namespace some_namespace

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())));
}

@jalopezg-git jalopezg-git requested review from kuhar and dwblaikie June 18, 2025 16:19
@jalopezg-git jalopezg-git self-assigned this Jun 18, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 18, 2025

@llvm/pr-subscribers-llvm-adt

Author: Javier Lopez-Gomez (jalopezg-git)

Changes

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.

In particular, the case below was not working before this patch, but I see no particular reason why it shouldn't be supported.

namespace some_namespace {
struct some_struct {
  std::vector&lt;int&gt; data;
  std::string swap_val;
};

struct derives_from_some_struct : some_struct {
};
} // namespace some_namespace

TEST(STLExtrasTest, ConcatRangePtrToDerivedClass) {
  auto S0 = std::make_unique&lt;some_namespace::some_struct&gt;();
  auto S1 = std::make_unique&lt;some_namespace::derives_from_some_struct&gt;();
  SmallVector&lt;some_namespace::some_struct *&gt; V0{S0.get()};
  SmallVector&lt;some_namespace::derives_from_some_struct *&gt; V1{S1.get(), S1.get()};

  // Use concat over ranges of pointers to different (but related) types.
  EXPECT_THAT(concat&lt;some_namespace::some_struct *&gt;(V0, V1),
             ElementsAre(S0.get(),
                         static_cast&lt;some_namespace::some_struct *&gt;(S1.get()),
                         static_cast&lt;some_namespace::some_struct *&gt;(S1.get())));
}

Full diff: https://github.com/llvm/llvm-project/pull/144744.diff

2 Files Affected:

  • (modified) llvm/include/llvm/ADT/STLExtras.h (+6-5)
  • (modified) llvm/unittests/ADT/STLExtrasTest.cpp (+16)
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.

Copy link

github-actions bot commented Jun 18, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Comment on lines 538 to 539
auto S0 = std::make_unique<some_namespace::some_struct>();
auto S1 = std::make_unique<some_namespace::derives_from_some_struct>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we necessarily need unique_ptr to test this, stack allocated values would work too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed 👍; thanks for pointing out!

Comment on lines 1092 to 1096
if constexpr (ReturnsValueOrPointer)
return *Begin;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this wraps pointers with std::optional? Why can't we return pointers here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, let me give it another round of work - this week is WG21 meeting; I was in a hurry but still wanted to open a draft PR.

@jalopezg-git jalopezg-git marked this pull request as draft June 18, 2025 21:49
@jalopezg-git jalopezg-git force-pushed the jalopezg-fix-llvm__concat-related-type branch 6 times, most recently from 3d31e30 to 74331ed Compare June 20, 2025 06:22
@jalopezg-git jalopezg-git marked this pull request as ready for review June 20, 2025 06:24
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.
@jalopezg-git jalopezg-git force-pushed the jalopezg-fix-llvm__concat-related-type branch from 74331ed to ca4ae15 Compare June 20, 2025 06:26
@jalopezg-git jalopezg-git marked this pull request as draft June 20, 2025 07:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants