From: Richard Smith Date: Tue, 18 Mar 2014 02:07:28 +0000 (+0000) Subject: AST dumper: if we have multiple implicit instantiations of the same class X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=01400f94f57efa3597ae63d8366f827aa4f7625f;p=clang AST dumper: if we have multiple implicit instantiations of the same class template specialization (from different modules), dump them all, so that every declaration is dumped somewhere. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@204100 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 8134257335..b4cdcea832 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -254,6 +254,11 @@ namespace { void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D); void VisitCXXRecordDecl(const CXXRecordDecl *D); void VisitStaticAssertDecl(const StaticAssertDecl *D); + template + void VisitTemplateDeclSpecialization(ChildDumper &Children, + const SpecializationDecl *D, + bool DumpExplicitInst, + bool DumpRefOnly); template void VisitTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst); void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D); @@ -1075,6 +1080,46 @@ void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) { dumpStmt(D->getMessage()); } +template +void ASTDumper::VisitTemplateDeclSpecialization(ChildDumper &Children, + const SpecializationDecl *D, + bool DumpExplicitInst, + bool DumpRefOnly) { + bool DumpedAny = false; + for (auto *RedeclWithBadType : D->redecls()) { + // FIXME: The redecls() range sometimes has elements of a less-specific + // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives + // us TagDecls, and should give CXXRecordDecls). + auto *Redecl = dyn_cast(RedeclWithBadType); + if (!Redecl) { + // Found the injected-class-name for a class template. This will be dumped + // as part of its surrounding class so we don't need to dump it here. + assert(isa(RedeclWithBadType) && + "expected an injected-class-name"); + continue; + } + + switch (Redecl->getTemplateSpecializationKind()) { + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + if (!DumpExplicitInst) + break; + // Fall through. + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + Children.dump(Redecl, DumpRefOnly); + DumpedAny = true; + break; + case TSK_ExplicitSpecialization: + break; + } + } + + // Ensure we dump at least one decl for each specialization. + if (!DumpedAny) + Children.dumpRef(D); +} + template void ASTDumper::VisitTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) { @@ -1084,22 +1129,9 @@ void ASTDumper::VisitTemplateDecl(const TemplateDecl *D, ChildDumper Children(*this); Children.dump(D->getTemplatedDecl()); - for (auto *Child : D->specializations()) { - switch (Child->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ImplicitInstantiation: - Children.dump(Child, /*Ref*/D != D->getCanonicalDecl()); - break; - case TSK_ExplicitInstantiationDeclaration: - case TSK_ExplicitInstantiationDefinition: - Children.dump(Child, /*Ref*/D != D->getCanonicalDecl() || - !DumpExplicitInst); - break; - case TSK_ExplicitSpecialization: - Children.dumpRef(Child); - break; - } - } + for (auto *Child : D->specializations()) + VisitTemplateDeclSpecialization(Children, Child, DumpExplicitInst, + !D->isCanonicalDecl()); } void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp index 65f41f677b..dbd7d9b21b 100644 --- a/test/Modules/cxx-templates.cpp +++ b/test/Modules/cxx-templates.cpp @@ -1,6 +1,7 @@ // RUN: rm -rf %t // RUN: not %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-lookups | FileCheck %s --check-prefix=CHECK-GLOBAL // RUN: not %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-lookups -ast-dump-filter N | FileCheck %s --check-prefix=CHECK-NAMESPACE-N +// RUN: not %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump | FileCheck %s --check-prefix=CHECK-DUMP // RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 @import cxx_templates_a; @@ -123,3 +124,13 @@ void testImplicitSpecialMembers(SomeTemplate &a, // CHECK-NAMESPACE-N: DeclarationName 'f' // CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f' // CHECK-NAMESPACE-N-NEXT: `-FunctionTemplate {{.*}} 'f' + +// CHECK-DUMP: ClassTemplateDecl {{.*}} <{{.*}}/cxx-templates-common.h:1:1, {{.*}}> in cxx_templates_common SomeTemplate +// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev [[CHAR2:[^ ]*]] {{.*}} SomeTemplate +// CHECK-DUMP-NEXT: TemplateArgument type 'char [2]' +// CHECK-DUMP: ClassTemplateSpecializationDecl [[CHAR2]] {{.*}} SomeTemplate definition +// CHECK-DUMP-NEXT: TemplateArgument type 'char [2]' +// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev [[CHAR1:[^ ]*]] {{.*}} SomeTemplate +// CHECK-DUMP-NEXT: TemplateArgument type 'char [1]' +// CHECK-DUMP: ClassTemplateSpecializationDecl [[CHAR1]] {{.*}} SomeTemplate definition +// CHECK-DUMP-NEXT: TemplateArgument type 'char [1]'