Michael137 created this revision.
Michael137 added a reviewer: aprantl.
Herald added a project: All.
Michael137 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

A use-case has come up in DWARF CodeGen where we want to determine
whether a particular template argument matches the default template
parameter declaration.

Re-using this TypePrinter component there allows us to avoid duplicating
most of this code and immediately allows us to cover a wider range
of use-cases than the DWARF CodeGen does today.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D139985

Files:
  clang/include/clang/AST/TemplateUtils.h
  clang/lib/AST/CMakeLists.txt
  clang/lib/AST/TemplateUtils.cpp
  clang/lib/AST/TypePrinter.cpp

Index: clang/lib/AST/TypePrinter.cpp
===================================================================
--- clang/lib/AST/TypePrinter.cpp
+++ clang/lib/AST/TypePrinter.cpp
@@ -22,6 +22,7 @@
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/TemplateBase.h"
 #include "clang/AST/TemplateName.h"
+#include "clang/AST/TemplateUtils.h"
 #include "clang/AST/TextNodeDumper.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/AddressSpaces.h"
@@ -1936,140 +1937,6 @@
   return A.getArgument().print(PP, OS, IncludeType);
 }
 
-static bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg,
-                                          TemplateArgument Pattern,
-                                          ArrayRef<TemplateArgument> Args,
-                                          unsigned Depth);
-
-static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern,
-                              ArrayRef<TemplateArgument> Args, unsigned Depth) {
-  if (Ctx.hasSameType(T, Pattern))
-    return true;
-
-  // A type parameter matches its argument.
-  if (auto *TTPT = Pattern->getAs<TemplateTypeParmType>()) {
-    if (TTPT->getDepth() == Depth && TTPT->getIndex() < Args.size() &&
-        Args[TTPT->getIndex()].getKind() == TemplateArgument::Type) {
-      QualType SubstArg = Ctx.getQualifiedType(
-          Args[TTPT->getIndex()].getAsType(), Pattern.getQualifiers());
-      return Ctx.hasSameType(SubstArg, T);
-    }
-    return false;
-  }
-
-  // FIXME: Recurse into array types.
-
-  // All other cases will need the types to be identically qualified.
-  Qualifiers TQual, PatQual;
-  T = Ctx.getUnqualifiedArrayType(T, TQual);
-  Pattern = Ctx.getUnqualifiedArrayType(Pattern, PatQual);
-  if (TQual != PatQual)
-    return false;
-
-  // Recurse into pointer-like types.
-  {
-    QualType TPointee = T->getPointeeType();
-    QualType PPointee = Pattern->getPointeeType();
-    if (!TPointee.isNull() && !PPointee.isNull())
-      return T->getTypeClass() == Pattern->getTypeClass() &&
-             isSubstitutedType(Ctx, TPointee, PPointee, Args, Depth);
-  }
-
-  // Recurse into template specialization types.
-  if (auto *PTST =
-          Pattern.getCanonicalType()->getAs<TemplateSpecializationType>()) {
-    TemplateName Template;
-    ArrayRef<TemplateArgument> TemplateArgs;
-    if (auto *TTST = T->getAs<TemplateSpecializationType>()) {
-      Template = TTST->getTemplateName();
-      TemplateArgs = TTST->template_arguments();
-    } else if (auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
-                   T->getAsCXXRecordDecl())) {
-      Template = TemplateName(CTSD->getSpecializedTemplate());
-      TemplateArgs = CTSD->getTemplateArgs().asArray();
-    } else {
-      return false;
-    }
-
-    if (!isSubstitutedTemplateArgument(Ctx, Template, PTST->getTemplateName(),
-                                       Args, Depth))
-      return false;
-    if (TemplateArgs.size() != PTST->template_arguments().size())
-      return false;
-    for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
-      if (!isSubstitutedTemplateArgument(
-              Ctx, TemplateArgs[I], PTST->template_arguments()[I], Args, Depth))
-        return false;
-    return true;
-  }
-
-  // FIXME: Handle more cases.
-  return false;
-}
-
-static bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg,
-                                          TemplateArgument Pattern,
-                                          ArrayRef<TemplateArgument> Args,
-                                          unsigned Depth) {
-  Arg = Ctx.getCanonicalTemplateArgument(Arg);
-  Pattern = Ctx.getCanonicalTemplateArgument(Pattern);
-  if (Arg.structurallyEquals(Pattern))
-    return true;
-
-  if (Pattern.getKind() == TemplateArgument::Expression) {
-    if (auto *DRE =
-            dyn_cast<DeclRefExpr>(Pattern.getAsExpr()->IgnoreParenImpCasts())) {
-      if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl()))
-        return NTTP->getDepth() == Depth && Args.size() > NTTP->getIndex() &&
-               Args[NTTP->getIndex()].structurallyEquals(Arg);
-    }
-  }
-
-  if (Arg.getKind() != Pattern.getKind())
-    return false;
-
-  if (Arg.getKind() == TemplateArgument::Type)
-    return isSubstitutedType(Ctx, Arg.getAsType(), Pattern.getAsType(), Args,
-                             Depth);
-
-  if (Arg.getKind() == TemplateArgument::Template) {
-    TemplateDecl *PatTD = Pattern.getAsTemplate().getAsTemplateDecl();
-    if (auto *TTPD = dyn_cast_or_null<TemplateTemplateParmDecl>(PatTD))
-      return TTPD->getDepth() == Depth && Args.size() > TTPD->getIndex() &&
-             Ctx.getCanonicalTemplateArgument(Args[TTPD->getIndex()])
-                 .structurallyEquals(Arg);
-  }
-
-  // FIXME: Handle more cases.
-  return false;
-}
-
-/// Make a best-effort determination of whether the type T can be produced by
-/// substituting Args into the default argument of Param.
-static bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
-                                         const NamedDecl *Param,
-                                         ArrayRef<TemplateArgument> Args,
-                                         unsigned Depth) {
-  // An empty pack is equivalent to not providing a pack argument.
-  if (Arg.getKind() == TemplateArgument::Pack && Arg.pack_size() == 0)
-    return true;
-
-  if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Param)) {
-    return TTPD->hasDefaultArgument() &&
-           isSubstitutedTemplateArgument(Ctx, Arg, TTPD->getDefaultArgument(),
-                                         Args, Depth);
-  } else if (auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
-    return TTPD->hasDefaultArgument() &&
-           isSubstitutedTemplateArgument(
-               Ctx, Arg, TTPD->getDefaultArgument().getArgument(), Args, Depth);
-  } else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
-    return NTTPD->hasDefaultArgument() &&
-           isSubstitutedTemplateArgument(Ctx, Arg, NTTPD->getDefaultArgument(),
-                                         Args, Depth);
-  }
-  return false;
-}
-
 template <typename TA>
 static void
 printTo(raw_ostream &OS, ArrayRef<TA> Args, const PrintingPolicy &Policy,
@@ -2083,9 +1950,9 @@
     for (const TA &A : Args)
       OrigArgs.push_back(getArgument(A));
     while (!Args.empty() &&
-           isSubstitutedDefaultArgument(Ctx, getArgument(Args.back()),
-                                        TPL->getParam(Args.size() - 1),
-                                        OrigArgs, TPL->getDepth()))
+           TemplateUtils::isSubstitutedDefaultArgument(
+               Ctx, getArgument(Args.back()), TPL->getParam(Args.size() - 1),
+               OrigArgs, TPL->getDepth()))
       Args = Args.drop_back();
   }
 
