Skip to content

Conversation

cor3ntin
Copy link
Contributor

We failed to check that the trivial constructor where eligible (this implies non deleted).

Fixes #160610

@cor3ntin cor3ntin requested a review from erichkeane September 29, 2025 09:58
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Sep 29, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 29, 2025

@llvm/pr-subscribers-clang

Author: Corentin Jabot (cor3ntin)

Changes

We failed to check that the trivial constructor where eligible (this implies non deleted).

Fixes #160610


Full diff: https://github.com/llvm/llvm-project/pull/161163.diff

3 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+1)
  • (modified) clang/lib/Sema/SemaTypeTraits.cpp (+10-7)
  • (modified) clang/test/SemaCXX/type-traits.cpp (+40)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 270b5d336eba7..e8deae50e4cb0 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -432,6 +432,7 @@ Bug Fixes to C++ Support
 - Fix an assertion failure when taking the address on a non-type template parameter argument of
   object type. (#GH151531)
 - Suppress ``-Wdouble-promotion`` when explicitly asked for with C++ list initialization (#GH33409).
+- Fix the result of `__builtin_is_implicit_lifetime` for types with a user-provided constructor. (#GH160610)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index c2427dcf52538..6c798d6acb0a0 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -1163,13 +1163,16 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
     //   - it has at least one trivial eligible constructor and a trivial,
     //     non-deleted destructor.
     const CXXDestructorDecl *Dtor = RD->getDestructor();
-    if (UnqualT->isAggregateType())
-      if (Dtor && !Dtor->isUserProvided())
-        return true;
-    if (RD->hasTrivialDestructor() && (!Dtor || !Dtor->isDeleted()))
-      if (RD->hasTrivialDefaultConstructor() ||
-          RD->hasTrivialCopyConstructor() || RD->hasTrivialMoveConstructor())
-        return true;
+    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;
+      }
+    }
     return false;
   }
   case UTT_IsIntangibleType:
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 3f0124755c674..f8a88b1d0c0ad 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -2038,6 +2038,46 @@ void is_implicit_lifetime(int n) {
   static_assert(__builtin_is_implicit_lifetime(int * __restrict));
 }
 
+namespace GH160610 {
+class NonAggregate {
+public:
+    NonAggregate() = default;
+
+    NonAggregate(const NonAggregate&)            = delete;
+    NonAggregate& operator=(const NonAggregate&) = delete;
+private:
+    int num;
+};
+
+class DataMemberInitializer {
+public:
+    DataMemberInitializer() = default;
+
+    DataMemberInitializer(const DataMemberInitializer&)            = delete;
+    DataMemberInitializer& operator=(const DataMemberInitializer&) = delete;
+private:
+    int num = 0;
+};
+
+class UserProvidedConstructor {
+public:
+    UserProvidedConstructor() {}
+
+    UserProvidedConstructor(const UserProvidedConstructor&)            = delete;
+    UserProvidedConstructor& operator=(const UserProvidedConstructor&) = delete;
+};
+
+template <typename T>
+class Tpl {
+    Tpl() requires false = default ;
+};
+
+static_assert(__builtin_is_implicit_lifetime(NonAggregate));
+static_assert(!__builtin_is_implicit_lifetime(DataMemberInitializer));
+static_assert(!__builtin_is_implicit_lifetime(UserProvidedConstructor));
+static_assert(!__builtin_is_implicit_lifetime(Tpl<int>));
+}
+
 void is_signed()
 {
   //static_assert(__is_signed(char));

…ovided Ctr

We failed to check that the trivial constructor where eligible
(this implies non deleted).

Fixes llvm#160610
@cor3ntin cor3ntin merged commit e5bbc9f into llvm:main Sep 29, 2025
10 checks passed
}

namespace GH160610 {
class NonAggregate {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth adding a few more combinations here, like combinations of defaulted and deleted.

mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Oct 3, 2025
…trs (llvm#161163)

We failed to check that the trivial constructor where eligible (this
implies non deleted).

Fixes llvm#160610
@bolshakov-a
Copy link
Contributor

bolshakov-a commented Oct 3, 2025

After this change, clang fails to detect implicitly defined trivial copy constructors. The assertion fails in this code:

struct S {
    S();
};

//S s1;

static_assert(__builtin_is_implicit_lifetime(S));

Uncomment s1 definition, and the code compiles, probably due to instantiation of the implicit S members.

@bolshakov-a
Copy link
Contributor

@cor3ntin, what do you think?

@cor3ntin
Copy link
Contributor Author

cor3ntin commented Oct 8, 2025

I will look into it, thanks for letting me know

cor3ntin added a commit to cor3ntin/llvm-project that referenced this pull request Oct 9, 2025
Classes with a user provided constructor are still implicit lifetime
if they have an implicit, trivial copy ctr.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Clang] __builtin_is_implicit_lifetime isn't checking for trivial constructors
5 participants