diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -12,9 +12,9 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTImporter.h" -#include "clang/AST/ASTImporterSharedState.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/ASTImporterSharedState.h" #include "clang/AST/ASTStructuralEquivalence.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" @@ -34,6 +34,7 @@ #include "clang/AST/LambdaCapture.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/OperationKinds.h" +#include "clang/AST/ParentMapContext.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" @@ -58,8 +59,8 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" @@ -3214,9 +3215,12 @@ } // Returns true if the given D has a DeclContext up to the TranslationUnitDecl -// which is equal to the given DC. +// which is equal to the given DC, or D is equal to DC. static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) { - const DeclContext *DCi = D->getDeclContext(); + const DeclContext *DCi = dyn_cast(D); + if (!DCi) + DCi = D->getDeclContext(); + assert(DCi && "Declaration should have a context"); while (DCi != D->getTranslationUnitDecl()) { if (DCi == DC) return true; @@ -3225,9 +3229,36 @@ return false; } +// Returns true if the statement S has a parent declaration that has a +// DeclContext that is inside (or equal to) DC. In a specific use case if DC is +// a FunctionDecl, check if statement S resides in the body of the function. +static bool isAncestorDeclContextOf(const DeclContext *DC, const Stmt *S) { + ParentMapContext &ParentC = DC->getParentASTContext().getParentMapContext(); + DynTypedNodeList Parents = ParentC.getParents(*S); + while (!Parents.empty()) { + if (const Decl *PD = Parents.begin()->get()) + return isAncestorDeclContextOf(DC, PD); + Parents = ParentC.getParents(*Parents.begin()); + } + return false; +} + static bool hasTypeDeclaredInsideFunction(QualType T, const FunctionDecl *FD) { if (T.isNull()) return false; + + auto CheckTemplateArgument = [FD](const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Type: + return hasTypeDeclaredInsideFunction(Arg.getAsType(), FD); + case TemplateArgument::Expression: + return isAncestorDeclContextOf(FD, Arg.getAsExpr()); + default: + // FIXME: Handle other argument kinds. + return false; + } + }; + if (const auto *RecordT = T->getAs()) { const RecordDecl *RD = RecordT->getDecl(); assert(RD); @@ -3236,12 +3267,15 @@ return true; } if (const auto *RDTempl = dyn_cast(RD)) - return llvm::count_if(RDTempl->getTemplateArgs().asArray(), - [FD](const TemplateArgument &Arg) { - return hasTypeDeclaredInsideFunction( - Arg.getAsType(), FD); - }); + if (llvm::count_if(RDTempl->getTemplateArgs().asArray(), + CheckTemplateArgument)) + return true; + // Note: It is possible that T can be get as both a RecordType and a + // TemplateSpecializationType. } + if (const auto *TST = T->getAs()) + return llvm::count_if(TST->template_arguments(), CheckTemplateArgument); + return false; } diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -6320,6 +6320,24 @@ struct ImportAutoFunctions : ASTImporterOptionSpecificTestBase {}; +TEST_P(ImportAutoFunctions, ReturnWithTemplateWithIntegerArgDeclaredInside) { + Decl *FromTU = getTuDecl( + R"( + template struct Tmpl {}; + auto foo() { + constexpr int X = 1; + return Tmpl(); + } + )", + Lang_CXX14, "input0.cc"); + FunctionDecl *From = FirstDeclMatcher().match( + FromTU, functionDecl(hasName("foo"))); + + FunctionDecl *To = Import(From, Lang_CXX14); + EXPECT_TRUE(To); + EXPECT_TRUE(isa(To->getReturnType())); +} + TEST_P(ImportAutoFunctions, ReturnWithTemplateWithStructDeclaredInside1) { Decl *FromTU = getTuDecl( R"(