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