[clang] [Clang] Fix assertion failure in getASTRecordLayout for invalid declarations (PR #208153)
Aditi Medhane via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 8 23:32:23 PDT 2026
https://github.com/AditiRM updated https://github.com/llvm/llvm-project/pull/208153
>From 78b861d62b432d17881243a6eb3854a7de23258f Mon Sep 17 00:00:00 2001
From: AditiRM <aditimedhane73 at gmail.com>
Date: Wed, 8 Jul 2026 07:09:35 +0000
Subject: [PATCH 1/3] [Clang] Fix assertion failure in getASTRecordLayout
---
clang/lib/AST/RecordLayoutBuilder.cpp | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 854f88f20b2b6..6b5027772885d 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -3384,6 +3384,32 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
// not a complete definition (which is what isCompleteDefinition() tests)
// until we *finish* parsing the definition.
D = D->getDefinition();
+
+ // Handle invalid declarations gracefully during error recovery
+ // This can happen when there are template specialization errors
+ if (!D || D->isInvalidDecl() || !D->isCompleteDefinition()) {
+ // Check if we already have a cached layout
+ const ASTRecordLayout *Entry = ASTRecordLayouts[D];
+ if (Entry)
+ return *Entry;
+
+ // Create a minimal safe layout for error recovery
+ // Use 1-byte size and alignment to avoid division by zero or other issues
+ ASTRecordLayout *NewEntry = new (*this)
+ ASTRecordLayout(*this,
+ CharUnits::One(), // Size = 1 byte
+ CharUnits::One(), // Alignment = 1 byte
+ CharUnits::One(), // PreferredAlignment = 1 byte
+ CharUnits::One(), // UnadjustedAlignment = 1 byte
+ CharUnits::One(), // RequiredAlignment = 1 byte
+ CharUnits::One(), // DataSize = 1 byte
+ ArrayRef<uint64_t>() // Empty field offsets
+ );
+
+ ASTRecordLayouts[D] = NewEntry;
+ return *NewEntry;
+ }
+
assert(D && "Cannot get layout of forward declarations!");
assert(!D->isInvalidDecl() && "Cannot get layout of invalid decl!");
assert(D->isCompleteDefinition() && "Cannot layout type before complete!");
>From e3959f499ea4f8a9e35c922a5fc93332e844396a Mon Sep 17 00:00:00 2001
From: AditiRM <aditimedhane73 at gmail.com>
Date: Wed, 8 Jul 2026 10:41:10 +0000
Subject: [PATCH 2/3] Add testcase triggering the assert failure
---
...ecialization-after-instantiation-crash.cpp | 42 +++++++++++++++++++
1 file changed, 42 insertions(+)
create mode 100644 clang/test/SemaCXX/explicit-specialization-after-instantiation-crash.cpp
diff --git a/clang/test/SemaCXX/explicit-specialization-after-instantiation-crash.cpp b/clang/test/SemaCXX/explicit-specialization-after-instantiation-crash.cpp
new file mode 100644
index 0000000000000..37b00db4d3877
--- /dev/null
+++ b/clang/test/SemaCXX/explicit-specialization-after-instantiation-crash.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+//
+// Test that explicit template specialization after instantiation
+// is handled gracefully without assertion failure.
+//
+// Before the fix, this code triggered an assertion failure:
+// Assertion failed: !D->isInvalidDecl() && "Cannot get layout of invalid decl!"
+// Location: clang/lib/AST/RecordLayoutBuilder.cpp:3388
+// Exit code: 134 (SIGABRT)
+//
+// After the fix:
+// Clean error messages are reported
+// Exit code: 1
+//
+// The fix adds error handling in getASTRecordLayout() to return a minimal
+// safe layout (1-byte size/alignment) for invalid declarations, allowing
+// error recovery to continue and report all errors.
+
+template <typename T>
+struct X {
+ struct Y {
+ Y() : v(0) {}
+ int v;
+ int getValue();
+ } y;
+};
+
+template <typename T>
+int X<T>::Y::getValue() {
+ return ++v;
+}
+
+// expected-error at +1 {{explicit specialization of 'Y' after instantiation}}
+template <> struct X<int>::Y { int getValue() { return 55; } };
+// expected-note at -10 {{implicit instantiation first required here}}
+
+extern template class X<int>::Y;
+
+int main() {
+ X<int> x;
+ return x.y.getValue(); // expected-error {{no member named 'getValue' in 'X<int>::Y'}}
+}
>From aa8c8a24b524d13c0717e525ca41ded48fe2814f Mon Sep 17 00:00:00 2001
From: AditiRM <aditimedhane73 at gmail.com>
Date: Thu, 9 Jul 2026 06:48:14 +0000
Subject: [PATCH 3/3] [neat] review changes
---
clang/lib/AST/RecordLayoutBuilder.cpp | 4 ----
...cit-specialization-after-instantiation-crash.cpp | 13 -------------
2 files changed, 17 deletions(-)
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 6b5027772885d..662e76ab7cfd2 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -3410,10 +3410,6 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
return *NewEntry;
}
- assert(D && "Cannot get layout of forward declarations!");
- assert(!D->isInvalidDecl() && "Cannot get layout of invalid decl!");
- assert(D->isCompleteDefinition() && "Cannot layout type before complete!");
-
// Look up this layout, if already laid out, return what we have.
// Note that we can't save a reference to the entry because this function
// is recursive.
diff --git a/clang/test/SemaCXX/explicit-specialization-after-instantiation-crash.cpp b/clang/test/SemaCXX/explicit-specialization-after-instantiation-crash.cpp
index 37b00db4d3877..8f78ea6535d07 100644
--- a/clang/test/SemaCXX/explicit-specialization-after-instantiation-crash.cpp
+++ b/clang/test/SemaCXX/explicit-specialization-after-instantiation-crash.cpp
@@ -2,19 +2,6 @@
//
// Test that explicit template specialization after instantiation
// is handled gracefully without assertion failure.
-//
-// Before the fix, this code triggered an assertion failure:
-// Assertion failed: !D->isInvalidDecl() && "Cannot get layout of invalid decl!"
-// Location: clang/lib/AST/RecordLayoutBuilder.cpp:3388
-// Exit code: 134 (SIGABRT)
-//
-// After the fix:
-// Clean error messages are reported
-// Exit code: 1
-//
-// The fix adds error handling in getASTRecordLayout() to return a minimal
-// safe layout (1-byte size/alignment) for invalid declarations, allowing
-// error recovery to continue and report all errors.
template <typename T>
struct X {
More information about the cfe-commits
mailing list