davide updated this revision to Diff 31184. davide added a comment. Take two. The check looks a little bit ugly, maybe there's a shorter way to handle it. I also enhanced test coverage, and added diagnostic for the undefined behaviour in C as you suggested.
http://reviews.llvm.org/D11658 Files: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDecl.cpp test/CXX/basic/basic.start/basic.start.main/p3.cpp test/Sema/warn-extern-main.c
Index: test/Sema/warn-extern-main.c =================================================================== --- test/Sema/warn-extern-main.c +++ test/Sema/warn-extern-main.c @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST1 +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST2 +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST3 +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST4 +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST5 +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST6 +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST7 +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST8 + +#if TEST1 +int main; // expected-warning{{external-linkage variable named 'main' has undefined behavior}} + +#elif TEST2 +extern int main; // expected-warning{{external-linkage variable named 'main' has undefined behavior}} + +#elif TEST3 +// expected-no-diagnostics +void x() { + static int main; +} + +#elif TEST4 +void x() { + extern int main; // expected-warning{{external-linkage variable named 'main' has undefined behavior}} +} + +#elif TEST5 +// expected-no-diagnostics +void x() { + int main; +} + +#elif TEST6 +// expected-no-diagnostics +static int main; + +#elif TEST7 +// expected-no-diagnostics +void x() { + auto int main; +} + +#elif TEST8 +// expected-no-diagnostics +void x() { + register int main; +} + +#else +#error Unknown Test +#endif Index: test/CXX/basic/basic.start/basic.start.main/p3.cpp =================================================================== --- test/CXX/basic/basic.start/basic.start.main/p3.cpp +++ test/CXX/basic/basic.start/basic.start.main/p3.cpp @@ -0,0 +1,66 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST1 +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST2 +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST3 +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST4 +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14 -DTEST5 +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14 -DTEST6 +// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST7 +// 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 + +#if TEST1 +int main; // expected-error{{main can't be declared as global variable}} + +#elif TEST2 +// expected-no-diagnostics +int f () { + int main; + return main; +} + +#elif TEST3 +// expected-no-diagnostics +void x(int main) {}; +int y(int main); + +#elif TEST4 +// expected-no-diagnostics +class A { + static int main; +}; + +#elif TEST5 +// expected-no-diagnostics +template<class T> constexpr T main; + +#elif TEST6 +extern template<class T> constexpr T main; //expected-error{{expected unqualified-id}} + +#elif TEST7 +// expected-no-diagnostics +namespace foo { + int main; +} + +#elif TEST8 +void z(void) +{ + extern int main; // expected-error{{main can't be declared as global variable}} +} + +#elif TEST9 +// expected-no-diagnostics +int q(void) +{ + static int main; + return main; +} + +#elif TEST10 +// expected-no-diagnostics +int main; + +#else +#error Unknown Test +#endif Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -6105,6 +6105,23 @@ } } + // Special handling of variable named 'main'. + if (Name.isIdentifier() && Name.getAsIdentifierInfo()->isStr("main")) { + + // C++ [basic.start.main]p3 + // A program that declares a variable main at global scope is ill-formed. + if (getLangOpts().CPlusPlus && !getLangOpts().Freestanding && + NewVD->hasGlobalStorage() && !NewVD->isStaticLocal() && + !NewVD->isStaticDataMember() && !NewVD->getDescribedVarTemplate() && + NewVD->getDeclContext()->isTranslationUnit()) + Diag(D.getLocStart(), diag::err_main_global_variable); + + // In C, and external-linkage variable named main results in undefined + // behavior. + if (!getLangOpts().CPlusPlus && NewVD->isExternC()) + Diag(D.getLocStart(), diag::warn_main_redefined); + } + if (D.isRedeclaration() && !Previous.empty()) { checkDLLAttributeRedeclaration( *this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewVD, Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -510,6 +510,9 @@ def err_main_arg_wrong : Error<"%select{first|second|third|fourth}0 " "parameter of 'main' (%select{argument count|argument array|environment|" "platform-specific data}0) must be of type %1">; +def err_main_global_variable : Error<"main can't be declared as global variable">; +def warn_main_redefined : Warning<"external-linkage variable named 'main' has " + "undefined behavior">, InGroup<Main>; def ext_main_used : Extension< "ISO C++ does not allow 'main' to be used by a program">, InGroup<Main>;
_______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits