Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -97,6 +97,8 @@ typedef DesignatedInitExpr::Designator Designator; Designator ImportDesignator(const Designator &D); + Optional ImportLambdaCapture(const LambdaCapture &From); + /// \brief What we should import from the definition. enum ImportDefinitionKind { @@ -127,16 +129,26 @@ bool ImportDefinition(ObjCProtocolDecl *From, ObjCProtocolDecl *To, ImportDefinitionKind Kind = IDK_Default); TemplateParameterList *ImportTemplateParameterList( - TemplateParameterList *Params); + TemplateParameterList *Params); TemplateArgument ImportTemplateArgument(const TemplateArgument &From); Optional ImportTemplateArgumentLoc( const TemplateArgumentLoc &TALoc); bool ImportTemplateArguments(const TemplateArgument *FromArgs, unsigned NumFromArgs, - SmallVectorImpl &ToArgs); + SmallVectorImpl &ToArgs); + template bool ImportTemplateArgumentListInfo(const InContainerTy &Container, TemplateArgumentListInfo &ToTAInfo); + + template + bool ImportTemplateArgumentListInfo(SourceLocation FromLAngleLoc, + SourceLocation FromRAngleLoc, + const InContainerTy &Container, + TemplateArgumentListInfo &Result); + + bool ImportTemplateInformation(FunctionDecl *FromFD, FunctionDecl *ToFD); + bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain = true); bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, @@ -295,6 +307,7 @@ Expr *VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E); Expr *VisitMemberExpr(MemberExpr *E); Expr *VisitCallExpr(CallExpr *E); + Expr *VisitLambdaExpr(LambdaExpr *LE); Expr *VisitInitListExpr(InitListExpr *E); Expr *VisitArrayInitLoopExpr(ArrayInitLoopExpr *E); Expr *VisitArrayInitIndexExpr(ArrayInitIndexExpr *E); @@ -1045,7 +1058,6 @@ = FromData.HasDeclaredCopyConstructorWithConstParam; ToData.HasDeclaredCopyAssignmentWithConstParam = FromData.HasDeclaredCopyAssignmentWithConstParam; - ToData.IsLambda = FromData.IsLambda; SmallVector Bases; for (const auto &Base1 : FromCXX->bases()) { @@ -1256,6 +1268,9 @@ return false; } +// We cannot use Optional<> pattern here and below because +// TemplateArgumentListInfo's operator new is declared as deleted so it cannot +// be stored in Optional. template bool ASTNodeImporter::ImportTemplateArgumentListInfo( const InContainerTy &Container, TemplateArgumentListInfo &ToTAInfo) { @@ -1268,6 +1283,18 @@ return false; } +template +bool ASTNodeImporter::ImportTemplateArgumentListInfo( + SourceLocation FromLAngleLoc, SourceLocation FromRAngleLoc, + const InContainerTy &Container, TemplateArgumentListInfo &Result) { + TemplateArgumentListInfo ToTAInfo(Importer.Import(FromLAngleLoc), + Importer.Import(FromRAngleLoc)); + if (ImportTemplateArgumentListInfo(Container, ToTAInfo)) + return true; + Result = ToTAInfo; + return false; +} + bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain) { // Eliminate a potential failure point where we attempt to re-import @@ -1918,16 +1945,16 @@ if (DCXX->getLambdaContextDecl() && !CDecl) return nullptr; D2CXX->setLambdaMangling(DCXX->getLambdaManglingNumber(), CDecl); - } else if (DCXX->isInjectedClassName()) { - // We have to be careful to do a similar dance to the one in - // Sema::ActOnStartCXXMemberDeclarations - CXXRecordDecl *const PrevDecl = nullptr; - const bool DelayTypeCreation = true; - D2CXX = CXXRecordDecl::Create( - Importer.getToContext(), D->getTagKind(), DC, StartLoc, Loc, - Name.getAsIdentifierInfo(), PrevDecl, DelayTypeCreation); - Importer.getToContext().getTypeDeclType( - D2CXX, llvm::dyn_cast(DC)); + } else if (DCXX->isInjectedClassName()) { + // We have to be careful to do a similar dance to the one in + // Sema::ActOnStartCXXMemberDeclarations + CXXRecordDecl *const PrevDecl = nullptr; + const bool DelayTypeCreation = true; + D2CXX = CXXRecordDecl::Create( + Importer.getToContext(), D->getTagKind(), DC, StartLoc, Loc, + Name.getAsIdentifierInfo(), PrevDecl, DelayTypeCreation); + Importer.getToContext().getTypeDeclType( + D2CXX, llvm::dyn_cast(DC)); } else { D2CXX = CXXRecordDecl::Create(Importer.getToContext(), D->getTagKind(), @@ -1936,6 +1963,9 @@ } D2 = D2CXX; D2->setAccess(D->getAccess()); + D2->setLexicalDeclContext(LexicalDC); + if (!DCXX->getDescribedClassTemplate()) + LexicalDC->addDeclInternal(D2); Importer.Imported(D, D2); @@ -1964,11 +1994,11 @@ } else { D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(), DC, StartLoc, Loc, Name.getAsIdentifierInfo()); + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(D2); } D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); - D2->setLexicalDeclContext(LexicalDC); - LexicalDC->addDeclInternal(D2); if (D->isAnonymousStructOrUnion()) D2->setAnonymousStructOrUnion(true); if (PrevDecl) { @@ -2044,6 +2074,92 @@ return ToEnumerator; } +bool ASTNodeImporter::ImportTemplateInformation(FunctionDecl *FromFD, + FunctionDecl *ToFD) { + switch (FromFD->getTemplatedKind()) { + case FunctionDecl::TK_NonTemplate: + case FunctionDecl::TK_FunctionTemplate: + break; + + case FunctionDecl::TK_MemberSpecialization: { + FunctionDecl *InstFD = cast_or_null( + Importer.Import(FromFD->getInstantiatedFromMemberFunction())); + if (!InstFD) + return true; + + TemplateSpecializationKind TSK = FromFD->getTemplateSpecializationKind(); + SourceLocation POI = Importer.Import( + FromFD->getMemberSpecializationInfo()->getPointOfInstantiation()); + ToFD->setInstantiationOfMemberFunction(InstFD, TSK); + ToFD->getMemberSpecializationInfo()->setPointOfInstantiation(POI); + break; + } + + case FunctionDecl::TK_FunctionTemplateSpecialization: { + auto *FTSInfo = FromFD->getTemplateSpecializationInfo(); + FunctionTemplateDecl *Template = cast_or_null( + Importer.Import(FTSInfo->getTemplate())); + if (!Template) + return true; + TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind(); + + // Import template arguments. + auto TemplArgs = FTSInfo->TemplateArguments->asArray(); + SmallVector ToTemplArgs; + if (ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(), + ToTemplArgs)) + return true; + + TemplateArgumentList *ToTAList = TemplateArgumentList::CreateCopy( + Importer.getToContext(), ToTemplArgs); + + TemplateArgumentListInfo ToTAInfo; + const auto *FromTAArgsAsWritten = FTSInfo->TemplateArgumentsAsWritten; + if (FromTAArgsAsWritten) { + if (ImportTemplateArgumentListInfo( + FromTAArgsAsWritten->LAngleLoc, FromTAArgsAsWritten->RAngleLoc, + FromTAArgsAsWritten->arguments(), ToTAInfo)) + return true; + } + + SourceLocation POI = Importer.Import(FTSInfo->getPointOfInstantiation()); + + ToFD->setFunctionTemplateSpecialization( + Template, ToTAList, /* InsertPos= */ nullptr, + TSK, FromTAArgsAsWritten ? &ToTAInfo : nullptr, POI); + break; + } + + case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { + auto *FromInfo = FromFD->getDependentSpecializationInfo(); + UnresolvedSet<8> TemplDecls; + unsigned NumTemplates = FromInfo->getNumTemplates(); + for (unsigned I = 0; I < NumTemplates; I++) { + if (auto *ToFTD = cast_or_null( + Importer.Import(FromInfo->getTemplate(I)))) + TemplDecls.addDecl(ToFTD); + else + return true; + } + + // Import TemplateArgumentListInfo. + TemplateArgumentListInfo ToTAInfo; + if (ImportTemplateArgumentListInfo( + FromInfo->getLAngleLoc(), FromInfo->getRAngleLoc(), + llvm::makeArrayRef(FromInfo->getTemplateArgs(), + FromInfo->getNumTemplateArgs()), + ToTAInfo)) + return true; + + ToFD->setDependentTemplateSpecialization(Importer.getToContext(), + TemplDecls, ToTAInfo); + break; + } + } + + return false; +} + Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // Import the major distinguishing characteristics of this function. DeclContext *DC, *LexicalDC; @@ -2151,15 +2267,18 @@ Parameters.push_back(ToP); } - // Create the imported function. TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + if (D->getTypeSourceInfo() && !TInfo) + return nullptr; + + // Create the imported function. FunctionDecl *ToFunction = nullptr; SourceLocation InnerLocStart = Importer.Import(D->getInnerLocStart()); if (CXXConstructorDecl *FromConstructor = dyn_cast(D)) { ToFunction = CXXConstructorDecl::Create(Importer.getToContext(), cast(DC), InnerLocStart, - NameInfo, T, TInfo, + NameInfo, T, TInfo, FromConstructor->isExplicit(), D->isInlineSpecified(), D->isImplicit(), @@ -2225,9 +2344,9 @@ Importer.Imported(D, ToFunction); // Set the parameters. - for (unsigned I = 0, N = Parameters.size(); I != N; ++I) { - Parameters[I]->setOwningFunction(ToFunction); - ToFunction->addDeclInternal(Parameters[I]); + for (ParmVarDecl *Param : Parameters) { + Param->setOwningFunction(ToFunction); + ToFunction->addDeclInternal(Param); } ToFunction->setParams(Parameters); @@ -2237,6 +2356,16 @@ ToFunction->setPreviousDecl(Recent); } + // We need to complete creation of FunctionProtoTypeLoc manually with setting + // params it refers to. + if (TInfo) { + if (auto ProtoLoc = + TInfo->getTypeLoc().IgnoreParens().getAs()) { + for (unsigned I = 0, N = Parameters.size(); I != N; ++I) + ProtoLoc.setParam(I, Parameters[I]); + } + } + if (usedDifferentExceptionSpec) { // Update FunctionProtoType::ExtProtoInfo. QualType T = Importer.Import(D->getType()); @@ -2254,8 +2383,17 @@ // FIXME: Other bits to merge? + // If it is a template, import all related things. + if (ImportTemplateInformation(D, ToFunction)) + return nullptr; + // Add this function to the lexical context. - LexicalDC->addDeclInternal(ToFunction); + // NOTE: If the function is templated declaration, it should be not added into + // LexicalDC. But described template is imported during import of + // FunctionTemplateDecl (it happens later). So, we use source declaration + // to determine if we should add the result function. + if (!D->getDescribedFunctionTemplate()) + LexicalDC->addDeclInternal(ToFunction); if (auto *FromCXXMethod = dyn_cast(D)) ImportOverrides(cast(ToFunction), FromCXXMethod); @@ -2749,6 +2887,14 @@ if (FromDefArg && !ToDefArg) return nullptr; + if (D->isObjCMethodParameter()) { + ToParm->setObjCMethodScopeInfo(D->getFunctionScopeIndex()); + ToParm->setObjCDeclQualifier(D->getObjCDeclQualifier()); + } else { + ToParm->setScopeInfo(D->getFunctionScopeDepth(), + D->getFunctionScopeIndex()); + } + if (D->isUsed()) ToParm->setIsUsed(); @@ -3850,12 +3996,12 @@ return nullptr; } - CXXRecordDecl *DTemplated = D->getTemplatedDecl(); - + CXXRecordDecl *FromTemplated = D->getTemplatedDecl(); + // Create the declaration that is being templated. - CXXRecordDecl *D2Templated = cast_or_null( - Importer.Import(DTemplated)); - if (!D2Templated) + CXXRecordDecl *ToTemplated = cast_or_null( + Importer.Import(FromTemplated)); + if (!ToTemplated) return nullptr; // Resolve possible cyclic import. @@ -3863,15 +4009,15 @@ return AlreadyImported; // Create the class template declaration itself. - TemplateParameterList *TemplateParams - = ImportTemplateParameterList(D->getTemplateParameters()); + TemplateParameterList *TemplateParams = + ImportTemplateParameterList(D->getTemplateParameters()); if (!TemplateParams) return nullptr; ClassTemplateDecl *D2 = ClassTemplateDecl::Create(Importer.getToContext(), DC, Loc, Name, TemplateParams, - D2Templated); - D2Templated->setDescribedClassTemplate(D2); + ToTemplated); + ToTemplated->setDescribedClassTemplate(D2); D2->setAccess(D->getAccess()); D2->setLexicalDeclContext(LexicalDC); @@ -3879,10 +4025,10 @@ // Note the relationship between the class templates. Importer.Imported(D, D2); - Importer.Imported(DTemplated, D2Templated); + Importer.Imported(FromTemplated, ToTemplated); - if (DTemplated->isCompleteDefinition() && - !D2Templated->isCompleteDefinition()) { + if (FromTemplated->isCompleteDefinition() && + !ToTemplated->isCompleteDefinition()) { // FIXME: Import definition! } @@ -3958,12 +4104,8 @@ // Import TemplateArgumentListInfo TemplateArgumentListInfo ToTAInfo; auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten(); - for (unsigned I = 0, E = ASTTemplateArgs.NumTemplateArgs; I < E; ++I) { - if (auto ToLoc = ImportTemplateArgumentLoc(ASTTemplateArgs[I])) - ToTAInfo.addArgument(*ToLoc); - else - return nullptr; - } + if (ImportTemplateArgumentListInfo(ASTTemplateArgs.arguments(), ToTAInfo)) + return nullptr; QualType CanonInjType = Importer.Import( PartialSpec->getInjectedSpecializationType()); @@ -4901,12 +5043,8 @@ TemplateArgumentListInfo ToTAInfo; TemplateArgumentListInfo *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { - for (const auto &FromLoc : E->template_arguments()) { - if (auto ToTALoc = ImportTemplateArgumentLoc(FromLoc)) - ToTAInfo.addArgument(*ToTALoc); - else - return nullptr; - } + if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo)) + return nullptr; ResInfo = &ToTAInfo; } @@ -5861,11 +5999,10 @@ if (BaseType.isNull()) return nullptr; - TemplateArgumentListInfo ToTAInfo(Importer.Import(E->getLAngleLoc()), - Importer.Import(E->getRAngleLoc())); - TemplateArgumentListInfo *ResInfo = nullptr; + TemplateArgumentListInfo ToTAInfo, *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { - if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo)) + if (ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(), + E->template_arguments(), ToTAInfo)) return nullptr; ResInfo = &ToTAInfo; } @@ -5926,11 +6063,10 @@ return nullptr; } - TemplateArgumentListInfo ToTAInfo(Importer.Import(E->getLAngleLoc()), - Importer.Import(E->getRAngleLoc())); - TemplateArgumentListInfo *ResInfo = nullptr; + TemplateArgumentListInfo ToTAInfo, *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { - if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo)) + if (ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(), + E->template_arguments(), ToTAInfo)) return nullptr; ResInfo = &ToTAInfo; } @@ -5981,6 +6117,74 @@ Importer.Import(E->getRParenLoc())); } +Optional +ASTNodeImporter::ImportLambdaCapture(const LambdaCapture &From) { + VarDecl *Var = nullptr; + if (From.capturesVariable()) { + Var = cast_or_null(Importer.Import(From.getCapturedVar())); + if (!Var) + return None; + } + + return LambdaCapture(Importer.Import(From.getLocation()), From.isImplicit(), + From.getCaptureKind(), Var, + From.isPackExpansion() + ? Importer.Import(From.getEllipsisLoc()) + : SourceLocation()); +} + +Expr *ASTNodeImporter::VisitLambdaExpr(LambdaExpr *LE) { + CXXRecordDecl *FromClass = LE->getLambdaClass(); + CXXRecordDecl *ToClass = dyn_cast_or_null( + Importer.Import(FromClass)); + if (!ToClass) + return nullptr; + + // NOTE: lambda classes are created with BeingDefined flag set up. + // It means that ImportDefinition doesn't work for them and we should fill it + // manually. + if (ToClass->isBeingDefined()) { + for (auto FromField : FromClass->fields()) { + auto *ToField = cast_or_null(Importer.Import(FromField)); + if (!ToField) + return nullptr; + } + } + + auto *ToCallOp = dyn_cast_or_null( + Importer.Import(LE->getCallOperator())); + if (!ToCallOp) + return nullptr; + + ToClass->completeDefinition(); + + unsigned NumCaptures = LE->capture_size(); + SmallVector Captures; + Captures.reserve(NumCaptures); + for (const auto &FromCapture : LE->captures()) { + if (auto ToCapture = ImportLambdaCapture(FromCapture)) + Captures.push_back(*ToCapture); + else + return nullptr; + } + + SmallVector InitCaptures(NumCaptures); + if (ImportContainerChecked(LE->capture_inits(), InitCaptures)) + return nullptr; + + return LambdaExpr::Create(Importer.getToContext(), ToClass, + Importer.Import(LE->getIntroducerRange()), + LE->getCaptureDefault(), + Importer.Import(LE->getCaptureDefaultLoc()), + Captures, + LE->hasExplicitParameters(), + LE->hasExplicitResultType(), + InitCaptures, + Importer.Import(LE->getLocEnd()), + LE->containsUnexpandedParameterPack()); +} + + Expr *ASTNodeImporter::VisitInitListExpr(InitListExpr *ILE) { QualType T = Importer.Import(ILE->getType()); if (T.isNull()) Index: lib/AST/ASTStructuralEquivalence.cpp =================================================================== --- lib/AST/ASTStructuralEquivalence.cpp +++ lib/AST/ASTStructuralEquivalence.cpp @@ -1264,6 +1264,17 @@ return !Finish(); } +static bool IsTemplateDeclStructurallyEquivalent( + StructuralEquivalenceContext &Ctx, TemplateDecl *D1, TemplateDecl *D2) { + if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier())) + return false; + if (!D1->getIdentifier()) // Special name + if (D1->getNameAsString() != D2->getNameAsString()) + return false; + return IsStructurallyEquivalent(Ctx, D1->getTemplateParameters(), + D2->getTemplateParameters()); +} + bool StructuralEquivalenceContext::Finish() { while (!DeclsToCheck.empty()) { // Check the next declaration. @@ -1323,9 +1334,29 @@ } else if (ClassTemplateDecl *ClassTemplate1 = dyn_cast(D1)) { if (ClassTemplateDecl *ClassTemplate2 = dyn_cast(D2)) { - if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(), - ClassTemplate2->getIdentifier()) || - !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2)) + if (!::IsTemplateDeclStructurallyEquivalent(*this, ClassTemplate1, + ClassTemplate2) || + !::IsStructurallyEquivalent(*this, ClassTemplate1, + ClassTemplate2) || + !::IsStructurallyEquivalent( + *this, ClassTemplate1->getTemplatedDecl(), + ClassTemplate2->getTemplatedDecl())) + Equivalent = false; + } else { + // Class template/non-class-template mismatch. + Equivalent = false; + } + } else if (FunctionTemplateDecl *FunctionTemplate1 = + dyn_cast(D1)) { + if (FunctionTemplateDecl *FunctionTemplate2 = + dyn_cast(D2)) { + if (!::IsTemplateDeclStructurallyEquivalent(*this, FunctionTemplate1, + FunctionTemplate2) || + !::IsStructurallyEquivalent(*this, FunctionTemplate1, + FunctionTemplate2) || + !::IsStructurallyEquivalent( + *this, FunctionTemplate1->getTemplatedDecl()->getType(), + FunctionTemplate2->getTemplatedDecl()->getType())) Equivalent = false; } else { // Class template/non-class-template mismatch. Index: lib/AST/ExternalASTMerger.cpp =================================================================== --- lib/AST/ExternalASTMerger.cpp +++ lib/AST/ExternalASTMerger.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/ExternalASTMerger.h" using namespace clang; @@ -351,6 +352,27 @@ } } +template +static bool importSpecializations(DeclTy *D, ASTImporter *Importer) { + for (auto *Spec : D->specializations()) + if (!Importer->Import(Spec)) + return true; + return false; +} + +/// Imports specializations from template declarations that can be specialized. +static bool importSpecializationsIfNeeded(Decl *D, ASTImporter *Importer) { + if (!isa(D)) + return false; + if (auto *FunctionTD = dyn_cast(D)) + return importSpecializations(FunctionTD, Importer); + else if (auto *ClassTD = dyn_cast(D)) + return importSpecializations(ClassTD, Importer); + else if (auto *VarTD = dyn_cast(D)) + return importSpecializations(VarTD, Importer); + return false; +} + bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { llvm::SmallVector Decls; @@ -376,9 +398,17 @@ Decls.reserve(Candidates.size()); for (const Candidate &C : Candidates) { - NamedDecl *d = cast(C.second->Import(C.first.get())); - assert(d); - Decls.push_back(d); + Decl *LookupRes = C.first.get(); + ASTImporter *Importer = C.second; + NamedDecl *ND = cast(Importer->Import(LookupRes)); + assert(ND); + // If we don't import specialization, they are not available via lookup + // because the lookup result is imported TemplateDecl and it does not + // reference its specializations until they are imported explicitly. + bool IsSpecImportFailed = + importSpecializationsIfNeeded(LookupRes, Importer); + assert(!IsSpecImportFailed); + Decls.push_back(ND); } SetExternalVisibleDeclsForName(DC, Name, Decls); return true; Index: test/ASTMerge/class-template/Inputs/class-template1.cpp =================================================================== --- test/ASTMerge/class-template/Inputs/class-template1.cpp +++ test/ASTMerge/class-template/Inputs/class-template1.cpp @@ -1,5 +1,7 @@ template -struct X0; +struct X0 { + T getValue(T arg) { return arg; } +}; template struct X1; @@ -26,6 +28,7 @@ template<> struct X0 { int member; + char getValue(char ch) { return static_cast(member); } }; template<> Index: test/ASTMerge/class-template/Inputs/class-template2.cpp =================================================================== --- test/ASTMerge/class-template/Inputs/class-template2.cpp +++ test/ASTMerge/class-template/Inputs/class-template2.cpp @@ -1,5 +1,7 @@ template -struct X0; +struct X0 { + T getValue(T arg); +}; template struct X1; Index: test/ASTMerge/class-template/test.cpp =================================================================== --- test/ASTMerge/class-template/test.cpp +++ test/ASTMerge/class-template/test.cpp @@ -1,24 +1,28 @@ -// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/class-template1.cpp -// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/class-template2.cpp -// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -std=c++1z -emit-pch -o %t.1.ast %S/Inputs/class-template1.cpp +// RUN: %clang_cc1 -std=c++1z -emit-pch -o %t.2.ast %S/Inputs/class-template2.cpp +// RUN: not %clang_cc1 -std=c++1z -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s -// CHECK: class-template1.cpp:7:14: error: non-type template parameter declared with incompatible types in different translation units ('int' vs. 'long') -// CHECK: class-template2.cpp:7:15: note: declared here with type 'long' +static_assert(sizeof(X0().getValue(1)) == sizeof(char)); +static_assert(sizeof(X0().getValue(1)) == sizeof(int)); -// CHECK: class-template1.cpp:10:14: error: template parameter has different kinds in different translation units -// CHECK: class-template2.cpp:10:10: note: template parameter declared here +// CHECK: class-template1.cpp:9:14: error: non-type template parameter declared with incompatible types in different translation units ('int' vs. 'long') +// CHECK: class-template2.cpp:9:15: note: declared here with type 'long' -// CHECK: class-template1.cpp:16:23: error: non-type template parameter declared with incompatible types in different translation units ('long' vs. 'int') -// CHECK: class-template2.cpp:16:23: note: declared here with type 'int' +// CHECK: class-template1.cpp:12:14: error: template parameter has different kinds in different translation units +// CHECK: class-template2.cpp:12:10: note: template parameter declared here -// CHECK: class-template1.cpp:19:10: error: template parameter has different kinds in different translation units -// CHECK: class-template2.cpp:19:10: note: template parameter declared here +// CHECK: class-template1.cpp:18:23: error: non-type template parameter declared with incompatible types in different translation units ('long' vs. 'int') +// CHECK: class-template2.cpp:18:23: note: declared here with type 'int' -// CHECK: class-template2.cpp:25:20: error: external variable 'x0r' declared with incompatible types in different translation units ('X0 *' vs. 'X0 *') -// CHECK: class-template1.cpp:24:19: note: declared here with type 'X0 *' +// CHECK: class-template1.cpp:21:10: error: template parameter has different kinds in different translation units +// CHECK: class-template2.cpp:21:10: note: template parameter declared here -// CHECK: class-template1.cpp:32:8: warning: type 'X0' has incompatible definitions in different translation units -// CHECK: class-template1.cpp:33:7: note: field 'member' has type 'int' here -// CHECK: class-template2.cpp:34:9: note: field 'member' has type 'float' here +// CHECK: class-template2.cpp:27:20: error: external variable 'x0r' declared with incompatible types in different translation units ('X0 *' vs. 'X0 *') +// CHECK: class-template1.cpp:26:19: note: declared here with type 'X0 *' + +// CHECK: class-template1.cpp:35:8: warning: type 'X0' has incompatible definitions in different translation units +// CHECK: class-template1.cpp:36:7: note: field 'member' has type 'int' here +// CHECK: class-template2.cpp:36:9: note: field 'member' has type 'float' here // CHECK: 1 warning and 5 errors generated. +// CHECK-NOT: static_assert Index: test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp =================================================================== --- test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp +++ test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp @@ -122,3 +122,20 @@ const bool ExpressionTrait = __is_lvalue_expr(1); const unsigned ArrayRank = __array_rank(int[10][20]); const unsigned ArrayExtent = __array_extent(int[10][20], 1); + +constexpr int testLambdaAdd(int toAdd) { + const int Captured1 = 1, Captured2 = 2; + constexpr auto LambdaAdd = [Captured1, Captured2](int k) -> int { + return Captured1 + Captured2 + k; + }; + return LambdaAdd(toAdd); +} + +template +struct TestLambdaTemplate { + T i, j; + TestLambdaTemplate(T i, const T &j) : i(i), j(j) {} + T testLambda(T k) { + return [this](T k) -> decltype(auto) { return i + j + k; }(k); + } +}; Index: test/ASTMerge/exprs-cpp/test.cpp =================================================================== --- test/ASTMerge/exprs-cpp/test.cpp +++ test/ASTMerge/exprs-cpp/test.cpp @@ -30,6 +30,8 @@ static_assert(ArrayRank == 2); static_assert(ArrayExtent == 20); +static_assert(testLambdaAdd(3) == 6); + void testImport(int *x, const S1 &cs1, S1 &s1) { testNewThrowDelete(); testArrayElement(nullptr, 12); @@ -44,4 +46,5 @@ testDefaultArg(); testDefaultArgExpr(); useTemplateType(); + TestLambdaTemplate(1, 2).testLambda(3); } Index: test/ASTMerge/function-cpp/Inputs/function-1.cpp =================================================================== --- /dev/null +++ test/ASTMerge/function-cpp/Inputs/function-1.cpp @@ -0,0 +1,8 @@ + +template constexpr T add(T arg1, T arg2) { + return arg1 + arg2; +} + +template<> constexpr int add(int arg1, int arg2) { + return arg1 + arg2 + 2; +} Index: test/ASTMerge/function-cpp/test.cpp =================================================================== --- /dev/null +++ test/ASTMerge/function-cpp/test.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -std=c++1z -emit-pch -o %t.1.ast %S/Inputs/function-1.cpp +// RUN: %clang_cc1 -std=c++1z -ast-merge %t.1.ast -fsyntax-only %s 2>&1 | FileCheck %s +// XFAIL: * + +static_assert(add(1, 2) == 5); + +// FIXME: support of templated function overload is still not implemented. +static_assert(add('\1', '\2') == 3); + +// CHECK-NOT: static_assert Index: test/Import/template-specialization/Inputs/T.cpp =================================================================== --- test/Import/template-specialization/Inputs/T.cpp +++ test/Import/template-specialization/Inputs/T.cpp @@ -12,3 +12,7 @@ int g; }; }; + + +template constexpr int f() { return 0; } +template <> constexpr int f() { return 4; } Index: test/Import/template-specialization/test.cpp =================================================================== --- test/Import/template-specialization/test.cpp +++ test/Import/template-specialization/test.cpp @@ -1,7 +1,10 @@ // RUN: clang-import-test -import %S/Inputs/T.cpp -expression %s -// XFAIL: * + void expr() { A::B b1; A::B b2; b1.f + b2.g; } + +static_assert(f() == 0, ""); +static_assert(f() == 4, ""); Index: unittests/AST/ASTImporterTest.cpp =================================================================== --- unittests/AST/ASTImporterTest.cpp +++ unittests/AST/ASTImporterTest.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// +#include "MatchVerifier.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTImporter.h" -#include "MatchVerifier.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/Tooling.h" @@ -99,7 +99,11 @@ if (FoundDecls.size() != 1) return testing::AssertionFailure() << "Multiple declarations were found!"; - auto Imported = Importer.Import(*FoundDecls.begin()); + // Sanity check: the node being imported should match in the same way as + // the result node. + EXPECT_TRUE(Verifier.match(FoundDecls.front(), AMatcher)); + + auto Imported = Importer.Import(FoundDecls.front()); if (!Imported) return testing::AssertionFailure() << "Import failed, nullptr returned!"; @@ -624,7 +628,7 @@ TEST(ImportDecl, ImportUsingDecl) { MatchVerifier Verifier; testImport("namespace foo { int bar; }" - "int declToImport(){ using foo::bar; }", + "void declToImport() { using foo::bar; }", Lang_CXX, "", Lang_CXX, Verifier, functionDecl( has( @@ -665,13 +669,13 @@ "}" "void instantiate() { declToImport(); }", Lang_CXX, "", Lang_CXX, Verifier, - functionTemplateDecl(has(functionDecl(has( - compoundStmt(has(unresolvedLookupExpr()))))))); + functionTemplateDecl(has(functionDecl( + has(compoundStmt(has(unresolvedLookupExpr()))))))); } TEST(ImportExpr, ImportCXXUnresolvedConstructExpr) { MatchVerifier Verifier; - testImport("template class C { T t; };" + testImport("template struct C { T t; };" "template void declToImport() {" " C d;" " d.t = T();" @@ -680,7 +684,7 @@ Lang_CXX, "", Lang_CXX, Verifier, functionTemplateDecl(has(functionDecl(has(compoundStmt(has( binaryOperator(has(cxxUnresolvedConstructExpr()))))))))); - testImport("template class C { T t; };" + testImport("template struct C { T t; };" "template void declToImport() {" " C d;" " (&d)->t = T();" @@ -691,5 +695,22 @@ binaryOperator(has(cxxUnresolvedConstructExpr()))))))))); } +/// Check that function "declToImport()" (which is the templated function +/// for corresponding FunctionTemplateDecl) is not added into DeclContext. +/// Same for class template declarations. +TEST(ImportDecl, ImportTemplatedDeclForTemplate) { + MatchVerifier Verifier; + testImport("template void declToImport() { T a = 1; }" + "void instantiate() { declToImport(); }", + Lang_CXX, "", Lang_CXX, Verifier, + functionTemplateDecl(hasAncestor(translationUnitDecl( + unless(has(functionDecl(hasName("declToImport")))))))); + testImport("template struct declToImport { T t; };" + "void instantiate() { declToImport(); }", + Lang_CXX, "", Lang_CXX, Verifier, + classTemplateDecl(hasAncestor(translationUnitDecl( + unless(has(cxxRecordDecl(hasName("declToImport")))))))); +} + } // end namespace ast_matchers } // end namespace clang