Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -5444,6 +5444,22 @@ CUDAKernelCallExpr> cudaKernelCallExpr; +/// \brief Matches member access expressions where the member could not +/// be resolved because the base member was dependent. +/// +/// Example matches d.t, and also (&d)->t +/// \code +/// template class C {T t; }; +/// template void foo() { +/// C d; +/// d.t = T(); +/// (&d)->t = T(); +/// } +/// \endcode +const internal::VariadicDynCastAllOfMatcher + cxxDependentScopeMemberExpr; + + /// \brief Matches expressions that resolve to a null pointer constant, such as /// GNU's __null, C++11's nullptr, or C's NULL macro. /// Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -124,6 +124,9 @@ ImportDefinitionKind Kind = IDK_Default); bool ImportDefinition(ObjCProtocolDecl *From, ObjCProtocolDecl *To, ImportDefinitionKind Kind = IDK_Default); + + void ImportAttributes(Decl *From, Decl *To); + TemplateParameterList *ImportTemplateParameterList( TemplateParameterList *Params); TemplateArgument ImportTemplateArgument(const TemplateArgument &From); @@ -138,6 +141,8 @@ bool Complain = true); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC); + bool IsStructuralMatch(FunctionTemplateDecl *From, + FunctionTemplateDecl *To); bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To); Decl *VisitDecl(Decl *D); @@ -160,6 +165,7 @@ Decl *VisitFieldDecl(FieldDecl *D); Decl *VisitIndirectFieldDecl(IndirectFieldDecl *D); Decl *VisitFriendDecl(FriendDecl *D); + Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D); Decl *VisitObjCIvarDecl(ObjCIvarDecl *D); Decl *VisitVarDecl(VarDecl *D); Decl *VisitImplicitParamDecl(ImplicitParamDecl *D); @@ -266,6 +272,7 @@ Expr *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E); Expr *VisitCXXNewExpr(CXXNewExpr *CE); Expr *VisitCXXDeleteExpr(CXXDeleteExpr *E); + Expr *VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); Expr *VisitCXXConstructExpr(CXXConstructExpr *E); Expr *VisitCXXMemberCallExpr(CXXMemberCallExpr *E); Expr *VisitExprWithCleanups(ExprWithCleanups *EWC); @@ -2316,6 +2323,15 @@ return false; } +void ASTNodeImporter::ImportAttributes(Decl *From, Decl *To) { + for (Decl::attr_iterator I = From->attr_begin(), E = From->attr_end(); I != E; + ++I) { + Attr *ToAttr = (*I)->clone(Importer.getToContext()); + ToAttr->setRange(Importer.Import((*I)->getRange())); + To->addAttr(ToAttr); + } +} + TemplateParameterList *ASTNodeImporter::ImportTemplateParameterList( TemplateParameterList *Params) { SmallVector ToParams(Params->size()); @@ -2493,6 +2509,15 @@ FromVal == ToVal; } +bool ASTNodeImporter::IsStructuralMatch(FunctionTemplateDecl *From, + FunctionTemplateDecl *To) { + StructuralEquivalenceContext Ctx(Importer.getFromContext(), + Importer.getToContext(), + Importer.getNonEquivalentDecls(), + false, false); + return Ctx.IsStructurallyEquivalent(From, To); +} + bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), @@ -3491,6 +3516,64 @@ return FrD; } +Decl *ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *ToD; + + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + return nullptr; + assert(DC && "Null DeclContext after importing decl parts"); + if (ToD) + return ToD; + + // Try to find a function in our own ("to") context with the same name, same + // type, and in the same context as the function we're importing. + if (!LexicalDC->isFunctionOrMethod()) { + unsigned IDNS = Decl::IDNS_Ordinary; + SmallVector FoundDecls; + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) + continue; + + if (FunctionTemplateDecl *FoundFunction = + dyn_cast(FoundDecls[I])) { + if (FoundFunction->hasExternalFormalLinkage() && + D->hasExternalFormalLinkage()) { + if (IsStructuralMatch(D, FoundFunction)) { + Importer.Imported(D, FoundFunction); + // FIXME: Actually try to merge the body and other attributes. + return FoundFunction; + } + } + } + } + } + + TemplateParameterList *Params = ImportTemplateParameterList( + D->getTemplateParameters()); + if (!Params) + return nullptr; + + FunctionDecl *TemplatedFD = cast_or_null(D->getTemplatedDecl()); + if (!TemplatedFD) + return nullptr; + + FunctionTemplateDecl *ToFunc = FunctionTemplateDecl::Create( + Importer.getToContext(), DC, Loc, Name, Params, TemplatedFD); + + TemplatedFD->setDescribedFunctionTemplate(ToFunc); + ImportAttributes(D, ToFunc); + ToFunc->setAccess(D->getAccess()); + ToFunc->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToFunc); + + LexicalDC->addDeclInternal(ToFunc); + return ToFunc; +} + Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { // Import the major distinguishing characteristics of an ivar. DeclContext *DC, *LexicalDC; @@ -6372,6 +6455,40 @@ Importer.Import(E->getLocStart())); } +Expr *ASTNodeImporter::VisitCXXDependentScopeMemberExpr( + CXXDependentScopeMemberExpr *E) { + Expr *Base = E->getBase(); + if (!Base) + return nullptr; + + QualType BaseType = E->getBaseType(); + if (BaseType.isNull()) + return nullptr; + + TemplateArgumentListInfo ToTAInfo; + TemplateArgumentListInfo *ResInfo = nullptr; + if (E->hasExplicitTemplateArgs()) { + for (const auto &FromLoc : E->template_arguments()) { + bool Error = false; + TemplateArgumentLoc ToTALoc = ImportTemplateArgumentLoc(FromLoc, Error); + if (Error) + return nullptr; + ToTAInfo.addArgument(ToTALoc); + } + ResInfo = &ToTAInfo; + } + + return CXXDependentScopeMemberExpr::Create(Importer.getToContext(), + Base, BaseType, + E->isArrow(), + E->getOperatorLoc(), + E->getQualifierLoc(), + E->getTemplateKeywordLoc(), + E->getFirstQualifierFoundInScope(), + E->getMemberNameInfo(), + ResInfo); +} + Expr *ASTNodeImporter::VisitCXXConstructExpr(CXXConstructExpr *E) { QualType T = Importer.Import(E->getType()); if (T.isNull()) Index: lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- lib/ASTMatchers/Dynamic/Registry.cpp +++ lib/ASTMatchers/Dynamic/Registry.cpp @@ -141,6 +141,7 @@ REGISTER_MATCHER(cxxCtorInitializer); REGISTER_MATCHER(cxxDefaultArgExpr); REGISTER_MATCHER(cxxDeleteExpr); + REGISTER_MATCHER(cxxDependentScopeMemberExpr); REGISTER_MATCHER(cxxDestructorDecl); REGISTER_MATCHER(cxxDynamicCastExpr); REGISTER_MATCHER(cxxForRangeStmt); Index: unittests/AST/ASTImporterTest.cpp =================================================================== --- unittests/AST/ASTImporterTest.cpp +++ unittests/AST/ASTImporterTest.cpp @@ -489,5 +489,54 @@ } +TEST(ImportDecl, ImportFunctionTemplateDecl) { + MatchVerifier Verifier; + EXPECT_TRUE( + testImport( + "template void declToImport() { };", + Lang_CXX, "", Lang_CXX, Verifier, + functionTemplateDecl())); +} + + +TEST(ImportExpr, ImportCXXDependentScopeMemberExpr) { + MatchVerifier Verifier; + EXPECT_TRUE( + testImport( + "template class C { T t; };" + "template void declToImport() {" + "C d;" + "d.t = T();" + "}", + Lang_CXX, "", Lang_CXX, Verifier, + functionTemplateDecl( + has( + functionDecl( + has( + compoundStmt( + has( + binaryOperator( + has( + cxxDependentScopeMemberExpr())))))))))); + EXPECT_TRUE( + testImport( + "template class C { T t; };" + "template void declToImport() {" + "C d;" + "(&d)->t = T();" + "}", + Lang_CXX, "", Lang_CXX, Verifier, + functionTemplateDecl( + has( + functionDecl( + has( + compoundStmt( + has( + binaryOperator( + has( + cxxDependentScopeMemberExpr())))))))))); +} + + } // end namespace ast_matchers } // end namespace clang