diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 9d141997d026f6..066dd1b38c064d 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3881,6 +3881,13 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) { ToVar->setPreviousDecl(Recent); } + // Import the described template, if any. + if (D->getDescribedVarTemplate()) { + auto ToVTOrErr = import(D->getDescribedVarTemplate()); + if (!ToVTOrErr) + return ToVTOrErr.takeError(); + } + if (Error Err = ImportInitializer(D, ToVar)) return std::move(Err); @@ -5460,20 +5467,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( } ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { - // If this variable has a definition in the translation unit we're coming - // from, - // but this particular declaration is not that definition, import the - // definition and map to that. - auto *Definition = - cast_or_null(D->getTemplatedDecl()->getDefinition()); - if (Definition && Definition != D->getTemplatedDecl()) { - if (ExpectedDecl ImportedDefOrErr = import( - Definition->getDescribedVarTemplate())) - return Importer.MapImported(D, *ImportedDefOrErr); - else - return ImportedDefOrErr.takeError(); - } - // Import the major distinguishing characteristics of this variable template. DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -5487,19 +5480,26 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { // We may already have a template of the same name; try to find and match it. assert(!DC->isFunctionOrMethod() && "Variable templates cannot be declared at function scope"); + SmallVector ConflictingDecls; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); + VarTemplateDecl *FoundByLookup = nullptr; for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; - Decl *Found = FoundDecl; - if (VarTemplateDecl *FoundTemplate = dyn_cast(Found)) { + if (VarTemplateDecl *FoundTemplate = dyn_cast(FoundDecl)) { if (IsStructuralMatch(D, FoundTemplate)) { - // The variable templates structurally match; call it the same template. - Importer.MapImported(D->getTemplatedDecl(), - FoundTemplate->getTemplatedDecl()); - return Importer.MapImported(D, FoundTemplate); + // The Decl in the "From" context has a definition, but in the + // "To" context we already have a definition. + VarTemplateDecl *FoundDef = getTemplateDefinition(FoundTemplate); + if (D->isThisDeclarationADefinition() && FoundDef) + // FIXME Check for ODR error if the two definitions have + // different initializers? + return Importer.MapImported(D, FoundDef); + + FoundByLookup = FoundTemplate; + break; } ConflictingDecls.push_back(FoundDecl); } @@ -5544,6 +5544,18 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { ToVarTD->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToVarTD); + if (FoundByLookup) { + auto *Recent = + const_cast(FoundByLookup->getMostRecentDecl()); + if (!ToTemplated->getPreviousDecl()) { + auto *PrevTemplated = + FoundByLookup->getTemplatedDecl()->getMostRecentDecl(); + if (ToTemplated != PrevTemplated) + ToTemplated->setPreviousDecl(PrevTemplated); + } + ToVarTD->setPreviousDecl(Recent); + } + if (DTemplated->isThisDeclarationADefinition() && !ToTemplated->isThisDeclarationADefinition()) { // FIXME: Import definition! diff --git a/clang/unittests/AST/ASTImporterGenericRedeclTest.cpp b/clang/unittests/AST/ASTImporterGenericRedeclTest.cpp index e0c5e9407788ad..944256e857c7ac 100644 --- a/clang/unittests/AST/ASTImporterGenericRedeclTest.cpp +++ b/clang/unittests/AST/ASTImporterGenericRedeclTest.cpp @@ -74,6 +74,21 @@ struct ClassTemplate { } }; +struct VariableTemplate { + using DeclTy = VarTemplateDecl; + static constexpr auto *Prototype = "template extern T X;"; + static constexpr auto *Definition = + R"( + template T X; + template <> int X; + )"; + // There is no matcher for varTemplateDecl so use a work-around. + BindableMatcher getPattern() { + return namedDecl(hasName("X"), unless(isImplicit()), + has(templateTypeParmDecl())); + } +}; + struct FunctionTemplateSpec { using DeclTy = FunctionDecl; static constexpr auto *Prototype = @@ -427,6 +442,9 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE( ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE( RedeclChain, ClassTemplate, , PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition) +ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE( + RedeclChain, VariableTemplate, , + PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE( RedeclChain, FunctionTemplateSpec, , PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition) @@ -446,6 +464,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, , DefinitionShouldBeImportedAsADefinition) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, , DefinitionShouldBeImportedAsADefinition) +ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, , + DefinitionShouldBeImportedAsADefinition) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, , DefinitionShouldBeImportedAsADefinition) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, , @@ -463,6 +483,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, , ImportPrototypeAfterImportedPrototype) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, , ImportPrototypeAfterImportedPrototype) +ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, , + ImportPrototypeAfterImportedPrototype) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, , ImportPrototypeAfterImportedPrototype) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, , @@ -480,6 +502,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, , ImportDefinitionAfterImportedPrototype) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, , ImportDefinitionAfterImportedPrototype) +ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, , + ImportDefinitionAfterImportedPrototype) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, , ImportDefinitionAfterImportedPrototype) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, , @@ -497,6 +521,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, , ImportPrototypeAfterImportedDefinition) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, , ImportPrototypeAfterImportedDefinition) +ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, , + ImportPrototypeAfterImportedDefinition) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, , ImportPrototypeAfterImportedDefinition) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, , @@ -513,6 +539,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, , ImportPrototypes) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, , ImportPrototypes) +ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, , + ImportPrototypes) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, , ImportPrototypes) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, , @@ -529,6 +557,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, , ImportDefinitions) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, , ImportDefinitions) +ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, , + ImportDefinitions) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, , ImportDefinitions) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, , @@ -546,6 +576,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, , ImportDefinitionThenPrototype) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, , ImportDefinitionThenPrototype) +ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, , + ImportDefinitionThenPrototype) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, , ImportDefinitionThenPrototype) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, , @@ -563,6 +595,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, , ImportPrototypeThenDefinition) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, , ImportPrototypeThenDefinition) +ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, , + ImportPrototypeThenDefinition) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, , ImportPrototypeThenDefinition) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, , @@ -574,6 +608,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, , WholeRedeclChainIsImportedAtOnce) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, , WholeRedeclChainIsImportedAtOnce) +ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, , + WholeRedeclChainIsImportedAtOnce) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, , WholeRedeclChainIsImportedAtOnce) @@ -583,6 +619,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, , ImportPrototypeThenProtoAndDefinition) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, , ImportPrototypeThenProtoAndDefinition) +ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, , + ImportPrototypeThenProtoAndDefinition) ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, , ImportPrototypeThenProtoAndDefinition) @@ -598,6 +636,8 @@ INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunctionTemplate, DefaultTestValuesForRunOptions, ); INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClassTemplate, DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainVariableTemplate, + DefaultTestValuesForRunOptions, ); INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunctionTemplateSpec, DefaultTestValuesForRunOptions, ); INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClassTemplateSpec,