[clang][ASTImporter] Fix import of function with auto return type.

Fix a case of importing a function with auto return type
that is resolved with a type template argument that is declared
inside the function.
Fixes #55500

Reviewed By: martong

Differential Revision: https://reviews.llvm.org/D127396
This commit is contained in:
Balázs Kéri 2022-06-10 10:00:34 +02:00
parent 76b57ef88c
commit f93dee1033
2 changed files with 77 additions and 13 deletions

View file

@ -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<RecordType>()) {
const RecordDecl *RD = RecordT->getDecl();
assert(RD);
if (isAncestorDeclContextOf(FD, RD)) {
assert(RD->getLexicalDeclContext() == RD->getDeclContext());
return true;
}
if (const auto *RDTempl = dyn_cast<ClassTemplateSpecializationDecl>(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<FunctionProtoType>();
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<RecordType>() : 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<TypedefType>()) {
const TypedefNameDecl *TD = TypedefT->getDecl();
assert(TD);

View file

@ -6319,6 +6319,61 @@ TEST_P(ASTImporterOptionSpecificTestBase,
struct ImportAutoFunctions : ASTImporterOptionSpecificTestBase {};
TEST_P(ImportAutoFunctions, ReturnWithTemplateWithStructDeclaredInside1) {
Decl *FromTU = getTuDecl(
R"(
template<class> struct Tmpl {};
auto foo() {
struct X {};
return Tmpl<X>();
}
)",
Lang_CXX14, "input0.cc");
FunctionDecl *From = FirstDeclMatcher<FunctionDecl>().match(
FromTU, functionDecl(hasName("foo")));
FunctionDecl *To = Import(From, Lang_CXX14);
EXPECT_TRUE(To);
EXPECT_TRUE(isa<AutoType>(To->getReturnType()));
}
TEST_P(ImportAutoFunctions, ReturnWithTemplateWithStructDeclaredInside2) {
Decl *FromTU = getTuDecl(
R"(
template<class> struct Tmpl {};
auto foo() {
struct X {};
return Tmpl<Tmpl<X>>();
}
)",
Lang_CXX14, "input0.cc");
FunctionDecl *From = FirstDeclMatcher<FunctionDecl>().match(
FromTU, functionDecl(hasName("foo")));
FunctionDecl *To = Import(From, Lang_CXX14);
EXPECT_TRUE(To);
EXPECT_TRUE(isa<AutoType>(To->getReturnType()));
}
TEST_P(ImportAutoFunctions, ReturnWithTemplateWithTypedefDeclaredInside) {
Decl *FromTU = getTuDecl(
R"(
template<class> struct Tmpl {};
auto foo() {
struct X {};
using x_type = X;
return Tmpl<x_type>();
}
)",
Lang_CXX14, "input0.cc");
FunctionDecl *From = FirstDeclMatcher<FunctionDecl>().match(
FromTU, functionDecl(hasName("foo")));
FunctionDecl *To = Import(From, Lang_CXX14);
EXPECT_TRUE(To);
EXPECT_TRUE(isa<AutoType>(To->getReturnType()));
}
TEST_P(ImportAutoFunctions, ReturnWithTypedefDeclaredInside) {
Decl *FromTU = getTuDecl(
R"(