https://github.com/AaronBallman created 
https://github.com/llvm/llvm-project/pull/140925

There are two related issues being fixed in this patch. Both issues relate to 
use of an invalid structure which contains a member that we error recover such 
that the field has the same type as the structure. In both cases, we would hit 
an infinite loop while analyzing the fields because the type of the field 
matches the type of the record.

Fixes #140887

>From 074aba253c2981d009c1c18f82e5ca1ad4ce960c Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aa...@aaronballman.com>
Date: Wed, 21 May 2025 12:15:03 -0400
Subject: [PATCH] [C] Fix crash-on-invalid due to infinite recursion

There are two related issues being fixed in this patch. Both issues
relate to use of an invalid structure which contains a member that we
error recover such that the field has the same type as the structure.
In both cases, we would hit an infinite loop while analyzing the fields
because the type of the field matches the type of the record.

Fixes #140887
---
 clang/docs/ReleaseNotes.rst                     |  2 ++
 clang/lib/Sema/SemaDecl.cpp                     |  3 ++-
 clang/lib/Sema/SemaInit.cpp                     |  2 +-
 clang/test/Sema/c2y-invalid-constexpr.c         | 12 ++++++++++++
 clang/test/Sema/warn-default-const-init-crash.c | 11 +++++++++++
 5 files changed, 28 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/Sema/c2y-invalid-constexpr.c
 create mode 100644 clang/test/Sema/warn-default-const-init-crash.c

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b466f3758e0b6..f53d75456c09a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -273,6 +273,8 @@ C23 Feature Support
   be completed).
 - Fixed a failed assertion with an invalid parameter to the ``#embed``
   directive. Fixes #GH126940.
+- Fixed a crash when a declaration of a ``constexpr`` variable with an invalid
+  type. Fixes #GH140887
 
 C11 Feature Support
 ^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index cb81ac889e480..814f81cb64cae 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -8681,7 +8681,8 @@ static bool CheckC23ConstexprVarType(Sema &SemaRef, 
SourceLocation VarLoc,
 
   if (CanonT->isRecordType()) {
     const RecordDecl *RD = CanonT->getAsRecordDecl();
-    if (llvm::any_of(RD->fields(), [&SemaRef, VarLoc](const FieldDecl *F) {
+    if (!RD->isInvalidDecl() &&
+        llvm::any_of(RD->fields(), [&SemaRef, VarLoc](const FieldDecl *F) {
           return CheckC23ConstexprVarType(SemaRef, VarLoc, F->getType());
         }))
       return true;
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 3c3f796044471..935c4da8ef1d4 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6618,7 +6618,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
       // initializer present. However, we only do this for structure types, not
       // union types, because an unitialized field in a union is generally
       // reasonable, especially in C where unions can be used for type punning.
-      if (!Initializer && !Rec->isUnion()) {
+      if (!Initializer && !Rec->isUnion() && !Rec->isInvalidDecl()) {
         if (const FieldDecl *FD = getConstField(Rec)) {
           unsigned DiagID = diag::warn_default_init_const_field_unsafe;
           if (Var->getStorageDuration() == SD_Static ||
diff --git a/clang/test/Sema/c2y-invalid-constexpr.c 
b/clang/test/Sema/c2y-invalid-constexpr.c
new file mode 100644
index 0000000000000..166827d0a7184
--- /dev/null
+++ b/clang/test/Sema/c2y-invalid-constexpr.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c23 %s
+
+// This was previously causing a stack overflow when checking the valid
+// declaration of an invalid type. Ensure we issue reasonable diagnostics
+// instead of crashing.
+struct GH140887 { // expected-note {{definition of 'struct GH140887' is not 
complete until the closing '}'}}
+  GH140887();     // expected-error {{must use 'struct' tag to refer to type 
'GH140887'}} \
+                     expected-error {{expected member name or ';' after 
declaration specifiers}} \
+                     expected-error {{field has incomplete type 'struct 
GH140887'}}
+};
+constexpr struct GH140887 a; // expected-error {{constexpr variable 'a' must 
be initialized by a constant expression}}
+
diff --git a/clang/test/Sema/warn-default-const-init-crash.c 
b/clang/test/Sema/warn-default-const-init-crash.c
new file mode 100644
index 0000000000000..4a2c858af6c82
--- /dev/null
+++ b/clang/test/Sema/warn-default-const-init-crash.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// This invalid code was causing a stack overflow, check that we issue
+// reasonable diagnostics and not crash.
+struct GH140887 {    // expected-note {{definition of 'struct GH140887' is not 
complete until the closing '}'}}
+  struct GH140887 s; // expected-error {{field has incomplete type 'struct 
GH140887'}}
+};
+
+void gh140887() {
+  struct GH140887 s;
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to