[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