[clang] [clang] Reject invalid record declarations in builtin bit_cast checks (PR #235341)

via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 25 04:03:33 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Daniel Petrovic (daniel-petrovic)

<details>
<summary>Changes</summary>

Prevent crash when evaluating  builtin bit_cast with invalid record types. 
The crash is caused by the unconditional recursive call  in constexpr eligibility check.
This fix checks RecordDecl::isInvalidDecl() before the recursive call in constexpr evaluator as well as in bytecode interpreter.

Fixes: #<!-- -->235252

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


3 Files Affected:

- (modified) clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp (+2) 
- (modified) clang/lib/AST/ExprConstant.cpp (+2) 
- (modified) clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp (+15) 


``````````diff
diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
index 3bec4f3bf1396b..ebaf4ecb2da637 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
@@ -295,6 +295,8 @@ static bool CheckBitcastType(InterpState &S, CodePtr OpPC, QualType T,
     return diag(E_Volatile);
 
   if (const RecordDecl *RD = T->getAsRecordDecl()) {
+    if (RD->isInvalidDecl())
+      return false;
     if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
       for (const CXXBaseSpecifier &BS : CXXRD->bases()) {
         if (!CheckBitcastType(S, OpPC, BS.getType(), IsToType))
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 3762bc83c779b0..d8e3b0538a9bb8 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -8604,6 +8604,8 @@ static bool checkBitCastConstexprEligibilityType(SourceLocation Loc,
     return diag(3);
 
   if (RecordDecl *Record = Ty->getAsRecordDecl()) {
+    if (Record->isInvalidDecl())
+      return false;
     if (auto *CXXRD = dyn_cast<CXXRecordDecl>(Record)) {
       for (CXXBaseSpecifier &BS : CXXRD->bases())
         if (!checkBitCastConstexprEligibilityType(Loc, BS.getType(), Info, Ctx,
diff --git a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp
index ea5333df0b4698..09a53ea6d4ea54 100644
--- a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp
+++ b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp
@@ -550,3 +550,18 @@ namespace InvalidBaseClass {
   };
   static_assert(__builtin_bit_cast(char, E()) == 0); // expected-error {{not an integral constant expression}}
 }
+
+namespace InvalidRecord {
+  template <class To, class From>
+  constexpr To cast(const From& from) {
+    __builtin_bit_cast(To, from); // expected-warning {{expression result unused}}
+  }
+
+  struct S { // expected-note {{definition of 'InvalidRecord::S' is not complete until the closing '}'}}
+    S s;  // expected-error {{field has incomplete type 'S'}}
+    enum E { e } E;
+  };
+
+  static_assert(cast<S>((char)42).E == S::E::e); // expected-error {{static assertion expression is not an integral constant expression}}
+                                                 // expected-note at -1 {{in instantiation of function template specialization 'InvalidRecord::cast<InvalidRecord::S, char>' requested here}}
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/235341


More information about the cfe-commits mailing list