For varargs, diagnose passing ObjC objects by value like other non-POD types.

While we still want to consider this a hard error (non-POD variadic args are
normally a DefaultError warning), delaying the diagnostic allows us to give
better error messages, which also match the usual non-POD errors more closely.

In addition, this change improves the diagnostic messages for format string
argument type mismatches by passing down the type of the callee, so we can
say "variadic method" or "variadic function" appropriately.

<rdar://problem/11825593>

llvm-svn: 160517
This commit is contained in:
Jordan Rose 2012-07-19 18:10:23 +00:00
parent 96c49686b9
commit 3e0ec58c09
8 changed files with 83 additions and 54 deletions

View File

@ -4891,16 +4891,19 @@ def err_ref_bad_target : Error<
"reference to %select{__device__|__global__|__host__|__host__ __device__}0 " "reference to %select{__device__|__global__|__host__|__host__ __device__}0 "
"function %1 in %select{__device__|__global__|__host__|__host__ __device__}2 function">; "function %1 in %select{__device__|__global__|__host__|__host__ __device__}2 function">;
def err_cannot_pass_objc_interface_to_vararg : Error<
"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< def warn_non_pod_vararg_with_format_string : Warning<
"cannot pass %select{non-POD|non-trivial}0 object of type %1 to variadic " "cannot pass %select{non-POD|non-trivial}0 object of type %1 to variadic "
"function; expected type from format string was %2">, "%select{function|block|method|constructor}2; expected type from format "
InGroup<DiagGroup<"non-pod-varargs">>, DefaultError; "string was %3">, InGroup<DiagGroup<"non-pod-varargs">>, DefaultError;
// The arguments to this diagnostic should match the warning above.
def err_cannot_pass_objc_interface_to_vararg_format : Error<
"cannot pass object with interface type %1 by value to variadic "
"%select{function|block|method|constructor}2; expected type from format "
"string was %3">;
def err_cannot_pass_objc_interface_to_vararg : Error<
"cannot pass object with interface type %0 by value through variadic "
"%select{function|block|method|constructor}1">;
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">,

View File

