https://github.com/a-tarasyuk created https://github.com/llvm/llvm-project/pull/101853
Fixes #101512 >From 16706eb1648653f41da5b6d10c1104b1cf1609bf 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] p2 requirements --- clang/docs/ReleaseNotes.rst | 2 ++ .../clang/Basic/DiagnosticSemaKinds.td | 3 ++ clang/include/clang/Sema/Sema.h | 2 +- clang/lib/AST/Decl.cpp | 14 +++++---- clang/lib/Sema/SemaDecl.cpp | 15 +++++++--- clang/test/CodeGenCXX/mangle.cpp | 10 ------- clang/test/SemaCXX/linkage1.cpp | 29 +++++++++++++++++++ 7 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 clang/test/SemaCXX/linkage1.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4c7bd099420ab..3303db5a87ace 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 `extern` context as invalid according to [basic.start.main] p2. 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..dd95ea3cc6f0f 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5986,6 +5986,9 @@ def err_new_abi_tag_on_redeclaration : Error< "'abi_tag' %0 missing in original declaration">; def note_use_ifdef_guards : Note< "unguarded header; consider using #ifdef guards or #pragma once">; +def err_invalid_linkage_specification : Error< + "invalid linkage specification " + "'extern \"%select{C|C++}0\"'">; def warn_var_decl_not_read_only : Warning< "object of type %0 cannot be placed in read-only memory">, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 2ec6367eccea0..0fc07d4a01ad3 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3585,7 +3585,7 @@ class Sema final : public SemaBase { /// \param OldT The portion of the type of the old declaration to check. bool canFullyTypeCheckRedeclaration(ValueDecl *NewD, ValueDecl *OldD, QualType NewT, QualType OldT); - void CheckMain(FunctionDecl *FD, const DeclSpec &D); + void CheckMain(FunctionDecl *FD, DeclContext *DC, const DeclSpec &D); void CheckMSVCRTEntryPoint(FunctionDecl *FD); /// Returns an implicit CodeSegAttr if a __declspec(code_seg) is found on a diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 490c4a2fc525c..447297103f396 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3292,11 +3292,15 @@ 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 TranslationUnitDecl *TUnit = + dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext()); + const LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(getDeclContext()); + if (!TUnit && !LSD) + return false; + if ((TUnit && TUnit->getASTContext().getLangOpts().Freestanding) || + (LSD && LSD->getASTContext().getLangOpts().Freestanding)) + return false; + return isNamed(this, "main"); } bool FunctionDecl::isMSVCRTEntryPoint() const { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 4fea38d1b02a9..ae6d6681d6029 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10308,7 +10308,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (!getLangOpts().CPlusPlus) { // Perform semantic checking on the function declaration. if (!NewFD->isInvalidDecl() && NewFD->isMain()) - CheckMain(NewFD, D.getDeclSpec()); + CheckMain(NewFD, DC, D.getDeclSpec()); if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint()) CheckMSVCRTEntryPoint(NewFD); @@ -10473,7 +10473,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Perform semantic checking on the function declaration. if (!NewFD->isInvalidDecl() && NewFD->isMain()) - CheckMain(NewFD, D.getDeclSpec()); + CheckMain(NewFD, DC, D.getDeclSpec()); if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint()) CheckMSVCRTEntryPoint(NewFD); @@ -12210,7 +12210,15 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, return Redeclaration; } -void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { +void Sema::CheckMain(FunctionDecl *FD, DeclContext *DC, const DeclSpec &DS) { + // [basic.start.main] p2 + // The main function shall not be declared with a linkage-specification. + if (DC->isExternCXXContext() || DC->isExternCContext()) { + Diag(FD->getLocation(), diag::err_invalid_linkage_specification) + << 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 +12246,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/CodeGenCXX/mangle.cpp b/clang/test/CodeGenCXX/mangle.cpp index d0800af55c87e..c9d61def0a0d0 100644 --- a/clang/test/CodeGenCXX/mangle.cpp +++ b/clang/test/CodeGenCXX/mangle.cpp @@ -137,16 +137,6 @@ int f(struct a *x) { return x->b; } -// PR5017 -extern "C" { -struct Debug { - const Debug& operator<< (unsigned a) const { return *this; } -}; -Debug dbg; -// CHECK: @_ZNK5DebuglsEj -int main(void) { dbg << 32 ;} -} - template<typename T> struct S6 { typedef int B; }; diff --git a/clang/test/SemaCXX/linkage1.cpp b/clang/test/SemaCXX/linkage1.cpp new file mode 100644 index 0000000000000..8be82209afc08 --- /dev/null +++ b/clang/test/SemaCXX/linkage1.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -pedantic-errors %s + +namespace c { + extern "C" void main(); // expected-error {{invalid linkage specification 'extern "C"'}} +} +extern "C" { + int main(); // expected-error {{invalid linkage specification 'extern "C"'}} +} +extern "C" int main(); // expected-error {{invalid linkage specification 'extern "C"'}} +extern "C" struct A { int main(); }; // ok + +namespace cpp { + extern "C++" int main(); // expected-error {{invalid linkage specification 'extern "C++"'}} +} +extern "C++" { + int main(); // expected-error {{invalid linkage specification 'extern "C++"'}} +} +extern "C++" int main(); // expected-error {{invalid linkage specification 'extern "C++"'}} +extern "C++" struct B { int main(); }; // ok + +namespace ns { + extern "C" struct A { + int main; // ok + }; + + extern "C" struct B { + int main(); // ok + }; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits