https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/134617
>From 64210203803f7ba9deec06d467ee570bff761108 Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk <oleksandr.taras...@outlook.com> Date: Sun, 6 Apr 2025 00:17:38 +0300 Subject: [PATCH 1/4] [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}} */ >From 42a8440b90f3a091326aa9f74b98bb5725176da2 Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk <oleksandr.taras...@outlook.com> Date: Mon, 7 Apr 2025 22:44:41 +0300 Subject: [PATCH 2/4] add an explanatory comment --- clang/lib/Sema/SemaDecl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index b020a1b2fd3e0..6f35873c6b69f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16230,6 +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. + // Clang implicitly returns 0 in C89 mode, but that's considered an + // extension. The check is necessary to ensure the expected extension + // warning is emitted in C89 mode. if ((FD->hasImplicitReturnZero() && (getLangOpts().CPlusPlus || getLangOpts().C99 || !FD->isMain())) || FD->hasAttr<NakedAttr>()) >From 26987a788b471c50c09009d9a63b5b1dcaf7fac7 Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk <oleksandr.taras...@outlook.com> Date: Mon, 7 Apr 2025 22:44:59 +0300 Subject: [PATCH 3/4] update diagnostic message --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 34f2ee883ca63..aac2c10e502c4 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1031,7 +1031,7 @@ 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">, +def ext_main_no_return : Extension<"implicit '0' return value from 'main' is a C99 extension">, 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': " >From 45821fd65f744df37daf3727ba624f8c171edff4 Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk <oleksandr.taras...@outlook.com> Date: Mon, 7 Apr 2025 22:45:12 +0300 Subject: [PATCH 4/4] add additional tests --- clang/test/Sema/main-no-return-c89-1.c | 10 ++++++++++ clang/test/Sema/main-no-return-c89-2.c | 11 +++++++++++ clang/test/Sema/main-no-return-c89-3.c | 8 ++++++++ clang/test/Sema/main-no-return-c89.c | 6 ------ 4 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 clang/test/Sema/main-no-return-c89-1.c create mode 100644 clang/test/Sema/main-no-return-c89-2.c create mode 100644 clang/test/Sema/main-no-return-c89-3.c delete mode 100644 clang/test/Sema/main-no-return-c89.c diff --git a/clang/test/Sema/main-no-return-c89-1.c b/clang/test/Sema/main-no-return-c89-1.c new file mode 100644 index 0000000000000..97ba040527025 --- /dev/null +++ b/clang/test/Sema/main-no-return-c89-1.c @@ -0,0 +1,10 @@ +/* RUN: %clang_cc1 -std=c89 -fsyntax-only -verify -Wno-strict-prototypes -pedantic %s + * RUN: %clang_cc1 -std=c89 -fsyntax-only -verify -Wno-strict-prototypes -Wmain-return-type %s + * RUN: %clang_cc1 -std=c89 -fsyntax-only -verify=implicit-main-return -Wno-strict-prototypes -pedantic -Wno-main-return-type %s + */ + +/* implicit-main-return-no-diagnostics */ + +int main() { + +} /* expected-warning {{implicit '0' return value from 'main' is a C99 extension}} */ diff --git a/clang/test/Sema/main-no-return-c89-2.c b/clang/test/Sema/main-no-return-c89-2.c new file mode 100644 index 0000000000000..080229be8a5dc --- /dev/null +++ b/clang/test/Sema/main-no-return-c89-2.c @@ -0,0 +1,11 @@ +/* RUN: %clang_cc1 -std=c89 -fsyntax-only -verify -Wno-strict-prototypes -Wmain-return-type %s + */ + +/* expected-no-diagnostics */ + +void exit(int); + +int main() { + if (1) + exit(1); +} diff --git a/clang/test/Sema/main-no-return-c89-3.c b/clang/test/Sema/main-no-return-c89-3.c new file mode 100644 index 0000000000000..e48e33c6ebd6c --- /dev/null +++ b/clang/test/Sema/main-no-return-c89-3.c @@ -0,0 +1,8 @@ +/* RUN: %clang_cc1 -std=c89 -fsyntax-only -verify -Wno-strict-prototypes -Wmain-return-type %s + */ + +/* expected-no-diagnostics */ + +int main() { + return 0; +} diff --git a/clang/test/Sema/main-no-return-c89.c b/clang/test/Sema/main-no-return-c89.c deleted file mode 100644 index 19d55916fc833..0000000000000 --- a/clang/test/Sema/main-no-return-c89.c +++ /dev/null @@ -1,6 +0,0 @@ -/* 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}} */ _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits