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::TraverseTemplateArgumentLocsHelper( handles traversal of template args and qualifier. \ For explicit specializations ("template<> set {...};"), \ 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 +struct Tpl { + template + 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 +template +int Tpl::var; +// CHECK-NEXT: Tpl::var +// CHECK-NEXT: Tpl::(anonymous) +// CHECK-NEXT: Tpl::var +// CHECK-NEXT: T + +int i = Tpl::var; +// CHECK-NEXT: i +// CHECK-NEXT: Tpl::var diff --git a/clang/test/Analysis/pr169302.cpp b/clang/test/Analysis/pr169302.cpp new file mode 100644 index 0000000000000..9ff73bc8535e3 --- /dev/null +++ b/clang/test/Analysis/pr169302.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=core -verify %s + +// expected-no-diagnostics + +template struct S; + +class Sp { +public: + template void M() {} + template struct I { + static void IM(); + }; +}; + +template <> struct S { + using F = void (Sp::*)(); + template static constexpr F SpM = &Sp::template M

; +}; + +template constexpr S::F S::SpM; + +template void Sp::I::IM() { + using Spec = S; + typename Spec::F E = Spec::template SpM; +}