https://github.com/higher-performance updated https://github.com/llvm/llvm-project/pull/148692
>From 668c02da2d472c6d13981cd7fdb258419d0ffb05 Mon Sep 17 00:00:00 2001 From: higher-performance <higher.performance.git...@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/docs/ReleaseNotes.rst | 2 ++ clang/include/clang/AST/Decl.h | 5 +++++ clang/include/clang/ASTMatchers/ASTMatchers.h | 3 ++- clang/lib/AST/Decl.cpp | 9 ++++++--- .../ASTMatchers/ASTMatchersNarrowingTest.cpp | 13 +++++++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 57a94242c9e61..0171fb03505cc 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1088,6 +1088,8 @@ Fixed Point Support in Clang AST Matchers ------------ +- Ensure ``hasBitWidth`` doesn't crash on bit widths that are dependent on template + parameters. - Ensure ``isDerivedFrom`` matches the correct base in case more than one alias exists. - Extend ``templateArgumentCountIs`` to support function and variable template specialization. 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() diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index 49abe881eeabb..287122393446d 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -2925,6 +2925,19 @@ TEST_P(ASTMatchersTest, IsBitField) { fieldDecl(isBitField(), hasName("b")))); EXPECT_TRUE(matches("struct C { int a : 2; int b : 4; };", fieldDecl(isBitField(), hasBitWidth(2), hasName("a")))); + if (GetParam().isCXX()) { + // This test verifies 2 things: + // (1) That templates work correctly. + // (2) That the matcher does not crash on template-dependent bit widths. + EXPECT_TRUE(matches("template<int N> " + "struct C { " + "explicit C(bool x) : a(x) { } " + "int a : N; " + "int b : 4; " + "}; " + "template struct C<2>;", + fieldDecl(isBitField(), hasBitWidth(2), hasName("a")))); + } } TEST_P(ASTMatchersTest, HasInClassInitializer) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits