[clang-tools-extra] [clang-tidy] detect redundant uses of LLVM's cast, dyn_cast (PR #189274)

Henrik G. Olsson via cfe-commits cfe-commits at lists.llvm.org
Sun Mar 29 11:52:40 PDT 2026


https://github.com/hnrklssn updated https://github.com/llvm/llvm-project/pull/189274

>From 3c91a0e1744ce531af38404ffa7c20409937d79b Mon Sep 17 00:00:00 2001
From: "Henrik G. Olsson" <h_olsson at apple.com>
Date: Sun, 29 Mar 2026 10:39:21 -0700
Subject: [PATCH 1/2] [clang-tidy] detect redundant uses of LLVM's cast,
 dyn_cast

Warns when casting to the same pointee type, or when the target
pointee type is a super type of the argument's pointee type.
Supported functions:
 - cast
 - cast_if_present
 - cast_or_null
 - dyn_cast
 - dyn_cast_if_present
 - dyn_cast_or_null
---
 .../clang-tidy/llvm/CMakeLists.txt            |   1 +
 .../clang-tidy/llvm/LLVMTidyModule.cpp        |   3 +
 .../clang-tidy/llvm/RedundantCastingCheck.cpp | 131 ++++++++++++++
 .../clang-tidy/llvm/RedundantCastingCheck.h   |  33 ++++
 clang-tools-extra/docs/ReleaseNotes.rst       |   5 +
 .../docs/clang-tidy/checks/list.rst           |   1 +
 .../checks/llvm/redundant-casting.rst         |  24 +++
 .../checkers/llvm/redundant-casting.cpp       | 163 ++++++++++++++++++
 8 files changed, 361 insertions(+)
 create mode 100644 clang-tools-extra/clang-tidy/llvm/RedundantCastingCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/llvm/RedundantCastingCheck.h
 create mode 100644 clang-tools-extra/docs/clang-tidy/checks/llvm/redundant-casting.rst
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/llvm/redundant-casting.cpp

