https://github.com/AditiRM updated https://github.com/llvm/llvm-project/pull/208153
>From 78b861d62b432d17881243a6eb3854a7de23258f Mon Sep 17 00:00:00 2001 From: AditiRM <[email protected]> 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 <[email protected]> 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@+1 {{explicit specialization of 'Y' after instantiation}} +template <> struct X<int>::Y { int getValue() { return 55; } }; +// expected-note@-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 <[email protected]> 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 { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
