Skip to content

Commit

Permalink
[ASTImporter] Fix infinite recurse on return type declared inside body (
Browse files Browse the repository at this point in the history
#68775)

Lambda without trailing auto could have return type declared inside the
body too.

Fixes #68775
  • Loading branch information
danix800 committed Apr 20, 2024
1 parent 30257dd commit 0ccdd4c
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 5 deletions.
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,9 @@ Bug Fixes to AST Handling
Miscellaneous Bug Fixes
^^^^^^^^^^^^^^^^^^^^^^^

- Fixed an infinite recursion in ASTImporter, on return type declared inside
body of C++11 lambda without trailing return (#GH68775).

Miscellaneous Clang Crashes Fixed
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
23 changes: 18 additions & 5 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ namespace clang {
// Returns true if the given function has a placeholder return type and
// that type is declared inside the body of the function.
// E.g. auto f() { struct X{}; return X(); }
bool hasAutoReturnTypeDeclaredInside(FunctionDecl *D);
bool hasReturnTypeDeclaredInside(FunctionDecl *D);
};

template <typename InContainerTy>
Expand Down Expand Up @@ -3647,15 +3647,28 @@ class IsTypeDeclaredInsideVisitor
};
} // namespace

/// This function checks if the function has 'auto' return type that contains
/// This function checks if the given function has a return type that contains
/// a reference (in any way) to a declaration inside the same function.
bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
bool ASTNodeImporter::hasReturnTypeDeclaredInside(FunctionDecl *D) {
QualType FromTy = D->getType();
const auto *FromFPT = FromTy->getAs<FunctionProtoType>();
assert(FromFPT && "Must be called on FunctionProtoType");

auto IsCXX11LambdaWithouTrailingReturn = [&]() {
if (Importer.FromContext.getLangOpts().CPlusPlus14) // C++14 or later
return false;

if (FromFPT->hasTrailingReturn())
return false;

if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
return cast<CXXRecordDecl>(MD->getDeclContext())->isLambda();

return false;
};

QualType RetT = FromFPT->getReturnType();
if (isa<AutoType>(RetT.getTypePtr())) {
if (isa<AutoType>(RetT.getTypePtr()) || IsCXX11LambdaWithouTrailingReturn()) {
FunctionDecl *Def = D->getDefinition();
IsTypeDeclaredInsideVisitor Visitor(Def ? Def : D);
return Visitor.CheckType(RetT);
Expand Down Expand Up @@ -3811,7 +3824,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// E.g.: auto foo() { struct X{}; return X(); }
// To avoid an infinite recursion when importing, create the FunctionDecl
// with a simplified return type.
if (hasAutoReturnTypeDeclaredInside(D)) {
if (hasReturnTypeDeclaredInside(D)) {
FromReturnTy = Importer.getFromContext().VoidTy;
UsedDifferentProtoType = true;
}
Expand Down
17 changes: 17 additions & 0 deletions clang/unittests/AST/ASTImporterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6721,6 +6721,23 @@ TEST_P(ASTImporterOptionSpecificTestBase, LambdaInFunctionBody) {
EXPECT_FALSE(FromL->isDependentLambda());
}

TEST_P(ASTImporterOptionSpecificTestBase,
ReturnTypeDeclaredInsideOfCXX11LambdaWithoutTrailingReturn) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
R"(
void foo() {
(void) []() {
struct X {};
return X();
};
}
)",
Lang_CXX11, "", Lang_CXX11, "foo"); // c++11 only
auto *ToLambda = FirstDeclMatcher<LambdaExpr>().match(To, lambdaExpr());
EXPECT_TRUE(ToLambda);
}

TEST_P(ASTImporterOptionSpecificTestBase, LambdaInFunctionParam) {
Decl *FromTU = getTuDecl(
R"(
Expand Down

0 comments on commit 0ccdd4c

Please sign in to comment.