Author: Roy Jacobson Date: 2022-08-25T09:11:06+03:00 New Revision: 70770a16bcfa70b2a4b38d55ab8097f9f92c2326
URL: https://github.com/llvm/llvm-project/commit/70770a16bcfa70b2a4b38d55ab8097f9f92c2326 DIFF: https://github.com/llvm/llvm-project/commit/70770a16bcfa70b2a4b38d55ab8097f9f92c2326.diff LOG: Revert "[Clang] Implement P0848 (Conditionally Trivial Special Member Functions)" See bug report here: https://github.com/llvm/llvm-project/issues/57351 This reverts commit 7171615099142ed49042c0f27af437b05150dd9b. Added: Modified: clang/docs/ReleaseNotes.rst clang/lib/AST/DeclCXX.cpp clang/lib/Frontend/InitPreprocessor.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/www/cxx_status.html Removed: clang/test/AST/conditionally-trivial-smfs.cpp clang/test/SemaCXX/constrained-special-member-functions.cpp ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 6109f4e8ac6bc..46339ff9ce8d1 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -167,10 +167,6 @@ C++20 Feature Support (C++14 [dcl.constexpr]p6 (CWG DR647/CWG DR1358)) - Correctly defer dependent immediate function invocations until template instantiation. This fixes `GH55601 <https://github.com/llvm/llvm-project/issues/55601>`_. -- Implemented "Conditionally Trivial Special Member Functions" (`P0848 <https://wg21.link/p0848r3>`_). - Note: The handling of deleted functions is not yet compliant, as Clang - does not implement `DR1496 <https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1496>`_ - and `DR1734 <https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1734>`_. diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 4e259df1b95e1..38c46b112b803 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -894,11 +894,9 @@ void CXXRecordDecl::addedMember(Decl *D) { // This is an extension in C++03. data().PlainOldData = false; } - // When instantiating a class, we delay updating the destructor and - // triviality properties of the class until selecting a destructor and - // computing the eligibility of its special member functions. This is - // because there might be function constraints that we need to evaluate - // and compare later in the instantiation. + // We delay updating destructor relevant properties until + // addedSelectedDestructor. + // FIXME: Defer this for the other special member functions as well. if (!Method->isIneligibleOrNotSelected()) { addedEligibleSpecialMemberFunction(Method, SMKind); } @@ -1439,12 +1437,10 @@ void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) { // Update which trivial / non-trivial special members we have. // addedMember will have skipped this step for this member. - if (!D->isIneligibleOrNotSelected()) { - if (D->isTrivial()) - data().HasTrivialSpecialMembers |= SMKind; - else - data().DeclaredNonTrivialSpecialMembers |= SMKind; - } + if (D->isTrivial()) + data().HasTrivialSpecialMembers |= SMKind; + else + data().DeclaredNonTrivialSpecialMembers |= SMKind; } void CXXRecordDecl::setCaptures(ASTContext &Context, diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index eff811e113e5e..20bfbf144a30a 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -674,9 +674,6 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, // C++20 features. if (LangOpts.CPlusPlus20) { //Builder.defineMacro("__cpp_aggregate_paren_init", "201902L"); - // P0848 is implemented, but we're still waiting for other concepts - // issues to be addressed before bumping __cpp_concepts up to 202002L. - // Refer to the discussion of this at https://reviews.llvm.org/D128619. Builder.defineMacro("__cpp_concepts", "201907L"); Builder.defineMacro("__cpp_conditional_explicit", "201806L"); //Builder.defineMacro("__cpp_consteval", "201811L"); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index ef59ecebb70ac..88939597c454b 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -17968,6 +17968,7 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, AllIvarDecls.push_back(Ivar); } +namespace { /// [class.dtor]p4: /// At the end of the definition of a class, overload resolution is /// performed among the prospective destructors declared in that class with @@ -17976,7 +17977,7 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, /// /// We do the overload resolution here, then mark the selected constructor in the AST. /// Later CXXRecordDecl::getDestructor() will return the selected constructor. -static void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) { +void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) { if (!Record->hasUserDeclaredDestructor()) { return; } @@ -18034,130 +18035,7 @@ static void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) { Record->addedSelectedDestructor(dyn_cast<CXXDestructorDecl>(OCS.begin()->Function)); } } - -/// [class.mem.special]p5 -/// Two special member functions are of the same kind if: -/// - they are both default constructors, -/// - they are both copy or move constructors with the same first parameter -/// type, or -/// - they are both copy or move assignment operators with the same first -/// parameter type and the same cv-qualifiers and ref-qualifier, if any. -static bool AreSpecialMemberFunctionsSameKind(ASTContext &Context, - CXXMethodDecl *M1, - CXXMethodDecl *M2, - Sema::CXXSpecialMember CSM) { - if (CSM == Sema::CXXDefaultConstructor) - return true; - if (!Context.hasSameType(M1->getParamDecl(0)->getType(), - M2->getParamDecl(0)->getType())) - return false; - if (!Context.hasSameType(M1->getThisType(), M2->getThisType())) - return false; - - return true; -} - -/// [class.mem.special]p6: -/// An eligible special member function is a special member function for which: -/// - the function is not deleted, -/// - the associated constraints, if any, are satisfied, and -/// - no special member function of the same kind whose associated constraints -/// [CWG2595], if any, are satisfied is more constrained. -static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record, - ArrayRef<CXXMethodDecl *> Methods, - Sema::CXXSpecialMember CSM) { - SmallVector<bool, 4> SatisfactionStatus; - - for (CXXMethodDecl *Method : Methods) { - const Expr *Constraints = Method->getTrailingRequiresClause(); - if (!Constraints) - SatisfactionStatus.push_back(true); - else { - ConstraintSatisfaction Satisfaction; - if (S.CheckFunctionConstraints(Method, Satisfaction)) - SatisfactionStatus.push_back(false); - else - SatisfactionStatus.push_back(Satisfaction.IsSatisfied); - } - } - - for (size_t i = 0; i < Methods.size(); i++) { - if (!SatisfactionStatus[i]) - continue; - CXXMethodDecl *Method = Methods[i]; - const Expr *Constraints = Method->getTrailingRequiresClause(); - bool AnotherMethodIsMoreConstrained = false; - for (size_t j = 0; j < Methods.size(); j++) { - if (i == j || !SatisfactionStatus[j]) - continue; - CXXMethodDecl *OtherMethod = Methods[j]; - if (!AreSpecialMemberFunctionsSameKind(S.Context, Method, OtherMethod, - CSM)) - continue; - - const Expr *OtherConstraints = OtherMethod->getTrailingRequiresClause(); - if (!OtherConstraints) - continue; - if (!Constraints) { - AnotherMethodIsMoreConstrained = true; - break; - } - if (S.IsAtLeastAsConstrained(OtherMethod, {OtherConstraints}, Method, - {Constraints}, - AnotherMethodIsMoreConstrained)) { - // There was an error with the constraints comparison. Exit the loop - // and don't consider this function eligible. - AnotherMethodIsMoreConstrained = true; - } - if (AnotherMethodIsMoreConstrained) - break; - } - // FIXME: Do not consider deleted methods as eligible after implementing - // DR1734 and DR1496. - if (!AnotherMethodIsMoreConstrained) { - Method->setIneligibleOrNotSelected(false); - Record->addedEligibleSpecialMemberFunction(Method, 1 << CSM); - } - } -} - -static void ComputeSpecialMemberFunctionsEligiblity(Sema &S, - CXXRecordDecl *Record) { - SmallVector<CXXMethodDecl *, 4> DefaultConstructors; - SmallVector<CXXMethodDecl *, 4> CopyConstructors; - SmallVector<CXXMethodDecl *, 4> MoveConstructors; - SmallVector<CXXMethodDecl *, 4> CopyAssignmentOperators; - SmallVector<CXXMethodDecl *, 4> MoveAssignmentOperators; - - for (auto *Decl : Record->decls()) { - auto *MD = dyn_cast<CXXMethodDecl>(Decl); - if (!MD) - continue; - if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) { - if (CD->isInvalidDecl()) - continue; - if (CD->isDefaultConstructor()) - DefaultConstructors.push_back(MD); - else if (CD->isCopyConstructor()) - CopyConstructors.push_back(MD); - else if (CD->isMoveConstructor()) - MoveConstructors.push_back(MD); - } else if (MD->isCopyAssignmentOperator()) { - CopyAssignmentOperators.push_back(MD); - } else if (MD->isMoveAssignmentOperator()) { - MoveAssignmentOperators.push_back(MD); - } - } - - SetEligibleMethods(S, Record, DefaultConstructors, - Sema::CXXDefaultConstructor); - SetEligibleMethods(S, Record, CopyConstructors, Sema::CXXCopyConstructor); - SetEligibleMethods(S, Record, MoveConstructors, Sema::CXXMoveConstructor); - SetEligibleMethods(S, Record, CopyAssignmentOperators, - Sema::CXXCopyAssignment); - SetEligibleMethods(S, Record, MoveAssignmentOperators, - Sema::CXXMoveAssignment); -} +} // namespace void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, ArrayRef<Decl *> Fields, SourceLocation LBrac, @@ -18185,6 +18063,9 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl); CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(EnclosingDecl); + if (CXXRecord && !CXXRecord->isDependentType()) + ComputeSelectedDestructor(*this, CXXRecord); + // Start counting up the number of named members; make sure to include // members of anonymous structs and unions in the total. unsigned NumNamedMembers = 0; @@ -18470,8 +18351,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, Completed = true; } } - ComputeSelectedDestructor(*this, CXXRecord); - ComputeSpecialMemberFunctionsEligiblity(*this, CXXRecord); } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 198de680ae3d4..9ab009488c955 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6618,7 +6618,7 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false; bool DtorIsTrivialForCall = false; - // If a class has at least one eligible, trivial copy constructor, it + // If a class has at least one non-deleted, trivial copy constructor, it // is passed according to the C ABI. Otherwise, it is passed indirectly. // // Note: This permits classes with non-trivial copy or move ctors to be @@ -6633,8 +6633,7 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, } } else { for (const CXXConstructorDecl *CD : D->ctors()) { - if (CD->isCopyConstructor() && !CD->isDeleted() && - !CD->isIneligibleOrNotSelected()) { + if (CD->isCopyConstructor() && !CD->isDeleted()) { if (CD->isTrivial()) CopyCtorIsTrivial = true; if (CD->isTrivialForCall()) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 24ea3254cb272..cce054d11dc8b 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2481,9 +2481,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( Constructor->getConstexprKind(), InheritedConstructor(), TrailingRequiresClause); Method->setRangeEnd(Constructor->getEndLoc()); - if (Constructor->isDefaultConstructor() || - Constructor->isCopyOrMoveConstructor()) - Method->setIneligibleOrNotSelected(true); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -2506,8 +2503,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, SC, D->UsesFPIntrin(), D->isInlineSpecified(), D->getConstexprKind(), D->getEndLoc(), TrailingRequiresClause); - if (D->isMoveAssignmentOperator() || D->isCopyAssignmentOperator()) - Method->setIneligibleOrNotSelected(true); } if (D->isInlined()) diff --git a/clang/test/AST/conditionally-trivial-smfs.cpp b/clang/test/AST/conditionally-trivial-smfs.cpp deleted file mode 100644 index 34db1cd8d3611..0000000000000 --- a/clang/test/AST/conditionally-trivial-smfs.cpp +++ /dev/null @@ -1,343 +0,0 @@ -// RUN: %clang_cc1 -std=c++20 -triple x86_64-pc-linux -ast-dump=json %s | FileCheck %s --check-prefixes=CHECK,LIN -// RUN: %clang_cc1 -std=c++20 -triple x86_64-pc-win32 -ast-dump=json %s | FileCheck %s - -// This test validates that we compute correct AST properties of classes with -// conditionally trivial special member functions. - -template <int N> -struct DefaultConstructorCheck { - DefaultConstructorCheck() requires(N == 1) = default; - DefaultConstructorCheck() requires(N == 2) = delete; - DefaultConstructorCheck() requires(N == 3); - DefaultConstructorCheck(); -}; - - -template struct DefaultConstructorCheck<1>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "canPassInRegisters": true, -// CHECK-NEXT: "copyAssign": { - -// CHECK: "defaultCtor": { -// CHECK-NEXT: "defaultedIsConstexpr": true, -// CHECK-NEXT: "exists": true, -// CHECK-NEXT: "isConstexpr": true, -// CHECK-NEXT: "trivial": true, -// CHECK-NEXT: "userProvided": true -// CHECK-NEXT: }, - -// CHECK: "hasConstexprNonCopyMoveConstructor": true, -// CHECK-NEXT: "hasUserDeclaredConstructor": true, -// CHECK-NEXT: "isEmpty": true, -// CHECK-NEXT: "isLiteral": true, -// CHECK-NEXT: "isStandardLayout": true, -// CHECK-NEXT: "isTrivial": true, -// CHECK-NEXT: "isTriviallyCopyable": true, - -template struct DefaultConstructorCheck<2>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "canPassInRegisters": true, -// CHECK-NEXT: "copyAssign": { - -// CHECK: "defaultCtor": { -// CHECK-NEXT: "defaultedIsConstexpr": true, -// CHECK-NEXT: "exists": true, -// CHECK-NEXT: "isConstexpr": true, -// CHECK-NEXT: "trivial": true, -// CHECK-NEXT: "userProvided": true -// CHECK-NEXT: }, - -// CHECK: "hasConstexprNonCopyMoveConstructor": true, -// CHECK-NEXT: "hasUserDeclaredConstructor": true, -// CHECK-NEXT: "isEmpty": true, -// CHECK-NEXT: "isLiteral": true, -// CHECK-NEXT: "isStandardLayout": true, -// CHECK-NEXT: "isTrivial": true, -// CHECK-NEXT: "isTriviallyCopyable": true, - - -template struct DefaultConstructorCheck<3>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "canPassInRegisters": true, -// CHECK-NEXT: "copyAssign": { - -// CHECK: "defaultCtor": { -// CHECK-NEXT: "defaultedIsConstexpr": true, -// CHECK-NEXT: "exists": true, -// CHECK-NEXT: "isConstexpr": true, -// CHECK-NEXT: "nonTrivial": true, -// CHECK-NEXT: "userProvided": true -// CHECK-NEXT: }, - -// CHECK: "hasConstexprNonCopyMoveConstructor": true, -// CHECK-NEXT: "hasUserDeclaredConstructor": true, -// CHECK-NEXT: "isEmpty": true, -// CHECK-NEXT: "isLiteral": true, -// CHECK-NEXT: "isStandardLayout": true, -// CHECK-NEXT: "isTriviallyCopyable": true, - -template <int N> -struct CopyConstructorCheck { - CopyConstructorCheck(const CopyConstructorCheck&) requires(N == 1) = default; - CopyConstructorCheck(const CopyConstructorCheck&) requires(N == 2) = delete; - CopyConstructorCheck(const CopyConstructorCheck&) requires(N == 3); - CopyConstructorCheck(const CopyConstructorCheck&); -}; - - -template struct CopyConstructorCheck<1>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "canPassInRegisters": true, -// CHECK-NEXT: "copyAssign": { - -// CHECK: "copyCtor": { -// CHECK-NEXT: "hasConstParam": true, -// CHECK-NEXT: "implicitHasConstParam": true, -// CHECK-NEXT: "trivial": true, -// CHECK-NEXT: "userDeclared": true -// CHECK-NEXT: }, - -// CHECK: "hasUserDeclaredConstructor": true, -// CHECK-NEXT: "isEmpty": true, -// CHECK-NEXT: "isStandardLayout": true, -// CHECK-NEXT: "isTriviallyCopyable": true, -// CHECK-NEXT: "moveAssign": {}, - -template struct CopyConstructorCheck<2>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "copyAssign": { - -// CHECK: "copyCtor": { -// CHECK-NEXT: "hasConstParam": true, -// CHECK-NEXT: "implicitHasConstParam": true, -// CHECK-NEXT: "trivial": true, -// CHECK-NEXT: "userDeclared": true -// CHECK-NEXT: }, - -// CHECK: "hasUserDeclaredConstructor": true, -// CHECK-NEXT: "isEmpty": true, -// CHECK-NEXT: "isStandardLayout": true, -// CHECK-NEXT: "isTriviallyCopyable": true, -// CHECK-NEXT: "moveAssign": {}, - -template struct CopyConstructorCheck<3>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "copyAssign": { - -// CHECK: "copyCtor": { -// CHECK-NEXT: "hasConstParam": true, -// CHECK-NEXT: "implicitHasConstParam": true, -// CHECK-NEXT: "nonTrivial": true, -// CHECK-NEXT: "userDeclared": true -// CHECK-NEXT: }, - -// CHECK: "hasUserDeclaredConstructor": true, -// CHECK-NEXT: "isEmpty": true, -// CHECK-NEXT: "isStandardLayout": true, -// CHECK-NEXT: "moveAssign": {}, - -template <int N> -struct MoveConstructorCheck { - MoveConstructorCheck(MoveConstructorCheck&&) requires(N == 1) = default; - MoveConstructorCheck(MoveConstructorCheck&&) requires(N == 2) = delete; - MoveConstructorCheck(MoveConstructorCheck&&) requires(N == 3); - MoveConstructorCheck(MoveConstructorCheck&&); -}; - - -template struct MoveConstructorCheck<1>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// LIN-NEXT: "canPassInRegisters": true, -// CHECK-NEXT: "copyAssign": { - -// CHECK: "hasUserDeclaredConstructor": true, -// CHECK-NEXT: "isEmpty": true, -// CHECK-NEXT: "isStandardLayout": true, -// CHECK-NEXT: "isTriviallyCopyable": true, -// CHECK-NEXT: "moveAssign": {}, -// CHECK-NEXT: "moveCtor": { -// CHECK-NEXT: "exists": true, -// CHECK-NEXT: "trivial": true, -// CHECK-NEXT: "userDeclared": true -// CHECK-NEXT: } - -template struct MoveConstructorCheck<2>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "copyAssign": { - -// CHECK: "hasUserDeclaredConstructor": true, -// CHECK-NEXT: "isEmpty": true, -// CHECK-NEXT: "isStandardLayout": true, -// CHECK-NEXT: "isTriviallyCopyable": true, -// CHECK-NEXT: "moveAssign": {}, -// CHECK-NEXT: "moveCtor": { -// CHECK-NEXT: "exists": true, -// CHECK-NEXT: "trivial": true, -// CHECK-NEXT: "userDeclared": true -// CHECK-NEXT: } - -template struct MoveConstructorCheck<3>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "copyAssign": { - -// CHECK: "hasUserDeclaredConstructor": true, -// CHECK-NEXT: "isEmpty": true, -// CHECK-NEXT: "isStandardLayout": true, -// CHECK-NEXT: "moveAssign": {}, -// CHECK-NEXT: "moveCtor": { -// CHECK-NEXT: "exists": true, -// CHECK-NEXT: "nonTrivial": true, -// CHECK-NEXT: "userDeclared": true -// CHECK-NEXT: } - -template <int N> -struct CopyAssignmentCheck { - CopyAssignmentCheck& operator=(const CopyAssignmentCheck&) requires(N == 1) = default; - CopyAssignmentCheck& operator=(const CopyAssignmentCheck&) requires(N == 2) = delete; - CopyAssignmentCheck& operator=(const CopyAssignmentCheck&) requires(N == 3); - CopyAssignmentCheck& operator=(const CopyAssignmentCheck&); -}; - - -template struct CopyAssignmentCheck<1>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "canPassInRegisters": true, -// CHECK-NEXT "copyAssign": { -// CHECK-NEXT "hasConstParam": true, -// CHECK-NEXT "implicitHasConstParam": true, -// CHECK-NEXT "trivial": true, -// CHECK-NEXT "userDeclared": true -// CHECK-NEXT }, - -// CHECK: "hasConstexprNonCopyMoveConstructor": true, -// CHECK-NEXT "isAggregate": true, -// CHECK-NEXT "isEmpty": true, -// CHECK-NEXT "isLiteral": true, -// CHECK-NEXT "isStandardLayout": true, -// CHECK-NEXT "isTrivial": true, -// CHECK-NEXT "isTriviallyCopyable": true, -// CHECK-NEXT "moveAssign": {}, - -template struct CopyAssignmentCheck<2>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "canPassInRegisters": true, -// CHECK-NEXT "copyAssign": { -// CHECK-NEXT "hasConstParam": true, -// CHECK-NEXT "implicitHasConstParam": true, -// CHECK-NEXT "trivial": true, -// CHECK-NEXT "userDeclared": true -// CHECK-NEXT }, - -// CHECK: "hasConstexprNonCopyMoveConstructor": true, -// CHECK-NEXT "isAggregate": true, -// CHECK-NEXT "isEmpty": true, -// CHECK-NEXT "isLiteral": true, -// CHECK-NEXT "isStandardLayout": true, -// CHECK-NEXT "isTrivial": true, -// CHECK-NEXT "isTriviallyCopyable": true, -// CHECK-NEXT "moveAssign": {}, - -template struct CopyAssignmentCheck<3>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "canPassInRegisters": true, -// CHECK-NEXT "copyAssign": { -// CHECK-NEXT "hasConstParam": true, -// CHECK-NEXT "implicitHasConstParam": true, -// CHECK-NEXT "trivial": true, -// CHECK-NEXT "userDeclared": true -// CHECK-NEXT }, - -// CHECK: "hasConstexprNonCopyMoveConstructor": true, -// CHECK-NEXT "isAggregate": true, -// CHECK-NEXT "isEmpty": true, -// CHECK-NEXT "isLiteral": true, -// CHECK-NEXT "isStandardLayout": true, -// CHECK-NEXT "moveAssign": {}, - -template <int N> -struct MoveAssignmentCheck { - MoveAssignmentCheck& operator=(MoveAssignmentCheck&&) requires(N == 1) = default; - MoveAssignmentCheck& operator=(MoveAssignmentCheck&&) requires(N == 2) = delete; - MoveAssignmentCheck& operator=(MoveAssignmentCheck&&) requires(N == 3); - MoveAssignmentCheck& operator=(MoveAssignmentCheck&&); -}; - - -template struct MoveAssignmentCheck<1>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "copyAssign": { - -// CHECK: "hasConstexprNonCopyMoveConstructor": true, -// CHECK-NEXT: "isAggregate": true, -// CHECK-NEXT: "isEmpty": true, -// CHECK-NEXT: "isLiteral": true, -// CHECK-NEXT: "isStandardLayout": true, -// CHECK-NEXT: "isTrivial": true, -// CHECK-NEXT: "isTriviallyCopyable": true, -// CHECK-NEXT: "moveAssign": { -// CHECK-NEXT: "exists": true, -// CHECK-NEXT: "trivial": true, -// CHECK-NEXT: "userDeclared": true -// CHECK-NEXT: }, - -template struct MoveAssignmentCheck<2>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "copyAssign": { - -// CHECK: "hasConstexprNonCopyMoveConstructor": true, -// CHECK-NEXT: "isAggregate": true, -// CHECK-NEXT: "isEmpty": true, -// CHECK-NEXT: "isLiteral": true, -// CHECK-NEXT: "isStandardLayout": true, -// CHECK-NEXT: "isTrivial": true, -// CHECK-NEXT: "isTriviallyCopyable": true, -// CHECK-NEXT: "moveAssign": { -// CHECK-NEXT: "exists": true, -// CHECK-NEXT: "trivial": true, -// CHECK-NEXT: "userDeclared": true -// CHECK-NEXT: }, - -template struct MoveAssignmentCheck<3>; -// CHECK: "kind": "ClassTemplateSpecializationDecl", -// CHECK: "definitionData": { -// CHECK-NEXT: "canConstDefaultInit": true, -// CHECK-NEXT: "copyAssign": { - -// CHECK: "hasConstexprNonCopyMoveConstructor": true, -// CHECK-NEXT: "isAggregate": true, -// CHECK-NEXT: "isEmpty": true, -// CHECK-NEXT: "isLiteral": true, -// CHECK-NEXT: "isStandardLayout": true, -// CHECK-NEXT: "moveAssign": { -// CHECK-NEXT: "exists": true, -// CHECK-NEXT: "nonTrivial": true, -// CHECK-NEXT: "userDeclared": true -// CHECK-NEXT: }, diff --git a/clang/test/SemaCXX/constrained-special-member-functions.cpp b/clang/test/SemaCXX/constrained-special-member-functions.cpp deleted file mode 100644 index b3eb2c0eaf5f4..0000000000000 --- a/clang/test/SemaCXX/constrained-special-member-functions.cpp +++ /dev/null @@ -1,231 +0,0 @@ -// RUN: %clang_cc1 -verify -std=c++20 %s - -template <int N> -concept C0 = (N == 0); -template <int N> -concept C1 = (N == 1); -template <int N> -concept C2 = (N == 2); - -// Checks are indexed by: -// Definition: -// 1. Explicitly defaulted definition -// 2. Deleted definition -// 3. User provided definition -// We have a less constrained user provided method that should not disable -// the (copyable) triviality of the type. - -// Note that because Clang does not implement DRs 1496 and 1734, we say some -// classes are trivial when the SMFs are deleted. - -template <int N> -struct DefaultConstructorChecker { - DefaultConstructorChecker() requires C0<N> = default; - DefaultConstructorChecker() requires C1<N> = delete; - DefaultConstructorChecker() requires C2<N>; - DefaultConstructorChecker(); -}; -static_assert(__is_trivially_copyable(DefaultConstructorChecker<0>)); -static_assert(__is_trivially_copyable(DefaultConstructorChecker<1>)); -static_assert(__is_trivially_copyable(DefaultConstructorChecker<2>)); -static_assert(__is_trivially_copyable(DefaultConstructorChecker<3>)); -static_assert(__is_trivial(DefaultConstructorChecker<0>)); -// FIXME: DR1496 -static_assert(__is_trivial(DefaultConstructorChecker<1>)); -static_assert(!__is_trivial(DefaultConstructorChecker<2>)); -static_assert(!__is_trivial(DefaultConstructorChecker<3>)); - -template <int N> -struct CopyConstructorChecker { - CopyConstructorChecker(const CopyConstructorChecker&) requires C0<N> = default; - CopyConstructorChecker(const CopyConstructorChecker&) requires C1<N> = delete; - CopyConstructorChecker(const CopyConstructorChecker&) requires C2<N>; - CopyConstructorChecker(const CopyConstructorChecker&); -}; - -static_assert(__is_trivially_copyable(CopyConstructorChecker<0>)); -// FIXME: DR1734 -static_assert(__is_trivially_copyable(CopyConstructorChecker<1>)); -static_assert(!__is_trivially_copyable(CopyConstructorChecker<2>)); -static_assert(!__is_trivially_copyable(CopyConstructorChecker<3>)); -static_assert(!__is_trivial(CopyConstructorChecker<0>)); -static_assert(!__is_trivial(CopyConstructorChecker<1>)); -static_assert(!__is_trivial(CopyConstructorChecker<2>)); -static_assert(!__is_trivial(CopyConstructorChecker<3>)); - -template <int N> -struct MoveConstructorChecker { - MoveConstructorChecker(MoveConstructorChecker&&) requires C0<N> = default; - MoveConstructorChecker(MoveConstructorChecker&&) requires C1<N> = delete; - MoveConstructorChecker(MoveConstructorChecker&&) requires C2<N>; - MoveConstructorChecker(MoveConstructorChecker&&); -}; - -static_assert(__is_trivially_copyable(MoveConstructorChecker<0>)); -// FIXME: DR1734 -static_assert(__is_trivially_copyable(MoveConstructorChecker<1>)); -static_assert(!__is_trivially_copyable(MoveConstructorChecker<2>)); -static_assert(!__is_trivially_copyable(MoveConstructorChecker<3>)); -static_assert(!__is_trivial(MoveConstructorChecker<0>)); -static_assert(!__is_trivial(MoveConstructorChecker<1>)); -static_assert(!__is_trivial(MoveConstructorChecker<2>)); -static_assert(!__is_trivial(MoveConstructorChecker<3>)); - -template <int N> -struct MoveAssignmentChecker { - MoveAssignmentChecker& operator=(MoveAssignmentChecker&&) requires C0<N> = default; - MoveAssignmentChecker& operator=(MoveAssignmentChecker&&) requires C1<N> = delete; - MoveAssignmentChecker& operator=(MoveAssignmentChecker&&) requires C2<N>; - MoveAssignmentChecker& operator=(MoveAssignmentChecker&&); -}; - -static_assert(__is_trivially_copyable(MoveAssignmentChecker<0>)); -// FIXME: DR1734. -static_assert(__is_trivially_copyable(MoveAssignmentChecker<1>)); -static_assert(!__is_trivially_copyable(MoveAssignmentChecker<2>)); -static_assert(!__is_trivially_copyable(MoveAssignmentChecker<3>)); -static_assert(__is_trivial(MoveAssignmentChecker<0>)); -// FIXME: DR1734. -static_assert(__is_trivial(MoveAssignmentChecker<1>)); -static_assert(!__is_trivial(MoveAssignmentChecker<2>)); -static_assert(!__is_trivial(MoveAssignmentChecker<3>)); - -template <int N> -struct CopyAssignmentChecker { - CopyAssignmentChecker& operator=(const CopyAssignmentChecker&) requires C0<N> = default; - CopyAssignmentChecker& operator=(const CopyAssignmentChecker&) requires C1<N> = delete; - CopyAssignmentChecker& operator=(const CopyAssignmentChecker&) requires C2<N>; - CopyAssignmentChecker& operator=(const CopyAssignmentChecker&); -}; - -static_assert(__is_trivially_copyable(CopyAssignmentChecker<0>)); -// FIXME: DR1734. -static_assert(__is_trivially_copyable(CopyAssignmentChecker<1>)); -static_assert(!__is_trivially_copyable(CopyAssignmentChecker<2>)); -static_assert(!__is_trivially_copyable(CopyAssignmentChecker<3>)); -static_assert(__is_trivial(CopyAssignmentChecker<0>)); -// FIXME: DR1734. -static_assert(__is_trivial(CopyAssignmentChecker<1>)); -static_assert(!__is_trivial(CopyAssignmentChecker<2>)); -static_assert(!__is_trivial(CopyAssignmentChecker<3>)); - - -template <int N> -struct KindComparisonChecker1 { - KindComparisonChecker1& operator=(const KindComparisonChecker1&) requires C0<N> = default; - KindComparisonChecker1& operator=(KindComparisonChecker1&); -}; - -template <int N> -struct KindComparisonChecker2 { - KindComparisonChecker2& operator=(const KindComparisonChecker2&) requires C0<N> = default; - const KindComparisonChecker2& operator=(KindComparisonChecker2&) const; -}; - -template <int N> -struct KindComparisonChecker3 { - using Alias = KindComparisonChecker3; - Alias& operator=(const Alias&) requires C0<N> = default; - KindComparisonChecker3& operator=(const KindComparisonChecker3&); -}; - -static_assert(!__is_trivial(KindComparisonChecker1<0>)); -static_assert(!__is_trivially_copyable(KindComparisonChecker1<0>)); - -static_assert(!__is_trivial(KindComparisonChecker2<0>)); -static_assert(!__is_trivially_copyable(KindComparisonChecker2<0>)); - -static_assert(__is_trivial(KindComparisonChecker3<0>)); -static_assert(__is_trivially_copyable(KindComparisonChecker3<0>)); - -template <class T> -concept HasA = requires(T t) { - { t.a() }; -}; - -template <class T> -concept HasAB = HasA<T> && requires(T t) { - { t.b() }; -}; - -template <class T> -concept HasAC = HasA<T> && requires(T t) { - { t.c() }; -}; - -template <class T> -concept HasABC = HasAB<T> && HasAC<T> && requires(T t) { - { t.c() }; -}; - -template <class T> -struct ComplexConstraints { - ComplexConstraints() requires HasABC<T> = default; - ComplexConstraints() requires HasAB<T>; - ComplexConstraints() requires HasAC<T>; - ComplexConstraints() requires HasA<T> = delete; - ComplexConstraints(); -}; - -struct A { - void a(); -}; - -struct AB { - void a(); - void b(); -}; - -struct ABC { - void a(); - void b(); - void c(); -}; - -struct AC { - void a(); - void c(); -}; - -static_assert(__is_trivial(ComplexConstraints<ABC>), ""); -static_assert(!__is_trivial(ComplexConstraints<AB>), ""); -static_assert(!__is_trivial(ComplexConstraints<AC>), ""); -static_assert(__is_trivial(ComplexConstraints<A>), ""); -static_assert(!__is_trivial(ComplexConstraints<int>), ""); - - -// This is evaluated at the completion of CRTPBase, while `T` is not yet completed. -// This is probably correct behavior. -// FIXME: We should not throw an error, instead SFINAE should make the constraint -// silently unsatisfied. See [temp.constr.constr]p5 -template <class T> -struct CRTPBase { - CRTPBase() requires (sizeof(T) > 0); // expected-error {{to an incomplete type}} - CRTPBase() = default; -}; - -struct Child : CRTPBase<Child> { int x; }; -// expected-note@-1 {{definition of 'Child' is not complete until}} -// expected-note@-2 {{in instantiation of template class 'CRTPBase<Child>' requested here}} -static Child c; - - -namespace GH57046 { -template<unsigned N> -struct Foo { - Foo() requires (N==1) {} // expected-note {{declared here}} - Foo() requires (N==2) = default; -}; - -template <unsigned N, unsigned M> -struct S { - Foo<M> data; - S() requires (N==1) {} - consteval S() requires (N==2) = default; // expected-note {{non-constexpr constructor 'Foo' cannot be used in a constant expression}} -}; - -void func() { - S<2, 1> s1; // expected-error {{is not a constant expression}} expected-note {{in call to 'S()'}} - S<2, 2> s2; -} -} diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index 5876e39a0b536..5aae4ba822826 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -927,16 +927,8 @@ <h2 id="cxx20">C++20 implementation status</h2> </tr> <tr> <!-- from Cologne --> <td><a href="https://wg21.link/p0848r3">P0848R3</a></td> - <td rowspan="1" class="unreleased" align="center"> - <details> - <summary>Clang 16 (Partial)</summary> - Because of other concepts implementation deficits, the __cpp_concepts macro is not yet set to 202002L. - Also, the related defect reports <a href="https://wg21.link/cwg1496">DR1496</a> and - <a href="https://wg21.link/cwg1734">DR1734</a> are not yet implemented. Accordingly, deleted - special member functions are treated as eligible even though they shouldn't be. - </details> - </td> - </tr> + <td rowspan="1" class="none" align="center">No</td> + </tr> <tr> <td><a href="https://wg21.link/p1616r1">P1616R1</a></td> <td rowspan="2" class="full" align="center">Clang 10</td> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits