diff options
author | Gabor Marton <martongabesz@gmail.com> | 2018-05-23 13:53:36 +0000 |
---|---|---|
committer | Gabor Marton <martongabesz@gmail.com> | 2018-05-23 13:53:36 +0000 |
commit | 9581c331d29ed51015f8faa8167a39fda43d4e75 (patch) | |
tree | 4ed106430c472844682bb235ebc074b55adc31f4 /clang/lib | |
parent | d173caf3bf2e3d20b033e21426af1111b68dbee1 (diff) | |
download | bcm5719-llvm-9581c331d29ed51015f8faa8167a39fda43d4e75.tar.gz bcm5719-llvm-9581c331d29ed51015f8faa8167a39fda43d4e75.zip |
Fix duplicate class template definitions problem
Summary:
We fail to import a `ClassTemplateDecl` if the "To" context already
contains a definition and then a forward decl. This is because
`localUncachedLookup` does not find the definition. This is not a
lookup error, the parser behaves differently than assumed in the
importer code. A `DeclContext` contains one DenseMap (`LookupPtr`)
which maps names to lists. The list is a special list `StoredDeclsList`
which is optimized to have one element. During building the initial
AST, the parser first adds the definition to the `DeclContext`. Then
during parsing the second declaration (the forward decl) the parser
again calls `DeclContext::addDecl` but that will not add a new element
to the `StoredDeclsList` rarther it simply overwrites the old element
with the most recent one. This patch fixes the error by finding the
definition in the redecl chain. Added tests for the same issue with
`CXXRecordDecl` and with `ClassTemplateSpecializationDecl`. These tests
pass and they pass because in `VisitRecordDecl` and in
`VisitClassTemplateSpecializationDecl` we already use
`D->getDefinition()` after the lookup.
Reviewers: a.sidorin, xazax.hun, szepet
Subscribers: rnkovacs, dkrupp, cfe-commits
Differential Revision: https://reviews.llvm.org/D46950
llvm-svn: 333082
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 46 |
1 files changed, 31 insertions, 15 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 6fa4617cf06..3c698974364 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -4070,6 +4070,17 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { TemplateParams); } +// Returns the definition for a (forward) declaration of a ClassTemplateDecl, if +// it has any definition in the redecl chain. +static ClassTemplateDecl *getDefinition(ClassTemplateDecl *D) { + CXXRecordDecl *ToTemplatedDef = D->getTemplatedDecl()->getDefinition(); + if (!ToTemplatedDef) + return nullptr; + ClassTemplateDecl *TemplateWithDef = + ToTemplatedDef->getDescribedClassTemplate(); + return TemplateWithDef; +} + Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { // If this record has a definition in the translation unit we're coming from, // but this particular declaration is not that definition, import the @@ -4084,7 +4095,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { return Importer.Imported(D, ImportedDef); } - + // Import the major distinguishing characteristics of this class template. DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -4103,34 +4114,39 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; - + Decl *Found = FoundDecl; if (auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found)) { - if (IsStructuralMatch(D, FoundTemplate)) { - // The class templates structurally match; call it the same template. - // We found a forward declaration but the class to be imported has a - // definition. - // FIXME Add this forward declaration to the redeclaration chain. - if (D->isThisDeclarationADefinition() && - !FoundTemplate->isThisDeclarationADefinition()) + // The class to be imported is a definition. + if (D->isThisDeclarationADefinition()) { + // Lookup will find the fwd decl only if that is more recent than the + // definition. So, try to get the definition if that is available in + // the redecl chain. + ClassTemplateDecl *TemplateWithDef = getDefinition(FoundTemplate); + if (!TemplateWithDef) continue; + FoundTemplate = TemplateWithDef; // Continue with the definition. + } + + if (IsStructuralMatch(D, FoundTemplate)) { + // The class templates structurally match; call it the same template. - Importer.Imported(D->getTemplatedDecl(), + Importer.Imported(D->getTemplatedDecl(), FoundTemplate->getTemplatedDecl()); return Importer.Imported(D, FoundTemplate); - } + } } - + ConflictingDecls.push_back(FoundDecl); } - + if (!ConflictingDecls.empty()) { Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary, - ConflictingDecls.data(), + ConflictingDecls.data(), ConflictingDecls.size()); } - + if (!Name) return nullptr; } |