Index: clang/lib/AST/TemplateUtils.cpp
===================================================================
--- /dev/null
+++ clang/lib/AST/TemplateUtils.cpp
@@ -0,0 +1,155 @@
+//===- TemplateUtils.cpp---------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//  This defines helpers for operating on template parameters in Clang's AST.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/TemplateUtils.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/TemplateBase.h"
+
+using namespace clang;
+
+namespace {
+bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg,
+                                   TemplateArgument Pattern,
+                                   ArrayRef<TemplateArgument> Args,
+                                   unsigned Depth);
+
+bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern,
+                       ArrayRef<TemplateArgument> Args, unsigned Depth) {
+  if (Ctx.hasSameType(T, Pattern))
+    return true;
+
+  // A type parameter matches its argument.
+  if (auto *TTPT = Pattern->getAs<TemplateTypeParmType>()) {
+    if (TTPT->getDepth() == Depth && TTPT->getIndex() < Args.size() &&
+        Args[TTPT->getIndex()].getKind() == TemplateArgument::Type) {
+      QualType SubstArg = Ctx.getQualifiedType(
+          Args[TTPT->getIndex()].getAsType(), Pattern.getQualifiers());
+      return Ctx.hasSameType(SubstArg, T);
+    }
+    return false;
+  }
+
+  // FIXME: Recurse into array types.
+
+  // All other cases will need the types to be identically qualified.
+  Qualifiers TQual, PatQual;
+  T = Ctx.getUnqualifiedArrayType(T, TQual);
+  Pattern = Ctx.getUnqualifiedArrayType(Pattern, PatQual);
+  if (TQual != PatQual)
+    return false;
+
+  // Recurse into pointer-like types.
+  {
+    QualType TPointee = T->getPointeeType();
+    QualType PPointee = Pattern->getPointeeType();
+    if (!TPointee.isNull() && !PPointee.isNull())
+      return T->getTypeClass() == Pattern->getTypeClass() &&
+             isSubstitutedType(Ctx, TPointee, PPointee, Args, Depth);
+  }
+
+  // Recurse into template specialization types.
+  if (auto *PTST =
+          Pattern.getCanonicalType()->getAs<TemplateSpecializationType>()) {
+    TemplateName Template;
+    ArrayRef<TemplateArgument> TemplateArgs;
+    if (auto *TTST = T->getAs<TemplateSpecializationType>()) {
+      Template = TTST->getTemplateName();
+      TemplateArgs = TTST->template_arguments();
+    } else if (auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
+                   T->getAsCXXRecordDecl())) {
+      Template = TemplateName(CTSD->getSpecializedTemplate());
+      TemplateArgs = CTSD->getTemplateArgs().asArray();
+    } else {
+      return false;
+    }
+
+    if (!isSubstitutedTemplateArgument(Ctx, Template, PTST->getTemplateName(),
+                                       Args, Depth))
+      return false;
+    if (TemplateArgs.size() != PTST->template_arguments().size())
+      return false;
+    for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+      if (!isSubstitutedTemplateArgument(
+              Ctx, TemplateArgs[I], PTST->template_arguments()[I], Args, Depth))
+        return false;
+    return true;
+  }
+
+  // FIXME: Handle more cases.
+  return false;
+}
+
+bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg,
+                                   TemplateArgument Pattern,
+                                   ArrayRef<TemplateArgument> Args,
+                                   unsigned Depth) {
+  Arg = Ctx.getCanonicalTemplateArgument(Arg);
+  Pattern = Ctx.getCanonicalTemplateArgument(Pattern);
+  if (Arg.structurallyEquals(Pattern))
+    return true;
+
+  if (Pattern.getKind() == TemplateArgument::Expression) {
+    if (auto *DRE =
+            dyn_cast<DeclRefExpr>(Pattern.getAsExpr()->IgnoreParenImpCasts())) {
+      if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl()))
+        return NTTP->getDepth() == Depth && Args.size() > NTTP->getIndex() &&
+               Args[NTTP->getIndex()].structurallyEquals(Arg);
+    }
+  }
+
+  if (Arg.getKind() != Pattern.getKind())
+    return false;
+
+  if (Arg.getKind() == TemplateArgument::Type)
+    return isSubstitutedType(Ctx, Arg.getAsType(), Pattern.getAsType(), Args,
+                             Depth);
+
+  if (Arg.getKind() == TemplateArgument::Template) {
+    TemplateDecl *PatTD = Pattern.getAsTemplate().getAsTemplateDecl();
+    if (auto *TTPD = dyn_cast_or_null<TemplateTemplateParmDecl>(PatTD))
+      return TTPD->getDepth() == Depth && Args.size() > TTPD->getIndex() &&
+             Ctx.getCanonicalTemplateArgument(Args[TTPD->getIndex()])
+                 .structurallyEquals(Arg);
+  }
+
+  // FIXME: Handle more cases.
+  return false;
+}
+} // namespace
+
+namespace clang::TemplateUtils {
+/// Make a best-effort determination of whether the type T can be produced by
+/// substituting Args into the default argument of Param.
+bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
+                                  const NamedDecl *Param,
+                                  ArrayRef<TemplateArgument> Args,
+                                  unsigned Depth) {
+  // An empty pack is equivalent to not providing a pack argument.
+  if (Arg.getKind() == TemplateArgument::Pack && Arg.pack_size() == 0)
+    return true;
+
+  if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Param)) {
+    return TTPD->hasDefaultArgument() &&
+           isSubstitutedTemplateArgument(Ctx, Arg, TTPD->getDefaultArgument(),
+                                         Args, Depth);
+  } else if (auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
+    return TTPD->hasDefaultArgument() &&
+           isSubstitutedTemplateArgument(
+               Ctx, Arg, TTPD->getDefaultArgument().getArgument(), Args, Depth);
+  } else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+    return NTTPD->hasDefaultArgument() &&
+           isSubstitutedTemplateArgument(Ctx, Arg, NTTPD->getDefaultArgument(),
+                                         Args, Depth);
+  }
+  return false;
+}
+} // namespace clang::TemplateUtils
Index: clang/lib/AST/CMakeLists.txt
===================================================================
--- clang/lib/AST/CMakeLists.txt
+++ clang/lib/AST/CMakeLists.txt
@@ -114,6 +114,7 @@
   StmtViz.cpp
   TemplateBase.cpp
   TemplateName.cpp
+  TemplateUtils.cpp
   TextNodeDumper.cpp
   Type.cpp
   TypeLoc.cpp
Index: clang/include/clang/AST/TemplateUtils.h
===================================================================
--- /dev/null
+++ clang/include/clang/AST/TemplateUtils.h
@@ -0,0 +1,28 @@
+//===--- TemplateUtils.h - Classes for operating on Templates ---*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//  This defines helpers for operating on template parameters in Clang's AST.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_TEMPLATEUTILS_H
+#define LLVM_CLANG_AST_TEMPLATEUTILS_H
+
+#include "clang/AST/ASTContext.h"
+
+namespace clang {
+namespace TemplateUtils {
+/// Make a best-effort determination of whether the type T can be produced by
+/// substituting Args into the default argument of Param.
+bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
+                                  const NamedDecl *Param,
+                                  ArrayRef<TemplateArgument> Args,
+                                  unsigned Depth);
+} // namespace TemplateUtils
+} // namespace clang
+#endif
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to