>From 478fe4d52a6f21c4f439f3d44019d88872f1a2fb Mon Sep 17 00:00:00 2001
From: Vasiliy Korchagin <korchagin@ispras.ru>
Date: Wed, 8 Feb 2012 16:12:09 +0400
Subject: [PATCH] Added option "-allow-non-int-main" which allows main() function to have non-integer return type.

---
 include/clang/Basic/DiagnosticSemaKinds.td         |    2 ++
 include/clang/Basic/LangOptions.def                |    1 +
 include/clang/Driver/CC1Options.td                 |    2 ++
 include/clang/Driver/Options.td                    |    2 ++
 lib/Driver/Tools.cpp                               |    3 +++
 lib/Frontend/CompilerInvocation.cpp                |    5 +++++
 lib/Sema/SemaDecl.cpp                              |   10 +++++++---
 .../CXX/basic/basic.start/basic.start.main/p2j.cpp |    4 ++++
 8 files changed, 26 insertions(+), 3 deletions(-)
 create mode 100644 test/CXX/basic/basic.start/basic.start.main/p2j.cpp

diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 4366cd4..40cbe4c 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -346,6 +346,8 @@ 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_main_returns_nonint : Error<"'main' must return 'int'">;
+def warn_main_returns_nonint : Warning<"return type of 'main' is not 'int'">,
+    InGroup<Main>;
 def err_main_surplus_args : Error<"too many parameters (%0) for 'main': "
     "must be 0, 2, or 3">;
 def warn_main_one_arg : Warning<"only one parameter on 'main' declaration">,
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index d2dff89..7ba60fa 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -56,6 +56,7 @@ BENIGN_LANGOPT(ObjCDefaultSynthProperties , 1, 0,
                "Objective-C auto-synthesized properties")
 BENIGN_LANGOPT(ObjCInferRelatedResultType , 1, 1, 
                "Objective-C related result type inference")
+LANGOPT(AllowNonIntMain   , 1, 0, "Allow main() to have non-integer return type.")
 LANGOPT(Trigraphs         , 1, 0,"trigraphs")
 LANGOPT(BCPLComment       , 1, 0, "BCPL-style '//' comments")
 LANGOPT(Bool              , 1, 0, "bool, true, and false keywords")
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 557e73b..c17c170 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -478,6 +478,8 @@ def foverride_record_layout_EQ : Joined<"-foverride-record-layout=">,
 // Language Options
 //===----------------------------------------------------------------------===//
 
+def allow_non_int_main : Flag<"-allow-non-int-main">,
+  HelpText<"Allow main() to have non-integer return type">;
 def fno_builtin : Flag<"-fno-builtin">,
   HelpText<"Disable implicit builtin knowledge of functions">;
 def faltivec : Flag<"-faltivec">,
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index f0c7f05..37ec48f 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -214,6 +214,8 @@ def X_Joined : Joined<"-X">;
 def Z_Flag : Flag<"-Z">;
 def Z_Joined : Joined<"-Z">;
 def all__load : Flag<"-all_load">;
+def allow_non_int_main : Flag<"-allow-non-int-main">,
+  HelpText<"Allow main() to have non-integer return type">;
 def allowable__client : Separate<"-allowable_client">;
 def ansi : Flag<"-ansi">, Group<a_Group>;
 def arch__errors__fatal : Flag<"-arch_errors_fatal">;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 714a21a..aad4980 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1846,6 +1846,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     CmdArgs.push_back(A->getValue(Args));
   }
 
+  if (Args.hasArg(options::OPT_allow_non_int_main))
+    CmdArgs.push_back("-allow-non-int-main");
+
   if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ,
                                options::OPT_Wlarge_by_value_copy_def)) {
     CmdArgs.push_back("-Wlarge-by-value-copy");
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 8417aa4..8c721d3 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -653,6 +653,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
   // It would be better to push the all target specific choices into the driver,
   // so that everything below that was more uniform.
 
+  if (Opts.AllowNonIntMain)
+    Res.push_back("-allow-non-int-main");
   if (Opts.Trigraphs)
     Res.push_back("-trigraphs");
   // Implicit based on the input kind:
@@ -1746,6 +1748,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
   Opts.GNUKeywords = Args.hasFlag(OPT_fgnu_keywords, OPT_fno_gnu_keywords,
                                   Opts.GNUKeywords);
 
+  if (Args.hasArg(OPT_allow_non_int_main))
+    Opts.AllowNonIntMain = 1;
+
   if (Args.hasArg(OPT_fno_operator_names))
     Opts.CXXOperatorNames = 0;
 
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index ffc7c61..5ba9ea2 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -5802,8 +5802,12 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
   const FunctionType* FT = T->getAs<FunctionType>();
 
   if (!Context.hasSameUnqualifiedType(FT->getResultType(), Context.IntTy)) {
-    Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint);
-    FD->setInvalidDecl(true);
+    if (Context.getLangOptions().AllowNonIntMain) {
+      Diag(FD->getTypeSpecStartLoc(), diag::warn_main_returns_nonint);
+    } else {
+      Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint);
+      FD->setInvalidDecl(true);
+    }
   }
 
   // Treat protoless main() as nullary.
@@ -7208,7 +7212,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
 
   if (FD) {
     FD->setBody(Body);
-    if (FD->isMain()) {
+    if (FD->isMain() && !Context.getLangOptions().AllowNonIntMain) {
       // C and C++ allow for main to automagically return 0.
       // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
       FD->setHasImplicitReturnZero(true);
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2j.cpp b/test/CXX/basic/basic.start/basic.start.main/p2j.cpp
new file mode 100644
index 0000000..b9bee76
--- /dev/null
+++ b/test/CXX/basic/basic.start/basic.start.main/p2j.cpp
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -allow-non-int-main -fsyntax-only -verify %s
+
+void main() { // expected-warning {{return type of 'main' is not 'int'}}
+}
-- 
1.7.5.4

