summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp1363
1 files changed, 1047 insertions, 316 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
index fdc2349..1e75f59 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
@@ -16,12 +16,14 @@
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
@@ -66,16 +68,31 @@ static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) {
<< 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);
+/// Check that the first argument to __builtin_annotation is an integer
+/// and the second argument is a non-wide string literal.
+static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) {
+ if (checkArgCount(S, TheCall, 2))
+ return true;
+
+ // First argument should be an integer.
+ Expr *ValArg = TheCall->getArg(0);
+ QualType Ty = ValArg->getType();
+ if (!Ty->isIntegerType()) {
+ S.Diag(ValArg->getLocStart(), diag::err_builtin_annotation_first_arg)
+ << ValArg->getSourceRange();
+ return true;
+ }
+
+ // Second argument should be a constant string.
+ Expr *StrArg = TheCall->getArg(1)->IgnoreParenCasts();
+ StringLiteral *Literal = dyn_cast<StringLiteral>(StrArg);
if (!Literal || !Literal->isAscii()) {
- S.Diag(Arg->getLocStart(), diag::err_builtin_annotation_not_string_constant)
- << Arg->getSourceRange();
+ S.Diag(StrArg->getLocStart(), diag::err_builtin_annotation_second_arg)
+ << StrArg->getSourceRange();
return true;
}
+
+ TheCall->setType(Ty);
return false;
}
@@ -256,7 +273,7 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::AO##ID);
#include "clang/Basic/Builtins.def"
case Builtin::BI__builtin_annotation:
- if (CheckBuiltinAnnotationString(*this, TheCall->getArg(1)))
+ if (SemaBuiltinAnnotation(*this, TheCall))
return ExprError();
break;
}
@@ -270,6 +287,13 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ if (CheckMipsBuiltinFunctionCall(BuiltinID, TheCall))
+ return ExprError();
+ break;
default:
break;
}
@@ -331,7 +355,7 @@ static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context) {
bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
llvm::APSInt Result;
- unsigned mask = 0;
+ uint64_t mask = 0;
unsigned TV = 0;
int PtrArgNum = -1;
bool HasConstPtr = false;
@@ -349,7 +373,7 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
TV = Result.getLimitedValue(64);
- if ((TV > 63) || (mask & (1 << TV)) == 0)
+ if ((TV > 63) || (mask & (1ULL << TV)) == 0)
return Diag(TheCall->getLocStart(), diag::err_invalid_neon_type_code)
<< TheCall->getArg(ImmArg)->getSourceRange();
}
@@ -388,6 +412,11 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
#undef GET_NEON_IMMEDIATE_CHECK
};
+ // We can't check the value of a dependent argument.
+ if (TheCall->getArg(i)->isTypeDependent() ||
+ TheCall->getArg(i)->isValueDependent())
+ return false;
+
// Check that the immediate argument is actually a constant.
if (SemaBuiltinConstantArg(TheCall, i, Result))
return true;
@@ -402,34 +431,126 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
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();
+bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+ unsigned i = 0, l = 0, u = 0;
+ switch (BuiltinID) {
+ default: return false;
+ case Mips::BI__builtin_mips_wrdsp: i = 1; l = 0; u = 63; break;
+ case Mips::BI__builtin_mips_rddsp: i = 0; l = 0; u = 63; break;
+ };
- // None of the checks below are needed for functions that don't have
- // simple names (e.g., C++ conversion functions).
- if (!FnInfo)
+ // We can't check the value of a dependent argument.
+ if (TheCall->getArg(i)->isTypeDependent() ||
+ TheCall->getArg(i)->isValueDependent())
return false;
+ // Check that the immediate argument is actually a constant.
+ llvm::APSInt Result;
+ if (SemaBuiltinConstantArg(TheCall, i, Result))
+ return true;
+
+ // Range check against the upper/lower values for this instruction.
+ unsigned Val = Result.getZExtValue();
+ if (Val < l || Val > u)
+ return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
+ << l << u << TheCall->getArg(i)->getSourceRange();
+
+ return false;
+}
+
+/// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo
+/// parameter with the FormatAttr's correct format_idx and firstDataArg.
+/// Returns true when the format fits the function and the FormatStringInfo has
+/// been populated.
+bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
+ FormatStringInfo *FSI) {
+ FSI->HasVAListArg = Format->getFirstArg() == 0;
+ FSI->FormatIdx = Format->getFormatIdx() - 1;
+ FSI->FirstDataArg = FSI->HasVAListArg ? 0 : Format->getFirstArg() - 1;
+
+ // The way the format attribute works in GCC, the implicit this argument
+ // of member functions is counted. However, it doesn't appear in our own
+ // lists, so decrement format_idx in that case.
+ if (IsCXXMember) {
+ if(FSI->FormatIdx == 0)
+ return false;
+ --FSI->FormatIdx;
+ if (FSI->FirstDataArg != 0)
+ --FSI->FirstDataArg;
+ }
+ return true;
+}
+
+/// Handles the checks for format strings, non-POD arguments to vararg
+/// functions, and NULL arguments passed to non-NULL parameters.
+void Sema::checkCall(NamedDecl *FDecl, Expr **Args,
+ unsigned NumArgs,
+ unsigned NumProtoArgs,
+ bool IsMemberFunction,
+ SourceLocation Loc,
+ SourceRange Range,
+ VariadicCallType CallType) {
// FIXME: This mechanism should be abstracted to be less fragile and
// more efficient. For example, just map function ids to custom
// handlers.
// Printf and scanf checking.
+ bool HandledFormatString = false;
for (specific_attr_iterator<FormatAttr>
- i = FDecl->specific_attr_begin<FormatAttr>(),
- e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
- CheckFormatArguments(*i, TheCall);
- }
+ I = FDecl->specific_attr_begin<FormatAttr>(),
+ E = FDecl->specific_attr_end<FormatAttr>(); I != E ; ++I)
+ if (CheckFormatArguments(*I, Args, NumArgs, IsMemberFunction, CallType,
+ Loc, Range))
+ HandledFormatString = true;
+
+ // Refuse POD arguments that weren't caught by the format string
+ // checks above.
+ if (!HandledFormatString && CallType != VariadicDoesNotApply)
+ for (unsigned ArgIdx = NumProtoArgs; ArgIdx < NumArgs; ++ArgIdx)
+ variadicArgumentPODCheck(Args[ArgIdx], CallType);
for (specific_attr_iterator<NonNullAttr>
- i = FDecl->specific_attr_begin<NonNullAttr>(),
- e = FDecl->specific_attr_end<NonNullAttr>(); i != e; ++i) {
- CheckNonNullArguments(*i, TheCall->getArgs(),
- TheCall->getCallee()->getLocStart());
+ I = FDecl->specific_attr_begin<NonNullAttr>(),
+ E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I)
+ CheckNonNullArguments(*I, Args, Loc);
+
+ // Type safety checking.
+ for (specific_attr_iterator<ArgumentWithTypeTagAttr>
+ i = FDecl->specific_attr_begin<ArgumentWithTypeTagAttr>(),
+ e = FDecl->specific_attr_end<ArgumentWithTypeTagAttr>(); i != e; ++i) {
+ CheckArgumentWithTypeTag(*i, Args);
}
+}
+
+/// CheckConstructorCall - Check a constructor call for correctness and safety
+/// properties not enforced by the C type system.
+void Sema::CheckConstructorCall(FunctionDecl *FDecl, Expr **Args,
+ unsigned NumArgs,
+ const FunctionProtoType *Proto,
+ SourceLocation Loc) {
+ VariadicCallType CallType =
+ Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
+ checkCall(FDecl, Args, NumArgs, Proto->getNumArgs(),
+ /*IsMemberFunction=*/true, Loc, SourceRange(), CallType);
+}
+
+/// CheckFunctionCall - Check a direct function call for various correctness
+/// and safety properties not strictly enforced by the C type system.
+bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
+ const FunctionProtoType *Proto) {
+ bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall);
+ VariadicCallType CallType = getVariadicCallType(FDecl, Proto,
+ TheCall->getCallee());
+ unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
+ checkCall(FDecl, TheCall->getArgs(), TheCall->getNumArgs(), NumProtoArgs,
+ IsMemberFunction, TheCall->getRParenLoc(),
+ TheCall->getCallee()->getSourceRange(), CallType);
+
+ IdentifierInfo *FnInfo = FDecl->getIdentifier();
+ // None of the checks below are needed for functions that don't have
+ // simple names (e.g., C++ conversion functions).
+ if (!FnInfo)
+ return false;
unsigned CMId = FDecl->getMemoryFunctionKind();
if (CMId == 0)
@@ -448,25 +569,18 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
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) {
+ VariadicCallType CallType =
+ Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply;
- 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);
- }
+ checkCall(Method, Args, NumArgs, Method->param_size(),
+ /*IsMemberFunction=*/false,
+ lbrac, Method->getSourceRange(), CallType);
return false;
}
-bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
+bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
+ const FunctionProtoType *Proto) {
const VarDecl *V = dyn_cast<VarDecl>(NDecl);
if (!V)
return false;
@@ -475,13 +589,15 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
if (!Ty->isBlockPointerType())
return false;
- // format string checking.
- for (specific_attr_iterator<FormatAttr>
- i = NDecl->specific_attr_begin<FormatAttr>(),
- e = NDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
- CheckFormatArguments(*i, TheCall);
- }
+ VariadicCallType CallType =
+ Proto && Proto->isVariadic() ? VariadicBlock : VariadicDoesNotApply ;
+ unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
+ checkCall(NDecl, TheCall->getArgs(), TheCall->getNumArgs(),
+ NumProtoArgs, /*IsMemberFunction=*/false,
+ TheCall->getRParenLoc(),
+ TheCall->getCallee()->getSourceRange(), CallType);
+
return false;
}
@@ -1260,7 +1376,7 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
// If the common type isn't a real floating type, then the arguments were
// invalid for this operation.
- if (!Res->isRealFloatingType())
+ if (Res.isNull() || !Res->isRealFloatingType())
return Diag(OrigArg0.get()->getLocStart(),
diag::err_typecheck_call_invalid_ordered_compare)
<< OrigArg0.get()->getType() << OrigArg1.get()->getType()
@@ -1409,7 +1525,11 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
// constant integers.
for (unsigned i = 1; i != NumArgs; ++i) {
Expr *Arg = TheCall->getArg(i);
-
+
+ // We can't check the value of a dependent argument.
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ continue;
+
llvm::APSInt Result;
if (SemaBuiltinConstantArg(TheCall, i, Result))
return true;
@@ -1454,7 +1574,12 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
// For compatibility check 0-3, llvm only handles 0 and 2.
bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
llvm::APSInt Result;
-
+
+ // We can't check the value of a dependent argument.
+ if (TheCall->getArg(1)->isTypeDependent() ||
+ TheCall->getArg(1)->isValueDependent())
+ return false;
+
// Check constant-ness first.
if (SemaBuiltinConstantArg(TheCall, 1, Result))
return true;
@@ -1485,14 +1610,19 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
return false;
}
-// Handle i > 1 ? "x" : "y", recursively.
-bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
- unsigned NumArgs, bool HasVAListArg,
- unsigned format_idx, unsigned firstDataArg,
- FormatStringType Type, bool inFunctionCall) {
+// Determine if an expression is a string literal or constant string.
+// If this function returns false on the arguments to a function expecting a
+// format string, we will usually need to emit a warning.
+// True string literals are then checked by CheckFormatString.
+Sema::StringLiteralCheckType
+Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
+ unsigned NumArgs, bool HasVAListArg,
+ unsigned format_idx, unsigned firstDataArg,
+ FormatStringType Type, VariadicCallType CallType,
+ bool inFunctionCall) {
tryAgain:
if (E->isTypeDependent() || E->isValueDependent())
- return false;
+ return SLCT_NotALiteral;
E = E->IgnoreParenCasts();
@@ -1501,18 +1631,26 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
// The behavior of printf and friends in this case is implementation
// dependent. Ideally if the format string cannot be null then
// it should have a 'nonnull' attribute in the function prototype.
- return true;
+ return SLCT_CheckedLiteral;
switch (E->getStmtClass()) {
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: {
- const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E);
- return SemaCheckStringLiteral(C->getTrueExpr(), Args, NumArgs, HasVAListArg,
- format_idx, firstDataArg, Type,
- inFunctionCall)
- && SemaCheckStringLiteral(C->getFalseExpr(), Args, NumArgs, HasVAListArg,
- format_idx, firstDataArg, Type,
- inFunctionCall);
+ // The expression is a literal if both sub-expressions were, and it was
+ // completely checked only if both sub-expressions were checked.
+ const AbstractConditionalOperator *C =
+ cast<AbstractConditionalOperator>(E);
+ StringLiteralCheckType Left =
+ checkFormatStringExpr(C->getTrueExpr(), Args, NumArgs,
+ HasVAListArg, format_idx, firstDataArg,
+ Type, CallType, inFunctionCall);
+ if (Left == SLCT_NotALiteral)
+ return SLCT_NotALiteral;
+ StringLiteralCheckType Right =
+ checkFormatStringExpr(C->getFalseExpr(), Args, NumArgs,
+ HasVAListArg, format_idx, firstDataArg,
+ Type, CallType, inFunctionCall);
+ return Left < Right ? Left : Right;
}
case Stmt::ImplicitCastExprClass: {
@@ -1525,13 +1663,13 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
E = src;
goto tryAgain;
}
- return false;
+ return SLCT_NotALiteral;
case Stmt::PredefinedExprClass:
// While __func__, etc., are technically not string literals, they
// cannot contain format specifiers and thus are not a security
// liability.
- return true;
+ return SLCT_UncheckedLiteral;
case Stmt::DeclRefExprClass: {
const DeclRefExpr *DR = cast<DeclRefExpr>(E);
@@ -1554,10 +1692,17 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
}
if (isConstant) {
- if (const Expr *Init = VD->getAnyInitializer())
- return SemaCheckStringLiteral(Init, Args, NumArgs,
- HasVAListArg, format_idx, firstDataArg,
- Type, /*inFunctionCall*/false);
+ if (const Expr *Init = VD->getAnyInitializer()) {
+ // Look through initializers like const char c[] = { "foo" }
+ if (const InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) {
+ if (InitList->isStringLiteralInit())
+ Init = InitList->getInit(0)->IgnoreParenImpCasts();
+ }
+ return checkFormatStringExpr(Init, Args, NumArgs,
+ HasVAListArg, format_idx,
+ firstDataArg, Type, CallType,
+ /*inFunctionCall*/false);
+ }
}
// For vprintf* functions (i.e., HasVAListArg==true), we add a
@@ -1590,14 +1735,14 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
// We can't pass a 'scanf' string to a 'printf' function.
if (PVIndex == PVFormat->getFormatIdx() &&
Type == GetFormatStringType(PVFormat))
- return true;
+ return SLCT_UncheckedLiteral;
}
}
}
}
}
- return false;
+ return SLCT_NotALiteral;
}
case Stmt::CallExprClass:
@@ -1611,13 +1756,23 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
--ArgIndex;
const Expr *Arg = CE->getArg(ArgIndex - 1);
- return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg,
- format_idx, firstDataArg, Type,
- inFunctionCall);
+ return checkFormatStringExpr(Arg, Args, NumArgs,
+ HasVAListArg, format_idx, firstDataArg,
+ Type, CallType, inFunctionCall);
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ unsigned BuiltinID = FD->getBuiltinID();
+ if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
+ BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
+ const Expr *Arg = CE->getArg(0);
+ return checkFormatStringExpr(Arg, Args, NumArgs,
+ HasVAListArg, format_idx,
+ firstDataArg, Type, CallType,
+ inFunctionCall);
+ }
}
}
- return false;
+ return SLCT_NotALiteral;
}
case Stmt::ObjCStringLiteralClass:
case Stmt::StringLiteralClass: {
@@ -1630,15 +1785,15 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
if (StrE) {
CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx,
- firstDataArg, Type, inFunctionCall);
- return true;
+ firstDataArg, Type, inFunctionCall, CallType);
+ return SLCT_CheckedLiteral;
}
- return false;
+ return SLCT_NotALiteral;
}
default:
- return false;
+ return SLCT_NotALiteral;
}
}
@@ -1667,44 +1822,30 @@ Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
.Default(FST_Unknown);
}
-/// CheckPrintfScanfArguments - Check calls to printf and scanf (and similar
+/// CheckFormatArguments - Check calls to printf and scanf (and similar
/// functions) for correct use of format strings.
-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,
+/// Returns true if a format string has been fully checked.
+bool Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
unsigned NumArgs, bool IsCXXMember,
+ VariadicCallType CallType,
SourceLocation Loc, SourceRange Range) {
- bool HasVAListArg = Format->getFirstArg() == 0;
- unsigned format_idx = Format->getFormatIdx() - 1;
- unsigned firstDataArg = HasVAListArg ? 0 : Format->getFirstArg() - 1;
- if (IsCXXMember) {
- if (format_idx == 0)
- return;
- --format_idx;
- if(firstDataArg != 0)
- --firstDataArg;
- }
- CheckFormatArguments(Args, NumArgs, HasVAListArg, format_idx,
- firstDataArg, GetFormatStringType(Format), Loc, Range);
+ FormatStringInfo FSI;
+ if (getFormatStringInfo(Format, IsCXXMember, &FSI))
+ return CheckFormatArguments(Args, NumArgs, FSI.HasVAListArg, FSI.FormatIdx,
+ FSI.FirstDataArg, GetFormatStringType(Format),
+ CallType, Loc, Range);
+ return false;
}
-void Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
+bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
+ VariadicCallType CallType,
SourceLocation Loc, SourceRange Range) {
// CHECK: printf/scanf-like function is called with no format string.
if (format_idx >= NumArgs) {
Diag(Loc, diag::warn_missing_format_string) << Range;
- return;
+ return false;
}
const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts();
@@ -1721,21 +1862,25 @@ void Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
// C string (e.g. "%d")
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
- if (SemaCheckStringLiteral(OrigFormatExpr, Args, NumArgs, HasVAListArg,
- format_idx, firstDataArg, Type))
- return; // Literal format string found, check done!
+ StringLiteralCheckType CT =
+ checkFormatStringExpr(OrigFormatExpr, Args, NumArgs, HasVAListArg,
+ format_idx, firstDataArg, Type, CallType);
+ if (CT != SLCT_NotALiteral)
+ // Literal format string found, check done!
+ return CT == SLCT_CheckedLiteral;
// Strftime is particular as it always uses a single 'time' argument,
// so it is safe to pass a non-literal string.
if (Type == FST_Strftime)
- return;
+ return false;
// Do not emit diag when the string param is a macro expansion and the
// format is either NSString or CFString. This is a hack to prevent
// 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 (Type == FST_NSString &&
+ SourceMgr.isInSystemMacro(Args[format_idx]->getLocStart()))
+ return false;
// If there are no arguments specified, warn with -Wformat-security, otherwise
// warn only with -Wformat-nonliteral.
@@ -1747,6 +1892,7 @@ void Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
Diag(Args[format_idx]->getLocStart(),
diag::warn_format_nonliteral)
<< OrigFormatExpr->getSourceRange();
+ return false;
}
namespace {
@@ -1757,7 +1903,6 @@ protected:
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;
@@ -1767,21 +1912,20 @@ protected:
bool usesPositionalArgs;
bool atFirstArg;
bool inFunctionCall;
+ Sema::VariadicCallType CallType;
public:
CheckFormatHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
- unsigned numDataArgs, bool isObjCLiteral,
- const char *beg, bool hasVAListArg,
+ unsigned numDataArgs, const char *beg, bool hasVAListArg,
Expr **args, unsigned numArgs,
- unsigned formatIdx, bool inFunctionCall)
+ unsigned formatIdx, bool inFunctionCall,
+ Sema::VariadicCallType callType)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
- FirstDataArg(firstDataArg),
- NumDataArgs(numDataArgs),
- IsObjCLiteral(isObjCLiteral), Beg(beg),
- HasVAListArg(hasVAListArg),
+ FirstDataArg(firstDataArg), NumDataArgs(numDataArgs),
+ Beg(beg), HasVAListArg(hasVAListArg),
Args(args), NumArgs(numArgs), FormatIdx(formatIdx),
usesPositionalArgs(false), atFirstArg(true),
- inFunctionCall(inFunctionCall) {
+ inFunctionCall(inFunctionCall), CallType(callType) {
CoveredArgs.resize(numDataArgs);
CoveredArgs.reset();
}
@@ -1938,7 +2082,7 @@ void CheckFormatHandler::HandleZeroPosition(const char *startPos,
}
void CheckFormatHandler::HandleNullChar(const char *nullCharacter) {
- if (!IsObjCLiteral) {
+ if (!isa<ObjCStringLiteral>(OrigFormatExpr)) {
// The presence of a null character is likely an error.
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_format_string_contains_null_char),
@@ -1947,6 +2091,8 @@ void CheckFormatHandler::HandleNullChar(const char *nullCharacter) {
}
}
+// Note that this may return NULL if there was an error parsing or building
+// one of the argument expressions.
const Expr *CheckFormatHandler::getDataArg(unsigned i) const {
return Args[FirstDataArg + i];
}
@@ -1960,9 +2106,14 @@ void CheckFormatHandler::DoneProcessing() {
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());
+ if (const Expr *E = getDataArg((unsigned) notCoveredArg)) {
+ SourceLocation Loc = E->getLocStart();
+ if (!S.getSourceManager().isInSystemMacro(Loc)) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_data_arg_not_used),
+ Loc, /*IsStringLocation*/false,
+ getFormatStringRange());
+ }
+ }
}
}
}
@@ -2086,17 +2237,20 @@ void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall,
namespace {
class CheckPrintfHandler : public CheckFormatHandler {
+ bool ObjCContext;
public:
CheckPrintfHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
- unsigned numDataArgs, bool isObjCLiteral,
+ unsigned numDataArgs, bool isObjC,
const char *beg, bool hasVAListArg,
Expr **Args, unsigned NumArgs,
- unsigned formatIdx, bool inFunctionCall)
+ unsigned formatIdx, bool inFunctionCall,
+ Sema::VariadicCallType CallType)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
- numDataArgs, isObjCLiteral, beg, hasVAListArg,
- Args, NumArgs, formatIdx, inFunctionCall) {}
-
+ numDataArgs, beg, hasVAListArg, Args, NumArgs,
+ formatIdx, inFunctionCall, CallType), ObjCContext(isObjC)
+ {}
+
bool HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS,
@@ -2106,7 +2260,11 @@ public:
bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen);
-
+ bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
+ const char *StartSpecifier,
+ unsigned SpecifierLen,
+ const Expr *E);
+
bool HandleAmount(const analyze_format_string::OptionalAmount &Amt, unsigned k,
const char *startSpecifier, unsigned specifierLen);
void HandleInvalidAmount(const analyze_printf::PrintfSpecifier &FS,
@@ -2120,6 +2278,9 @@ public:
const analyze_printf::OptionalFlag &ignoredFlag,
const analyze_printf::OptionalFlag &flag,
const char *startSpecifier, unsigned specifierLen);
+ bool checkForCStrMembers(const analyze_printf::ArgType &AT,
+ const Expr *E, const CharSourceRange &CSR);
+
};
}
@@ -2161,14 +2322,17 @@ bool CheckPrintfHandler::HandleAmount(
// doesn't emit a warning for that case.
CoveredArgs.set(argIndex);
const Expr *Arg = getDataArg(argIndex);
+ if (!Arg)
+ return false;
+
QualType T = Arg->getType();
- const analyze_printf::ArgTypeResult &ATR = Amt.getArgType(S.Context);
- assert(ATR.isValid());
+ const analyze_printf::ArgType &AT = Amt.getArgType(S.Context);
+ assert(AT.isValid());
- if (!ATR.matchesType(S.Context, T)) {
+ if (!AT.matchesType(S.Context, T)) {
EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_wrong_type)
- << k << ATR.getRepresentativeTypeName(S.Context)
+ << k << AT.getRepresentativeTypeName(S.Context)
<< T << Arg->getSourceRange(),
getLocationOfByte(Amt.getStart()),
/*IsStringLocation*/true,
@@ -2237,6 +2401,64 @@ void CheckPrintfHandler::HandleIgnoredFlag(
getSpecifierRange(ignoredFlag.getPosition(), 1)));
}
+// Determines if the specified is a C++ class or struct containing
+// a member with the specified name and kind (e.g. a CXXMethodDecl named
+// "c_str()").
+template<typename MemberKind>
+static llvm::SmallPtrSet<MemberKind*, 1>
+CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
+ const RecordType *RT = Ty->getAs<RecordType>();
+ llvm::SmallPtrSet<MemberKind*, 1> Results;
+
+ if (!RT)
+ return Results;
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD)
+ return Results;
+
+ LookupResult R(S, &S.PP.getIdentifierTable().get(Name), SourceLocation(),
+ Sema::LookupMemberName);
+
+ // We just need to include all members of the right kind turned up by the
+ // filter, at this point.
+ if (S.LookupQualifiedName(R, RT->getDecl()))
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ NamedDecl *decl = (*I)->getUnderlyingDecl();
+ if (MemberKind *FK = dyn_cast<MemberKind>(decl))
+ Results.insert(FK);
+ }
+ return Results;
+}
+
+// Check if a (w)string was passed when a (w)char* was needed, and offer a
+// better diagnostic if so. AT is assumed to be valid.
+// Returns true when a c_str() conversion method is found.
+bool CheckPrintfHandler::checkForCStrMembers(
+ const analyze_printf::ArgType &AT, const Expr *E,
+ const CharSourceRange &CSR) {
+ typedef llvm::SmallPtrSet<CXXMethodDecl*, 1> MethodSet;
+
+ MethodSet Results =
+ CXXRecordMembersNamed<CXXMethodDecl>("c_str", S, E->getType());
+
+ for (MethodSet::iterator MI = Results.begin(), ME = Results.end();
+ MI != ME; ++MI) {
+ const CXXMethodDecl *Method = *MI;
+ if (Method->getNumParams() == 0 &&
+ AT.matchesType(S.Context, Method->getResultType())) {
+ // FIXME: Suggest parens if the expression needs them.
+ SourceLocation EndLoc =
+ S.getPreprocessor().getLocForEndOfToken(E->getLocEnd());
+ S.Diag(E->getLocStart(), diag::note_printf_c_str)
+ << "c_str()"
+ << FixItHint::CreateInsertion(EndLoc, ".c_str()");
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool
CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
&FS,
@@ -2294,24 +2516,24 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
// Now type check the data expression that matches the
// format specifier.
const Expr *Ex = getDataArg(argIndex);
- const analyze_printf::ArgTypeResult &ATR =
+ const analyze_printf::ArgType &AT =
(CS.getKind() == ConversionSpecifier::bArg) ?
- ArgTypeResult(S.Context.IntTy) : ArgTypeResult::CStrTy;
- if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType()))
+ ArgType(S.Context.IntTy) : ArgType::CStrTy;
+ if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType()))
S.Diag(getLocationOfByte(CS.getStart()),
diag::warn_printf_conversion_argument_type_mismatch)
- << ATR.getRepresentativeType(S.Context) << Ex->getType()
+ << AT.getRepresentativeType(S.Context) << Ex->getType()
<< getSpecifierRange(startSpecifier, specifierLen)
<< Ex->getSourceRange();
// Now type check the data expression that matches the
// format specifier.
Ex = getDataArg(argIndex + 1);
- const analyze_printf::ArgTypeResult &ATR2 = ArgTypeResult::CStrTy;
- if (ATR2.isValid() && !ATR2.matchesType(S.Context, Ex->getType()))
+ const analyze_printf::ArgType &AT2 = ArgType::CStrTy;
+ if (AT2.isValid() && !AT2.matchesType(S.Context, Ex->getType()))
S.Diag(getLocationOfByte(CS.getStart()),
diag::warn_printf_conversion_argument_type_mismatch)
- << ATR2.getRepresentativeType(S.Context) << Ex->getType()
+ << AT2.getRepresentativeType(S.Context) << Ex->getType()
<< getSpecifierRange(startSpecifier, specifierLen)
<< Ex->getSourceRange();
@@ -2321,7 +2543,7 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
// Check for using an Objective-C specific conversion specifier
// in a non-ObjC literal.
- if (!IsObjCLiteral && CS.isObjCArg()) {
+ if (!ObjCContext && CS.isObjCArg()) {
return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier,
specifierLen);
}
@@ -2379,17 +2601,6 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
HandleNonStandardConversionSpecification(LM, CS, startSpecifier,
specifierLen);
- // 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;
@@ -2397,54 +2608,98 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
return false;
+ const Expr *Arg = getDataArg(argIndex);
+ if (!Arg)
+ return true;
+
+ return checkFormatExpr(FS, startSpecifier, specifierLen, Arg);
+}
+
+bool
+CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
+ const char *StartSpecifier,
+ unsigned SpecifierLen,
+ const Expr *E) {
+ using namespace analyze_format_string;
+ using namespace analyze_printf;
// Now type check the data expression that matches the
// format specifier.
- const Expr *Ex = getDataArg(argIndex);
- const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context,
- 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;
+ const analyze_printf::ArgType &AT = FS.getArgType(S.Context,
+ ObjCContext);
+ if (AT.isValid() && !AT.matchesType(S.Context, E->getType())) {
+ // Look through argument promotions for our error message's reported type.
+ // This includes the integral and floating promotions, but excludes array
+ // and function pointer decay; seeing that an argument intended to be a
+ // string has type 'char [6]' is probably more confusing than 'char *'.
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ICE->getCastKind() == CK_IntegralCast ||
+ ICE->getCastKind() == CK_FloatingCast) {
+ E = ICE->getSubExpr();
+
+ // Check if we didn't match because of an implicit cast from a 'char'
+ // or 'short' to an 'int'. This is done because printf is a varargs
+ // function.
+ if (ICE->getType() == S.Context.IntTy ||
+ ICE->getType() == S.Context.UnsignedIntTy) {
+ // All further checking is done on the subexpression.
+ if (AT.matchesType(S.Context, E->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.getLangOpts(),
- S.Context, IsObjCLiteral);
+ bool success = fixedFS.fixType(E->getType(), S.getLangOpts(),
+ S.Context, ObjCContext);
if (success) {
// Get the fix string from the fixed format specifier
- SmallString<128> buf;
+ SmallString<16> 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),
+ << AT.getRepresentativeTypeName(S.Context) << E->getType()
+ << E->getSourceRange(),
+ E->getLocStart(),
+ /*IsStringLocation*/false,
+ getSpecifierRange(StartSpecifier, SpecifierLen),
FixItHint::CreateReplacement(
- getSpecifierRange(startSpecifier, specifierLen),
+ getSpecifierRange(StartSpecifier, SpecifierLen),
os.str()));
- }
- else {
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
- << getSpecifierRange(startSpecifier, specifierLen)
- << Ex->getSourceRange(),
- getLocationOfByte(CS.getStart()),
- true,
- getSpecifierRange(startSpecifier, specifierLen));
+ } else {
+ const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
+ SpecifierLen);
+ // Since the warning for passing non-POD types to variadic functions
+ // was deferred until now, we emit a warning for non-POD
+ // arguments here.
+ if (S.isValidVarArgType(E->getType()) == Sema::VAK_Invalid) {
+ unsigned DiagKind;
+ if (E->getType()->isObjCObjectType())
+ DiagKind = diag::err_cannot_pass_objc_interface_to_vararg_format;
+ else
+ DiagKind = diag::warn_non_pod_vararg_with_format_string;
+
+ EmitFormatDiagnostic(
+ S.PDiag(DiagKind)
+ << S.getLangOpts().CPlusPlus0x
+ << E->getType()
+ << CallType
+ << AT.getRepresentativeTypeName(S.Context)
+ << CSR
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/false, CSR);
+
+ checkForCStrMembers(AT, E, CSR);
+ } else
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << E->getType()
+ << CSR
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/false, CSR);
}
}
@@ -2458,13 +2713,14 @@ 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,
+ unsigned numDataArgs, const char *beg, bool hasVAListArg,
Expr **Args, unsigned NumArgs,
- unsigned formatIdx, bool inFunctionCall)
+ unsigned formatIdx, bool inFunctionCall,
+ Sema::VariadicCallType CallType)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
- numDataArgs, isObjCLiteral, beg, hasVAListArg,
- Args, NumArgs, formatIdx, inFunctionCall) {}
+ numDataArgs, beg, hasVAListArg,
+ Args, NumArgs, formatIdx, inFunctionCall, CallType)
+ {}
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
@@ -2581,8 +2837,11 @@ bool CheckScanfHandler::HandleScanfSpecifier(
// 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())) {
+ if (!Ex)
+ return true;
+
+ const analyze_format_string::ArgType &AT = FS.getArgType(S.Context);
+ if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) {
ScanfSpecifier fixedFS = FS;
bool success = fixedFS.fixType(Ex->getType(), S.getLangOpts(),
S.Context);
@@ -2595,10 +2854,10 @@ bool CheckScanfHandler::HandleScanfSpecifier(
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
+ << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
<< Ex->getSourceRange(),
- getLocationOfByte(CS.getStart()),
- /*IsStringLocation*/true,
+ Ex->getLocStart(),
+ /*IsStringLocation*/false,
getSpecifierRange(startSpecifier, specifierLen),
FixItHint::CreateReplacement(
getSpecifierRange(startSpecifier, specifierLen),
@@ -2606,10 +2865,10 @@ bool CheckScanfHandler::HandleScanfSpecifier(
} else {
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
+ << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
<< Ex->getSourceRange(),
- getLocationOfByte(CS.getStart()),
- /*IsStringLocation*/true,
+ Ex->getLocStart(),
+ /*IsStringLocation*/false,
getSpecifierRange(startSpecifier, specifierLen));
}
}
@@ -2622,10 +2881,10 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
Expr **Args, unsigned NumArgs,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
- bool inFunctionCall) {
+ bool inFunctionCall, VariadicCallType CallType) {
// CHECK: is the format string a wide literal?
- if (!FExpr->isAscii()) {
+ if (!FExpr->isAscii() && !FExpr->isUTF8()) {
CheckFormatHandler::EmitFormatDiagnostic(
*this, inFunctionCall, Args[format_idx],
PDiag(diag::warn_format_string_is_wide_literal), FExpr->getLocStart(),
@@ -2650,18 +2909,17 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
if (Type == FST_Printf || Type == FST_NSString) {
CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
- numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr),
+ numDataArgs, (Type == FST_NSString),
Str, HasVAListArg, Args, NumArgs, format_idx,
- inFunctionCall);
+ inFunctionCall, CallType);
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
getLangOpts()))
H.DoneProcessing();
} else if (Type == FST_Scanf) {
- CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
- numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr),
+ CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs,
Str, HasVAListArg, Args, NumArgs, format_idx,
- inFunctionCall);
+ inFunctionCall, CallType);
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
getLangOpts()))
@@ -2761,19 +3019,43 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
// TODO: For strncpy() and friends, this could suggest sizeof(dst)
// over sizeof(src) as well.
unsigned ActionIdx = 0; // Default is to suggest dereferencing.
+ StringRef ReadableName = FnName->getName();
+
if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest))
if (UnaryOp->getOpcode() == UO_AddrOf)
ActionIdx = 1; // If its an address-of operator, just remove it.
if (Context.getTypeSize(PointeeTy) == Context.getCharWidth())
ActionIdx = 2; // If the pointee's size is sizeof(char),
// suggest an explicit length.
- unsigned DestSrcSelect =
- (BId == Builtin::BIstrndup ? 1 : ArgIdx);
- DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest,
+
+ // If the function is defined as a builtin macro, do not show macro
+ // expansion.
+ SourceLocation SL = SizeOfArg->getExprLoc();
+ SourceRange DSR = Dest->getSourceRange();
+ SourceRange SSR = SizeOfArg->getSourceRange();
+ SourceManager &SM = PP.getSourceManager();
+
+ if (SM.isMacroArgExpansion(SL)) {
+ ReadableName = Lexer::getImmediateMacroName(SL, SM, LangOpts);
+ SL = SM.getSpellingLoc(SL);
+ DSR = SourceRange(SM.getSpellingLoc(DSR.getBegin()),
+ SM.getSpellingLoc(DSR.getEnd()));
+ SSR = SourceRange(SM.getSpellingLoc(SSR.getBegin()),
+ SM.getSpellingLoc(SSR.getEnd()));
+ }
+
+ DiagRuntimeBehavior(SL, SizeOfArg,
PDiag(diag::warn_sizeof_pointer_expr_memaccess)
- << FnName << DestSrcSelect << ActionIdx
- << Dest->getSourceRange()
- << SizeOfArg->getSourceRange());
+ << ReadableName
+ << PointeeTy
+ << DestTy
+ << DSR
+ << SSR);
+ DiagRuntimeBehavior(SL, SizeOfArg,
+ PDiag(diag::warn_sizeof_pointer_expr_memaccess_note)
+ << ActionIdx
+ << SSR);
+
break;
}
}
@@ -2859,6 +3141,19 @@ static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) {
return Ex;
}
+static bool isConstantSizeArrayWithMoreThanOneElement(QualType Ty,
+ ASTContext &Context) {
+ // Only handle constant-sized or VLAs, but not flexible members.
+ if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(Ty)) {
+ // Only issue the FIXIT for arrays of size > 1.
+ if (CAT->getSize().getSExtValue() <= 1)
+ return false;
+ } else if (!Ty->isVariableArrayType()) {
+ return false;
+ }
+ return true;
+}
+
// Warn if the user has made the 'size' argument to strlcpy or strlcat
// be the size of the source, instead of the destination.
void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
@@ -2909,21 +3204,13 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
// pointers if we know the actual size, like if DstArg is 'array+2'
// we could say 'sizeof(array)-2'.
const Expr *DstArg = Call->getArg(0)->IgnoreParenImpCasts();
- QualType DstArgTy = DstArg->getType();
-
- // Only handle constant-sized or VLAs, but not flexible members.
- if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(DstArgTy)) {
- // Only issue the FIXIT for arrays of size > 1.
- if (CAT->getSize().getSExtValue() <= 1)
- return;
- } else if (!DstArgTy->isVariableArrayType()) {
+ if (!isConstantSizeArrayWithMoreThanOneElement(DstArg->getType(), Context))
return;
- }
SmallString<128> sizeString;
llvm::raw_svector_ostream OS(sizeString);
OS << "sizeof(";
- DstArg->printPretty(OS, Context, 0, getPrintingPolicy());
+ DstArg->printPretty(OS, 0, getPrintingPolicy());
OS << ")";
Diag(OriginalSizeArg->getLocStart(), diag::note_strlcpycat_wrong_size)
@@ -3000,33 +3287,30 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
SM.getSpellingLoc(SR.getEnd()));
}
+ // Check if the destination is an array (rather than a pointer to an array).
+ QualType DstTy = DstArg->getType();
+ bool isKnownSizeArray = isConstantSizeArrayWithMoreThanOneElement(DstTy,
+ Context);
+ if (!isKnownSizeArray) {
+ if (PatternType == 1)
+ Diag(SL, diag::warn_strncat_wrong_size) << SR;
+ else
+ Diag(SL, diag::warn_strncat_src_size) << SR;
+ return;
+ }
+
if (PatternType == 1)
Diag(SL, diag::warn_strncat_large_size) << SR;
else
Diag(SL, diag::warn_strncat_src_size) << SR;
- // Output a FIXIT hint if the destination is an array (rather than a
- // pointer to an array). This could be enhanced to handle some
- // pointers if we know the actual size, like if DstArg is 'array+2'
- // we could say 'sizeof(array)-2'.
- QualType DstArgTy = DstArg->getType();
-
- // Only handle constant-sized or VLAs, but not flexible members.
- if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(DstArgTy)) {
- // Only issue the FIXIT for arrays of size > 1.
- if (CAT->getSize().getSExtValue() <= 1)
- return;
- } else if (!DstArgTy->isVariableArrayType()) {
- return;
- }
-
SmallString<128> sizeString;
llvm::raw_svector_ostream OS(sizeString);
OS << "sizeof(";
- DstArg->printPretty(OS, Context, 0, getPrintingPolicy());
+ DstArg->printPretty(OS, 0, getPrintingPolicy());
OS << ") - ";
OS << "strlen(";
- DstArg->printPretty(OS, Context, 0, getPrintingPolicy());
+ DstArg->printPretty(OS, 0, getPrintingPolicy());
OS << ") - 1";
Diag(SL, diag::note_strncat_wrong_size)
@@ -3035,8 +3319,10 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
//===--- CHECK: Return Address of Stack Variable --------------------------===//
-static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars);
-static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &refVars);
+static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
+ Decl *ParentDecl);
+static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &refVars,
+ Decl *ParentDecl);
/// CheckReturnStackAddr - Check if a return statement returns the address
/// of a stack variable.
@@ -3051,9 +3337,9 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
// label addresses or references to temporaries.
if (lhsType->isPointerType() ||
(!getLangOpts().ObjCAutoRefCount && lhsType->isBlockPointerType())) {
- stackE = EvalAddr(RetValExp, refVars);
+ stackE = EvalAddr(RetValExp, refVars, /*ParentDecl=*/0);
} else if (lhsType->isReferenceType()) {
- stackE = EvalVal(RetValExp, refVars);
+ stackE = EvalVal(RetValExp, refVars, /*ParentDecl=*/0);
}
if (stackE == 0)
@@ -3127,7 +3413,8 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
/// * arbitrary interplay between "&" and "*" operators
/// * pointer arithmetic from an address of a stack variable
/// * taking the address of an array element where the array is on the stack
-static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
+static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
+ Decl *ParentDecl) {
if (E->isTypeDependent())
return NULL;
@@ -3153,7 +3440,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
V->getType()->isReferenceType() && V->hasInit()) {
// Add the reference variable to the "trail".
refVars.push_back(DR);
- return EvalAddr(V->getInit(), refVars);
+ return EvalAddr(V->getInit(), refVars, ParentDecl);
}
return NULL;
@@ -3165,7 +3452,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
UnaryOperator *U = cast<UnaryOperator>(E);
if (U->getOpcode() == UO_AddrOf)
- return EvalVal(U->getSubExpr(), refVars);
+ return EvalVal(U->getSubExpr(), refVars, ParentDecl);
else
return NULL;
}
@@ -3186,7 +3473,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
if (!Base->getType()->isPointerType()) Base = B->getRHS();
assert (Base->getType()->isPointerType());
- return EvalAddr(Base, refVars);
+ return EvalAddr(Base, refVars, ParentDecl);
}
// For conditional operators we need to see if either the LHS or RHS are
@@ -3198,7 +3485,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
if (Expr *lhsExpr = C->getLHS()) {
// In C++, we can have a throw-expression, which has 'void' type.
if (!lhsExpr->getType()->isVoidType())
- if (Expr* LHS = EvalAddr(lhsExpr, refVars))
+ if (Expr* LHS = EvalAddr(lhsExpr, refVars, ParentDecl))
return LHS;
}
@@ -3206,7 +3493,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
if (C->getRHS()->getType()->isVoidType())
return NULL;
- return EvalAddr(C->getRHS(), refVars);
+ return EvalAddr(C->getRHS(), refVars, ParentDecl);
}
case Stmt::BlockExprClass:
@@ -3218,7 +3505,8 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
return E; // address of label.
case Stmt::ExprWithCleanupsClass:
- return EvalAddr(cast<ExprWithCleanups>(E)->getSubExpr(), refVars);
+ return EvalAddr(cast<ExprWithCleanups>(E)->getSubExpr(), refVars,
+ ParentDecl);
// For casts, we need to handle conversions from arrays to
// pointer values, and pointer-to-pointer conversions.
@@ -3242,10 +3530,10 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
- return EvalAddr(SubExpr, refVars);
+ return EvalAddr(SubExpr, refVars, ParentDecl);
case CK_ArrayToPointerDecay:
- return EvalVal(SubExpr, refVars);
+ return EvalVal(SubExpr, refVars, ParentDecl);
default:
return 0;
@@ -3255,7 +3543,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
case Stmt::MaterializeTemporaryExprClass:
if (Expr *Result = EvalAddr(
cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
- refVars))
+ refVars, ParentDecl))
return Result;
return E;
@@ -3269,7 +3557,8 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
/// EvalVal - This function is complements EvalAddr in the mutual recursion.
/// See the comments for EvalAddr for more details.
-static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
+static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
+ Decl *ParentDecl) {
do {
// We should only be called for evaluating non-pointer expressions, or
// expressions with a pointer type that are not used as references but instead
@@ -3291,7 +3580,7 @@ do {
}
case Stmt::ExprWithCleanupsClass:
- return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars);
+ return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars,ParentDecl);
case Stmt::DeclRefExprClass: {
// When we hit a DeclRefExpr we are looking at code that refers to a
@@ -3299,7 +3588,11 @@ do {
// local storage within the function, and if so, return the expression.
DeclRefExpr *DR = cast<DeclRefExpr>(E);
- if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl()))
+ if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) {
+ // Check if it refers to itself, e.g. "int& i = i;".
+ if (V == ParentDecl)
+ return DR;
+
if (V->hasLocalStorage()) {
if (!V->getType()->isReferenceType())
return DR;
@@ -3309,9 +3602,10 @@ do {
if (V->hasInit()) {
// Add the reference variable to the "trail".
refVars.push_back(DR);
- return EvalVal(V->getInit(), refVars);
+ return EvalVal(V->getInit(), refVars, V);
}
}
+ }
return NULL;
}
@@ -3323,7 +3617,7 @@ do {
UnaryOperator *U = cast<UnaryOperator>(E);
if (U->getOpcode() == UO_Deref)
- return EvalAddr(U->getSubExpr(), refVars);
+ return EvalAddr(U->getSubExpr(), refVars, ParentDecl);
return NULL;
}
@@ -3332,7 +3626,7 @@ do {
// Array subscripts are potential references to data on the stack. We
// retrieve the DeclRefExpr* for the array variable if it indeed
// has local storage.
- return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase(), refVars);
+ return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase(), refVars,ParentDecl);
}
case Stmt::ConditionalOperatorClass: {
@@ -3342,10 +3636,10 @@ do {
// Handle the GNU extension for missing LHS.
if (Expr *lhsExpr = C->getLHS())
- if (Expr *LHS = EvalVal(lhsExpr, refVars))
+ if (Expr *LHS = EvalVal(lhsExpr, refVars, ParentDecl))
return LHS;
- return EvalVal(C->getRHS(), refVars);
+ return EvalVal(C->getRHS(), refVars, ParentDecl);
}
// Accesses to members are potential references to data on the stack.
@@ -3361,13 +3655,13 @@ do {
if (M->getMemberDecl()->getType()->isReferenceType())
return NULL;
- return EvalVal(M->getBase(), refVars);
+ return EvalVal(M->getBase(), refVars, ParentDecl);
}
case Stmt::MaterializeTemporaryExprClass:
if (Expr *Result = EvalVal(
cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
- refVars))
+ refVars, ParentDecl))
return Result;
return E;
@@ -3390,8 +3684,6 @@ do {
/// Issue a warning if these are no self-comparisons, as they are not likely
/// to do what the programmer intended.
void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) {
- bool EmitWarning = true;
-
Expr* LeftExprSansParen = LHS->IgnoreParenImpCasts();
Expr* RightExprSansParen = RHS->IgnoreParenImpCasts();
@@ -3400,7 +3692,7 @@ void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) {
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LeftExprSansParen))
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RightExprSansParen))
if (DRL->getDecl() == DRR->getDecl())
- EmitWarning = false;
+ return;
// Special case: check for comparisons against literals that can be exactly
@@ -3408,32 +3700,26 @@ void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) {
// is a heuristic: often comparison against such literals are used to
// detect if a value in a variable has not changed. This clearly can
// lead to false negatives.
- if (EmitWarning) {
- if (FloatingLiteral* FLL = dyn_cast<FloatingLiteral>(LeftExprSansParen)) {
- if (FLL->isExact())
- EmitWarning = false;
- } else
- if (FloatingLiteral* FLR = dyn_cast<FloatingLiteral>(RightExprSansParen)){
- if (FLR->isExact())
- EmitWarning = false;
- }
- }
+ if (FloatingLiteral* FLL = dyn_cast<FloatingLiteral>(LeftExprSansParen)) {
+ if (FLL->isExact())
+ return;
+ } else
+ if (FloatingLiteral* FLR = dyn_cast<FloatingLiteral>(RightExprSansParen))
+ if (FLR->isExact())
+ return;
// Check for comparisons with builtin types.
- if (EmitWarning)
- if (CallExpr* CL = dyn_cast<CallExpr>(LeftExprSansParen))
- if (CL->isBuiltinCall())
- EmitWarning = false;
+ if (CallExpr* CL = dyn_cast<CallExpr>(LeftExprSansParen))
+ if (CL->isBuiltinCall())
+ return;
- if (EmitWarning)
- if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen))
- if (CR->isBuiltinCall())
- EmitWarning = false;
+ if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen))
+ if (CR->isBuiltinCall())
+ return;
// Emit the diagnostic.
- if (EmitWarning)
- Diag(Loc, diag::warn_floatingpoint_eq)
- << LHS->getSourceRange() << RHS->getSourceRange();
+ Diag(Loc, diag::warn_floatingpoint_eq)
+ << LHS->getSourceRange() << RHS->getSourceRange();
}
//===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===//
@@ -3960,9 +4246,10 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
return;
}
- S.Diag(E->getOperatorLoc(), diag::warn_mixed_sign_comparison)
- << LHS->getType() << RHS->getType()
- << LHS->getSourceRange() << RHS->getSourceRange();
+ S.DiagRuntimeBehavior(E->getOperatorLoc(), E,
+ S.PDiag(diag::warn_mixed_sign_comparison)
+ << LHS->getType() << RHS->getType()
+ << LHS->getSourceRange() << RHS->getSourceRange());
}
/// Analyzes an attempt to assign the given value to a bitfield.
@@ -4003,7 +4290,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
// Check whether the stored value is equal to the original value.
TruncatedValue = TruncatedValue.extend(OriginalWidth);
- if (Value == TruncatedValue)
+ if (llvm::APSInt::isSameValue(Value, TruncatedValue))
return false;
// Special-case bitfields of width 1: booleans are naturally 0/1, and
@@ -4077,8 +4364,17 @@ void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T,
== llvm::APFloat::opOK && isExact)
return;
+ SmallString<16> PrettySourceValue;
+ Value.toString(PrettySourceValue);
+ SmallString<16> PrettyTargetValue;
+ if (T->isSpecificBuiltinType(BuiltinType::Bool))
+ PrettyTargetValue = IntegerValue == 0 ? "false" : "true";
+ else
+ IntegerValue.toString(PrettyTargetValue);
+
S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer)
- << FL->getType() << T << FL->getSourceRange() << SourceRange(CContext);
+ << FL->getType() << T.getUnqualifiedType() << PrettySourceValue
+ << PrettyTargetValue << FL->getSourceRange() << SourceRange(CContext);
}
std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
@@ -4145,7 +4441,6 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
}
}
}
- return; // Other casts to bool are not checked.
}
// Strip vector types.
@@ -4209,7 +4504,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
}
// If the target is integral, always warn.
- if ((TargetBT && TargetBT->isInteger())) {
+ if (TargetBT && TargetBT->isInteger()) {
if (S.SourceMgr.isInSystemMacro(CC))
return;
@@ -4229,19 +4524,26 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
}
- if (!Source->isIntegerType() || !Target->isIntegerType())
- return;
-
if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)
- == Expr::NPCK_GNUNull) && Target->isIntegerType()) {
+ == Expr::NPCK_GNUNull) && !Target->isAnyPointerType()
+ && !Target->isBlockPointerType() && !Target->isMemberPointerType()) {
SourceLocation Loc = E->getSourceRange().getBegin();
if (Loc.isMacroID())
Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
- S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
- << T << Loc << clang::SourceRange(CC);
- return;
+ if (!Loc.isMacroID() || CC.isMacroID())
+ S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
+ << T << clang::SourceRange(CC)
+ << FixItHint::CreateReplacement(Loc, S.getFixItZeroLiteralForType(T));
}
+ if (!Source->isIntegerType() || !Target->isIntegerType())
+ return;
+
+ // TODO: remove this early return once the false positives for constant->bool
+ // in templates, macros, etc, are reduced or removed.
+ if (Target->isSpecificBuiltinType(BuiltinType::Bool))
+ return;
+
IntRange SourceRange = GetExprRange(S.Context, E);
IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target);
@@ -4326,14 +4628,15 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
}
-void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T);
+void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
+ SourceLocation CC, QualType T);
void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
SourceLocation CC, bool &ICContext) {
E = E->IgnoreParenImpCasts();
if (isa<ConditionalOperator>(E))
- return CheckConditionalOperator(S, cast<ConditionalOperator>(E), T);
+ return CheckConditionalOperator(S, cast<ConditionalOperator>(E), CC, T);
AnalyzeImplicitConversions(S, E, CC);
if (E->getType() != T)
@@ -4341,9 +4644,8 @@ void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
return;
}
-void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) {
- SourceLocation CC = E->getQuestionLoc();
-
+void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
+ SourceLocation CC, QualType T) {
AnalyzeImplicitConversions(S, E->getCond(), CC);
bool Suspicious = false;
@@ -4385,7 +4687,7 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
// were being fed directly into the output.
if (isa<ConditionalOperator>(E)) {
ConditionalOperator *CO = cast<ConditionalOperator>(E);
- CheckConditionalOperator(S, CO, T);
+ CheckConditionalOperator(S, CO, CC, T);
return;
}
@@ -4450,7 +4752,7 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
/// conversion
void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) {
// Don't diagnose in unevaluated contexts.
- if (ExprEvalContexts.back().Context == Sema::Unevaluated)
+ if (isUnevaluatedContext())
return;
// Don't diagnose for value- or type-dependent expressions.
@@ -4490,7 +4792,7 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd,
// This is also C++ [dcl.fct]p6.
if (!Param->isInvalidDecl() &&
RequireCompleteType(Param->getLocation(), Param->getType(),
- diag::err_typecheck_decl_incomplete_type)) {
+ diag::err_typecheck_decl_incomplete_type)) {
Param->setInvalidDecl();
HasInvalidParm = true;
}
@@ -4511,7 +4813,7 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd,
QualType PType = Param->getOriginalType();
if (const ArrayType *AT = Context.getAsArrayType(PType)) {
if (AT->getSizeModifier() == ArrayType::Star) {
- // FIXME: This diagnosic should point the the '[*]' if source-location
+ // FIXME: This diagnosic should point the '[*]' if source-location
// information is added for it.
Diag(Param->getLocation(), diag::err_array_star_in_function_definition);
}
@@ -4589,11 +4891,23 @@ static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size,
// Don't consider sizes resulting from macro expansions or template argument
// substitution to form C89 tail-padded arrays.
- ConstantArrayTypeLoc TL =
- cast<ConstantArrayTypeLoc>(FD->getTypeSourceInfo()->getTypeLoc());
- const Expr *SizeExpr = dyn_cast<IntegerLiteral>(TL.getSizeExpr());
- if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
- return false;
+
+ TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
+ while (TInfo) {
+ TypeLoc TL = TInfo->getTypeLoc();
+ // Look through typedefs.
+ const TypedefTypeLoc *TTL = dyn_cast<TypedefTypeLoc>(&TL);
+ if (TTL) {
+ const TypedefNameDecl *TDL = TTL->getTypedefNameDecl();
+ TInfo = TDL->getTypeSourceInfo();
+ continue;
+ }
+ ConstantArrayTypeLoc CTL = cast<ConstantArrayTypeLoc>(TL);
+ const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
+ if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
+ return false;
+ break;
+ }
const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext());
if (!RD) return false;
@@ -4999,7 +5313,7 @@ bool Sema::checkUnsafeAssigns(SourceLocation Loc,
while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
if (cast->getCastKind() == CK_ARCConsumeObject) {
Diag(Loc, diag::warn_arc_retained_assign)
- << (LT == Qualifiers::OCL_ExplicitNone)
+ << (LT == Qualifiers::OCL_ExplicitNone) << 1
<< RHS->getSourceRange();
return true;
}
@@ -5056,6 +5370,16 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
RHS = cast->getSubExpr();
}
}
+ else if (Attributes & ObjCPropertyDecl::OBJC_PR_weak) {
+ while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
+ if (cast->getCastKind() == CK_ARCConsumeObject) {
+ Diag(Loc, diag::warn_arc_retained_assign)
+ << 0 << 0<< RHS->getSourceRange();
+ return;
+ }
+ RHS = cast->getSubExpr();
+ }
+ }
}
}
@@ -5184,3 +5508,410 @@ void Sema::DiagnoseEmptyLoopBody(const Stmt *S,
Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line);
}
}
+
+//===--- Layout compatibility ----------------------------------------------//
+
+namespace {
+
+bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2);
+
+/// \brief Check if two enumeration types are layout-compatible.
+bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) {
+ // C++11 [dcl.enum] p8:
+ // Two enumeration types are layout-compatible if they have the same
+ // underlying type.
+ return ED1->isComplete() && ED2->isComplete() &&
+ C.hasSameType(ED1->getIntegerType(), ED2->getIntegerType());
+}
+
+/// \brief Check if two fields are layout-compatible.
+bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) {
+ if (!isLayoutCompatible(C, Field1->getType(), Field2->getType()))
+ return false;
+
+ if (Field1->isBitField() != Field2->isBitField())
+ return false;
+
+ if (Field1->isBitField()) {
+ // Make sure that the bit-fields are the same length.
+ unsigned Bits1 = Field1->getBitWidthValue(C);
+ unsigned Bits2 = Field2->getBitWidthValue(C);
+
+ if (Bits1 != Bits2)
+ return false;
+ }
+
+ return true;
+}
+
+/// \brief Check if two standard-layout structs are layout-compatible.
+/// (C++11 [class.mem] p17)
+bool isLayoutCompatibleStruct(ASTContext &C,
+ RecordDecl *RD1,
+ RecordDecl *RD2) {
+ // If both records are C++ classes, check that base classes match.
+ if (const CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(RD1)) {
+ // If one of records is a CXXRecordDecl we are in C++ mode,
+ // thus the other one is a CXXRecordDecl, too.
+ const CXXRecordDecl *D2CXX = cast<CXXRecordDecl>(RD2);
+ // Check number of base classes.
+ if (D1CXX->getNumBases() != D2CXX->getNumBases())
+ return false;
+
+ // Check the base classes.
+ for (CXXRecordDecl::base_class_const_iterator
+ Base1 = D1CXX->bases_begin(),
+ BaseEnd1 = D1CXX->bases_end(),
+ Base2 = D2CXX->bases_begin();
+ Base1 != BaseEnd1;
+ ++Base1, ++Base2) {
+ if (!isLayoutCompatible(C, Base1->getType(), Base2->getType()))
+ return false;
+ }
+ } else if (const CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(RD2)) {
+ // If only RD2 is a C++ class, it should have zero base classes.
+ if (D2CXX->getNumBases() > 0)
+ return false;
+ }
+
+ // Check the fields.
+ RecordDecl::field_iterator Field2 = RD2->field_begin(),
+ Field2End = RD2->field_end(),
+ Field1 = RD1->field_begin(),
+ Field1End = RD1->field_end();
+ for ( ; Field1 != Field1End && Field2 != Field2End; ++Field1, ++Field2) {
+ if (!isLayoutCompatible(C, *Field1, *Field2))
+ return false;
+ }
+ if (Field1 != Field1End || Field2 != Field2End)
+ return false;
+
+ return true;
+}
+
+/// \brief Check if two standard-layout unions are layout-compatible.
+/// (C++11 [class.mem] p18)
+bool isLayoutCompatibleUnion(ASTContext &C,
+ RecordDecl *RD1,
+ RecordDecl *RD2) {
+ llvm::SmallPtrSet<FieldDecl *, 8> UnmatchedFields;
+ for (RecordDecl::field_iterator Field2 = RD2->field_begin(),
+ Field2End = RD2->field_end();
+ Field2 != Field2End; ++Field2) {
+ UnmatchedFields.insert(*Field2);
+ }
+
+ for (RecordDecl::field_iterator Field1 = RD1->field_begin(),
+ Field1End = RD1->field_end();
+ Field1 != Field1End; ++Field1) {
+ llvm::SmallPtrSet<FieldDecl *, 8>::iterator
+ I = UnmatchedFields.begin(),
+ E = UnmatchedFields.end();
+
+ for ( ; I != E; ++I) {
+ if (isLayoutCompatible(C, *Field1, *I)) {
+ bool Result = UnmatchedFields.erase(*I);
+ (void) Result;
+ assert(Result);
+ break;
+ }
+ }
+ if (I == E)
+ return false;
+ }
+
+ return UnmatchedFields.empty();
+}
+
+bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) {
+ if (RD1->isUnion() != RD2->isUnion())
+ return false;
+
+ if (RD1->isUnion())
+ return isLayoutCompatibleUnion(C, RD1, RD2);
+ else
+ return isLayoutCompatibleStruct(C, RD1, RD2);
+}
+
+/// \brief Check if two types are layout-compatible in C++11 sense.
+bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) {
+ if (T1.isNull() || T2.isNull())
+ return false;
+
+ // C++11 [basic.types] p11:
+ // If two types T1 and T2 are the same type, then T1 and T2 are
+ // layout-compatible types.
+ if (C.hasSameType(T1, T2))
+ return true;
+
+ T1 = T1.getCanonicalType().getUnqualifiedType();
+ T2 = T2.getCanonicalType().getUnqualifiedType();
+
+ const Type::TypeClass TC1 = T1->getTypeClass();
+ const Type::TypeClass TC2 = T2->getTypeClass();
+
+ if (TC1 != TC2)
+ return false;
+
+ if (TC1 == Type::Enum) {
+ return isLayoutCompatible(C,
+ cast<EnumType>(T1)->getDecl(),
+ cast<EnumType>(T2)->getDecl());
+ } else if (TC1 == Type::Record) {
+ if (!T1->isStandardLayoutType() || !T2->isStandardLayoutType())
+ return false;
+
+ return isLayoutCompatible(C,
+ cast<RecordType>(T1)->getDecl(),
+ cast<RecordType>(T2)->getDecl());
+ }
+
+ return false;
+}
+}
+
+//===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----//
+
+namespace {
+/// \brief Given a type tag expression find the type tag itself.
+///
+/// \param TypeExpr Type tag expression, as it appears in user's code.
+///
+/// \param VD Declaration of an identifier that appears in a type tag.
+///
+/// \param MagicValue Type tag magic value.
+bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx,
+ const ValueDecl **VD, uint64_t *MagicValue) {
+ while(true) {
+ if (!TypeExpr)
+ return false;
+
+ TypeExpr = TypeExpr->IgnoreParenImpCasts()->IgnoreParenCasts();
+
+ switch (TypeExpr->getStmtClass()) {
+ case Stmt::UnaryOperatorClass: {
+ const UnaryOperator *UO = cast<UnaryOperator>(TypeExpr);
+ if (UO->getOpcode() == UO_AddrOf || UO->getOpcode() == UO_Deref) {
+ TypeExpr = UO->getSubExpr();
+ continue;
+ }
+ return false;
+ }
+
+ case Stmt::DeclRefExprClass: {
+ const DeclRefExpr *DRE = cast<DeclRefExpr>(TypeExpr);
+ *VD = DRE->getDecl();
+ return true;
+ }
+
+ case Stmt::IntegerLiteralClass: {
+ const IntegerLiteral *IL = cast<IntegerLiteral>(TypeExpr);
+ llvm::APInt MagicValueAPInt = IL->getValue();
+ if (MagicValueAPInt.getActiveBits() <= 64) {
+ *MagicValue = MagicValueAPInt.getZExtValue();
+ return true;
+ } else
+ return false;
+ }
+
+ case Stmt::BinaryConditionalOperatorClass:
+ case Stmt::ConditionalOperatorClass: {
+ const AbstractConditionalOperator *ACO =
+ cast<AbstractConditionalOperator>(TypeExpr);
+ bool Result;
+ if (ACO->getCond()->EvaluateAsBooleanCondition(Result, Ctx)) {
+ if (Result)
+ TypeExpr = ACO->getTrueExpr();
+ else
+ TypeExpr = ACO->getFalseExpr();
+ continue;
+ }
+ return false;
+ }
+
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator *BO = cast<BinaryOperator>(TypeExpr);
+ if (BO->getOpcode() == BO_Comma) {
+ TypeExpr = BO->getRHS();
+ continue;
+ }
+ return false;
+ }
+
+ default:
+ return false;
+ }
+ }
+}
+
+/// \brief Retrieve the C type corresponding to type tag TypeExpr.
+///
+/// \param TypeExpr Expression that specifies a type tag.
+///
+/// \param MagicValues Registered magic values.
+///
+/// \param FoundWrongKind Set to true if a type tag was found, but of a wrong
+/// kind.
+///
+/// \param TypeInfo Information about the corresponding C type.
+///
+/// \returns true if the corresponding C type was found.
+bool GetMatchingCType(
+ const IdentifierInfo *ArgumentKind,
+ const Expr *TypeExpr, const ASTContext &Ctx,
+ const llvm::DenseMap<Sema::TypeTagMagicValue,
+ Sema::TypeTagData> *MagicValues,
+ bool &FoundWrongKind,
+ Sema::TypeTagData &TypeInfo) {
+ FoundWrongKind = false;
+
+ // Variable declaration that has type_tag_for_datatype attribute.
+ const ValueDecl *VD = NULL;
+
+ uint64_t MagicValue;
+
+ if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue))
+ return false;
+
+ if (VD) {
+ for (specific_attr_iterator<TypeTagForDatatypeAttr>
+ I = VD->specific_attr_begin<TypeTagForDatatypeAttr>(),
+ E = VD->specific_attr_end<TypeTagForDatatypeAttr>();
+ I != E; ++I) {
+ if (I->getArgumentKind() != ArgumentKind) {
+ FoundWrongKind = true;
+ return false;
+ }
+ TypeInfo.Type = I->getMatchingCType();
+ TypeInfo.LayoutCompatible = I->getLayoutCompatible();
+ TypeInfo.MustBeNull = I->getMustBeNull();
+ return true;
+ }
+ return false;
+ }
+
+ if (!MagicValues)
+ return false;
+
+ llvm::DenseMap<Sema::TypeTagMagicValue,
+ Sema::TypeTagData>::const_iterator I =
+ MagicValues->find(std::make_pair(ArgumentKind, MagicValue));
+ if (I == MagicValues->end())
+ return false;
+
+ TypeInfo = I->second;
+ return true;
+}
+} // unnamed namespace
+
+void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind,
+ uint64_t MagicValue, QualType Type,
+ bool LayoutCompatible,
+ bool MustBeNull) {
+ if (!TypeTagForDatatypeMagicValues)
+ TypeTagForDatatypeMagicValues.reset(
+ new llvm::DenseMap<TypeTagMagicValue, TypeTagData>);
+
+ TypeTagMagicValue Magic(ArgumentKind, MagicValue);
+ (*TypeTagForDatatypeMagicValues)[Magic] =
+ TypeTagData(Type, LayoutCompatible, MustBeNull);
+}
+
+namespace {
+bool IsSameCharType(QualType T1, QualType T2) {
+ const BuiltinType *BT1 = T1->getAs<BuiltinType>();
+ if (!BT1)
+ return false;
+
+ const BuiltinType *BT2 = T2->getAs<BuiltinType>();
+ if (!BT2)
+ return false;
+
+ BuiltinType::Kind T1Kind = BT1->getKind();
+ BuiltinType::Kind T2Kind = BT2->getKind();
+
+ return (T1Kind == BuiltinType::SChar && T2Kind == BuiltinType::Char_S) ||
+ (T1Kind == BuiltinType::UChar && T2Kind == BuiltinType::Char_U) ||
+ (T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) ||
+ (T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar);
+}
+} // unnamed namespace
+
+void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
+ const Expr * const *ExprArgs) {
+ const IdentifierInfo *ArgumentKind = Attr->getArgumentKind();
+ bool IsPointerAttr = Attr->getIsPointer();
+
+ const Expr *TypeTagExpr = ExprArgs[Attr->getTypeTagIdx()];
+ bool FoundWrongKind;
+ TypeTagData TypeInfo;
+ if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context,
+ TypeTagForDatatypeMagicValues.get(),
+ FoundWrongKind, TypeInfo)) {
+ if (FoundWrongKind)
+ Diag(TypeTagExpr->getExprLoc(),
+ diag::warn_type_tag_for_datatype_wrong_kind)
+ << TypeTagExpr->getSourceRange();
+ return;
+ }
+
+ const Expr *ArgumentExpr = ExprArgs[Attr->getArgumentIdx()];
+ if (IsPointerAttr) {
+ // Skip implicit cast of pointer to `void *' (as a function argument).
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr))
+ if (ICE->getType()->isVoidPointerType())
+ ArgumentExpr = ICE->getSubExpr();
+ }
+ QualType ArgumentType = ArgumentExpr->getType();
+
+ // Passing a `void*' pointer shouldn't trigger a warning.
+ if (IsPointerAttr && ArgumentType->isVoidPointerType())
+ return;
+
+ if (TypeInfo.MustBeNull) {
+ // Type tag with matching void type requires a null pointer.
+ if (!ArgumentExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNotNull)) {
+ Diag(ArgumentExpr->getExprLoc(),
+ diag::warn_type_safety_null_pointer_required)
+ << ArgumentKind->getName()
+ << ArgumentExpr->getSourceRange()
+ << TypeTagExpr->getSourceRange();
+ }
+ return;
+ }
+
+ QualType RequiredType = TypeInfo.Type;
+ if (IsPointerAttr)
+ RequiredType = Context.getPointerType(RequiredType);
+
+ bool mismatch = false;
+ if (!TypeInfo.LayoutCompatible) {
+ mismatch = !Context.hasSameType(ArgumentType, RequiredType);
+
+ // C++11 [basic.fundamental] p1:
+ // Plain char, signed char, and unsigned char are three distinct types.
+ //
+ // But we treat plain `char' as equivalent to `signed char' or `unsigned
+ // char' depending on the current char signedness mode.
+ if (mismatch)
+ if ((IsPointerAttr && IsSameCharType(ArgumentType->getPointeeType(),
+ RequiredType->getPointeeType())) ||
+ (!IsPointerAttr && IsSameCharType(ArgumentType, RequiredType)))
+ mismatch = false;
+ } else
+ if (IsPointerAttr)
+ mismatch = !isLayoutCompatible(Context,
+ ArgumentType->getPointeeType(),
+ RequiredType->getPointeeType());
+ else
+ mismatch = !isLayoutCompatible(Context, ArgumentType, RequiredType);
+
+ if (mismatch)
+ Diag(ArgumentExpr->getExprLoc(), diag::warn_type_safety_type_mismatch)
+ << ArgumentType << ArgumentKind->getName()
+ << TypeInfo.LayoutCompatible << RequiredType
+ << ArgumentExpr->getSourceRange()
+ << TypeTagExpr->getSourceRange();
+}
+
OpenPOWER on IntegriCloud