Skip to content

Commit c7b0bdf

Browse files
committed
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! llvm-svn: 158887
1 parent 15b4caf commit c7b0bdf

File tree

8 files changed

+518
-217
lines changed

8 files changed

+518
-217
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4723,6 +4723,11 @@ def err_cannot_pass_objc_interface_to_vararg : Error<
47234723
"cannot pass object with interface type %0 by-value through variadic "
47244724
"%select{function|block|method}1">;
47254725

4726+
def warn_non_pod_vararg_with_format_string : Warning<
4727+
"cannot pass %select{non-POD|non-trivial}0 object of type %1 to variadic "
4728+
"function; expected type from format string was %2">,
4729+
InGroup<DiagGroup<"non-pod-varargs">>, DefaultError;
4730+
47264731
def warn_cannot_pass_non_pod_arg_to_vararg : Warning<
47274732
"cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic"
47284733
" %select{function|block|method|constructor}2; call will abort at runtime">,
@@ -5206,7 +5211,8 @@ def warn_scanf_scanlist_incomplete : Warning<
52065211
"no closing ']' for '%%[' in scanf format string">,
52075212
InGroup<Format>;
52085213
def note_format_string_defined : Note<"format string is defined here">;
5209-
5214+
def note_printf_c_str: Note<"did you mean to call the %0 method?">;
5215+
52105216
def warn_null_arg : Warning<
52115217
"null passed to a callee which requires a non-null argument">,
52125218
InGroup<NonNull>;
@@ -5666,4 +5672,3 @@ def err_module_private_definition : Error<
56665672
}
56675673

56685674
} // end of sema component.
5669-

clang/include/clang/Sema/Sema.h

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6409,6 +6409,21 @@ class Sema {
64096409
VariadicDoesNotApply
64106410
};
64116411

6412+
VariadicCallType getVariadicCallType(FunctionDecl *FDecl,
6413+
const FunctionProtoType *Proto,
6414+
Expr *Fn);
6415+
6416+
// Used for determining in which context a type is allowed to be passed to a
6417+
// vararg function.
6418+
enum VarArgKind {
6419+
VAK_Valid,
6420+
VAK_ValidInCXX11,
6421+
VAK_Invalid
6422+
};
6423+
6424+
// Determines which VarArgKind fits an expression.
6425+
VarArgKind isValidVarArgType(const QualType &Ty);
6426+
64126427
/// GatherArgumentsForCall - Collector argument expressions for various
64136428
/// form of call prototypes.
64146429
bool GatherArgumentsForCall(SourceLocation CallLoc,
@@ -6421,10 +6436,14 @@ class Sema {
64216436
bool AllowExplicit = false);
64226437

64236438
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
6424-
// will warn if the resulting type is not a POD type.
6439+
// will return ExprError() if the resulting type is not a POD type.
64256440
ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
64266441
FunctionDecl *FDecl);
64276442

6443+
/// Checks to see if the given expression is a valid argument to a variadic
6444+
/// function, issuing a diagnostic and returning NULL if not.
6445+
bool variadicArgumentPODCheck(const Expr *E, VariadicCallType CT);
6446+
64286447
// UsualArithmeticConversions - performs the UsualUnaryConversions on it's
64296448
// operands and then handles various conversions that are common to binary
64306449
// operators (C99 6.3.1.8). If both operands aren't arithmetic, this
@@ -6999,10 +7018,33 @@ class Sema {
69997018
const ArraySubscriptExpr *ASE=0,
70007019
bool AllowOnePastEnd=true, bool IndexNegated=false);
70017020
void CheckArrayAccess(const Expr *E);
7002-
bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
7021+
// Used to grab the relevant information from a FormatAttr and a
7022+
// FunctionDeclaration.
7023+
struct FormatStringInfo {
7024+
unsigned FormatIdx;
7025+
unsigned FirstDataArg;
7026+
bool HasVAListArg;
7027+
};
7028+
7029+
bool getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
7030+
FormatStringInfo *FSI);
7031+
bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
7032+
const FunctionProtoType *Proto);
70037033
bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc,
70047034
Expr **Args, unsigned NumArgs);
7005-
bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
7035+
bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
7036+
const FunctionProtoType *Proto);
7037+
void CheckConstructorCall(FunctionDecl *FDecl,
7038+
Expr **Args,
7039+
unsigned NumArgs,
7040+
const FunctionProtoType *Proto,
7041+
SourceLocation Loc);
7042+
7043+
void checkCall(NamedDecl *FDecl, Expr **Args, unsigned NumArgs,
7044+
unsigned NumProtoArgs, bool IsMemberFunction,
7045+
SourceLocation Loc, SourceRange Range,
7046+
VariadicCallType CallType);
7047+
70067048

70077049
bool CheckObjCString(Expr *Arg);
70087050

@@ -7037,21 +7079,31 @@ class Sema {
70377079
FST_Unknown
70387080
};
70397081
static FormatStringType GetFormatStringType(const FormatAttr *Format);
7040-
bool SemaCheckStringLiteral(const Expr *E, Expr **Args, unsigned NumArgs,
7041-
bool HasVAListArg, unsigned format_idx,
7042-
unsigned firstDataArg, FormatStringType Type,
7043-
bool inFunctionCall = true);
7082+
7083+
enum StringLiteralCheckType {
7084+
SLCT_NotALiteral,
7085+
SLCT_UncheckedLiteral,
7086+
SLCT_CheckedLiteral
7087+
};
7088+
7089+
StringLiteralCheckType checkFormatStringExpr(const Expr *E,
7090+
Expr **Args, unsigned NumArgs,
7091+
bool HasVAListArg,
7092+
unsigned format_idx,
7093+
unsigned firstDataArg,
7094+
FormatStringType Type,
7095+
bool inFunctionCall = true);
70447096

70457097
void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr,
70467098
Expr **Args, unsigned NumArgs, bool HasVAListArg,
70477099
unsigned format_idx, unsigned firstDataArg,
70487100
FormatStringType Type, bool inFunctionCall);
70497101

7050-
void CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall);
7051-
void CheckFormatArguments(const FormatAttr *Format, Expr **Args,
7102+
bool CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall);
7103+
bool CheckFormatArguments(const FormatAttr *Format, Expr **Args,
70527104
unsigned NumArgs, bool IsCXXMember,
70537105
SourceLocation Loc, SourceRange Range);
7054-
void CheckFormatArguments(Expr **Args, unsigned NumArgs,
7106+
bool CheckFormatArguments(Expr **Args, unsigned NumArgs,
70557107
bool HasVAListArg, unsigned format_idx,
70567108
unsigned firstDataArg, FormatStringType Type,
70577109
SourceLocation Loc, SourceRange range);

0 commit comments

Comments
 (0)