diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 21b9f21b8e6e2..7fee8d21fa39e 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3227,23 +3227,32 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) { return false; } +static bool hasTypeDeclaredInsideFunction(QualType T, const FunctionDecl *FD) { + if (T.isNull()) + return false; + if (const auto *RecordT = T->getAs()) { + const RecordDecl *RD = RecordT->getDecl(); + assert(RD); + if (isAncestorDeclContextOf(FD, RD)) { + assert(RD->getLexicalDeclContext() == RD->getDeclContext()); + 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); + }); + } + return false; +} + bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) { QualType FromTy = D->getType(); const auto *FromFPT = FromTy->getAs(); assert(FromFPT && "Must be called on FunctionProtoType"); - if (const AutoType *AutoT = - FromFPT->getReturnType()->getContainedAutoType()) { - QualType DeducedT = AutoT->getDeducedType(); - if (const auto *RecordT = - !DeducedT.isNull() ? DeducedT->getAs() : nullptr) { - const RecordDecl *RD = RecordT->getDecl(); - assert(RD); - if (isAncestorDeclContextOf(D, RD)) { - assert(RD->getLexicalDeclContext() == RD->getDeclContext()); - return true; - } - } - } + if (const AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType()) + return hasTypeDeclaredInsideFunction(AutoT->getDeducedType(), D); if (const auto *TypedefT = FromFPT->getReturnType()->getAs()) { const TypedefNameDecl *TD = TypedefT->getDecl(); assert(TD); diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 4d37ac2ebb2ed..607c049608e6f 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -6319,6 +6319,61 @@ TEST_P(ASTImporterOptionSpecificTestBase, struct ImportAutoFunctions : ASTImporterOptionSpecificTestBase {}; +TEST_P(ImportAutoFunctions, ReturnWithTemplateWithStructDeclaredInside1) { + Decl *FromTU = getTuDecl( + R"( + template struct Tmpl {}; + auto foo() { + struct X {}; + 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, ReturnWithTemplateWithStructDeclaredInside2) { + Decl *FromTU = getTuDecl( + R"( + template struct Tmpl {}; + auto foo() { + struct X {}; + 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, ReturnWithTemplateWithTypedefDeclaredInside) { + Decl *FromTU = getTuDecl( + R"( + template struct Tmpl {}; + auto foo() { + struct X {}; + using x_type = X; + 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, ReturnWithTypedefDeclaredInside) { Decl *FromTU = getTuDecl( R"(