diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2c13e0c177..a7582a0d28 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4723,11 +4723,6 @@ 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< - "cannot pass %select{non-POD|non-trivial}0 object of type %1 to variadic " - "function; expected type from format string was %2">, - InGroup>, DefaultError; - def warn_cannot_pass_non_pod_arg_to_vararg : Warning< "cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic" " %select{function|block|method|constructor}2; call will abort at runtime">, @@ -5211,8 +5206,7 @@ def warn_scanf_scanlist_incomplete : Warning< "no closing ']' for '%%[' in scanf format string">, InGroup; def note_format_string_defined : Note<"format string is defined here">; -def note_printf_c_str: Note<"did you mean to call the %0 method?">; - + def warn_null_arg : Warning< "null passed to a callee which requires a non-null argument">, InGroup; @@ -5672,3 +5666,4 @@ def err_module_private_definition : Error< } } // end of sema component. + diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 4b54e82d40..6e7f23bd6b 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -6409,21 +6409,6 @@ public: VariadicDoesNotApply }; - VariadicCallType getVariadicCallType(FunctionDecl *FDecl, - const FunctionProtoType *Proto, - Expr *Fn); - - // Used for determining in which context a type is allowed to be passed to a - // vararg function. - enum VarArgKind { - VAK_Valid, - VAK_ValidInCXX11, - VAK_Invalid - }; - - // Determines which VarArgKind fits an expression. - VarArgKind isValidVarArgType(const QualType &Ty); - /// GatherArgumentsForCall - Collector argument expressions for various /// form of call prototypes. bool GatherArgumentsForCall(SourceLocation CallLoc, @@ -6436,14 +6421,10 @@ public: bool AllowExplicit = false); // 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, FunctionDecl *FDecl); - /// Checks to see if the given expression is a valid argument to a variadic - /// function, issuing a diagnostic and returning NULL if not. - bool variadicArgumentPODCheck(const Expr *E, VariadicCallType CT); - // UsualArithmeticConversions - performs the UsualUnaryConversions on it's // operands and then handles various conversions that are common to binary // operators (C99 6.3.1.8). If both operands aren't arithmetic, this @@ -7018,33 +6999,10 @@ private: const ArraySubscriptExpr *ASE=0, bool AllowOnePastEnd=true, bool IndexNegated=false); void CheckArrayAccess(const Expr *E); - // Used to grab the relevant information from a FormatAttr and a - // FunctionDeclaration. - struct FormatStringInfo { - unsigned FormatIdx; - unsigned FirstDataArg; - bool HasVAListArg; - }; - - bool getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, - FormatStringInfo *FSI); - bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, - const FunctionProtoType *Proto); + bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall); bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc, Expr **Args, unsigned NumArgs); - 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 CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall); bool CheckObjCString(Expr *Arg); @@ -7079,31 +7037,21 @@ private: FST_Unknown }; static FormatStringType GetFormatStringType(const FormatAttr *Format); - - enum StringLiteralCheckType { - SLCT_NotALiteral, - SLCT_UncheckedLiteral, - SLCT_CheckedLiteral - }; - - StringLiteralCheckType checkFormatStringExpr(const Expr *E, - Expr **Args, unsigned NumArgs, - bool HasVAListArg, - unsigned format_idx, - unsigned firstDataArg, - FormatStringType Type, - bool inFunctionCall = true); + bool SemaCheckStringLiteral(const Expr *E, Expr **Args, unsigned NumArgs, + bool HasVAListArg, unsigned format_idx, + unsigned firstDataArg, FormatStringType Type, + bool inFunctionCall = true); void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr, Expr **Args, unsigned NumArgs, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, bool inFunctionCall); - bool CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall); - bool CheckFormatArguments(const FormatAttr *Format, Expr **Args, + void CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall); + void CheckFormatArguments(const FormatAttr *Format, Expr **Args, unsigned NumArgs, bool IsCXXMember, SourceLocation Loc, SourceRange Range); - bool CheckFormatArguments(Expr **Args, unsigned NumArgs, + void CheckFormatArguments(Expr **Args, unsigned NumArgs, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, SourceLocation Loc, SourceRange range); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index ef7dc8819f..b8ed7b52f6 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -16,7 +16,6 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Initialization.h" -#include "clang/Sema/Lookup.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Analysis/Analyses/FormatString.h" #include "clang/AST/ASTContext.h" @@ -419,91 +418,34 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return false; } -/// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo -/// parameter with the FormatAttr's correct format_idx and firstDataArg. -/// Returns true when the format fits the function and the FormatStringInfo has -/// been populated. -bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, - FormatStringInfo *FSI) { - FSI->HasVAListArg = Format->getFirstArg() == 0; - FSI->FormatIdx = Format->getFormatIdx() - 1; - FSI->FirstDataArg = FSI->HasVAListArg ? 0 : Format->getFirstArg() - 1; +/// CheckFunctionCall - Check a direct function call for various correctness +/// and safety properties not strictly enforced by the C type system. +bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { + // Get the IdentifierInfo* for the called function. + IdentifierInfo *FnInfo = FDecl->getIdentifier(); - // The way the format attribute works in GCC, the implicit this argument - // of member functions is counted. However, it doesn't appear in our own - // lists, so decrement format_idx in that case. - if (IsCXXMember) { - if(FSI->FormatIdx == 0) - return false; - --FSI->FormatIdx; - if (FSI->FirstDataArg != 0) - --FSI->FirstDataArg; - } - return true; -} + // None of the checks below are needed for functions that don't have + // simple names (e.g., C++ conversion functions). + if (!FnInfo) + return false; -/// Handles the checks for format strings, non-POD arguments to vararg -/// functions, and NULL arguments passed to non-NULL parameters. -void Sema::checkCall(NamedDecl *FDecl, Expr **Args, - unsigned NumArgs, - unsigned NumProtoArgs, - bool IsMemberFunction, - SourceLocation Loc, - SourceRange Range, - VariadicCallType CallType) { // FIXME: This mechanism should be abstracted to be less fragile and // more efficient. For example, just map function ids to custom // handlers. // Printf and scanf checking. - bool HandledFormatString = false; for (specific_attr_iterator - I = FDecl->specific_attr_begin(), - E = FDecl->specific_attr_end(); I != E ; ++I) - if (CheckFormatArguments(*I, Args, NumArgs, IsMemberFunction, Loc, Range)) - HandledFormatString = true; - - // Refuse POD arguments that weren't caught by the format string - // checks above. - if (!HandledFormatString && CallType != VariadicDoesNotApply) - for (unsigned ArgIdx = NumProtoArgs; ArgIdx < NumArgs; ++ArgIdx) - variadicArgumentPODCheck(Args[ArgIdx], CallType); + i = FDecl->specific_attr_begin(), + e = FDecl->specific_attr_end(); i != e ; ++i) { + CheckFormatArguments(*i, TheCall); + } for (specific_attr_iterator - I = FDecl->specific_attr_begin(), - E = FDecl->specific_attr_end(); I != E; ++I) - CheckNonNullArguments(*I, Args, Loc); -} - -/// CheckConstructorCall - Check a constructor call for correctness and safety -/// properties not enforced by the C type system. -void Sema::CheckConstructorCall(FunctionDecl *FDecl, Expr **Args, - unsigned NumArgs, - const FunctionProtoType *Proto, - SourceLocation Loc) { - VariadicCallType CallType = - Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; - checkCall(FDecl, Args, NumArgs, Proto->getNumArgs(), - /*IsMemberFunction=*/true, Loc, SourceRange(), CallType); -} - -/// CheckFunctionCall - Check a direct function call for various correctness -/// and safety properties not strictly enforced by the C type system. -bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, - const FunctionProtoType *Proto) { - bool IsMemberFunction = isa(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; + i = FDecl->specific_attr_begin(), + e = FDecl->specific_attr_end(); i != e; ++i) { + CheckNonNullArguments(*i, TheCall->getArgs(), + TheCall->getCallee()->getLocStart()); + } unsigned CMId = FDecl->getMemoryFunctionKind(); if (CMId == 0) @@ -522,18 +464,25 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac, Expr **Args, unsigned NumArgs) { - VariadicCallType CallType = - Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply; + for (specific_attr_iterator + i = Method->specific_attr_begin(), + e = Method->specific_attr_end(); i != e ; ++i) { - checkCall(Method, Args, NumArgs, Method->param_size(), - /*IsMemberFunction=*/false, - lbrac, Method->getSourceRange(), CallType); + CheckFormatArguments(*i, Args, NumArgs, false, lbrac, + Method->getSourceRange()); + } + + // diagnose nonnull arguments. + for (specific_attr_iterator + i = Method->specific_attr_begin(), + e = Method->specific_attr_end(); i != e; ++i) { + CheckNonNullArguments(*i, Args, lbrac); + } return false; } -bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall, - const FunctionProtoType *Proto) { +bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { const VarDecl *V = dyn_cast(NDecl); if (!V) return false; @@ -542,15 +491,13 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall, if (!Ty->isBlockPointerType()) return false; - VariadicCallType CallType = - Proto && Proto->isVariadic() ? VariadicBlock : VariadicDoesNotApply ; - unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0; + // format string checking. + for (specific_attr_iterator + i = NDecl->specific_attr_begin(), + e = NDecl->specific_attr_end(); i != e ; ++i) { + CheckFormatArguments(*i, TheCall); + } - checkCall(NDecl, TheCall->getArgs(), TheCall->getNumArgs(), - NumProtoArgs, /*IsMemberFunction=*/false, - TheCall->getRParenLoc(), - TheCall->getCallee()->getSourceRange(), CallType); - return false; } @@ -1554,18 +1501,14 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { return false; } -// Determine if an expression is a string literal or constant string. -// If this function returns false on the arguments to a function expecting a -// format string, we will usually need to emit a warning. -// True string literals are then checked by CheckFormatString. -Sema::StringLiteralCheckType -Sema::checkFormatStringExpr(const Expr *E, Expr **Args, - unsigned NumArgs, bool HasVAListArg, - unsigned format_idx, unsigned firstDataArg, - FormatStringType Type, bool inFunctionCall) { +// Handle i > 1 ? "x" : "y", recursively. +bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args, + unsigned NumArgs, bool HasVAListArg, + unsigned format_idx, unsigned firstDataArg, + FormatStringType Type, bool inFunctionCall) { tryAgain: if (E->isTypeDependent() || E->isValueDependent()) - return SLCT_NotALiteral; + return false; 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 // dependent. Ideally if the format string cannot be null then // it should have a 'nonnull' attribute in the function prototype. - return SLCT_CheckedLiteral; + return true; switch (E->getStmtClass()) { case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { - // The expression is a literal if both sub-expressions were, and it was - // completely checked only if both sub-expressions were checked. - const AbstractConditionalOperator *C = - cast(E); - StringLiteralCheckType Left = - checkFormatStringExpr(C->getTrueExpr(), Args, NumArgs, - HasVAListArg, format_idx, firstDataArg, - Type, inFunctionCall); - if (Left == SLCT_NotALiteral) - return SLCT_NotALiteral; - StringLiteralCheckType Right = - checkFormatStringExpr(C->getFalseExpr(), Args, NumArgs, - HasVAListArg, format_idx, firstDataArg, - Type, inFunctionCall); - return Left < Right ? Left : Right; + const AbstractConditionalOperator *C = cast(E); + return SemaCheckStringLiteral(C->getTrueExpr(), Args, NumArgs, HasVAListArg, + format_idx, firstDataArg, Type, + inFunctionCall) + && SemaCheckStringLiteral(C->getFalseExpr(), Args, NumArgs, HasVAListArg, + format_idx, firstDataArg, Type, + inFunctionCall); } case Stmt::ImplicitCastExprClass: { @@ -1606,13 +1541,13 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args, E = src; goto tryAgain; } - return SLCT_NotALiteral; + return false; case Stmt::PredefinedExprClass: // While __func__, etc., are technically not string literals, they // cannot contain format specifiers and thus are not a security // liability. - return SLCT_UncheckedLiteral; + return true; case Stmt::DeclRefExprClass: { const DeclRefExpr *DR = cast(E); @@ -1641,10 +1576,9 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args, if (InitList->isStringLiteralInit()) Init = InitList->getInit(0)->IgnoreParenImpCasts(); } - return checkFormatStringExpr(Init, Args, NumArgs, - HasVAListArg, format_idx, - firstDataArg, Type, - /*inFunctionCall*/false); + return SemaCheckStringLiteral(Init, Args, NumArgs, + HasVAListArg, format_idx, firstDataArg, + Type, /*inFunctionCall*/false); } } @@ -1678,14 +1612,14 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args, // We can't pass a 'scanf' string to a 'printf' function. if (PVIndex == PVFormat->getFormatIdx() && Type == GetFormatStringType(PVFormat)) - return SLCT_UncheckedLiteral; + return true; } } } } } - return SLCT_NotALiteral; + return false; } case Stmt::CallExprClass: @@ -1699,22 +1633,22 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args, --ArgIndex; const Expr *Arg = CE->getArg(ArgIndex - 1); - return checkFormatStringExpr(Arg, Args, NumArgs, - HasVAListArg, format_idx, firstDataArg, - Type, inFunctionCall); + return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg, + format_idx, firstDataArg, Type, + inFunctionCall); } else if (const FunctionDecl *FD = dyn_cast(ND)) { unsigned BuiltinID = FD->getBuiltinID(); if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) { const Expr *Arg = CE->getArg(0); - return checkFormatStringExpr(Arg, Args, NumArgs, - HasVAListArg, format_idx, - firstDataArg, Type, inFunctionCall); + return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg, + format_idx, firstDataArg, Type, + inFunctionCall); } } } - return SLCT_NotALiteral; + return false; } case Stmt::ObjCStringLiteralClass: case Stmt::StringLiteralClass: { @@ -1728,14 +1662,14 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args, if (StrE) { CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx, firstDataArg, Type, inFunctionCall); - return SLCT_CheckedLiteral; + return true; } - return SLCT_NotALiteral; + return false; } 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 /// 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(TheCall); - return CheckFormatArguments(Format, TheCall->getArgs(), - TheCall->getNumArgs(), - IsCXXMember, TheCall->getRParenLoc(), - TheCall->getCallee()->getSourceRange()); +void Sema::CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall) { + bool IsCXXMember = false; + // The way the format attribute works in GCC, the implicit this argument + // of member functions is counted. However, it doesn't appear in our own + // lists, so decrement format_idx in that case. + IsCXXMember = isa(TheCall); + CheckFormatArguments(Format, TheCall->getArgs(), TheCall->getNumArgs(), + IsCXXMember, TheCall->getRParenLoc(), + TheCall->getCallee()->getSourceRange()); } -bool Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args, +void Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args, unsigned NumArgs, bool IsCXXMember, 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); - return false; + bool HasVAListArg = Format->getFirstArg() == 0; + unsigned format_idx = Format->getFormatIdx() - 1; + unsigned firstDataArg = HasVAListArg ? 0 : Format->getFirstArg() - 1; + if (IsCXXMember) { + if (format_idx == 0) + return; + --format_idx; + if(firstDataArg != 0) + --firstDataArg; + } + CheckFormatArguments(Args, NumArgs, HasVAListArg, format_idx, + firstDataArg, GetFormatStringType(Format), Loc, Range); } -bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs, +void Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, SourceLocation Loc, SourceRange Range) { // CHECK: printf/scanf-like function is called with no format string. if (format_idx >= NumArgs) { Diag(Loc, diag::warn_missing_format_string) << Range; - return false; + return; } const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts(); @@ -1810,17 +1752,14 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs, // C string (e.g. "%d") // ObjC string uses the same format specifiers as C string, so we can use // the same format string checking logic for both ObjC and C strings. - StringLiteralCheckType CT = - checkFormatStringExpr(OrigFormatExpr, Args, NumArgs, HasVAListArg, - format_idx, firstDataArg, Type); - if (CT != SLCT_NotALiteral) - // Literal format string found, check done! - return CT == SLCT_CheckedLiteral; + if (SemaCheckStringLiteral(OrigFormatExpr, Args, NumArgs, HasVAListArg, + format_idx, firstDataArg, Type)) + return; // Literal format string found, check done! // Strftime is particular as it always uses a single 'time' argument, // so it is safe to pass a non-literal string. if (Type == FST_Strftime) - return false; + return; // 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 @@ -1828,7 +1767,7 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs, // which are usually used in place of NS and CF string literals. if (Type == FST_NSString && SourceMgr.isInSystemMacro(Args[format_idx]->getLocStart())) - return false; + return; // If there are no arguments specified, warn with -Wformat-security, otherwise // warn only with -Wformat-nonliteral. @@ -1840,7 +1779,6 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs, Diag(Args[format_idx]->getLocStart(), diag::warn_format_nonliteral) << OrigFormatExpr->getSourceRange(); - return false; } namespace { @@ -2200,11 +2138,7 @@ public: bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen); - bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, - const char *StartSpecifier, - unsigned SpecifierLen, - const Expr *E); - + bool HandleAmount(const analyze_format_string::OptionalAmount &Amt, unsigned k, const char *startSpecifier, unsigned specifierLen); void HandleInvalidAmount(const analyze_printf::PrintfSpecifier &FS, @@ -2218,9 +2152,6 @@ public: const analyze_printf::OptionalFlag &ignoredFlag, const analyze_printf::OptionalFlag &flag, const char *startSpecifier, unsigned specifierLen); - bool checkForCStrMembers(const analyze_printf::ArgTypeResult &ATR, - const Expr *E, const CharSourceRange &CSR); - }; } @@ -2338,64 +2269,6 @@ void CheckPrintfHandler::HandleIgnoredFlag( 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 -static llvm::SmallPtrSet -CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) { - const RecordType *RT = Ty->getAs(); - llvm::SmallPtrSet Results; - - if (!RT) - return Results; - const CXXRecordDecl *RD = dyn_cast(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(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 MethodSet; - - MethodSet Results = - CXXRecordMembersNamed("c_str", S, E->getType()); - - for (MethodSet::iterator MI = Results.begin(), ME = Results.end(); - MI != ME; ++MI) { - const CXXMethodDecl *Method = *MI; - if (Method->getNumParams() == 0 && - ATR.matchesType(S.Context, Method->getResultType())) { - // FIXME: Suggest parens if the expression needs them. - SourceLocation EndLoc = - S.getPreprocessor().getLocForEndOfToken(E->getLocEnd()); - S.Diag(E->getLocStart(), diag::note_printf_c_str) - << "c_str()" - << FixItHint::CreateInsertion(EndLoc, ".c_str()"); - return true; - } - } - - return false; -} - bool CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, @@ -2523,30 +2396,20 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex)) return false; - return checkFormatExpr(FS, startSpecifier, specifierLen, - getDataArg(argIndex)); -} - -bool -CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, - const char *StartSpecifier, - unsigned SpecifierLen, - const Expr *E) { - using namespace analyze_format_string; - using namespace analyze_printf; // Now type check the data expression that matches the // format specifier. + const Expr *Ex = getDataArg(argIndex); const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context, ObjCContext); - if (ATR.isValid() && !ATR.matchesType(S.Context, E->getType())) { + if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) { // Look through argument promotions for our error message's reported type. // This includes the integral and floating promotions, but excludes array // and function pointer decay; seeing that an argument intended to be a // string has type 'char [6]' is probably more confusing than 'char *'. - if (const ImplicitCastExpr *ICE = dyn_cast(E)) { + if (const ImplicitCastExpr *ICE = dyn_cast(Ex)) { if (ICE->getCastKind() == CK_IntegralCast || ICE->getCastKind() == CK_FloatingCast) { - E = ICE->getSubExpr(); + Ex = ICE->getSubExpr(); // Check if we didn't match because of an implicit cast from a 'char' // or 'short' to an 'int'. This is done because printf is a varargs @@ -2554,7 +2417,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, if (ICE->getType() == S.Context.IntTy || ICE->getType() == S.Context.UnsignedIntTy) { // All further checking is done on the subexpression. - if (ATR.matchesType(S.Context, E->getType())) + if (ATR.matchesType(S.Context, Ex->getType())) 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. PrintfSpecifier fixedFS = FS; - bool success = fixedFS.fixType(E->getType(), S.getLangOpts(), + bool success = fixedFS.fixType(Ex->getType(), S.getLangOpts(), S.Context, ObjCContext); if (success) { @@ -2573,38 +2436,24 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, EmitFormatDiagnostic( S.PDiag(diag::warn_printf_conversion_argument_type_mismatch) - << ATR.getRepresentativeTypeName(S.Context) << E->getType() - << E->getSourceRange(), - E->getLocStart(), + << ATR.getRepresentativeTypeName(S.Context) << Ex->getType() + << Ex->getSourceRange(), + Ex->getLocStart(), /*IsStringLocation*/false, - getSpecifierRange(StartSpecifier, SpecifierLen), + getSpecifierRange(startSpecifier, specifierLen), FixItHint::CreateReplacement( - getSpecifierRange(StartSpecifier, SpecifierLen), + getSpecifierRange(startSpecifier, specifierLen), os.str())); - } else { - const CharSourceRange &CSR = getSpecifierRange(StartSpecifier, - SpecifierLen); - // Since the warning for passing non-POD types to variadic functions - // was deferred until now, we emit a warning for non-POD - // arguments here. - if (S.isValidVarArgType(E->getType()) == Sema::VAK_Invalid) { - EmitFormatDiagnostic( - S.PDiag(diag::warn_non_pod_vararg_with_format_string) - << S.getLangOpts().CPlusPlus0x - << E->getType() - << ATR.getRepresentativeTypeName(S.Context) - << CSR - << E->getSourceRange(), - E->getLocStart(), /*IsStringLocation*/false, CSR); - - checkForCStrMembers(ATR, E, CSR); - } else - EmitFormatDiagnostic( - S.PDiag(diag::warn_printf_conversion_argument_type_mismatch) - << ATR.getRepresentativeTypeName(S.Context) << E->getType() - << CSR - << E->getSourceRange(), - E->getLocStart(), /*IsStringLocation*/false, CSR); + } + else { + EmitFormatDiagnostic( + S.PDiag(diag::warn_printf_conversion_argument_type_mismatch) + << ATR.getRepresentativeTypeName(S.Context) << Ex->getType() + << getSpecifierRange(startSpecifier, specifierLen) + << Ex->getSourceRange(), + Ex->getLocStart(), + /*IsStringLocation*/false, + getSpecifierRange(startSpecifier, specifierLen)); } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 828083527a..2a11c74593 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -9028,6 +9028,13 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, unsigned NumExprs = ExprArgs.size(); Expr **Exprs = (Expr **)ExprArgs.release(); + for (specific_attr_iterator + i = Constructor->specific_attr_begin(), + e = Constructor->specific_attr_end(); i != e; ++i) { + const NonNullAttr *NonNull = *i; + CheckNonNullArguments(NonNull, ExprArgs.get(), ConstructLoc); + } + MarkFunctionReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, Constructor, Elidable, Exprs, NumExprs, @@ -9093,7 +9100,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { bool Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, - SourceLocation Loc, + SourceLocation Loc, ASTOwningVector &ConvertedArgs, bool AllowExplicit) { // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall. @@ -9121,8 +9128,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size()); - CheckConstructorCall(Constructor, AllArgs.data(), AllArgs.size(), - Proto, Loc); + // FIXME: Missing call to CheckFunctionCall or equivalent return Invalid; } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index e50dfca8f5..2d10a4973b 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -598,59 +598,12 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *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 /// will warn if the resulting type is not a POD type, and rejects ObjC /// interfaces passed by value. ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, FunctionDecl *FDecl) { - const QualType &Ty = E->getType(); - if (const BuiltinType *PlaceholderTy = Ty->getAsPlaceholderType()) { + if (const BuiltinType *PlaceholderTy = E->getType()->getAsPlaceholderType()) { // Strip the unbridged-cast placeholder expression off, if applicable. if (PlaceholderTy->getKind() == BuiltinType::ARCUnbridgedCast && (CT == VariadicMethod || @@ -671,44 +624,77 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return ExprError(); 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, PDiag(diag::err_cannot_pass_objc_interface_to_vararg) - << Ty << CT)) + << E->getType() << CT)) return ExprError(); - // Diagnostics regarding non-POD argument types are - // emitted along with format string checking in Sema::CheckFunctionCall(). - if (isValidVarArgType(Ty) == VAK_Invalid) { - // Turn this into a trap. - CXXScopeSpec SS; - SourceLocation TemplateKWLoc; - UnqualifiedId Name; - Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"), - E->getLocStart()); - ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc, - Name, true, false); - if (TrapFn.isInvalid()) - return ExprError(); + // Complain about passing non-POD types through varargs. However, don't + // perform this check for incomplete types, which we can get here when we're + // in an unevaluated context. + if (!E->getType()->isIncompleteType() && + !E->getType().isCXX98PODType(Context)) { + // C++0x [expr.call]p7: + // Passing a potentially-evaluated argument of class type (Clause 9) + // having a non-trivial copy constructor, a non-trivial move constructor, + // or a non-trivial destructor, with no corresponding parameter, + // is conditionally-supported with implementation-defined semantics. + bool TrivialEnough = false; + if (getLangOpts().CPlusPlus0x && !E->getType()->isDependentType()) { + if (CXXRecordDecl *Record = E->getType()->getAsCXXRecordDecl()) { + if (Record->hasTrivialCopyConstructor() && + Record->hasTrivialMoveConstructor() && + Record->hasTrivialDestructor()) { + DiagRuntimeBehavior(E->getLocStart(), 0, + PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg) + << E->getType() << CT); + TrivialEnough = true; + } + } + } - ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), - E->getLocStart(), MultiExprArg(), - E->getLocEnd()); - if (Call.isInvalid()) - return ExprError(); + if (!TrivialEnough && + getLangOpts().ObjCAutoRefCount && + E->getType()->isObjCLifetimeType()) + TrivialEnough = true; + + if (TrivialEnough) { + // Nothing to diagnose. This is okay. + } else if (DiagRuntimeBehavior(E->getLocStart(), 0, + PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) + << getLangOpts().CPlusPlus0x << E->getType() + << CT)) { + // Turn this into a trap. + CXXScopeSpec SS; + SourceLocation TemplateKWLoc; + UnqualifiedId Name; + Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"), + E->getLocStart()); + ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc, Name, + true, false); + if (TrapFn.isInvalid()) + return ExprError(); - ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma, - Call.get(), E); - if (Comma.isInvalid()) - return ExprError(); - return Comma.get(); + ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), E->getLocStart(), + MultiExprArg(), E->getLocEnd()); + if (Call.isInvalid()) + return ExprError(); + + ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma, + Call.get(), E); + if (Comma.isInvalid()) + return ExprError(); + E = Comma.get(); + } } - + // c++ rules are enforced elsewhere. if (!getLangOpts().CPlusPlus && RequireCompleteType(E->getExprLoc(), E->getType(), diag::err_call_incomplete_argument)) return ExprError(); - + return Owned(E); } @@ -3437,25 +3423,6 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, 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(FDecl)) - return VariadicConstructor; - else if (Fn && Fn->getType()->isBlockPointerType()) - return VariadicBlock; - else if (FDecl) { - if (CXXMethodDecl *Method = dyn_cast_or_null(FDecl)) - if (Method->isInstance()) - return VariadicMethod; - return VariadicFunction; - } - } - return VariadicDoesNotApply; -} - /// ConvertArgumentsForCall - Converts the arguments specified in /// Args/NumArgs to the parameter types of the function FDecl with /// function prototype Proto. Call is the call expression itself, and @@ -3547,8 +3514,12 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, } } SmallVector AllArgs; - VariadicCallType CallType = getVariadicCallType(FDecl, Proto, Fn); - + VariadicCallType CallType = + Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; + if (Fn->getType()->isBlockPointerType()) + CallType = VariadicBlock; // Block + else if (isa(Fn)) + CallType = VariadicMethod; Invalid = GatherArgumentsForCall(Call->getLocStart(), FDecl, Proto, 0, Args, NumArgs, AllArgs, CallType); if (Invalid) @@ -3637,6 +3608,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, // If this is a variadic call, handle args passed through "...". if (CallType != VariadicDoesNotApply) { + // Assume that extern "C" functions with variadic arguments that // return __unknown_anytype aren't *really* variadic. if (Proto->getResultType() == Context.UnknownAnyTy && @@ -3974,8 +3946,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, TheCall->setType(FuncT->getCallResultType(Context)); TheCall->setValueKind(Expr::getValueKindForType(FuncT->getResultType())); - const FunctionProtoType *Proto = dyn_cast(FuncT); - if (Proto) { + if (const FunctionProtoType *Proto = dyn_cast(FuncT)) { if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, NumArgs, RParenLoc, IsExecConfig)) return ExprError(); @@ -3987,7 +3958,8 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // on our knowledge of the function definition. const FunctionDecl *Def = 0; if (FDecl->hasBody(Def) && NumArgs != Def->param_size()) { - Proto = Def->getType()->getAs(); + const FunctionProtoType *Proto + = Def->getType()->getAs(); if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size())) Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments) << (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. if (FDecl) { - if (CheckFunctionCall(FDecl, TheCall, Proto)) + if (CheckFunctionCall(FDecl, TheCall)) return ExprError(); if (BuiltinID) return CheckBuiltinFunctionCall(BuiltinID, TheCall); } else if (NDecl) { - if (CheckBlockCall(NDecl, TheCall, Proto)) + if (CheckBlockCall(NDecl, TheCall)) return ExprError(); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 9a14cad72b..013af8a8f6 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -10720,7 +10720,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs); - if (CheckFunctionCall(Method, TheCall, Proto)) + if (CheckFunctionCall(Method, TheCall)) return ExprError(); if ((isa(CurContext) || @@ -11028,7 +11028,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs); - if (CheckFunctionCall(Method, TheCall, Proto)) + if (CheckFunctionCall(Method, TheCall)) return true; return MaybeBindToTemporary(TheCall); @@ -11208,7 +11208,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, if (CheckCallReturnType(FD->getResultType(), UDSuffixLoc, UDL, FD)) return ExprError(); - if (CheckFunctionCall(FD, UDL, NULL)) + if (CheckFunctionCall(FD, UDL)) return ExprError(); return MaybeBindToTemporary(UDL); diff --git a/test/SemaCXX/printf-block.cpp b/test/SemaCXX/printf-block.cpp deleted file mode 100644 index a7d266bac5..0000000000 --- a/test/SemaCXX/printf-block.cpp +++ /dev/null @@ -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'}} -} diff --git a/test/SemaCXX/printf-cstr.cpp b/test/SemaCXX/printf-cstr.cpp deleted file mode 100644 index efb2f704e1..0000000000 --- a/test/SemaCXX/printf-cstr.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -Wformat -verify %s -Wno-error=non-pod-varargs - -#include - -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?}} -}