Introduce option -Wargument-larger-than[=N] which warns about function definitions if they take by-value
or return by-value any POD that is larger than some threshold (default is 64 bytes).

Implements rdar://8548050.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@119583 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index aa1b439..d9e3760 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1199,6 +1199,15 @@
     CmdArgs.push_back(A->getValue(Args));
   }
 
+  if (Arg *A = Args.getLastArg(options::OPT_Wargument_larger_than_EQ,
+                               options::OPT_Wargument_larger_than_def)) {
+    CmdArgs.push_back("-Wargument-larger-than");
+    if (A->getNumValues())
+      CmdArgs.push_back(A->getValue(Args));
+    else
+      CmdArgs.push_back("64"); // default value for -Wargument-larger-than
+  }
+
   if (Args.hasArg(options::OPT__relocatable_pch))
     CmdArgs.push_back("-relocatable-pch");
 
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index b20520b..466dfbd 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1373,6 +1373,8 @@
   Opts.MathErrno = Args.hasArg(OPT_fmath_errno);
   Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024,
                                                Diags);
+  Opts.ArgumentLargerThan = Args.getLastArgIntValue(OPT_Wargument_larger_than,
+                                                    0, Diags);
   Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
   Opts.ObjCConstantStringClass =
     Args.getLastArgValue(OPT_fconstant_string_class);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c246cad..dc017d2 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -26,6 +26,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/StmtCXX.h"
+#include "clang/AST/CharUnits.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Parse/ParseDiagnostic.h"
@@ -4864,6 +4865,36 @@
   }
 }
 
+void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
+                                                  ParmVarDecl * const *ParamEnd,
+                                                  QualType ReturnTy,
+                                                  NamedDecl *D) {
+  if (LangOpts.ArgumentLargerThan == 0) // No check.
+    return;
+
+  if (ReturnTy->isPODType() &&
+      Diags.getDiagnosticLevel(diag::warn_return_value_size) !=
+          Diagnostic::Ignored) {
+    unsigned Size = Context.getTypeSizeInChars(ReturnTy).getQuantity();
+    if (Size > LangOpts.ArgumentLargerThan)
+      Diag(D->getLocation(), diag::warn_return_value_size)
+          << D->getDeclName() << Size;
+  }
+
+  if (Diags.getDiagnosticLevel(diag::warn_parameter_size)==Diagnostic::Ignored)
+    return;
+
+  for (; Param != ParamEnd; ++Param) {
+    QualType T = (*Param)->getType();
+    if (!T->isPODType())
+      continue;
+    unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
+    if (Size > LangOpts.ArgumentLargerThan)
+      Diag((*Param)->getLocation(), diag::warn_parameter_size)
+          << (*Param)->getDeclName() << Size;
+  }
+}
+
 ParmVarDecl *Sema::CheckParameter(DeclContext *DC, 
                                   TypeSourceInfo *TSInfo, QualType T,
                                   IdentifierInfo *Name,
@@ -5162,6 +5193,8 @@
 
     if (!FD->isInvalidDecl()) {
       DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
+      DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(),
+                                             FD->getResultType(), FD);
       
       // If this is a constructor, we need a vtable.
       if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD))
@@ -5175,8 +5208,11 @@
     assert(MD == getCurMethodDecl() && "Method parsing confused");
     MD->setBody(Body);
     MD->setEndLoc(Body->getLocEnd());
-    if (!MD->isInvalidDecl())
+    if (!MD->isInvalidDecl()) {
       DiagnoseUnusedParameters(MD->param_begin(), MD->param_end());
+      DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(),
+                                             MD->getResultType(), MD);
+    }
   } else {
     return 0;
   }