I modeled it in this way: every time we act on a variable declaration, we check if it's main and it's global, and in case it's true we emit a diagnostic. Actually, to completely fulfill the standard requirements we should also consider ill-formed anything that declares the name "main" with C linkage, but I'd like to tackle this separately. In particular I'm not sure if "name" refers only to variables or also to e.g. function names etc..
For reference, this was reported in PR24309.
Details
Diff Detail
Event Timeline
lib/Sema/SemaDecl.cpp | ||
---|---|---|
6110 | This check should not apply in -ffreestanding mode. | |
6110 | getAsString is not the best thing to use here; it produces a human-readable string (for diagnostics etc). Instead, check Name.isIdentifier() && Name.getAsIdentifierInfo()->isStr("main"). | |
6110 | In C, an external-linkage variable named main results in undefined behavior (because the behavior is undefined if there is no external-linkage function named main, and also if there is both a function and a variable named main), so we can diagnose that case too. | |
test/CXX/basic/basic.start/basic.start.main/p3.cpp | ||
6–9 | Maybe also test:
|
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.
Maybe you could refactor the check to something like:
if (Name.isIdentifier() && Name.getAsIdentifierInfo()->isStr("main") NewVD->getDeclContext()->getRedeclContext()->isTranslationUnit() && !getLangOpts().Freestanding && !NewVD->getDescribedVarTemplate()) { if (getLangOpts().CPlusPlus) Diag1; else if (NewVD->hasExternalFormalLinkage()) Diag2; }
include/clang/Basic/DiagnosticSemaKinds.td | ||
---|---|---|
514 | Hyphenating 'external linkage' is unusual; how about 'variable named 'main' with external linkage has undefined behavior'? | |
lib/Sema/SemaDecl.cpp | ||
6113 | The freestanding check should apply in C too. | |
6114–6116 | The only checks you need here are: 1) DeclContext's redecl context is the translation unit, and 2) NewVD is not a variable template. All the other checks are implied by the DC check. I'd suggest factoring these out into the main check. | |
6116 | You need to check NewVD->getDeclContext()->getRedeclContext(), in case there are LinkageSpecDecls surrounding the variable (extern "C++" int main;). | |
6121 | It's weird to ask isExternC from C. Use hasExternalFormalLinkage instead. |
- Refactored check
- Added test for -ffreestanding in C
- Changed the diagnostic emitted
Also, thanks for your time and guidance.
Oops, I uploaded the wrong diff. Anyway, I changed can't to cannot and committed this as r245051.
While looking at DiagnosticSemaKind.td I noticed there are still 7 diagnostics that use can't instead of cannot. Are you OK if I change those? (in a subsequent commit, of course)
It's much more common to use "cannot" rather than the contraction "can't" in our diagnostic wording.