@ -6455,7 +6455,7 @@ 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 create a runtime trap 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);
@ -7117,20 +7117,23 @@ private:
unsigned format_idx, unsigned format_idx,
unsigned firstDataArg, unsigned firstDataArg,
FormatStringType Type, FormatStringType Type,
VariadicCallType CallType,
bool inFunctionCall = true); bool inFunctionCall = true);
void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr, void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr,
Expr **Args, unsigned NumArgs, bool HasVAListArg, Expr **Args, unsigned NumArgs, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg, unsigned format_idx, unsigned firstDataArg,
FormatStringType Type, bool inFunctionCall); FormatStringType Type, bool inFunctionCall,
VariadicCallType CallType);
bool CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall);
bool CheckFormatArguments(const FormatAttr *Format, Expr **Args, bool CheckFormatArguments(const FormatAttr *Format, Expr **Args,
unsigned NumArgs, bool IsCXXMember, unsigned NumArgs, bool IsCXXMember,
VariadicCallType CallType,
SourceLocation Loc, SourceRange Range); SourceLocation Loc, SourceRange Range);
bool CheckFormatArguments(Expr **Args, unsigned NumArgs, bool CheckFormatArguments(Expr **Args, unsigned NumArgs,
bool HasVAListArg, unsigned format_idx, bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type, unsigned firstDataArg, FormatStringType Type,
VariadicCallType CallType,
SourceLocation Loc, SourceRange range); SourceLocation Loc, SourceRange range);
void CheckNonNullArguments(const NonNullAttr *NonNull, void CheckNonNullArguments(const NonNullAttr *NonNull,

View File

@ -499,7 +499,8 @@ void Sema::checkCall(NamedDecl *FDecl, Expr **Args,
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)) if (CheckFormatArguments(*I, Args, NumArgs, IsMemberFunction, CallType,
Loc, Range))
HandledFormatString = true; HandledFormatString = true;
// Refuse POD arguments that weren't caught by the format string // Refuse POD arguments that weren't caught by the format string
@ -1610,7 +1611,8 @@ Sema::StringLiteralCheckType
Sema::checkFormatStringExpr(const Expr *E, Expr **Args, 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, VariadicCallType CallType,
bool inFunctionCall) {
tryAgain: tryAgain:
if (E->isTypeDependent() || E->isValueDependent()) if (E->isTypeDependent() || E->isValueDependent())
return SLCT_NotALiteral; return SLCT_NotALiteral;
@ -1634,13 +1636,13 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
StringLiteralCheckType Left = StringLiteralCheckType Left =
checkFormatStringExpr(C->getTrueExpr(), Args, NumArgs, checkFormatStringExpr(C->getTrueExpr(), Args, NumArgs,
HasVAListArg, format_idx, firstDataArg, HasVAListArg, format_idx, firstDataArg,
Type, inFunctionCall); Type, CallType, inFunctionCall);
if (Left == SLCT_NotALiteral) if (Left == SLCT_NotALiteral)
return SLCT_NotALiteral; return SLCT_NotALiteral;
StringLiteralCheckType Right = StringLiteralCheckType Right =
checkFormatStringExpr(C->getFalseExpr(), Args, NumArgs, checkFormatStringExpr(C->getFalseExpr(), Args, NumArgs,
HasVAListArg, format_idx, firstDataArg, HasVAListArg, format_idx, firstDataArg,
Type, inFunctionCall); Type, CallType, inFunctionCall);
return Left < Right ? Left : Right; return Left < Right ? Left : Right;
} }
@ -1691,7 +1693,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
} }
return checkFormatStringExpr(Init, Args, NumArgs, return checkFormatStringExpr(Init, Args, NumArgs,
HasVAListArg, format_idx, HasVAListArg, format_idx,
firstDataArg, Type, firstDataArg, Type, CallType,
/*inFunctionCall*/false); /*inFunctionCall*/false);
} }
} }
@ -1749,7 +1751,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
return checkFormatStringExpr(Arg, Args, NumArgs, return checkFormatStringExpr(Arg, Args, NumArgs,
HasVAListArg, format_idx, firstDataArg, HasVAListArg, format_idx, firstDataArg,
Type, inFunctionCall); Type, CallType, 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 ||
@ -1757,7 +1759,8 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
const Expr *Arg = CE->getArg(0); const Expr *Arg = CE->getArg(0);
return checkFormatStringExpr(Arg, Args, NumArgs, return checkFormatStringExpr(Arg, Args, NumArgs,
HasVAListArg, format_idx, HasVAListArg, format_idx,
firstDataArg, Type, inFunctionCall); firstDataArg, Type, CallType,
inFunctionCall);
} }
} }
} }
@ -1775,7 +1778,7 @@ 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, CallType);
return SLCT_CheckedLiteral; return SLCT_CheckedLiteral;
} }
@ -1812,31 +1815,25 @@ Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
.Default(FST_Unknown); .Default(FST_Unknown);
} }
/// CheckPrintfScanfArguments - Check calls to printf and scanf (and similar /// CheckFormatArguments - 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. /// 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());
}
bool Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args, bool Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
unsigned NumArgs, bool IsCXXMember, unsigned NumArgs, bool IsCXXMember,
VariadicCallType CallType,
SourceLocation Loc, SourceRange Range) { SourceLocation Loc, SourceRange Range) {
FormatStringInfo FSI; FormatStringInfo FSI;
if (getFormatStringInfo(Format, IsCXXMember, &FSI)) if (getFormatStringInfo(Format, IsCXXMember, &FSI))
return CheckFormatArguments(Args, NumArgs, FSI.HasVAListArg, FSI.FormatIdx, return CheckFormatArguments(Args, NumArgs, FSI.HasVAListArg, FSI.FormatIdx,
FSI.FirstDataArg, GetFormatStringType(Format), FSI.FirstDataArg, GetFormatStringType(Format),
Loc, Range); CallType, Loc, Range);
return false; return false;
} }
bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs, bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
bool HasVAListArg, unsigned format_idx, bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type, unsigned firstDataArg, FormatStringType Type,
VariadicCallType CallType,
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) {
@ -1860,7 +1857,7 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
// 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 = StringLiteralCheckType CT =
checkFormatStringExpr(OrigFormatExpr, Args, NumArgs, HasVAListArg, checkFormatStringExpr(OrigFormatExpr, Args, NumArgs, HasVAListArg,
format_idx, firstDataArg, Type); format_idx, firstDataArg, Type, CallType);
if (CT != SLCT_NotALiteral) if (CT != SLCT_NotALiteral)
// Literal format string found, check done! // Literal format string found, check done!
return CT == SLCT_CheckedLiteral; return CT == SLCT_CheckedLiteral;
@ -1908,18 +1905,20 @@ protected:
bool usesPositionalArgs; bool usesPositionalArgs;
bool atFirstArg; bool atFirstArg;
bool inFunctionCall; bool inFunctionCall;
Sema::VariadicCallType CallType;
public: public:
CheckFormatHandler(Sema &s, const StringLiteral *fexpr, CheckFormatHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg, const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, const char *beg, bool hasVAListArg, unsigned numDataArgs, const char *beg, bool hasVAListArg,
Expr **args, unsigned numArgs, Expr **args, unsigned numArgs,
unsigned formatIdx, bool inFunctionCall) unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType callType)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), FirstDataArg(firstDataArg), NumDataArgs(numDataArgs),
Beg(beg), HasVAListArg(hasVAListArg), Beg(beg), HasVAListArg(hasVAListArg),
Args(args), NumArgs(numArgs), FormatIdx(formatIdx), Args(args), NumArgs(numArgs), FormatIdx(formatIdx),
usesPositionalArgs(false), atFirstArg(true), usesPositionalArgs(false), atFirstArg(true),
inFunctionCall(inFunctionCall) { inFunctionCall(inFunctionCall), CallType(callType) {
CoveredArgs.resize(numDataArgs); CoveredArgs.resize(numDataArgs);
CoveredArgs.reset(); CoveredArgs.reset();
} }
@ -2238,11 +2237,13 @@ public:
unsigned numDataArgs, bool isObjC, unsigned numDataArgs, bool isObjC,
const char *beg, bool hasVAListArg, const char *beg, bool hasVAListArg,
Expr **Args, unsigned NumArgs, Expr **Args, unsigned NumArgs,
unsigned formatIdx, bool inFunctionCall) unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType CallType)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, beg, hasVAListArg, Args, NumArgs, numDataArgs, beg, hasVAListArg, Args, NumArgs,
formatIdx, inFunctionCall), ObjCContext(isObjC) {} formatIdx, inFunctionCall, CallType), ObjCContext(isObjC)
{}
bool HandleInvalidPrintfConversionSpecifier( bool HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS, const analyze_printf::PrintfSpecifier &FS,
@ -2646,10 +2647,17 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// was deferred until now, we emit a warning for non-POD // was deferred until now, we emit a warning for non-POD
// arguments here. // arguments here.
if (S.isValidVarArgType(E->getType()) == Sema::VAK_Invalid) { if (S.isValidVarArgType(E->getType()) == Sema::VAK_Invalid) {
unsigned DiagKind;
if (E->getType()->isObjCObjectType())
DiagKind = diag::err_cannot_pass_objc_interface_to_vararg_format;
else
DiagKind = diag::warn_non_pod_vararg_with_format_string;
EmitFormatDiagnostic( EmitFormatDiagnostic(
S.PDiag(diag::warn_non_pod_vararg_with_format_string) S.PDiag(DiagKind)
<< S.getLangOpts().CPlusPlus0x << S.getLangOpts().CPlusPlus0x
<< E->getType() << E->getType()
<< CallType
<< ATR.getRepresentativeTypeName(S.Context) << ATR.getRepresentativeTypeName(S.Context)
<< CSR << CSR
<< E->getSourceRange(), << E->getSourceRange(),
@ -2678,10 +2686,12 @@ public:
const Expr *origFormatExpr, unsigned firstDataArg, const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, const char *beg, bool hasVAListArg, unsigned numDataArgs, const char *beg, bool hasVAListArg,
Expr **Args, unsigned NumArgs, Expr **Args, unsigned NumArgs,
unsigned formatIdx, bool inFunctionCall) unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType CallType)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, beg, hasVAListArg, numDataArgs, beg, hasVAListArg,
Args, NumArgs, formatIdx, inFunctionCall) {} Args, NumArgs, formatIdx, inFunctionCall, CallType)
{}
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier, const char *startSpecifier,
@ -2842,7 +2852,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
Expr **Args, unsigned NumArgs, Expr **Args, unsigned NumArgs,
bool HasVAListArg, unsigned format_idx, bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type, unsigned firstDataArg, FormatStringType Type,
bool inFunctionCall) { bool inFunctionCall, VariadicCallType CallType) {
// CHECK: is the format string a wide literal? // CHECK: is the format string a wide literal?
if (!FExpr->isAscii() && !FExpr->isUTF8()) { if (!FExpr->isAscii() && !FExpr->isUTF8()) {
@ -2872,7 +2882,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
numDataArgs, (Type == FST_NSString), numDataArgs, (Type == FST_NSString),
Str, HasVAListArg, Args, NumArgs, format_idx, Str, HasVAListArg, Args, NumArgs, format_idx,
inFunctionCall); inFunctionCall, CallType);
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen, if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
getLangOpts())) getLangOpts()))
@ -2880,7 +2890,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
} else if (Type == FST_Scanf) { } else if (Type == FST_Scanf) {
CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs,
Str, HasVAListArg, Args, NumArgs, format_idx, Str, HasVAListArg, Args, NumArgs, format_idx,
inFunctionCall); inFunctionCall, CallType);
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen, if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
getLangOpts())) getLangOpts()))

