[clang] [clang][ASTImporter] New fix for default template parameter values. (PR #101836)

Balázs Kéri via cfe-commits cfe-commits at lists.llvm.org
Sat Aug 3 09:18:48 PDT 2024


https://github.com/balazske created https://github.com/llvm/llvm-project/pull/101836

Commit e4440b8 added a change that introduced new crash in an incorrectly handled case. This is fixed here.

>From 2e98fc222566c5e746ade4ccaba23de3b59e0a5d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.keri at ericsson.com>
Date: Sat, 3 Aug 2024 18:10:34 +0200
Subject: [PATCH] [clang][ASTImporter] New fix for default template parameter
 values.

Commit e4440b8 added a change that introduced new crash in an
incorrectly handled case. This is fixed here.
---
 clang/lib/AST/ASTImporter.cpp           | 12 ++-
 clang/unittests/AST/ASTImporterTest.cpp | 97 +++++++++++++++++++++++++
 2 files changed, 106 insertions(+), 3 deletions(-)

diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 103235547f482..7e4a92ccbe40f 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -5972,7 +5972,11 @@ ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
         import(D->getDefaultArgument());
     if (!ToDefaultArgOrErr)
       return ToDefaultArgOrErr.takeError();
-    ToD->setDefaultArgument(ToD->getASTContext(), *ToDefaultArgOrErr);
+    // The import process can trigger import of the parent template which can
+    // set the default argument value (to "inherited").
+    // In this case do nothing here.
+    if (!ToD->hasDefaultArgument())
+      ToD->setDefaultArgument(ToD->getASTContext(), *ToDefaultArgOrErr);
   }
 
   return ToD;
@@ -6004,7 +6008,8 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
         import(D->getDefaultArgument());
     if (!ToDefaultArgOrErr)
       return ToDefaultArgOrErr.takeError();
-    ToD->setDefaultArgument(Importer.getToContext(), *ToDefaultArgOrErr);
+    if (!ToD->hasDefaultArgument())
+      ToD->setDefaultArgument(Importer.getToContext(), *ToDefaultArgOrErr);
   }
 
   return ToD;
@@ -6041,7 +6046,8 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
         import(D->getDefaultArgument());
     if (!ToDefaultArgOrErr)
       return ToDefaultArgOrErr.takeError();
-    ToD->setDefaultArgument(Importer.getToContext(), *ToDefaultArgOrErr);
+    if (!ToD->hasDefaultArgument())
+      ToD->setDefaultArgument(Importer.getToContext(), *ToDefaultArgOrErr);
   }
 
   return ToD;
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 57242ff49fe3b..4c41171deec46 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -9919,6 +9919,103 @@ TEST_P(ImportTemplateParmDeclDefaultValue, ImportExistingVarTemplate) {
   testImport(FromLastD);
 }
 
+TEST_P(ImportTemplateParmDeclDefaultValue,
+       ImportParentTemplateDuringNonTypeTemplateParmDecl) {
+  // This wants to provoke that during import of 'Y' in "typename T = Y"
+  // (before this import returns) the later definition of 'X' is imported fully.
+  const char *Code =
+      R"(
+      struct Z;
+
+      struct Y {
+        Z *z;
+        static const int x = 1;
+      };
+
+      template <int P = Y::x>
+      struct X;
+
+      template <int P>
+      struct X {
+        static const int A = 1;
+      };
+
+      struct Z {
+        template<int P>
+        void f(int A = X<P>::A);
+      };
+      )";
+
+  Decl *FromTU = getTuDecl(Code, Lang_CXX14);
+  auto *FromD = FirstDeclMatcher<NonTypeTemplateParmDecl>().match(
+      FromTU, nonTypeTemplateParmDecl(hasName("P")));
+  auto *ToD = Import(FromD, Lang_CXX14);
+  EXPECT_TRUE(ToD);
+}
+
+TEST_P(ImportTemplateParmDeclDefaultValue,
+       ImportParentTemplateDuringTemplateTypeParmDecl) {
+  const char *Code =
+      R"(
+      struct Z;
+
+      struct Y {
+        Z *z;
+      };
+
+      template <typename T = Y>
+      struct X;
+
+      template <typename T>
+      struct X {
+        static const int A = 1;
+      };
+
+      struct Z {
+        template<typename T>
+        void f(int A = X<T>::A);
+      };
+      )";
+
+  Decl *FromTU = getTuDecl(Code, Lang_CXX14);
+  auto *FromD = FirstDeclMatcher<TemplateTypeParmDecl>().match(
+      FromTU, templateTypeParmDecl(hasName("T")));
+  auto *ToD = Import(FromD, Lang_CXX14);
+  EXPECT_TRUE(ToD);
+}
+
+TEST_P(ImportTemplateParmDeclDefaultValue,
+       ImportParentTemplateDuringTemplateTemplateParmDecl) {
+  const char *Code =
+      R"(
+      struct Z;
+
+      template <int>
+      struct Y {
+        Z *z;
+      };
+
+      template <template <int> class T = Y>
+      struct X;
+
+      template <template <int> class T>
+      struct X {
+        static const int A = 1;
+      };
+
+      struct Z {
+        template <template <int> class T>
+        void f(int A = X<T>::A);
+      };
+      )";
+
+  Decl *FromTU = getTuDecl(Code, Lang_CXX14);
+  auto *FromD = FirstDeclMatcher<TemplateTemplateParmDecl>().match(
+      FromTU, templateTemplateParmDecl(hasName("T")));
+  auto *ToD = Import(FromD, Lang_CXX14);
+  EXPECT_TRUE(ToD);
+}
+
 INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest,
                          DefaultTestValuesForRunOptions);
 



More information about the cfe-commits mailing list