diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 70 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 27 |
2 files changed, 56 insertions, 41 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 1f57b26c9e..519a5ca3fd 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -499,7 +499,8 @@ void Sema::checkCall(NamedDecl *FDecl, Expr **Args, for (specific_attr_iterator<FormatAttr> I = FDecl->specific_attr_begin<FormatAttr>(), 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; // Refuse POD arguments that weren't caught by the format string @@ -1610,7 +1611,8 @@ Sema::StringLiteralCheckType Sema::checkFormatStringExpr(const Expr *E, Expr **Args, unsigned NumArgs, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, - FormatStringType Type, bool inFunctionCall) { + FormatStringType Type, VariadicCallType CallType, + bool inFunctionCall) { tryAgain: if (E->isTypeDependent() || E->isValueDependent()) return SLCT_NotALiteral; @@ -1634,13 +1636,13 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args, StringLiteralCheckType Left = checkFormatStringExpr(C->getTrueExpr(), Args, NumArgs, HasVAListArg, format_idx, firstDataArg, - Type, inFunctionCall); + Type, CallType, inFunctionCall); if (Left == SLCT_NotALiteral) return SLCT_NotALiteral; StringLiteralCheckType Right = checkFormatStringExpr(C->getFalseExpr(), Args, NumArgs, HasVAListArg, format_idx, firstDataArg, - Type, inFunctionCall); + Type, CallType, inFunctionCall); return Left < Right ? Left : Right; } @@ -1691,7 +1693,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args, } return checkFormatStringExpr(Init, Args, NumArgs, HasVAListArg, format_idx, - firstDataArg, Type, + firstDataArg, Type, CallType, /*inFunctionCall*/false); } } @@ -1749,7 +1751,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args, return checkFormatStringExpr(Arg, Args, NumArgs, HasVAListArg, format_idx, firstDataArg, - Type, inFunctionCall); + Type, CallType, inFunctionCall); } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { unsigned BuiltinID = FD->getBuiltinID(); if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || @@ -1757,7 +1759,8 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args, const Expr *Arg = CE->getArg(0); return checkFormatStringExpr(Arg, Args, NumArgs, HasVAListArg, format_idx, - firstDataArg, Type, inFunctionCall); + firstDataArg, Type, CallType, + inFunctionCall); } } } @@ -1775,7 +1778,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args, if (StrE) { CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx, - firstDataArg, Type, inFunctionCall); + firstDataArg, Type, inFunctionCall, CallType); return SLCT_CheckedLiteral; } @@ -1812,31 +1815,25 @@ Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) { .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. /// 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, unsigned NumArgs, bool IsCXXMember, + VariadicCallType CallType, SourceLocation Loc, SourceRange Range) { FormatStringInfo FSI; if (getFormatStringInfo(Format, IsCXXMember, &FSI)) return CheckFormatArguments(Args, NumArgs, FSI.HasVAListArg, FSI.FormatIdx, FSI.FirstDataArg, GetFormatStringType(Format), - Loc, Range); + CallType, Loc, Range); return false; } bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, + VariadicCallType CallType, SourceLocation Loc, SourceRange Range) { // CHECK: printf/scanf-like function is called with no format string. 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. StringLiteralCheckType CT = checkFormatStringExpr(OrigFormatExpr, Args, NumArgs, HasVAListArg, - format_idx, firstDataArg, Type); + format_idx, firstDataArg, Type, CallType); if (CT != SLCT_NotALiteral) // Literal format string found, check done! return CT == SLCT_CheckedLiteral; @@ -1908,18 +1905,20 @@ protected: bool usesPositionalArgs; bool atFirstArg; bool inFunctionCall; + Sema::VariadicCallType CallType; public: CheckFormatHandler(Sema &s, const StringLiteral *fexpr, const Expr *origFormatExpr, unsigned firstDataArg, unsigned numDataArgs, const char *beg, bool hasVAListArg, Expr **args, unsigned numArgs, - unsigned formatIdx, bool inFunctionCall) + unsigned formatIdx, bool inFunctionCall, + Sema::VariadicCallType callType) : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg), HasVAListArg(hasVAListArg), Args(args), NumArgs(numArgs), FormatIdx(formatIdx), usesPositionalArgs(false), atFirstArg(true), - inFunctionCall(inFunctionCall) { + inFunctionCall(inFunctionCall), CallType(callType) { CoveredArgs.resize(numDataArgs); CoveredArgs.reset(); } @@ -2238,11 +2237,13 @@ public: unsigned numDataArgs, bool isObjC, const char *beg, bool hasVAListArg, Expr **Args, unsigned NumArgs, - unsigned formatIdx, bool inFunctionCall) + unsigned formatIdx, bool inFunctionCall, + Sema::VariadicCallType CallType) : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, numDataArgs, beg, hasVAListArg, Args, NumArgs, - formatIdx, inFunctionCall), ObjCContext(isObjC) {} - + formatIdx, inFunctionCall, CallType), ObjCContext(isObjC) + {} + bool HandleInvalidPrintfConversionSpecifier( 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 // arguments here. 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( - S.PDiag(diag::warn_non_pod_vararg_with_format_string) + S.PDiag(DiagKind) << S.getLangOpts().CPlusPlus0x << E->getType() + << CallType << ATR.getRepresentativeTypeName(S.Context) << CSR << E->getSourceRange(), @@ -2678,10 +2686,12 @@ public: const Expr *origFormatExpr, unsigned firstDataArg, unsigned numDataArgs, const char *beg, bool hasVAListArg, Expr **Args, unsigned NumArgs, - unsigned formatIdx, bool inFunctionCall) + unsigned formatIdx, bool inFunctionCall, + Sema::VariadicCallType CallType) : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, numDataArgs, beg, hasVAListArg, - Args, NumArgs, formatIdx, inFunctionCall) {} + Args, NumArgs, formatIdx, inFunctionCall, CallType) + {} bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, @@ -2842,7 +2852,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, Expr **Args, unsigned NumArgs, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, - bool inFunctionCall) { + bool inFunctionCall, VariadicCallType CallType) { // CHECK: is the format string a wide literal? if (!FExpr->isAscii() && !FExpr->isUTF8()) { @@ -2872,7 +2882,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, (Type == FST_NSString), Str, HasVAListArg, Args, NumArgs, format_idx, - inFunctionCall); + inFunctionCall, CallType); if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen, getLangOpts())) @@ -2880,7 +2890,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, } else if (Type == FST_Scanf) { CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, Str, HasVAListArg, Args, NumArgs, format_idx, - inFunctionCall); + inFunctionCall, CallType); if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen, getLangOpts())) diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 177165c79e..f2e50ba77b 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -602,14 +602,20 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) { /// 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)) + if (Ty->isIncompleteType()) { + if (Ty->isObjCObjectType()) + return VAK_Invalid; return VAK_Valid; + } + + if (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() && @@ -635,18 +641,23 @@ bool Sema::variadicArgumentPODCheck(const Expr *E, VariadicCallType CT) { PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg) << E->getType() << CT); 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, PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) << getLangOpts().CPlusPlus0x << Ty << CT); } + } // c++ rules are enforced elsewhere. return false; } /// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but -/// will warn if the resulting type is not a POD type, and rejects ObjC -/// interfaces passed by value. +/// will create a trap if the resulting type is not a POD type. ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, FunctionDecl *FDecl) { if (const BuiltinType *PlaceholderTy = E->getType()->getAsPlaceholderType()) { @@ -670,12 +681,6 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return ExprError(); 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 // emitted along with format string checking in Sema::CheckFunctionCall(). if (isValidVarArgType(E->getType()) == VAK_Invalid) { |