Skip to content

Conversation

@higher-performance
Copy link
Contributor

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;
};

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jul 14, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 14, 2025

@llvm/pr-subscribers-clang

Author: None (higher-performance)

Changes

This avoids crashing due to template-dependent bit widths, such as in the following:

template&lt;unsigned N&gt;
struct S {
        explicit S(bool x) : x(x) { }
        int x : N;
};

Full diff: https://github.com/llvm/llvm-project/pull/148692.diff

3 Files Affected:

  • (modified) clang/include/clang/AST/Decl.h (+5)
  • (modified) clang/include/clang/ASTMatchers/ASTMatchers.h (+2-1)
  • (modified) clang/lib/AST/Decl.cpp (+6-3)
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()

@cor3ntin
Copy link
Contributor

Can you add tests (and a release note) Thanks!

…ng the width, to avoid crashing inside templates
@higher-performance
Copy link
Contributor Author

Done.

@higher-performance higher-performance merged commit 859dcfc into llvm:main Jul 15, 2025
10 checks passed
@higher-performance higher-performance deleted the has-bit-width branch July 15, 2025 20:06
/// 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() &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you are only testing the Node.hasConstantIntegerBitWidth() == true case in the test below. If that is correct we should add a test that covers both cases and any other combinations of these conditions not covered by testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants