aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2010-11-17 23:11:54 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2010-11-17 23:11:54 +0000
commit3532fdd1db8ff6f353f2a5b215cebe3e0e2ff3c2 (patch)
treedb6a848f7bc2bd18e2137862feafdb8612f34eea
parentfdda17179047ff0b5e28cc777dc89ebc42f083cf (diff)
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
-rw-r--r--include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--include/clang/Basic/LangOptions.h4
-rw-r--r--include/clang/Driver/CC1Options.td5
-rw-r--r--include/clang/Driver/Options.td2
-rw-r--r--include/clang/Sema/Sema.h7
-rw-r--r--lib/Driver/Tools.cpp9
-rw-r--r--lib/Frontend/CompilerInvocation.cpp2
-rw-r--r--lib/Sema/SemaDecl.cpp38
-rw-r--r--test/SemaCXX/warn-argument-larger-than.cpp42
10 files changed, 114 insertions, 1 deletions
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 7fb14705df..1010e84490 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -158,6 +158,7 @@ def VLA : DiagGroup<"vla">;
def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
def : DiagGroup<"write-strings">;
def CharSubscript : DiagGroup<"char-subscripts">;
+def ArgumentSizeLargerThan : DiagGroup<"argument-larger-than">;
// Aggregation warning settings.
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 4610a72d28..f2cd0ce01c 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -113,6 +113,11 @@ def warn_unused_member_function : Warning<"unused member function %0">,
def warn_used_but_marked_unused: Warning<"%0 was marked unused but was used">,
InGroup<UsedButMarkedUnused>, DefaultIgnore;
+def warn_parameter_size: Warning<"size of %0 is %1 bytes">,
+ InGroup<ArgumentSizeLargerThan>;
+def warn_return_value_size: Warning<"return value of %0 is %1 bytes">,
+ InGroup<ArgumentSizeLargerThan>;
+
def warn_implicit_function_decl : Warning<
"implicit declaration of function %0">,
InGroup<ImplicitFunctionDeclare>, DefaultIgnore;
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index fe69067a6d..558d6dc416 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -122,6 +122,8 @@ private:
public:
unsigned InstantiationDepth; // Maximum template instantiation depth.
+ unsigned ArgumentLargerThan; // Warn if parameter/return value is larger
+ // in bytes than this setting. 0 is no check.
// Version of Microsoft Visual C/C++ we are pretending to be. This is
// temporary until we support all MS extensions used in Windows SDK and stdlib
@@ -175,6 +177,8 @@ public:
InstantiationDepth = 1024;
+ ArgumentLargerThan = 0;
+
Optimize = 0;
OptimizeSize = 0;
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index dee123ddd4..78f79c1eb1 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -500,6 +500,11 @@ def fvisibility_inlines_hidden : Flag<"-fvisibility-inlines-hidden">,
HelpText<"Give inline C++ member functions default visibility by default">;
def ftemplate_depth : Separate<"-ftemplate-depth">,
HelpText<"Maximum depth of recursive template instantiation">;
+def Wargument_larger_than : Separate<"-Wargument-larger-than">,
+ HelpText<"Warn if a function definition returns or accepts an object larger "
+ "in bytes that a given value">;
+def Wargument_larger_than_EQ : Joined<"-Wargument-larger-than=">,
+ Alias<Wargument_larger_than>;
def trigraphs : Flag<"-trigraphs">,
HelpText<"Process trigraph sequences">;
def fwritable_strings : Flag<"-fwritable-strings">,
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 360805b40f..51c366564b 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -401,6 +401,8 @@ def ferror_limit_EQ : Joined<"-ferror-limit=">, Group<f_Group>;
def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group<f_Group>;
def ftemplate_backtrace_limit_EQ : Joined<"-ftemplate-backtrace-limit=">,
Group<f_Group>;
+def Wargument_larger_than_def : Flag<"-Wargument-larger-than">;
+def Wargument_larger_than_EQ : Joined<"-Wargument-larger-than=">;
def fterminated_vtables : Flag<"-fterminated-vtables">, Group<f_Group>;
def fthreadsafe_statics : Flag<"-fthreadsafe-statics">, Group<f_Group>;
def ftime_report : Flag<"-ftime-report">, Group<f_Group>;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 61e263065a..cae11a4a20 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -760,6 +760,13 @@ public:
void DiagnoseUnusedParameters(ParmVarDecl * const *Begin,
ParmVarDecl * const *End);
+ /// \brief Diagnose size of parameters and return value of a Function
+ /// or ObjCMethod.
+ void DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Begin,
+ ParmVarDecl * const *End,
+ QualType ReturnTy,
+ NamedDecl *D);
+
void DiagnoseInvalidJumps(Stmt *Body);
Decl *ActOnFileScopeAsmDecl(SourceLocation Loc, Expr *expr);
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index aa1b439916..d9e3760a8d 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1199,6 +1199,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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 b20520bbee..466dfbd9af 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1373,6 +1373,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
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 c246cad098..dc017d2ba5 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::DiagnoseUnusedParameters(ParmVarDecl * const *Param,
}
}
+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 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
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 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
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;
}
diff --git a/test/SemaCXX/warn-argument-larger-than.cpp b/test/SemaCXX/warn-argument-larger-than.cpp
new file mode 100644
index 0000000000..7a8002530b
--- /dev/null
+++ b/test/SemaCXX/warn-argument-larger-than.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -Wargument-larger-than=100 %s
+
+// rdar://8548050
+namespace rdar8548050 {
+
+struct S100 {
+ char x[100];
+};
+
+struct S101 {
+ char x[101];
+};
+
+S100 f100(S100 s) { return s; }
+
+S101 f101(S101 s) { return s; } // expected-warning {{return value of 'f101' is 101 bytes}} \
+ // expected-warning {{size of 's' is 101 bytes}}
+
+typedef int Arr[200];
+void farr(Arr a) { }
+
+struct NonPOD {
+ char x[200];
+ virtual void m();
+};
+
+NonPOD fNonPOD(NonPOD s) { return s; }
+
+template <unsigned size>
+struct TS {
+ char x[size];
+};
+
+template <unsigned size>
+void tf(TS<size> ts) {} // expected-warning {{size of 'ts' is 300 bytes}}
+
+void g() {
+ TS<300> ts;
+ tf<300>(ts); // expected-note {{instantiation}}
+}
+
+}