[cfe-commits] r158887 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/Sema/SemaChecking.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/printf-block.cpp test/Sema

Rafael Espíndola rafael.espindola at gmail.com
Thu Jun 21 16:52:33 PDT 2012


Sorry, I had to revert this because of
http://llvm.org/bugs/show_bug.cgi?id=13168

On 20 June 2012 21:08, Richard Smith <richard-llvm at metafoo.co.uk> wrote:
> Author: rsmith
> Date: Wed Jun 20 20:08:35 2012
> New Revision: 158887
>
> URL: http://llvm.org/viewvc/llvm-project?rev=158887&view=rev
> Log:
> 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!
>
> Added:
>    cfe/trunk/test/SemaCXX/printf-block.cpp
>    cfe/trunk/test/SemaCXX/printf-cstr.cpp
> Modified:
>    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>    cfe/trunk/include/clang/Sema/Sema.h
>    cfe/trunk/lib/Sema/SemaChecking.cpp
>    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>    cfe/trunk/lib/Sema/SemaExpr.cpp
>    cfe/trunk/lib/Sema/SemaOverload.cpp
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=158887&r1=158886&r2=158887&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jun 20 20:08:35 2012
> @@ -4723,6 +4723,11 @@
>   "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<DiagGroup<"non-pod-varargs">>, 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">,
> @@ -5206,7 +5211,8 @@
>   "no closing ']' for '%%[' in scanf format string">,
>   InGroup<Format>;
>  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<NonNull>;
> @@ -5666,4 +5672,3 @@
>  }
>
>  } // end of sema component.
> -
>
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=158887&r1=158886&r2=158887&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Wed Jun 20 20:08:35 2012
> @@ -6409,6 +6409,21 @@
>     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,
> @@ -6421,10 +6436,14 @@
>                               bool AllowExplicit = false);
>
>   // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
> -  // will warn if the resulting type is not a POD type.
> +  // will return ExprError() 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
> @@ -6999,10 +7018,33 @@
>                         const ArraySubscriptExpr *ASE=0,
>                         bool AllowOnePastEnd=true, bool IndexNegated=false);
>   void CheckArrayAccess(const Expr *E);
> -  bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
> +  // 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 CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc,
>                            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);
>
> @@ -7037,21 +7079,31 @@
>     FST_Unknown
>   };
>   static FormatStringType GetFormatStringType(const FormatAttr *Format);
> -  bool SemaCheckStringLiteral(const Expr *E, Expr **Args, unsigned NumArgs,
> -                              bool HasVAListArg, unsigned format_idx,
> -                              unsigned firstDataArg, FormatStringType Type,
> -                              bool inFunctionCall = true);
> +
> +  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);
>
>   void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr,
>                          Expr **Args, unsigned NumArgs, bool HasVAListArg,
>                          unsigned format_idx, unsigned firstDataArg,
>                          FormatStringType Type, bool inFunctionCall);
>
> -  void CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall);
> -  void CheckFormatArguments(const FormatAttr *Format, Expr **Args,
> +  bool CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall);
> +  bool CheckFormatArguments(const FormatAttr *Format, Expr **Args,
>                             unsigned NumArgs, bool IsCXXMember,
>                             SourceLocation Loc, SourceRange Range);
> -  void CheckFormatArguments(Expr **Args, unsigned NumArgs,
> +  bool CheckFormatArguments(Expr **Args, unsigned NumArgs,
>                             bool HasVAListArg, unsigned format_idx,
>                             unsigned firstDataArg, FormatStringType Type,
>                             SourceLocation Loc, SourceRange range);
>
> Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=158887&r1=158886&r2=158887&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Jun 20 20:08:35 2012
> @@ -16,6 +16,7 @@
>  #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"
> @@ -418,34 +419,91 @@
>   return false;
>  }
>
> -/// 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();
> +/// 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;
>
> -  // None of the checks below are needed for functions that don't have
> -  // simple names (e.g., C++ conversion functions).
> -  if (!FnInfo)
> -    return 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.
> +  if (IsCXXMember) {
> +    if(FSI->FormatIdx == 0)
> +      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
>   // more efficient. For example, just map function ids to custom
>   // handlers.
>
>   // Printf and scanf checking.
> +  bool HandledFormatString = false;
>   for (specific_attr_iterator<FormatAttr>
> -         i = FDecl->specific_attr_begin<FormatAttr>(),
> -         e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
> -    CheckFormatArguments(*i, TheCall);
> -  }
> +         I = FDecl->specific_attr_begin<FormatAttr>(),
> +         E = FDecl->specific_attr_end<FormatAttr>(); 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);
>
>   for (specific_attr_iterator<NonNullAttr>
> -         i = FDecl->specific_attr_begin<NonNullAttr>(),
> -         e = FDecl->specific_attr_end<NonNullAttr>(); i != e; ++i) {
> -    CheckNonNullArguments(*i, TheCall->getArgs(),
> -                          TheCall->getCallee()->getLocStart());
> -  }
> +         I = FDecl->specific_attr_begin<NonNullAttr>(),
> +         E = FDecl->specific_attr_end<NonNullAttr>(); 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<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();
>   if (CMId == 0)
> @@ -464,25 +522,18 @@
>
>  bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
>                                Expr **Args, unsigned NumArgs) {
> -  for (specific_attr_iterator<FormatAttr>
> -       i = Method->specific_attr_begin<FormatAttr>(),
> -       e = Method->specific_attr_end<FormatAttr>(); i != e ; ++i) {
> -
> -    CheckFormatArguments(*i, Args, NumArgs, false, lbrac,
> -                         Method->getSourceRange());
> -  }
> +  VariadicCallType CallType =
> +      Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply;
>
> -  // 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);
> -  }
> +  checkCall(Method, Args, NumArgs, Method->param_size(),
> +            /*IsMemberFunction=*/false,
> +            lbrac, Method->getSourceRange(), CallType);
>
>   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);
>   if (!V)
>     return false;
> @@ -491,13 +542,15 @@
>   if (!Ty->isBlockPointerType())
>     return false;
>
> -  // format string checking.
> -  for (specific_attr_iterator<FormatAttr>
> -       i = NDecl->specific_attr_begin<FormatAttr>(),
> -       e = NDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
> -    CheckFormatArguments(*i, TheCall);
> -  }
> -
> +  VariadicCallType CallType =
> +      Proto && Proto->isVariadic() ? VariadicBlock : VariadicDoesNotApply ;
> +  unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
> +
> +  checkCall(NDecl, TheCall->getArgs(), TheCall->getNumArgs(),
> +            NumProtoArgs, /*IsMemberFunction=*/false,
> +            TheCall->getRParenLoc(),
> +            TheCall->getCallee()->getSourceRange(), CallType);
> +
>   return false;
>  }
>
> @@ -1501,14 +1554,18 @@
>   return false;
>  }
>
> -// 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) {
> +// 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) {
>  tryAgain:
>   if (E->isTypeDependent() || E->isValueDependent())
> -    return false;
> +    return SLCT_NotALiteral;
>
>   E = E->IgnoreParenCasts();
>
> @@ -1517,18 +1574,26 @@
>     // 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 true;
> +    return SLCT_CheckedLiteral;
>
>   switch (E->getStmtClass()) {
>   case Stmt::BinaryConditionalOperatorClass:
>   case Stmt::ConditionalOperatorClass: {
> -    const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E);
> -    return SemaCheckStringLiteral(C->getTrueExpr(), Args, NumArgs, HasVAListArg,
> -                                  format_idx, firstDataArg, Type,
> -                                  inFunctionCall)
> -       && SemaCheckStringLiteral(C->getFalseExpr(), Args, NumArgs, HasVAListArg,
> -                                 format_idx, firstDataArg, Type,
> -                                 inFunctionCall);
> +    // 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<AbstractConditionalOperator>(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;
>   }
>
>   case Stmt::ImplicitCastExprClass: {
> @@ -1541,13 +1606,13 @@
>       E = src;
>       goto tryAgain;
>     }
> -    return false;
> +    return SLCT_NotALiteral;
>
>   case Stmt::PredefinedExprClass:
>     // While __func__, etc., are technically not string literals, they
>     // cannot contain format specifiers and thus are not a security
>     // liability.
> -    return true;
> +    return SLCT_UncheckedLiteral;
>
>   case Stmt::DeclRefExprClass: {
>     const DeclRefExpr *DR = cast<DeclRefExpr>(E);
> @@ -1576,9 +1641,10 @@
>             if (InitList->isStringLiteralInit())
>               Init = InitList->getInit(0)->IgnoreParenImpCasts();
>           }
> -          return SemaCheckStringLiteral(Init, Args, NumArgs,
> -                                        HasVAListArg, format_idx, firstDataArg,
> -                                        Type, /*inFunctionCall*/false);
> +          return checkFormatStringExpr(Init, Args, NumArgs,
> +                                       HasVAListArg, format_idx,
> +                                       firstDataArg, Type,
> +                                       /*inFunctionCall*/false);
>         }
>       }
>
> @@ -1612,14 +1678,14 @@
>               // We can't pass a 'scanf' string to a 'printf' function.
>               if (PVIndex == PVFormat->getFormatIdx() &&
>                   Type == GetFormatStringType(PVFormat))
> -                return true;
> +                return SLCT_UncheckedLiteral;
>             }
>           }
>         }
>       }
>     }
>
> -    return false;
> +    return SLCT_NotALiteral;
>   }
>
>   case Stmt::CallExprClass:
> @@ -1633,22 +1699,22 @@
>             --ArgIndex;
>         const Expr *Arg = CE->getArg(ArgIndex - 1);
>
> -        return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg,
> -                                      format_idx, firstDataArg, Type,
> -                                      inFunctionCall);
> +        return checkFormatStringExpr(Arg, Args, NumArgs,
> +                                     HasVAListArg, format_idx, firstDataArg,
> +                                     Type, inFunctionCall);
>       } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
>         unsigned BuiltinID = FD->getBuiltinID();
>         if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
>             BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
>           const Expr *Arg = CE->getArg(0);
> -          return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg,
> -                                        format_idx, firstDataArg, Type,
> -                                        inFunctionCall);
> +          return checkFormatStringExpr(Arg, Args, NumArgs,
> +                                       HasVAListArg, format_idx,
> +                                       firstDataArg, Type, inFunctionCall);
>         }
>       }
>     }
>
> -    return false;
> +    return SLCT_NotALiteral;
>   }
>   case Stmt::ObjCStringLiteralClass:
>   case Stmt::StringLiteralClass: {
> @@ -1662,14 +1728,14 @@
>     if (StrE) {
>       CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx,
>                         firstDataArg, Type, inFunctionCall);
> -      return true;
> +      return SLCT_CheckedLiteral;
>     }
>
> -    return false;
> +    return SLCT_NotALiteral;
>   }
>
>   default:
> -    return false;
> +    return SLCT_NotALiteral;
>   }
>  }
>
> @@ -1700,42 +1766,34 @@
>
>  /// CheckPrintfScanfArguments - Check calls to printf and scanf (and similar
>  /// functions) for correct use of format strings.
> -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<CXXMemberCallExpr>(TheCall);
> -  CheckFormatArguments(Format, TheCall->getArgs(), TheCall->getNumArgs(),
> -                       IsCXXMember, TheCall->getRParenLoc(),
> -                       TheCall->getCallee()->getSourceRange());
> +/// 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());
>  }
>
> -void Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
> +bool Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
>                                 unsigned NumArgs, bool IsCXXMember,
>                                 SourceLocation Loc, SourceRange Range) {
> -  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);
> +  FormatStringInfo FSI;
> +  if (getFormatStringInfo(Format, IsCXXMember, &FSI))
> +    return CheckFormatArguments(Args, NumArgs, FSI.HasVAListArg, FSI.FormatIdx,
> +                                FSI.FirstDataArg, GetFormatStringType(Format),
> +                                Loc, Range);
> +  return false;
>  }
>
> -void Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
> +bool 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;
> +    return false;
>   }
>
>   const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts();
> @@ -1752,14 +1810,17 @@
>   // 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.
> -  if (SemaCheckStringLiteral(OrigFormatExpr, Args, NumArgs, HasVAListArg,
> -                             format_idx, firstDataArg, Type))
> -    return;  // Literal format string found, check done!
> +  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;
>
>   // 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;
> +    return false;
>
>   // 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
> @@ -1767,7 +1828,7 @@
>   // which are usually used in place of NS and CF string literals.
>   if (Type == FST_NSString &&
>       SourceMgr.isInSystemMacro(Args[format_idx]->getLocStart()))
> -    return;
> +    return false;
>
>   // If there are no arguments specified, warn with -Wformat-security, otherwise
>   // warn only with -Wformat-nonliteral.
> @@ -1779,6 +1840,7 @@
>     Diag(Args[format_idx]->getLocStart(),
>          diag::warn_format_nonliteral)
>            << OrigFormatExpr->getSourceRange();
> +  return false;
>  }
>
>  namespace {
> @@ -2138,7 +2200,11 @@
>   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,
> @@ -2152,6 +2218,9 @@
>                          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);
> +
>  };
>  }
>
> @@ -2269,6 +2338,64 @@
>                          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
>  CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
>                                             &FS,
> @@ -2396,20 +2523,30 @@
>   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, Ex->getType())) {
> +  if (ATR.isValid() && !ATR.matchesType(S.Context, E->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<ImplicitCastExpr>(Ex)) {
> +    if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
>       if (ICE->getCastKind() == CK_IntegralCast ||
>           ICE->getCastKind() == CK_FloatingCast) {
> -        Ex = ICE->getSubExpr();
> +        E = 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
> @@ -2417,7 +2554,7 @@
>         if (ICE->getType() == S.Context.IntTy ||
>             ICE->getType() == S.Context.UnsignedIntTy) {
>           // All further checking is done on the subexpression.
> -          if (ATR.matchesType(S.Context, Ex->getType()))
> +          if (ATR.matchesType(S.Context, E->getType()))
>             return true;
>         }
>       }
> @@ -2425,7 +2562,7 @@
>
>     // We may be able to offer a FixItHint if it is a supported type.
>     PrintfSpecifier fixedFS = FS;
> -    bool success = fixedFS.fixType(Ex->getType(), S.getLangOpts(),
> +    bool success = fixedFS.fixType(E->getType(), S.getLangOpts(),
>                                    S.Context, ObjCContext);
>
>     if (success) {
> @@ -2436,24 +2573,38 @@
>
>       EmitFormatDiagnostic(
>         S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
> -          << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
> -          << Ex->getSourceRange(),
> -        Ex->getLocStart(),
> +          << ATR.getRepresentativeTypeName(S.Context) << E->getType()
> +          << E->getSourceRange(),
> +        E->getLocStart(),
>         /*IsStringLocation*/false,
> -        getSpecifierRange(startSpecifier, specifierLen),
> +        getSpecifierRange(StartSpecifier, SpecifierLen),
>         FixItHint::CreateReplacement(
> -          getSpecifierRange(startSpecifier, specifierLen),
> +          getSpecifierRange(StartSpecifier, SpecifierLen),
>           os.str()));
> -    }
> -    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));
> +    } 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);
>     }
>   }
>
>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=158887&r1=158886&r2=158887&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jun 20 20:08:35 2012
> @@ -9028,13 +9028,6 @@
>   unsigned NumExprs = ExprArgs.size();
>   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);
>   return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
>                                         Constructor, Elidable, Exprs, NumExprs,
> @@ -9100,7 +9093,7 @@
>  bool
>  Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
>                               MultiExprArg ArgsPtr,
> -                              SourceLocation Loc,
> +                              SourceLocation Loc,
>                               ASTOwningVector<Expr*> &ConvertedArgs,
>                               bool AllowExplicit) {
>   // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
> @@ -9128,7 +9121,8 @@
>
>   DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size());
>
> -  // FIXME: Missing call to CheckFunctionCall or equivalent
> +  CheckConstructorCall(Constructor, AllArgs.data(), AllArgs.size(),
> +                       Proto, Loc);
>
>   return Invalid;
>  }
>
> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=158887&r1=158886&r2=158887&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Jun 20 20:08:35 2012
> @@ -590,12 +590,59 @@
>   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) {
> -  if (const BuiltinType *PlaceholderTy = E->getType()->getAsPlaceholderType()) {
> +  const QualType &Ty = E->getType();
> +  if (const BuiltinType *PlaceholderTy = Ty->getAsPlaceholderType()) {
>     // Strip the unbridged-cast placeholder expression off, if applicable.
>     if (PlaceholderTy->getKind() == BuiltinType::ARCUnbridgedCast &&
>         (CT == VariadicMethod ||
> @@ -616,77 +663,44 @@
>     return ExprError();
>   E = ExprRes.take();
>
> -  // Don't allow one to pass an Objective-C interface to a vararg.
> -  if (E->getType()->isObjCObjectType() &&
> +  if (Ty->isObjCObjectType() &&
>     DiagRuntimeBehavior(E->getLocStart(), 0,
>                         PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
> -                          << E->getType() << CT))
> +                          << Ty << CT))
>     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;
> -        }
> -      }
> -    }
> +  // 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();
>
> -    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 Call = ActOnCallExpr(TUScope, TrapFn.get(),
> +                                    E->getLocStart(), MultiExprArg(),
> +                                    E->getLocEnd());
> +    if (Call.isInvalid())
> +      return ExprError();
>
> -      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();
> -    }
> +    ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma,
> +                                  Call.get(), E);
> +    if (Comma.isInvalid())
> +      return ExprError();
> +    return 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);
>  }
>
> @@ -3415,6 +3429,25 @@
>   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
>  /// Args/NumArgs to the parameter types of the function FDecl with
>  /// function prototype Proto. Call is the call expression itself, and
> @@ -3506,12 +3539,8 @@
>     }
>   }
>   SmallVector<Expr *, 8> AllArgs;
> -  VariadicCallType CallType =
> -    Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
> -  if (Fn->getType()->isBlockPointerType())
> -    CallType = VariadicBlock; // Block
> -  else if (isa<MemberExpr>(Fn))
> -    CallType = VariadicMethod;
> +  VariadicCallType CallType = getVariadicCallType(FDecl, Proto, Fn);
> +
>   Invalid = GatherArgumentsForCall(Call->getLocStart(), FDecl,
>                                    Proto, 0, Args, NumArgs, AllArgs, CallType);
>   if (Invalid)
> @@ -3600,7 +3629,6 @@
>
>   // 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 &&
> @@ -3938,7 +3966,8 @@
>   TheCall->setType(FuncT->getCallResultType(Context));
>   TheCall->setValueKind(Expr::getValueKindForType(FuncT->getResultType()));
>
> -  if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT)) {
> +  const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT);
> +  if (Proto) {
>     if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, NumArgs,
>                                 RParenLoc, IsExecConfig))
>       return ExprError();
> @@ -3950,8 +3979,7 @@
>       // on our knowledge of the function definition.
>       const FunctionDecl *Def = 0;
>       if (FDecl->hasBody(Def) && NumArgs != Def->param_size()) {
> -        const FunctionProtoType *Proto
> -          = Def->getType()->getAs<FunctionProtoType>();
> +        Proto = Def->getType()->getAs<FunctionProtoType>();
>         if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size()))
>           Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
>             << (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
> @@ -4009,13 +4037,13 @@
>
>   // Do special checking on direct calls to functions.
>   if (FDecl) {
> -    if (CheckFunctionCall(FDecl, TheCall))
> +    if (CheckFunctionCall(FDecl, TheCall, Proto))
>       return ExprError();
>
>     if (BuiltinID)
>       return CheckBuiltinFunctionCall(BuiltinID, TheCall);
>   } else if (NDecl) {
> -    if (CheckBlockCall(NDecl, TheCall))
> +    if (CheckBlockCall(NDecl, TheCall, Proto))
>       return ExprError();
>   }
>
>
> Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=158887&r1=158886&r2=158887&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jun 20 20:08:35 2012
> @@ -10720,7 +10720,7 @@
>
>   DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
>
> -  if (CheckFunctionCall(Method, TheCall))
> +  if (CheckFunctionCall(Method, TheCall, Proto))
>     return ExprError();
>
>   if ((isa<CXXConstructorDecl>(CurContext) ||
> @@ -11028,7 +11028,7 @@
>
>   DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
>
> -  if (CheckFunctionCall(Method, TheCall))
> +  if (CheckFunctionCall(Method, TheCall, Proto))
>     return true;
>
>   return MaybeBindToTemporary(TheCall);
> @@ -11208,7 +11208,7 @@
>   if (CheckCallReturnType(FD->getResultType(), UDSuffixLoc, UDL, FD))
>     return ExprError();
>
> -  if (CheckFunctionCall(FD, UDL))
> +  if (CheckFunctionCall(FD, UDL, NULL))
>     return ExprError();
>
>   return MaybeBindToTemporary(UDL);
>
> Added: cfe/trunk/test/SemaCXX/printf-block.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/printf-block.cpp?rev=158887&view=auto
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/printf-block.cpp (added)
> +++ cfe/trunk/test/SemaCXX/printf-block.cpp Wed Jun 20 20:08:35 2012
> @@ -0,0 +1,18 @@
> +// 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'}}
> +}
>
> Added: cfe/trunk/test/SemaCXX/printf-cstr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/printf-cstr.cpp?rev=158887&view=auto
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/printf-cstr.cpp (added)
> +++ cfe/trunk/test/SemaCXX/printf-cstr.cpp Wed Jun 20 20:08:35 2012
> @@ -0,0 +1,53 @@
> +// 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?}}
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits




More information about the cfe-commits mailing list