[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