From 7b8c4b7c781e2ef7700dba5942b9521cdb16aea8 Mon Sep 17 00:00:00 2001 From: Corentin Jabot Date: Thu, 9 Oct 2025 10:18:28 +0200 Subject: [PATCH 1/5] [Clang] Fix a regression introduced by #161163. Classes with a user provided constructor are still implicit lifetime if they have an implicit, trivial copy ctr. --- clang/lib/Sema/SemaTypeTraits.cpp | 24 +++++++++++++++++------- clang/test/SemaCXX/type-traits.cpp | 12 +++++++++++- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index 3e34675cbf064..13f25c453d8ba 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -1165,14 +1165,24 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, const CXXDestructorDecl *Dtor = RD->getDestructor(); if (UnqualT->isAggregateType() && (!Dtor || !Dtor->isUserProvided())) return true; - if (RD->hasTrivialDestructor() && (!Dtor || !Dtor->isDeleted())) { - for (CXXConstructorDecl *Ctr : RD->ctors()) { - if (Ctr->isIneligibleOrNotSelected() || Ctr->isDeleted()) - continue; - if (Ctr->isTrivial()) - return true; - } + if (!(RD->hasTrivialDestructor() && (!Dtor || !Dtor->isDeleted()))) + return false; + bool FoundCopyCtr = false; + bool FoundMoveCtr = false; + for (CXXConstructorDecl *Ctr : RD->ctors()) { + FoundCopyCtr = Ctr->isCopyConstructor(); + FoundMoveCtr = Ctr->isMoveConstructor(); + if (Ctr->isIneligibleOrNotSelected() || Ctr->isDeleted()) + continue; + if (Ctr->isTrivial()) + return true; } + if (!FoundCopyCtr && RD->hasTrivialCopyConstructor() && + !RD->defaultedCopyConstructorIsDeleted()) + return true; + if (!FoundMoveCtr && RD->hasTrivialMoveConstructor() && + !RD->defaultedMoveConstructorIsDeleted()) + return true; return false; } case UTT_IsIntangibleType: diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index 901d510bba847..343529fe81b57 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -2066,7 +2066,17 @@ class UserProvidedConstructor { UserProvidedConstructor(const UserProvidedConstructor&) = delete; UserProvidedConstructor& operator=(const UserProvidedConstructor&) = delete; }; +struct Ctr { + Ctr(); +}; +struct Ctr2 { + Ctr2(); +private: + NoEligibleTrivialContructor inner; +}; +static_assert(__builtin_is_implicit_lifetime(Ctr)); +static_assert(!__builtin_is_implicit_lifetime(NoEligibleTrivialContructor)); static_assert(__builtin_is_implicit_lifetime(NonAggregate)); static_assert(!__builtin_is_implicit_lifetime(DataMemberInitializer)); static_assert(!__builtin_is_implicit_lifetime(UserProvidedConstructor)); @@ -2076,7 +2086,7 @@ template class Tpl { Tpl() requires false = default ; }; -static_assert(!__builtin_is_implicit_lifetime(Tpl)); +static_assert(__builtin_is_implicit_lifetime(Tpl)); #endif } From d35944ba8fe00e97a6d0cb90df6bbec86d7bb50f Mon Sep 17 00:00:00 2001 From: Corentin Jabot Date: Thu, 9 Oct 2025 18:24:41 +0200 Subject: [PATCH 2/5] fix the case of non copyable subobjects --- clang/lib/Sema/SemaTypeTraits.cpp | 10 ++++++++-- clang/test/SemaCXX/type-traits.cpp | 10 ++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index 13f25c453d8ba..187d39e8f26ed 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -1167,16 +1167,22 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return true; if (!(RD->hasTrivialDestructor() && (!Dtor || !Dtor->isDeleted()))) return false; + if (RD->hasTrivialDefaultConstructor()) + return true; bool FoundCopyCtr = false; bool FoundMoveCtr = false; + bool FoundDefaultCtr = false; for (CXXConstructorDecl *Ctr : RD->ctors()) { - FoundCopyCtr = Ctr->isCopyConstructor(); - FoundMoveCtr = Ctr->isMoveConstructor(); if (Ctr->isIneligibleOrNotSelected() || Ctr->isDeleted()) continue; if (Ctr->isTrivial()) return true; + FoundCopyCtr = Ctr->isCopyConstructor(); + FoundMoveCtr = Ctr->isMoveConstructor(); + FoundDefaultCtr = Ctr->isDefaultConstructor(); } + if (!FoundDefaultCtr && RD->hasTrivialDefaultConstructor()) + return true; if (!FoundCopyCtr && RD->hasTrivialCopyConstructor() && !RD->defaultedCopyConstructorIsDeleted()) return true; diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index 343529fe81b57..bc010dc5932ca 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -2075,7 +2075,17 @@ struct Ctr2 { NoEligibleTrivialContructor inner; }; +struct NonCopyable{ + NonCopyable() = default; + NonCopyable(const NonCopyable&) = delete; +}; + +class C { + NonCopyable nc; +}; + static_assert(__builtin_is_implicit_lifetime(Ctr)); +static_assert(__builtin_is_implicit_lifetime(C)); static_assert(!__builtin_is_implicit_lifetime(NoEligibleTrivialContructor)); static_assert(__builtin_is_implicit_lifetime(NonAggregate)); static_assert(!__builtin_is_implicit_lifetime(DataMemberInitializer)); From 9ef4c814ee26fd40c0a481b86902d2bcf67eb570 Mon Sep 17 00:00:00 2001 From: Corentin Jabot Date: Fri, 10 Oct 2025 13:31:48 +0200 Subject: [PATCH 3/5] more fixes + cleanup + add missing tests --- clang/lib/Sema/SemaTypeTraits.cpp | 16 +++++----------- clang/test/SemaCXX/type-traits.cpp | 5 +++-- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index 187d39e8f26ed..d4cecaaac8c64 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -1167,26 +1167,20 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return true; if (!(RD->hasTrivialDestructor() && (!Dtor || !Dtor->isDeleted()))) return false; - if (RD->hasTrivialDefaultConstructor()) - return true; - bool FoundCopyCtr = false; - bool FoundMoveCtr = false; - bool FoundDefaultCtr = false; for (CXXConstructorDecl *Ctr : RD->ctors()) { if (Ctr->isIneligibleOrNotSelected() || Ctr->isDeleted()) continue; if (Ctr->isTrivial()) return true; - FoundCopyCtr = Ctr->isCopyConstructor(); - FoundMoveCtr = Ctr->isMoveConstructor(); - FoundDefaultCtr = Ctr->isDefaultConstructor(); } - if (!FoundDefaultCtr && RD->hasTrivialDefaultConstructor()) + if (RD->needsImplicitDefaultConstructor() && + RD->hasTrivialDefaultConstructor() && + !RD->hasNonTrivialDefaultConstructor()) return true; - if (!FoundCopyCtr && RD->hasTrivialCopyConstructor() && + if (RD->needsImplicitCopyConstructor() && RD->hasTrivialCopyConstructor() && !RD->defaultedCopyConstructorIsDeleted()) return true; - if (!FoundMoveCtr && RD->hasTrivialMoveConstructor() && + if (RD->needsImplicitMoveConstructor() && RD->hasTrivialMoveConstructor() && !RD->defaultedMoveConstructorIsDeleted()) return true; return false; diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index bc010dc5932ca..47fe6e5119767 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -2067,10 +2067,10 @@ class UserProvidedConstructor { UserProvidedConstructor& operator=(const UserProvidedConstructor&) = delete; }; struct Ctr { - Ctr(); + Ctr(); }; struct Ctr2 { - Ctr2(); + Ctr2(); private: NoEligibleTrivialContructor inner; }; @@ -2085,6 +2085,7 @@ class C { }; static_assert(__builtin_is_implicit_lifetime(Ctr)); +static_assert(!__builtin_is_implicit_lifetime(Ctr2)); static_assert(__builtin_is_implicit_lifetime(C)); static_assert(!__builtin_is_implicit_lifetime(NoEligibleTrivialContructor)); static_assert(__builtin_is_implicit_lifetime(NonAggregate)); From 4c5bc8ac6fb9558d035183e2273f8615543d7858 Mon Sep 17 00:00:00 2001 From: Corentin Jabot Date: Fri, 10 Oct 2025 14:57:28 +0200 Subject: [PATCH 4/5] more tests for constrained default constructors --- clang/lib/Sema/SemaTypeTraits.cpp | 3 +-- clang/test/SemaCXX/type-traits.cpp | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index d4cecaaac8c64..e4d055fd31301 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -1076,8 +1076,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, if (T.isPODType(C) || T->isObjCLifetimeType()) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) { - if (RD->hasTrivialDefaultConstructor() && - !RD->hasNonTrivialDefaultConstructor()) + if (RD->hasTrivialDefaultConstructor()) return true; bool FoundConstructor = false; diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index 47fe6e5119767..9ef44d0346b48 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -2099,7 +2099,25 @@ class Tpl { }; static_assert(__builtin_is_implicit_lifetime(Tpl)); +template +class MultipleDefaults { + MultipleDefaults() {}; + MultipleDefaults() requires true = default; +}; +static_assert(__builtin_is_implicit_lifetime(MultipleDefaults)); +template +class MultipleDefaults2 { + MultipleDefaults2() requires true {}; + MultipleDefaults2() = default; +}; + +static_assert(__builtin_is_implicit_lifetime(MultipleDefaults2)); + + #endif + + + } void is_signed() From 346aeca77951f69b5925348648884ed9e4ddbbed Mon Sep 17 00:00:00 2001 From: Corentin Jabot Date: Wed, 15 Oct 2025 10:14:28 +0200 Subject: [PATCH 5/5] cleanup --- clang/lib/Sema/SemaTypeTraits.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index e4d055fd31301..aca21cc793170 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -1164,7 +1164,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, const CXXDestructorDecl *Dtor = RD->getDestructor(); if (UnqualT->isAggregateType() && (!Dtor || !Dtor->isUserProvided())) return true; - if (!(RD->hasTrivialDestructor() && (!Dtor || !Dtor->isDeleted()))) + bool HasTrivialNonDeletedDtr = + RD->hasTrivialDestructor() && (!Dtor || !Dtor->isDeleted()); + if (!HasTrivialNonDeletedDtr) return false; for (CXXConstructorDecl *Ctr : RD->ctors()) { if (Ctr->isIneligibleOrNotSelected() || Ctr->isDeleted())