diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -463,12 +463,12 @@ else if (isa(*D) && cast(*D)->hasBody()) Terminator = nullptr; else if (auto FD = dyn_cast(*D)) { - if (FD->isThisDeclarationADefinition()) + if (FD->doesThisDeclarationHaveABody() && !FD->isDefaulted()) Terminator = nullptr; else Terminator = ";"; } else if (auto TD = dyn_cast(*D)) { - if (TD->getTemplatedDecl()->isThisDeclarationADefinition()) + if (TD->getTemplatedDecl()->doesThisDeclarationHaveABody()) Terminator = nullptr; else Terminator = ";"; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -3267,42 +3267,74 @@ continue; } - Decl *NewMember = Instantiator.Visit(Member); - if (NewMember) { - if (FieldDecl *Field = dyn_cast(NewMember)) { - Fields.push_back(Field); - } else if (EnumDecl *Enum = dyn_cast(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(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(Member); + Field && isa(Field->getType().getTypePtr())) { + QualType PatternType = Field->getType() + ->castAs() + ->getPattern(); + std::optional 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(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(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(NewMember)) { + Fields.push_back(Field); + } else if (EnumDecl *Enum = dyn_cast(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(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(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. + } } } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/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,7 @@ ? 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 +5956,6 @@ case DeclaratorContext::CXXNew: case DeclaratorContext::AliasDecl: case DeclaratorContext::AliasTemplate: - case DeclaratorContext::Member: case DeclaratorContext::Block: case DeclaratorContext::ForInit: case DeclaratorContext::SelectionInit: diff --git a/clang/test/AST/ast-print-method-decl.cpp b/clang/test/AST/ast-print-method-decl.cpp --- a/clang/test/AST/ast-print-method-decl.cpp +++ b/clang/test/AST/ast-print-method-decl.cpp @@ -85,3 +85,18 @@ // CHECK-NEXT: }; }; + + +// CHECK: struct DefMethodsWithoutBody { +struct DefMethodsWithoutBody { + // CHECK-NEXT: DefMethodsWithoutBody() = delete; + DefMethodsWithoutBody() = delete; + + // CHECK-NEXT: DefMethodsWithoutBody() = default; + ~DefMethodsWithoutBody() = default; + + // CHECK-NEXT: void m1() __attribute__((alias("X"))); + void m1() __attribute__((alias("X"))); + + // CHECK-NEXT: }; +}; diff --git a/clang/test/CodeGenCXX/data_member_packs.cpp b/clang/test/CodeGenCXX/data_member_packs.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/data_member_packs.cpp @@ -0,0 +1,29 @@ +// 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 struct S1 { + Ts... ts; +}; + +template struct S2 { + T t[2]; + Ts... ts; +}; + +// CHECK: %struct.S1 = type { i32 } +S1 s1; +// CHECK-NEXT: %struct.S1.0 = type { i32, float, double } +S1 s2; +// Test template args as the last arg. +// CHECK-NEXT: %struct.S2 = type { [2 x i32], float, double } +S2 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> 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 s6;