[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