Skip to content

[Clang][RAV] Simplify TraverseTemplateArgumentLocsHelper#199131

Open
hvdijk wants to merge 2 commits into
llvm:mainfrom
hvdijk:rav-simplify-ttalh
Open

[Clang][RAV] Simplify TraverseTemplateArgumentLocsHelper#199131
hvdijk wants to merge 2 commits into
llvm:mainfrom
hvdijk:rav-simplify-ttalh

Conversation

@hvdijk
Copy link
Copy Markdown
Contributor

@hvdijk hvdijk commented May 21, 2026

We were checking the result of getTemplateArgsAsWritten() to skip over implicit instantiations, with an assert to ensure that it has the desired effect, before checking getTemplateSpecializationKind() == TSK_ExplicitSpecialization which would skip over implicit instantiations anyway. As the included tests show, the invariant that we were relying on did not hold, but we no longer have any need to rely on that, we can now just check the result of getTemplateSpecializationKind() directly.

Fixes: #198903
Fixes: #169302

We were checking the result of getTemplateArgsAsWritten() to skip over
implicit instantiations, with an assert to ensure that it has the
desired effect,  before checking getTemplateSpecializationKind() ==
TSK_ExplicitSpecialization which would skip over implicit instantiations
anyway. As the included tests show, the invariant that we were relying
on did not hold, but we no longer have any need to rely on that, we can
now just check the result of getTemplateSpecializationKind() directly.

Fixes: llvm#198903
Fixes: llvm#169302
@llvmorg-github-actions llvmorg-github-actions Bot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:static analyzer labels May 21, 2026
@llvmorg-github-actions
Copy link
Copy Markdown

llvmorg-github-actions Bot commented May 21, 2026

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Harald van Dijk (hvdijk)

Changes

We were checking the result of getTemplateArgsAsWritten() to skip over implicit instantiations, with an assert to ensure that it has the desired effect, before checking getTemplateSpecializationKind() == TSK_ExplicitSpecialization which would skip over implicit instantiations anyway. As the included tests show, the invariant that we were relying on did not hold, but we no longer have any need to rely on that, we can now just check the result of getTemplateSpecializationKind() directly.

Fixes: #198903
Fixes: #169302


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

3 Files Affected:

  • (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+8-13)
  • (added) clang/test/AST/pr198903.cpp (+25)
  • (added) clang/test/Analysis/pr169302.cpp (+25)
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index febdf715698d9..2efdde5450f3c 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2222,25 +2222,20 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
        handles traversal of template args and qualifier.                       \
        For explicit specializations ("template<> set<int> {...};"),            \
        we traverse template args here since there is no EID. */                \
-    if (const auto *ArgsWritten = D->getTemplateArgsAsWritten()) {             \
-      assert(D->getTemplateSpecializationKind() != TSK_ImplicitInstantiation); \
-      if (D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {  \
-        TRY_TO(TraverseTemplateArgumentLocsHelper(                             \
-            ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs));    \
-      }                                                                        \
-    }                                                                          \
-                                                                               \
-    if (getDerived().shouldVisitTemplateInstantiations() ||                    \
-        D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {    \
-      /* Traverse base definition for explicit specializations */              \
-      TRY_TO(Traverse##DECLKIND##Helper(D));                                   \
-    } else {                                                                   \
+    if (D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {    \
+      const auto *ArgsWritten = D->getTemplateArgsAsWritten();                 \
+      TRY_TO(TraverseTemplateArgumentLocsHelper(                               \
+          ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs));      \
+    } else if (!getDerived().shouldVisitTemplateInstantiations()) {            \
       /* Returning from here skips traversing the                              \
          declaration context of the *TemplateSpecializationDecl                \
          (embedded in the DEF_TRAVERSE_DECL() macro)                           \
          which contains the instantiated members of the template. */           \
       return true;                                                             \
     }                                                                          \
+                                                                               \
+    /* Traverse base definition for explicit specializations */                \
+    TRY_TO(Traverse##DECLKIND##Helper(D));                                     \
   })
 
 DEF_TRAVERSE_TMPL_SPEC_DECL(Class, CXXRecord)
diff --git a/clang/test/AST/pr198903.cpp b/clang/test/AST/pr198903.cpp
new file mode 100644
index 0000000000000..1f0f68f92b7e4
--- /dev/null
+++ b/clang/test/AST/pr198903.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -ast-list %s | FileCheck -strict-whitespace %s
+
+template <typename>
+struct Tpl {
+  template <typename>
+  static int var;
+};
+// CHECK: Tpl
+// CHECK-NEXT: Tpl::(anonymous)
+// CHECK-NEXT: Tpl
+// CHECK-NEXT: Tpl::var
+// CHECK-NEXT: Tpl::(anonymous)
+// CHECK-NEXT: Tpl::var
+
+template <typename T>
+template <typename>
+int Tpl<T>::var;
+// CHECK-NEXT: Tpl::var
+// CHECK-NEXT: Tpl::(anonymous)
+// CHECK-NEXT: Tpl::var
+// CHECK-NEXT: T
+
+int i = Tpl<int>::var<int>;
+// CHECK-NEXT: i
+// CHECK-NEXT: Tpl<int>::var
diff --git a/clang/test/Analysis/pr169302.cpp b/clang/test/Analysis/pr169302.cpp
new file mode 100644
index 0000000000000..9aa594627708a
--- /dev/null
+++ b/clang/test/Analysis/pr169302.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core -verify %s
+
+// expected-no-diagnostics
+
+template <typename> struct S;
+
+class Sp {
+public:
+  template <bool> void M() {}
+  template <unsigned> struct I {
+    static void IM();
+  };
+};
+
+template <> struct S<Sp> {
+  using F = void (Sp::*)();
+  template <bool P> static constexpr F SpM = &Sp::template M<P>;
+};
+
+template <bool> constexpr S<Sp>::F S<Sp>::SpM;
+
+template <unsigned X> void Sp::I<X>::IM() {
+  using Spec = S<Sp>;
+  typename Spec::F E = Spec::template SpM<true>;
+}

@hvdijk hvdijk requested review from erichkeane and sdkrystian May 21, 2026 22:52
@hvdijk
Copy link
Copy Markdown
Contributor Author

hvdijk commented May 21, 2026

cc @16bit-ykiko, I can't add you as a reviewer, but this is based on your PR #191658 and if you have comments on this, I would welcome them.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 21, 2026

🐧 Linux x64 Test Results

  • 118021 tests passed
  • 4763 tests skipped

✅ The build succeeded and all tests passed.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 21, 2026

🪟 Windows x64 Test Results

  • 55636 tests passed
  • 2597 tests skipped

✅ The build succeeded and all tests passed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:static analyzer clang Clang issues not falling into any other category

Projects

None yet

1 participant