[clang] [Clang] add ext warning for missing return in 'main' for C89 mode (PR #134617)
Oleksandr T. via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 7 04:38:16 PDT 2025
https://github.com/a-tarasyuk created https://github.com/llvm/llvm-project/pull/134617
Fixes #21650
---
Clang currently inserts an implicit `return 0;` in `main()` when compiling in `C89` mode, even though the `C89` standard doesn't require this behavior. This patch changes that behavior by emitting a warning instead of silently inserting the implicit return under `-pedantic`.
>From 64210203803f7ba9deec06d467ee570bff761108 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Sun, 6 Apr 2025 00:17:38 +0300
Subject: [PATCH] [Clang] add ext warning for missing return in 'main' for C89
mode
---
clang/docs/ReleaseNotes.rst | 1 +
.../clang/Basic/DiagnosticSemaKinds.td | 2 ++
clang/lib/Sema/AnalysisBasedWarnings.cpp | 27 +++++++++++--------
clang/lib/Sema/SemaDecl.cpp | 4 ++-
clang/test/Sema/main-no-return-c89.c | 6 +++++
5 files changed, 28 insertions(+), 12 deletions(-)
create mode 100644 clang/test/Sema/main-no-return-c89.c
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5217e04b5e83f..6227b6133da0b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -318,6 +318,7 @@ Improvements to Clang's diagnostics
- ``-Wc++98-compat`` no longer diagnoses use of ``__auto_type`` or
``decltype(auto)`` as though it was the extension for ``auto``. (#GH47900)
+- Clang now issues a warning for missing return in ``main`` in C89 mode. (#GH21650)
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 393bfecf9a36b..34f2ee883ca63 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1031,6 +1031,8 @@ def err_mainlike_template_decl : Error<"%0 cannot be a template">;
def err_main_returns_nonint : Error<"'main' must return 'int'">;
def ext_main_returns_nonint : ExtWarn<"return type of 'main' is not 'int'">,
InGroup<MainReturnType>;
+def ext_main_no_return : Extension<"non-void 'main' function does not return a value">,
+ InGroup<MainReturnType>;
def note_main_change_return_type : Note<"change return type to 'int'">;
def err_main_surplus_args : Error<"too many parameters (%0) for 'main': "
"must be 0, 2, or 3">;
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 3d6da4f70f99e..38aa3f0edf718 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -550,7 +550,8 @@ struct CheckFallThroughDiagnostics {
unsigned FunKind; // TODO: use diag::FalloffFunctionKind
SourceLocation FuncLoc;
- static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) {
+ static CheckFallThroughDiagnostics MakeForFunction(Sema &S,
+ const Decl *Func) {
CheckFallThroughDiagnostics D;
D.FuncLoc = Func->getLocation();
D.diag_FallThrough_HasNoReturn = diag::warn_noreturn_has_return_expr;
@@ -564,8 +565,13 @@ struct CheckFallThroughDiagnostics {
// Don't suggest that template instantiations be marked "noreturn"
bool isTemplateInstantiation = false;
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func))
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) {
isTemplateInstantiation = Function->isTemplateInstantiation();
+ if (!S.getLangOpts().CPlusPlus && !S.getLangOpts().C99 &&
+ Function->isMain()) {
+ D.diag_FallThrough_ReturnsNonVoid = diag::ext_main_no_return;
+ }
+ }
if (!isVirtualMethod && !isTemplateInstantiation)
D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function;
@@ -2737,15 +2743,14 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
// Warning: check missing 'return'
if (P.enableCheckFallThrough) {
const CheckFallThroughDiagnostics &CD =
- (isa<BlockDecl>(D)
- ? CheckFallThroughDiagnostics::MakeForBlock()
- : (isa<CXXMethodDecl>(D) &&
- cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&
- cast<CXXMethodDecl>(D)->getParent()->isLambda())
- ? CheckFallThroughDiagnostics::MakeForLambda()
- : (fscope->isCoroutine()
- ? CheckFallThroughDiagnostics::MakeForCoroutine(D)
- : CheckFallThroughDiagnostics::MakeForFunction(D)));
+ (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
+ : (isa<CXXMethodDecl>(D) &&
+ cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&
+ cast<CXXMethodDecl>(D)->getParent()->isLambda())
+ ? CheckFallThroughDiagnostics::MakeForLambda()
+ : (fscope->isCoroutine()
+ ? CheckFallThroughDiagnostics::MakeForCoroutine(D)
+ : CheckFallThroughDiagnostics::MakeForFunction(S, D)));
CheckFallThroughForBody(S, D, Body, BlockType, CD, AC);
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index d630f9bd409fd..b020a1b2fd3e0 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16230,7 +16230,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// If the function implicitly returns zero (like 'main') or is naked,
// don't complain about missing return statements.
- if (FD->hasImplicitReturnZero() || FD->hasAttr<NakedAttr>())
+ if ((FD->hasImplicitReturnZero() &&
+ (getLangOpts().CPlusPlus || getLangOpts().C99 || !FD->isMain())) ||
+ FD->hasAttr<NakedAttr>())
WP.disableCheckFallThrough();
// MSVC permits the use of pure specifier (=0) on function definition,
diff --git a/clang/test/Sema/main-no-return-c89.c b/clang/test/Sema/main-no-return-c89.c
new file mode 100644
index 0000000000000..19d55916fc833
--- /dev/null
+++ b/clang/test/Sema/main-no-return-c89.c
@@ -0,0 +1,6 @@
+/* RUN: %clang_cc1 -std=c89 -fsyntax-only -verify -pedantic -Wno-strict-prototypes %s
+ */
+
+int main() {
+
+} /* expected-warning {{non-void 'main' function does not return a value}} */
More information about the cfe-commits
mailing list