Skip to content

Commit 16706eb

Browse files
committed
[Clang] strengthen checks for 'main' function to meet [basic.start.main] p2 requirements
1 parent 1a9acd7 commit 16706eb

File tree

7 files changed

+55
-20
lines changed

7 files changed

+55
-20
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ Improvements to Clang's diagnostics
145145

146146
- -Wdangling-assignment-gsl is enabled by default.
147147

148+
- Clang now diagnoses the use of `main` in `extern` context as invalid according to [basic.start.main] p2. Fixes #GH101512.
149+
148150
Improvements to Clang's time-trace
149151
----------------------------------
150152

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5986,6 +5986,9 @@ def err_new_abi_tag_on_redeclaration : Error<
59865986
"'abi_tag' %0 missing in original declaration">;
59875987
def note_use_ifdef_guards : Note<
59885988
"unguarded header; consider using #ifdef guards or #pragma once">;
5989+
def err_invalid_linkage_specification : Error<
5990+
"invalid linkage specification "
5991+
"'extern \"%select{C|C++}0\"'">;
59895992

59905993
def warn_var_decl_not_read_only : Warning<
59915994
"object of type %0 cannot be placed in read-only memory">,

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3585,7 +3585,7 @@ class Sema final : public SemaBase {
35853585
/// \param OldT The portion of the type of the old declaration to check.
35863586
bool canFullyTypeCheckRedeclaration(ValueDecl *NewD, ValueDecl *OldD,
35873587
QualType NewT, QualType OldT);
3588-
void CheckMain(FunctionDecl *FD, const DeclSpec &D);
3588+
void CheckMain(FunctionDecl *FD, DeclContext *DC, const DeclSpec &D);
35893589
void CheckMSVCRTEntryPoint(FunctionDecl *FD);
35903590

35913591
/// Returns an implicit CodeSegAttr if a __declspec(code_seg) is found on a

clang/lib/AST/Decl.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3292,11 +3292,15 @@ bool FunctionDecl::isImmediateFunction() const {
32923292
}
32933293

32943294
bool FunctionDecl::isMain() const {
3295-
const TranslationUnitDecl *tunit =
3296-
dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
3297-
return tunit &&
3298-
!tunit->getASTContext().getLangOpts().Freestanding &&
3299-
isNamed(this, "main");
3295+
const TranslationUnitDecl *TUnit =
3296+
dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
3297+
const LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(getDeclContext());
3298+
if (!TUnit && !LSD)
3299+
return false;
3300+
if ((TUnit && TUnit->getASTContext().getLangOpts().Freestanding) ||
3301+
(LSD && LSD->getASTContext().getLangOpts().Freestanding))
3302+
return false;
3303+
return isNamed(this, "main");
33003304
}
33013305

33023306
bool FunctionDecl::isMSVCRTEntryPoint() const {

clang/lib/Sema/SemaDecl.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10308,7 +10308,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
1030810308
if (!getLangOpts().CPlusPlus) {
1030910309
// Perform semantic checking on the function declaration.
1031010310
if (!NewFD->isInvalidDecl() && NewFD->isMain())
10311-
CheckMain(NewFD, D.getDeclSpec());
10311+
CheckMain(NewFD, DC, D.getDeclSpec());
1031210312

1031310313
if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint())
1031410314
CheckMSVCRTEntryPoint(NewFD);
@@ -10473,7 +10473,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
1047310473

1047410474
// Perform semantic checking on the function declaration.
1047510475
if (!NewFD->isInvalidDecl() && NewFD->isMain())
10476-
CheckMain(NewFD, D.getDeclSpec());
10476+
CheckMain(NewFD, DC, D.getDeclSpec());
1047710477

1047810478
if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint())
1047910479
CheckMSVCRTEntryPoint(NewFD);
@@ -12210,7 +12210,15 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
1221012210
return Redeclaration;
1221112211
}
1221212212

12213-
void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
12213+
void Sema::CheckMain(FunctionDecl *FD, DeclContext *DC, const DeclSpec &DS) {
12214+
// [basic.start.main] p2
12215+
// The main function shall not be declared with a linkage-specification.
12216+
if (DC->isExternCXXContext() || DC->isExternCContext()) {
12217+
Diag(FD->getLocation(), diag::err_invalid_linkage_specification)
12218+
<< FD->getLanguageLinkage();
12219+
FD->setInvalidDecl();
12220+
return;
12221+
}
1221412222
// C++11 [basic.start.main]p3:
1221512223
// A program that [...] declares main to be inline, static or
1221612224
// constexpr is ill-formed.
@@ -12238,7 +12246,6 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
1223812246
<< FixItHint::CreateRemoval(DS.getConstexprSpecLoc());
1223912247
FD->setConstexprKind(ConstexprSpecKind::Unspecified);
1224012248
}
12241-
1224212249
if (getLangOpts().OpenCL) {
1224312250
Diag(FD->getLocation(), diag::err_opencl_no_main)
1224412251
<< FD->hasAttr<OpenCLKernelAttr>();

clang/test/CodeGenCXX/mangle.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,16 +137,6 @@ int f(struct a *x) {
137137
return x->b;
138138
}
139139

140-
// PR5017
141-
extern "C" {
142-
struct Debug {
143-
const Debug& operator<< (unsigned a) const { return *this; }
144-
};
145-
Debug dbg;
146-
// CHECK: @_ZNK5DebuglsEj
147-
int main(void) { dbg << 32 ;}
148-
}
149-
150140
template<typename T> struct S6 {
151141
typedef int B;
152142
};

clang/test/SemaCXX/linkage1.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic-errors %s
2+
3+
namespace c {
4+
extern "C" void main(); // expected-error {{invalid linkage specification 'extern "C"'}}
5+
}
6+
extern "C" {
7+
int main(); // expected-error {{invalid linkage specification 'extern "C"'}}
8+
}
9+
extern "C" int main(); // expected-error {{invalid linkage specification 'extern "C"'}}
10+
extern "C" struct A { int main(); }; // ok
11+
12+
namespace cpp {
13+
extern "C++" int main(); // expected-error {{invalid linkage specification 'extern "C++"'}}
14+
}
15+
extern "C++" {
16+
int main(); // expected-error {{invalid linkage specification 'extern "C++"'}}
17+
}
18+
extern "C++" int main(); // expected-error {{invalid linkage specification 'extern "C++"'}}
19+
extern "C++" struct B { int main(); }; // ok
20+
21+
namespace ns {
22+
extern "C" struct A {
23+
int main; // ok
24+
};
25+
26+
extern "C" struct B {
27+
int main(); // ok
28+
};
29+
}

0 commit comments

Comments
 (0)