[clang] adds explanation for why std::is_const is false (PR #235587)

via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 25 21:36:17 PDT 2026


https://github.com/NomaTyx updated https://github.com/llvm/llvm-project/pull/235587

>From 1f4aebc546d42af48dd1930c5ff6ded1f1cbda98 Mon Sep 17 00:00:00 2001
From: Julia Ziebart <jjziebart99 at gmail.com>
Date: Sun, 25 Oct 2026 21:17:14 -0700
Subject: [PATCH] adds explanation for why std::is_const is false and adds more
 expected error messages to static-assert.cpp (otherwise it would see my added
 messages and fail the test)

---
 clang/include/clang/Basic/BuiltinTraits.td    |  1 +
 .../clang/Basic/DiagnosticSemaKinds.td        |  6 +-
 clang/lib/Sema/SemaTypeTraits.cpp             | 27 ++++++
 clang/test/SemaCXX/static-assert.cpp          | 25 ++++--
 .../type-traits-unsatisfied-diags-std.cpp     | 86 +++++++++++++++++++
 .../SemaCXX/type-traits-unsatisfied-diags.cpp | 19 ++++
 6 files changed, 155 insertions(+), 9 deletions(-)

diff --git a/clang/include/clang/Basic/BuiltinTraits.td b/clang/include/clang/Basic/BuiltinTraits.td
index f80234dd21e145..430c0ca613f4e5 100644
--- a/clang/include/clang/Basic/BuiltinTraits.td
+++ b/clang/include/clang/Basic/BuiltinTraits.td
@@ -558,6 +558,7 @@ def IsMemberPointer : UnaryTrait {
 
 def IsConst : UnaryTrait {
   let Spelling = "__is_const";
+  let StdName = "is_const";
 }
 
 def IsVolatile : UnaryTrait {
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index dcb5732c3c19e7..ec28942fed64e1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1858,7 +1858,8 @@ def note_unsatisfied_trait
            "%StandardLayout{standard-layout}|"
            "%Aggregate{aggregate}|"
            "%Final{final}|"
-           "%Abstract{abstract}"
+           "%Abstract{abstract}|"
+           "%Const{const}"
            "}1">;
 
 def note_unsatisfied_trait_reason
@@ -1911,7 +1912,8 @@ def note_unsatisfied_trait_reason
            "%ArrayType{is an array type}|"
            "%UnionType{is a union type}|"
            "%NotStructOrClass{is not a struct or class type}|"
-           "%OverridesAllPureVirtual{overrides all pure virtual functions from base class %1}"
+           "%OverridesAllPureVirtual{overrides all pure virtual functions from base class %1}|"
+           "%NotMarkedConst{is not marked 'const'}"
            "}0">;
 
 def warn_consteval_if_always_true : Warning<
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index cb30ff9fd02da9..0296a0426867c2 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -2751,6 +2751,30 @@ static void DiagnoseNonAbstractReason(Sema &SemaRef, SourceLocation Loc,
     DiagnoseNonAbstractReason(SemaRef, Loc, D);
 }
 
+static void DiagnoseNonConstReason(Sema &SemaRef, SourceLocation Loc,
+                                   QualType T) {
+  SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
+      << T << diag::TraitName::Const;
+
+  if (T->isReferenceType()) {
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::Ref;
+    return;
+  }
+
+  if (T->isFunctionType()) {
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::FunctionType;
+    return;
+  }
+
+  if (!T.isConstQualified()) {
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::NotMarkedConst;
+    return;
+  }
+}
+
 void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   if (E->containsErrors())
     return;
@@ -2794,6 +2818,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   case UTT_IsAbstract:
     DiagnoseNonAbstractReason(*this, E->getBeginLoc(), Args[0]);
     break;
+  case UTT_IsConst:
+    DiagnoseNonConstReason(*this, E->getBeginLoc(), Args[0]);
+    break;
   default:
     break;
   }
diff --git a/clang/test/SemaCXX/static-assert.cpp b/clang/test/SemaCXX/static-assert.cpp
index dcaaaafd824450..0522a7d65e57e5 100644
--- a/clang/test/SemaCXX/static-assert.cpp
+++ b/clang/test/SemaCXX/static-assert.cpp
@@ -146,7 +146,9 @@ struct ExampleTypes {
 static_assert(std::is_same<ExampleTypes::T, ExampleTypes::U>::value, "message");
 // expected-error at -1{{static assertion failed due to requirement 'std::is_same<int, float>::value': message}}
 static_assert(std::is_const<ExampleTypes::T>::value, "message");
-// expected-error at -1{{static assertion failed due to requirement 'std::is_const<int>::value': message}}
+// expected-error at -1{{static assertion failed due to requirement 'std::is_const<int>::value': message}} \
+// expected-note at -1{{'ExampleTypes::T' (aka 'int') is not const}} \
+// expected-note at -1 {{because it is not marked 'const'}}
 static_assert(!std::is_const<const ExampleTypes::T>::value, "message");
 // expected-error at -1{{static assertion failed due to requirement '!std::is_const<const int>::value': message}}
 static_assert(!(std::is_const<const ExampleTypes::T>::value), "message");
@@ -162,12 +164,17 @@ static_assert(!(std::is_const<const ExampleTypes::T>()()), "message");
 static_assert(std::is_same<decltype(std::is_const<const ExampleTypes::T>()), int>::value, "message");
 // expected-error at -1{{static assertion failed due to requirement 'std::is_same<std::is_const<const int>, int>::value': message}}
 static_assert(std::is_const<decltype(ExampleTypes::T(3))>::value, "message");
-// expected-error at -1{{static assertion failed due to requirement 'std::is_const<int>::value': message}}
+// expected-error at -1{{static assertion failed due to requirement 'std::is_const<int>::value': message}} \
+// expected-note at -1{{'decltype(ExampleTypes::T(3))' (aka 'int') is not const}} \
+// expected-note at -1{{because it is not marked 'const'}}
 static_assert(std::is_const<decltype(ExampleTypes::T())>::value, "message");
-// expected-error at -1{{static assertion failed due to requirement 'std::is_const<int>::value': message}}
+// expected-error at -1{{static assertion failed due to requirement 'std::is_const<int>::value': message}} \
+// expected-note at -1{{'decltype(ExampleTypes::T())' (aka 'int') is not const}} \
+// expected-note at -1{{because it is not marked 'const'}}
 static_assert(std::is_const<decltype(ExampleTypes(3))>::value, "message");
-// expected-error at -1{{static assertion failed due to requirement 'std::is_const<ExampleTypes>::value': message}}
-
+// expected-error at -1{{static assertion failed due to requirement 'std::is_const<ExampleTypes>::value': message}} \
+// expected-note at -1{{'decltype(ExampleTypes(3))' (aka 'ExampleTypes') is not const}} \
+// expected-note at -1{{because it is not marked 'const'}}
 struct BI_tag {};
 struct RAI_tag : BI_tag {};
 struct MyIterator {
@@ -207,9 +214,13 @@ template void foo2<int, float, 3>();
 template <class T>
 void foo3(T t) {
   static_assert(std::is_const<T>::value, "message");
-  // expected-error-re at -1{{static assertion failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value': message}}
+  // expected-error-re at -1{{static assertion failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value': message}} \
+  // expected-note-re at -1{{'(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})' is not const}} \
+  // expected-note at -1{{because it is not marked 'const'}}
   static_assert(std::is_const<decltype(t)>::value, "message");
-  // expected-error-re at -1{{static assertion failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value': message}}
+  // expected-error-re at -1{{static assertion failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value': message}} \
+  // expected-note-re at -1{{'decltype(t)' (aka '(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})') is not const}} \
+  // expected-note at -1{{because it is not marked 'const'}}
 }
 void callFoo3() {
   foo3([]() {});
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
index 8a9f3bc400d206..7655e60133c438 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_const {
+  static constexpr bool value = __is_const(T);
+};
+template <typename T>
+constexpr bool is_const_v = __is_const(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_const {
+  static constexpr bool value = __is_const(T);
+};
+template <typename T>
+using is_const = __details_is_const<T>;
+template <typename T>
+constexpr bool is_const_v = __is_const(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_const : bool_constant<__is_const(T)> {};
+template <typename T>
+using is_const = __details_is_const<T>;
+template <typename T>
+constexpr bool is_const_v = is_const<T>::value;
+
 #endif
 }
 
@@ -374,6 +397,37 @@ static_assert(std::is_abstract_v<int&>);
 // expected-note at -1 {{because it is a reference type}} \
 // expected-note at -1 {{because it is not a struct or class type}}
 
+static_assert(!std::is_const<int>::value);
+
+static_assert(std::is_const<void()>::value);
+// expected-error-re at -1 {{static assertion failed due to requirement 'std::{{.*}}is_const<void ()>::value'}} \
+// expected-note at -1 {{'void ()' is not const}} \
+// expected-note at -1 {{because it is a function type}}
+
+static_assert(std::is_const_v<void()>);
+// expected-error at -1 {{static assertion failed due to requirement 'std::is_const_v<void ()>'}} \
+// expected-note at -1 {{'void ()' is not const}} \
+// expected-note at -1 {{because it is a function type}}
+
+static_assert(std::is_const<int &>::value);
+// expected-error-re at -1 {{static assertion failed due to requirement 'std::{{.*}}is_const<int &>::value'}} \
+// expected-note at -1 {{'int &' is not const}} \
+// expected-note at -1 {{because it is a reference type}}
+
+static_assert(std::is_const_v<int &>);
+// expected-error at -1 {{static assertion failed due to requirement 'std::is_const_v<int &>'}} \
+// expected-note at -1 {{'int &' is not const}} \
+// expected-note at -1 {{because it is a reference type}}
+
+static_assert(std::is_const_v<int>);
+// expected-error at -1 {{static assertion failed due to requirement 'std::is_const_v<int>'}} \
+// expected-note at -1 {{'int' is not const}} \
+// expected-note at -1 {{because it is not marked 'const'}}
+
+static_assert(std::is_const<int>::value);
+// expected-error-re at -1 {{static assertion failed due to requirement 'std::{{.*}}is_const<int>::value'}} \
+// expected-note at -1 {{'int' is not const}} \
+// expected-note at -1 {{because it is not marked 'const'}}
 
 namespace test_namespace {
     using namespace std;
@@ -473,6 +527,38 @@ namespace test_namespace {
     // expected-note at -1 {{'int &' is not abstract}} \
     // expected-note at -1 {{because it is a reference type}} \
     // expected-note at -1 {{because it is not a struct or class type}}
+
+    static_assert(!is_const<int>::value);
+
+    static_assert(is_const<void()>::value);
+    // expected-error-re at -1 {{static assertion failed due to requirement '{{.*}}is_const<void ()>::value'}} \
+    // expected-note at -1 {{'void ()' is not const}} \
+    // expected-note at -1 {{because it is a function type}} \
+
+    static_assert(is_const_v<void ()>);
+    // expected-error at -1 {{static assertion failed due to requirement 'is_const_v<void ()>'}} \
+    // expected-note at -1 {{'void ()' is not const}} \
+    // expected-note at -1 {{because it is a function type}}
+
+    static_assert(is_const<int &>::value);
+    // expected-error-re at -1 {{static assertion failed due to requirement '{{.*}}is_const<int &>::value'}} \
+    // expected-note at -1 {{'int &' is not const}} \
+    // expected-note at -1 {{because it is a reference type}}
+
+    static_assert(is_const_v<int &>);
+    // expected-error at -1 {{static assertion failed due to requirement 'is_const_v<int &>'}} \
+    // expected-note at -1 {{'int &' is not const}} \
+    // expected-note at -1 {{because it is a reference type}}
+
+    static_assert(is_const<int>::value);
+    // expected-error-re at -1 {{static assertion failed due to requirement '{{.*}}is_const<int>::value'}} \
+    // expected-note at -1 {{'int' is not const}} \
+    // expected-note at -1 {{because it is not marked 'const'}}
+
+    static_assert(is_const_v<int>);
+    // expected-error at -1 {{static assertion failed due to requirement 'is_const_v<int>'}} \
+    // expected-note at -1 {{'int' is not const}} \
+    // expected-note at -1 {{because it is not marked 'const'}}
 }
 
 
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index 3bde5b06a3aba4..a111a6483ebd10 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -892,3 +892,22 @@ static_assert(__is_abstract(U));
 // expected-note at -1 {{because it is not a struct or class type}}
 
 }
+
+namespace is_const_tests {
+
+static_assert(__is_const(void()));
+// expected-error at -1 {{static assertion failed due to requirement '__is_const(void ())'}} \
+// expected-note at -1 {{'void ()' is not const}} \
+// expected-note at -1 {{because it is a function type}}
+
+static_assert(__is_const(int &));
+// expected-error at -1 {{static assertion failed due to requirement '__is_const(int &)'}} \
+// expected-note at -1 {{'int &' is not const}} \
+// expected-note at -1 {{because it is a reference type}}
+
+static_assert(__is_const(int));
+// expected-error at -1 {{static assertion failed due to requirement '__is_const(int)'}} \
+// expected-note at -1 {{'int' is not const}} \
+// expected-note at -1 {{because it is not marked 'const'}}
+
+}
\ No newline at end of file



More information about the cfe-commits mailing list