[clang] acd80a2 - [clang][ASTImporter] Improved handling of functions with auto return type.
Balázs Kéri via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 25 01:28:32 PDT 2022
Author: Balázs Kéri
Date: 2022-07-25T10:28:01+02:00
New Revision: acd80a29ae7dcffabcb41e8579ebf4f371f0ddd7
URL: https://github.com/llvm/llvm-project/commit/acd80a29ae7dcffabcb41e8579ebf4f371f0ddd7
DIFF: https://github.com/llvm/llvm-project/commit/acd80a29ae7dcffabcb41e8579ebf4f371f0ddd7.diff
LOG: [clang][ASTImporter] Improved handling of functions with auto return type.
Avoid a crash if a function is imported that has auto return type that
references to a template with an expression-type of argument that
references into the function's body.
Fixes issue #56047
Reviewed By: martong
Differential Revision: https://reviews.llvm.org/D129640
Added:
Modified:
clang/lib/AST/ASTImporter.cpp
clang/unittests/AST/ASTImporterTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index f7e7b73d12189..0273e50683716 100644
--- 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"
@@ -3219,9 +3220,12 @@ Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD,
}
// 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<DeclContext>(D);
+ if (!DCi)
+ DCi = D->getDeclContext();
+ assert(DCi && "Declaration should have a context");
while (DCi != D->getTranslationUnitDecl()) {
if (DCi == DC)
return true;
@@ -3230,9 +3234,36 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
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<Decl>())
+ 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<RecordType>()) {
const RecordDecl *RD = RecordT->getDecl();
assert(RD);
@@ -3241,12 +3272,15 @@ static bool hasTypeDeclaredInsideFunction(QualType T, const FunctionDecl *FD) {
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);
- });
+ 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<TemplateSpecializationType>())
+ return llvm::count_if(TST->template_arguments(), CheckTemplateArgument);
+
return false;
}
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index d0edbcb40ab8e..dc289dfc109b8 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -6320,6 +6320,24 @@ TEST_P(ASTImporterOptionSpecificTestBase,
struct ImportAutoFunctions : ASTImporterOptionSpecificTestBase {};
+TEST_P(ImportAutoFunctions, ReturnWithTemplateWithIntegerArgDeclaredInside) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ template<int> struct Tmpl {};
+ auto foo() {
+ constexpr int X = 1;
+ 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, ReturnWithTemplateWithStructDeclaredInside1) {
Decl *FromTU = getTuDecl(
R"(
More information about the cfe-commits
mailing list