[clang] [clang][AST] Treat unsigned _BitInt(1) as boolean-valued (PR #195793)
Andrei Sabalenka via cfe-commits
cfe-commits at lists.llvm.org
Tue May 5 04:58:38 PDT 2026
https://github.com/mechakotik updated https://github.com/llvm/llvm-project/pull/195793
>From 0083046de6e7e741d228d7576846d0343ebff683 Mon Sep 17 00:00:00 2001
From: Andrei Sabalenka <mechakotik at gmail.com>
Date: Tue, 5 May 2026 01:45:22 +0300
Subject: [PATCH] [clang][AST] Treat unsigned _BitInt(1) as boolean-valued
Update Expr::isKnownToHaveBooleanValue to recognize unsigned _BitInt(1) when semantic boolean-ness is not required.
---
clang/lib/AST/Expr.cpp | 5 ++++
clang/unittests/AST/ASTExprTest.cpp | 46 +++++++++++++++++++++++++++++
2 files changed, 51 insertions(+)
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 64d61dbc3d128..a542f2492c63f 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -142,6 +142,11 @@ bool Expr::isKnownToHaveBooleanValue(bool Semantic) const {
// If this is a non-scalar-integer type, we don't care enough to try.
if (!E->getType()->isIntegralOrEnumerationType()) return false;
+ if (!Semantic)
+ if (const auto *BIT = E->getType()->getAs<BitIntType>())
+ if (BIT->isUnsigned() && BIT->getNumBits() == 1)
+ return true;
+
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
switch (UO->getOpcode()) {
case UO_Plus:
diff --git a/clang/unittests/AST/ASTExprTest.cpp b/clang/unittests/AST/ASTExprTest.cpp
index adaceb76de8b4..6e5683c68eb4d 100644
--- a/clang/unittests/AST/ASTExprTest.cpp
+++ b/clang/unittests/AST/ASTExprTest.cpp
@@ -108,3 +108,49 @@ TEST(ASTExpr, InitListIsConstantInitialized) {
(void)FooInit->updateInit(Ctx, 2, Ref);
EXPECT_FALSE(FooInit->isConstantInitializer(Ctx, false));
}
+
+TEST(ASTExpr, IsKnownToHaveBooleanValue) {
+ auto AST = tooling::buildASTFromCodeWithArgs(
+ R"c(
+ struct S {
+ int signed_bf1 : 1;
+ unsigned unsigned_bf1 : 1;
+ unsigned unsigned_bf2 : 2;
+ };
+
+ _Bool bool_value;
+ int int_value;
+ unsigned _BitInt(1) unsigned_bitint1;
+ unsigned _BitInt(2) unsigned_bitint2;
+ struct S s;
+
+ void f(void) {
+ int from_bool = bool_value;
+ int from_int = int_value;
+ int from_signed_bitfield1 = s.signed_bf1;
+ int from_bitfield1 = s.unsigned_bf1;
+ int from_bitfield2 = s.unsigned_bf2;
+ int from_bitint1 = unsigned_bitint1;
+ int from_bitint2 = unsigned_bitint2;
+ }
+ )c",
+ {"-std=c23"}, "input.c");
+ ASSERT_TRUE(AST);
+
+ auto ExpectKnown = [&](const char *Name, bool Semantic, bool NonSemantic) {
+ const VarDecl *VD = getVariableNode(AST.get(), Name);
+ ASSERT_NE(VD, nullptr);
+ ASSERT_TRUE(VD->hasInit());
+ const Expr *Init = VD->getInit();
+ EXPECT_EQ(Semantic, Init->isKnownToHaveBooleanValue(true)) << Name;
+ EXPECT_EQ(NonSemantic, Init->isKnownToHaveBooleanValue(false)) << Name;
+ };
+
+ ExpectKnown("from_bool", true, true);
+ ExpectKnown("from_int", false, false);
+ ExpectKnown("from_signed_bitfield1", false, false);
+ ExpectKnown("from_bitfield1", false, true);
+ ExpectKnown("from_bitfield2", false, false);
+ ExpectKnown("from_bitint1", false, true);
+ ExpectKnown("from_bitint2", false, false);
+}
More information about the cfe-commits
mailing list