SlaterLatiao created this revision. Herald added a project: All. SlaterLatiao requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D156546 Files: clang/lib/Sema/SemaTemplateInstantiate.cpp clang/lib/Sema/SemaType.cpp clang/test/CodeGenCXX/packed_data_member.cpp
Index: clang/test/CodeGenCXX/packed_data_member.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/packed_data_member.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 --std=c++20 %s -emit-llvm -o - -triple x86_64-linux | FileCheck %s --check-prefixes=CHECK + +// Tests declaration of packed data members. +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; \ No newline at end of file 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 @@ -5944,7 +5946,6 @@ ? diag::warn_cxx98_compat_variadic_templates : diag::ext_variadic_templates); break; - case DeclaratorContext::File: case DeclaratorContext::KNRTypeList: case DeclaratorContext::ObjCParameter: // FIXME: special diagnostic here? @@ -5954,7 +5955,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,75 @@ 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. + Decl *NewMember = Instantiator.Visit(Member); + if (NewMember) { + FieldDecl *PackedField = dyn_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