[cfe-commits] r158887 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/Sema/SemaChecking.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/printf-block.cpp test/Sema
Rafael Espíndola
rafael.espindola at gmail.com
Thu Jun 21 16:52:33 PDT 2012
Sorry, I had to revert this because of
http://llvm.org/bugs/show_bug.cgi?id=13168
On 20 June 2012 21:08, Richard Smith <richard-llvm at metafoo.co.uk> wrote:
> Author: rsmith
> Date: Wed Jun 20 20:08:35 2012
> New Revision: 158887
>
> URL: http://llvm.org/viewvc/llvm-project?rev=158887&view=rev
> Log:
> If an object (such as a std::string) with an appropriate c_str() member function
> is passed to a variadic function in a position where a format string indicates
> that c_str()'s return type is desired, provide a note suggesting that the user
> may have intended to call the c_str() member.
>
> Factor the non-POD-vararg checking out of DefaultVariadicArgumentPromotion and
> move it to SemaChecking in order to facilitate this. Factor the call checking
> out of function call checking and block call checking, and extend it to cover
> constructor calls too.
>
> Patch by Sam Panzer!
>
> Added:
> cfe/trunk/test/SemaCXX/printf-block.cpp
> cfe/trunk/test/SemaCXX/printf-cstr.cpp
> Modified:
> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> cfe/trunk/include/clang/Sema/Sema.h
> cfe/trunk/lib/Sema/SemaChecking.cpp
> cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> cfe/trunk/lib/Sema/SemaExpr.cpp
> cfe/trunk/lib/Sema/SemaOverload.cpp
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=158887&r1=158886&r2=158887&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jun 20 20:08:35 2012
> @@ -4723,6 +4723,11 @@
> "cannot pass object with interface type %0 by-value through variadic "
> "%select{function|block|method}1">;
>
> +def warn_non_pod_vararg_with_format_string : Warning<
> + "cannot pass %select{non-POD|non-trivial}0 object of type %1 to variadic "
> + "function; expected type from format string was %2">,
> + InGroup<DiagGroup<"non-pod-varargs">>, DefaultError;
> +
> def warn_cannot_pass_non_pod_arg_to_vararg : Warning<
> "cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic"
> " %select{function|block|method|constructor}2; call will abort at runtime">,
> @@ -5206,7 +5211,8 @@
> "no closing ']' for '%%[' in scanf format string">,
> InGroup<Format>;
> def note_format_string_defined : Note<"format string is defined here">;
> -
> +def note_printf_c_str: Note<"did you mean to call the %0 method?">;
> +
> def warn_null_arg : Warning<
> "null passed to a callee which requires a non-null argument">,
> InGroup<NonNull>;
> @@ -5666,4 +5672,3 @@
> }
>
> } // end of sema component.
> -
>
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=158887&r1=158886&r2=158887&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Wed Jun 20 20:08:35 2012
> @@ -6409,6 +6409,21 @@
> VariadicDoesNotApply
> };
>
> + VariadicCallType getVariadicCallType(FunctionDecl *FDecl,
> + const FunctionProtoType *Proto,
> + Expr *Fn);
> +
> + // Used for determining in which context a type is allowed to be passed to a
> + // vararg function.
> + enum VarArgKind {
> + VAK_Valid,
> + VAK_ValidInCXX11,
> + VAK_Invalid
> + };
> +
> + // Determines which VarArgKind fits an expression.
> + VarArgKind isValidVarArgType(const QualType &Ty);
> +
> /// GatherArgumentsForCall - Collector argument expressions for various
> /// form of call prototypes.
> bool GatherArgumentsForCall(SourceLocation CallLoc,
> @@ -6421,10 +6436,14 @@
> bool AllowExplicit = false);
>
> // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
> - // will warn if the resulting type is not a POD type.
> + // will return ExprError() if the resulting type is not a POD type.
> ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
> FunctionDecl *FDecl);
>
> + /// Checks to see if the given expression is a valid argument to a variadic
> + /// function, issuing a diagnostic and returning NULL if not.
> + bool variadicArgumentPODCheck(const Expr *E, VariadicCallType CT);
> +
> // UsualArithmeticConversions - performs the UsualUnaryConversions on it's
> // operands and then handles various conversions that are common to binary
> // operators (C99 6.3.1.8). If both operands aren't arithmetic, this
> @@ -6999,10 +7018,33 @@
> const ArraySubscriptExpr *ASE=0,
> bool AllowOnePastEnd=true, bool IndexNegated=false);
> void CheckArrayAccess(const Expr *E);
> - bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
> + // Used to grab the relevant information from a FormatAttr and a
> + // FunctionDeclaration.
> + struct FormatStringInfo {
> + unsigned FormatIdx;
> + unsigned FirstDataArg;
> + bool HasVAListArg;
> + };
> +
> + bool getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
> + FormatStringInfo *FSI);
> + bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
> + const FunctionProtoType *Proto);
> bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc,
> Expr **Args, unsigned NumArgs);
> - bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
> + bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
> + const FunctionProtoType *Proto);
> + void CheckConstructorCall(FunctionDecl *FDecl,
> + Expr **Args,
> + unsigned NumArgs,
> + const FunctionProtoType *Proto,
> + SourceLocation Loc);
> +
> + void checkCall(NamedDecl *FDecl, Expr **Args, unsigned NumArgs,
> + unsigned NumProtoArgs, bool IsMemberFunction,
> + SourceLocation Loc, SourceRange Range,
> + VariadicCallType CallType);
> +
>
> bool CheckObjCString(Expr *Arg);
>
> @@ -7037,21 +7079,31 @@
> FST_Unknown
> };
> static FormatStringType GetFormatStringType(const FormatAttr *Format);
> - bool SemaCheckStringLiteral(const Expr *E, Expr **Args, unsigned NumArgs,
> - bool HasVAListArg, unsigned format_idx,
> - unsigned firstDataArg, FormatStringType Type,
> - bool inFunctionCall = true);
> +
> + enum StringLiteralCheckType {
> + SLCT_NotALiteral,
> + SLCT_UncheckedLiteral,
> + SLCT_CheckedLiteral
> + };
> +
> + StringLiteralCheckType checkFormatStringExpr(const Expr *E,
> + Expr **Args, unsigned NumArgs,
> + bool HasVAListArg,
> + unsigned format_idx,
> + unsigned firstDataArg,
> + FormatStringType Type,
> + bool inFunctionCall = true);
>
> void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr,
> Expr **Args, unsigned NumArgs, bool HasVAListArg,
> unsigned format_idx, unsigned firstDataArg,
> FormatStringType Type, bool inFunctionCall);
>
> - void CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall);
> - void CheckFormatArguments(const FormatAttr *Format, Expr **Args,
> + bool CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall);
> + bool CheckFormatArguments(const FormatAttr *Format, Expr **Args,
> unsigned NumArgs, bool IsCXXMember,
> SourceLocation Loc, SourceRange Range);
> - void CheckFormatArguments(Expr **Args, unsigned NumArgs,
> + bool CheckFormatArguments(Expr **Args, unsigned NumArgs,
> bool HasVAListArg, unsigned format_idx,
> unsigned firstDataArg, FormatStringType Type,
> SourceLocation Loc, SourceRange range);
>
> Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=158887&r1=158886&r2=158887&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Jun 20 20:08:35 2012
> @@ -16,6 +16,7 @@
> #include "clang/Sema/Sema.h"
> #include "clang/Sema/SemaInternal.h"
> #include "clang/Sema/Initialization.h"
> +#include "clang/Sema/Lookup.h"
> #include "clang/Sema/ScopeInfo.h"
> #include "clang/Analysis/Analyses/FormatString.h"
> #include "clang/AST/ASTContext.h"
> @@ -418,34 +419,91 @@
> return false;
> }
>
> -/// CheckFunctionCall - Check a direct function call for various correctness
> -/// and safety properties not strictly enforced by the C type system.
> -bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
> - // Get the IdentifierInfo* for the called function.
> - IdentifierInfo *FnInfo = FDecl->getIdentifier();
> +/// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo
> +/// parameter with the FormatAttr's correct format_idx and firstDataArg.
> +/// Returns true when the format fits the function and the FormatStringInfo has
> +/// been populated.
> +bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
> + FormatStringInfo *FSI) {
> + FSI->HasVAListArg = Format->getFirstArg() == 0;
> + FSI->FormatIdx = Format->getFormatIdx() - 1;
> + FSI->FirstDataArg = FSI->HasVAListArg ? 0 : Format->getFirstArg() - 1;
>
> - // None of the checks below are needed for functions that don't have
> - // simple names (e.g., C++ conversion functions).
> - if (!FnInfo)
> - return false;
> + // The way the format attribute works in GCC, the implicit this argument
> + // of member functions is counted. However, it doesn't appear in our own
> + // lists, so decrement format_idx in that case.
> + if (IsCXXMember) {
> + if(FSI->FormatIdx == 0)
> + return false;
> + --FSI->FormatIdx;
> + if (FSI->FirstDataArg != 0)
> + --FSI->FirstDataArg;
> + }
> + return true;
> +}
>
> +/// Handles the checks for format strings, non-POD arguments to vararg
> +/// functions, and NULL arguments passed to non-NULL parameters.
> +void Sema::checkCall(NamedDecl *FDecl, Expr **Args,
> + unsigned NumArgs,
> + unsigned NumProtoArgs,
> + bool IsMemberFunction,
> + SourceLocation Loc,
> + SourceRange Range,
> + VariadicCallType CallType) {
> // FIXME: This mechanism should be abstracted to be less fragile and
> // more efficient. For example, just map function ids to custom
> // handlers.
>
> // Printf and scanf checking.
> + bool HandledFormatString = false;
> for (specific_attr_iterator<FormatAttr>
> - i = FDecl->specific_attr_begin<FormatAttr>(),
> - e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
> - CheckFormatArguments(*i, TheCall);
> - }
> + I = FDecl->specific_attr_begin<FormatAttr>(),
> + E = FDecl->specific_attr_end<FormatAttr>(); I != E ; ++I)
> + if (CheckFormatArguments(*I, Args, NumArgs, IsMemberFunction, Loc, Range))
> + HandledFormatString = true;
> +
> + // Refuse POD arguments that weren't caught by the format string
> + // checks above.
> + if (!HandledFormatString && CallType != VariadicDoesNotApply)
> + for (unsigned ArgIdx = NumProtoArgs; ArgIdx < NumArgs; ++ArgIdx)
> + variadicArgumentPODCheck(Args[ArgIdx], CallType);
>
> for (specific_attr_iterator<NonNullAttr>
> - i = FDecl->specific_attr_begin<NonNullAttr>(),
> - e = FDecl->specific_attr_end<NonNullAttr>(); i != e; ++i) {
> - CheckNonNullArguments(*i, TheCall->getArgs(),
> - TheCall->getCallee()->getLocStart());
> - }
> + I = FDecl->specific_attr_begin<NonNullAttr>(),
> + E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I)
> + CheckNonNullArguments(*I, Args, Loc);
> +}
> +
> +/// CheckConstructorCall - Check a constructor call for correctness and safety
> +/// properties not enforced by the C type system.
> +void Sema::CheckConstructorCall(FunctionDecl *FDecl, Expr **Args,
> + unsigned NumArgs,
> + const FunctionProtoType *Proto,
> + SourceLocation Loc) {
> + VariadicCallType CallType =
> + Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
> + checkCall(FDecl, Args, NumArgs, Proto->getNumArgs(),
> + /*IsMemberFunction=*/true, Loc, SourceRange(), CallType);
> +}
> +
> +/// CheckFunctionCall - Check a direct function call for various correctness
> +/// and safety properties not strictly enforced by the C type system.
> +bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
> + const FunctionProtoType *Proto) {
> + bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall);
> + VariadicCallType CallType = getVariadicCallType(FDecl, Proto,
> + TheCall->getCallee());
> + unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
> + checkCall(FDecl, TheCall->getArgs(), TheCall->getNumArgs(), NumProtoArgs,
> + IsMemberFunction, TheCall->getRParenLoc(),
> + TheCall->getCallee()->getSourceRange(), CallType);
> +
> + IdentifierInfo *FnInfo = FDecl->getIdentifier();
> + // None of the checks below are needed for functions that don't have
> + // simple names (e.g., C++ conversion functions).
> + if (!FnInfo)
> + return false;
>
> unsigned CMId = FDecl->getMemoryFunctionKind();
> if (CMId == 0)
> @@ -464,25 +522,18 @@
>
> bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
> Expr **Args, unsigned NumArgs) {
> - for (specific_attr_iterator<FormatAttr>
> - i = Method->specific_attr_begin<FormatAttr>(),
> - e = Method->specific_attr_end<FormatAttr>(); i != e ; ++i) {
> -
> - CheckFormatArguments(*i, Args, NumArgs, false, lbrac,
> - Method->getSourceRange());
> - }
> + VariadicCallType CallType =
> + Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply;
>
> - // diagnose nonnull arguments.
> - for (specific_attr_iterator<NonNullAttr>
> - i = Method->specific_attr_begin<NonNullAttr>(),
> - e = Method->specific_attr_end<NonNullAttr>(); i != e; ++i) {
> - CheckNonNullArguments(*i, Args, lbrac);
> - }
> + checkCall(Method, Args, NumArgs, Method->param_size(),
> + /*IsMemberFunction=*/false,
> + lbrac, Method->getSourceRange(), CallType);
>
> return false;
> }
>
> -bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
> +bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
> + const FunctionProtoType *Proto) {
> const VarDecl *V = dyn_cast<VarDecl>(NDecl);
> if (!V)
> return false;
> @@ -491,13 +542,15 @@
> if (!Ty->isBlockPointerType())
> return false;
>
> - // format string checking.
> - for (specific_attr_iterator<FormatAttr>
> - i = NDecl->specific_attr_begin<FormatAttr>(),
> - e = NDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
> - CheckFormatArguments(*i, TheCall);
> - }
> -
> + VariadicCallType CallType =
> + Proto && Proto->isVariadic() ? VariadicBlock : VariadicDoesNotApply ;
> + unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
> +
> + checkCall(NDecl, TheCall->getArgs(), TheCall->getNumArgs(),
> + NumProtoArgs, /*IsMemberFunction=*/false,
> + TheCall->getRParenLoc(),
> + TheCall->getCallee()->getSourceRange(), CallType);
> +
> return false;
> }
>
> @@ -1501,14 +1554,18 @@
> return false;
> }
>
> -// Handle i > 1 ? "x" : "y", recursively.
> -bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
> - unsigned NumArgs, bool HasVAListArg,
> - unsigned format_idx, unsigned firstDataArg,
> - FormatStringType Type, bool inFunctionCall) {
> +// Determine if an expression is a string literal or constant string.
> +// If this function returns false on the arguments to a function expecting a
> +// format string, we will usually need to emit a warning.
> +// True string literals are then checked by CheckFormatString.
> +Sema::StringLiteralCheckType
> +Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
> + unsigned NumArgs, bool HasVAListArg,
> + unsigned format_idx, unsigned firstDataArg,
> + FormatStringType Type, bool inFunctionCall) {
> tryAgain:
> if (E->isTypeDependent() || E->isValueDependent())
> - return false;
> + return SLCT_NotALiteral;
>
> E = E->IgnoreParenCasts();
>
> @@ -1517,18 +1574,26 @@
> // The behavior of printf and friends in this case is implementation
> // dependent. Ideally if the format string cannot be null then
> // it should have a 'nonnull' attribute in the function prototype.
> - return true;
> + return SLCT_CheckedLiteral;
>
> switch (E->getStmtClass()) {
> case Stmt::BinaryConditionalOperatorClass:
> case Stmt::ConditionalOperatorClass: {
> - const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E);
> - return SemaCheckStringLiteral(C->getTrueExpr(), Args, NumArgs, HasVAListArg,
> - format_idx, firstDataArg, Type,
> - inFunctionCall)
> - && SemaCheckStringLiteral(C->getFalseExpr(), Args, NumArgs, HasVAListArg,
> - format_idx, firstDataArg, Type,
> - inFunctionCall);
> + // The expression is a literal if both sub-expressions were, and it was
> + // completely checked only if both sub-expressions were checked.
> + const AbstractConditionalOperator *C =
> + cast<AbstractConditionalOperator>(E);
> + StringLiteralCheckType Left =
> + checkFormatStringExpr(C->getTrueExpr(), Args, NumArgs,
> + HasVAListArg, format_idx, firstDataArg,
> + Type, inFunctionCall);
> + if (Left == SLCT_NotALiteral)
> + return SLCT_NotALiteral;
> + StringLiteralCheckType Right =
> + checkFormatStringExpr(C->getFalseExpr(), Args, NumArgs,
> + HasVAListArg, format_idx, firstDataArg,
> + Type, inFunctionCall);
> + return Left < Right ? Left : Right;
> }
>
> case Stmt::ImplicitCastExprClass: {
> @@ -1541,13 +1606,13 @@
> E = src;
> goto tryAgain;
> }
> - return false;
> + return SLCT_NotALiteral;
>
> case Stmt::PredefinedExprClass:
> // While __func__, etc., are technically not string literals, they
> // cannot contain format specifiers and thus are not a security
> // liability.
> - return true;
> + return SLCT_UncheckedLiteral;
>
> case Stmt::DeclRefExprClass: {
> const DeclRefExpr *DR = cast<DeclRefExpr>(E);
> @@ -1576,9 +1641,10 @@
> if (InitList->isStringLiteralInit())
> Init = InitList->getInit(0)->IgnoreParenImpCasts();
> }
> - return SemaCheckStringLiteral(Init, Args, NumArgs,
> - HasVAListArg, format_idx, firstDataArg,
> - Type, /*inFunctionCall*/false);
> + return checkFormatStringExpr(Init, Args, NumArgs,
> + HasVAListArg, format_idx,
> + firstDataArg, Type,
> + /*inFunctionCall*/false);
> }
> }
>
> @@ -1612,14 +1678,14 @@
> // We can't pass a 'scanf' string to a 'printf' function.
> if (PVIndex == PVFormat->getFormatIdx() &&
> Type == GetFormatStringType(PVFormat))
> - return true;
> + return SLCT_UncheckedLiteral;
> }
> }
> }
> }
> }
>
> - return false;
> + return SLCT_NotALiteral;
> }
>
> case Stmt::CallExprClass:
> @@ -1633,22 +1699,22 @@
> --ArgIndex;
> const Expr *Arg = CE->getArg(ArgIndex - 1);
>
> - return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg,
> - format_idx, firstDataArg, Type,
> - inFunctionCall);
> + return checkFormatStringExpr(Arg, Args, NumArgs,
> + HasVAListArg, format_idx, firstDataArg,
> + Type, inFunctionCall);
> } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
> unsigned BuiltinID = FD->getBuiltinID();
> if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
> BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
> const Expr *Arg = CE->getArg(0);
> - return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg,
> - format_idx, firstDataArg, Type,
> - inFunctionCall);
> + return checkFormatStringExpr(Arg, Args, NumArgs,
> + HasVAListArg, format_idx,
> + firstDataArg, Type, inFunctionCall);
> }
> }
> }
>
> - return false;
> + return SLCT_NotALiteral;
> }
> case Stmt::ObjCStringLiteralClass:
> case Stmt::StringLiteralClass: {
> @@ -1662,14 +1728,14 @@
> if (StrE) {
> CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx,
> firstDataArg, Type, inFunctionCall);
> - return true;
> + return SLCT_CheckedLiteral;
> }
>
> - return false;
> + return SLCT_NotALiteral;
> }
>
> default:
> - return false;
> + return SLCT_NotALiteral;
> }
> }
>
> @@ -1700,42 +1766,34 @@
>
> /// CheckPrintfScanfArguments - Check calls to printf and scanf (and similar
> /// functions) for correct use of format strings.
> -void Sema::CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall) {
> - bool IsCXXMember = false;
> - // The way the format attribute works in GCC, the implicit this argument
> - // of member functions is counted. However, it doesn't appear in our own
> - // lists, so decrement format_idx in that case.
> - IsCXXMember = isa<CXXMemberCallExpr>(TheCall);
> - CheckFormatArguments(Format, TheCall->getArgs(), TheCall->getNumArgs(),
> - IsCXXMember, TheCall->getRParenLoc(),
> - TheCall->getCallee()->getSourceRange());
> +/// Returns true if a format string has been fully checked.
> +bool Sema::CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall) {
> + bool IsCXXMember = isa<CXXMemberCallExpr>(TheCall);
> + return CheckFormatArguments(Format, TheCall->getArgs(),
> + TheCall->getNumArgs(),
> + IsCXXMember, TheCall->getRParenLoc(),
> + TheCall->getCallee()->getSourceRange());
> }
>
> -void Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
> +bool Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
> unsigned NumArgs, bool IsCXXMember,
> SourceLocation Loc, SourceRange Range) {
> - bool HasVAListArg = Format->getFirstArg() == 0;
> - unsigned format_idx = Format->getFormatIdx() - 1;
> - unsigned firstDataArg = HasVAListArg ? 0 : Format->getFirstArg() - 1;
> - if (IsCXXMember) {
> - if (format_idx == 0)
> - return;
> - --format_idx;
> - if(firstDataArg != 0)
> - --firstDataArg;
> - }
> - CheckFormatArguments(Args, NumArgs, HasVAListArg, format_idx,
> - firstDataArg, GetFormatStringType(Format), Loc, Range);
> + FormatStringInfo FSI;
> + if (getFormatStringInfo(Format, IsCXXMember, &FSI))
> + return CheckFormatArguments(Args, NumArgs, FSI.HasVAListArg, FSI.FormatIdx,
> + FSI.FirstDataArg, GetFormatStringType(Format),
> + Loc, Range);
> + return false;
> }
>
> -void Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
> +bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
> bool HasVAListArg, unsigned format_idx,
> unsigned firstDataArg, FormatStringType Type,
> SourceLocation Loc, SourceRange Range) {
> // CHECK: printf/scanf-like function is called with no format string.
> if (format_idx >= NumArgs) {
> Diag(Loc, diag::warn_missing_format_string) << Range;
> - return;
> + return false;
> }
>
> const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts();
> @@ -1752,14 +1810,17 @@
> // C string (e.g. "%d")
> // ObjC string uses the same format specifiers as C string, so we can use
> // the same format string checking logic for both ObjC and C strings.
> - if (SemaCheckStringLiteral(OrigFormatExpr, Args, NumArgs, HasVAListArg,
> - format_idx, firstDataArg, Type))
> - return; // Literal format string found, check done!
> + StringLiteralCheckType CT =
> + checkFormatStringExpr(OrigFormatExpr, Args, NumArgs, HasVAListArg,
> + format_idx, firstDataArg, Type);
> + if (CT != SLCT_NotALiteral)
> + // Literal format string found, check done!
> + return CT == SLCT_CheckedLiteral;
>
> // Strftime is particular as it always uses a single 'time' argument,
> // so it is safe to pass a non-literal string.
> if (Type == FST_Strftime)
> - return;
> + return false;
>
> // Do not emit diag when the string param is a macro expansion and the
> // format is either NSString or CFString. This is a hack to prevent
> @@ -1767,7 +1828,7 @@
> // which are usually used in place of NS and CF string literals.
> if (Type == FST_NSString &&
> SourceMgr.isInSystemMacro(Args[format_idx]->getLocStart()))
> - return;
> + return false;
>
> // If there are no arguments specified, warn with -Wformat-security, otherwise
> // warn only with -Wformat-nonliteral.
> @@ -1779,6 +1840,7 @@
> Diag(Args[format_idx]->getLocStart(),
> diag::warn_format_nonliteral)
> << OrigFormatExpr->getSourceRange();
> + return false;
> }
>
> namespace {
> @@ -2138,7 +2200,11 @@
> bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
> const char *startSpecifier,
> unsigned specifierLen);
> -
> + bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
> + const char *StartSpecifier,
> + unsigned SpecifierLen,
> + const Expr *E);
> +
> bool HandleAmount(const analyze_format_string::OptionalAmount &Amt, unsigned k,
> const char *startSpecifier, unsigned specifierLen);
> void HandleInvalidAmount(const analyze_printf::PrintfSpecifier &FS,
> @@ -2152,6 +2218,9 @@
> const analyze_printf::OptionalFlag &ignoredFlag,
> const analyze_printf::OptionalFlag &flag,
> const char *startSpecifier, unsigned specifierLen);
> + bool checkForCStrMembers(const analyze_printf::ArgTypeResult &ATR,
> + const Expr *E, const CharSourceRange &CSR);
> +
> };
> }
>
> @@ -2269,6 +2338,64 @@
> getSpecifierRange(ignoredFlag.getPosition(), 1)));
> }
>
> +// Determines if the specified is a C++ class or struct containing
> +// a member with the specified name and kind (e.g. a CXXMethodDecl named
> +// "c_str()").
> +template<typename MemberKind>
> +static llvm::SmallPtrSet<MemberKind*, 1>
> +CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
> + const RecordType *RT = Ty->getAs<RecordType>();
> + llvm::SmallPtrSet<MemberKind*, 1> Results;
> +
> + if (!RT)
> + return Results;
> + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
> + if (!RD)
> + return Results;
> +
> + LookupResult R(S, &S.PP.getIdentifierTable().get(Name), SourceLocation(),
> + Sema::LookupMemberName);
> +
> + // We just need to include all members of the right kind turned up by the
> + // filter, at this point.
> + if (S.LookupQualifiedName(R, RT->getDecl()))
> + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
> + NamedDecl *decl = (*I)->getUnderlyingDecl();
> + if (MemberKind *FK = dyn_cast<MemberKind>(decl))
> + Results.insert(FK);
> + }
> + return Results;
> +}
> +
> +// Check if a (w)string was passed when a (w)char* was needed, and offer a
> +// better diagnostic if so. ATR is assumed to be valid.
> +// Returns true when a c_str() conversion method is found.
> +bool CheckPrintfHandler::checkForCStrMembers(
> + const analyze_printf::ArgTypeResult &ATR, const Expr *E,
> + const CharSourceRange &CSR) {
> + typedef llvm::SmallPtrSet<CXXMethodDecl*, 1> MethodSet;
> +
> + MethodSet Results =
> + CXXRecordMembersNamed<CXXMethodDecl>("c_str", S, E->getType());
> +
> + for (MethodSet::iterator MI = Results.begin(), ME = Results.end();
> + MI != ME; ++MI) {
> + const CXXMethodDecl *Method = *MI;
> + if (Method->getNumParams() == 0 &&
> + ATR.matchesType(S.Context, Method->getResultType())) {
> + // FIXME: Suggest parens if the expression needs them.
> + SourceLocation EndLoc =
> + S.getPreprocessor().getLocForEndOfToken(E->getLocEnd());
> + S.Diag(E->getLocStart(), diag::note_printf_c_str)
> + << "c_str()"
> + << FixItHint::CreateInsertion(EndLoc, ".c_str()");
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> bool
> CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
> &FS,
> @@ -2396,20 +2523,30 @@
> if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
> return false;
>
> + return checkFormatExpr(FS, startSpecifier, specifierLen,
> + getDataArg(argIndex));
> +}
> +
> +bool
> +CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
> + const char *StartSpecifier,
> + unsigned SpecifierLen,
> + const Expr *E) {
> + using namespace analyze_format_string;
> + using namespace analyze_printf;
> // Now type check the data expression that matches the
> // format specifier.
> - const Expr *Ex = getDataArg(argIndex);
> const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context,
> ObjCContext);
> - if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
> + if (ATR.isValid() && !ATR.matchesType(S.Context, E->getType())) {
> // Look through argument promotions for our error message's reported type.
> // This includes the integral and floating promotions, but excludes array
> // and function pointer decay; seeing that an argument intended to be a
> // string has type 'char [6]' is probably more confusing than 'char *'.
> - if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex)) {
> + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
> if (ICE->getCastKind() == CK_IntegralCast ||
> ICE->getCastKind() == CK_FloatingCast) {
> - Ex = ICE->getSubExpr();
> + E = ICE->getSubExpr();
>
> // Check if we didn't match because of an implicit cast from a 'char'
> // or 'short' to an 'int'. This is done because printf is a varargs
> @@ -2417,7 +2554,7 @@
> if (ICE->getType() == S.Context.IntTy ||
> ICE->getType() == S.Context.UnsignedIntTy) {
> // All further checking is done on the subexpression.
> - if (ATR.matchesType(S.Context, Ex->getType()))
> + if (ATR.matchesType(S.Context, E->getType()))
> return true;
> }
> }
> @@ -2425,7 +2562,7 @@
>
> // We may be able to offer a FixItHint if it is a supported type.
> PrintfSpecifier fixedFS = FS;
> - bool success = fixedFS.fixType(Ex->getType(), S.getLangOpts(),
> + bool success = fixedFS.fixType(E->getType(), S.getLangOpts(),
> S.Context, ObjCContext);
>
> if (success) {
> @@ -2436,24 +2573,38 @@
>
> EmitFormatDiagnostic(
> S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
> - << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
> - << Ex->getSourceRange(),
> - Ex->getLocStart(),
> + << ATR.getRepresentativeTypeName(S.Context) << E->getType()
> + << E->getSourceRange(),
> + E->getLocStart(),
> /*IsStringLocation*/false,
> - getSpecifierRange(startSpecifier, specifierLen),
> + getSpecifierRange(StartSpecifier, SpecifierLen),
> FixItHint::CreateReplacement(
> - getSpecifierRange(startSpecifier, specifierLen),
> + getSpecifierRange(StartSpecifier, SpecifierLen),
> os.str()));
> - }
> - else {
> - EmitFormatDiagnostic(
> - S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
> - << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
> - << getSpecifierRange(startSpecifier, specifierLen)
> - << Ex->getSourceRange(),
> - Ex->getLocStart(),
> - /*IsStringLocation*/false,
> - getSpecifierRange(startSpecifier, specifierLen));
> + } else {
> + const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
> + SpecifierLen);
> + // Since the warning for passing non-POD types to variadic functions
> + // was deferred until now, we emit a warning for non-POD
> + // arguments here.
> + if (S.isValidVarArgType(E->getType()) == Sema::VAK_Invalid) {
> + EmitFormatDiagnostic(
> + S.PDiag(diag::warn_non_pod_vararg_with_format_string)
> + << S.getLangOpts().CPlusPlus0x
> + << E->getType()
> + << ATR.getRepresentativeTypeName(S.Context)
> + << CSR
> + << E->getSourceRange(),
> + E->getLocStart(), /*IsStringLocation*/false, CSR);
> +
> + checkForCStrMembers(ATR, E, CSR);
> + } else
> + EmitFormatDiagnostic(
> + S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
> + << ATR.getRepresentativeTypeName(S.Context) << E->getType()
> + << CSR
> + << E->getSourceRange(),
> + E->getLocStart(), /*IsStringLocation*/false, CSR);
> }
> }
>
>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=158887&r1=158886&r2=158887&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jun 20 20:08:35 2012
> @@ -9028,13 +9028,6 @@
> unsigned NumExprs = ExprArgs.size();
> Expr **Exprs = (Expr **)ExprArgs.release();
>
> - for (specific_attr_iterator<NonNullAttr>
> - i = Constructor->specific_attr_begin<NonNullAttr>(),
> - e = Constructor->specific_attr_end<NonNullAttr>(); i != e; ++i) {
> - const NonNullAttr *NonNull = *i;
> - CheckNonNullArguments(NonNull, ExprArgs.get(), ConstructLoc);
> - }
> -
> MarkFunctionReferenced(ConstructLoc, Constructor);
> return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
> Constructor, Elidable, Exprs, NumExprs,
> @@ -9100,7 +9093,7 @@
> bool
> Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
> MultiExprArg ArgsPtr,
> - SourceLocation Loc,
> + SourceLocation Loc,
> ASTOwningVector<Expr*> &ConvertedArgs,
> bool AllowExplicit) {
> // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
> @@ -9128,7 +9121,8 @@
>
> DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size());
>
> - // FIXME: Missing call to CheckFunctionCall or equivalent
> + CheckConstructorCall(Constructor, AllArgs.data(), AllArgs.size(),
> + Proto, Loc);
>
> return Invalid;
> }
>
> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=158887&r1=158886&r2=158887&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Jun 20 20:08:35 2012
> @@ -590,12 +590,59 @@
> return Owned(E);
> }
>
> +/// Determine the degree of POD-ness for an expression.
> +/// Incomplete types are considered POD, since this check can be performed
> +/// when we're in an unevaluated context.
> +Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
> + if (Ty->isIncompleteType() || Ty.isCXX98PODType(Context))
> + return VAK_Valid;
> + // C++0x [expr.call]p7:
> + // Passing a potentially-evaluated argument of class type (Clause 9)
> + // having a non-trivial copy constructor, a non-trivial move constructor,
> + // or a non-trivial destructor, with no corresponding parameter,
> + // is conditionally-supported with implementation-defined semantics.
> +
> + if (getLangOpts().CPlusPlus0x && !Ty->isDependentType())
> + if (CXXRecordDecl *Record = Ty->getAsCXXRecordDecl())
> + if (Record->hasTrivialCopyConstructor() &&
> + Record->hasTrivialMoveConstructor() &&
> + Record->hasTrivialDestructor())
> + return VAK_ValidInCXX11;
> +
> + if (getLangOpts().ObjCAutoRefCount && Ty->isObjCLifetimeType())
> + return VAK_Valid;
> + return VAK_Invalid;
> +}
> +
> +bool Sema::variadicArgumentPODCheck(const Expr *E, VariadicCallType CT) {
> + // Don't allow one to pass an Objective-C interface to a vararg.
> + const QualType & Ty = E->getType();
> +
> + // Complain about passing non-POD types through varargs.
> + switch (isValidVarArgType(Ty)) {
> + case VAK_Valid:
> + break;
> + case VAK_ValidInCXX11:
> + DiagRuntimeBehavior(E->getLocStart(), 0,
> + PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg)
> + << E->getType() << CT);
> + break;
> + case VAK_Invalid:
> + return DiagRuntimeBehavior(E->getLocStart(), 0,
> + PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
> + << getLangOpts().CPlusPlus0x << Ty << CT);
> + }
> + // c++ rules are enforced elsewhere.
> + return false;
> +}
> +
> /// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
> /// will warn if the resulting type is not a POD type, and rejects ObjC
> /// interfaces passed by value.
> ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
> FunctionDecl *FDecl) {
> - if (const BuiltinType *PlaceholderTy = E->getType()->getAsPlaceholderType()) {
> + const QualType &Ty = E->getType();
> + if (const BuiltinType *PlaceholderTy = Ty->getAsPlaceholderType()) {
> // Strip the unbridged-cast placeholder expression off, if applicable.
> if (PlaceholderTy->getKind() == BuiltinType::ARCUnbridgedCast &&
> (CT == VariadicMethod ||
> @@ -616,77 +663,44 @@
> return ExprError();
> E = ExprRes.take();
>
> - // Don't allow one to pass an Objective-C interface to a vararg.
> - if (E->getType()->isObjCObjectType() &&
> + if (Ty->isObjCObjectType() &&
> DiagRuntimeBehavior(E->getLocStart(), 0,
> PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
> - << E->getType() << CT))
> + << Ty << CT))
> return ExprError();
>
> - // Complain about passing non-POD types through varargs. However, don't
> - // perform this check for incomplete types, which we can get here when we're
> - // in an unevaluated context.
> - if (!E->getType()->isIncompleteType() &&
> - !E->getType().isCXX98PODType(Context)) {
> - // C++0x [expr.call]p7:
> - // Passing a potentially-evaluated argument of class type (Clause 9)
> - // having a non-trivial copy constructor, a non-trivial move constructor,
> - // or a non-trivial destructor, with no corresponding parameter,
> - // is conditionally-supported with implementation-defined semantics.
> - bool TrivialEnough = false;
> - if (getLangOpts().CPlusPlus0x && !E->getType()->isDependentType()) {
> - if (CXXRecordDecl *Record = E->getType()->getAsCXXRecordDecl()) {
> - if (Record->hasTrivialCopyConstructor() &&
> - Record->hasTrivialMoveConstructor() &&
> - Record->hasTrivialDestructor()) {
> - DiagRuntimeBehavior(E->getLocStart(), 0,
> - PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg)
> - << E->getType() << CT);
> - TrivialEnough = true;
> - }
> - }
> - }
> + // Diagnostics regarding non-POD argument types are
> + // emitted along with format string checking in Sema::CheckFunctionCall().
> + if (isValidVarArgType(Ty) == VAK_Invalid) {
> + // Turn this into a trap.
> + CXXScopeSpec SS;
> + SourceLocation TemplateKWLoc;
> + UnqualifiedId Name;
> + Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"),
> + E->getLocStart());
> + ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc,
> + Name, true, false);
> + if (TrapFn.isInvalid())
> + return ExprError();
>
> - if (!TrivialEnough &&
> - getLangOpts().ObjCAutoRefCount &&
> - E->getType()->isObjCLifetimeType())
> - TrivialEnough = true;
> -
> - if (TrivialEnough) {
> - // Nothing to diagnose. This is okay.
> - } else if (DiagRuntimeBehavior(E->getLocStart(), 0,
> - PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
> - << getLangOpts().CPlusPlus0x << E->getType()
> - << CT)) {
> - // Turn this into a trap.
> - CXXScopeSpec SS;
> - SourceLocation TemplateKWLoc;
> - UnqualifiedId Name;
> - Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"),
> - E->getLocStart());
> - ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc, Name,
> - true, false);
> - if (TrapFn.isInvalid())
> - return ExprError();
> + ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(),
> + E->getLocStart(), MultiExprArg(),
> + E->getLocEnd());
> + if (Call.isInvalid())
> + return ExprError();
>
> - ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), E->getLocStart(),
> - MultiExprArg(), E->getLocEnd());
> - if (Call.isInvalid())
> - return ExprError();
> -
> - ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma,
> - Call.get(), E);
> - if (Comma.isInvalid())
> - return ExprError();
> - E = Comma.get();
> - }
> + ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma,
> + Call.get(), E);
> + if (Comma.isInvalid())
> + return ExprError();
> + return Comma.get();
> }
> - // c++ rules are enforced elsewhere.
> +
> if (!getLangOpts().CPlusPlus &&
> RequireCompleteType(E->getExprLoc(), E->getType(),
> diag::err_call_incomplete_argument))
> return ExprError();
> -
> +
> return Owned(E);
> }
>
> @@ -3415,6 +3429,25 @@
> return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param));
> }
>
> +
> +Sema::VariadicCallType
> +Sema::getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto,
> + Expr *Fn) {
> + if (Proto && Proto->isVariadic()) {
> + if (dyn_cast_or_null<CXXConstructorDecl>(FDecl))
> + return VariadicConstructor;
> + else if (Fn && Fn->getType()->isBlockPointerType())
> + return VariadicBlock;
> + else if (FDecl) {
> + if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(FDecl))
> + if (Method->isInstance())
> + return VariadicMethod;
> + return VariadicFunction;
> + }
> + }
> + return VariadicDoesNotApply;
> +}
> +
> /// ConvertArgumentsForCall - Converts the arguments specified in
> /// Args/NumArgs to the parameter types of the function FDecl with
> /// function prototype Proto. Call is the call expression itself, and
> @@ -3506,12 +3539,8 @@
> }
> }
> SmallVector<Expr *, 8> AllArgs;
> - VariadicCallType CallType =
> - Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
> - if (Fn->getType()->isBlockPointerType())
> - CallType = VariadicBlock; // Block
> - else if (isa<MemberExpr>(Fn))
> - CallType = VariadicMethod;
> + VariadicCallType CallType = getVariadicCallType(FDecl, Proto, Fn);
> +
> Invalid = GatherArgumentsForCall(Call->getLocStart(), FDecl,
> Proto, 0, Args, NumArgs, AllArgs, CallType);
> if (Invalid)
> @@ -3600,7 +3629,6 @@
>
> // If this is a variadic call, handle args passed through "...".
> if (CallType != VariadicDoesNotApply) {
> -
> // Assume that extern "C" functions with variadic arguments that
> // return __unknown_anytype aren't *really* variadic.
> if (Proto->getResultType() == Context.UnknownAnyTy &&
> @@ -3938,7 +3966,8 @@
> TheCall->setType(FuncT->getCallResultType(Context));
> TheCall->setValueKind(Expr::getValueKindForType(FuncT->getResultType()));
>
> - if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT)) {
> + const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT);
> + if (Proto) {
> if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, NumArgs,
> RParenLoc, IsExecConfig))
> return ExprError();
> @@ -3950,8 +3979,7 @@
> // on our knowledge of the function definition.
> const FunctionDecl *Def = 0;
> if (FDecl->hasBody(Def) && NumArgs != Def->param_size()) {
> - const FunctionProtoType *Proto
> - = Def->getType()->getAs<FunctionProtoType>();
> + Proto = Def->getType()->getAs<FunctionProtoType>();
> if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size()))
> Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
> << (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
> @@ -4009,13 +4037,13 @@
>
> // Do special checking on direct calls to functions.
> if (FDecl) {
> - if (CheckFunctionCall(FDecl, TheCall))
> + if (CheckFunctionCall(FDecl, TheCall, Proto))
> return ExprError();
>
> if (BuiltinID)
> return CheckBuiltinFunctionCall(BuiltinID, TheCall);
> } else if (NDecl) {
> - if (CheckBlockCall(NDecl, TheCall))
> + if (CheckBlockCall(NDecl, TheCall, Proto))
> return ExprError();
> }
>
>
> Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=158887&r1=158886&r2=158887&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jun 20 20:08:35 2012
> @@ -10720,7 +10720,7 @@
>
> DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
>
> - if (CheckFunctionCall(Method, TheCall))
> + if (CheckFunctionCall(Method, TheCall, Proto))
> return ExprError();
>
> if ((isa<CXXConstructorDecl>(CurContext) ||
> @@ -11028,7 +11028,7 @@
>
> DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
>
> - if (CheckFunctionCall(Method, TheCall))
> + if (CheckFunctionCall(Method, TheCall, Proto))
> return true;
>
> return MaybeBindToTemporary(TheCall);
> @@ -11208,7 +11208,7 @@
> if (CheckCallReturnType(FD->getResultType(), UDSuffixLoc, UDL, FD))
> return ExprError();
>
> - if (CheckFunctionCall(FD, UDL))
> + if (CheckFunctionCall(FD, UDL, NULL))
> return ExprError();
>
> return MaybeBindToTemporary(UDL);
>
> Added: cfe/trunk/test/SemaCXX/printf-block.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/printf-block.cpp?rev=158887&view=auto
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/printf-block.cpp (added)
> +++ cfe/trunk/test/SemaCXX/printf-block.cpp Wed Jun 20 20:08:35 2012
> @@ -0,0 +1,18 @@
> +// RUN: %clang_cc1 -fsyntax-only -fblocks -Wformat -verify %s -Wno-error=non-pod-varargs
> +
> +int (^block) (int, const char *,...) __attribute__((__format__(__printf__,2,3))) = ^ __attribute__((__format__(__printf__,2,3))) (int arg, const char *format,...) {return 5;};
> +
> +class HasNoCStr {
> + const char *str;
> + public:
> + HasNoCStr(const char *s): str(s) { }
> + const char *not_c_str() {return str;}
> +};
> +
> +void test_block() {
> + const char str[] = "test";
> + HasNoCStr hncs(str);
> + int n = 4;
> + block(n, "%s %d", str, n); // no-warning
> + block(n, "%s %s", hncs, n); // expected-warning{{cannot pass non-POD object of type 'HasNoCStr' to variadic function; expected type from format string was 'char *'}} expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
> +}
>
> Added: cfe/trunk/test/SemaCXX/printf-cstr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/printf-cstr.cpp?rev=158887&view=auto
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/printf-cstr.cpp (added)
> +++ cfe/trunk/test/SemaCXX/printf-cstr.cpp Wed Jun 20 20:08:35 2012
> @@ -0,0 +1,53 @@
> +// RUN: %clang_cc1 -fsyntax-only -Wformat -verify %s -Wno-error=non-pod-varargs
> +
> +#include <stdarg.h>
> +
> +extern "C" {
> +extern int printf(const char *restrict, ...);
> +extern int sprintf(char *, const char *restrict, ...);
> +}
> +
> +class HasCStr {
> + const char *str;
> + public:
> + HasCStr(const char *s): str(s) { }
> + const char *c_str() {return str;}
> +};
> +
> +class HasNoCStr {
> + const char *str;
> + public:
> + HasNoCStr(const char *s): str(s) { }
> + const char *not_c_str() {return str;}
> +};
> +
> +extern const char extstr[16];
> +void pod_test() {
> + char str[] = "test";
> + char dest[32];
> + char formatString[] = "non-const %s %s";
> + HasCStr hcs(str);
> + HasNoCStr hncs(str);
> + int n = 10;
> +
> + printf("%d: %s\n", n, hcs.c_str());
> + printf("%d: %s\n", n, hcs); // expected-warning{{cannot pass non-POD object of type 'HasCStr' to variadic function; expected type from format string was 'char *'}} expected-note{{did you mean to call the c_str() method?}}
> + printf("%d: %s\n", n, hncs); // expected-warning{{cannot pass non-POD object of type 'HasNoCStr' to variadic function; expected type from format string was 'char *'}}
> + sprintf(str, "%d: %s", n, hcs); // expected-warning{{cannot pass non-POD object of type 'HasCStr' to variadic function; expected type from format string was 'char *'}} expected-note{{did you mean to call the c_str() method?}}
> +
> + printf(formatString, hcs, hncs); // expected-warning{{cannot pass object of non-POD type 'HasCStr' through variadic function}} expected-warning{{cannot pass object of non-POD type 'HasNoCStr' through variadic function}}
> + printf(extstr, hcs, n); // expected-warning{{cannot pass object of non-POD type 'HasCStr' through variadic function}}
> +}
> +
> +struct Printf {
> + Printf();
> + Printf(const Printf&);
> + Printf(const char *,...) __attribute__((__format__(__printf__,2,3)));
> +};
> +
> +void constructor_test() {
> + const char str[] = "test";
> + HasCStr hcs(str);
> + Printf p("%s %d %s", str, 10, 10); // expected-warning {{format specifies type 'char *' but the argument has type 'int'}}
> + Printf q("%s %d", hcs, 10); // expected-warning {{cannot pass non-POD object of type 'HasCStr' to variadic function; expected type from format string was 'char *'}} expected-note{{did you mean to call the c_str() method?}}
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list