зеркало из https://github.com/microsoft/clang-1.git
Revert r158887. This fixes pr13168.
Revert "If an object (such as a std::string) with an appropriate c_str() member function"
This reverts commit 7d96f6106b
.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158949 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
e601b237e4
Коммит
4e294eea2c
|
@ -4723,11 +4723,6 @@ def err_cannot_pass_objc_interface_to_vararg : Error<
|
||||||
"cannot pass object with interface type %0 by-value through variadic "
|
"cannot pass object with interface type %0 by-value through variadic "
|
||||||
"%select{function|block|method}1">;
|
"%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<
|
def warn_cannot_pass_non_pod_arg_to_vararg : Warning<
|
||||||
"cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic"
|
"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">,
|
" %select{function|block|method|constructor}2; call will abort at runtime">,
|
||||||
|
@ -5211,7 +5206,6 @@ def warn_scanf_scanlist_incomplete : Warning<
|
||||||
"no closing ']' for '%%[' in scanf format string">,
|
"no closing ']' for '%%[' in scanf format string">,
|
||||||
InGroup<Format>;
|
InGroup<Format>;
|
||||||
def note_format_string_defined : Note<"format string is defined here">;
|
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<
|
def warn_null_arg : Warning<
|
||||||
"null passed to a callee which requires a non-null argument">,
|
"null passed to a callee which requires a non-null argument">,
|
||||||
|
@ -5672,3 +5666,4 @@ def err_module_private_definition : Error<
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of sema component.
|
} // end of sema component.
|
||||||
|
|
||||||
|
|
|
@ -6409,21 +6409,6 @@ public:
|
||||||
VariadicDoesNotApply
|
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
|
/// GatherArgumentsForCall - Collector argument expressions for various
|
||||||
/// form of call prototypes.
|
/// form of call prototypes.
|
||||||
bool GatherArgumentsForCall(SourceLocation CallLoc,
|
bool GatherArgumentsForCall(SourceLocation CallLoc,
|
||||||
|
@ -6436,14 +6421,10 @@ public:
|
||||||
bool AllowExplicit = false);
|
bool AllowExplicit = false);
|
||||||
|
|
||||||
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
|
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
|
||||||
// will return ExprError() if the resulting type is not a POD type.
|
// will warn if the resulting type is not a POD type.
|
||||||
ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
|
ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
|
||||||
FunctionDecl *FDecl);
|
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
|
// UsualArithmeticConversions - performs the UsualUnaryConversions on it's
|
||||||
// operands and then handles various conversions that are common to binary
|
// operands and then handles various conversions that are common to binary
|
||||||
// operators (C99 6.3.1.8). If both operands aren't arithmetic, this
|
// operators (C99 6.3.1.8). If both operands aren't arithmetic, this
|
||||||
|
@ -7018,33 +6999,10 @@ private:
|
||||||
const ArraySubscriptExpr *ASE=0,
|
const ArraySubscriptExpr *ASE=0,
|
||||||
bool AllowOnePastEnd=true, bool IndexNegated=false);
|
bool AllowOnePastEnd=true, bool IndexNegated=false);
|
||||||
void CheckArrayAccess(const Expr *E);
|
void CheckArrayAccess(const Expr *E);
|
||||||
// Used to grab the relevant information from a FormatAttr and a
|
bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
|
||||||
// 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,
|
bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc,
|
||||||
Expr **Args, unsigned NumArgs);
|
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);
|
bool CheckObjCString(Expr *Arg);
|
||||||
|
|
||||||
|
@ -7079,19 +7037,9 @@ private:
|
||||||
FST_Unknown
|
FST_Unknown
|
||||||
};
|
};
|
||||||
static FormatStringType GetFormatStringType(const FormatAttr *Format);
|
static FormatStringType GetFormatStringType(const FormatAttr *Format);
|
||||||
|
bool SemaCheckStringLiteral(const Expr *E, Expr **Args, unsigned NumArgs,
|
||||||
enum StringLiteralCheckType {
|
bool HasVAListArg, unsigned format_idx,
|
||||||
SLCT_NotALiteral,
|
unsigned firstDataArg, FormatStringType Type,
|
||||||
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);
|
bool inFunctionCall = true);
|
||||||
|
|
||||||
void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr,
|
void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr,
|
||||||
|
@ -7099,11 +7047,11 @@ private:
|
||||||
unsigned format_idx, unsigned firstDataArg,
|
unsigned format_idx, unsigned firstDataArg,
|
||||||
FormatStringType Type, bool inFunctionCall);
|
FormatStringType Type, bool inFunctionCall);
|
||||||
|
|
||||||
bool CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall);
|
void CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall);
|
||||||
bool CheckFormatArguments(const FormatAttr *Format, Expr **Args,
|
void CheckFormatArguments(const FormatAttr *Format, Expr **Args,
|
||||||
unsigned NumArgs, bool IsCXXMember,
|
unsigned NumArgs, bool IsCXXMember,
|
||||||
SourceLocation Loc, SourceRange Range);
|
SourceLocation Loc, SourceRange Range);
|
||||||
bool CheckFormatArguments(Expr **Args, unsigned NumArgs,
|
void CheckFormatArguments(Expr **Args, unsigned NumArgs,
|
||||||
bool HasVAListArg, unsigned format_idx,
|
bool HasVAListArg, unsigned format_idx,
|
||||||
unsigned firstDataArg, FormatStringType Type,
|
unsigned firstDataArg, FormatStringType Type,
|
||||||
SourceLocation Loc, SourceRange range);
|
SourceLocation Loc, SourceRange range);
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include "clang/Sema/Sema.h"
|
#include "clang/Sema/Sema.h"
|
||||||
#include "clang/Sema/SemaInternal.h"
|
#include "clang/Sema/SemaInternal.h"
|
||||||
#include "clang/Sema/Initialization.h"
|
#include "clang/Sema/Initialization.h"
|
||||||
#include "clang/Sema/Lookup.h"
|
|
||||||
#include "clang/Sema/ScopeInfo.h"
|
#include "clang/Sema/ScopeInfo.h"
|
||||||
#include "clang/Analysis/Analyses/FormatString.h"
|
#include "clang/Analysis/Analyses/FormatString.h"
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "clang/AST/ASTContext.h"
|
||||||
|
@ -419,91 +418,34 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo
|
/// CheckFunctionCall - Check a direct function call for various correctness
|
||||||
/// parameter with the FormatAttr's correct format_idx and firstDataArg.
|
/// and safety properties not strictly enforced by the C type system.
|
||||||
/// Returns true when the format fits the function and the FormatStringInfo has
|
bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
|
||||||
/// been populated.
|
// Get the IdentifierInfo* for the called function.
|
||||||
bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
|
IdentifierInfo *FnInfo = FDecl->getIdentifier();
|
||||||
FormatStringInfo *FSI) {
|
|
||||||
FSI->HasVAListArg = Format->getFirstArg() == 0;
|
|
||||||
FSI->FormatIdx = Format->getFormatIdx() - 1;
|
|
||||||
FSI->FirstDataArg = FSI->HasVAListArg ? 0 : Format->getFirstArg() - 1;
|
|
||||||
|
|
||||||
// The way the format attribute works in GCC, the implicit this argument
|
// None of the checks below are needed for functions that don't have
|
||||||
// of member functions is counted. However, it doesn't appear in our own
|
// simple names (e.g., C++ conversion functions).
|
||||||
// lists, so decrement format_idx in that case.
|
if (!FnInfo)
|
||||||
if (IsCXXMember) {
|
|
||||||
if(FSI->FormatIdx == 0)
|
|
||||||
return false;
|
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
|
// FIXME: This mechanism should be abstracted to be less fragile and
|
||||||
// more efficient. For example, just map function ids to custom
|
// more efficient. For example, just map function ids to custom
|
||||||
// handlers.
|
// handlers.
|
||||||
|
|
||||||
// Printf and scanf checking.
|
// Printf and scanf checking.
|
||||||
bool HandledFormatString = false;
|
|
||||||
for (specific_attr_iterator<FormatAttr>
|
for (specific_attr_iterator<FormatAttr>
|
||||||
I = FDecl->specific_attr_begin<FormatAttr>(),
|
i = FDecl->specific_attr_begin<FormatAttr>(),
|
||||||
E = FDecl->specific_attr_end<FormatAttr>(); I != E ; ++I)
|
e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
|
||||||
if (CheckFormatArguments(*I, Args, NumArgs, IsMemberFunction, Loc, Range))
|
CheckFormatArguments(*i, TheCall);
|
||||||
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>
|
for (specific_attr_iterator<NonNullAttr>
|
||||||
I = FDecl->specific_attr_begin<NonNullAttr>(),
|
i = FDecl->specific_attr_begin<NonNullAttr>(),
|
||||||
E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I)
|
e = FDecl->specific_attr_end<NonNullAttr>(); i != e; ++i) {
|
||||||
CheckNonNullArguments(*I, Args, Loc);
|
CheckNonNullArguments(*i, TheCall->getArgs(),
|
||||||
}
|
TheCall->getCallee()->getLocStart());
|
||||||
|
}
|
||||||
/// 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();
|
unsigned CMId = FDecl->getMemoryFunctionKind();
|
||||||
if (CMId == 0)
|
if (CMId == 0)
|
||||||
|
@ -522,18 +464,25 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
|
||||||
|
|
||||||
bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
|
bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
|
||||||
Expr **Args, unsigned NumArgs) {
|
Expr **Args, unsigned NumArgs) {
|
||||||
VariadicCallType CallType =
|
for (specific_attr_iterator<FormatAttr>
|
||||||
Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply;
|
i = Method->specific_attr_begin<FormatAttr>(),
|
||||||
|
e = Method->specific_attr_end<FormatAttr>(); i != e ; ++i) {
|
||||||
|
|
||||||
checkCall(Method, Args, NumArgs, Method->param_size(),
|
CheckFormatArguments(*i, Args, NumArgs, false, lbrac,
|
||||||
/*IsMemberFunction=*/false,
|
Method->getSourceRange());
|
||||||
lbrac, Method->getSourceRange(), CallType);
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
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);
|
const VarDecl *V = dyn_cast<VarDecl>(NDecl);
|
||||||
if (!V)
|
if (!V)
|
||||||
return false;
|
return false;
|
||||||
|
@ -542,14 +491,12 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
|
||||||
if (!Ty->isBlockPointerType())
|
if (!Ty->isBlockPointerType())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
VariadicCallType CallType =
|
// format string checking.
|
||||||
Proto && Proto->isVariadic() ? VariadicBlock : VariadicDoesNotApply ;
|
for (specific_attr_iterator<FormatAttr>
|
||||||
unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
|
i = NDecl->specific_attr_begin<FormatAttr>(),
|
||||||
|
e = NDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
|
||||||
checkCall(NDecl, TheCall->getArgs(), TheCall->getNumArgs(),
|
CheckFormatArguments(*i, TheCall);
|
||||||
NumProtoArgs, /*IsMemberFunction=*/false,
|
}
|
||||||
TheCall->getRParenLoc(),
|
|
||||||
TheCall->getCallee()->getSourceRange(), CallType);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1554,18 +1501,14 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if an expression is a string literal or constant string.
|
// Handle i > 1 ? "x" : "y", recursively.
|
||||||
// If this function returns false on the arguments to a function expecting a
|
bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
|
||||||
// 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 NumArgs, bool HasVAListArg,
|
||||||
unsigned format_idx, unsigned firstDataArg,
|
unsigned format_idx, unsigned firstDataArg,
|
||||||
FormatStringType Type, bool inFunctionCall) {
|
FormatStringType Type, bool inFunctionCall) {
|
||||||
tryAgain:
|
tryAgain:
|
||||||
if (E->isTypeDependent() || E->isValueDependent())
|
if (E->isTypeDependent() || E->isValueDependent())
|
||||||
return SLCT_NotALiteral;
|
return false;
|
||||||
|
|
||||||
E = E->IgnoreParenCasts();
|
E = E->IgnoreParenCasts();
|
||||||
|
|
||||||
|
@ -1574,26 +1517,18 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
|
||||||
// The behavior of printf and friends in this case is implementation
|
// The behavior of printf and friends in this case is implementation
|
||||||
// dependent. Ideally if the format string cannot be null then
|
// dependent. Ideally if the format string cannot be null then
|
||||||
// it should have a 'nonnull' attribute in the function prototype.
|
// it should have a 'nonnull' attribute in the function prototype.
|
||||||
return SLCT_CheckedLiteral;
|
return true;
|
||||||
|
|
||||||
switch (E->getStmtClass()) {
|
switch (E->getStmtClass()) {
|
||||||
case Stmt::BinaryConditionalOperatorClass:
|
case Stmt::BinaryConditionalOperatorClass:
|
||||||
case Stmt::ConditionalOperatorClass: {
|
case Stmt::ConditionalOperatorClass: {
|
||||||
// The expression is a literal if both sub-expressions were, and it was
|
const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E);
|
||||||
// completely checked only if both sub-expressions were checked.
|
return SemaCheckStringLiteral(C->getTrueExpr(), Args, NumArgs, HasVAListArg,
|
||||||
const AbstractConditionalOperator *C =
|
format_idx, firstDataArg, Type,
|
||||||
cast<AbstractConditionalOperator>(E);
|
inFunctionCall)
|
||||||
StringLiteralCheckType Left =
|
&& SemaCheckStringLiteral(C->getFalseExpr(), Args, NumArgs, HasVAListArg,
|
||||||
checkFormatStringExpr(C->getTrueExpr(), Args, NumArgs,
|
format_idx, firstDataArg, Type,
|
||||||
HasVAListArg, format_idx, firstDataArg,
|
inFunctionCall);
|
||||||
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: {
|
case Stmt::ImplicitCastExprClass: {
|
||||||
|
@ -1606,13 +1541,13 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
|
||||||
E = src;
|
E = src;
|
||||||
goto tryAgain;
|
goto tryAgain;
|
||||||
}
|
}
|
||||||
return SLCT_NotALiteral;
|
return false;
|
||||||
|
|
||||||
case Stmt::PredefinedExprClass:
|
case Stmt::PredefinedExprClass:
|
||||||
// While __func__, etc., are technically not string literals, they
|
// While __func__, etc., are technically not string literals, they
|
||||||
// cannot contain format specifiers and thus are not a security
|
// cannot contain format specifiers and thus are not a security
|
||||||
// liability.
|
// liability.
|
||||||
return SLCT_UncheckedLiteral;
|
return true;
|
||||||
|
|
||||||
case Stmt::DeclRefExprClass: {
|
case Stmt::DeclRefExprClass: {
|
||||||
const DeclRefExpr *DR = cast<DeclRefExpr>(E);
|
const DeclRefExpr *DR = cast<DeclRefExpr>(E);
|
||||||
|
@ -1641,10 +1576,9 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
|
||||||
if (InitList->isStringLiteralInit())
|
if (InitList->isStringLiteralInit())
|
||||||
Init = InitList->getInit(0)->IgnoreParenImpCasts();
|
Init = InitList->getInit(0)->IgnoreParenImpCasts();
|
||||||
}
|
}
|
||||||
return checkFormatStringExpr(Init, Args, NumArgs,
|
return SemaCheckStringLiteral(Init, Args, NumArgs,
|
||||||
HasVAListArg, format_idx,
|
HasVAListArg, format_idx, firstDataArg,
|
||||||
firstDataArg, Type,
|
Type, /*inFunctionCall*/false);
|
||||||
/*inFunctionCall*/false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1678,14 +1612,14 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
|
||||||
// We can't pass a 'scanf' string to a 'printf' function.
|
// We can't pass a 'scanf' string to a 'printf' function.
|
||||||
if (PVIndex == PVFormat->getFormatIdx() &&
|
if (PVIndex == PVFormat->getFormatIdx() &&
|
||||||
Type == GetFormatStringType(PVFormat))
|
Type == GetFormatStringType(PVFormat))
|
||||||
return SLCT_UncheckedLiteral;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SLCT_NotALiteral;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Stmt::CallExprClass:
|
case Stmt::CallExprClass:
|
||||||
|
@ -1699,22 +1633,22 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
|
||||||
--ArgIndex;
|
--ArgIndex;
|
||||||
const Expr *Arg = CE->getArg(ArgIndex - 1);
|
const Expr *Arg = CE->getArg(ArgIndex - 1);
|
||||||
|
|
||||||
return checkFormatStringExpr(Arg, Args, NumArgs,
|
return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg,
|
||||||
HasVAListArg, format_idx, firstDataArg,
|
format_idx, firstDataArg, Type,
|
||||||
Type, inFunctionCall);
|
inFunctionCall);
|
||||||
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
|
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
|
||||||
unsigned BuiltinID = FD->getBuiltinID();
|
unsigned BuiltinID = FD->getBuiltinID();
|
||||||
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
|
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
|
||||||
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
|
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
|
||||||
const Expr *Arg = CE->getArg(0);
|
const Expr *Arg = CE->getArg(0);
|
||||||
return checkFormatStringExpr(Arg, Args, NumArgs,
|
return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg,
|
||||||
HasVAListArg, format_idx,
|
format_idx, firstDataArg, Type,
|
||||||
firstDataArg, Type, inFunctionCall);
|
inFunctionCall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SLCT_NotALiteral;
|
return false;
|
||||||
}
|
}
|
||||||
case Stmt::ObjCStringLiteralClass:
|
case Stmt::ObjCStringLiteralClass:
|
||||||
case Stmt::StringLiteralClass: {
|
case Stmt::StringLiteralClass: {
|
||||||
|
@ -1728,14 +1662,14 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
|
||||||
if (StrE) {
|
if (StrE) {
|
||||||
CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx,
|
CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx,
|
||||||
firstDataArg, Type, inFunctionCall);
|
firstDataArg, Type, inFunctionCall);
|
||||||
return SLCT_CheckedLiteral;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SLCT_NotALiteral;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return SLCT_NotALiteral;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1766,34 +1700,42 @@ Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
|
||||||
|
|
||||||
/// CheckPrintfScanfArguments - Check calls to printf and scanf (and similar
|
/// CheckPrintfScanfArguments - Check calls to printf and scanf (and similar
|
||||||
/// functions) for correct use of format strings.
|
/// functions) for correct use of format strings.
|
||||||
/// Returns true if a format string has been fully checked.
|
void Sema::CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall) {
|
||||||
bool Sema::CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall) {
|
bool IsCXXMember = false;
|
||||||
bool IsCXXMember = isa<CXXMemberCallExpr>(TheCall);
|
// The way the format attribute works in GCC, the implicit this argument
|
||||||
return CheckFormatArguments(Format, TheCall->getArgs(),
|
// of member functions is counted. However, it doesn't appear in our own
|
||||||
TheCall->getNumArgs(),
|
// lists, so decrement format_idx in that case.
|
||||||
|
IsCXXMember = isa<CXXMemberCallExpr>(TheCall);
|
||||||
|
CheckFormatArguments(Format, TheCall->getArgs(), TheCall->getNumArgs(),
|
||||||
IsCXXMember, TheCall->getRParenLoc(),
|
IsCXXMember, TheCall->getRParenLoc(),
|
||||||
TheCall->getCallee()->getSourceRange());
|
TheCall->getCallee()->getSourceRange());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
|
void Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
|
||||||
unsigned NumArgs, bool IsCXXMember,
|
unsigned NumArgs, bool IsCXXMember,
|
||||||
SourceLocation Loc, SourceRange Range) {
|
SourceLocation Loc, SourceRange Range) {
|
||||||
FormatStringInfo FSI;
|
bool HasVAListArg = Format->getFirstArg() == 0;
|
||||||
if (getFormatStringInfo(Format, IsCXXMember, &FSI))
|
unsigned format_idx = Format->getFormatIdx() - 1;
|
||||||
return CheckFormatArguments(Args, NumArgs, FSI.HasVAListArg, FSI.FormatIdx,
|
unsigned firstDataArg = HasVAListArg ? 0 : Format->getFirstArg() - 1;
|
||||||
FSI.FirstDataArg, GetFormatStringType(Format),
|
if (IsCXXMember) {
|
||||||
Loc, Range);
|
if (format_idx == 0)
|
||||||
return false;
|
return;
|
||||||
|
--format_idx;
|
||||||
|
if(firstDataArg != 0)
|
||||||
|
--firstDataArg;
|
||||||
|
}
|
||||||
|
CheckFormatArguments(Args, NumArgs, HasVAListArg, format_idx,
|
||||||
|
firstDataArg, GetFormatStringType(Format), Loc, Range);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
|
void Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
|
||||||
bool HasVAListArg, unsigned format_idx,
|
bool HasVAListArg, unsigned format_idx,
|
||||||
unsigned firstDataArg, FormatStringType Type,
|
unsigned firstDataArg, FormatStringType Type,
|
||||||
SourceLocation Loc, SourceRange Range) {
|
SourceLocation Loc, SourceRange Range) {
|
||||||
// CHECK: printf/scanf-like function is called with no format string.
|
// CHECK: printf/scanf-like function is called with no format string.
|
||||||
if (format_idx >= NumArgs) {
|
if (format_idx >= NumArgs) {
|
||||||
Diag(Loc, diag::warn_missing_format_string) << Range;
|
Diag(Loc, diag::warn_missing_format_string) << Range;
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts();
|
const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts();
|
||||||
|
@ -1810,17 +1752,14 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
|
||||||
// C string (e.g. "%d")
|
// C string (e.g. "%d")
|
||||||
// ObjC string uses the same format specifiers as C string, so we can use
|
// 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.
|
// the same format string checking logic for both ObjC and C strings.
|
||||||
StringLiteralCheckType CT =
|
if (SemaCheckStringLiteral(OrigFormatExpr, Args, NumArgs, HasVAListArg,
|
||||||
checkFormatStringExpr(OrigFormatExpr, Args, NumArgs, HasVAListArg,
|
format_idx, firstDataArg, Type))
|
||||||
format_idx, firstDataArg, Type);
|
return; // Literal format string found, check done!
|
||||||
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,
|
// Strftime is particular as it always uses a single 'time' argument,
|
||||||
// so it is safe to pass a non-literal string.
|
// so it is safe to pass a non-literal string.
|
||||||
if (Type == FST_Strftime)
|
if (Type == FST_Strftime)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
// Do not emit diag when the string param is a macro expansion and the
|
// 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
|
// format is either NSString or CFString. This is a hack to prevent
|
||||||
|
@ -1828,7 +1767,7 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
|
||||||
// which are usually used in place of NS and CF string literals.
|
// which are usually used in place of NS and CF string literals.
|
||||||
if (Type == FST_NSString &&
|
if (Type == FST_NSString &&
|
||||||
SourceMgr.isInSystemMacro(Args[format_idx]->getLocStart()))
|
SourceMgr.isInSystemMacro(Args[format_idx]->getLocStart()))
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
// If there are no arguments specified, warn with -Wformat-security, otherwise
|
// If there are no arguments specified, warn with -Wformat-security, otherwise
|
||||||
// warn only with -Wformat-nonliteral.
|
// warn only with -Wformat-nonliteral.
|
||||||
|
@ -1840,7 +1779,6 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
|
||||||
Diag(Args[format_idx]->getLocStart(),
|
Diag(Args[format_idx]->getLocStart(),
|
||||||
diag::warn_format_nonliteral)
|
diag::warn_format_nonliteral)
|
||||||
<< OrigFormatExpr->getSourceRange();
|
<< OrigFormatExpr->getSourceRange();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -2200,10 +2138,6 @@ public:
|
||||||
bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
|
bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
|
||||||
const char *startSpecifier,
|
const char *startSpecifier,
|
||||||
unsigned specifierLen);
|
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,
|
bool HandleAmount(const analyze_format_string::OptionalAmount &Amt, unsigned k,
|
||||||
const char *startSpecifier, unsigned specifierLen);
|
const char *startSpecifier, unsigned specifierLen);
|
||||||
|
@ -2218,9 +2152,6 @@ public:
|
||||||
const analyze_printf::OptionalFlag &ignoredFlag,
|
const analyze_printf::OptionalFlag &ignoredFlag,
|
||||||
const analyze_printf::OptionalFlag &flag,
|
const analyze_printf::OptionalFlag &flag,
|
||||||
const char *startSpecifier, unsigned specifierLen);
|
const char *startSpecifier, unsigned specifierLen);
|
||||||
bool checkForCStrMembers(const analyze_printf::ArgTypeResult &ATR,
|
|
||||||
const Expr *E, const CharSourceRange &CSR);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2338,64 +2269,6 @@ void CheckPrintfHandler::HandleIgnoredFlag(
|
||||||
getSpecifierRange(ignoredFlag.getPosition(), 1)));
|
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
|
bool
|
||||||
CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
|
CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
|
||||||
&FS,
|
&FS,
|
||||||
|
@ -2523,30 +2396,20 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
|
||||||
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
|
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
|
||||||
return false;
|
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
|
// Now type check the data expression that matches the
|
||||||
// format specifier.
|
// format specifier.
|
||||||
|
const Expr *Ex = getDataArg(argIndex);
|
||||||
const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context,
|
const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context,
|
||||||
ObjCContext);
|
ObjCContext);
|
||||||
if (ATR.isValid() && !ATR.matchesType(S.Context, E->getType())) {
|
if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
|
||||||
// Look through argument promotions for our error message's reported type.
|
// Look through argument promotions for our error message's reported type.
|
||||||
// This includes the integral and floating promotions, but excludes array
|
// This includes the integral and floating promotions, but excludes array
|
||||||
// and function pointer decay; seeing that an argument intended to be a
|
// and function pointer decay; seeing that an argument intended to be a
|
||||||
// string has type 'char [6]' is probably more confusing than 'char *'.
|
// string has type 'char [6]' is probably more confusing than 'char *'.
|
||||||
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
|
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex)) {
|
||||||
if (ICE->getCastKind() == CK_IntegralCast ||
|
if (ICE->getCastKind() == CK_IntegralCast ||
|
||||||
ICE->getCastKind() == CK_FloatingCast) {
|
ICE->getCastKind() == CK_FloatingCast) {
|
||||||
E = ICE->getSubExpr();
|
Ex = ICE->getSubExpr();
|
||||||
|
|
||||||
// Check if we didn't match because of an implicit cast from a 'char'
|
// 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
|
// or 'short' to an 'int'. This is done because printf is a varargs
|
||||||
|
@ -2554,7 +2417,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
|
||||||
if (ICE->getType() == S.Context.IntTy ||
|
if (ICE->getType() == S.Context.IntTy ||
|
||||||
ICE->getType() == S.Context.UnsignedIntTy) {
|
ICE->getType() == S.Context.UnsignedIntTy) {
|
||||||
// All further checking is done on the subexpression.
|
// All further checking is done on the subexpression.
|
||||||
if (ATR.matchesType(S.Context, E->getType()))
|
if (ATR.matchesType(S.Context, Ex->getType()))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2562,7 +2425,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
|
||||||
|
|
||||||
// We may be able to offer a FixItHint if it is a supported type.
|
// We may be able to offer a FixItHint if it is a supported type.
|
||||||
PrintfSpecifier fixedFS = FS;
|
PrintfSpecifier fixedFS = FS;
|
||||||
bool success = fixedFS.fixType(E->getType(), S.getLangOpts(),
|
bool success = fixedFS.fixType(Ex->getType(), S.getLangOpts(),
|
||||||
S.Context, ObjCContext);
|
S.Context, ObjCContext);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
|
@ -2573,38 +2436,24 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
|
||||||
|
|
||||||
EmitFormatDiagnostic(
|
EmitFormatDiagnostic(
|
||||||
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
|
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
|
||||||
<< ATR.getRepresentativeTypeName(S.Context) << E->getType()
|
<< ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
|
||||||
<< E->getSourceRange(),
|
<< Ex->getSourceRange(),
|
||||||
E->getLocStart(),
|
Ex->getLocStart(),
|
||||||
/*IsStringLocation*/false,
|
/*IsStringLocation*/false,
|
||||||
getSpecifierRange(StartSpecifier, SpecifierLen),
|
getSpecifierRange(startSpecifier, specifierLen),
|
||||||
FixItHint::CreateReplacement(
|
FixItHint::CreateReplacement(
|
||||||
getSpecifierRange(StartSpecifier, SpecifierLen),
|
getSpecifierRange(startSpecifier, specifierLen),
|
||||||
os.str()));
|
os.str()));
|
||||||
} else {
|
}
|
||||||
const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
|
else {
|
||||||
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(
|
EmitFormatDiagnostic(
|
||||||
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
|
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
|
||||||
<< ATR.getRepresentativeTypeName(S.Context) << E->getType()
|
<< ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
|
||||||
<< CSR
|
<< getSpecifierRange(startSpecifier, specifierLen)
|
||||||
<< E->getSourceRange(),
|
<< Ex->getSourceRange(),
|
||||||
E->getLocStart(), /*IsStringLocation*/false, CSR);
|
Ex->getLocStart(),
|
||||||
|
/*IsStringLocation*/false,
|
||||||
|
getSpecifierRange(startSpecifier, specifierLen));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9028,6 +9028,13 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
|
||||||
unsigned NumExprs = ExprArgs.size();
|
unsigned NumExprs = ExprArgs.size();
|
||||||
Expr **Exprs = (Expr **)ExprArgs.release();
|
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);
|
MarkFunctionReferenced(ConstructLoc, Constructor);
|
||||||
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
|
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
|
||||||
Constructor, Elidable, Exprs, NumExprs,
|
Constructor, Elidable, Exprs, NumExprs,
|
||||||
|
@ -9121,8 +9128,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
|
||||||
|
|
||||||
DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size());
|
DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size());
|
||||||
|
|
||||||
CheckConstructorCall(Constructor, AllArgs.data(), AllArgs.size(),
|
// FIXME: Missing call to CheckFunctionCall or equivalent
|
||||||
Proto, Loc);
|
|
||||||
|
|
||||||
return Invalid;
|
return Invalid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -598,59 +598,12 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
|
||||||
return Owned(E);
|
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
|
/// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
|
||||||
/// will warn if the resulting type is not a POD type, and rejects ObjC
|
/// will warn if the resulting type is not a POD type, and rejects ObjC
|
||||||
/// interfaces passed by value.
|
/// interfaces passed by value.
|
||||||
ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
|
ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
|
||||||
FunctionDecl *FDecl) {
|
FunctionDecl *FDecl) {
|
||||||
const QualType &Ty = E->getType();
|
if (const BuiltinType *PlaceholderTy = E->getType()->getAsPlaceholderType()) {
|
||||||
if (const BuiltinType *PlaceholderTy = Ty->getAsPlaceholderType()) {
|
|
||||||
// Strip the unbridged-cast placeholder expression off, if applicable.
|
// Strip the unbridged-cast placeholder expression off, if applicable.
|
||||||
if (PlaceholderTy->getKind() == BuiltinType::ARCUnbridgedCast &&
|
if (PlaceholderTy->getKind() == BuiltinType::ARCUnbridgedCast &&
|
||||||
(CT == VariadicMethod ||
|
(CT == VariadicMethod ||
|
||||||
|
@ -671,29 +624,61 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
|
||||||
return ExprError();
|
return ExprError();
|
||||||
E = ExprRes.take();
|
E = ExprRes.take();
|
||||||
|
|
||||||
if (Ty->isObjCObjectType() &&
|
// Don't allow one to pass an Objective-C interface to a vararg.
|
||||||
|
if (E->getType()->isObjCObjectType() &&
|
||||||
DiagRuntimeBehavior(E->getLocStart(), 0,
|
DiagRuntimeBehavior(E->getLocStart(), 0,
|
||||||
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
|
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
|
||||||
<< Ty << CT))
|
<< E->getType() << CT))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
// Diagnostics regarding non-POD argument types are
|
// Complain about passing non-POD types through varargs. However, don't
|
||||||
// emitted along with format string checking in Sema::CheckFunctionCall().
|
// perform this check for incomplete types, which we can get here when we're
|
||||||
if (isValidVarArgType(Ty) == VAK_Invalid) {
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
// Turn this into a trap.
|
||||||
CXXScopeSpec SS;
|
CXXScopeSpec SS;
|
||||||
SourceLocation TemplateKWLoc;
|
SourceLocation TemplateKWLoc;
|
||||||
UnqualifiedId Name;
|
UnqualifiedId Name;
|
||||||
Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"),
|
Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"),
|
||||||
E->getLocStart());
|
E->getLocStart());
|
||||||
ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc,
|
ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc, Name,
|
||||||
Name, true, false);
|
true, false);
|
||||||
if (TrapFn.isInvalid())
|
if (TrapFn.isInvalid())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(),
|
ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), E->getLocStart(),
|
||||||
E->getLocStart(), MultiExprArg(),
|
MultiExprArg(), E->getLocEnd());
|
||||||
E->getLocEnd());
|
|
||||||
if (Call.isInvalid())
|
if (Call.isInvalid())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
|
@ -701,9 +686,10 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
|
||||||
Call.get(), E);
|
Call.get(), E);
|
||||||
if (Comma.isInvalid())
|
if (Comma.isInvalid())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
return Comma.get();
|
E = Comma.get();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// c++ rules are enforced elsewhere.
|
||||||
if (!getLangOpts().CPlusPlus &&
|
if (!getLangOpts().CPlusPlus &&
|
||||||
RequireCompleteType(E->getExprLoc(), E->getType(),
|
RequireCompleteType(E->getExprLoc(), E->getType(),
|
||||||
diag::err_call_incomplete_argument))
|
diag::err_call_incomplete_argument))
|
||||||
|
@ -3437,25 +3423,6 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
|
||||||
return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param));
|
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
|
/// ConvertArgumentsForCall - Converts the arguments specified in
|
||||||
/// Args/NumArgs to the parameter types of the function FDecl with
|
/// Args/NumArgs to the parameter types of the function FDecl with
|
||||||
/// function prototype Proto. Call is the call expression itself, and
|
/// function prototype Proto. Call is the call expression itself, and
|
||||||
|
@ -3547,8 +3514,12 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SmallVector<Expr *, 8> AllArgs;
|
SmallVector<Expr *, 8> AllArgs;
|
||||||
VariadicCallType CallType = getVariadicCallType(FDecl, Proto, Fn);
|
VariadicCallType CallType =
|
||||||
|
Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
|
||||||
|
if (Fn->getType()->isBlockPointerType())
|
||||||
|
CallType = VariadicBlock; // Block
|
||||||
|
else if (isa<MemberExpr>(Fn))
|
||||||
|
CallType = VariadicMethod;
|
||||||
Invalid = GatherArgumentsForCall(Call->getLocStart(), FDecl,
|
Invalid = GatherArgumentsForCall(Call->getLocStart(), FDecl,
|
||||||
Proto, 0, Args, NumArgs, AllArgs, CallType);
|
Proto, 0, Args, NumArgs, AllArgs, CallType);
|
||||||
if (Invalid)
|
if (Invalid)
|
||||||
|
@ -3637,6 +3608,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
|
||||||
|
|
||||||
// If this is a variadic call, handle args passed through "...".
|
// If this is a variadic call, handle args passed through "...".
|
||||||
if (CallType != VariadicDoesNotApply) {
|
if (CallType != VariadicDoesNotApply) {
|
||||||
|
|
||||||
// Assume that extern "C" functions with variadic arguments that
|
// Assume that extern "C" functions with variadic arguments that
|
||||||
// return __unknown_anytype aren't *really* variadic.
|
// return __unknown_anytype aren't *really* variadic.
|
||||||
if (Proto->getResultType() == Context.UnknownAnyTy &&
|
if (Proto->getResultType() == Context.UnknownAnyTy &&
|
||||||
|
@ -3974,8 +3946,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
|
||||||
TheCall->setType(FuncT->getCallResultType(Context));
|
TheCall->setType(FuncT->getCallResultType(Context));
|
||||||
TheCall->setValueKind(Expr::getValueKindForType(FuncT->getResultType()));
|
TheCall->setValueKind(Expr::getValueKindForType(FuncT->getResultType()));
|
||||||
|
|
||||||
const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT);
|
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT)) {
|
||||||
if (Proto) {
|
|
||||||
if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, NumArgs,
|
if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, NumArgs,
|
||||||
RParenLoc, IsExecConfig))
|
RParenLoc, IsExecConfig))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
@ -3987,7 +3958,8 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
|
||||||
// on our knowledge of the function definition.
|
// on our knowledge of the function definition.
|
||||||
const FunctionDecl *Def = 0;
|
const FunctionDecl *Def = 0;
|
||||||
if (FDecl->hasBody(Def) && NumArgs != Def->param_size()) {
|
if (FDecl->hasBody(Def) && NumArgs != Def->param_size()) {
|
||||||
Proto = Def->getType()->getAs<FunctionProtoType>();
|
const FunctionProtoType *Proto
|
||||||
|
= Def->getType()->getAs<FunctionProtoType>();
|
||||||
if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size()))
|
if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size()))
|
||||||
Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
|
Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
|
||||||
<< (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
|
<< (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
|
||||||
|
@ -4045,13 +4017,13 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
|
||||||
|
|
||||||
// Do special checking on direct calls to functions.
|
// Do special checking on direct calls to functions.
|
||||||
if (FDecl) {
|
if (FDecl) {
|
||||||
if (CheckFunctionCall(FDecl, TheCall, Proto))
|
if (CheckFunctionCall(FDecl, TheCall))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
if (BuiltinID)
|
if (BuiltinID)
|
||||||
return CheckBuiltinFunctionCall(BuiltinID, TheCall);
|
return CheckBuiltinFunctionCall(BuiltinID, TheCall);
|
||||||
} else if (NDecl) {
|
} else if (NDecl) {
|
||||||
if (CheckBlockCall(NDecl, TheCall, Proto))
|
if (CheckBlockCall(NDecl, TheCall))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10720,7 +10720,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
||||||
|
|
||||||
DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
|
DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
|
||||||
|
|
||||||
if (CheckFunctionCall(Method, TheCall, Proto))
|
if (CheckFunctionCall(Method, TheCall))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
if ((isa<CXXConstructorDecl>(CurContext) ||
|
if ((isa<CXXConstructorDecl>(CurContext) ||
|
||||||
|
@ -11028,7 +11028,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
|
||||||
|
|
||||||
DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
|
DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
|
||||||
|
|
||||||
if (CheckFunctionCall(Method, TheCall, Proto))
|
if (CheckFunctionCall(Method, TheCall))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return MaybeBindToTemporary(TheCall);
|
return MaybeBindToTemporary(TheCall);
|
||||||
|
@ -11208,7 +11208,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
|
||||||
if (CheckCallReturnType(FD->getResultType(), UDSuffixLoc, UDL, FD))
|
if (CheckCallReturnType(FD->getResultType(), UDSuffixLoc, UDL, FD))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
if (CheckFunctionCall(FD, UDL, NULL))
|
if (CheckFunctionCall(FD, UDL))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
return MaybeBindToTemporary(UDL);
|
return MaybeBindToTemporary(UDL);
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
// 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'}}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
// 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?}}
|
|
||||||
}
|
|
Загрузка…
Ссылка в новой задаче