[Clang][RAV] Simplify TraverseTemplateArgumentLocsHelper#199131
Conversation
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
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-static-analyzer-1 Author: Harald van Dijk (hvdijk) ChangesWe 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 Full diff: https://github.com/llvm/llvm-project/pull/199131.diff 3 Files Affected:
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>;
+}
|
|
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. |
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
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