[clang] [clang] Explain why std::is_integral is not satisfied (PR #235416)

Aaron Advait Anish via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 25 01:32:05 PDT 2026


https://github.com/skylarcs-the-limit created https://github.com/llvm/llvm-project/pull/235416

Part of #141911.
This adds missing diagnostic notes explaining why std::is_integral fails.

>From 23208672099931b3ce8840dade1417ec5d3ff21b Mon Sep 17 00:00:00 2001
From: Aaron Advait Anish <cs24btech11002 at iith.ac.in>
Date: Sun, 25 Oct 2026 13:59:08 +0530
Subject: [PATCH] [clang] Explain why std::is_integral is not satisfied

Part of #141911.

Co-authored-by: Aare Renu Shri <cs24btech11001 at iith.ac.in>, Rupesh Devarapalli <cs24btech11023 at iith.ac.in>
---
 clang/include/clang/Basic/BuiltinTraits.td    |  1 +
 .../clang/Basic/DiagnosticSemaKinds.td        |  6 ++
 clang/lib/Sema/SemaTypeTraits.cpp             | 38 +++++++++++++
 .../type-traits-unsatisfied-diags-std.cpp     | 47 ++++++++++++++++
 .../SemaCXX/type-traits-unsatisfied-diags.cpp | 56 +++++++++++++++++++
 5 files changed, 148 insertions(+)

diff --git a/clang/include/clang/Basic/BuiltinTraits.td b/clang/include/clang/Basic/BuiltinTraits.td
index f80234dd21e145..a00ad3a24e5402 100644
--- a/clang/include/clang/Basic/BuiltinTraits.td
+++ b/clang/include/clang/Basic/BuiltinTraits.td
@@ -494,6 +494,7 @@ def IsFloatingPoint : UnaryTrait {
 
 def IsIntegral : UnaryTrait {
   let Spelling = "__is_integral";
+  let StdName = "is_integral";
 }
 
 def IsCompleteType : UnaryTrait {
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index dcb5732c3c19e7..0890bd0ad13461 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1855,6 +1855,7 @@ def note_unsatisfied_trait
            "%TriviallyRelocatable{trivially relocatable}|"
            "%TriviallyCopyable{trivially copyable}|"
            "%Empty{empty}|"
+           "%Integral{an integral type}|"
            "%StandardLayout{standard-layout}|"
            "%Aggregate{aggregate}|"
            "%Final{final}|"
@@ -1908,6 +1909,11 @@ def note_unsatisfied_trait_reason
            "%NotClassOrUnion{is not a class or union type}|"
            "%NotMarkedFinal{is not marked 'final'}|"
            "%PointerType{is a pointer type}|"
+           "%FloatingPointType{is a floating-point type}|"
+           "%EnumType{is an enum type}|"
+           "%VoidType{is void}|"
+           "%ClassType{is a class type}|"
+           "%MemberPointerType{is a member pointer type}|"
            "%ArrayType{is an array type}|"
            "%UnionType{is a union type}|"
            "%NotStructOrClass{is not a struct or class type}|"
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index cb30ff9fd02da9..0a0e37ac0e0a50 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -2406,6 +2406,41 @@ static void DiagnoseIsEmptyReason(Sema &S, SourceLocation Loc, QualType T) {
   }
 }
 
+static void DiagnoseNonIntegralReason(Sema &S, SourceLocation Loc, QualType T) {
+  S.Diag(Loc, diag::note_unsatisfied_trait) << T << diag::TraitName::Integral;
+  if (T->isFloatingType()) {
+    S.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::FloatingPointType;
+  } else if (T->isEnumeralType()) {
+    S.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::EnumType;
+  } else if (T->isPointerType()) {
+    S.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::PointerType;
+  } else if (T->isReferenceType()) {
+    S.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::Ref;
+  } else if (T->isArrayType()) {
+    S.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::ArrayType;
+  } else if (T->isUnionType()) {
+    S.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::UnionType;
+  } else if (T->isFunctionType()) {
+    S.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::FunctionType;
+  } else if (T->isVoidType()) {
+    S.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::VoidType;
+  } else if (T->isStructureOrClassType()) {
+    S.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::ClassType;
+  } else if (T->isMemberPointerType()) {
+    S.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::MemberPointerType;
+  }
+}
+
 static void DiagnoseIsFinalReason(Sema &S, SourceLocation Loc,
                                   const CXXRecordDecl *D) {
   if (!D || D->isInvalidDecl())
@@ -2773,6 +2808,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   case UTT_IsEmpty:
     DiagnoseIsEmptyReason(*this, E->getBeginLoc(), Args[0]);
     break;
+  case UTT_IsIntegral:
+    DiagnoseNonIntegralReason(*this, E->getBeginLoc(), Args[0]);
+    break;
   case UTT_IsStandardLayout:
     DiagnoseNonStandardLayoutReason(*this, E->getBeginLoc(), Args[0]);
     break;
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
index 8a9f3bc400d206..2b301d02f496dd 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
@@ -73,6 +73,13 @@ struct is_abstract {
 template <typename T>
 constexpr bool is_abstract_v = __is_abstract(T);
 
+template <typename T>
+struct is_integral {
+    static constexpr bool value = __is_integral(T);
+};
+template <typename T>
+constexpr bool is_integral_v = __is_integral(T);
+
 #endif
 
 #ifdef STD2
@@ -167,6 +174,15 @@ using is_abstract = __details_is_abstract<T>;
 template <typename T>
 constexpr bool is_abstract_v = __is_abstract(T);
 
+template <typename T>
+struct __details_is_integral {
+    static constexpr bool value = __is_integral(T);
+};
+template <typename T>
+using is_integral = __details_is_integral<T>;
+template <typename T>
+constexpr bool is_integral_v = __is_integral(T);
+
 #endif
 
 
@@ -252,6 +268,13 @@ using is_abstract = __details_is_abstract<T>;
 template <typename T>
 constexpr bool is_abstract_v = is_abstract<T>::value;
 
+template <typename T>
+struct __details_is_integral : bool_constant<__is_integral(T)> {};
+template <typename T>
+using is_integral = __details_is_integral<T>;
+template <typename T>
+constexpr bool is_integral_v = is_integral<T>::value;
+
 #endif
 }
 
@@ -590,4 +613,28 @@ void test() {
     // expected-note@#concept10 {{'void' is not aggregate}} \
     // expected-note@#concept10 {{because it is a cv void type}}
 }
+    static_assert(std::is_integral<double>::value);
+    // expected-error-re at -1 {{static assertion failed due to requirement 'std::{{.*}}is_integral<double>::value'}} \
+    // expected-note at -1 {{'double' is not an integral type}} \
+    // expected-note at -1 {{because it is a floating-point type}}
+    static_assert(std::is_integral_v<double>);
+    // expected-error at -1 {{static assertion failed due to requirement 'std::is_integral_v<double>'}} \
+    // expected-note at -1 {{'double' is not an integral type}} \
+    // expected-note at -1 {{because it is a floating-point type}}
+
+    static_assert(std::is_integral_v<int*>);
+    // expected-error at -1 {{static assertion failed due to requirement 'std::is_integral_v<int *>'}} \
+    // expected-note at -1 {{'int *' is not an integral type}} \
+    // expected-note at -1 {{because it is a pointer type}}
+
+    static_assert(std::is_integral_v<int&>);
+    // expected-error at -1 {{static assertion failed due to requirement 'std::is_integral_v<int &>'}} \
+    // expected-note at -1 {{'int &' is not an integral type}} \
+    // expected-note at -1 {{because it is a reference type}}
+
+    enum E {};
+    static_assert(std::is_integral_v<E>);
+    // expected-error at -1 {{static assertion failed due to requirement 'std::is_integral_v<concepts::E>'}} \
+    // expected-note at -1 {{'concepts::E' is not an integral type}} \
+    // expected-note at -1 {{because it is an enum type}}
 }
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index 3bde5b06a3aba4..a4f42f5530a5b2 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -892,3 +892,59 @@ static_assert(__is_abstract(U));
 // expected-note at -1 {{because it is not a struct or class type}}
 
 }
+
+namespace is_integral_tests {
+    static_assert(__is_integral(double));
+    // expected-error at -1 {{static assertion failed due to requirement '__is_integral(double)'}} \
+    // expected-note at -1 {{'double' is not an integral type}} \
+    // expected-note at -1 {{because it is a floating-point type}}
+
+    static_assert(__is_integral(int*));
+    // expected-error at -1 {{static assertion failed due to requirement '__is_integral(int *)'}} \
+    // expected-note at -1 {{'int *' is not an integral type}} \
+    // expected-note at -1 {{because it is a pointer type}}
+
+    static_assert(__is_integral(int&));
+    // expected-error at -1 {{static assertion failed due to requirement '__is_integral(int &)'}} \
+    // expected-note at -1 {{'int &' is not an integral type}} \
+    // expected-note at -1 {{because it is a reference type}}
+
+    enum E {};
+    static_assert(__is_integral(E));
+    // expected-error at -1 {{static assertion failed due to requirement '__is_integral(is_integral_tests::E)'}} \
+    // expected-note at -1 {{'E' is not an integral type}} \
+    // expected-note at -1 {{because it is an enum type}}
+
+    static_assert(__is_integral(int[3]));
+    // expected-error at -1 {{static assertion failed due to requirement '__is_integral(int[3])'}} \
+    // expected-note at -1 {{'int[3]' is not an integral type}} \
+    // expected-note at -1 {{because it is an array type}}
+
+    union U {};
+    static_assert(__is_integral(U));
+    // expected-error at -1 {{static assertion failed due to requirement '__is_integral(is_integral_tests::U)'}} \
+    // expected-note at -1 {{'U' is not an integral type}} \
+    // expected-note at -1 {{because it is a union type}}
+
+    struct S {};
+    static_assert(__is_integral(S));
+    // expected-error at -1 {{static assertion failed due to requirement '__is_integral(is_integral_tests::S)'}} \
+    // expected-note at -1 {{'S' is not an integral type}} \
+    // expected-note at -1 {{because it is a class type}}
+
+    static_assert(__is_integral(int S::*));
+    // expected-error at -1 {{static assertion failed due to requirement '__is_integral(int is_integral_tests::S::*)'}} \
+    // expected-note at -1 {{'int S::*' is not an integral type}} \
+    // expected-note at -1 {{because it is a member pointer type}}
+
+    using F = int(char);
+    static_assert(__is_integral(F));
+    // expected-error at -1 {{static assertion failed due to requirement '__is_integral(int (char))'}} \
+    // expected-note at -1 {{'F' (aka 'int (char)') is not an integral type}} \
+    // expected-note at -1 {{because it is a function type}}
+
+    static_assert(__is_integral(void));
+    // expected-error at -1 {{static assertion failed due to requirement '__is_integral(void)'}} \
+    // expected-note at -1 {{'void' is not an integral type}} \
+    // expected-note at -1 {{because it is void}}
+}



More information about the cfe-commits mailing list