https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/101853
>From befd46e0c2d3244941e4c4d48dd03d4edb3d4c04 Mon Sep 17 00:00:00 2001 From: Oleksandr T <oleksandr.taras...@outlook.com> Date: Sun, 4 Aug 2024 00:45:49 +0300 Subject: [PATCH] [Clang] strengthen checks for 'main' function to meet [basic.start.main] p3 requirements --- clang/docs/ReleaseNotes.rst | 2 + .../clang/Basic/DiagnosticSemaKinds.td | 6 ++ clang/lib/AST/Decl.cpp | 8 +-- clang/lib/Sema/SemaDecl.cpp | 30 +++++++-- .../basic/basic.start/basic.start.main/p3.cpp | 61 +++++++++++++++++++ 5 files changed, 96 insertions(+), 11 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4c7bd099420ab..93eec78606301 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -145,6 +145,8 @@ Improvements to Clang's diagnostics - -Wdangling-assignment-gsl is enabled by default. +- Clang now diagnoses the use of `main` in an `extern "C"` context as invalid according to [basic.start.main] p3. Fixes #GH101512. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 581434d33c5c9..21a66ea04704c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -990,6 +990,12 @@ def warn_main_redefined : Warning<"variable named 'main' with external linkage " "has undefined behavior">, InGroup<Main>; def ext_main_used : Extension< "referring to 'main' within an expression is a Clang extension">, InGroup<Main>; +def ext_main_invalid_linkage_specification : ExtWarn< + "'main' should not be " + "'extern \"%select{C|C++}0\"'">, InGroup<Main>; +def err_main_invalid_linkage_specification : Error< + "'main' should not be " + "'extern \"%select{C|C++}0\"'">; /// parser diagnostics def ext_no_declarators : ExtWarn<"declaration does not declare anything">, diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 490c4a2fc525c..9bf2ee680073b 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3292,11 +3292,9 @@ bool FunctionDecl::isImmediateFunction() const { } bool FunctionDecl::isMain() const { - const TranslationUnitDecl *tunit = - dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext()); - return tunit && - !tunit->getASTContext().getLangOpts().Freestanding && - isNamed(this, "main"); + const DeclContext *DC = getDeclContext(); + return isNamed(this, "main") && !getLangOpts().Freestanding && + (DC->getRedeclContext()->isTranslationUnit() || isExternC()); } bool FunctionDecl::isMSVCRTEntryPoint() const { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 4fea38d1b02a9..8c3b130515c6e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -7353,6 +7353,14 @@ void emitReadOnlyPlacementAttrWarning(Sema &S, const VarDecl *VD) { } } +static bool isMainVar(DeclarationName Name, VarDecl *VD) { + return Name.getAsIdentifierInfo() && + Name.getAsIdentifierInfo()->isStr("main") && + !VD->getDescribedVarTemplate() && + (VD->getDeclContext()->getRedeclContext()->isTranslationUnit() || + VD->isExternC()); +} + NamedDecl *Sema::ActOnVariableDeclarator( Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, @@ -8052,10 +8060,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( } // Special handling of variable named 'main'. - if (Name.getAsIdentifierInfo() && Name.getAsIdentifierInfo()->isStr("main") && - NewVD->getDeclContext()->getRedeclContext()->isTranslationUnit() && - !getLangOpts().Freestanding && !NewVD->getDescribedVarTemplate()) { - + if (!getLangOpts().Freestanding && isMainVar(Name, NewVD)) { // C++ [basic.start.main]p3 // A program that declares a variable main at global scope is ill-formed. if (getLangOpts().CPlusPlus) @@ -12210,7 +12215,21 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, return Redeclaration; } -void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { +void Sema::CheckMain(FunctionDecl *FD, const DeclSpec &DS) { + // [basic.start.main]p3 + // The main function shall not be declared with a linkage-specification. + if ((FD->isExternCContext() || FD->isExternCXXContext())) { + unsigned DiagID = 0; + if (FD->getDeclContext()->getRedeclContext()->isTranslationUnit()) + DiagID = diag::ext_main_invalid_linkage_specification; + else if (FD->isExternCContext()) + DiagID = diag::err_main_invalid_linkage_specification; + + if (DiagID) + Diag(FD->getLocation(), DiagID) << FD->getLanguageLinkage(); + FD->setInvalidDecl(); + return; + } // C++11 [basic.start.main]p3: // A program that [...] declares main to be inline, static or // constexpr is ill-formed. @@ -12238,7 +12257,6 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { << FixItHint::CreateRemoval(DS.getConstexprSpecLoc()); FD->setConstexprKind(ConstexprSpecKind::Unspecified); } - if (getLangOpts().OpenCL) { Diag(FD->getLocation(), diag::err_opencl_no_main) << FD->hasAttr<OpenCLKernelAttr>(); diff --git a/clang/test/CXX/basic/basic.start/basic.start.main/p3.cpp b/clang/test/CXX/basic/basic.start/basic.start.main/p3.cpp index f7085ca31d6c9..6d8d7c7a35963 100644 --- a/clang/test/CXX/basic/basic.start/basic.start.main/p3.cpp +++ b/clang/test/CXX/basic/basic.start/basic.start.main/p3.cpp @@ -8,6 +8,9 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST8 // RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST9 // RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST10 -ffreestanding +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST11 +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST12 +// RUN: %clang_cc1 -fsyntax-only -verify -pedantic-errors %s -DTEST13 #if TEST1 int main; // expected-error{{main cannot be declared as global variable}} @@ -61,6 +64,64 @@ int q(void) // expected-no-diagnostics int main; +#elif TEST11 +extern "C" { + namespace Y { + int main; // expected-error {{main cannot be declared as global variable}} + } +} +namespace ns { + extern "C" int main; // expected-error {{main cannot be declared as global variable}} +} + +#elif TEST12 +extern "C" struct A { int main(); }; // ok + +namespace c { + extern "C" void main(); // expected-error {{'main' should not be 'extern "C"'}} +} + +extern "C" { + namespace Z { + void main(); // expected-error {{'main' should not be 'extern "C"'}} + } +} + +namespace ns { + extern "C" struct A { + int main; // ok + }; + + extern "C" struct B { + int main(); // ok + }; +} + +#elif TEST13 +extern "C++" { + int main(); // expected-error {{'main' should not be 'extern "C++"'}} +} + +extern "C" { + int main(); // expected-error {{'main' should not be 'extern "C"'}} +} + +extern "C" int main(); // expected-error {{'main' should not be 'extern "C"'}} +extern "C++" int main(); // expected-error {{'main' should not be 'extern "C++"'}} + +namespace ns1 { + extern "C++" int main(); // ok + extern "C" { + extern "C++" { + int main(void *); // ok + } + } +} + +namespace ns2 { + extern "C++" void main() {} // ok +} + #else #error Unknown Test #endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits