Skip to content

Conversation

localspook
Copy link
Contributor

@localspook localspook commented Aug 6, 2025

modernize-replace-auto-ptr, modernize-use-equals-delete, and modernize-use-auto use std::unique_ptr, = delete, and auto respectively, which are all C++11 features.

The interesting bit is modernize-use-nullptr's tests:

  • Some relied on int-to-pointer conversions that were removed in C++11. There are two variations here. First, tests like this, which become ill-formed:
    const int null = 0;
    void * ptr = null;
    I just deleted these cases; if they're ill-formed, we're not losing anything, right?
    Second, tests like this:
    float * ptr = (float *)int(0.f);
    These don't become ill-formed, but start generating a different AST. In C++98, they are NullToPointer conversions, but in C++11, they become generic IntegralToPointer conversions. I deleted these cases too, though I'm less sure here.
  • Folded struct Bar into class A, because those both suffer from the same false negatives.

@llvmbot
Copy link
Member

llvmbot commented Aug 6, 2025

@llvm/pr-subscribers-clang-tools-extra

Author: Victor Chernyakin (localspook)

Changes

modernize-replace-auto-ptr, modernize-use-equals-delete, and modernize-use-auto use std::unique_ptr, = delete, and auto respectively, which are all C++11 features.

The interesting bit is modernize-use-nullptr's tests:

  • Some relied on int-to-pointer conversions that were removed in C++11. I just deleted these cases; if they're ill-formed, we're not losing anything, right?
  • Uncovered some cases that are false negatives in C++11 mode.

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

5 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h (+1-1)
  • (modified) clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h (+1-1)
  • (modified) clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h (+1-1)
  • (modified) clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h (+1-3)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-basic.cpp (+25-77)
diff --git a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h
index 636481300d730..c91f5f580c524 100644
--- a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h
@@ -42,7 +42,7 @@ class ReplaceAutoPtrCheck : public ClangTidyCheck {
 public:
   ReplaceAutoPtrCheck(StringRef Name, ClangTidyContext *Context);
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    return LangOpts.CPlusPlus;
+    return LangOpts.CPlusPlus11;
   }
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
diff --git a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h
index 76c52b2d28139..7a9bbbe1cdf77 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h
@@ -17,7 +17,7 @@ class UseAutoCheck : public ClangTidyCheck {
 public:
   UseAutoCheck(StringRef Name, ClangTidyContext *Context);
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    return LangOpts.CPlusPlus;
+    return LangOpts.CPlusPlus11;
   }
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
diff --git a/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h b/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h
index 64f60351c0657..dc3e712482c21 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h
@@ -23,7 +23,7 @@ class UseEqualsDeleteCheck : public ClangTidyCheck {
 public:
   UseEqualsDeleteCheck(StringRef Name, ClangTidyContext *Context);
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    return LangOpts.CPlusPlus;
+    return LangOpts.CPlusPlus11;
   }
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
diff --git a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
index f1591bae44657..4c02f8ccdf303 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
@@ -17,9 +17,7 @@ class UseNullptrCheck : public ClangTidyCheck {
 public:
   UseNullptrCheck(StringRef Name, ClangTidyContext *Context);
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    // FIXME this should be CPlusPlus11 but that causes test cases to
-    // erroneously fail.
-    return LangOpts.CPlusPlus || LangOpts.C23;
+    return LangOpts.CPlusPlus11 || LangOpts.C23;
   }
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-basic.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-basic.cpp
index 2579099148e3a..4f69ec5aeeb4c 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-basic.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-basic.cpp
@@ -1,9 +1,4 @@
-// RUN: %check_clang_tidy -std=c++98 %s modernize-use-nullptr %t -- -- -Wno-non-literal-null-conversion
-//
-// Some parts of the test (e.g. assignment of `const int` to `int *`) fail in
-// C++11, so we need to run the test in C++98 mode.
-//
-// FIXME: Make the test work in all language modes.
+// RUN: %check_clang_tidy %s modernize-use-nullptr %t -- -- -Wno-non-literal-null-conversion
 
 const unsigned int g_null = 0;
 #define NULL 0
@@ -23,11 +18,7 @@ void test_assignment() {
   p2 = p1;
   // CHECK-FIXES: p2 = p1;
 
-  const int null = 0;
-  int *p3 = null;
-  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
-  // CHECK-FIXES: int *p3 = nullptr;
-
+  int *p3;
   p3 = NULL;
   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr
   // CHECK-FIXES: p3 = nullptr;
@@ -35,14 +26,11 @@ void test_assignment() {
   int *p4 = p3;
   // CHECK-FIXES: int *p4 = p3;
 
-  p4 = null;
-  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr
-  // CHECK-FIXES: p4 = nullptr;
-
   int i1 = 0;
 
   int i2 = NULL;
 
+  const int null = 0;
   int i3 = null;
 
   int *p5, *p6, *p7;
@@ -70,33 +58,30 @@ int *Foo::m_p2 = NULL;
 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr
 // CHECK-FIXES: int *Foo::m_p2 = nullptr;
 
+// FIXME: all these DISABLED-* cases should trigger the warning.
 template <typename T>
 struct Bar {
   Bar(T *p) : m_p(p) {
     m_p = static_cast<T*>(NULL);
-    // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr
-    // CHECK-FIXES: m_p = static_cast<T*>(nullptr);
+    // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr
+    // DISABLED-CHECK-FIXES: m_p = static_cast<T*>(nullptr);
 
     m_p = static_cast<T*>(reinterpret_cast<int*>((void*)NULL));
     // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr
     // CHECK-FIXES: m_p = static_cast<T*>(nullptr);
 
-    m_p = static_cast<T*>(p ? p : static_cast<void*>(g_null));
-    // CHECK-MESSAGES: :[[@LINE-1]]:54: warning: use nullptr
-    // CHECK-FIXES: m_p = static_cast<T*>(p ? p : static_cast<void*>(nullptr));
-
     T *p2 = static_cast<T*>(reinterpret_cast<int*>((void*)NULL));
     // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr
     // CHECK-FIXES: T *p2 = static_cast<T*>(nullptr);
 
     m_p = NULL;
-    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use nullptr
-    // CHECK-FIXES: m_p = nullptr;
+    // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use nullptr
+    // DISABLED-CHECK-FIXES: m_p = nullptr;
 
     int i = static_cast<int>(0.f);
     T *i2 = static_cast<int>(0.f);
-    // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
-    // CHECK-FIXES: T *i2 = nullptr;
+    // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
+    // DISABLED-CHECK-FIXES: T *i2 = nullptr;
   }
 
   T *m_p;
@@ -108,9 +93,7 @@ struct Baz {
 };
 
 void test_cxx_cases() {
-  Foo f(g_null);
-  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr
-  // CHECK-FIXES: Foo f(nullptr);
+  Foo f;
 
   f.bar(NULL);
   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr
@@ -122,10 +105,6 @@ void test_cxx_cases() {
   // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr
   // CHECK-FIXES: f.m_p1 = nullptr;
 
-  Bar<int> b(g_null);
-  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr
-  // CHECK-FIXES: Bar<int> b(nullptr);
-
   Baz b2;
   int Baz::*memptr(0);
   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use nullptr
@@ -144,10 +123,6 @@ void test_function_default_param2(void *p = NULL);
 // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use nullptr
 // CHECK-FIXES: void test_function_default_param2(void *p = nullptr);
 
-void test_function_default_param3(void *p = g_null);
-// CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use nullptr
-// CHECK-FIXES: void test_function_default_param3(void *p = nullptr);
-
 void test_function(int *p) {}
 
 void test_function_no_ptr_param(int i) {}
@@ -161,10 +136,6 @@ void test_function_call() {
   // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr
   // CHECK-FIXES: test_function(nullptr);
 
-  test_function(g_null);
-  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr
-  // CHECK-FIXES: test_function(nullptr);
-
   test_function_no_ptr_param(0);
 }
 
@@ -180,51 +151,33 @@ void *test_function_return2() {
   // CHECK-FIXES: return nullptr;
 }
 
-long *test_function_return3() {
-  return g_null;
-  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
-  // CHECK-FIXES: return nullptr;
-}
-
-int test_function_return4() {
+int test_function_return3() {
   return 0;
 }
 
-int test_function_return5() {
+int test_function_return4() {
   return NULL;
 }
 
-int test_function_return6() {
+int test_function_return5() {
   return g_null;
 }
 
-int *test_function_return_cast1() {
-  return(int)0;
-  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr
-  // CHECK-FIXES: return nullptr;
-}
-
-int *test_function_return_cast2() {
+int *test_function_return_cast() {
 #define RET return
-  RET(int)0;
-  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use nullptr
+  RET 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr
   // CHECK-FIXES: RET nullptr;
 #undef RET
 }
 
 // Test parentheses expressions resulting in a nullptr.
-int *test_parentheses_expression1() {
+int *test_parentheses_expression() {
   return(0);
   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
   // CHECK-FIXES: return(nullptr);
 }
 
-int *test_parentheses_expression2() {
-  return(int(0.f));
-  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
-  // CHECK-FIXES: return(nullptr);
-}
-
 int *test_nested_parentheses_expression() {
   return((((0))));
   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
@@ -243,10 +196,11 @@ void *test_parentheses_explicit_cast_sequence1() {
   // CHECK-FIXES: return(static_cast<void*>(nullptr));
 }
 
+// FIXME: this case should trigger the warning.
 void *test_parentheses_explicit_cast_sequence2() {
   return(static_cast<void*>(reinterpret_cast<int*>((float*)int(0.f))));
-  // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr
-  // CHECK-FIXES: return(static_cast<void*>(nullptr));
+  // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr
+  // DISABLED-CHECK-FIXES: return(static_cast<void*>(nullptr));
 }
 
 // Test explicit cast expressions resulting in nullptr.
@@ -313,19 +267,13 @@ void test_const_pointers() {
   const int *const_p2 = NULL;
   // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
   // CHECK-FIXES: const int *const_p2 = nullptr;
-  const int *const_p3 = (int)0;
-  // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
-  // CHECK-FIXES: const int *const_p3 = nullptr;
-  const int *const_p4 = (int)0.0f;
-  // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
-  // CHECK-FIXES: const int *const_p4 = nullptr;
-  const int *const_p5 = (int*)0;
+  const int *const_p3 = (int*)0;
   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: use nullptr
-  // CHECK-FIXES: const int *const_p5 = (int*)nullptr;
+  // CHECK-FIXES: const int *const_p3 = (int*)nullptr;
   int *t;
-  const int *const_p6 = static_cast<int*>(t ? t : static_cast<int*>(0));
+  const int *const_p4 = static_cast<int*>(t ? t : static_cast<int*>(0));
   // CHECK-MESSAGES: :[[@LINE-1]]:69: warning: use nullptr
-  // CHECK-FIXES: const int *const_p6 = static_cast<int*>(t ? t : static_cast<int*>(nullptr));
+  // CHECK-FIXES: const int *const_p4 = static_cast<int*>(t ? t : static_cast<int*>(nullptr));
 }
 
 void test_nested_implicit_cast_expr() {

@llvmbot
Copy link
Member

llvmbot commented Aug 6, 2025

@llvm/pr-subscribers-clang-tidy

Author: Victor Chernyakin (localspook)

Changes

modernize-replace-auto-ptr, modernize-use-equals-delete, and modernize-use-auto use std::unique_ptr, = delete, and auto respectively, which are all C++11 features.

The interesting bit is modernize-use-nullptr's tests:

  • Some relied on int-to-pointer conversions that were removed in C++11. I just deleted these cases; if they're ill-formed, we're not losing anything, right?
  • Uncovered some cases that are false negatives in C++11 mode.

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

5 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h (+1-1)
  • (modified) clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h (+1-1)
  • (modified) clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h (+1-1)
  • (modified) clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h (+1-3)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-basic.cpp (+25-77)
diff --git a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h
index 636481300d730..c91f5f580c524 100644
--- a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h
@@ -42,7 +42,7 @@ class ReplaceAutoPtrCheck : public ClangTidyCheck {
 public:
   ReplaceAutoPtrCheck(StringRef Name, ClangTidyContext *Context);
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    return LangOpts.CPlusPlus;
+    return LangOpts.CPlusPlus11;
   }
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
diff --git a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h
index 76c52b2d28139..7a9bbbe1cdf77 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h
@@ -17,7 +17,7 @@ class UseAutoCheck : public ClangTidyCheck {
 public:
   UseAutoCheck(StringRef Name, ClangTidyContext *Context);
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    return LangOpts.CPlusPlus;
+    return LangOpts.CPlusPlus11;
   }
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
diff --git a/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h b/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h
index 64f60351c0657..dc3e712482c21 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h
@@ -23,7 +23,7 @@ class UseEqualsDeleteCheck : public ClangTidyCheck {
 public:
   UseEqualsDeleteCheck(StringRef Name, ClangTidyContext *Context);
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    return LangOpts.CPlusPlus;
+    return LangOpts.CPlusPlus11;
   }
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
diff --git a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
index f1591bae44657..4c02f8ccdf303 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
@@ -17,9 +17,7 @@ class UseNullptrCheck : public ClangTidyCheck {
 public:
   UseNullptrCheck(StringRef Name, ClangTidyContext *Context);
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    // FIXME this should be CPlusPlus11 but that causes test cases to
-    // erroneously fail.
-    return LangOpts.CPlusPlus || LangOpts.C23;
+    return LangOpts.CPlusPlus11 || LangOpts.C23;
   }
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-basic.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-basic.cpp
index 2579099148e3a..4f69ec5aeeb4c 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-basic.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-basic.cpp
@@ -1,9 +1,4 @@
-// RUN: %check_clang_tidy -std=c++98 %s modernize-use-nullptr %t -- -- -Wno-non-literal-null-conversion
-//
-// Some parts of the test (e.g. assignment of `const int` to `int *`) fail in
-// C++11, so we need to run the test in C++98 mode.
-//
-// FIXME: Make the test work in all language modes.
+// RUN: %check_clang_tidy %s modernize-use-nullptr %t -- -- -Wno-non-literal-null-conversion
 
 const unsigned int g_null = 0;
 #define NULL 0
@@ -23,11 +18,7 @@ void test_assignment() {
   p2 = p1;
   // CHECK-FIXES: p2 = p1;
 
-  const int null = 0;
-  int *p3 = null;
-  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
-  // CHECK-FIXES: int *p3 = nullptr;
-
+  int *p3;
   p3 = NULL;
   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr
   // CHECK-FIXES: p3 = nullptr;
@@ -35,14 +26,11 @@ void test_assignment() {
   int *p4 = p3;
   // CHECK-FIXES: int *p4 = p3;
 
-  p4 = null;
-  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr
-  // CHECK-FIXES: p4 = nullptr;
-
   int i1 = 0;
 
   int i2 = NULL;
 
+  const int null = 0;
   int i3 = null;
 
   int *p5, *p6, *p7;
@@ -70,33 +58,30 @@ int *Foo::m_p2 = NULL;
 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr
 // CHECK-FIXES: int *Foo::m_p2 = nullptr;
 
+// FIXME: all these DISABLED-* cases should trigger the warning.
 template <typename T>
 struct Bar {
   Bar(T *p) : m_p(p) {
     m_p = static_cast<T*>(NULL);
-    // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr
-    // CHECK-FIXES: m_p = static_cast<T*>(nullptr);
+    // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr
+    // DISABLED-CHECK-FIXES: m_p = static_cast<T*>(nullptr);
 
     m_p = static_cast<T*>(reinterpret_cast<int*>((void*)NULL));
     // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr
     // CHECK-FIXES: m_p = static_cast<T*>(nullptr);
 
-    m_p = static_cast<T*>(p ? p : static_cast<void*>(g_null));
-    // CHECK-MESSAGES: :[[@LINE-1]]:54: warning: use nullptr
-    // CHECK-FIXES: m_p = static_cast<T*>(p ? p : static_cast<void*>(nullptr));
-
     T *p2 = static_cast<T*>(reinterpret_cast<int*>((void*)NULL));
     // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr
     // CHECK-FIXES: T *p2 = static_cast<T*>(nullptr);
 
     m_p = NULL;
-    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use nullptr
-    // CHECK-FIXES: m_p = nullptr;
+    // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use nullptr
+    // DISABLED-CHECK-FIXES: m_p = nullptr;
 
     int i = static_cast<int>(0.f);
     T *i2 = static_cast<int>(0.f);
-    // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
-    // CHECK-FIXES: T *i2 = nullptr;
+    // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
+    // DISABLED-CHECK-FIXES: T *i2 = nullptr;
   }
 
   T *m_p;
@@ -108,9 +93,7 @@ struct Baz {
 };
 
 void test_cxx_cases() {
-  Foo f(g_null);
-  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr
-  // CHECK-FIXES: Foo f(nullptr);
+  Foo f;
 
   f.bar(NULL);
   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr
@@ -122,10 +105,6 @@ void test_cxx_cases() {
   // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr
   // CHECK-FIXES: f.m_p1 = nullptr;
 
-  Bar<int> b(g_null);
-  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr
-  // CHECK-FIXES: Bar<int> b(nullptr);
-
   Baz b2;
   int Baz::*memptr(0);
   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use nullptr
@@ -144,10 +123,6 @@ void test_function_default_param2(void *p = NULL);
 // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use nullptr
 // CHECK-FIXES: void test_function_default_param2(void *p = nullptr);
 
-void test_function_default_param3(void *p = g_null);
-// CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use nullptr
-// CHECK-FIXES: void test_function_default_param3(void *p = nullptr);
-
 void test_function(int *p) {}
 
 void test_function_no_ptr_param(int i) {}
@@ -161,10 +136,6 @@ void test_function_call() {
   // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr
   // CHECK-FIXES: test_function(nullptr);
 
-  test_function(g_null);
-  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr
-  // CHECK-FIXES: test_function(nullptr);
-
   test_function_no_ptr_param(0);
 }
 
@@ -180,51 +151,33 @@ void *test_function_return2() {
   // CHECK-FIXES: return nullptr;
 }
 
-long *test_function_return3() {
-  return g_null;
-  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
-  // CHECK-FIXES: return nullptr;
-}
-
-int test_function_return4() {
+int test_function_return3() {
   return 0;
 }
 
-int test_function_return5() {
+int test_function_return4() {
   return NULL;
 }
 
-int test_function_return6() {
+int test_function_return5() {
   return g_null;
 }
 
-int *test_function_return_cast1() {
-  return(int)0;
-  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr
-  // CHECK-FIXES: return nullptr;
-}
-
-int *test_function_return_cast2() {
+int *test_function_return_cast() {
 #define RET return
-  RET(int)0;
-  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use nullptr
+  RET 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr
   // CHECK-FIXES: RET nullptr;
 #undef RET
 }
 
 // Test parentheses expressions resulting in a nullptr.
-int *test_parentheses_expression1() {
+int *test_parentheses_expression() {
   return(0);
   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
   // CHECK-FIXES: return(nullptr);
 }
 
-int *test_parentheses_expression2() {
-  return(int(0.f));
-  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
-  // CHECK-FIXES: return(nullptr);
-}
-
 int *test_nested_parentheses_expression() {
   return((((0))));
   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
@@ -243,10 +196,11 @@ void *test_parentheses_explicit_cast_sequence1() {
   // CHECK-FIXES: return(static_cast<void*>(nullptr));
 }
 
+// FIXME: this case should trigger the warning.
 void *test_parentheses_explicit_cast_sequence2() {
   return(static_cast<void*>(reinterpret_cast<int*>((float*)int(0.f))));
-  // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr
-  // CHECK-FIXES: return(static_cast<void*>(nullptr));
+  // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr
+  // DISABLED-CHECK-FIXES: return(static_cast<void*>(nullptr));
 }
 
 // Test explicit cast expressions resulting in nullptr.
@@ -313,19 +267,13 @@ void test_const_pointers() {
   const int *const_p2 = NULL;
   // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
   // CHECK-FIXES: const int *const_p2 = nullptr;
-  const int *const_p3 = (int)0;
-  // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
-  // CHECK-FIXES: const int *const_p3 = nullptr;
-  const int *const_p4 = (int)0.0f;
-  // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
-  // CHECK-FIXES: const int *const_p4 = nullptr;
-  const int *const_p5 = (int*)0;
+  const int *const_p3 = (int*)0;
   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: use nullptr
-  // CHECK-FIXES: const int *const_p5 = (int*)nullptr;
+  // CHECK-FIXES: const int *const_p3 = (int*)nullptr;
   int *t;
-  const int *const_p6 = static_cast<int*>(t ? t : static_cast<int*>(0));
+  const int *const_p4 = static_cast<int*>(t ? t : static_cast<int*>(0));
   // CHECK-MESSAGES: :[[@LINE-1]]:69: warning: use nullptr
-  // CHECK-FIXES: const int *const_p6 = static_cast<int*>(t ? t : static_cast<int*>(nullptr));
+  // CHECK-FIXES: const int *const_p4 = static_cast<int*>(t ? t : static_cast<int*>(nullptr));
 }
 
 void test_nested_implicit_cast_expr() {

@vbvictor
Copy link
Contributor

vbvictor commented Aug 8, 2025

For some reason, there's also variation between OSes.

Some warnings on Windows doesn't show probably because there is no -fno-delayed-template-parsing. You could add this flag and check if some tests begin to pass.

Also, I think we could use -target flag to specify the OS and not disable tests for all OSes.

@localspook
Copy link
Contributor Author

-fno-delayed-template-parsing did the trick for some tests! And it was a good hint that helped me figure out why the others were inconsistent: -fms-extensions apparently enables C++98-style int-to-pointer conversions in higher language versions, which affects the generated AST. I've updated the PR description to cover the changes.

Copy link
Contributor

@carlosgalvezp carlosgalvezp left a comment

Choose a reason for hiding this comment

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

LGTM, couple tiny comments/questions

@localspook localspook merged commit bcb3bd0 into llvm:main Sep 4, 2025
9 checks passed
@localspook localspook deleted the only-in-cpp11 branch September 4, 2025 17:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants