This is an archive of the discontinued LLVM Phabricator instance.

[Sema] main can't be declared as global variable
ClosedPublic

Authored by davide on Jul 30 2015, 12:01 PM.

Details

Summary

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.

Diff Detail

Event Timeline

davide updated this revision to Diff 31063.Jul 30 2015, 12:01 PM
davide retitled this revision from to [Sema] main can't be declared as global variable.
davide updated this object.
davide added reviewers: aaron.ballman, rsmith.
davide added a subscriber: cfe-commits.
rsmith added inline comments.Jul 30 2015, 2:00 PM
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:

  • an internal-linkage global variable named main (ill-formed in C++, OK in C)
  • a function parameter named main (OK)
  • a static data member named main (OK, even if defined in TU scope)
  • a variable template named main (it looks like this is ill-formed, no diagnostic required, if the variable template has external linkage, and otherwise OK)
  • a variable named main within a namespace (OK)
  • a function-scope extern variable named main (ill-formed)
  • a function-scope static variable named main (OK)
davide updated this revision to Diff 31184.Jul 31 2015, 6:10 PM

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.

Hi Richard, do you have any comments on the new patch?

rsmith edited edge metadata.Aug 10 2015, 5:18 PM

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.

davide updated this revision to Diff 31932.Aug 12 2015, 6:09 AM
davide edited edge metadata.
  • Refactored check
  • Added test for -ffreestanding in C
  • Changed the diagnostic emitted

Also, thanks for your time and guidance.

Looks good other than the diagnostic wording.

include/clang/Basic/DiagnosticSemaKinds.td
513

It's much more common to use "cannot" rather than the contraction "can't" in our diagnostic wording.

514

I would still like this reworded.

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)

davide accepted this revision.Aug 15 2015, 8:24 AM
davide added a reviewer: davide.
This revision is now accepted and ready to land.Aug 15 2015, 8:24 AM
davide closed this revision.Aug 15 2015, 8:24 AM