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

Aaron Ballman aaron at aaronballman.com
Fri Sep 13 16:35:03 PDT 2013


> Index: include/clang/AST/Decl.h
> ===================================================================
> --- include/clang/AST/Decl.h
> +++ include/clang/AST/Decl.h
> @@ -1735,6 +1735,10 @@
>    /// entry point into an executable program.
>    bool isMain() const;
>
> +  /// \brief Determines whether this function is a Win32 user defined entry
> +  /// point.
> +  bool isWin32EntryPoint() const;
> +
>    /// \brief Determines whether this operator new or delete is one
>    /// of the reserved global placement operators:
>    ///    void *operator new(size_t, void *);
> Index: include/clang/Basic/DiagnosticSemaKinds.td
> ===================================================================
> --- include/clang/Basic/DiagnosticSemaKinds.td
> +++ include/clang/Basic/DiagnosticSemaKinds.td
> @@ -419,7 +419,7 @@
>  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: include/clang/Sema/Sema.h
> ===================================================================
> --- include/clang/Sema/Sema.h
> +++ include/clang/Sema/Sema.h
> @@ -1495,6 +1495,7 @@
>                                  FunctionDecl *NewFD, LookupResult &Previous,
>                                  bool IsExplicitSpecialization);
>    void CheckMain(FunctionDecl *FD, const DeclSpec &D);
> +  void CheckWin32EntryPoint(FunctionDecl *FD);
>    Decl *ActOnParamDeclarator(Scope *S, Declarator &D);
>    ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
>                                            SourceLocation Loc,
> Index: lib/AST/Decl.cpp
> ===================================================================
> --- lib/AST/Decl.cpp
> +++ lib/AST/Decl.cpp
> @@ -2204,6 +2204,34 @@
>           isNamed(this, "main");
>  }
>
> +bool FunctionDecl::isWin32EntryPoint() const {
> +  const TranslationUnitDecl *TUnit =
> +      dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
> +  if (!TUnit)
> +    return false;
> +
> +  // Even though ee aren't really targeting Win32 if we are freestanding,

Typo with ee

> +  // semantic analysis for these functions remain the same.

Remains instead of remain

> +
> +  // Win32 entry points only exist on win32 targets.
> +  if (TUnit->getASTContext().getTargetInfo().getTriple().getOS() !=
> +      llvm::Triple::Win32)
> +    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

Capital A should be lowercase

> +             "WinMain",  // An ANSI GUI app
> +             "wWinMain", // A Unicode GUI app
> +             "DllMain",  // A DLL

If we're including DllMain, what about other "main" entrypoints like
CplApplet (and other esoteric ones)?

> +             true)
> +      .Default(false);
> +}

This is based solely on the name, and not on the signature.  What if I
had a console app that did this:

#include <Windows.h>

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { return 0; }
int main(void) {
  return WinMain(0, 0, 0, 0); // Hahaha
}

> +
>  bool FunctionDecl::isReservedGlobalPlacementOperator() const {
>    assert(getDeclName().getNameKind() == DeclarationName::CXXOperatorName);
>    assert(getDeclName().getCXXOverloadedOperator() == OO_New ||
> Index: lib/AST/MicrosoftMangle.cpp
> ===================================================================
> --- lib/AST/MicrosoftMangle.cpp
> +++ lib/AST/MicrosoftMangle.cpp
> @@ -71,29 +71,6 @@
>    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 +231,16 @@
>      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->isWin32EntryPoint())
>        return false;
>
>      // C++ functions and those whose names are not a simple identifier need
> Index: lib/Sema/SemaDecl.cpp
> ===================================================================
> --- lib/Sema/SemaDecl.cpp
> +++ lib/Sema/SemaDecl.cpp
> @@ -6879,7 +6879,10 @@
>      // Perform semantic checking on the function declaration.
>      bool isExplicitSpecialization=false;
>      if (!NewFD->isInvalidDecl() && NewFD->isMain())
> -      CheckMain(NewFD, D.getDeclSpec());
> +        CheckMain(NewFD, D.getDeclSpec());
> +
> +    if (!NewFD->isInvalidDecl() && NewFD->isWin32EntryPoint())
> +        CheckWin32EntryPoint(NewFD);
>
>      if (!NewFD->isInvalidDecl())
>        D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
> @@ -7000,6 +7003,9 @@
>        if (!NewFD->isInvalidDecl() && NewFD->isMain())
>          CheckMain(NewFD, D.getDeclSpec());
>
> +      if (!NewFD->isInvalidDecl() && NewFD->isWin32EntryPoint())
> +        CheckWin32EntryPoint(NewFD);
> +
>        if (NewFD->isInvalidDecl()) {
>          // If this is a class member, mark the class invalid immediately.
>          // This avoids some consistency errors later.
> @@ -7670,7 +7676,25 @@
>    }
>
>    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::CheckWin32EntryPoint(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())
> +    FD->setHasImplicitReturnZero(true);
> +
> +  if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) {
> +    Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD->getName();
>      FD->setInvalidDecl();
>    }
>  }
> Index: lib/Sema/SemaOverload.cpp
> ===================================================================
> --- lib/Sema/SemaOverload.cpp
> +++ lib/Sema/SemaOverload.cpp
> @@ -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 @@
>    if (New->isMain())
>      return false;
>
> +  // Win32 user defined entry points cannot be overloaded.
> +  if (New->isWin32EntryPoint())
> +        return false;
> +
>    FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
>    FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
>
> Index: test/SemaCXX/ms-overload-entry-point.cpp
> ===================================================================
> --- /dev/null
> +++ test/SemaCXX/ms-overload-entry-point.cpp
> @@ -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;
> +}
>

~Aaron

On Fri, Sep 13, 2013 at 7:03 PM, David Majnemer
<david.majnemer at gmail.com> wrote:
> Hi rnk, rsmith, whunt, timurrrr,
>
> 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.
>
> http://llvm-reviews.chandlerc.com/D1683
>
> Files:
>   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
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>



More information about the cfe-commits mailing list