diff --git a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
index a807f0ab65f87..c81882e0e2024 100644
--- a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
@@ -10,6 +10,7 @@ add_clang_library(clangTidyLLVMModule STATIC
   PreferIsaOrDynCastInConditionalsCheck.cpp
   PreferRegisterOverUnsignedCheck.cpp
   PreferStaticOverAnonymousNamespaceCheck.cpp
+  RedundantCastingCheck.cpp
   TwineLocalCheck.cpp
   TypeSwitchCaseTypesCheck.cpp
   UseNewMLIROpBuilderCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
index c180574bdeed6..104fcf63712f7 100644
--- a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
@@ -16,6 +16,7 @@
 #include "PreferIsaOrDynCastInConditionalsCheck.h"
 #include "PreferRegisterOverUnsignedCheck.h"
 #include "PreferStaticOverAnonymousNamespaceCheck.h"
+#include "RedundantCastingCheck.h"
 #include "TwineLocalCheck.h"
 #include "TypeSwitchCaseTypesCheck.h"
 #include "UseNewMLIROpBuilderCheck.h"
@@ -43,6 +44,8 @@ class LLVMModule : public ClangTidyModule {
         "llvm-prefer-static-over-anonymous-namespace");
     CheckFactories.registerCheck<readability::QualifiedAutoCheck>(
         "llvm-qualified-auto");
+    CheckFactories.registerCheck<RedundantCastingCheck>(
+        "llvm-redundant-casting");
     CheckFactories.registerCheck<TwineLocalCheck>("llvm-twine-local");
     CheckFactories.registerCheck<TypeSwitchCaseTypesCheck>(
         "llvm-type-switch-case-types");
diff --git a/clang-tools-extra/clang-tidy/llvm/RedundantCastingCheck.cpp b/clang-tools-extra/clang-tidy/llvm/RedundantCastingCheck.cpp
new file mode 100644
index 0000000000000..a29701cc012b6
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/llvm/RedundantCastingCheck.cpp
@@ -0,0 +1,131 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantCastingCheck.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::llvm_check {
+
+namespace {
+AST_MATCHER(Expr, isMacroID) { return Node.getExprLoc().isMacroID(); }
+AST_MATCHER_P(OverloadExpr, hasAnyUnresolvedName, ArrayRef<StringRef>, Names) {
+  auto DeclName = Node.getName();
+  if (!DeclName.isIdentifier())
+    return false;
+  const IdentifierInfo *II = DeclName.getAsIdentifierInfo();
+  return llvm::any_of(Names, [II](StringRef Name) { return II->isStr(Name); });
+}
+} // namespace
+
+static StringRef FunctionNames[] = {
+    "cast",     "cast_or_null",     "cast_if_present",
+    "dyn_cast", "dyn_cast_or_null", "dyn_cast_if_present"};
+
+void RedundantCastingCheck::registerMatchers(MatchFinder *Finder) {
+  auto AnyCalleeName = [](ArrayRef<StringRef> CalleeName) {
+    return allOf(unless(isMacroID()), unless(cxxMemberCallExpr()),
+                 callee(expr(ignoringImpCasts(
+                     declRefExpr(to(namedDecl(hasAnyName(CalleeName))),
+                                 hasAnyTemplateArgumentLoc(anything()))
+                         .bind("callee")))));
+  };
+  auto AnyCalleeNameInUninstantiatedTemplate =
+      [](ArrayRef<StringRef> CalleeName) {
+        return allOf(unless(isMacroID()), unless(cxxMemberCallExpr()),
+                     callee(expr(ignoringImpCasts(
+                         unresolvedLookupExpr(hasAnyUnresolvedName(CalleeName))
+                             .bind("callee")))));
+      };
+  Finder->addMatcher(
+      callExpr(
+          AnyCalleeName(FunctionNames),
+          hasAncestor(functionDecl().bind("context")))
+          .bind("call"),
+      this);
+  Finder->addMatcher(
+      callExpr(AnyCalleeNameInUninstantiatedTemplate(FunctionNames))
+          .bind("call"),
+      this);
+}
+
+static QualType stripPointerOrReference(QualType Ty) {
+  QualType Pointee = Ty->getPointeeType();
+  if (Pointee.isNull())
+    return Ty;
+  return Pointee;
+}
+
+void RedundantCastingCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto &Nodes = Result.Nodes;
+  const auto *Call = Nodes.getNodeAs<CallExpr>("call");
+  if (Call->getNumArgs() != 1)
+    return;
+
+  CanQualType RetTy;
+  std::string FuncName;
+  if (const auto *ResolvedCallee = Nodes.getNodeAs<DeclRefExpr>("callee")) {
+    const auto *F = dyn_cast<FunctionDecl>(ResolvedCallee->getDecl());
+    const auto *SurroundingFunc = Nodes.getNodeAs<FunctionDecl>("context");
+    // Casts can be redundant for some instantiations but not others.
+    // Only emit warnings in templates in the uninstantated versions.
+    if (SurroundingFunc->isTemplateInstantiation())
+      return;
+
+    RetTy = stripPointerOrReference(F->getReturnType())
+                ->getCanonicalTypeUnqualified();
+    FuncName = F->getName();
+  } else if (const auto *UnresolvedCallee =
+                 Nodes.getNodeAs<UnresolvedLookupExpr>("callee")) {
+    if (UnresolvedCallee->getNumTemplateArgs() != 1)
+      return;
+    auto TArg = UnresolvedCallee->template_arguments()[0].getArgument();
+    if (TArg.getKind() != TemplateArgument::Type)
+      return;
+
+    RetTy = TArg.getAsType()->getCanonicalTypeUnqualified();
+    FuncName = UnresolvedCallee->getName().getAsString();
+  } else {
+    return;
+  }
+
+  const auto *Arg = Call->getArg(0);
+  const CanQualType FromTy =
+      stripPointerOrReference(Arg->getType())->getCanonicalTypeUnqualified();
+  const auto *FromDecl = FromTy->getAsCXXRecordDecl();
+  const auto *RetDecl = RetTy->getAsCXXRecordDecl();
+  const bool IsDerived = FromDecl && RetDecl && FromDecl->isDerivedFrom(RetDecl);
+  if (FromTy != RetTy && !IsDerived)
+    return;
+
+  auto GetText = [&](SourceRange R) {
+    return Lexer::getSourceText(CharSourceRange::getTokenRange(R),
+                                *Result.SourceManager, getLangOpts());
+  };
+  StringRef ArgText = GetText(Arg->getSourceRange());
+  diag(Call->getExprLoc(), "redundant use of '%0'")
+      << FuncName
+      << FixItHint::CreateReplacement(Call->getSourceRange(), ArgText);
+  diag(Arg->getExprLoc(), "source expression %0 has type %1",
+       DiagnosticIDs::Note)
+      << Arg << Arg->IgnoreParenImpCasts()->getType();
+
+  if (FromTy != RetTy) {
+    diag(Arg->getExprLoc(), "%0 is a subtype of %1", DiagnosticIDs::Note)
+        << FromTy << RetTy;
+  }
+}
+
+} // namespace clang::tidy::llvm_check
diff --git a/clang-tools-extra/clang-tidy/llvm/RedundantCastingCheck.h b/clang-tools-extra/clang-tidy/llvm/RedundantCastingCheck.h
new file mode 100644
index 0000000000000..3243616976014
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/llvm/RedundantCastingCheck.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_REDUNDANTCASTINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_REDUNDANTCASTINGCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::llvm_check {
+
+/// Detect redundant uses of LLVM's cast and dyn_cast functions.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/llvm/redundant-casting.html
+class RedundantCastingCheck : public ClangTidyCheck {
+public:
+  RedundantCastingCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus;
+  }
+};
+
+} // namespace clang::tidy::llvm_check
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_REDUNDANTCASTINGCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index eb735e6e62ee4..43d67e0831fd9 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -114,6 +114,11 @@ New checks
   Finds functions where throwing exceptions is unsafe but the function is still
   marked as potentially throwing.
 
