[clang] Check if clang::FieldDecl has constant-integer bit width before getting the width (PR #148692)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 14 11:07:45 PDT 2025
https://github.com/higher-performance created https://github.com/llvm/llvm-project/pull/148692
This avoids crashing due to template-dependent bit widths, such as in the following:
```
template<unsigned N>
struct S {
explicit S(bool x) : x(x) { }
int x : N;
};
```
>From 715aacbcafd894b72364f6fb7181057f6f1fa4c6 Mon Sep 17 00:00:00 2001
From: higher-performance <higher.performance.github at gmail.com>
Date: Mon, 14 Jul 2025 14:05:07 -0400
Subject: [PATCH] Check if clang::FieldDecl has constant-integer bit width
before getting the width, to avoid crashing inside templates
---
clang/include/clang/AST/Decl.h | 5 +++++
clang/include/clang/ASTMatchers/ASTMatchers.h | 3 ++-
clang/lib/AST/Decl.cpp | 9 ++++++---
3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index f70a039bf3517..f88c206ca4d44 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3234,6 +3234,11 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
return hasInClassInitializer() ? InitAndBitWidth->BitWidth : BitWidth;
}
+ /// Determines whether the bit width of this field is a constant integer.
+ /// This may not always be the case, such as inside template-dependent
+ /// expressions.
+ bool hasConstantIntegerBitWidth() const;
+
/// Computes the bit width of this field, if this is a bit field.
/// May not be called on non-bitfields.
/// Note that in order to successfully use this function, the bitwidth
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index bae004896c11f..fcce9b5c38b23 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -709,7 +709,8 @@ AST_MATCHER(FieldDecl, isBitField) {
/// fieldDecl(hasBitWidth(2))
/// matches 'int a;' and 'int c;' but not 'int b;'.
AST_MATCHER_P(FieldDecl, hasBitWidth, unsigned, Width) {
- return Node.isBitField() && Node.getBitWidthValue() == Width;
+ return Node.isBitField() && Node.hasConstantIntegerBitWidth() &&
+ Node.getBitWidthValue() == Width;
}
/// Matches non-static data members that have an in-class initializer.
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 8855d0107daca..f4cb5a026e25f 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -4677,11 +4677,14 @@ void FieldDecl::setLazyInClassInitializer(LazyDeclStmtPtr NewInit) {
Init = NewInit;
}
+bool FieldDecl::hasConstantIntegerBitWidth() const {
+ const auto *CE = dyn_cast_if_present<ConstantExpr>(getBitWidth());
+ return CE && CE->getAPValueResult().isInt();
+}
+
unsigned FieldDecl::getBitWidthValue() const {
assert(isBitField() && "not a bitfield");
- assert(isa<ConstantExpr>(getBitWidth()));
- assert(cast<ConstantExpr>(getBitWidth())->hasAPValueResult());
- assert(cast<ConstantExpr>(getBitWidth())->getAPValueResult().isInt());
+ assert(hasConstantIntegerBitWidth());
return cast<ConstantExpr>(getBitWidth())
->getAPValueResult()
.getInt()
More information about the cfe-commits
mailing list