Skip to content

[Clang] add ext warning for missing return in 'main' for C89 mode#134617

Merged
a-tarasyuk merged 8 commits into
llvm:mainfrom
a-tarasyuk:fix/21650
Apr 8, 2025
Merged

[Clang] add ext warning for missing return in 'main' for C89 mode#134617
a-tarasyuk merged 8 commits into
llvm:mainfrom
a-tarasyuk:fix/21650

Conversation

@a-tarasyuk

Copy link
Copy Markdown
Member

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.

@a-tarasyuk a-tarasyuk requested a review from AaronBallman April 7, 2025 11:38
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Apr 7, 2025
@llvmbot

llvmbot commented Apr 7, 2025

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-clang

Author: Oleksandr T. (a-tarasyuk)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/134617.diff

5 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+1)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2)
  • (modified) clang/lib/Sema/AnalysisBasedWarnings.cpp (+16-11)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+3-1)
  • (added) clang/test/Sema/main-no-return-c89.c (+6)
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}} */

@AaronBallman AaronBallman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this!

Comment thread clang/test/Sema/main-no-return-c89.c Outdated
Comment thread clang/lib/Sema/SemaDecl.cpp
Comment thread clang/include/clang/Basic/DiagnosticSemaKinds.td Outdated
Comment thread clang/test/Sema/main-no-return-c89.c Outdated
@a-tarasyuk a-tarasyuk requested a review from AaronBallman April 7, 2025 19:48

@AaronBallman AaronBallman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM aside from an 80-col formatting nit, thank you for the fix!

Comment thread clang/include/clang/Basic/DiagnosticSemaKinds.td Outdated
@a-tarasyuk a-tarasyuk requested a review from AaronBallman April 8, 2025 16:37
@a-tarasyuk a-tarasyuk merged commit 9f46305 into llvm:main Apr 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing '-Wreturn-type' warning for 'main' having no return statement in C89 mode

3 participants