https://github.com/xxxxbc updated 
https://github.com/llvm/llvm-project/pull/208762

>From ba0ed0b9c401624b778d89a10e6e780eadc3347b Mon Sep 17 00:00:00 2001
From: hehuan <[email protected]>
Date: Fri, 10 Jul 2026 23:50:13 +0800
Subject: [PATCH 1/2] [clang-tidy] Fix invalid code generation for member
 typedefs in readability-use-std-min-max

When the two compared operands have different types, the check emits an
explicit template argument for std::min/std::max. For class member
typedefs (e.g. std::string::size_type), the bare typedef name is not
usable at the fix location, producing code that does not compile.

Fix getNonTemplateAlias() to keep desugaring when the typedef is
declared inside a record (class/struct), so the underlying type is used
instead.

Fixes #208693.
---
 .../readability/UseStdMinMaxCheck.cpp           | 10 +++++++---
 clang-tools-extra/docs/ReleaseNotes.rst         |  5 ++++-
 .../checkers/readability/use-std-min-max.cpp    | 17 +++++++++++++++++
 3 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp 
b/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp
index 38e6dfb5328fa..67396c58736a9 100644
--- a/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp
@@ -63,9 +63,13 @@ static QualType getNonTemplateAlias(QualType QT) {
   while (true) {
     // cast to a TypedefType
     if (const auto *TT = dyn_cast<TypedefType>(QT)) {
-      // check if the typedef is a template and if it is dependent
-      if (!TT->getDecl()->getDescribedTemplate() &&
-          !TT->getDecl()->getDeclContext()->isDependentContext())
+      const TypedefNameDecl *TD = TT->getDecl();
+      // Check if the typedef is a template and if it is dependent. A class
+      // member typedef (e.g. std::string::size_type) is not usable by its
+      // bare name at the location of the fix, so keep desugaring in that case.
+      if (!TD->getDescribedTemplate() &&
+          !TD->getDeclContext()->isDependentContext() &&
+          !TD->getDeclContext()->isRecord())
         return QT;
       QT = TT->desugar();
     } else {
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 66ce08534cae8..8d1edfc0b842e 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -123,7 +123,10 @@ Changes in existing checks
 
 - Improved :doc:`readability-use-std-min-max
   <clang-tidy/checks/readability/use-std-min-max>` check by fixing spurious
-  trailing semicolons and lost comments when the ``if`` body has no braces.
+  trailing semicolons and lost comments when the ``if`` body has no braces, and
+  by fixing invalid code generation when the explicit template argument 
resolved
+  to a class member typedef (for example ``std::string::size_type``); the
+  underlying type is now used instead.
 
 Removed checks
 ^^^^^^^^^^^^^^
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/use-std-min-max.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/readability/use-std-min-max.cpp
index ebc3783e84650..19a2f7b94548f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/use-std-min-max.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/use-std-min-max.cpp
@@ -265,6 +265,23 @@ void f(int &n) {
 }
 } // namespace gh208708
 
+namespace gh208693 {
+struct B {
+protected:
+  typedef unsigned long bsize;
+};
+struct S : B {
+  typedef B::bsize size_type;
+  size_type size() const;
+};
+void f(const S &s, unsigned &n) {
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>` 
[readability-use-std-min-max]
+  // CHECK-FIXES: n = std::max<unsigned long>(s.size(), n);
+  if (s.size() > n)
+    n = s.size();
+}
+} // namespace gh208693
+
 namespace gh121676 {
 
 void useLeft() {

>From b51406f2a6f275cca5becce3b5e475c90b353edb Mon Sep 17 00:00:00 2001
From: hehuan <[email protected]>
Date: Tue, 22 Sep 2026 15:44:25 +0800
Subject: [PATCH 2/2] [clang-tidy] Fully desugar unusable member typedefs

---
 .../readability/UseStdMinMaxCheck.cpp         | 12 ++++++----
 .../checkers/readability/use-std-min-max.cpp  | 23 +++++++++++++++++++
 2 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp 
b/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp
index 67396c58736a9..f6855c35b725b 100644
--- a/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp
@@ -60,23 +60,27 @@ static bool maxCondition(const BinaryOperator::Opcode Op, 
const Expr *CondLhs,
 }
 
 static QualType getNonTemplateAlias(QualType QT) {
+  bool DesugaredRecordAlias = false;
   while (true) {
     // cast to a TypedefType
     if (const auto *TT = dyn_cast<TypedefType>(QT)) {
       const TypedefNameDecl *TD = TT->getDecl();
-      // Check if the typedef is a template and if it is dependent. A class
-      // member typedef (e.g. std::string::size_type) is not usable by its
-      // bare name at the location of the fix, so keep desugaring in that case.
+      // Check if the typedef is a template and if it is dependent.
       if (!TD->getDescribedTemplate() &&
           !TD->getDeclContext()->isDependentContext() &&
           !TD->getDeclContext()->isRecord())
         return QT;
+      DesugaredRecordAlias |= TD->getDeclContext()->isRecord();
       QT = TT->desugar();
     } else {
       break;
     }
   }
-  return QT;
+  // A class member typedef (e.g. std::string::size_type) is not usable by its
+  // bare name at the location of the fix. If desugaring it did not reveal a
+  // usable non-member alias, use the canonical type to also remove dependent
+  // member types exposed by its implementation.
+  return DesugaredRecordAlias ? QT.getCanonicalType() : QT;
 }
 
 static QualType getReplacementCastType(const Expr *CondLhs, const Expr 
*CondRhs,
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/use-std-min-max.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/readability/use-std-min-max.cpp
index 19a2f7b94548f..413eeca3c4012 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/use-std-min-max.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/use-std-min-max.cpp
@@ -274,12 +274,35 @@ struct S : B {
   typedef B::bsize size_type;
   size_type size() const;
 };
+template <class T>
+struct MakeUnsigned {
+  typedef unsigned long type;
+};
+template <class Allocator, class DifferenceType>
+struct SizeType : MakeUnsigned<DifferenceType> {};
+template <class Allocator>
+struct AllocatorTraits {
+  typedef Allocator allocator_type;
+  typedef long difference_type;
+  typedef typename SizeType<allocator_type, difference_type>::type size_type;
+};
+struct StringLike {
+  typedef AllocatorTraits<int> traits_type;
+  typedef typename traits_type::size_type size_type;
+  size_type size() const;
+};
 void f(const S &s, unsigned &n) {
   // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>` 
[readability-use-std-min-max]
   // CHECK-FIXES: n = std::max<unsigned long>(s.size(), n);
   if (s.size() > n)
     n = s.size();
 }
+void f(const StringLike &s, unsigned &n) {
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>` 
[readability-use-std-min-max]
+  // CHECK-FIXES: n = std::max<unsigned long>(s.size(), n);
+  if (s.size() > n)
+    n = s.size();
+}
 } // namespace gh208693
 
 namespace gh121676 {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to