diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-06-21 01:08:35 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-06-21 01:08:35 +0000 |
commit | 7d96f6106bfbd85b1af06f34fdbf2834aad0e47e (patch) | |
tree | 936fde4c40fa12ef5ee5c66475acdaa65d779a21 /lib/Sema/SemaExpr.cpp | |
parent | caba856a867c058f6c69ec0d5f3ea8169776fb9a (diff) |
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!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158887 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 174 |
1 files changed, 101 insertions, 73 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index adc8ea814e..de0de89b83 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -590,12 +590,59 @@ 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) { - 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 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, 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 @@ 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<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 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, } } 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 @@ 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 && @@ -3938,7 +3966,8 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, 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 @@ 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()) { - 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 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // 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(); } |