blob: 3393cf73f1c00378acdfc78342e67f4a7a142309 [file] [log] [blame]
//===--- SemaChecking.cpp - Extra Semantic Checking -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements extra semantic analysis beyond what is enforced
// by the C type system.
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/ConvertUTF.h"
#include <limits>
using namespace clang;
using namespace sema;
SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
unsigned ByteNo) const {
return SL->getLocationOfByte(ByteNo, PP.getSourceManager(),
PP.getLangOptions(), PP.getTargetInfo());
}
/// Checks that a call expression's argument count is the desired number.
/// This is useful when doing custom type-checking. Returns true on error.
static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) {
unsigned argCount = call->getNumArgs();
if (argCount == desiredArgCount) return false;
if (argCount < desiredArgCount)
return S.Diag(call->getLocEnd(), diag::err_typecheck_call_too_few_args)
<< 0 /*function call*/ << desiredArgCount << argCount
<< call->getSourceRange();
// Highlight all the excess arguments.
SourceRange range(call->getArg(desiredArgCount)->getLocStart(),
call->getArg(argCount - 1)->getLocEnd());
return S.Diag(range.getBegin(), diag::err_typecheck_call_too_many_args)
<< 0 /*function call*/ << desiredArgCount << argCount
<< call->getArg(1)->getSourceRange();
}
/// CheckBuiltinAnnotationString - Checks that string argument to the builtin
/// annotation is a non wide string literal.
static bool CheckBuiltinAnnotationString(Sema &S, Expr *Arg) {
Arg = Arg->IgnoreParenCasts();
StringLiteral *Literal = dyn_cast<StringLiteral>(Arg);
if (!Literal || !Literal->isAscii()) {
S.Diag(Arg->getLocStart(), diag::err_builtin_annotation_not_string_constant)
<< Arg->getSourceRange();
return true;
}
return false;
}
ExprResult
Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
ExprResult TheCallResult(Owned(TheCall));
// Find out if any arguments are required to be integer constant expressions.
unsigned ICEArguments = 0;
ASTContext::GetBuiltinTypeError Error;
Context.GetBuiltinType(BuiltinID, Error, &ICEArguments);
if (Error != ASTContext::GE_None)
ICEArguments = 0; // Don't diagnose previously diagnosed errors.
// If any arguments are required to be ICE's, check and diagnose.
for (unsigned ArgNo = 0; ICEArguments != 0; ++ArgNo) {
// Skip arguments not required to be ICE's.
if ((ICEArguments & (1 << ArgNo)) == 0) continue;
llvm::APSInt Result;
if (SemaBuiltinConstantArg(TheCall, ArgNo, Result))
return true;
ICEArguments &= ~(1 << ArgNo);
}
switch (BuiltinID) {
case Builtin::BI__builtin___CFStringMakeConstantString:
assert(TheCall->getNumArgs() == 1 &&
"Wrong # arguments to builtin CFStringMakeConstantString");
if (CheckObjCString(TheCall->getArg(0)))
return ExprError();
break;
case Builtin::BI__builtin_stdarg_start:
case Builtin::BI__builtin_va_start:
if (SemaBuiltinVAStart(TheCall))
return ExprError();
break;
case Builtin::BI__builtin_isgreater:
case Builtin::BI__builtin_isgreaterequal:
case Builtin::BI__builtin_isless:
case Builtin::BI__builtin_islessequal:
case Builtin::BI__builtin_islessgreater:
case Builtin::BI__builtin_isunordered:
if (SemaBuiltinUnorderedCompare(TheCall))
return ExprError();
break;
case Builtin::BI__builtin_fpclassify:
if (SemaBuiltinFPClassification(TheCall, 6))
return ExprError();
break;
case Builtin::BI__builtin_isfinite:
case Builtin::BI__builtin_isinf:
case Builtin::BI__builtin_isinf_sign:
case Builtin::BI__builtin_isnan:
case Builtin::BI__builtin_isnormal:
if (SemaBuiltinFPClassification(TheCall, 1))
return ExprError();
break;
case Builtin::BI__builtin_shufflevector:
return SemaBuiltinShuffleVector(TheCall);
// TheCall will be freed by the smart pointer here, but that's fine, since
// SemaBuiltinShuffleVector guts it, but then doesn't release it.
case Builtin::BI__builtin_prefetch:
if (SemaBuiltinPrefetch(TheCall))
return ExprError();
break;
case Builtin::BI__builtin_object_size:
if (SemaBuiltinObjectSize(TheCall))
return ExprError();
break;
case Builtin::BI__builtin_longjmp:
if (SemaBuiltinLongjmp(TheCall))
return ExprError();
break;
case Builtin::BI__builtin_classify_type:
if (checkArgCount(*this, TheCall, 1)) return true;
TheCall->setType(Context.IntTy);
break;
case Builtin::BI__builtin_constant_p:
if (checkArgCount(*this, TheCall, 1)) return true;
TheCall->setType(Context.IntTy);
break;
case Builtin::BI__sync_fetch_and_add:
case Builtin::BI__sync_fetch_and_add_1:
case Builtin::BI__sync_fetch_and_add_2:
case Builtin::BI__sync_fetch_and_add_4:
case Builtin::BI__sync_fetch_and_add_8:
case Builtin::BI__sync_fetch_and_add_16:
case Builtin::BI__sync_fetch_and_sub:
case Builtin::BI__sync_fetch_and_sub_1:
case Builtin::BI__sync_fetch_and_sub_2:
case Builtin::BI__sync_fetch_and_sub_4:
case Builtin::BI__sync_fetch_and_sub_8:
case Builtin::BI__sync_fetch_and_sub_16:
case Builtin::BI__sync_fetch_and_or:
case Builtin::BI__sync_fetch_and_or_1:
case Builtin::BI__sync_fetch_and_or_2:
case Builtin::BI__sync_fetch_and_or_4:
case Builtin::BI__sync_fetch_and_or_8:
case Builtin::BI__sync_fetch_and_or_16:
case Builtin::BI__sync_fetch_and_and:
case Builtin::BI__sync_fetch_and_and_1:
case Builtin::BI__sync_fetch_and_and_2:
case Builtin::BI__sync_fetch_and_and_4:
case Builtin::BI__sync_fetch_and_and_8:
case Builtin::BI__sync_fetch_and_and_16:
case Builtin::BI__sync_fetch_and_xor:
case Builtin::BI__sync_fetch_and_xor_1:
case Builtin::BI__sync_fetch_and_xor_2:
case Builtin::BI__sync_fetch_and_xor_4:
case Builtin::BI__sync_fetch_and_xor_8:
case Builtin::BI__sync_fetch_and_xor_16:
case Builtin::BI__sync_add_and_fetch:
case Builtin::BI__sync_add_and_fetch_1:
case Builtin::BI__sync_add_and_fetch_2:
case Builtin::BI__sync_add_and_fetch_4:
case Builtin::BI__sync_add_and_fetch_8:
case Builtin::BI__sync_add_and_fetch_16:
case Builtin::BI__sync_sub_and_fetch:
case Builtin::BI__sync_sub_and_fetch_1:
case Builtin::BI__sync_sub_and_fetch_2:
case Builtin::BI__sync_sub_and_fetch_4:
case Builtin::BI__sync_sub_and_fetch_8:
case Builtin::BI__sync_sub_and_fetch_16:
case Builtin::BI__sync_and_and_fetch:
case Builtin::BI__sync_and_and_fetch_1:
case Builtin::BI__sync_and_and_fetch_2:
case Builtin::BI__sync_and_and_fetch_4:
case Builtin::BI__sync_and_and_fetch_8:
case Builtin::BI__sync_and_and_fetch_16:
case Builtin::BI__sync_or_and_fetch:
case Builtin::BI__sync_or_and_fetch_1:
case Builtin::BI__sync_or_and_fetch_2:
case Builtin::BI__sync_or_and_fetch_4:
case Builtin::BI__sync_or_and_fetch_8:
case Builtin::BI__sync_or_and_fetch_16:
case Builtin::BI__sync_xor_and_fetch:
case Builtin::BI__sync_xor_and_fetch_1:
case Builtin::BI__sync_xor_and_fetch_2:
case Builtin::BI__sync_xor_and_fetch_4:
case Builtin::BI__sync_xor_and_fetch_8:
case Builtin::BI__sync_xor_and_fetch_16:
case Builtin::BI__sync_val_compare_and_swap:
case Builtin::BI__sync_val_compare_and_swap_1:
case Builtin::BI__sync_val_compare_and_swap_2:
case Builtin::BI__sync_val_compare_and_swap_4:
case Builtin::BI__sync_val_compare_and_swap_8:
case Builtin::BI__sync_val_compare_and_swap_16:
case Builtin::BI__sync_bool_compare_and_swap:
case Builtin::BI__sync_bool_compare_and_swap_1:
case Builtin::BI__sync_bool_compare_and_swap_2:
case Builtin::BI__sync_bool_compare_and_swap_4:
case Builtin::BI__sync_bool_compare_and_swap_8:
case Builtin::BI__sync_bool_compare_and_swap_16:
case Builtin::BI__sync_lock_test_and_set:
case Builtin::BI__sync_lock_test_and_set_1:
case Builtin::BI__sync_lock_test_and_set_2:
case Builtin::BI__sync_lock_test_and_set_4:
case Builtin::BI__sync_lock_test_and_set_8:
case Builtin::BI__sync_lock_test_and_set_16:
case Builtin::BI__sync_lock_release:
case Builtin::BI__sync_lock_release_1:
case Builtin::BI__sync_lock_release_2:
case Builtin::BI__sync_lock_release_4:
case Builtin::BI__sync_lock_release_8:
case Builtin::BI__sync_lock_release_16:
case Builtin::BI__sync_swap:
case Builtin::BI__sync_swap_1:
case Builtin::BI__sync_swap_2:
case Builtin::BI__sync_swap_4:
case Builtin::BI__sync_swap_8:
case Builtin::BI__sync_swap_16:
return SemaBuiltinAtomicOverloaded(move(TheCallResult));
case Builtin::BI__atomic_load:
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Load);
case Builtin::BI__atomic_store:
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Store);
case Builtin::BI__atomic_init:
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Init);
case Builtin::BI__atomic_exchange:
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xchg);
case Builtin::BI__atomic_compare_exchange_strong:
return SemaAtomicOpsOverloaded(move(TheCallResult),
AtomicExpr::CmpXchgStrong);
case Builtin::BI__atomic_compare_exchange_weak:
return SemaAtomicOpsOverloaded(move(TheCallResult),
AtomicExpr::CmpXchgWeak);
case Builtin::BI__atomic_fetch_add:
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Add);
case Builtin::BI__atomic_fetch_sub:
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Sub);
case Builtin::BI__atomic_fetch_and:
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::And);
case Builtin::BI__atomic_fetch_or:
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Or);
case Builtin::BI__atomic_fetch_xor:
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xor);
case Builtin::BI__builtin_annotation:
if (CheckBuiltinAnnotationString(*this, TheCall->getArg(1)))
return ExprError();
break;
}
// Since the target specific builtins for each arch overlap, only check those
// of the arch we are compiling for.
if (BuiltinID >= Builtin::FirstTSBuiltin) {
switch (Context.getTargetInfo().getTriple().getArch()) {
case llvm::Triple::arm:
case llvm::Triple::thumb:
if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
default:
break;
}
}
return move(TheCallResult);
}
// Get the valid immediate range for the specified NEON type code.
static unsigned RFT(unsigned t, bool shift = false) {
NeonTypeFlags Type(t);
int IsQuad = Type.isQuad();
switch (Type.getEltType()) {
case NeonTypeFlags::Int8:
case NeonTypeFlags::Poly8:
return shift ? 7 : (8 << IsQuad) - 1;
case NeonTypeFlags::Int16:
case NeonTypeFlags::Poly16:
return shift ? 15 : (4 << IsQuad) - 1;
case NeonTypeFlags::Int32:
return shift ? 31 : (2 << IsQuad) - 1;
case NeonTypeFlags::Int64:
return shift ? 63 : (1 << IsQuad) - 1;
case NeonTypeFlags::Float16:
assert(!shift && "cannot shift float types!");
return (4 << IsQuad) - 1;
case NeonTypeFlags::Float32:
assert(!shift && "cannot shift float types!");
return (2 << IsQuad) - 1;
}
llvm_unreachable("Invalid NeonTypeFlag!");
}
/// getNeonEltType - Return the QualType corresponding to the elements of
/// the vector type specified by the NeonTypeFlags. This is used to check
/// the pointer arguments for Neon load/store intrinsics.
static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context) {
switch (Flags.getEltType()) {
case NeonTypeFlags::Int8:
return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy;
case NeonTypeFlags::Int16:
return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy;
case NeonTypeFlags::Int32:
return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy;
case NeonTypeFlags::Int64:
return Flags.isUnsigned() ? Context.UnsignedLongLongTy : Context.LongLongTy;
case NeonTypeFlags::Poly8:
return Context.SignedCharTy;
case NeonTypeFlags::Poly16:
return Context.ShortTy;
case NeonTypeFlags::Float16:
return Context.UnsignedShortTy;
case NeonTypeFlags::Float32:
return Context.FloatTy;
}
llvm_unreachable("Invalid NeonTypeFlag!");
}
bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
llvm::APSInt Result;
unsigned mask = 0;
unsigned TV = 0;
int PtrArgNum = -1;
bool HasConstPtr = false;
switch (BuiltinID) {
#define GET_NEON_OVERLOAD_CHECK
#include "clang/Basic/arm_neon.inc"
#undef GET_NEON_OVERLOAD_CHECK
}
// For NEON intrinsics which are overloaded on vector element type, validate
// the immediate which specifies which variant to emit.
unsigned ImmArg = TheCall->getNumArgs()-1;
if (mask) {
if (SemaBuiltinConstantArg(TheCall, ImmArg, Result))
return true;
TV = Result.getLimitedValue(64);
if ((TV > 63) || (mask & (1 << TV)) == 0)
return Diag(TheCall->getLocStart(), diag::err_invalid_neon_type_code)
<< TheCall->getArg(ImmArg)->getSourceRange();
}
if (PtrArgNum >= 0) {
// Check that pointer arguments have the specified type.
Expr *Arg = TheCall->getArg(PtrArgNum);
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg))
Arg = ICE->getSubExpr();
ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg);
QualType RHSTy = RHS.get()->getType();
QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context);
if (HasConstPtr)
EltTy = EltTy.withConst();
QualType LHSTy = Context.getPointerType(EltTy);
AssignConvertType ConvTy;
ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
if (RHS.isInvalid())
return true;
if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), LHSTy, RHSTy,
RHS.get(), AA_Assigning))
return true;
}
// For NEON intrinsics which take an immediate value as part of the
// instruction, range check them here.
unsigned i = 0, l = 0, u = 0;
switch (BuiltinID) {
default: return false;
case ARM::BI__builtin_arm_ssat: i = 1; l = 1; u = 31; break;
case ARM::BI__builtin_arm_usat: i = 1; u = 31; break;
case ARM::BI__builtin_arm_vcvtr_f:
case ARM::BI__builtin_arm_vcvtr_d: i = 1; u = 1; break;
#define GET_NEON_IMMEDIATE_CHECK
#include "clang/Basic/arm_neon.inc"
#undef GET_NEON_IMMEDIATE_CHECK
};
// Check that the immediate argument is actually a constant.
if (SemaBuiltinConstantArg(TheCall, i, Result))
return true;
// Range check against the upper/lower values for this isntruction.
unsigned Val = Result.getZExtValue();
if (Val < l || Val > (u + l))
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
<< l << u+l << TheCall->getArg(i)->getSourceRange();
// FIXME: VFP Intrinsics should error if VFP not present.
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();
// None of the checks below are needed for functions that don't have
// simple names (e.g., C++ conversion functions).
if (!FnInfo)
return false;
// 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.
for (specific_attr_iterator<FormatAttr>
i = FDecl->specific_attr_begin<FormatAttr>(),
e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
CheckFormatArguments(*i, TheCall);
}
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());
}
unsigned CMId = FDecl->getMemoryFunctionKind();
if (CMId == 0)
return false;
// Handle memory setting and copying functions.
if (CMId == Builtin::BIstrlcpy || CMId == Builtin::BIstrlcat)
CheckStrlcpycatArguments(TheCall, FnInfo);
else if (CMId == Builtin::BIstrncat)
CheckStrncatArguments(TheCall, FnInfo);
else
CheckMemaccessArguments(TheCall, CMId, FnInfo);
return false;
}
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());
}
// 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);
}
return false;
}
bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
const VarDecl *V = dyn_cast<VarDecl>(NDecl);
if (!V)
return false;
QualType Ty = V->getType();
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);
}
return false;
}
ExprResult
Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) {
CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
// All these operations take one of the following four forms:
// T __atomic_load(_Atomic(T)*, int) (loads)
// T* __atomic_add(_Atomic(T*)*, ptrdiff_t, int) (pointer add/sub)
// int __atomic_compare_exchange_strong(_Atomic(T)*, T*, T, int, int)
// (cmpxchg)
// T __atomic_exchange(_Atomic(T)*, T, int) (everything else)
// where T is an appropriate type, and the int paremeterss are for orderings.
unsigned NumVals = 1;
unsigned NumOrders = 1;
if (Op == AtomicExpr::Load) {
NumVals = 0;
} else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong) {
NumVals = 2;
NumOrders = 2;
}
if (Op == AtomicExpr::Init)
NumOrders = 0;
if (TheCall->getNumArgs() < NumVals+NumOrders+1) {
Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
<< 0 << NumVals+NumOrders+1 << TheCall->getNumArgs()
<< TheCall->getCallee()->getSourceRange();
return ExprError();
} else if (TheCall->getNumArgs() > NumVals+NumOrders+1) {
Diag(TheCall->getArg(NumVals+NumOrders+1)->getLocStart(),
diag::err_typecheck_call_too_many_args)
<< 0 << NumVals+NumOrders+1 << TheCall->getNumArgs()
<< TheCall->getCallee()->getSourceRange();
return ExprError();
}
// Inspect the first argument of the atomic operation. This should always be
// a pointer to an _Atomic type.
Expr *Ptr = TheCall->getArg(0);
Ptr = DefaultFunctionArrayLvalueConversion(Ptr).get();
const PointerType *pointerType = Ptr->getType()->getAs<PointerType>();
if (!pointerType) {
Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
QualType AtomTy = pointerType->getPointeeType();
if (!AtomTy->isAtomicType()) {
Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
QualType ValType = AtomTy->getAs<AtomicType>()->getValueType();
if ((Op == AtomicExpr::Add || Op == AtomicExpr::Sub) &&
!ValType->isIntegerType() && !ValType->isPointerType()) {
Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
if (!ValType->isIntegerType() &&
(Op == AtomicExpr::And || Op == AtomicExpr::Or || Op == AtomicExpr::Xor)){
Diag(DRE->getLocStart(), diag::err_atomic_op_logical_needs_atomic_int)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
switch (ValType.getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
// okay
break;
case Qualifiers::OCL_Weak:
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Autoreleasing:
Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership)
<< ValType << Ptr->getSourceRange();
return ExprError();
}
QualType ResultType = ValType;
if (Op == AtomicExpr::Store || Op == AtomicExpr::Init)
ResultType = Context.VoidTy;
else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong)
ResultType = Context.BoolTy;
// The first argument --- the pointer --- has a fixed type; we
// deduce the types of the rest of the arguments accordingly. Walk
// the remaining arguments, converting them to the deduced value type.
for (unsigned i = 1; i != NumVals+NumOrders+1; ++i) {
ExprResult Arg = TheCall->getArg(i);
QualType Ty;
if (i < NumVals+1) {
// The second argument to a cmpxchg is a pointer to the data which will
// be exchanged. The second argument to a pointer add/subtract is the
// amount to add/subtract, which must be a ptrdiff_t. The third
// argument to a cmpxchg and the second argument in all other cases
// is the type of the value.
if (i == 1 && (Op == AtomicExpr::CmpXchgWeak ||
Op == AtomicExpr::CmpXchgStrong))
Ty = Context.getPointerType(ValType.getUnqualifiedType());
else if (!ValType->isIntegerType() &&
(Op == AtomicExpr::Add || Op == AtomicExpr::Sub))
Ty = Context.getPointerDiffType();
else
Ty = ValType;
} else {
// The order(s) are always converted to int.
Ty = Context.IntTy;
}
InitializedEntity Entity =
InitializedEntity::InitializeParameter(Context, Ty, false);
Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
if (Arg.isInvalid())
return true;
TheCall->setArg(i, Arg.get());
}
SmallVector<Expr*, 5> SubExprs;
SubExprs.push_back(Ptr);
if (Op == AtomicExpr::Load) {
SubExprs.push_back(TheCall->getArg(1)); // Order
} else if (Op == AtomicExpr::Init) {
SubExprs.push_back(TheCall->getArg(1)); // Val1
} else if (Op != AtomicExpr::CmpXchgWeak && Op != AtomicExpr::CmpXchgStrong) {
SubExprs.push_back(TheCall->getArg(2)); // Order
SubExprs.push_back(TheCall->getArg(1)); // Val1
} else {
SubExprs.push_back(TheCall->getArg(3)); // Order
SubExprs.push_back(TheCall->getArg(1)); // Val1
SubExprs.push_back(TheCall->getArg(2)); // Val2
SubExprs.push_back(TheCall->getArg(4)); // OrderFail
}
return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
SubExprs.data(), SubExprs.size(),
ResultType, Op,
TheCall->getRParenLoc()));
}
/// checkBuiltinArgument - Given a call to a builtin function, perform
/// normal type-checking on the given argument, updating the call in
/// place. This is useful when a builtin function requires custom
/// type-checking for some of its arguments but not necessarily all of
/// them.
///
/// Returns true on error.
static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) {
FunctionDecl *Fn = E->getDirectCallee();
assert(Fn && "builtin call without direct callee!");
ParmVarDecl *Param = Fn->getParamDecl(ArgIndex);
InitializedEntity Entity =
InitializedEntity::InitializeParameter(S.Context, Param);
ExprResult Arg = E->getArg(0);
Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg);
if (Arg.isInvalid())
return true;
E->setArg(ArgIndex, Arg.take());
return false;
}
/// SemaBuiltinAtomicOverloaded - We have a call to a function like
/// __sync_fetch_and_add, which is an overloaded function based on the pointer
/// type of its first argument. The main ActOnCallExpr routines have already
/// promoted the types of arguments because all of these calls are prototyped as
/// void(...).
///
/// This function goes through and does final semantic checking for these
/// builtins,
ExprResult
Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
CallExpr *TheCall = (CallExpr *)TheCallResult.get();
DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
// Ensure that we have at least one argument to do type inference from.
if (TheCall->getNumArgs() < 1) {
Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args_at_least)
<< 0 << 1 << TheCall->getNumArgs()
<< TheCall->getCallee()->getSourceRange();
return ExprError();
}
// Inspect the first argument of the atomic builtin. This should always be
// a pointer type, whose element is an integral scalar or pointer type.
// Because it is a pointer type, we don't have to worry about any implicit
// casts here.
// FIXME: We don't allow floating point scalars as input.
Expr *FirstArg = TheCall->getArg(0);
ExprResult FirstArgResult = DefaultFunctionArrayLvalueConversion(FirstArg);
if (FirstArgResult.isInvalid())
return ExprError();
FirstArg = FirstArgResult.take();
TheCall->setArg(0, FirstArg);
const PointerType *pointerType = FirstArg->getType()->getAs<PointerType>();
if (!pointerType) {
Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer)
<< FirstArg->getType() << FirstArg->getSourceRange();
return ExprError();
}
QualType ValType = pointerType->getPointeeType();
if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
!ValType->isBlockPointerType()) {
Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer_intptr)
<< FirstArg->getType() << FirstArg->getSourceRange();
return ExprError();
}
switch (ValType.getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
// okay
break;
case Qualifiers::OCL_Weak:
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Autoreleasing:
Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership)
<< ValType << FirstArg->getSourceRange();
return ExprError();
}
// Strip any qualifiers off ValType.
ValType = ValType.getUnqualifiedType();
// The majority of builtins return a value, but a few have special return
// types, so allow them to override appropriately below.
QualType ResultType = ValType;
// We need to figure out which concrete builtin this maps onto. For example,
// __sync_fetch_and_add with a 2 byte object turns into
// __sync_fetch_and_add_2.
#define BUILTIN_ROW(x) \
{ Builtin::BI##x##_1, Builtin::BI##x##_2, Builtin::BI##x##_4, \
Builtin::BI##x##_8, Builtin::BI##x##_16 }
static const unsigned BuiltinIndices[][5] = {
BUILTIN_ROW(__sync_fetch_and_add),
BUILTIN_ROW(__sync_fetch_and_sub),
BUILTIN_ROW(__sync_fetch_and_or),
BUILTIN_ROW(__sync_fetch_and_and),
BUILTIN_ROW(__sync_fetch_and_xor),
BUILTIN_ROW(__sync_add_and_fetch),
BUILTIN_ROW(__sync_sub_and_fetch),
BUILTIN_ROW(__sync_and_and_fetch),
BUILTIN_ROW(__sync_or_and_fetch),
BUILTIN_ROW(__sync_xor_and_fetch),
BUILTIN_ROW(__sync_val_compare_and_swap),
BUILTIN_ROW(__sync_bool_compare_and_swap),
BUILTIN_ROW(__sync_lock_test_and_set),
BUILTIN_ROW(__sync_lock_release),
BUILTIN_ROW(__sync_swap)
};
#undef BUILTIN_ROW
// Determine the index of the size.
unsigned SizeIndex;
switch (Context.getTypeSizeInChars(ValType).getQuantity()) {
case 1: SizeIndex = 0; break;
case 2: SizeIndex = 1; break;
case 4: SizeIndex = 2; break;
case 8: SizeIndex = 3; break;
case 16: SizeIndex = 4; break;
default:
Diag(DRE->getLocStart(), diag::err_atomic_builtin_pointer_size)
<< FirstArg->getType() << FirstArg->getSourceRange();
return ExprError();
}
// Each of these builtins has one pointer argument, followed by some number of
// values (0, 1 or 2) followed by a potentially empty varags list of stuff
// that we ignore. Find out which row of BuiltinIndices to read from as well
// as the number of fixed args.
unsigned BuiltinID = FDecl->getBuiltinID();
unsigned BuiltinIndex, NumFixed = 1;
switch (BuiltinID) {
default: llvm_unreachable("Unknown overloaded atomic builtin!");
case Builtin::BI__sync_fetch_and_add:
case Builtin::BI__sync_fetch_and_add_1:
case Builtin::BI__sync_fetch_and_add_2:
case Builtin::BI__sync_fetch_and_add_4:
case Builtin::BI__sync_fetch_and_add_8:
case Builtin::BI__sync_fetch_and_add_16:
BuiltinIndex = 0;
break;
case Builtin::BI__sync_fetch_and_sub:
case Builtin::BI__sync_fetch_and_sub_1:
case Builtin::BI__sync_fetch_and_sub_2:
case Builtin::BI__sync_fetch_and_sub_4:
case Builtin::BI__sync_fetch_and_sub_8:
case Builtin::BI__sync_fetch_and_sub_16:
BuiltinIndex = 1;
break;
case Builtin::BI__sync_fetch_and_or:
case Builtin::BI__sync_fetch_and_or_1:
case Builtin::BI__sync_fetch_and_or_2:
case Builtin::BI__sync_fetch_and_or_4:
case Builtin::BI__sync_fetch_and_or_8:
case Builtin::BI__sync_fetch_and_or_16:
BuiltinIndex = 2;
break;
case Builtin::BI__sync_fetch_and_and:
case Builtin::BI__sync_fetch_and_and_1:
case Builtin::BI__sync_fetch_and_and_2:
case Builtin::BI__sync_fetch_and_and_4:
case Builtin::BI__sync_fetch_and_and_8:
case Builtin::BI__sync_fetch_and_and_16:
BuiltinIndex = 3;
break;
case Builtin::BI__sync_fetch_and_xor:
case Builtin::BI__sync_fetch_and_xor_1:
case Builtin::BI__sync_fetch_and_xor_2:
case Builtin::BI__sync_fetch_and_xor_4:
case Builtin::BI__sync_fetch_and_xor_8:
case Builtin::BI__sync_fetch_and_xor_16:
BuiltinIndex = 4;
break;
case Builtin::BI__sync_add_and_fetch:
case Builtin::BI__sync_add_and_fetch_1:
case Builtin::BI__sync_add_and_fetch_2:
case Builtin::BI__sync_add_and_fetch_4:
case Builtin::BI__sync_add_and_fetch_8:
case Builtin::BI__sync_add_and_fetch_16:
BuiltinIndex = 5;
break;
case Builtin::BI__sync_sub_and_fetch:
case Builtin::BI__sync_sub_and_fetch_1:
case Builtin::BI__sync_sub_and_fetch_2:
case Builtin::BI__sync_sub_and_fetch_4:
case Builtin::BI__sync_sub_and_fetch_8:
case Builtin::BI__sync_sub_and_fetch_16:
BuiltinIndex = 6;
break;
case Builtin::BI__sync_and_and_fetch:
case Builtin::BI__sync_and_and_fetch_1:
case Builtin::BI__sync_and_and_fetch_2:
case Builtin::BI__sync_and_and_fetch_4:
case Builtin::BI__sync_and_and_fetch_8:
case Builtin::BI__sync_and_and_fetch_16:
BuiltinIndex = 7;
break;
case Builtin::BI__sync_or_and_fetch:
case Builtin::BI__sync_or_and_fetch_1:
case Builtin::BI__sync_or_and_fetch_2:
case Builtin::BI__sync_or_and_fetch_4:
case Builtin::BI__sync_or_and_fetch_8:
case Builtin::BI__sync_or_and_fetch_16:
BuiltinIndex = 8;
break;
case Builtin::BI__sync_xor_and_fetch:
case Builtin::BI__sync_xor_and_fetch_1:
case Builtin::BI__sync_xor_and_fetch_2:
case Builtin::BI__sync_xor_and_fetch_4:
case Builtin::BI__sync_xor_and_fetch_8:
case Builtin::BI__sync_xor_and_fetch_16:
BuiltinIndex = 9;
break;
case Builtin::BI__sync_val_compare_and_swap:
case Builtin::BI__sync_val_compare_and_swap_1:
case Builtin::BI__sync_val_compare_and_swap_2:
case Builtin::BI__sync_val_compare_and_swap_4:
case Builtin::BI__sync_val_compare_and_swap_8:
case Builtin::BI__sync_val_compare_and_swap_16:
BuiltinIndex = 10;
NumFixed = 2;
break;
case Builtin::BI__sync_bool_compare_and_swap:
case Builtin::BI__sync_bool_compare_and_swap_1:
case Builtin::BI__sync_bool_compare_and_swap_2:
case Builtin::BI__sync_bool_compare_and_swap_4:
case Builtin::BI__sync_bool_compare_and_swap_8:
case Builtin::BI__sync_bool_compare_and_swap_16:
BuiltinIndex = 11;
NumFixed = 2;
ResultType = Context.BoolTy;
break;
case Builtin::BI__sync_lock_test_and_set:
case Builtin::BI__sync_lock_test_and_set_1:
case Builtin::BI__sync_lock_test_and_set_2:
case Builtin::BI__sync_lock_test_and_set_4:
case Builtin::BI__sync_lock_test_and_set_8:
case Builtin::BI__sync_lock_test_and_set_16:
BuiltinIndex = 12;
break;
case Builtin::BI__sync_lock_release:
case Builtin::BI__sync_lock_release_1:
case Builtin::BI__sync_lock_release_2:
case Builtin::BI__sync_lock_release_4:
case Builtin::BI__sync_lock_release_8:
case Builtin::BI__sync_lock_release_16:
BuiltinIndex = 13;
NumFixed = 0;
ResultType = Context.VoidTy;
break;
case Builtin::BI__sync_swap:
case Builtin::BI__sync_swap_1:
case Builtin::BI__sync_swap_2:
case Builtin::BI__sync_swap_4:
case Builtin::BI__sync_swap_8:
case Builtin::BI__sync_swap_16:
BuiltinIndex = 14;
break;
}
// Now that we know how many fixed arguments we expect, first check that we
// have at least that many.
if (TheCall->getNumArgs() < 1+NumFixed) {
Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args_at_least)
<< 0 << 1+NumFixed << TheCall->getNumArgs()
<< TheCall->getCallee()->getSourceRange();
return ExprError();
}
// Get the decl for the concrete builtin from this, we can tell what the
// concrete integer type we should convert to is.
unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex];
const char *NewBuiltinName = Context.BuiltinInfo.GetName(NewBuiltinID);
IdentifierInfo *NewBuiltinII = PP.getIdentifierInfo(NewBuiltinName);
FunctionDecl *NewBuiltinDecl =
cast<FunctionDecl>(LazilyCreateBuiltin(NewBuiltinII, NewBuiltinID,
TUScope, false, DRE->getLocStart()));
// The first argument --- the pointer --- has a fixed type; we
// deduce the types of the rest of the arguments accordingly. Walk
// the remaining arguments, converting them to the deduced value type.
for (unsigned i = 0; i != NumFixed; ++i) {
ExprResult Arg = TheCall->getArg(i+1);
// GCC does an implicit conversion to the pointer or integer ValType. This
// can fail in some cases (1i -> int**), check for this error case now.
// Initialize the argument.
InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
ValType, /*consume*/ false);
Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
if (Arg.isInvalid())
return ExprError();
// Okay, we have something that *can* be converted to the right type. Check
// to see if there is a potentially weird extension going on here. This can
// happen when you do an atomic operation on something like an char* and
// pass in 42. The 42 gets converted to char. This is even more strange
// for things like 45.123 -> char, etc.
// FIXME: Do this check.
TheCall->setArg(i+1, Arg.take());
}
ASTContext& Context = this->getASTContext();
// Create a new DeclRefExpr to refer to the new decl.
DeclRefExpr* NewDRE = DeclRefExpr::Create(
Context,
DRE->getQualifierLoc(),
SourceLocation(),
NewBuiltinDecl,
DRE->getLocation(),
NewBuiltinDecl->getType(),
DRE->getValueKind());
// Set the callee in the CallExpr.
// FIXME: This leaks the original parens and implicit casts.
ExprResult PromotedCall = UsualUnaryConversions(NewDRE);
if (PromotedCall.isInvalid())
return ExprError();
TheCall->setCallee(PromotedCall.take());
// Change the result type of the call to match the original value type. This
// is arbitrary, but the codegen for these builtins ins design to handle it
// gracefully.
TheCall->setType(ResultType);
return move(TheCallResult);
}
/// CheckObjCString - Checks that the argument to the builtin
/// CFString constructor is correct
/// Note: It might also make sense to do the UTF-16 conversion here (would
/// simplify the backend).
bool Sema::CheckObjCString(Expr *Arg) {
Arg = Arg->IgnoreParenCasts();
StringLiteral *Literal = dyn_cast<StringLiteral>(Arg);
if (!Literal || !Literal->isAscii()) {
Diag(Arg->getLocStart(), diag::err_cfstring_literal_not_string_constant)
<< Arg->getSourceRange();
return true;
}
if (Literal->containsNonAsciiOrNull()) {
StringRef String = Literal->getString();
unsigned NumBytes = String.size();
SmallVector<UTF16, 128> ToBuf(NumBytes);
const UTF8 *FromPtr = (UTF8 *)String.data();
UTF16 *ToPtr = &ToBuf[0];
ConversionResult Result = ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes,
&ToPtr, ToPtr + NumBytes,
strictConversion);
// Check for conversion failure.
if (Result != conversionOK)
Diag(Arg->getLocStart(),
diag::warn_cfstring_truncated) << Arg->getSourceRange();
}
return false;
}
/// SemaBuiltinVAStart - Check the arguments to __builtin_va_start for validity.
/// Emit an error and return true on failure, return false on success.
bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
Expr *Fn = TheCall->getCallee();
if (TheCall->getNumArgs() > 2) {
Diag(TheCall->getArg(2)->getLocStart(),
diag::err_typecheck_call_too_many_args)
<< 0 /*function call*/ << 2 << TheCall->getNumArgs()
<< Fn->getSourceRange()
<< SourceRange(TheCall->getArg(2)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
return true;
}
if (TheCall->getNumArgs() < 2) {
return Diag(TheCall->getLocEnd(),
diag::err_typecheck_call_too_few_args_at_least)
<< 0 /*function call*/ << 2 << TheCall->getNumArgs();
}
// Type-check the first argument normally.
if (checkBuiltinArgument(*this, TheCall, 0))
return true;
// Determine whether the current function is variadic or not.
BlockScopeInfo *CurBlock = getCurBlock();
bool isVariadic;
if (CurBlock)
isVariadic = CurBlock->TheDecl->isVariadic();
else if (FunctionDecl *FD = getCurFunctionDecl())
isVariadic = FD->isVariadic();
else
isVariadic = getCurMethodDecl()->isVariadic();
if (!isVariadic) {
Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function);
return true;
}
// Verify that the second argument to the builtin is the last argument of the
// current function or method.
bool SecondArgIsLastNamedArgument = false;
const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts();
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) {
if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) {
// FIXME: This isn't correct for methods (results in bogus warning).
// Get the last formal in the current function.
const ParmVarDecl *LastArg;
if (CurBlock)
LastArg = *(CurBlock->TheDecl->param_end()-1);
else if (FunctionDecl *FD = getCurFunctionDecl())
LastArg = *(FD->param_end()-1);
else
LastArg = *(getCurMethodDecl()->param_end()-1);
SecondArgIsLastNamedArgument = PV == LastArg;
}
}
if (!SecondArgIsLastNamedArgument)
Diag(TheCall->getArg(1)->getLocStart(),
diag::warn_second_parameter_of_va_start_not_last_named_argument);
return false;
}
/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and
/// friends. This is declared to take (...), so we have to check everything.
bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
if (TheCall->getNumArgs() < 2)
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
<< 0 << 2 << TheCall->getNumArgs()/*function call*/;
if (TheCall->getNumArgs() > 2)
return Diag(TheCall->getArg(2)->getLocStart(),
diag::err_typecheck_call_too_many_args)
<< 0 /*function call*/ << 2 << TheCall->getNumArgs()
<< SourceRange(TheCall->getArg(2)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
ExprResult OrigArg0 = TheCall->getArg(0);
ExprResult OrigArg1 = TheCall->getArg(1);
// Do standard promotions between the two arguments, returning their common
// type.
QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false);
if (OrigArg0.isInvalid() || OrigArg1.isInvalid())
return true;
// Make sure any conversions are pushed back into the call; this is
// type safe since unordered compare builtins are declared as "_Bool
// foo(...)".
TheCall->setArg(0, OrigArg0.get());
TheCall->setArg(1, OrigArg1.get());
if (OrigArg0.get()->isTypeDependent() || OrigArg1.get()->isTypeDependent())
return false;
// If the common type isn't a real floating type, then the arguments were
// invalid for this operation.
if (!Res->isRealFloatingType())
return Diag(OrigArg0.get()->getLocStart(),
diag::err_typecheck_call_invalid_ordered_compare)
<< OrigArg0.get()->getType() << OrigArg1.get()->getType()
<< SourceRange(OrigArg0.get()->getLocStart(), OrigArg1.get()->getLocEnd());
return false;
}
/// SemaBuiltinSemaBuiltinFPClassification - Handle functions like
/// __builtin_isnan and friends. This is declared to take (...), so we have
/// to check everything. We expect the last argument to be a floating point
/// value.
bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
if (TheCall->getNumArgs() < NumArgs)
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
<< 0 << NumArgs << TheCall->getNumArgs()/*function call*/;
if (TheCall->getNumArgs() > NumArgs)
return Diag(TheCall->getArg(NumArgs)->getLocStart(),
diag::err_typecheck_call_too_many_args)
<< 0 /*function call*/ << NumArgs << TheCall->getNumArgs()
<< SourceRange(TheCall->getArg(NumArgs)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
Expr *OrigArg = TheCall->getArg(NumArgs-1);
if (OrigArg->isTypeDependent())
return false;
// This operation requires a non-_Complex floating-point number.
if (!OrigArg->getType()->isRealFloatingType())
return Diag(OrigArg->getLocStart(),
diag::err_typecheck_call_invalid_unary_fp)
<< OrigArg->getType() << OrigArg->getSourceRange();
// If this is an implicit conversion from float -> double, remove it.
if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) {
Expr *CastArg = Cast->getSubExpr();
if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) {
assert(Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) &&
"promotion from float to double is the only expected cast here");
Cast->setSubExpr(0);
TheCall->setArg(NumArgs-1, CastArg);
OrigArg = CastArg;
}
}
return false;
}
/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector.
// This is declared to take (...), so we have to check everything.
ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
if (TheCall->getNumArgs() < 2)
return ExprError(Diag(TheCall->getLocEnd(),
diag::err_typecheck_call_too_few_args_at_least)
<< 0 /*function call*/ << 2 << TheCall->getNumArgs()
<< TheCall->getSourceRange());
// Determine which of the following types of shufflevector we're checking:
// 1) unary, vector mask: (lhs, mask)
// 2) binary, vector mask: (lhs, rhs, mask)
// 3) binary, scalar mask: (lhs, rhs, index, ..., index)
QualType resType = TheCall->getArg(0)->getType();
unsigned numElements = 0;
if (!TheCall->getArg(0)->isTypeDependent() &&
!TheCall->getArg(1)->isTypeDependent()) {
QualType LHSType = TheCall->getArg(0)->getType();
QualType RHSType = TheCall->getArg(1)->getType();
if (!LHSType->isVectorType() || !RHSType->isVectorType()) {
Diag(TheCall->getLocStart(), diag::err_shufflevector_non_vector)
<< SourceRange(TheCall->getArg(0)->getLocStart(),
TheCall->getArg(1)->getLocEnd());
return ExprError();
}
numElements = LHSType->getAs<VectorType>()->getNumElements();
unsigned numResElements = TheCall->getNumArgs() - 2;
// Check to see if we have a call with 2 vector arguments, the unary shuffle
// with mask. If so, verify that RHS is an integer vector type with the
// same number of elts as lhs.
if (TheCall->getNumArgs() == 2) {
if (!RHSType->hasIntegerRepresentation() ||
RHSType->getAs<VectorType>()->getNumElements() != numElements)
Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector)
<< SourceRange(TheCall->getArg(1)->getLocStart(),
TheCall->getArg(1)->getLocEnd());
numResElements = numElements;
}
else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) {
Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector)
<< SourceRange(TheCall->getArg(0)->getLocStart(),
TheCall->getArg(1)->getLocEnd());
return ExprError();
} else if (numElements != numResElements) {
QualType eltType = LHSType->getAs<VectorType>()->getElementType();
resType = Context.getVectorType(eltType, numResElements,
VectorType::GenericVector);
}
}
for (unsigned i = 2; i < TheCall->getNumArgs(); i++) {
if (TheCall->getArg(i)->isTypeDependent() ||
TheCall->getArg(i)->isValueDependent())
continue;
llvm::APSInt Result(32);
if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context))
return ExprError(Diag(TheCall->getLocStart(),
diag::err_shufflevector_nonconstant_argument)
<< TheCall->getArg(i)->getSourceRange());
if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2)
return ExprError(Diag(TheCall->getLocStart(),
diag::err_shufflevector_argument_too_large)
<< TheCall->getArg(i)->getSourceRange());
}
SmallVector<Expr*, 32> exprs;
for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; i++) {
exprs.push_back(TheCall->getArg(i));
TheCall->setArg(i, 0);
}
return Owned(new (Context) ShuffleVectorExpr(Context, exprs.begin(),
exprs.size(), resType,
TheCall->getCallee()->getLocStart(),
TheCall->getRParenLoc()));
}
/// SemaBuiltinPrefetch - Handle __builtin_prefetch.
// This is declared to take (const void*, ...) and can take two
// optional constant int args.
bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
unsigned NumArgs = TheCall->getNumArgs();
if (NumArgs > 3)
return Diag(TheCall->getLocEnd(),
diag::err_typecheck_call_too_many_args_at_most)
<< 0 /*function call*/ << 3 << NumArgs
<< TheCall->getSourceRange();
// Argument 0 is checked for us and the remaining arguments must be
// constant integers.
for (unsigned i = 1; i != NumArgs; ++i) {
Expr *Arg = TheCall->getArg(i);
llvm::APSInt Result;
if (SemaBuiltinConstantArg(TheCall, i, Result))
return true;
// FIXME: gcc issues a warning and rewrites these to 0. These
// seems especially odd for the third argument since the default
// is 3.
if (i == 1) {
if (Result.getLimitedValue() > 1)
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
<< "0" << "1" << Arg->getSourceRange();
} else {
if (Result.getLimitedValue() > 3)
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
<< "0" << "3" << Arg->getSourceRange();
}
}
return false;
}
/// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr
/// TheCall is a constant expression.
bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
llvm::APSInt &Result) {
Expr *Arg = TheCall->getArg(ArgNum);
DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
if (Arg->isTypeDependent() || Arg->isValueDependent()) return false;
if (!Arg->isIntegerConstantExpr(Result, Context))
return Diag(TheCall->getLocStart(), diag::err_constant_integer_arg_type)
<< FDecl->getDeclName() << Arg->getSourceRange();
return false;
}
/// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr,
/// int type). This simply type checks that type is one of the defined
/// constants (0-3).
// For compatibility check 0-3, llvm only handles 0 and 2.
bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
llvm::APSInt Result;
// Check constant-ness first.
if (SemaBuiltinConstantArg(TheCall, 1, Result))
return true;
Expr *Arg = TheCall->getArg(1);
if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) {
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
<< "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
}
return false;
}
/// SemaBuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val).
/// This checks that val is a constant 1.
bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
Expr *Arg = TheCall->getArg(1);
llvm::APSInt Result;
// TODO: This is less than ideal. Overload this to take a value.
if (SemaBuiltinConstantArg(TheCall, 1, Result))
return true;
if (Result != 1)
return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_invalid_val)
<< SourceRange(Arg->getLocStart(), Arg->getLocEnd());
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) {
tryAgain:
if (E->isTypeDependent() || E->isValueDependent())
return false;
E = E->IgnoreParenCasts();
if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
// Technically -Wformat-nonliteral does not warn about this case.
// 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;
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);
}
case Stmt::ImplicitCastExprClass: {
E = cast<ImplicitCastExpr>(E)->getSubExpr();
goto tryAgain;
}
case Stmt::OpaqueValueExprClass:
if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) {
E = src;
goto tryAgain;
}
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 true;
case Stmt::DeclRefExprClass: {
const DeclRefExpr *DR = cast<DeclRefExpr>(E);
// As an exception, do not flag errors for variables binding to
// const string literals.
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
bool isConstant = false;
QualType T = DR->getType();
if (const ArrayType *AT = Context.getAsArrayType(T)) {
isConstant = AT->getElementType().isConstant(Context);
} else if (const PointerType *PT = T->getAs<PointerType>()) {
isConstant = T.isConstant(Context) &&
PT->getPointeeType().isConstant(Context);
} else if (T->isObjCObjectPointerType()) {
// In ObjC, there is usually no "const ObjectPointer" type,
// so don't check if the pointee type is constant.
isConstant = T.isConstant(Context);
}
if (isConstant) {
if (const Expr *Init = VD->getAnyInitializer())
return SemaCheckStringLiteral(Init, Args, NumArgs,
HasVAListArg, format_idx, firstDataArg,
Type, /*inFunctionCall*/false);
}
// For vprintf* functions (i.e., HasVAListArg==true), we add a
// special check to see if the format string is a function parameter
// of the function calling the printf function. If the function
// has an attribute indicating it is a printf-like function, then we
// should suppress warnings concerning non-literals being used in a call
// to a vprintf function. For example:
//
// void
// logmessage(char const *fmt __attribute__ (format (printf, 1, 2)), ...){
// va_list ap;
// va_start(ap, fmt);
// vprintf(fmt, ap); // Do NOT emit a warning about "fmt".
// ...
//
//
// FIXME: We don't have full attribute support yet, so just check to see
// if the argument is a DeclRefExpr that references a parameter. We'll
// add proper support for checking the attribute later.
if (HasVAListArg)
if (isa<ParmVarDecl>(VD))
return true;
}
return false;
}
case Stmt::CallExprClass:
case Stmt::CXXMemberCallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) {
unsigned ArgIndex = FA->getFormatIdx();
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
if (MD->isInstance())
--ArgIndex;
const Expr *Arg = CE->getArg(ArgIndex - 1);
return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg,
format_idx, firstDataArg, Type,
inFunctionCall);
}
}
return false;
}
case Stmt::ObjCStringLiteralClass:
case Stmt::StringLiteralClass: {
const StringLiteral *StrE = NULL;
if (const ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E))
StrE = ObjCFExpr->getString();
else
StrE = cast<StringLiteral>(E);
if (StrE) {
CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx,
firstDataArg, Type, inFunctionCall);
return true;
}
return false;
}
default:
return false;
}
}
void
Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
const Expr * const *ExprArgs,
SourceLocation CallSiteLoc) {
for (NonNullAttr::args_iterator i = NonNull->args_begin(),
e = NonNull->args_end();
i != e; ++i) {
const Expr *ArgExpr = ExprArgs[*i];
if (ArgExpr->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNotNull))
Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange();
}
}
Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
return llvm::StringSwitch<FormatStringType>(Format->getType())
.Case("scanf", FST_Scanf)
.Cases("printf", "printf0", FST_Printf)
.Cases("NSString", "CFString", FST_NSString)
.Case("strftime", FST_Strftime)
.Case("strfmon", FST_Strfmon)
.Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", FST_Kprintf)
.Default(FST_Unknown);
}
/// 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());
}
void 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);
}
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;
}
const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts();
// CHECK: format string is not a string literal.
//
// Dynamically generated format strings are difficult to
// automatically vet at compile time. Requiring that format strings
// are string literals: (1) permits the checking of format strings by
// the compiler and thereby (2) can practically remove the source of
// many format string exploits.
// Format string can be either ObjC string (e.g. @"%d") or
// 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!
// 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;
// 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
// diag when using the NSLocalizedString and CFCopyLocalizedString macros
// which are usually used in place of NS and CF string literals.
if (Type == FST_NSString && Args[format_idx]->getLocStart().isMacroID())
return;
// If there are no arguments specified, warn with -Wformat-security, otherwise
// warn only with -Wformat-nonliteral.
if (NumArgs == format_idx+1)
Diag(Args[format_idx]->getLocStart(),
diag::warn_format_nonliteral_noargs)
<< OrigFormatExpr->getSourceRange();
else
Diag(Args[format_idx]->getLocStart(),
diag::warn_format_nonliteral)
<< OrigFormatExpr->getSourceRange();
}
namespace {
class CheckFormatHandler : public analyze_format_string::FormatStringHandler {
protected:
Sema &S;
const StringLiteral *FExpr;
const Expr *OrigFormatExpr;
const unsigned FirstDataArg;
const unsigned NumDataArgs;
const bool IsObjCLiteral;
const char *Beg; // Start of format string.
const bool HasVAListArg;
const Expr * const *Args;
const unsigned NumArgs;
unsigned FormatIdx;
llvm::BitVector CoveredArgs;
bool usesPositionalArgs;
bool atFirstArg;
bool inFunctionCall;
public:
CheckFormatHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjCLiteral,
const char *beg, bool hasVAListArg,
Expr **args, unsigned numArgs,
unsigned formatIdx, bool inFunctionCall)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
FirstDataArg(firstDataArg),
NumDataArgs(numDataArgs),
IsObjCLiteral(isObjCLiteral), Beg(beg),
HasVAListArg(hasVAListArg),
Args(args), NumArgs(numArgs), FormatIdx(formatIdx),
usesPositionalArgs(false), atFirstArg(true),
inFunctionCall(inFunctionCall) {
CoveredArgs.resize(numDataArgs);
CoveredArgs.reset();
}
void DoneProcessing();
void HandleIncompleteSpecifier(const char *startSpecifier,
unsigned specifierLen);
virtual void HandleInvalidPosition(const char *startSpecifier,
unsigned specifierLen,
analyze_format_string::PositionContext p);
virtual void HandleZeroPosition(const char *startPos, unsigned posLen);
void HandleNullChar(const char *nullCharacter);
template <typename Range>
static void EmitFormatDiagnostic(Sema &S, bool inFunctionCall,
const Expr *ArgumentExpr,
PartialDiagnostic PDiag,
SourceLocation StringLoc,
bool IsStringLocation, Range StringRange,
FixItHint Fixit = FixItHint());
protected:
bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc,
const char *startSpec,
unsigned specifierLen,
const char *csStart, unsigned csLen);
void HandlePositionalNonpositionalArgs(SourceLocation Loc,
const char *startSpec,
unsigned specifierLen);
SourceRange getFormatStringRange();
CharSourceRange getSpecifierRange(const char *startSpecifier,
unsigned specifierLen);
SourceLocation getLocationOfByte(const char *x);
const Expr *getDataArg(unsigned i) const;
bool CheckNumArgs(const analyze_format_string::FormatSpecifier &FS,
const analyze_format_string::ConversionSpecifier &CS,
const char *startSpecifier, unsigned specifierLen,
unsigned argIndex);
template <typename Range>
void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc,
bool IsStringLocation, Range StringRange,
FixItHint Fixit = FixItHint());
void CheckPositionalAndNonpositionalArgs(
const analyze_format_string::FormatSpecifier *FS);
};
}
SourceRange CheckFormatHandler::getFormatStringRange() {
return OrigFormatExpr->getSourceRange();
}
CharSourceRange CheckFormatHandler::
getSpecifierRange(const char *startSpecifier, unsigned specifierLen) {
SourceLocation Start = getLocationOfByte(startSpecifier);
SourceLocation End = getLocationOfByte(startSpecifier + specifierLen - 1);
// Advance the end SourceLocation by one due to half-open ranges.
End = End.getLocWithOffset(1);
return CharSourceRange::getCharRange(Start, End);
}
SourceLocation CheckFormatHandler::getLocationOfByte(const char *x) {
return S.getLocationOfStringLiteralByte(FExpr, x - Beg);
}
void CheckFormatHandler::HandleIncompleteSpecifier(const char *startSpecifier,
unsigned specifierLen){
EmitFormatDiagnostic(S.PDiag(diag::warn_printf_incomplete_specifier),
getLocationOfByte(startSpecifier),
/*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen));
}
void
CheckFormatHandler::HandleInvalidPosition(const char *startPos, unsigned posLen,
analyze_format_string::PositionContext p) {
EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_positional_specifier)
<< (unsigned) p,
getLocationOfByte(startPos), /*IsStringLocation*/true,
getSpecifierRange(startPos, posLen));
}
void CheckFormatHandler::HandleZeroPosition(const char *startPos,
unsigned posLen) {
EmitFormatDiagnostic(S.PDiag(diag::warn_format_zero_positional_specifier),
getLocationOfByte(startPos),
/*IsStringLocation*/true,
getSpecifierRange(startPos, posLen));
}
void CheckFormatHandler::HandleNullChar(const char *nullCharacter) {
if (!IsObjCLiteral) {
// The presence of a null character is likely an error.
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_format_string_contains_null_char),
getLocationOfByte(nullCharacter), /*IsStringLocation*/true,
getFormatStringRange());
}
}
const Expr *CheckFormatHandler::getDataArg(unsigned i) const {
return Args[FirstDataArg + i];
}
void CheckFormatHandler::DoneProcessing() {
// Does the number of data arguments exceed the number of
// format conversions in the format string?
if (!HasVAListArg) {
// Find any arguments that weren't covered.
CoveredArgs.flip();
signed notCoveredArg = CoveredArgs.find_first();
if (notCoveredArg >= 0) {
assert((unsigned)notCoveredArg < NumDataArgs);
EmitFormatDiagnostic(S.PDiag(diag::warn_printf_data_arg_not_used),
getDataArg((unsigned) notCoveredArg)->getLocStart(),
/*IsStringLocation*/false, getFormatStringRange());
}
}
}
bool
CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex,
SourceLocation Loc,
const char *startSpec,
unsigned specifierLen,
const char *csStart,
unsigned csLen) {
bool keepGoing = true;
if (argIndex < NumDataArgs) {
// Consider the argument coverered, even though the specifier doesn't
// make sense.
CoveredArgs.set(argIndex);
}
else {
// If argIndex exceeds the number of data arguments we
// don't issue a warning because that is just a cascade of warnings (and
// they may have intended '%%' anyway). We don't want to continue processing
// the format string after this point, however, as we will like just get
// gibberish when trying to match arguments.
keepGoing = false;
}
EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_conversion)
<< StringRef(csStart, csLen),
Loc, /*IsStringLocation*/true,
getSpecifierRange(startSpec, specifierLen));
return keepGoing;
}
void
CheckFormatHandler::HandlePositionalNonpositionalArgs(SourceLocation Loc,
const char *startSpec,
unsigned specifierLen) {
EmitFormatDiagnostic(
S.PDiag(diag::warn_format_mix_positional_nonpositional_args),
Loc, /*isStringLoc*/true, getSpecifierRange(startSpec, specifierLen));
}
bool
CheckFormatHandler::CheckNumArgs(
const analyze_format_string::FormatSpecifier &FS,
const analyze_format_string::ConversionSpecifier &CS,
const char *startSpecifier, unsigned specifierLen, unsigned argIndex) {
if (argIndex >= NumDataArgs) {
PartialDiagnostic PDiag = FS.usesPositionalArg()
? (S.PDiag(diag::warn_printf_positional_arg_exceeds_data_args)
<< (argIndex+1) << NumDataArgs)
: S.PDiag(diag::warn_printf_insufficient_data_args);
EmitFormatDiagnostic(
PDiag, getLocationOfByte(CS.getStart()), /*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen));
return false;
}
return true;
}
template<typename Range>
void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag,
SourceLocation Loc,
bool IsStringLocation,
Range StringRange,
FixItHint FixIt) {
EmitFormatDiagnostic(S, inFunctionCall, Args[FormatIdx], PDiag,
Loc, IsStringLocation, StringRange, FixIt);
}
/// \brief If the format string is not within the funcion call, emit a note
/// so that the function call and string are in diagnostic messages.
///
/// \param inFunctionCall if true, the format string is within the function
/// call and only one diagnostic message will be produced. Otherwise, an
/// extra note will be emitted pointing to location of the format string.
///
/// \param ArgumentExpr the expression that is passed as the format string
/// argument in the function call. Used for getting locations when two
/// diagnostics are emitted.
///
/// \param PDiag the callee should already have provided any strings for the
/// diagnostic message. This function only adds locations and fixits
/// to diagnostics.
///
/// \param Loc primary location for diagnostic. If two diagnostics are
/// required, one will be at Loc and a new SourceLocation will be created for
/// the other one.
///
/// \param IsStringLocation if true, Loc points to the format string should be
/// used for the note. Otherwise, Loc points to the argument list and will
/// be used with PDiag.
///
/// \param StringRange some or all of the string to highlight. This is
/// templated so it can accept either a CharSourceRange or a SourceRange.
///
/// \param Fixit optional fix it hint for the format string.
template<typename Range>
void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall,
const Expr *ArgumentExpr,
PartialDiagnostic PDiag,
SourceLocation Loc,
bool IsStringLocation,
Range StringRange,
FixItHint FixIt) {
if (InFunctionCall)
S.Diag(Loc, PDiag) << StringRange << FixIt;
else {
S.Diag(IsStringLocation ? ArgumentExpr->getExprLoc() : Loc, PDiag)
<< ArgumentExpr->getSourceRange();
S.Diag(IsStringLocation ? Loc : StringRange.getBegin(),
diag::note_format_string_defined)
<< StringRange << FixIt;
}
}
//===--- CHECK: Printf format string checking ------------------------------===//
namespace {
class CheckPrintfHandler : public CheckFormatHandler {
public:
CheckPrintfHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjCLiteral,
const char *beg, bool hasVAListArg,
Expr **Args, unsigned NumArgs,
unsigned formatIdx, bool inFunctionCall)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, isObjCLiteral, beg, hasVAListArg,
Args, NumArgs, formatIdx, inFunctionCall) {}
bool HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen);
bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen);
bool HandleAmount(const analyze_format_string::OptionalAmount &Amt, unsigned k,
const char *startSpecifier, unsigned specifierLen);
void HandleInvalidAmount(const analyze_printf::PrintfSpecifier &FS,
const analyze_printf::OptionalAmount &Amt,
unsigned type,
const char *startSpecifier, unsigned specifierLen);
void HandleFlag(const analyze_printf::PrintfSpecifier &FS,
const analyze_printf::OptionalFlag &flag,
const char *startSpecifier, unsigned specifierLen);
void HandleIgnoredFlag(const analyze_printf::PrintfSpecifier &FS,
const analyze_printf::OptionalFlag &ignoredFlag,
const analyze_printf::OptionalFlag &flag,
const char *startSpecifier, unsigned specifierLen);
};
}
bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen) {
const analyze_printf::PrintfConversionSpecifier &CS =
FS.getConversionSpecifier();
return HandleInvalidConversionSpecifier(FS.getArgIndex(),
getLocationOfByte(CS.getStart()),
startSpecifier, specifierLen,
CS.getStart(), CS.getLength());
}
bool CheckPrintfHandler::HandleAmount(
const analyze_format_string::OptionalAmount &Amt,
unsigned k, const char *startSpecifier,
unsigned specifierLen) {
if (Amt.hasDataArgument()) {
if (!HasVAListArg) {
unsigned argIndex = Amt.getArgIndex();
if (argIndex >= NumDataArgs) {
EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_missing_arg)
<< k,
getLocationOfByte(Amt.getStart()),
/*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen));
// Don't do any more checking. We will just emit
// spurious errors.
return false;
}
// Type check the data argument. It should be an 'int'.
// Although not in conformance with C99, we also allow the argument to be
// an 'unsigned int' as that is a reasonably safe case. GCC also
// doesn't emit a warning for that case.
CoveredArgs.set(argIndex);
const Expr *Arg = getDataArg(argIndex);
QualType T = Arg->getType();
const analyze_printf::ArgTypeResult &ATR = Amt.getArgType(S.Context);
assert(ATR.isValid());
if (!ATR.matchesType(S.Context, T)) {
EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_wrong_type)
<< k << ATR.getRepresentativeTypeName(S.Context)
<< T << Arg->getSourceRange(),
getLocationOfByte(Amt.getStart()),
/*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen));
// Don't do any more checking. We will just emit
// spurious errors.
return false;
}
}
}
return true;
}
void CheckPrintfHandler::HandleInvalidAmount(
const analyze_printf::PrintfSpecifier &FS,
const analyze_printf::OptionalAmount &Amt,
unsigned type,
const char *startSpecifier,
unsigned specifierLen) {
const analyze_printf::PrintfConversionSpecifier &CS =
FS.getConversionSpecifier();
FixItHint fixit =
Amt.getHowSpecified() == analyze_printf::OptionalAmount::Constant
? FixItHint::CreateRemoval(getSpecifierRange(Amt.getStart(),
Amt.getConstantLength()))
: FixItHint();
EmitFormatDiagnostic(S.PDiag(diag::warn_printf_nonsensical_optional_amount)
<< type << CS.toString(),
getLocationOfByte(Amt.getStart()),
/*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen),
fixit);
}
void CheckPrintfHandler::HandleFlag(const analyze_printf::PrintfSpecifier &FS,
const analyze_printf::OptionalFlag &flag,
const char *startSpecifier,
unsigned specifierLen) {
// Warn about pointless flag with a fixit removal.
const analyze_printf::PrintfConversionSpecifier &CS =
FS.getConversionSpecifier();
EmitFormatDiagnostic(S.PDiag(diag::warn_printf_nonsensical_flag)
<< flag.toString() << CS.toString(),
getLocationOfByte(flag.getPosition()),
/*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen),
FixItHint::CreateRemoval(
getSpecifierRange(flag.getPosition(), 1)));
}
void CheckPrintfHandler::HandleIgnoredFlag(
const analyze_printf::PrintfSpecifier &FS,
const analyze_printf::OptionalFlag &ignoredFlag,
const analyze_printf::OptionalFlag &flag,
const char *startSpecifier,
unsigned specifierLen) {
// Warn about ignored flag with a fixit removal.
EmitFormatDiagnostic(S.PDiag(diag::warn_printf_ignored_flag)
<< ignoredFlag.toString() << flag.toString(),
getLocationOfByte(ignoredFlag.getPosition()),
/*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen),
FixItHint::CreateRemoval(
getSpecifierRange(ignoredFlag.getPosition(), 1)));
}
bool
CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
&FS,
const char *startSpecifier,
unsigned specifierLen) {
using namespace analyze_format_string;
using namespace analyze_printf;
const PrintfConversionSpecifier &CS = FS.getConversionSpecifier();
if (FS.consumesDataArgument()) {
if (atFirstArg) {
atFirstArg = false;
usesPositionalArgs = FS.usesPositionalArg();
}
else if (usesPositionalArgs != FS.usesPositionalArg()) {
HandlePositionalNonpositionalArgs(getLocationOfByte(CS.getStart()),
startSpecifier, specifierLen);
return false;
}
}
// First check if the field width, precision, and conversion specifier
// have matching data arguments.
if (!HandleAmount(FS.getFieldWidth(), /* field width */ 0,
startSpecifier, specifierLen)) {
return false;
}
if (!HandleAmount(FS.getPrecision(), /* precision */ 1,
startSpecifier, specifierLen)) {
return false;
}
if (!CS.consumesDataArgument()) {
// FIXME: Technically specifying a precision or field width here
// makes no sense. Worth issuing a warning at some point.
return true;
}
// Consume the argument.
unsigned argIndex = FS.getArgIndex();
if (argIndex < NumDataArgs) {
// The check to see if the argIndex is valid will come later.
// We set the bit here because we may exit early from this
// function if we encounter some other error.
CoveredArgs.set(argIndex);
}
// Check for using an Objective-C specific conversion specifier
// in a non-ObjC literal.
if (!IsObjCLiteral && CS.isObjCArg()) {
return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier,
specifierLen);
}
// Check for invalid use of field width
if (!FS.hasValidFieldWidth()) {
HandleInvalidAmount(FS, FS.getFieldWidth(), /* field width */ 0,
startSpecifier, specifierLen);
}
// Check for invalid use of precision
if (!FS.hasValidPrecision()) {
HandleInvalidAmount(FS, FS.getPrecision(), /* precision */ 1,
startSpecifier, specifierLen);
}
// Check each flag does not conflict with any other component.
if (!FS.hasValidThousandsGroupingPrefix())
HandleFlag(FS, FS.hasThousandsGrouping(), startSpecifier, specifierLen);
if (!FS.hasValidLeadingZeros())
HandleFlag(FS, FS.hasLeadingZeros(), startSpecifier, specifierLen);
if (!FS.hasValidPlusPrefix())
HandleFlag(FS, FS.hasPlusPrefix(), startSpecifier, specifierLen);
if (!FS.hasValidSpacePrefix())
HandleFlag(FS, FS.hasSpacePrefix(), startSpecifier, specifierLen);
if (!FS.hasValidAlternativeForm())
HandleFlag(FS, FS.hasAlternativeForm(), startSpecifier, specifierLen);
if (!FS.hasValidLeftJustified())
HandleFlag(FS, FS.isLeftJustified(), startSpecifier, specifierLen);
// Check that flags are not ignored by another flag
if (FS.hasSpacePrefix() && FS.hasPlusPrefix()) // ' ' ignored by '+'
HandleIgnoredFlag(FS, FS.hasSpacePrefix(), FS.hasPlusPrefix(),
startSpecifier, specifierLen);
if (FS.hasLeadingZeros() && FS.isLeftJustified()) // '0' ignored by '-'
HandleIgnoredFlag(FS, FS.hasLeadingZeros(), FS.isLeftJustified(),
startSpecifier, specifierLen);
// Check the length modifier is valid with the given conversion specifier.
const LengthModifier &LM = FS.getLengthModifier();
if (!FS.hasValidLengthModifier())
EmitFormatDiagnostic(S.PDiag(diag::warn_format_nonsensical_length)
<< LM.toString() << CS.toString(),
getLocationOfByte(LM.getStart()),
/*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen),
FixItHint::CreateRemoval(
getSpecifierRange(LM.getStart(),
LM.getLength())));
// Are we using '%n'?
if (CS.getKind() == ConversionSpecifier::nArg) {
// Issue a warning about this being a possible security issue.
EmitFormatDiagnostic(S.PDiag(diag::warn_printf_write_back),
getLocationOfByte(CS.getStart()),
/*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen));
// Continue checking the other format specifiers.
return true;
}
// The remaining checks depend on the data arguments.
if (HasVAListArg)
return true;
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
return false;
// 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,
IsObjCLiteral);
if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
// 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
// function.
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex))
if (ICE->getType() == S.Context.IntTy) {
// All further checking is done on the subexpression.
Ex = ICE->getSubExpr();
if (ATR.matchesType(S.Context, Ex->getType()))
return true;
}
// We may be able to offer a FixItHint if it is a supported type.
PrintfSpecifier fixedFS = FS;
bool success = fixedFS.fixType(Ex->getType(), S.getLangOptions());
if (success) {
// Get the fix string from the fixed format specifier
SmallString<128> buf;
llvm::raw_svector_ostream os(buf);
fixedFS.toString(os);
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
<< ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
<< Ex->getSourceRange(),
getLocationOfByte(CS.getStart()),
/*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen),
FixItHint::CreateReplacement(
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(),
getLocationOfByte(CS.getStart()),
true,
getSpecifierRange(startSpecifier, specifierLen));
}
}
return true;
}
//===--- CHECK: Scanf format string checking ------------------------------===//
namespace {
class CheckScanfHandler : public CheckFormatHandler {
public:
CheckScanfHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjCLiteral,
const char *beg, bool hasVAListArg,
Expr **Args, unsigned NumArgs,
unsigned formatIdx, bool inFunctionCall)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, isObjCLiteral, beg, hasVAListArg,
Args, NumArgs, formatIdx, inFunctionCall) {}
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen);
bool HandleInvalidScanfConversionSpecifier(
const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen);
void HandleIncompleteScanList(const char *start, const char *end);
};
}
void CheckScanfHandler::HandleIncompleteScanList(const char *start,
const char *end) {
EmitFormatDiagnostic(S.PDiag(diag::warn_scanf_scanlist_incomplete),
getLocationOfByte(end), /*IsStringLocation*/true,
getSpecifierRange(start, end - start));
}
bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier(
const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen) {
const analyze_scanf::ScanfConversionSpecifier &CS =
FS.getConversionSpecifier();
return HandleInvalidConversionSpecifier(FS.getArgIndex(),
getLocationOfByte(CS.getStart()),
startSpecifier, specifierLen,
CS.getStart(), CS.getLength());
}
bool CheckScanfHandler::HandleScanfSpecifier(
const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen) {
using namespace analyze_scanf;
using namespace analyze_format_string;
const ScanfConversionSpecifier &CS = FS.getConversionSpecifier();
// Handle case where '%' and '*' don't consume an argument. These shouldn't
// be used to decide if we are using positional arguments consistently.
if (FS.consumesDataArgument()) {
if (atFirstArg) {
atFirstArg = false;
usesPositionalArgs = FS.usesPositionalArg();
}
else if (usesPositionalArgs != FS.usesPositionalArg()) {
HandlePositionalNonpositionalArgs(getLocationOfByte(CS.getStart()),
startSpecifier, specifierLen);
return false;
}
}
// Check if the field with is non-zero.
const OptionalAmount &Amt = FS.getFieldWidth();
if (Amt.getHowSpecified() == OptionalAmount::Constant) {
if (Amt.getConstantAmount() == 0) {
const CharSourceRange &R = getSpecifierRange(Amt.getStart(),
Amt.getConstantLength());
EmitFormatDiagnostic(S.PDiag(diag::warn_scanf_nonzero_width),
getLocationOfByte(Amt.getStart()),
/*IsStringLocation*/true, R,
FixItHint::CreateRemoval(R));
}
}
if (!FS.consumesDataArgument()) {
// FIXME: Technically specifying a precision or field width here
// makes no sense. Worth issuing a warning at some point.
return true;
}
// Consume the argument.
unsigned argIndex = FS.getArgIndex();
if (argIndex < NumDataArgs) {
// The check to see if the argIndex is valid will come later.
// We set the bit here because we may exit early from this
// function if we encounter some other error.
CoveredArgs.set(argIndex);
}
// Check the length modifier is valid with the given conversion specifier.
const LengthModifier &LM = FS.getLengthModifier();
if (!FS.hasValidLengthModifier()) {
const CharSourceRange &R = getSpecifierRange(LM.getStart(), LM.getLength());
EmitFormatDiagnostic(S.PDiag(diag::warn_format_nonsensical_length)
<< LM.toString() << CS.toString()
<< getSpecifierRange(startSpecifier, specifierLen),
getLocationOfByte(LM.getStart()),
/*IsStringLocation*/true, R,
FixItHint::CreateRemoval(R));
}
// The remaining checks depend on the data arguments.
if (HasVAListArg)
return true;
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
return false;
// Check that the argument type matches the format specifier.
const Expr *Ex = getDataArg(argIndex);
const analyze_scanf::ScanfArgTypeResult &ATR = FS.getArgType(S.Context);
if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
ScanfSpecifier fixedFS = FS;
bool success = fixedFS.fixType(Ex->getType(), S.getLangOptions());
if (success) {
// Get the fix string from the fixed format specifier.
SmallString<128> buf;
llvm::raw_svector_ostream os(buf);
fixedFS.toString(os);
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
<< ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
<< Ex->getSourceRange(),
getLocationOfByte(CS.getStart()),
/*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen),
FixItHint::CreateReplacement(
getSpecifierRange(startSpecifier, specifierLen),
os.str()));
} else {
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
<< ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
<< Ex->getSourceRange(),
getLocationOfByte(CS.getStart()),
/*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen));
}
}
return true;
}
void Sema::CheckFormatString(const StringLiteral *FExpr,
const Expr *OrigFormatExpr,
Expr **Args, unsigned NumArgs,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
bool inFunctionCall) {
// CHECK: is the format string a wide literal?
if (!FExpr->isAscii()) {
CheckFormatHandler::EmitFormatDiagnostic(
*this, inFunctionCall, Args[format_idx],
PDiag(diag::warn_format_string_is_wide_literal), FExpr->getLocStart(),
/*IsStringLocation*/true, OrigFormatExpr->getSourceRange());
return;
}
// Str - The format string. NOTE: this is NOT null-terminated!
StringRef StrRef = FExpr->getString();
const char *Str = StrRef.data();
unsigned StrLen = StrRef.size();
const unsigned numDataArgs = NumArgs - firstDataArg;
// CHECK: empty format string?
if (StrLen == 0 && numDataArgs > 0) {
CheckFormatHandler::EmitFormatDiagnostic(
*this, inFunctionCall, Args[format_idx],
PDiag(diag::warn_empty_format_string), FExpr->getLocStart(),
/*IsStringLocation*/true, OrigFormatExpr->getSourceRange());
return;
}
if (Type == FST_Printf || Type == FST_NSString) {
CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr),
Str, HasVAListArg, Args, NumArgs, format_idx,
inFunctionCall);
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
getLangOptions()))
H.DoneProcessing();
} else if (Type == FST_Scanf) {
CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr),
Str, HasVAListArg, Args, NumArgs, format_idx,
inFunctionCall);
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
getLangOptions()))
H.DoneProcessing();
} // TODO: handle other formats
}
//===--- CHECK: Standard memory functions ---------------------------------===//
/// \brief Determine whether the given type is a dynamic class type (e.g.,
/// whether it has a vtable).
static bool isDynamicClassType(QualType T) {
if (CXXRecordDecl *Record = T->getAsCXXRecordDecl())
if (CXXRecordDecl *Definition = Record->getDefinition())
if (Definition->isDynamicClass())