View File

@ -602,14 +602,20 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
/// Incomplete types are considered POD, since this check can be performed /// Incomplete types are considered POD, since this check can be performed
/// when we're in an unevaluated context. /// when we're in an unevaluated context.
Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) { Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
if (Ty->isIncompleteType() || Ty.isCXX98PODType(Context)) if (Ty->isIncompleteType()) {
if (Ty->isObjCObjectType())
return VAK_Invalid;
return VAK_Valid; return VAK_Valid;
}
if (Ty.isCXX98PODType(Context))
return VAK_Valid;
// C++0x [expr.call]p7: // C++0x [expr.call]p7:
// Passing a potentially-evaluated argument of class type (Clause 9) // Passing a potentially-evaluated argument of class type (Clause 9)
// having a non-trivial copy constructor, a non-trivial move constructor, // having a non-trivial copy constructor, a non-trivial move constructor,
// or a non-trivial destructor, with no corresponding parameter, // or a non-trivial destructor, with no corresponding parameter,
// is conditionally-supported with implementation-defined semantics. // is conditionally-supported with implementation-defined semantics.
if (getLangOpts().CPlusPlus0x && !Ty->isDependentType()) if (getLangOpts().CPlusPlus0x && !Ty->isDependentType())
if (CXXRecordDecl *Record = Ty->getAsCXXRecordDecl()) if (CXXRecordDecl *Record = Ty->getAsCXXRecordDecl())
if (Record->hasTrivialCopyConstructor() && if (Record->hasTrivialCopyConstructor() &&
@ -635,18 +641,23 @@ bool Sema::variadicArgumentPODCheck(const Expr *E, VariadicCallType CT) {
PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg) PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg)
<< E->getType() << CT); << E->getType() << CT);
break; break;
case VAK_Invalid: case VAK_Invalid: {
if (Ty->isObjCObjectType())
return DiagRuntimeBehavior(E->getLocStart(), 0,
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
<< Ty << CT);
return DiagRuntimeBehavior(E->getLocStart(), 0, return DiagRuntimeBehavior(E->getLocStart(), 0,
PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
<< getLangOpts().CPlusPlus0x << Ty << CT); << getLangOpts().CPlusPlus0x << Ty << CT);
} }
}
// c++ rules are enforced elsewhere. // c++ rules are enforced elsewhere.
return false; 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 create a trap if the resulting type is not a POD type.
/// interfaces passed by value.
ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
FunctionDecl *FDecl) { FunctionDecl *FDecl) {
if (const BuiltinType *PlaceholderTy = E->getType()->getAsPlaceholderType()) { if (const BuiltinType *PlaceholderTy = E->getType()->getAsPlaceholderType()) {
@ -670,12 +681,6 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
return ExprError(); return ExprError();
E = ExprRes.take(); E = ExprRes.take();
if (E->getType()->isObjCObjectType() &&
DiagRuntimeBehavior(E->getLocStart(), 0,
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
<< E->getType() << CT))
return ExprError();
// Diagnostics regarding non-POD argument types are // Diagnostics regarding non-POD argument types are
// emitted along with format string checking in Sema::CheckFunctionCall(). // emitted along with format string checking in Sema::CheckFunctionCall().
if (isValidVarArgType(E->getType()) == VAK_Invalid) { if (isValidVarArgType(E->getType()) == VAK_Invalid) {

View File

@ -14,5 +14,5 @@ void test_block() {
HasNoCStr hncs(str); HasNoCStr hncs(str);
int n = 4; int n = 4;
block(n, "%s %d", str, n); // no-warning 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'}} block(n, "%s %s", hncs, n); // expected-warning{{cannot pass non-POD object of type 'HasNoCStr' to variadic block; expected type from format string was 'char *'}} expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
} }

View File

@ -49,5 +49,5 @@ void constructor_test() {
const char str[] = "test"; const char str[] = "test";
HasCStr hcs(str); HasCStr hcs(str);
Printf p("%s %d %s", str, 10, 10); // expected-warning {{format specifies type 'char *' but the argument has type 'int'}} 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?}} Printf q("%s %d", hcs, 10); // expected-warning {{cannot pass non-POD object of type 'HasCStr' to variadic constructor; expected type from format string was 'char *'}} expected-note{{did you mean to call the c_str() method?}}
} }

View File

@ -227,3 +227,11 @@ void testInvalidFormatArgument(NSDictionary *dict) {
[Foo fooWithFormat:@"%@ %@", dict[CFSTR("abc")]]; // expected-error{{indexing expression is invalid because subscript type 'CFStringRef' (aka 'const struct __CFString *') is not an integral or Objective-C pointer type}} expected-warning{{more '%' conversions than data arguments}} [Foo fooWithFormat:@"%@ %@", dict[CFSTR("abc")]]; // expected-error{{indexing expression is invalid because subscript type 'CFStringRef' (aka 'const struct __CFString *') is not an integral or Objective-C pointer type}} expected-warning{{more '%' conversions than data arguments}}
} }
// <rdar://problem/11825593>
void testByValueObjectInFormat(Foo *obj) {
printf("%d %d %d", 1L, *obj, 1L); // expected-error {{cannot pass object with interface type 'Foo' by value to variadic function; expected type from format string was 'int'}} expected-warning 2 {{format specifies type 'int' but the argument has type 'long'}}
[Bar log2:@"%d", *obj]; // expected-error {{cannot pass object with interface type 'Foo' by value to variadic method; expected type from format string was 'int'}}
}

View File

@ -26,7 +26,7 @@ foo somefunc2() {} // expected-error {{interface type 'foo' cannot be returned b
// rdar://6780761 // rdar://6780761
void f0(foo *a0) { void f0(foo *a0) {
extern void g0(int x, ...); extern void g0(int x, ...);
g0(1, *(foo*)a0); // expected-error {{cannot pass object with interface type 'foo' by-value through variadic function}} g0(1, *(foo*)a0); // expected-error {{cannot pass object with interface type 'foo' by value through variadic function}}
} }
// rdar://8421082 // rdar://8421082