diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2010-11-17 23:11:54 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2010-11-17 23:11:54 +0000 |
commit | 3532fdd1db8ff6f353f2a5b215cebe3e0e2ff3c2 (patch) | |
tree | db6a848f7bc2bd18e2137862feafdb8612f34eea | |
parent | fdda17179047ff0b5e28cc777dc89ebc42f083cf (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.td | 1 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | include/clang/Basic/LangOptions.h | 4 | ||||
-rw-r--r-- | include/clang/Driver/CC1Options.td | 5 | ||||
-rw-r--r-- | include/clang/Driver/Options.td | 2 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 7 | ||||
-rw-r--r-- | lib/Driver/Tools.cpp | 9 | ||||
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 38 | ||||
-rw-r--r-- | test/SemaCXX/warn-argument-larger-than.cpp | 42 |
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}} +} + +} |