Skip to content

Commit 859dcfc

Browse files
Check if clang::FieldDecl has constant-integer bit width before getting the width (#148692)
This avoids crashing due to template-dependent bit widths
1 parent ba95df1 commit 859dcfc

File tree

5 files changed

+28
-4
lines changed

5 files changed

+28
-4
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,8 @@ Fixed Point Support in Clang
11461146
AST Matchers
11471147
------------
11481148

1149+
- Ensure ``hasBitWidth`` doesn't crash on bit widths that are dependent on template
1150+
parameters.
11491151
- Ensure ``isDerivedFrom`` matches the correct base in case more than one alias exists.
11501152
- Extend ``templateArgumentCountIs`` to support function and variable template
11511153
specialization.

clang/include/clang/AST/Decl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3252,6 +3252,11 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
32523252
return hasInClassInitializer() ? InitAndBitWidth->BitWidth : BitWidth;
32533253
}
32543254

3255+
/// Determines whether the bit width of this field is a constant integer.
3256+
/// This may not always be the case, such as inside template-dependent
3257+
/// expressions.
3258+
bool hasConstantIntegerBitWidth() const;
3259+
32553260
/// Computes the bit width of this field, if this is a bit field.
32563261
/// May not be called on non-bitfields.
32573262
/// Note that in order to successfully use this function, the bitwidth

clang/include/clang/ASTMatchers/ASTMatchers.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,8 @@ AST_MATCHER(FieldDecl, isBitField) {
710710
/// fieldDecl(hasBitWidth(2))
711711
/// matches 'int a;' and 'int c;' but not 'int b;'.
712712
AST_MATCHER_P(FieldDecl, hasBitWidth, unsigned, Width) {
713-
return Node.isBitField() && Node.getBitWidthValue() == Width;
713+
return Node.isBitField() && Node.hasConstantIntegerBitWidth() &&
714+
Node.getBitWidthValue() == Width;
714715
}
715716

716717
/// Matches non-static data members that have an in-class initializer.

clang/lib/AST/Decl.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4677,11 +4677,14 @@ void FieldDecl::setLazyInClassInitializer(LazyDeclStmtPtr NewInit) {
46774677
Init = NewInit;
46784678
}
46794679

4680+
bool FieldDecl::hasConstantIntegerBitWidth() const {
4681+
const auto *CE = dyn_cast_if_present<ConstantExpr>(getBitWidth());
4682+
return CE && CE->getAPValueResult().isInt();
4683+
}
4684+
46804685
unsigned FieldDecl::getBitWidthValue() const {
46814686
assert(isBitField() && "not a bitfield");
4682-
assert(isa<ConstantExpr>(getBitWidth()));
4683-
assert(cast<ConstantExpr>(getBitWidth())->hasAPValueResult());
4684-
assert(cast<ConstantExpr>(getBitWidth())->getAPValueResult().isInt());
4687+
assert(hasConstantIntegerBitWidth());
46854688
return cast<ConstantExpr>(getBitWidth())
46864689
->getAPValueResult()
46874690
.getInt()

clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2925,6 +2925,19 @@ TEST_P(ASTMatchersTest, IsBitField) {
29252925
fieldDecl(isBitField(), hasName("b"))));
29262926
EXPECT_TRUE(matches("struct C { int a : 2; int b : 4; };",
29272927
fieldDecl(isBitField(), hasBitWidth(2), hasName("a"))));
2928+
if (GetParam().isCXX()) {
2929+
// This test verifies 2 things:
2930+
// (1) That templates work correctly.
2931+
// (2) That the matcher does not crash on template-dependent bit widths.
2932+
EXPECT_TRUE(matches("template<int N> "
2933+
"struct C { "
2934+
"explicit C(bool x) : a(x) { } "
2935+
"int a : N; "
2936+
"int b : 4; "
2937+
"}; "
2938+
"template struct C<2>;",
2939+
fieldDecl(isBitField(), hasBitWidth(2), hasName("a"))));
2940+
}
29282941
}
29292942

29302943
TEST_P(ASTMatchersTest, HasInClassInitializer) {

0 commit comments

Comments
 (0)