[clang] [Clang] Mark the declaration invalid when a function definition has no body (PR #218168)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Aug 30 14:48:15 PDT 2026
https://github.com/SoulTch updated https://github.com/llvm/llvm-project/pull/218168
>From f7bc746481505ceff87e0140e1d4de5c149b0e5d Mon Sep 17 00:00:00 2001
From: Jeongjin Lee <SoulTch at users.noreply.github.com>
Date: Sat, 22 Aug 2026 17:32:21 -0400
Subject: [PATCH 1/5] [Clang] Mark the declaration invalid when a function
definition has no body
Fixes #194298
Assisted-by: Claude Opus 5 (Claude Code)
---
clang/lib/Parse/ParseCXXInlineMethods.cpp | 1 +
clang/lib/Parse/ParseTemplate.cpp | 4 +++-
clang/lib/Parse/Parser.cpp | 2 ++
clang/test/SemaCXX/coroutines.cpp | 8 ++++++++
4 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 3f101feb26a6d..51591011ca548 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -633,6 +633,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
// Error recovery.
if (!Tok.is(tok::l_brace)) {
FnScope.Exit();
+ LM.D->getAsFunction()->setInvalidDecl();
Actions.ActOnFinishFunctionBody(LM.D, nullptr);
return;
}
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 7a3629ddc19a9..a174778307ada 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -1528,8 +1528,10 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
"current template being instantiated!");
ParseFunctionStatementBody(LPT.D, FnScope);
Actions.UnmarkAsLateParsedTemplate(FunD);
- } else
+ } else {
+ FunD->setInvalidDecl();
Actions.ActOnFinishFunctionBody(LPT.D, nullptr);
+ }
}
}
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index bad81ea92cd2d..5c39ba2ad71a1 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1407,6 +1407,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// Recover from error.
if (!Tok.is(tok::l_brace)) {
BodyScope.Exit();
+ if (Res)
+ Res->getAsFunction()->setInvalidDecl();
Actions.ActOnFinishFunctionBody(Res, nullptr);
return Res;
}
diff --git a/clang/test/SemaCXX/coroutines.cpp b/clang/test/SemaCXX/coroutines.cpp
index 4cef2f2b7ea0f..19b2ce1678e1f 100644
--- a/clang/test/SemaCXX/coroutines.cpp
+++ b/clang/test/SemaCXX/coroutines.cpp
@@ -1566,3 +1566,11 @@ void g() {
}
}
+
+namespace GH194298 {
+// https://github.com/llvm/llvm-project/issues/194298
+coro<promise_void> f1() : bar { co_await suspend_always{} }; // expected-error {{only constructors take base initializers}}
+coro<promise> f2() : bar { co_yield 0 }; // expected-error {{only constructors take base initializers}}
+coro<promise_void> f3() : bar { co_return }; // expected-error {{expected expression}} \
+ // expected-error {{only constructors take base initializers}}
+}
>From 6d20dada8a5462eb876883ab2e56477cf4b7bcf5 Mon Sep 17 00:00:00 2001
From: SoulTch <drilsteal2015 at gmail.com>
Date: Sun, 23 Aug 2026 21:08:57 -0400
Subject: [PATCH 2/5] Add coroutine tests for base initializers
Added test cases for coroutine base initializers.
---
clang/test/SemaCXX/coroutines.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/test/SemaCXX/coroutines.cpp b/clang/test/SemaCXX/coroutines.cpp
index 19b2ce1678e1f..207378256859d 100644
--- a/clang/test/SemaCXX/coroutines.cpp
+++ b/clang/test/SemaCXX/coroutines.cpp
@@ -1568,7 +1568,6 @@ void g() {
}
namespace GH194298 {
-// https://github.com/llvm/llvm-project/issues/194298
coro<promise_void> f1() : bar { co_await suspend_always{} }; // expected-error {{only constructors take base initializers}}
coro<promise> f2() : bar { co_yield 0 }; // expected-error {{only constructors take base initializers}}
coro<promise_void> f3() : bar { co_return }; // expected-error {{expected expression}} \
>From d456fa79ce697834b41c73d587d6f0ace167df81 Mon Sep 17 00:00:00 2001
From: Jeongjin Lee <SoulTch at users.noreply.github.com>
Date: Wed, 26 Aug 2026 16:52:07 -0400
Subject: [PATCH 3/5] [Clang] Factor out function body parsing into
Parser::ParseFunctionBody
Assisted-by: Claude Opus 5 (Claude Code)
---
clang/include/clang/Parse/Parser.h | 11 ++++++++
clang/lib/Parse/ParseCXXInlineMethods.cpp | 19 +-------------
clang/lib/Parse/ParseTemplate.cpp | 31 +++++++----------------
clang/lib/Parse/Parser.cpp | 20 +++++++++------
4 files changed, 33 insertions(+), 48 deletions(-)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index ae91153e34e3a..6913c42884a36 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -7738,6 +7738,17 @@ class Parser : public CodeCompletionHandler {
///
Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope);
+ /// ParseFunctionBody - Parse the body of a function definition. The
+ /// '= default' and '= delete' forms are handled by the caller.
+ ///
+ /// \verbatim
+ /// function-body:
+ /// ctor-initializer[opt] compound-statement
+ /// function-try-block
+ /// \endverbatim
+ ///
+ Decl *ParseFunctionBody(Decl *D, ParseScope &BodyScope);
+
/// When in code-completion, skip parsing of the function/method body
/// unless the body contains the code-completion point.
///
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 51591011ca548..0340540b239cd 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -623,23 +623,6 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
Actions.ActOnFinishInlineFunctionDef(FD);
});
- if (Tok.is(tok::kw_try)) {
- ParseFunctionTryBlock(LM.D, FnScope);
- return;
- }
- if (Tok.is(tok::colon)) {
- ParseConstructorInitializer(LM.D);
-
- // Error recovery.
- if (!Tok.is(tok::l_brace)) {
- FnScope.Exit();
- LM.D->getAsFunction()->setInvalidDecl();
- Actions.ActOnFinishFunctionBody(LM.D, nullptr);
- return;
- }
- } else
- Actions.ActOnDefaultCtorInitializers(LM.D);
-
assert((Actions.getDiagnostics().hasErrorOccurred() ||
!isa<FunctionTemplateDecl>(LM.D) ||
cast<FunctionTemplateDecl>(LM.D)->getTemplateParameters()->getDepth()
@@ -647,7 +630,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
"TemplateParameterDepth should be greater than the depth of "
"current template being instantiated!");
- ParseFunctionStatementBody(LM.D, FnScope);
+ ParseFunctionBody(LM.D, FnScope);
}
void Parser::ParseLexedMemberInitializers(ParsingClass &Class) {
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index a174778307ada..ea2b44c359944 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -1511,28 +1511,15 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
Actions.ActOnStartOfFunctionDef(getCurScope(), FunD);
- if (Tok.is(tok::kw_try)) {
- ParseFunctionTryBlock(LPT.D, FnScope);
- } else {
- if (Tok.is(tok::colon))
- ParseConstructorInitializer(LPT.D);
- else
- Actions.ActOnDefaultCtorInitializers(LPT.D);
-
- if (Tok.is(tok::l_brace)) {
- assert((!isa<FunctionTemplateDecl>(LPT.D) ||
- cast<FunctionTemplateDecl>(LPT.D)
- ->getTemplateParameters()
- ->getDepth() == TemplateParameterDepth - 1) &&
- "TemplateParameterDepth should be greater than the depth of "
- "current template being instantiated!");
- ParseFunctionStatementBody(LPT.D, FnScope);
- Actions.UnmarkAsLateParsedTemplate(FunD);
- } else {
- FunD->setInvalidDecl();
- Actions.ActOnFinishFunctionBody(LPT.D, nullptr);
- }
- }
+ assert((!isa<FunctionTemplateDecl>(LPT.D) ||
+ cast<FunctionTemplateDecl>(LPT.D)
+ ->getTemplateParameters()
+ ->getDepth() == TemplateParameterDepth - 1) &&
+ "TemplateParameterDepth should be greater than the depth of "
+ "current template being instantiated!");
+
+ ParseFunctionBody(LPT.D, FnScope);
+ Actions.UnmarkAsLateParsedTemplate(FunD);
}
void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) {
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 5c39ba2ad71a1..3685de2d5aa28 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1396,26 +1396,30 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
return Actions.ActOnFinishFunctionBody(Res, nullptr, false);
}
+ return ParseFunctionBody(Res, BodyScope);
+}
+
+Decl *Parser::ParseFunctionBody(Decl *D, ParseScope &BodyScope) {
if (Tok.is(tok::kw_try))
- return ParseFunctionTryBlock(Res, BodyScope);
+ return ParseFunctionTryBlock(D, BodyScope);
// If we have a colon, then we're probably parsing a C++
// ctor-initializer.
if (Tok.is(tok::colon)) {
- ParseConstructorInitializer(Res);
+ ParseConstructorInitializer(D);
// Recover from error.
if (!Tok.is(tok::l_brace)) {
BodyScope.Exit();
- if (Res)
- Res->getAsFunction()->setInvalidDecl();
- Actions.ActOnFinishFunctionBody(Res, nullptr);
- return Res;
+ if (D)
+ D->getAsFunction()->setInvalidDecl();
+ Actions.ActOnFinishFunctionBody(D, nullptr);
+ return D;
}
} else
- Actions.ActOnDefaultCtorInitializers(Res);
+ Actions.ActOnDefaultCtorInitializers(D);
- return ParseFunctionStatementBody(Res, BodyScope);
+ return ParseFunctionStatementBody(D, BodyScope);
}
void Parser::SkipFunctionBody() {
>From 64188a5cbb132c3cbeb5b5d63f217bb5b313c643 Mon Sep 17 00:00:00 2001
From: Jeongjin Lee <SoulTch at users.noreply.github.com>
Date: Sun, 30 Aug 2026 16:38:17 -0400
Subject: [PATCH 4/5] [Clang] Add release note for #194298
Assisted-by: Claude Opus 5 (Claude Code)
---
clang/docs/ReleaseNotes.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index bdbabf2cd98d0..1b3f3cc62668f 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -551,6 +551,9 @@ features cannot lower the translation-unit ABI level;
inside a union caused the union to be treated as a polymorphic class.
(#GH213854)
+- Fixed a crash when a coroutine keyword appeared inside a mem-initializer on a
+ function that is not a constructor. (#GH194298)
+
#### Bug Fixes to AST Handling
- Fixed a non-deterministic ordering of unused local typedefs that made
>From 3b73672045cf6b2dc3e3a4de62114ba3d6e4de67 Mon Sep 17 00:00:00 2001
From: Jeongjin Lee <SoulTch at users.noreply.github.com>
Date: Sun, 30 Aug 2026 17:30:49 -0400
Subject: [PATCH 5/5] [Clang] Use ParseFunctionBody in ParseLexedObjCMethodDefs
Assisted-by: Claude Opus 5 (Claude Code)
---
clang/lib/Parse/ParseObjc.cpp | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index d01b0abf917cb..b265b8afac920 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -3306,15 +3306,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
Actions.ObjC().ActOnStartOfObjCMethodDef(getCurScope(), MCDecl);
else
Actions.ActOnStartOfFunctionDef(getCurScope(), MCDecl);
- if (Tok.is(tok::kw_try))
- ParseFunctionTryBlock(MCDecl, BodyScope);
- else {
- if (Tok.is(tok::colon))
- ParseConstructorInitializer(MCDecl);
- else
- Actions.ActOnDefaultCtorInitializers(MCDecl);
- ParseFunctionStatementBody(MCDecl, BodyScope);
- }
+ ParseFunctionBody(MCDecl, BodyScope);
if (Tok.getLocation() != OrigLoc) {
// Due to parsing error, we either went over the cached tokens or
More information about the cfe-commits
mailing list