+- New :doc:`llvm-redundant-casting
+  <clang-tidy/checks/llvm/redundant-casting>` check.
+
+  Detect redundant uses of LLVM's cast functions.
+
 - New :doc:`llvm-type-switch-case-types
   <clang-tidy/checks/llvm/type-switch-case-types>` check.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index ceab1e9414951..03ed10217fe45 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -251,6 +251,7 @@ Clang-Tidy Checks
    :doc:`llvm-prefer-isa-or-dyn-cast-in-conditionals <llvm/prefer-isa-or-dyn-cast-in-conditionals>`, "Yes"
    :doc:`llvm-prefer-register-over-unsigned <llvm/prefer-register-over-unsigned>`, "Yes"
    :doc:`llvm-prefer-static-over-anonymous-namespace <llvm/prefer-static-over-anonymous-namespace>`,
+   :doc:`llvm-redundant-casting <llvm/redundant-casting>`, "Yes"
    :doc:`llvm-twine-local <llvm/twine-local>`, "Yes"
    :doc:`llvm-type-switch-case-types <llvm/type-switch-case-types>`, "Yes"
    :doc:`llvm-use-new-mlir-op-builder <llvm/use-new-mlir-op-builder>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/redundant-casting.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm/redundant-casting.rst
new file mode 100644
index 0000000000000..c09bc40dd207e
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/redundant-casting.rst
@@ -0,0 +1,24 @@
+.. title:: clang-tidy - llvm-redundant-casting
+
+llvm-redundant-casting
+======================
+
+Points out uses of ``cast<>``, ``dyn_cast<>`` and their ``or_null`` variants
+that are unnecessary because the argument already is of the target type, or a
+derived type thereof.
+
+.. code-block:: c++
+
+  struct A {};
+  A a;
+  // Finds:
+  A x = cast<A>(a);
+  // replaced by:
+  A x = a;
+
+  struct B : public A {};
+  B b;
+  // Finds:
+  A y = cast<A>(b);
+  // replaced by:
+  A y = b;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/redundant-casting.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/redundant-casting.cpp
new file mode 100644
index 0000000000000..4027933f95c4b
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/redundant-casting.cpp
@@ -0,0 +1,163 @@
+// RUN: %check_clang_tidy -std=c++17 %s llvm-redundant-casting %t
+
+namespace llvm {
+#define CAST_FUNCTION(name)                                          \
+template <typename To, typename From>                                \
+[[nodiscard]] inline decltype(auto) name(const From &Val) {          \
+  return static_cast<const To&>(Val);                                \
+}                                                                    \
+template <typename To, typename From>                                \
+[[nodiscard]] inline decltype(auto) name(From &Val) {                \
+  return static_cast<To&>(Val);                                      \
+}                                                                    \
+template <typename To, typename From>                                \
+[[nodiscard]] inline decltype(auto) name(const From *Val) {          \
+  return static_cast<const To*>(Val);                                \
+}                                                                    \
+template <typename To, typename From>                                \
+[[nodiscard]] inline decltype(auto) name(From *Val) {                \
+  return static_cast<To*>(Val);                                      \
+}
+CAST_FUNCTION(cast)
+CAST_FUNCTION(dyn_cast)
+CAST_FUNCTION(cast_or_null)
+CAST_FUNCTION(cast_if_present)
+CAST_FUNCTION(dyn_cast_or_null)
+CAST_FUNCTION(dyn_cast_if_present)
+}
+
+struct A {};
+struct B : A {};
+A &getA();
+
+void testCast(A& value) {
+  A& a1 = llvm::cast<A>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant use of 'cast' [llvm-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:25: note: source expression 'value' has type 'A'
+  // CHECK-FIXES: A& a1 = value;
+  (void)a1;
+}
+
+void testDynCast(A& value) {
+  A& a2 = llvm::dyn_cast<A>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant use of 'dyn_cast' [llvm-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:29: note: source expression 'value' has type 'A'
+  // CHECK-FIXES: A& a2 = value;
+  (void)a2;
+}
+
+void testCastOrNull(A& value) {
+  A& a3 = llvm::cast_or_null<A>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant use of 'cast_or_null' [llvm-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:33: note: source expression 'value' has type 'A'
+  // CHECK-FIXES: A& a3 = value;
+  (void)a3;
+}
+
+void testCastIfPresent(A& value) {
+  A& a4 = llvm::cast_if_present<A>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant use of 'cast_if_present' [llvm-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:36: note: source expression 'value' has type 'A'
+  // CHECK-FIXES: A& a4 = value;
+  (void)a4;
+}
+
+void testDynCastOrNull(A& value) {
+  A& a5 = llvm::dyn_cast_or_null<A>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant use of 'dyn_cast_or_null' [llvm-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:37: note: source expression 'value' has type 'A'
+  // CHECK-FIXES: A& a5 = value;
+  (void)a5;
+}
+
+void testDynCastIfPresent(A& value) {
+  A& a6 = llvm::dyn_cast_if_present<A>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant use of 'dyn_cast_if_present' [llvm-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:40: note: source expression 'value' has type 'A'
+  // CHECK-FIXES: A& a6 = value;
+  (void)a6;
+}
+
+void testCastNonDeclRef() {
+  A& a7 = llvm::cast<A>((getA()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant use of 'cast' [llvm-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:25: note: source expression '(getA())' has type 'A'
+  // CHECK-FIXES: A& a7 = (getA());
+  (void)a7;
+}
+
+void testUpcast(B& value) {
+  A& a8 = llvm::cast<A>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant use of 'cast' [llvm-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:25: note: source expression 'value' has type 'B'
+  // CHECK-MESSAGES: :[[@LINE-3]]:25: note: 'B' is a subtype of 'A'
+  // CHECK-FIXES: A& a8 = value;
+  (void)a8;
+}
+
+void testDowncast(A& value) {
+  B& a9 = llvm::cast<B>(value);
+  // CHECK-MESSAGES-NOT: warning
+  // CHECK-FIXES-NOT: A& a9 = value;
+  (void)a9;
+}
+
+namespace llvm {
+void testCastInLLVM(A& value) {
+  A& a11 = cast<A>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant use of 'cast' [llvm-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:20: note: source expression 'value' has type 'A'
+  // CHECK-FIXES: A& a11 = value;
+  (void)a11;
+}
+} // namespace llvm
+
+void testCastPointer(A* value) {
+  A *a12 = llvm::cast<A>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant use of 'cast' [llvm-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:26: note: source expression 'value' has type 'A *'
+  // CHECK-FIXES: A *a12 = value;
+  (void)a12;
+}
+
+template <typename T>
+void testCastTemplateIgnore(T* value) {
+  A *a13 = llvm::cast<A>(value);
+  // CHECK-MESSAGES-NOT: warning
+  // CHECK-FIXES-NOT: A *a13 = value;
+  (void)a13;
+}
+template void testCastTemplateIgnore<A>(A *value);
+
+template <typename T>
+struct testCastTemplateIgnoreStruct {
+  void method(T* value) {
+    A *a14 = llvm::cast<A>(value);
+    // CHECK-MESSAGES-NOT: warning
+    // CHECK-FIXES-NOT: A *a14 = value;
+    (void)a14;
+  }
+};
+
+void call(testCastTemplateIgnoreStruct<A> s, A *a) {
+  s.method(a);
+}
+
+template <typename T>
+void testCastTemplateTrigger1(T* value) {
+  T *a15 = llvm::cast<T>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant use of 'cast' [llvm-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:26: note: source expression 'value' has type 'T *'
+  // CHECK-FIXES: T *a15 = value;
+  (void)a15;
+}
+
+template <typename T>
+void testCastTemplateTrigger2(A* value, T other) {
+  A *a16 = llvm::cast<A>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant use of 'cast' [llvm-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:26: note: source expression 'value' has type 'A *'
+  // CHECK-FIXES: A *a16 = value;
+  (void)a16; (void) other;
+}
+

>From 2f63c0e1dfd8a163858695c1f6cdec1002786a06 Mon Sep 17 00:00:00 2001
From: "Henrik G. Olsson" <h_olsson at apple.com>
Date: Sun, 29 Mar 2026 11:52:24 -0700
Subject: [PATCH 2/2] attempt to fix windows ci failure

---
 .../test/clang-tidy/checkers/llvm/redundant-casting.cpp         | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/redundant-casting.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/redundant-casting.cpp
index 4027933f95c4b..aad3d6a701fa4 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/llvm/redundant-casting.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/redundant-casting.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++17 %s llvm-redundant-casting %t
+// RUN: %check_clang_tidy -std=c++17 %s llvm-redundant-casting %t -- -- -fno-delayed-template-parsing
 
 namespace llvm {
 #define CAST_FUNCTION(name)                                          \



More information about the cfe-commits mailing list