Skip to content

Conversation

@cyndyishida
Copy link
Member

The expectation of this API is that it only changes the major version of a preexisting version tuple. However, it was adding 0's, which causes unintended changes in serialization or printing.

Instead, check for the existence of the non-major parts of the tuple.

VersionTuple::withMajorReplaced

The expectation of this API is to only change the major version of a
preexisting version tuple. However, it was actually adding 0's which
causes unintended changes in serialization or printing.

Instead, check for the existing of the non-major parts of the tuple.
@llvmbot
Copy link
Member

llvmbot commented May 9, 2025

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-clang-driver

@llvm/pr-subscribers-llvm-support

Author: Cyndy Ishida (cyndyishida)

Changes

The expectation of this API is that it only changes the major version of a preexisting version tuple. However, it was adding 0's, which causes unintended changes in serialization or printing.

Instead, check for the existence of the non-major parts of the tuple.


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

3 Files Affected:

  • (modified) llvm/include/llvm/Support/VersionTuple.h (+1-3)
  • (modified) llvm/lib/Support/VersionTuple.cpp (+10)
  • (modified) llvm/unittests/Support/VersionTupleTest.cpp (+30)
diff --git a/llvm/include/llvm/Support/VersionTuple.h b/llvm/include/llvm/Support/VersionTuple.h
index 0a4623f049d28..aeb4798209203 100644
--- a/llvm/include/llvm/Support/VersionTuple.h
+++ b/llvm/include/llvm/Support/VersionTuple.h
@@ -100,9 +100,7 @@ class VersionTuple {
 
   /// Return a version tuple that contains a different major version but
   /// everything else is the same.
-  VersionTuple withMajorReplaced(unsigned NewMajor) const {
-    return VersionTuple(NewMajor, Minor, Subminor, Build);
-  }
+  VersionTuple withMajorReplaced(unsigned NewMajor) const;
 
   /// Return a version tuple that contains only components that are non-zero.
   VersionTuple normalize() const {
diff --git a/llvm/lib/Support/VersionTuple.cpp b/llvm/lib/Support/VersionTuple.cpp
index a4224f23b2f94..c6e20f1bd3ef4 100644
--- a/llvm/lib/Support/VersionTuple.cpp
+++ b/llvm/lib/Support/VersionTuple.cpp
@@ -108,3 +108,13 @@ bool VersionTuple::tryParse(StringRef input) {
   *this = VersionTuple(major, minor, micro, build);
   return false;
 }
+
+VersionTuple VersionTuple::withMajorReplaced(unsigned NewMajor) const {
+  if (HasBuild)
+    return VersionTuple(NewMajor, Minor, Subminor, Build);
+  if (HasSubminor)
+    return VersionTuple(NewMajor, Minor, Subminor);
+  if (HasMinor)
+    return VersionTuple(NewMajor, Minor);
+  return VersionTuple(NewMajor);
+}
diff --git a/llvm/unittests/Support/VersionTupleTest.cpp b/llvm/unittests/Support/VersionTupleTest.cpp
index af6c0a7febad5..d498d670fb710 100644
--- a/llvm/unittests/Support/VersionTupleTest.cpp
+++ b/llvm/unittests/Support/VersionTupleTest.cpp
@@ -47,3 +47,33 @@ TEST(VersionTuple, tryParse) {
   EXPECT_TRUE(VT.tryParse("1 "));
   EXPECT_TRUE(VT.tryParse("."));
 }
+
+TEST(VersionTuple, withMajorReplaced) {
+  VersionTuple VT(2);
+  VersionTuple ReplacedVersion = VT.withMajorReplaced(7);
+  EXPECT_FALSE(ReplacedVersion.getMinor().has_value());
+  EXPECT_FALSE(ReplacedVersion.getSubminor().has_value());
+  EXPECT_FALSE(ReplacedVersion.getBuild().has_value());
+  EXPECT_EQ(VersionTuple(7), ReplacedVersion);
+
+  VT = VersionTuple(100, 1);
+  ReplacedVersion = VT.withMajorReplaced(7);
+  EXPECT_TRUE(ReplacedVersion.getMinor().has_value());
+  EXPECT_FALSE(ReplacedVersion.getSubminor().has_value());
+  EXPECT_FALSE(ReplacedVersion.getBuild().has_value());
+  EXPECT_EQ(VersionTuple(7, 1), ReplacedVersion);
+
+  VT = VersionTuple(101, 11, 12);
+  ReplacedVersion = VT.withMajorReplaced(7);
+  EXPECT_TRUE(ReplacedVersion.getMinor().has_value());
+  EXPECT_TRUE(ReplacedVersion.getSubminor().has_value());
+  EXPECT_FALSE(ReplacedVersion.getBuild().has_value());
+  EXPECT_EQ(VersionTuple(7, 11, 12), ReplacedVersion);
+
+  VT = VersionTuple(101, 11, 12, 2);
+  ReplacedVersion = VT.withMajorReplaced(7);
+  EXPECT_TRUE(ReplacedVersion.getMinor().has_value());
+  EXPECT_TRUE(ReplacedVersion.getSubminor().has_value());
+  EXPECT_TRUE(ReplacedVersion.getBuild().has_value());
+  EXPECT_EQ(VersionTuple(7, 11, 12, 2), ReplacedVersion);
+}

Copy link
Collaborator

@cachemeifyoucan cachemeifyoucan left a comment

Choose a reason for hiding this comment

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

LGTM

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' labels May 9, 2025
@cyndyishida cyndyishida merged commit 12e6622 into llvm:main May 9, 2025
11 of 13 checks passed
@cyndyishida cyndyishida deleted the PR-VersionTupleMajor branch May 9, 2025 23:56
cyndyishida added a commit to cyndyishida/llvm-project that referenced this pull request May 12, 2025
…orReplaced (llvm#139318)

The expectation of this API is that it only changes the major version of
a preexisting version tuple. However, it was adding 0's, which caused
unintended changes in serialization or printing.

Instead, check for the existence of the non-major parts of the tuple.

(cherry picked from commit 12e6622)
cyndyishida added a commit to swiftlang/llvm-project that referenced this pull request May 13, 2025
…orReplaced (llvm#139318)

The expectation of this API is that it only changes the major version of
a preexisting version tuple. However, it was adding 0's, which caused
unintended changes in serialization or printing.

Instead, check for the existence of the non-major parts of the tuple.

(cherry picked from commit 12e6622)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category llvm:support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants