]> granicus.if.org Git - clang/commitdiff
[-cxx-abi microsoft] Correctly identify Win32 entry points
authorDavid Majnemer <david.majnemer@gmail.com>
Mon, 16 Sep 2013 22:44:20 +0000 (22:44 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Mon, 16 Sep 2013 22:44:20 +0000 (22:44 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@190818 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/AST/Decl.cpp
lib/AST/MicrosoftMangle.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaOverload.cpp
test/SemaCXX/ms-overload-entry-point.cpp [new file with mode: 0644]

index 1ca63489f6eb21d8b61fe86428f07714509bf66a..7cd61fcc227392021ef32eae4de5559214d16437 100644 (file)
@@ -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 *);
index 518190c2a4ebfc3854f16976d9f1bcf0e943ac09..9f620fefa15047a8a323e324fbb7f9708a8d435e 100644 (file)
@@ -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>;
index ad27b3fd3ffc6df95d4d01a48f1a94d6eaa6a4c3..573f028019947360632a0975317a645a4f69b06c 100644 (file)
@@ -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,
index 1c2ead0ee59722b6c18e40e26ad4cb6f2ea5eca6..0fa1b980f31199c6f02cfe00eaec1c0015b0668c 100644 (file)
@@ -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 ||
index 9cea06187e2f61f7f58d42e431f5b11d25fbd7b5..8506c4c8dde691f187e54c593c1d1cef8d7a4c75 100644 (file)
@@ -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(const FunctionDecl *fn) {
   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::shouldMangleDeclName(const NamedDecl *D) {
     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
index 9c93e113125c7ecc7503e6109dccb3f7f8c7ec3f..a2e05e0094f5c8490c0b40fe040d36bf157a5ed6 100644 (file)
@@ -6881,6 +6881,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
     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, Declarator &D, DeclContext *DC,
       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, const DeclSpec& DS) {
   }
   
   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();
   }
 }
index c7620e49f7c73048ae697dd5e19c595aa924565c..800f9832498329c6e87c603c05035008d94cc354 100644 (file)
@@ -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, FunctionDecl *Old,
   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();
 
diff --git a/test/SemaCXX/ms-overload-entry-point.cpp b/test/SemaCXX/ms-overload-entry-point.cpp
new file mode 100644 (file)
index 0000000..67fed01
--- /dev/null
@@ -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;
+}