Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -23,7 +23,6 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/MemoryBuffer.h" -#include namespace clang { class ASTNodeImporter : public TypeVisitor, @@ -1335,6 +1334,21 @@ return false; } +template <> +bool ASTNodeImporter::ImportTemplateArgumentListInfo( + const TemplateArgumentListInfo &From, TemplateArgumentListInfo &Result) { + return ImportTemplateArgumentListInfo( + From.getLAngleLoc(), From.getRAngleLoc(), From.arguments(), Result); +} + +template <> +bool ASTNodeImporter::ImportTemplateArgumentListInfo< + ASTTemplateArgumentListInfo>(const ASTTemplateArgumentListInfo &From, + TemplateArgumentListInfo &Result) { + return ImportTemplateArgumentListInfo(From.LAngleLoc, From.RAngleLoc, + From.arguments(), Result); +} + bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain) { // Eliminate a potential failure point where we attempt to re-import @@ -1655,10 +1669,8 @@ SourceLocation StartL = Importer.Import(D->getLocStart()); TypedefNameDecl *ToTypedef; if (IsAlias) - ToTypedef = TypeAliasDecl::Create(Importer.getToContext(), DC, - StartL, Loc, - Name.getAsIdentifierInfo(), - TInfo); + ToTypedef = TypeAliasDecl::Create(Importer.getToContext(), DC, StartL, Loc, + Name.getAsIdentifierInfo(), TInfo); else ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC, StartL, Loc, @@ -1668,7 +1680,11 @@ ToTypedef->setAccess(D->getAccess()); ToTypedef->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToTypedef); - LexicalDC->addDeclInternal(ToTypedef); + + // Templated declarations should not appear in DeclContext. + TypeAliasDecl *FromAlias = IsAlias ? cast(D) : nullptr; + if (!FromAlias || !FromAlias->getDescribedAliasTemplate()) + LexicalDC->addDeclInternal(ToTypedef); return ToTypedef; } @@ -1686,11 +1702,11 @@ DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - NamedDecl *ToD; - if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + NamedDecl *FoundD; + if (ImportDeclParts(D, DC, LexicalDC, Name, FoundD, Loc)) return nullptr; - if (ToD) - return ToD; + if (FoundD) + return FoundD; // If this typedef is not in block scope, determine whether we've // seen a typedef with the same name (that we can merge with) or any @@ -1723,7 +1739,7 @@ if (!Params) return nullptr; - NamedDecl *TemplDecl = cast_or_null( + auto *TemplDecl = cast_or_null( Importer.Import(D->getTemplatedDecl())); if (!TemplDecl) return nullptr; @@ -1731,11 +1747,13 @@ TypeAliasTemplateDecl *ToAlias = TypeAliasTemplateDecl::Create( Importer.getToContext(), DC, Loc, Name, Params, TemplDecl); + TemplDecl->setDescribedAliasTemplate(ToAlias); + ToAlias->setAccess(D->getAccess()); ToAlias->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToAlias); LexicalDC->addDeclInternal(ToAlias); - return ToD; + return ToAlias; } Decl *ASTNodeImporter::VisitLabelDecl(LabelDecl *D) { @@ -2155,12 +2173,9 @@ TemplateArgumentListInfo ToTAInfo; const auto *FromTAArgsAsWritten = FTSInfo->TemplateArgumentsAsWritten; - if (FromTAArgsAsWritten) { - if (ImportTemplateArgumentListInfo( - FromTAArgsAsWritten->LAngleLoc, FromTAArgsAsWritten->RAngleLoc, - FromTAArgsAsWritten->arguments(), ToTAInfo)) + if (FromTAArgsAsWritten) + if (ImportTemplateArgumentListInfo(*FromTAArgsAsWritten, ToTAInfo)) return true; - } SourceLocation POI = Importer.Import(FTSInfo->getPointOfInstantiation()); @@ -2839,7 +2854,10 @@ ToVar->setAccess(D->getAccess()); ToVar->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToVar); - LexicalDC->addDeclInternal(ToVar); + + // Templated declarations should never appear in the enclosing DeclContext. + if (!D->getDescribedVarTemplate()) + LexicalDC->addDeclInternal(ToVar); if (!D->isFileVarDecl() && D->isUsed()) @@ -4142,8 +4160,8 @@ // Import TemplateArgumentListInfo TemplateArgumentListInfo ToTAInfo; - auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten(); - if (ImportTemplateArgumentListInfo(ASTTemplateArgs.arguments(), ToTAInfo)) + const auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten(); + if (ImportTemplateArgumentListInfo(ASTTemplateArgs, ToTAInfo)) return nullptr; QualType CanonInjType = Importer.Import( @@ -4275,21 +4293,8 @@ return nullptr; // Create the declaration that is being templated. - SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart()); - SourceLocation IdLoc = Importer.Import(DTemplated->getLocation()); - TypeSourceInfo *TInfo = Importer.Import(DTemplated->getTypeSourceInfo()); - VarDecl *D2Templated = VarDecl::Create(Importer.getToContext(), DC, StartLoc, - IdLoc, Name.getAsIdentifierInfo(), T, - TInfo, DTemplated->getStorageClass()); - D2Templated->setAccess(DTemplated->getAccess()); - D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc())); - D2Templated->setLexicalDeclContext(LexicalDC); - - // Importer.Imported(DTemplated, D2Templated); - // LexicalDC->addDeclInternal(D2Templated); - - // Merge the initializer. - if (ImportDefinition(DTemplated, D2Templated)) + VarDecl *ToTemplated = dyn_cast_or_null(Importer.Import(DTemplated)); + if (!ToTemplated) return nullptr; // Create the variable template declaration itself. @@ -4298,24 +4303,24 @@ if (!TemplateParams) return nullptr; - VarTemplateDecl *D2 = VarTemplateDecl::Create( - Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated); - D2Templated->setDescribedVarTemplate(D2); + VarTemplateDecl *ToVarTD = VarTemplateDecl::Create( + Importer.getToContext(), DC, Loc, Name, TemplateParams, ToTemplated); + ToTemplated->setDescribedVarTemplate(ToVarTD); - D2->setAccess(D->getAccess()); - D2->setLexicalDeclContext(LexicalDC); - LexicalDC->addDeclInternal(D2); + ToVarTD->setAccess(D->getAccess()); + ToVarTD->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(ToVarTD); // Note the relationship between the variable templates. - Importer.Imported(D, D2); - Importer.Imported(DTemplated, D2Templated); + Importer.Imported(D, ToVarTD); + Importer.Imported(DTemplated, ToTemplated); if (DTemplated->isThisDeclarationADefinition() && - !D2Templated->isThisDeclarationADefinition()) { + !ToTemplated->isThisDeclarationADefinition()) { // FIXME: Import definition! } - return D2; + return ToVarTD; } Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl( @@ -4384,14 +4389,58 @@ QualType T = Importer.Import(D->getType()); if (T.isNull()) return nullptr; + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + if (D->getTypeSourceInfo() && !TInfo) + return nullptr; + + TemplateArgumentListInfo ToTAInfo; + if (ImportTemplateArgumentListInfo(D->getTemplateArgsInfo(), + ToTAInfo)) + return nullptr; + using PartVarSpecDecl = VarTemplatePartialSpecializationDecl; // Create a new specialization. - D2 = VarTemplateSpecializationDecl::Create( - Importer.getToContext(), DC, StartLoc, IdLoc, VarTemplate, T, TInfo, - D->getStorageClass(), TemplateArgs); + if (auto *FromPartial = dyn_cast(D)) { + // Import TemplateArgumentListInfo + TemplateArgumentListInfo ArgInfos; + const auto *FromTAArgsAsWritten = FromPartial->getTemplateArgsAsWritten(); + // NOTE: FromTAArgsAsWritten and template parameter list are non-null. + if (ImportTemplateArgumentListInfo(*FromTAArgsAsWritten, ArgInfos)) + return nullptr; + + TemplateParameterList *ToTPList = ImportTemplateParameterList( + FromPartial->getTemplateParameters()); + if (!ToTPList) + return nullptr; + + auto *ToPartial = PartVarSpecDecl::Create( + Importer.getToContext(), DC, StartLoc, IdLoc, ToTPList, VarTemplate, + T, TInfo, D->getStorageClass(), TemplateArgs, ArgInfos); + + auto *FromInst = FromPartial->getInstantiatedFromMember(); + auto *ToInst = cast_or_null(Importer.Import(FromInst)); + if (FromInst && !ToInst) + return nullptr; + + ToPartial->setInstantiatedFromMember(ToInst); + if (FromPartial->isMemberSpecialization()) + ToPartial->setMemberSpecialization(); + + D2 = ToPartial; + + } else { // Full specialization + D2 = VarTemplateSpecializationDecl::Create( + Importer.getToContext(), DC, StartLoc, IdLoc, VarTemplate, T, TInfo, + D->getStorageClass(), TemplateArgs); + } + + SourceLocation POI = D->getPointOfInstantiation(); + if (POI.isValid()) + D2->setPointOfInstantiation(Importer.Import(POI)); + D2->setSpecializationKind(D->getSpecializationKind()); - D2->setTemplateArgsInfo(D->getTemplateArgsInfo()); + D2->setTemplateArgsInfo(ToTAInfo); // Add this specialization to the class template. VarTemplate->AddSpecialization(D2, InsertPos); @@ -4399,13 +4448,24 @@ // Import the qualifier, if any. D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); + if (D->isConstexpr()) + D2->setConstexpr(true); + // Add the specialization to this context. D2->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(D2); + + D2->setAccess(D->getAccess()); } + Importer.Imported(D, D2); - if (D->isThisDeclarationADefinition() && ImportDefinition(D, D2)) + // NOTE: isThisDeclarationADefinition() can return DeclarationOnly even if + // declaration has initializer. Should this be fixed in the AST?.. Anyway, + // we have to check the declaration for initializer - otherwise, it won't be + // imported. + if ((D->isThisDeclarationADefinition() || D->hasInit()) && + ImportDefinition(D, D2)) return nullptr; return D2; Index: test/ASTMerge/var-cpp/Inputs/var1.cpp =================================================================== --- /dev/null +++ test/ASTMerge/var-cpp/Inputs/var1.cpp @@ -0,0 +1,17 @@ + +template +constexpr T my_pi = T(3.1415926535897932385L); // variable template + +template <> constexpr char my_pi = '3'; // variable template specialization + +template +struct Wrapper { + template static constexpr U my_const = U(1); + // Variable template partial specialization with member variable. + template static constexpr U *my_const = (U *)(0); +}; + +constexpr char a[] = "hello"; + +template <> template <> +constexpr const char *Wrapper::my_const = a; Index: test/ASTMerge/var-cpp/test.cpp =================================================================== --- /dev/null +++ test/ASTMerge/var-cpp/test.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-pch -std=c++17 -o %t.1.ast %S/Inputs/var1.cpp +// RUN: %clang_cc1 -std=c++17 -ast-merge %t.1.ast -fsyntax-only %s 2>&1 + +static_assert(my_pi == (double)3.1415926535897932385L); +static_assert(my_pi == '3'); + +static_assert(Wrapper::my_const == 1.f); +static_assert(Wrapper::my_const == nullptr); +static_assert(Wrapper::my_const == a); Index: unittests/AST/ASTImporterTest.cpp =================================================================== --- unittests/AST/ASTImporterTest.cpp +++ unittests/AST/ASTImporterTest.cpp @@ -542,20 +542,32 @@ TEST(ImportType, ImportTypeAliasTemplate) { MatchVerifier Verifier; - testImport("template " - "struct dummy { static const int i = K; };" - "template using dummy2 = dummy;" - "int declToImport() { return dummy2<3>::i; }", - Lang_CXX11, "", Lang_CXX11, Verifier, - functionDecl( - hasBody( - compoundStmt( - has( - returnStmt( - has( - implicitCastExpr( - has( - declRefExpr()))))))))); + testImport( + "template " + "struct dummy { static const int i = K; };" + "template using dummy2 = dummy;" + "int declToImport() { return dummy2<3>::i; }", + Lang_CXX11, "", Lang_CXX11, Verifier, + functionDecl( + hasBody(compoundStmt( + has(returnStmt(has(implicitCastExpr(has(declRefExpr()))))))), + unless(hasAncestor(translationUnitDecl(has(typeAliasDecl())))))); +} + +const internal::VariadicDynCastAllOfMatcher + varTemplateSpecializationDecl; + +TEST(ImportDecl, ImportVarTemplate) { + MatchVerifier Verifier; + testImport( + "template " + "T pi = T(3.1415926535897932385L);" + "void declToImport() { pi; }", + Lang_CXX11, "", Lang_CXX11, Verifier, + functionDecl( + hasBody(has(declRefExpr(to(varTemplateSpecializationDecl())))), + unless(hasAncestor(translationUnitDecl(has(varDecl( + hasName("pi"), unless(varTemplateSpecializationDecl())))))))); } TEST(ImportType, ImportPackExpansion) {