SlaterLatiao updated this revision to Diff 545297.
SlaterLatiao added a comment.

Address comments.

- Added test case of duplicate types in template arguments.
- Added ending new line to test case file.
- Renamed "packed data members" -> "data member packs"


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156546/new/

https://reviews.llvm.org/D156546

Files:
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/CodeGenCXX/data_member_packs.cpp

Index: clang/test/CodeGenCXX/data_member_packs.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/data_member_packs.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 --std=c++20 %s -emit-llvm -o - -triple x86_64-linux | FileCheck %s --check-prefixes=CHECK
+
+// Tests declaration data member packs.
+template<typename... Ts> struct S1 {
+    Ts... ts;
+};
+
+template<typename T, typename... Ts> struct S2 {
+    T t[2];
+    Ts... ts;
+};
+
+// CHECK: %struct.S1 = type { i32 }
+S1<int> s1;
+// CHECK-NEXT: %struct.S1.0 = type { i32, float, double }
+S1<int, float, double> s2;
+// Test template args as the last arg.
+// CHECK-NEXT: %struct.S2 = type { [2 x i32], float, double }
+S2<int, float, double> s3;
+// Test nested template args.
+// CHECK-NEXT: %struct.S1.1 = type { i32, float, %struct.S1.2 }
+// CHECK-NEXT: %struct.S1.2 = type { double, double }
+S1<int, float, S1<double, double>> s4;
+// Test empty template arg.
+// CHECK-NEXT: %struct.S1.3 = type { i8 }
+S1<> s5;
+// Test duplicate types in template args.
+// CHECK-NEXT: %struct.S1.4 = type { i32, i32 }
+S1<int, int> s6;
+
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -5927,6 +5927,8 @@
                                          /*ExpectPackInType=*/false);
       }
       break;
+    case DeclaratorContext::Member:
+      // Expand for packed data members.
     case DeclaratorContext::TemplateParam:
       // C++0x [temp.param]p15:
       //   If a template-parameter is a [...] is a parameter-declaration that
@@ -5954,7 +5956,6 @@
     case DeclaratorContext::CXXNew:
     case DeclaratorContext::AliasDecl:
     case DeclaratorContext::AliasTemplate:
-    case DeclaratorContext::Member:
     case DeclaratorContext::Block:
     case DeclaratorContext::ForInit:
     case DeclaratorContext::SelectionInit:
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3267,42 +3267,74 @@
       continue;
     }
 
-    Decl *NewMember = Instantiator.Visit(Member);
-    if (NewMember) {
-      if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) {
-        Fields.push_back(Field);
-      } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(NewMember)) {
-        // C++11 [temp.inst]p1: The implicit instantiation of a class template
-        // specialization causes the implicit instantiation of the definitions
-        // of unscoped member enumerations.
-        // Record a point of instantiation for this implicit instantiation.
-        if (TSK == TSK_ImplicitInstantiation && !Enum->isScoped() &&
-            Enum->isCompleteDefinition()) {
-          MemberSpecializationInfo *MSInfo =Enum->getMemberSpecializationInfo();
-          assert(MSInfo && "no spec info for member enum specialization");
-          MSInfo->setTemplateSpecializationKind(TSK_ImplicitInstantiation);
-          MSInfo->setPointOfInstantiation(PointOfInstantiation);
-        }
-      } else if (StaticAssertDecl *SA = dyn_cast<StaticAssertDecl>(NewMember)) {
-        if (SA->isFailed()) {
-          // A static_assert failed. Bail out; instantiating this
-          // class is probably not meaningful.
-          Instantiation->setInvalidDecl();
-          break;
+    // Instantiate packed data members.
+    if (FieldDecl *Field = dyn_cast<FieldDecl>(Member);
+        Field && isa<PackExpansionType>(Field->getType().getTypePtr())) {
+      QualType PatternType = Field->getType()
+                                 ->castAs<PackExpansionType>()
+                                 ->getPattern();
+      std::optional<unsigned> NumArgumentsInExpansion =
+          getNumArgumentsInExpansion(Field->getType(), TemplateArgs);
+      assert(NumArgumentsInExpansion && "should not see unknown template argument here");
+      for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) {
+        // Generate a new field from PackExpansion field.
+        if (Decl *NewMember = Instantiator.Visit(Member)) {
+          FieldDecl *PackedField = cast<FieldDecl>(NewMember);
+          Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, Arg);
+          QualType T =
+              SubstType(PatternType, TemplateArgs, PackedField->getLocation(),
+                        PackedField->getDeclName());
+          PackedField->setType(T);
+          Fields.push_back(PackedField);
+          if (NewMember->isInvalidDecl())
+            Instantiation->setInvalidDecl();
+        } else {
+          // FIXME: Eventually, a NULL return will mean that one of the
+          // instantiations was a semantic disaster, and we'll want to mark
+          // the declaration invalid. For now, we expect to skip some members
+          // that we can't yet handle.
         }
-      } else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewMember)) {
-        if (MD->isConstexpr() && !MD->getFriendObjectKind() &&
-            (MD->isVirtualAsWritten() || Instantiation->getNumBases()))
-          MightHaveConstexprVirtualFunctions = true;
       }
-
-      if (NewMember->isInvalidDecl())
-        Instantiation->setInvalidDecl();
     } else {
-      // FIXME: Eventually, a NULL return will mean that one of the
-      // instantiations was a semantic disaster, and we'll want to mark the
-      // declaration invalid.
-      // For now, we expect to skip some members that we can't yet handle.
+      Decl *NewMember = Instantiator.Visit(Member);
+      if (NewMember) {
+        if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) {
+          Fields.push_back(Field);
+        } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(NewMember)) {
+          // C++11 [temp.inst]p1: The implicit instantiation of a class template
+          // specialization causes the implicit instantiation of the definitions
+          // of unscoped member enumerations.
+          // Record a point of instantiation for this implicit instantiation.
+          if (TSK == TSK_ImplicitInstantiation && !Enum->isScoped() &&
+              Enum->isCompleteDefinition()) {
+            MemberSpecializationInfo *MSInfo =
+                Enum->getMemberSpecializationInfo();
+            assert(MSInfo && "no spec info for member enum specialization");
+            MSInfo->setTemplateSpecializationKind(TSK_ImplicitInstantiation);
+            MSInfo->setPointOfInstantiation(PointOfInstantiation);
+          }
+        } else if (StaticAssertDecl *SA =
+                       dyn_cast<StaticAssertDecl>(NewMember)) {
+          if (SA->isFailed()) {
+            // A static_assert failed. Bail out; instantiating this
+            // class is probably not meaningful.
+            Instantiation->setInvalidDecl();
+            break;
+          }
+        } else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewMember)) {
+          if (MD->isConstexpr() && !MD->getFriendObjectKind() &&
+              (MD->isVirtualAsWritten() || Instantiation->getNumBases()))
+            MightHaveConstexprVirtualFunctions = true;
+        }
+
+        if (NewMember->isInvalidDecl())
+          Instantiation->setInvalidDecl();
+      } else {
+        // FIXME: Eventually, a NULL return will mean that one of the
+        // instantiations was a semantic disaster, and we'll want to mark the
+        // declaration invalid.
+        // For now, we expect to skip some members that we can't yet handle.
+      }
     }
   }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to