r190818 - [-cxx-abi microsoft] Correctly identify Win32 entry points

David Majnemer david.majnemer at gmail.com
Mon Sep 16 15:44:20 PDT 2013


Author: majnemer
Date: Mon Sep 16 17:44:20 2013
New Revision: 190818

URL: http://llvm.org/viewvc/llvm-project?rev=190818&view=rev
Log:
[-cxx-abi microsoft] Correctly identify Win32 entry points

Summary:
This fixes several issues with the original implementation:
- Win32 entry points cannot be in namespaces
- A Win32 entry point cannot be a function template, diagnose if we it.
- Win32 entry points cannot be overloaded.
- Win32 entry points implicitly return, similar to main.

Reviewers: rnk, rsmith, whunt, timurrrr

Reviewed By: rnk

CC: cfe-commits, nrieck

Differential Revision: http://llvm-reviews.chandlerc.com/D1683

Added:
    cfe/trunk/test/SemaCXX/ms-overload-entry-point.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/AST/MicrosoftMangle.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=190818&r1=190817&r2=190818&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Mon Sep 16 17:44:20 2013
@@ -1735,6 +1735,10 @@ public:
   /// entry point into an executable program.
   bool isMain() const;
 
+  /// \brief Determines whether this function is a MSVCRT user defined entry
+  /// point.
+  bool isMSVCRTEntryPoint() const;
+
   /// \brief Determines whether this operator new or delete is one
   /// of the reserved global placement operators:
   ///    void *operator new(size_t, void *);

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=190818&r1=190817&r2=190818&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Sep 16 17:44:20 2013
@@ -419,7 +419,7 @@ def ext_noreturn_main : ExtWarn<
 def note_main_remove_noreturn : Note<"remove '_Noreturn'">;
 def err_constexpr_main : Error<
   "'main' is not allowed to be declared constexpr">;
-def err_main_template_decl : Error<"'main' cannot be a template">;
+def err_mainlike_template_decl : Error<"'%0' cannot be a template">;
 def err_main_returns_nonint : Error<"'main' must return 'int'">;
 def ext_main_returns_nonint : ExtWarn<"return type of 'main' is not 'int'">,
     InGroup<MainReturnType>;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=190818&r1=190817&r2=190818&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Sep 16 17:44:20 2013
@@ -1495,6 +1495,7 @@ public:
                                 FunctionDecl *NewFD, LookupResult &Previous,
                                 bool IsExplicitSpecialization);
   void CheckMain(FunctionDecl *FD, const DeclSpec &D);
+  void CheckMSVCRTEntryPoint(FunctionDecl *FD);
   Decl *ActOnParamDeclarator(Scope *S, Declarator &D);
   ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
                                           SourceLocation Loc,

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=190818&r1=190817&r2=190818&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Mon Sep 16 17:44:20 2013
@@ -2204,6 +2204,33 @@ bool FunctionDecl::isMain() const {
          isNamed(this, "main");
 }
 
+bool FunctionDecl::isMSVCRTEntryPoint() const {
+  const TranslationUnitDecl *TUnit =
+      dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
+  if (!TUnit)
+    return false;
+
+  // Even though we aren't really targeting MSVCRT if we are freestanding,
+  // semantic analysis for these functions remains the same.
+
+  // MSVCRT entry points only exist on MSVCRT targets.
+  if (!TUnit->getASTContext().getTargetInfo().getTriple().isOSMSVCRT())
+    return false;
+
+  // Nameless functions like constructors cannot be entry points.
+  if (!getIdentifier())
+    return false;
+
+  return llvm::StringSwitch<bool>(getName())
+      .Cases("main",     // an ANSI console app
+             "wmain",    // a Unicode console App
+             "WinMain",  // an ANSI GUI app
+             "wWinMain", // a Unicode GUI app
+             "DllMain",  // a DLL
+             true)
+      .Default(false);
+}
+
 bool FunctionDecl::isReservedGlobalPlacementOperator() const {
   assert(getDeclName().getNameKind() == DeclarationName::CXXOperatorName);
   assert(getDeclName().getCXXOverloadedOperator() == OO_New ||

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=190818&r1=190817&r2=190818&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Mon Sep 16 17:44:20 2013
@@ -24,7 +24,6 @@
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringSwitch.h"
 
 using namespace clang;
 
@@ -71,29 +70,6 @@ static const FunctionDecl *getStructor(c
   return fn;
 }
 
-// The ABI expects that we would never mangle "typical" user-defined entry
-// points regardless of visibility or freestanding-ness.
-//
-// N.B. This is distinct from asking about "main".  "main" has a lot of special
-// rules associated with it in the standard while these user-defined entry
-// points are outside of the purview of the standard.  For example, there can be
-// only one definition for "main" in a standards compliant program; however
-// nothing forbids the existence of wmain and WinMain in the same translation
-// unit.
-static bool isUserDefinedEntryPoint(const FunctionDecl *FD) {
-  if (!FD->getIdentifier())
-    return false;
-
-  return llvm::StringSwitch<bool>(FD->getName())
-      .Cases("main",     // An ANSI console app
-             "wmain",    // A Unicode console App
-             "WinMain",  // An ANSI GUI app
-             "wWinMain", // A Unicode GUI app
-             "DllMain",  // A DLL
-             true)
-      .Default(false);
-}
-
 /// MicrosoftCXXNameMangler - Manage the mangling of a single name for the
 /// Microsoft Visual C++ ABI.
 class MicrosoftCXXNameMangler {
@@ -254,7 +230,16 @@ bool MicrosoftMangleContext::shouldMangl
     if (FD->hasAttr<OverloadableAttr>())
       return true;
 
-    if (isUserDefinedEntryPoint(FD))
+    // The ABI expects that we would never mangle "typical" user-defined entry
+    // points regardless of visibility or freestanding-ness.
+    //
+    // N.B. This is distinct from asking about "main".  "main" has a lot of
+    // special rules associated with it in the standard while these
+    // user-defined entry points are outside of the purview of the standard.
+    // For example, there can be only one definition for "main" in a standards
+    // compliant program; however nothing forbids the existence of wmain and
+    // WinMain in the same translation unit.
+    if (FD->isMSVCRTEntryPoint())
       return false;
 
     // C++ functions and those whose names are not a simple identifier need

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=190818&r1=190817&r2=190818&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Sep 16 17:44:20 2013
@@ -6881,6 +6881,9 @@ Sema::ActOnFunctionDeclarator(Scope *S,
     if (!NewFD->isInvalidDecl() && NewFD->isMain())
       CheckMain(NewFD, D.getDeclSpec());
 
+    if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint())
+      CheckMSVCRTEntryPoint(NewFD);
+
     if (!NewFD->isInvalidDecl())
       D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
                                                   isExplicitSpecialization));
@@ -7000,6 +7003,9 @@ Sema::ActOnFunctionDeclarator(Scope *S,
       if (!NewFD->isInvalidDecl() && NewFD->isMain())
         CheckMain(NewFD, D.getDeclSpec());
 
+      if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint())
+        CheckMSVCRTEntryPoint(NewFD);
+
       if (NewFD->isInvalidDecl()) {
         // If this is a class member, mark the class invalid immediately.
         // This avoids some consistency errors later.
@@ -7670,7 +7676,27 @@ void Sema::CheckMain(FunctionDecl* FD, c
   }
   
   if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) {
-    Diag(FD->getLocation(), diag::err_main_template_decl);
+    Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD->getName();
+    FD->setInvalidDecl();
+  }
+}
+
+void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) {
+  QualType T = FD->getType();
+  assert(T->isFunctionType() && "function decl is not of function type");
+  const FunctionType *FT = T->castAs<FunctionType>();
+
+  // Set an implicit return of 'zero' if the function can return some integral,
+  // enumeration, pointer or nullptr type.
+  if (FT->getResultType()->isIntegralOrEnumerationType() ||
+      FT->getResultType()->isAnyPointerType() ||
+      FT->getResultType()->isNullPtrType())
+    // DllMain is exempt because a return value of zero means it failed.
+    if (FD->getName() != "DllMain")
+      FD->setHasImplicitReturnZero(true);
+
+  if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) {
+    Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD->getName();
     FD->setInvalidDecl();
   }
 }

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=190818&r1=190817&r2=190818&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Sep 16 17:44:20 2013
@@ -21,6 +21,7 @@
 #include "clang/AST/TypeOrdering.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/TargetInfo.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
@@ -979,6 +980,10 @@ bool Sema::IsOverload(FunctionDecl *New,
   if (New->isMain())
     return false;
 
+  // MSVCRT user defined entry points cannot be overloaded.
+  if (New->isMSVCRTEntryPoint())
+    return false;
+
   FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
   FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
 

Added: cfe/trunk/test/SemaCXX/ms-overload-entry-point.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/ms-overload-entry-point.cpp?rev=190818&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/ms-overload-entry-point.cpp (added)
+++ cfe/trunk/test/SemaCXX/ms-overload-entry-point.cpp Mon Sep 16 17:44:20 2013
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -triple i386-pc-win32 %s
+
+template <typename T>
+int wmain() { // expected-error{{'wmain' cannot be a template}}
+  return 0;
+}
+
+namespace {
+int WinMain(void) { return 0; }
+int WinMain(int) { return 0; }
+}
+
+void wWinMain(void) {} // expected-note{{previous definition is here}}
+void wWinMain(int) {} // expected-error{{conflicting types for 'wWinMain'}}
+
+int foo() {
+  wmain<void>(); // expected-error{{no matching function for call to 'wmain'}}
+  wmain<int>(); // expected-error{{no matching function for call to 'wmain'}}
+  WinMain();
+  return 0;
+}





More information about the cfe-commits mailing list