summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaChecking.cpp')
-rw-r--r--lib/Sema/SemaChecking.cpp922
1 files changed, 782 insertions, 140 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 692a210..4e11b3a 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -12,32 +12,31 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/Initialization.h"
-#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/EvaluatedExprVisitor.h"
#include "clang/AST/Expr.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/Analysis/Analyses/FormatString.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Sema.h"
#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ConvertUTF.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;
@@ -488,8 +487,8 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
/// 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,
+void Sema::checkCall(NamedDecl *FDecl,
+ ArrayRef<const Expr *> Args,
unsigned NumProtoArgs,
bool IsMemberFunction,
SourceLocation Loc,
@@ -503,41 +502,40 @@ void Sema::checkCall(NamedDecl *FDecl, Expr **Args,
for (specific_attr_iterator<FormatAttr>
I = FDecl->specific_attr_begin<FormatAttr>(),
E = FDecl->specific_attr_end<FormatAttr>(); I != E ; ++I)
- if (CheckFormatArguments(*I, Args, NumArgs, IsMemberFunction, CallType,
- Loc, Range))
+ if (CheckFormatArguments(*I, Args, 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) {
+ for (unsigned ArgIdx = NumProtoArgs; ArgIdx < Args.size(); ++ArgIdx) {
// Args[ArgIdx] can be null in malformed code.
- if (Expr *Arg = Args[ArgIdx])
+ if (const Expr *Arg = Args[ArgIdx])
variadicArgumentPODCheck(Arg, CallType);
}
for (specific_attr_iterator<NonNullAttr>
I = FDecl->specific_attr_begin<NonNullAttr>(),
E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I)
- CheckNonNullArguments(*I, Args, Loc);
+ CheckNonNullArguments(*I, Args.data(), 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);
+ CheckArgumentWithTypeTag(*i, Args.data());
}
}
/// 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,
+void Sema::CheckConstructorCall(FunctionDecl *FDecl,
+ ArrayRef<const Expr *> Args,
const FunctionProtoType *Proto,
SourceLocation Loc) {
VariadicCallType CallType =
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
- checkCall(FDecl, Args, NumArgs, Proto->getNumArgs(),
+ checkCall(FDecl, Args, Proto->getNumArgs(),
/*IsMemberFunction=*/true, Loc, SourceRange(), CallType);
}
@@ -561,7 +559,8 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
++Args;
--NumArgs;
}
- checkCall(FDecl, Args, NumArgs, NumProtoArgs,
+ checkCall(FDecl, llvm::makeArrayRef<const Expr *>(Args, NumArgs),
+ NumProtoArgs,
IsMemberFunction, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -591,7 +590,8 @@ bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
VariadicCallType CallType =
Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply;
- checkCall(Method, Args, NumArgs, Method->param_size(),
+ checkCall(Method, llvm::makeArrayRef<const Expr *>(Args, NumArgs),
+ Method->param_size(),
/*IsMemberFunction=*/false,
lbrac, Method->getSourceRange(), CallType);
@@ -612,7 +612,9 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
Proto && Proto->isVariadic() ? VariadicBlock : VariadicDoesNotApply ;
unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
- checkCall(NDecl, TheCall->getArgs(), TheCall->getNumArgs(),
+ checkCall(NDecl,
+ llvm::makeArrayRef<const Expr *>(TheCall->getArgs(),
+ TheCall->getNumArgs()),
NumProtoArgs, /*IsMemberFunction=*/false,
TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -1646,8 +1648,8 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
// 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,
+Sema::checkFormatStringExpr(const Expr *E, ArrayRef<const Expr *> Args,
+ bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg,
FormatStringType Type, VariadicCallType CallType,
bool inFunctionCall) {
@@ -1672,13 +1674,13 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
const AbstractConditionalOperator *C =
cast<AbstractConditionalOperator>(E);
StringLiteralCheckType Left =
- checkFormatStringExpr(C->getTrueExpr(), Args, NumArgs,
+ checkFormatStringExpr(C->getTrueExpr(), Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, inFunctionCall);
if (Left == SLCT_NotALiteral)
return SLCT_NotALiteral;
StringLiteralCheckType Right =
- checkFormatStringExpr(C->getFalseExpr(), Args, NumArgs,
+ checkFormatStringExpr(C->getFalseExpr(), Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, inFunctionCall);
return Left < Right ? Left : Right;
@@ -1729,7 +1731,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
if (InitList->isStringLiteralInit())
Init = InitList->getInit(0)->IgnoreParenImpCasts();
}
- return checkFormatStringExpr(Init, Args, NumArgs,
+ return checkFormatStringExpr(Init, Args,
HasVAListArg, format_idx,
firstDataArg, Type, CallType,
/*inFunctionCall*/false);
@@ -1787,7 +1789,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
--ArgIndex;
const Expr *Arg = CE->getArg(ArgIndex - 1);
- return checkFormatStringExpr(Arg, Args, NumArgs,
+ return checkFormatStringExpr(Arg, Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, inFunctionCall);
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
@@ -1795,7 +1797,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
const Expr *Arg = CE->getArg(0);
- return checkFormatStringExpr(Arg, Args, NumArgs,
+ return checkFormatStringExpr(Arg, Args,
HasVAListArg, format_idx,
firstDataArg, Type, CallType,
inFunctionCall);
@@ -1815,7 +1817,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
StrE = cast<StringLiteral>(E);
if (StrE) {
- CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx,
+ CheckFormatString(StrE, E, Args, HasVAListArg, format_idx,
firstDataArg, Type, inFunctionCall, CallType);
return SLCT_CheckedLiteral;
}
@@ -1836,8 +1838,20 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
e = NonNull->args_end();
i != e; ++i) {
const Expr *ArgExpr = ExprArgs[*i];
- if (ArgExpr->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNotNull))
+
+ // As a special case, transparent unions initialized with zero are
+ // considered null for the purposes of the nonnull attribute.
+ if (const RecordType *UT = ArgExpr->getType()->getAsUnionType()) {
+ if (UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ if (const CompoundLiteralExpr *CLE =
+ dyn_cast<CompoundLiteralExpr>(ArgExpr))
+ if (const InitListExpr *ILE =
+ dyn_cast<InitListExpr>(CLE->getInitializer()))
+ ArgExpr = ILE->getInit(0);
+ }
+
+ bool Result;
+ if (ArgExpr->EvaluateAsBooleanCondition(Result, Context) && !Result)
Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange();
}
}
@@ -1856,25 +1870,26 @@ Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
/// CheckFormatArguments - Check calls to printf and scanf (and similar
/// functions) for correct use of format strings.
/// Returns true if a format string has been fully checked.
-bool Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
- unsigned NumArgs, bool IsCXXMember,
+bool Sema::CheckFormatArguments(const FormatAttr *Format,
+ ArrayRef<const Expr *> Args,
+ bool IsCXXMember,
VariadicCallType CallType,
SourceLocation Loc, SourceRange Range) {
FormatStringInfo FSI;
if (getFormatStringInfo(Format, IsCXXMember, &FSI))
- return CheckFormatArguments(Args, NumArgs, FSI.HasVAListArg, FSI.FormatIdx,
+ return CheckFormatArguments(Args, FSI.HasVAListArg, FSI.FormatIdx,
FSI.FirstDataArg, GetFormatStringType(Format),
CallType, Loc, Range);
return false;
}
-bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
+bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
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) {
+ if (format_idx >= Args.size()) {
Diag(Loc, diag::warn_missing_format_string) << Range;
return false;
}
@@ -1894,7 +1909,7 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
StringLiteralCheckType CT =
- checkFormatStringExpr(OrigFormatExpr, Args, NumArgs, HasVAListArg,
+ checkFormatStringExpr(OrigFormatExpr, Args, HasVAListArg,
format_idx, firstDataArg, Type, CallType);
if (CT != SLCT_NotALiteral)
// Literal format string found, check done!
@@ -1915,7 +1930,7 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
// If there are no arguments specified, warn with -Wformat-security, otherwise
// warn only with -Wformat-nonliteral.
- if (NumArgs == format_idx+1)
+ if (Args.size() == format_idx+1)
Diag(Args[format_idx]->getLocStart(),
diag::warn_format_nonliteral_noargs)
<< OrigFormatExpr->getSourceRange();
@@ -1936,8 +1951,7 @@ protected:
const unsigned NumDataArgs;
const char *Beg; // Start of format string.
const bool HasVAListArg;
- const Expr * const *Args;
- const unsigned NumArgs;
+ ArrayRef<const Expr *> Args;
unsigned FormatIdx;
llvm::BitVector CoveredArgs;
bool usesPositionalArgs;
@@ -1948,13 +1962,13 @@ public:
CheckFormatHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, const char *beg, bool hasVAListArg,
- Expr **args, unsigned numArgs,
+ ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType callType)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
FirstDataArg(firstDataArg), NumDataArgs(numDataArgs),
Beg(beg), HasVAListArg(hasVAListArg),
- Args(args), NumArgs(numArgs), FormatIdx(formatIdx),
+ Args(Args), FormatIdx(formatIdx),
usesPositionalArgs(false), atFirstArg(true),
inFunctionCall(inFunctionCall), CallType(callType) {
CoveredArgs.resize(numDataArgs);
@@ -2066,7 +2080,7 @@ void CheckFormatHandler::HandleInvalidLengthModifier(
CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
// See if we know how to fix this length modifier.
- llvm::Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
if (FixedLM) {
EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
getLocationOfByte(LM.getStart()),
@@ -2099,7 +2113,7 @@ void CheckFormatHandler::HandleNonStandardLengthModifier(
CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
// See if we know how to fix this length modifier.
- llvm::Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
if (FixedLM) {
EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
<< LM.toString() << 0,
@@ -2126,7 +2140,7 @@ void CheckFormatHandler::HandleNonStandardConversionSpecifier(
using namespace analyze_format_string;
// See if we know how to fix this conversion specifier.
- llvm::Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
+ Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
if (FixedCS) {
EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
<< CS.toString() << /*conversion specifier*/1,
@@ -2346,11 +2360,11 @@ public:
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjC,
const char *beg, bool hasVAListArg,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType CallType)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
- numDataArgs, beg, hasVAListArg, Args, NumArgs,
+ numDataArgs, beg, hasVAListArg, Args,
formatIdx, inFunctionCall, CallType), ObjCContext(isObjC)
{}
@@ -2690,12 +2704,24 @@ static bool requiresParensToAddCast(const Expr *E) {
switch (Inside->getStmtClass()) {
case Stmt::ArraySubscriptExprClass:
case Stmt::CallExprClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::CXXBoolLiteralExprClass:
case Stmt::DeclRefExprClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::IntegerLiteralClass:
case Stmt::MemberExprClass:
+ case Stmt::ObjCArrayLiteralClass:
+ case Stmt::ObjCBoolLiteralExprClass:
+ case Stmt::ObjCBoxedExprClass:
+ case Stmt::ObjCDictionaryLiteralClass:
+ case Stmt::ObjCEncodeExprClass:
case Stmt::ObjCIvarRefExprClass:
case Stmt::ObjCMessageExprClass:
case Stmt::ObjCPropertyRefExprClass:
+ case Stmt::ObjCStringLiteralClass:
+ case Stmt::ObjCSubscriptRefExprClass:
case Stmt::ParenExprClass:
+ case Stmt::StringLiteralClass:
case Stmt::UnaryOperatorClass:
return false;
default:
@@ -2717,8 +2743,8 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (!AT.isValid())
return true;
- QualType IntendedTy = E->getType();
- if (AT.matchesType(S.Context, IntendedTy))
+ QualType ExprTy = E->getType();
+ if (AT.matchesType(S.Context, ExprTy))
return true;
// Look through argument promotions for our error message's reported type.
@@ -2729,7 +2755,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (ICE->getCastKind() == CK_IntegralCast ||
ICE->getCastKind() == CK_FloatingCast) {
E = ICE->getSubExpr();
- IntendedTy = E->getType();
+ ExprTy = E->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
@@ -2737,22 +2763,63 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (ICE->getType() == S.Context.IntTy ||
ICE->getType() == S.Context.UnsignedIntTy) {
// All further checking is done on the subexpression.
- if (AT.matchesType(S.Context, IntendedTy))
+ if (AT.matchesType(S.Context, ExprTy))
return true;
}
}
+ } else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) {
+ // Special case for 'a', which has type 'int' in C.
+ // Note, however, that we do /not/ want to treat multibyte constants like
+ // 'MooV' as characters! This form is deprecated but still exists.
+ if (ExprTy == S.Context.IntTy)
+ if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue()))
+ ExprTy = S.Context.CharTy;
+ }
+
+ // %C in an Objective-C context prints a unichar, not a wchar_t.
+ // If the argument is an integer of some kind, believe the %C and suggest
+ // a cast instead of changing the conversion specifier.
+ QualType IntendedTy = ExprTy;
+ if (ObjCContext &&
+ FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) {
+ if (ExprTy->isIntegralOrUnscopedEnumerationType() &&
+ !ExprTy->isCharType()) {
+ // 'unichar' is defined as a typedef of unsigned short, but we should
+ // prefer using the typedef if it is visible.
+ IntendedTy = S.Context.UnsignedShortTy;
+
+ LookupResult Result(S, &S.Context.Idents.get("unichar"), E->getLocStart(),
+ Sema::LookupOrdinaryName);
+ if (S.LookupName(Result, S.getCurScope())) {
+ NamedDecl *ND = Result.getFoundDecl();
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(ND))
+ if (TD->getUnderlyingType() == IntendedTy)
+ IntendedTy = S.Context.getTypedefType(TD);
+ }
+ }
}
+ // Special-case some of Darwin's platform-independence types by suggesting
+ // casts to primitive types that are known to be large enough.
+ bool ShouldNotPrintDirectly = false;
if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
- // Special-case some of Darwin's platform-independence types.
- if (const TypedefType *UserTy = IntendedTy->getAs<TypedefType>()) {
+ // Use a 'while' to peel off layers of typedefs.
+ QualType TyTy = IntendedTy;
+ while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) {
StringRef Name = UserTy->getDecl()->getName();
- IntendedTy = llvm::StringSwitch<QualType>(Name)
+ QualType CastTy = llvm::StringSwitch<QualType>(Name)
.Case("NSInteger", S.Context.LongTy)
.Case("NSUInteger", S.Context.UnsignedLongTy)
.Case("SInt32", S.Context.IntTy)
.Case("UInt32", S.Context.UnsignedIntTy)
- .Default(IntendedTy);
+ .Default(QualType());
+
+ if (!CastTy.isNull()) {
+ ShouldNotPrintDirectly = true;
+ IntendedTy = CastTy;
+ break;
+ }
+ TyTy = UserTy->desugar();
}
}
@@ -2769,7 +2836,19 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
- if (IntendedTy != E->getType()) {
+ if (IntendedTy == ExprTy) {
+ // In this case, the specifier is wrong and should be changed to match
+ // the argument.
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << IntendedTy
+ << E->getSourceRange(),
+ E->getLocStart(),
+ /*IsStringLocation*/false,
+ SpecRange,
+ FixItHint::CreateReplacement(SpecRange, os.str()));
+
+ } else {
// The canonical type for formatting this value is different from the
// actual type of the expression. (This occurs, for example, with Darwin's
// NSInteger on 32-bit platforms, where it is typedef'd as 'int', but
@@ -2807,26 +2886,28 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
Hints.push_back(FixItHint::CreateInsertion(After, ")"));
}
- // We extract the name from the typedef because we don't want to show
- // the underlying type in the diagnostic.
- const TypedefType *UserTy = cast<TypedefType>(E->getType());
- StringRef Name = UserTy->getDecl()->getName();
-
- // Finally, emit the diagnostic.
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast)
- << Name << IntendedTy
- << E->getSourceRange(),
- E->getLocStart(), /*IsStringLocation=*/false,
- SpecRange, Hints);
- } else {
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << IntendedTy
- << E->getSourceRange(),
- E->getLocStart(),
- /*IsStringLocation*/false,
- SpecRange,
- FixItHint::CreateReplacement(SpecRange, os.str()));
+ if (ShouldNotPrintDirectly) {
+ // The expression has a type that should not be printed directly.
+ // We extract the name from the typedef because we don't want to show
+ // the underlying type in the diagnostic.
+ StringRef Name = cast<TypedefType>(ExprTy)->getDecl()->getName();
+
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast)
+ << Name << IntendedTy
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation=*/false,
+ SpecRange, Hints);
+ } else {
+ // In this case, the expression could be printed using a different
+ // specifier, but we've decided that the specifier is probably correct
+ // and we should cast instead. Just use the normal warning message.
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << ExprTy
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/false,
+ SpecRange, Hints);
+ }
}
} else {
const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
@@ -2834,17 +2915,17 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// 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) {
+ if (S.isValidVarArgType(ExprTy) == Sema::VAK_Invalid) {
unsigned DiagKind;
- if (E->getType()->isObjCObjectType())
+ if (ExprTy->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()
+ << S.getLangOpts().CPlusPlus11
+ << ExprTy
<< CallType
<< AT.getRepresentativeTypeName(S.Context)
<< CSR
@@ -2855,7 +2936,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
} else
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << E->getType()
+ << AT.getRepresentativeTypeName(S.Context) << ExprTy
<< CSR
<< E->getSourceRange(),
E->getLocStart(), /*IsStringLocation*/false, CSR);
@@ -2872,12 +2953,12 @@ public:
CheckScanfHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, const char *beg, bool hasVAListArg,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType CallType)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, beg, hasVAListArg,
- Args, NumArgs, formatIdx, inFunctionCall, CallType)
+ Args, formatIdx, inFunctionCall, CallType)
{}
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
@@ -3029,7 +3110,7 @@ bool CheckScanfHandler::HandleScanfSpecifier(
void Sema::CheckFormatString(const StringLiteral *FExpr,
const Expr *OrigFormatExpr,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<const Expr *> Args,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
bool inFunctionCall, VariadicCallType CallType) {
@@ -3047,7 +3128,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
StringRef StrRef = FExpr->getString();
const char *Str = StrRef.data();
unsigned StrLen = StrRef.size();
- const unsigned numDataArgs = NumArgs - firstDataArg;
+ const unsigned numDataArgs = Args.size() - firstDataArg;
// CHECK: empty format string?
if (StrLen == 0 && numDataArgs > 0) {
@@ -3061,7 +3142,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
if (Type == FST_Printf || Type == FST_NSString) {
CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
numDataArgs, (Type == FST_NSString),
- Str, HasVAListArg, Args, NumArgs, format_idx,
+ Str, HasVAListArg, Args, format_idx,
inFunctionCall, CallType);
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
@@ -3070,7 +3151,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
H.DoneProcessing();
} else if (Type == FST_Scanf) {
CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs,
- Str, HasVAListArg, Args, NumArgs, format_idx,
+ Str, HasVAListArg, Args, format_idx,
inFunctionCall, CallType);
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
@@ -3177,7 +3258,8 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
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())
+ if (!PointeeTy->isIncompleteType() &&
+ (Context.getTypeSize(PointeeTy) == Context.getCharWidth()))
ActionIdx = 2; // If the pointee's size is sizeof(char),
// suggest an explicit length.
@@ -3922,7 +4004,11 @@ struct IntRange {
unsigned NumPositive = Enum->getNumPositiveBits();
unsigned NumNegative = Enum->getNumNegativeBits();
- return IntRange(std::max(NumPositive, NumNegative), NumNegative == 0);
+ if (NumNegative == 0)
+ return IntRange(NumPositive, true/*NonNegative*/);
+ else
+ return IntRange(std::max(NumPositive + 1, NumNegative),
+ false/*NonNegative*/);
}
const BuiltinType *BT = cast<BuiltinType>(T);
@@ -4328,38 +4414,108 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
Expr *Constant, Expr *Other,
llvm::APSInt Value,
bool RhsConstant) {
+ // 0 values are handled later by CheckTrivialUnsignedComparison().
+ if (Value == 0)
+ return;
+
BinaryOperatorKind op = E->getOpcode();
QualType OtherT = Other->getType();
QualType ConstantT = Constant->getType();
+ QualType CommonT = E->getLHS()->getType();
if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT))
return;
assert((OtherT->isIntegerType() && ConstantT->isIntegerType())
&& "comparison with non-integer type");
- // FIXME. handle cases for signedness to catch (signed char)N == 200
+
+ bool ConstantSigned = ConstantT->isSignedIntegerType();
+ bool CommonSigned = CommonT->isSignedIntegerType();
+
+ bool EqualityOnly = false;
+
+ // TODO: Investigate using GetExprRange() to get tighter bounds on
+ // on the bit ranges.
IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
- IntRange LitRange = GetValueRange(S.Context, Value, Value.getBitWidth());
- if (OtherRange.Width >= LitRange.Width)
- return;
+ unsigned OtherWidth = OtherRange.Width;
+
+ if (CommonSigned) {
+ // The common type is signed, therefore no signed to unsigned conversion.
+ if (!OtherRange.NonNegative) {
+ // Check that the constant is representable in type OtherT.
+ if (ConstantSigned) {
+ if (OtherWidth >= Value.getMinSignedBits())
+ return;
+ } else { // !ConstantSigned
+ if (OtherWidth >= Value.getActiveBits() + 1)
+ return;
+ }
+ } else { // !OtherSigned
+ // Check that the constant is representable in type OtherT.
+ // Negative values are out of range.
+ if (ConstantSigned) {
+ if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits())
+ return;
+ } else { // !ConstantSigned
+ if (OtherWidth >= Value.getActiveBits())
+ return;
+ }
+ }
+ } else { // !CommonSigned
+ if (OtherRange.NonNegative) {
+ if (OtherWidth >= Value.getActiveBits())
+ return;
+ } else if (!OtherRange.NonNegative && !ConstantSigned) {
+ // Check to see if the constant is representable in OtherT.
+ if (OtherWidth > Value.getActiveBits())
+ return;
+ // Check to see if the constant is equivalent to a negative value
+ // cast to CommonT.
+ if (S.Context.getIntWidth(ConstantT) == S.Context.getIntWidth(CommonT) &&
+ Value.isNegative() && Value.getMinSignedBits() <= OtherWidth)
+ return;
+ // The constant value rests between values that OtherT can represent after
+ // conversion. Relational comparison still works, but equality
+ // comparisons will be tautological.
+ EqualityOnly = true;
+ } else { // OtherSigned && ConstantSigned
+ assert(0 && "Two signed types converted to unsigned types.");
+ }
+ }
+
+ bool PositiveConstant = !ConstantSigned || Value.isNonNegative();
+
bool IsTrue = true;
- if (op == BO_EQ)
- IsTrue = false;
- else if (op == BO_NE)
- IsTrue = true;
- else if (RhsConstant) {
+ if (op == BO_EQ || op == BO_NE) {
+ IsTrue = op == BO_NE;
+ } else if (EqualityOnly) {
+ return;
+ } else if (RhsConstant) {
if (op == BO_GT || op == BO_GE)
- IsTrue = !LitRange.NonNegative;
+ IsTrue = !PositiveConstant;
else // op == BO_LT || op == BO_LE
- IsTrue = LitRange.NonNegative;
+ IsTrue = PositiveConstant;
} else {
if (op == BO_LT || op == BO_LE)
- IsTrue = !LitRange.NonNegative;
+ IsTrue = !PositiveConstant;
else // op == BO_GT || op == BO_GE
- IsTrue = LitRange.NonNegative;
+ IsTrue = PositiveConstant;
}
- SmallString<16> PrettySourceValue(Value.toString(10));
+
+ // If this is a comparison to an enum constant, include that
+ // constant in the diagnostic.
+ const EnumConstantDecl *ED = 0;
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Constant))
+ ED = dyn_cast<EnumConstantDecl>(DR->getDecl());
+
+ SmallString<64> PrettySourceValue;
+ llvm::raw_svector_ostream OS(PrettySourceValue);
+ if (ED)
+ OS << '\'' << *ED << "' (" << Value << ")";
+ else
+ OS << Value;
+
S.Diag(E->getOperatorLoc(), diag::warn_out_of_range_compare)
- << PrettySourceValue << OtherT << IsTrue
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ << OS.str() << OtherT << IsTrue
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
}
/// Analyze the operands of the given comparison. Implements the
@@ -4800,7 +4956,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)
== Expr::NPCK_GNUNull) && !Target->isAnyPointerType()
&& !Target->isBlockPointerType() && !Target->isMemberPointerType()
- && Target->isScalarType()) {
+ && Target->isScalarType() && !Target->isNullPtrType()) {
SourceLocation Loc = E->getSourceRange().getBegin();
if (Loc.isMacroID())
Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
@@ -4843,7 +4999,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// People want to build with -Wshorten-64-to-32 and not -Wconversion.
if (S.SourceMgr.isInSystemMacro(CC))
return;
-
+
if (TargetRange.Width == 32 && S.Context.getIntWidth(E->getType()) == 64)
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_64_32,
/* pruneControlFlow */ true);
@@ -4887,10 +5043,8 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (const EnumType *SourceEnum = Source->getAs<EnumType>())
if (const EnumType *TargetEnum = Target->getAs<EnumType>())
- if ((SourceEnum->getDecl()->getIdentifier() ||
- SourceEnum->getDecl()->getTypedefNameForAnonDecl()) &&
- (TargetEnum->getDecl()->getIdentifier() ||
- TargetEnum->getDecl()->getTypedefNameForAnonDecl()) &&
+ if (SourceEnum->getDecl()->hasNameForLinkage() &&
+ TargetEnum->getDecl()->hasNameForLinkage() &&
SourceEnum != TargetEnum) {
if (S.SourceMgr.isInSystemMacro(CC))
return;
@@ -5046,6 +5200,462 @@ void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) {
AnalyzeImplicitConversions(*this, E, CC);
}
+/// Diagnose when expression is an integer constant expression and its evaluation
+/// results in integer overflow
+void Sema::CheckForIntOverflow (Expr *E) {
+ if (isa<BinaryOperator>(E->IgnoreParens())) {
+ llvm::SmallVector<PartialDiagnosticAt, 4> Diags;
+ E->EvaluateForOverflow(Context, &Diags);
+ }
+}
+
+namespace {
+/// \brief Visitor for expressions which looks for unsequenced operations on the
+/// same object.
+class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
+ /// \brief A tree of sequenced regions within an expression. Two regions are
+ /// unsequenced if one is an ancestor or a descendent of the other. When we
+ /// finish processing an expression with sequencing, such as a comma
+ /// expression, we fold its tree nodes into its parent, since they are
+ /// unsequenced with respect to nodes we will visit later.
+ class SequenceTree {
+ struct Value {
+ explicit Value(unsigned Parent) : Parent(Parent), Merged(false) {}
+ unsigned Parent : 31;
+ bool Merged : 1;
+ };
+ llvm::SmallVector<Value, 8> Values;
+
+ public:
+ /// \brief A region within an expression which may be sequenced with respect
+ /// to some other region.
+ class Seq {
+ explicit Seq(unsigned N) : Index(N) {}
+ unsigned Index;
+ friend class SequenceTree;
+ public:
+ Seq() : Index(0) {}
+ };
+
+ SequenceTree() { Values.push_back(Value(0)); }
+ Seq root() const { return Seq(0); }
+
+ /// \brief Create a new sequence of operations, which is an unsequenced
+ /// subset of \p Parent. This sequence of operations is sequenced with
+ /// respect to other children of \p Parent.
+ Seq allocate(Seq Parent) {
+ Values.push_back(Value(Parent.Index));
+ return Seq(Values.size() - 1);
+ }
+
+ /// \brief Merge a sequence of operations into its parent.
+ void merge(Seq S) {
+ Values[S.Index].Merged = true;
+ }
+
+ /// \brief Determine whether two operations are unsequenced. This operation
+ /// is asymmetric: \p Cur should be the more recent sequence, and \p Old
+ /// should have been merged into its parent as appropriate.
+ bool isUnsequenced(Seq Cur, Seq Old) {
+ unsigned C = representative(Cur.Index);
+ unsigned Target = representative(Old.Index);
+ while (C >= Target) {
+ if (C == Target)
+ return true;
+ C = Values[C].Parent;
+ }
+ return false;
+ }
+
+ private:
+ /// \brief Pick a representative for a sequence.
+ unsigned representative(unsigned K) {
+ if (Values[K].Merged)
+ // Perform path compression as we go.
+ return Values[K].Parent = representative(Values[K].Parent);
+ return K;
+ }
+ };
+
+ /// An object for which we can track unsequenced uses.
+ typedef NamedDecl *Object;
+
+ /// Different flavors of object usage which we track. We only track the
+ /// least-sequenced usage of each kind.
+ enum UsageKind {
+ /// A read of an object. Multiple unsequenced reads are OK.
+ UK_Use,
+ /// A modification of an object which is sequenced before the value
+ /// computation of the expression, such as ++n.
+ UK_ModAsValue,
+ /// A modification of an object which is not sequenced before the value
+ /// computation of the expression, such as n++.
+ UK_ModAsSideEffect,
+
+ UK_Count = UK_ModAsSideEffect + 1
+ };
+
+ struct Usage {
+ Usage() : Use(0), Seq() {}
+ Expr *Use;
+ SequenceTree::Seq Seq;
+ };
+
+ struct UsageInfo {
+ UsageInfo() : Diagnosed(false) {}
+ Usage Uses[UK_Count];
+ /// Have we issued a diagnostic for this variable already?
+ bool Diagnosed;
+ };
+ typedef llvm::SmallDenseMap<Object, UsageInfo, 16> UsageInfoMap;
+
+ Sema &SemaRef;
+ /// Sequenced regions within the expression.
+ SequenceTree Tree;
+ /// Declaration modifications and references which we have seen.
+ UsageInfoMap UsageMap;
+ /// The region we are currently within.
+ SequenceTree::Seq Region;
+ /// Filled in with declarations which were modified as a side-effect
+ /// (that is, post-increment operations).
+ llvm::SmallVectorImpl<std::pair<Object, Usage> > *ModAsSideEffect;
+ /// Expressions to check later. We defer checking these to reduce
+ /// stack usage.
+ llvm::SmallVectorImpl<Expr*> &WorkList;
+
+ /// RAII object wrapping the visitation of a sequenced subexpression of an
+ /// expression. At the end of this process, the side-effects of the evaluation
+ /// become sequenced with respect to the value computation of the result, so
+ /// we downgrade any UK_ModAsSideEffect within the evaluation to
+ /// UK_ModAsValue.
+ struct SequencedSubexpression {
+ SequencedSubexpression(SequenceChecker &Self)
+ : Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) {
+ Self.ModAsSideEffect = &ModAsSideEffect;
+ }
+ ~SequencedSubexpression() {
+ for (unsigned I = 0, E = ModAsSideEffect.size(); I != E; ++I) {
+ UsageInfo &U = Self.UsageMap[ModAsSideEffect[I].first];
+ U.Uses[UK_ModAsSideEffect] = ModAsSideEffect[I].second;
+ Self.addUsage(U, ModAsSideEffect[I].first,
+ ModAsSideEffect[I].second.Use, UK_ModAsValue);
+ }
+ Self.ModAsSideEffect = OldModAsSideEffect;
+ }
+
+ SequenceChecker &Self;
+ llvm::SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect;
+ llvm::SmallVectorImpl<std::pair<Object, Usage> > *OldModAsSideEffect;
+ };
+
+ /// \brief Find the object which is produced by the specified expression,
+ /// if any.
+ Object getObject(Expr *E, bool Mod) const {
+ E = E->IgnoreParenCasts();
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec))
+ return getObject(UO->getSubExpr(), Mod);
+ } else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Comma)
+ return getObject(BO->getRHS(), Mod);
+ if (Mod && BO->isAssignmentOp())
+ return getObject(BO->getLHS(), Mod);
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ // FIXME: Check for more interesting cases, like "x.n = ++x.n".
+ if (isa<CXXThisExpr>(ME->getBase()->IgnoreParenCasts()))
+ return ME->getMemberDecl();
+ } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ // FIXME: If this is a reference, map through to its value.
+ return DRE->getDecl();
+ return 0;
+ }
+
+ /// \brief Note that an object was modified or used by an expression.
+ void addUsage(UsageInfo &UI, Object O, Expr *Ref, UsageKind UK) {
+ Usage &U = UI.Uses[UK];
+ if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) {
+ if (UK == UK_ModAsSideEffect && ModAsSideEffect)
+ ModAsSideEffect->push_back(std::make_pair(O, U));
+ U.Use = Ref;
+ U.Seq = Region;
+ }
+ }
+ /// \brief Check whether a modification or use conflicts with a prior usage.
+ void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind,
+ bool IsModMod) {
+ if (UI.Diagnosed)
+ return;
+
+ const Usage &U = UI.Uses[OtherKind];
+ if (!U.Use || !Tree.isUnsequenced(Region, U.Seq))
+ return;
+
+ Expr *Mod = U.Use;
+ Expr *ModOrUse = Ref;
+ if (OtherKind == UK_Use)
+ std::swap(Mod, ModOrUse);
+
+ SemaRef.Diag(Mod->getExprLoc(),
+ IsModMod ? diag::warn_unsequenced_mod_mod
+ : diag::warn_unsequenced_mod_use)
+ << O << SourceRange(ModOrUse->getExprLoc());
+ UI.Diagnosed = true;
+ }
+
+ void notePreUse(Object O, Expr *Use) {
+ UsageInfo &U = UsageMap[O];
+ // Uses conflict with other modifications.
+ checkUsage(O, U, Use, UK_ModAsValue, false);
+ }
+ void notePostUse(Object O, Expr *Use) {
+ UsageInfo &U = UsageMap[O];
+ checkUsage(O, U, Use, UK_ModAsSideEffect, false);
+ addUsage(U, O, Use, UK_Use);
+ }
+
+ void notePreMod(Object O, Expr *Mod) {
+ UsageInfo &U = UsageMap[O];
+ // Modifications conflict with other modifications and with uses.
+ checkUsage(O, U, Mod, UK_ModAsValue, true);
+ checkUsage(O, U, Mod, UK_Use, false);
+ }
+ void notePostMod(Object O, Expr *Use, UsageKind UK) {
+ UsageInfo &U = UsageMap[O];
+ checkUsage(O, U, Use, UK_ModAsSideEffect, true);
+ addUsage(U, O, Use, UK);
+ }
+
+public:
+ SequenceChecker(Sema &S, Expr *E,
+ llvm::SmallVectorImpl<Expr*> &WorkList)
+ : EvaluatedExprVisitor<SequenceChecker>(S.Context), SemaRef(S),
+ Region(Tree.root()), ModAsSideEffect(0), WorkList(WorkList) {
+ Visit(E);
+ }
+
+ void VisitStmt(Stmt *S) {
+ // Skip all statements which aren't expressions for now.
+ }
+
+ void VisitExpr(Expr *E) {
+ // By default, just recurse to evaluated subexpressions.
+ EvaluatedExprVisitor<SequenceChecker>::VisitStmt(E);
+ }
+
+ void VisitCastExpr(CastExpr *E) {
+ Object O = Object();
+ if (E->getCastKind() == CK_LValueToRValue)
+ O = getObject(E->getSubExpr(), false);
+
+ if (O)
+ notePreUse(O, E);
+ VisitExpr(E);
+ if (O)
+ notePostUse(O, E);
+ }
+
+ void VisitBinComma(BinaryOperator *BO) {
+ // C++11 [expr.comma]p1:
+ // Every value computation and side effect associated with the left
+ // expression is sequenced before every value computation and side
+ // effect associated with the right expression.
+ SequenceTree::Seq LHS = Tree.allocate(Region);
+ SequenceTree::Seq RHS = Tree.allocate(Region);
+ SequenceTree::Seq OldRegion = Region;
+
+ {
+ SequencedSubexpression SeqLHS(*this);
+ Region = LHS;
+ Visit(BO->getLHS());
+ }
+
+ Region = RHS;
+ Visit(BO->getRHS());
+
+ Region = OldRegion;
+
+ // Forget that LHS and RHS are sequenced. They are both unsequenced
+ // with respect to other stuff.
+ Tree.merge(LHS);
+ Tree.merge(RHS);
+ }
+
+ void VisitBinAssign(BinaryOperator *BO) {
+ // The modification is sequenced after the value computation of the LHS
+ // and RHS, so check it before inspecting the operands and update the
+ // map afterwards.
+ Object O = getObject(BO->getLHS(), true);
+ if (!O)
+ return VisitExpr(BO);
+
+ notePreMod(O, BO);
+
+ // C++11 [expr.ass]p7:
+ // E1 op= E2 is equivalent to E1 = E1 op E2, except that E1 is evaluated
+ // only once.
+ //
+ // Therefore, for a compound assignment operator, O is considered used
+ // everywhere except within the evaluation of E1 itself.
+ if (isa<CompoundAssignOperator>(BO))
+ notePreUse(O, BO);
+
+ Visit(BO->getLHS());
+
+ if (isa<CompoundAssignOperator>(BO))
+ notePostUse(O, BO);
+
+ Visit(BO->getRHS());
+
+ notePostMod(O, BO, UK_ModAsValue);
+ }
+ void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) {
+ VisitBinAssign(CAO);
+ }
+
+ void VisitUnaryPreInc(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
+ void VisitUnaryPreDec(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
+ void VisitUnaryPreIncDec(UnaryOperator *UO) {
+ Object O = getObject(UO->getSubExpr(), true);
+ if (!O)
+ return VisitExpr(UO);
+
+ notePreMod(O, UO);
+ Visit(UO->getSubExpr());
+ notePostMod(O, UO, UK_ModAsValue);
+ }
+
+ void VisitUnaryPostInc(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+ void VisitUnaryPostDec(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+ void VisitUnaryPostIncDec(UnaryOperator *UO) {
+ Object O = getObject(UO->getSubExpr(), true);
+ if (!O)
+ return VisitExpr(UO);
+
+ notePreMod(O, UO);
+ Visit(UO->getSubExpr());
+ notePostMod(O, UO, UK_ModAsSideEffect);
+ }
+
+ /// Don't visit the RHS of '&&' or '||' if it might not be evaluated.
+ void VisitBinLOr(BinaryOperator *BO) {
+ // The side-effects of the LHS of an '&&' are sequenced before the
+ // value computation of the RHS, and hence before the value computation
+ // of the '&&' itself, unless the LHS evaluates to zero. We treat them
+ // as if they were unconditionally sequenced.
+ {
+ SequencedSubexpression Sequenced(*this);
+ Visit(BO->getLHS());
+ }
+
+ bool Result;
+ if (!BO->getLHS()->isValueDependent() &&
+ BO->getLHS()->EvaluateAsBooleanCondition(Result, SemaRef.Context)) {
+ if (!Result)
+ Visit(BO->getRHS());
+ } else {
+ // Check for unsequenced operations in the RHS, treating it as an
+ // entirely separate evaluation.
+ //
+ // FIXME: If there are operations in the RHS which are unsequenced
+ // with respect to operations outside the RHS, and those operations
+ // are unconditionally evaluated, diagnose them.
+ WorkList.push_back(BO->getRHS());
+ }
+ }
+ void VisitBinLAnd(BinaryOperator *BO) {
+ {
+ SequencedSubexpression Sequenced(*this);
+ Visit(BO->getLHS());
+ }
+
+ bool Result;
+ if (!BO->getLHS()->isValueDependent() &&
+ BO->getLHS()->EvaluateAsBooleanCondition(Result, SemaRef.Context)) {
+ if (Result)
+ Visit(BO->getRHS());
+ } else {
+ WorkList.push_back(BO->getRHS());
+ }
+ }
+
+ // Only visit the condition, unless we can be sure which subexpression will
+ // be chosen.
+ void VisitAbstractConditionalOperator(AbstractConditionalOperator *CO) {
+ SequencedSubexpression Sequenced(*this);
+ Visit(CO->getCond());
+
+ bool Result;
+ if (!CO->getCond()->isValueDependent() &&
+ CO->getCond()->EvaluateAsBooleanCondition(Result, SemaRef.Context))
+ Visit(Result ? CO->getTrueExpr() : CO->getFalseExpr());
+ else {
+ WorkList.push_back(CO->getTrueExpr());
+ WorkList.push_back(CO->getFalseExpr());
+ }
+ }
+
+ void VisitCXXConstructExpr(CXXConstructExpr *CCE) {
+ if (!CCE->isListInitialization())
+ return VisitExpr(CCE);
+
+ // In C++11, list initializations are sequenced.
+ llvm::SmallVector<SequenceTree::Seq, 32> Elts;
+ SequenceTree::Seq Parent = Region;
+ for (CXXConstructExpr::arg_iterator I = CCE->arg_begin(),
+ E = CCE->arg_end();
+ I != E; ++I) {
+ Region = Tree.allocate(Parent);
+ Elts.push_back(Region);
+ Visit(*I);
+ }
+
+ // Forget that the initializers are sequenced.
+ Region = Parent;
+ for (unsigned I = 0; I < Elts.size(); ++I)
+ Tree.merge(Elts[I]);
+ }
+
+ void VisitInitListExpr(InitListExpr *ILE) {
+ if (!SemaRef.getLangOpts().CPlusPlus11)
+ return VisitExpr(ILE);
+
+ // In C++11, list initializations are sequenced.
+ llvm::SmallVector<SequenceTree::Seq, 32> Elts;
+ SequenceTree::Seq Parent = Region;
+ for (unsigned I = 0; I < ILE->getNumInits(); ++I) {
+ Expr *E = ILE->getInit(I);
+ if (!E) continue;
+ Region = Tree.allocate(Parent);
+ Elts.push_back(Region);
+ Visit(E);
+ }
+
+ // Forget that the initializers are sequenced.
+ Region = Parent;
+ for (unsigned I = 0; I < Elts.size(); ++I)
+ Tree.merge(Elts[I]);
+ }
+};
+}
+
+void Sema::CheckUnsequencedOperations(Expr *E) {
+ llvm::SmallVector<Expr*, 8> WorkList;
+ WorkList.push_back(E);
+ while (!WorkList.empty()) {
+ Expr *Item = WorkList.back();
+ WorkList.pop_back();
+ SequenceChecker(*this, Item, WorkList);
+ }
+}
+
+void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
+ bool IsConstexpr) {
+ CheckImplicitConversions(E, CheckLoc);
+ CheckUnsequencedOperations(E);
+ if (!IsConstexpr && !E->isValueDependent())
+ CheckForIntOverflow(E);
+}
+
void Sema::CheckBitFieldInitialization(SourceLocation InitLoc,
FieldDecl *BitField,
Expr *Init) {
@@ -5091,7 +5701,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 '[*]' if source-location
+ // FIXME: This diagnostic should point the '[*]' if source-location
// information is added for it.
Diag(Param->getLocation(), diag::err_array_star_in_function_definition);
}
@@ -5174,16 +5784,16 @@ static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size,
while (TInfo) {
TypeLoc TL = TInfo->getTypeLoc();
// Look through typedefs.
- const TypedefTypeLoc *TTL = dyn_cast<TypedefTypeLoc>(&TL);
- if (TTL) {
- const TypedefNameDecl *TDL = TTL->getTypedefNameDecl();
+ if (TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>()) {
+ 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;
+ if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) {
+ const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
+ if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
+ return false;
+ }
break;
}
@@ -5574,7 +6184,7 @@ static bool isSetterLikeSelector(Selector sel) {
return false;
if (str.empty()) return true;
- return !islower(str.front());
+ return !isLowercase(str.front());
}
/// Check a message send to see if it's likely to cause a retain cycle.
@@ -5625,21 +6235,59 @@ void Sema::checkRetainCycles(VarDecl *Var, Expr *Init) {
diagnoseRetainCycle(*this, Capturer, Owner);
}
-bool Sema::checkUnsafeAssigns(SourceLocation Loc,
- QualType LHS, Expr *RHS) {
- Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
- if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
+static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc,
+ Expr *RHS, bool isProperty) {
+ // Check if RHS is an Objective-C object literal, which also can get
+ // immediately zapped in a weak reference. Note that we explicitly
+ // allow ObjCStringLiterals, since those are designed to never really die.
+ RHS = RHS->IgnoreParenImpCasts();
+
+ // This enum needs to match with the 'select' in
+ // warn_objc_arc_literal_assign (off-by-1).
+ Sema::ObjCLiteralKind Kind = S.CheckLiteralKind(RHS);
+ if (Kind == Sema::LK_String || Kind == Sema::LK_None)
return false;
- // strip off any implicit cast added to get to the one arc-specific
+
+ S.Diag(Loc, diag::warn_arc_literal_assign)
+ << (unsigned) Kind
+ << (isProperty ? 0 : 1)
+ << RHS->getSourceRange();
+
+ return true;
+}
+
+static bool checkUnsafeAssignObject(Sema &S, SourceLocation Loc,
+ Qualifiers::ObjCLifetime LT,
+ Expr *RHS, bool isProperty) {
+ // Strip off any implicit cast added to get to the one ARC-specific.
while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
if (cast->getCastKind() == CK_ARCConsumeObject) {
- Diag(Loc, diag::warn_arc_retained_assign)
- << (LT == Qualifiers::OCL_ExplicitNone) << 1
+ S.Diag(Loc, diag::warn_arc_retained_assign)
+ << (LT == Qualifiers::OCL_ExplicitNone)
+ << (isProperty ? 0 : 1)
<< RHS->getSourceRange();
return true;
}
RHS = cast->getSubExpr();
}
+
+ if (LT == Qualifiers::OCL_Weak &&
+ checkUnsafeAssignLiteral(S, Loc, RHS, isProperty))
+ return true;
+
+ return false;
+}
+
+bool Sema::checkUnsafeAssigns(SourceLocation Loc,
+ QualType LHS, Expr *RHS) {
+ Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
+
+ if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
+ return false;
+
+ if (checkUnsafeAssignObject(*this, Loc, LT, RHS, false))
+ return true;
+
return false;
}
@@ -5702,14 +6350,8 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
}
}
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();
- }
+ if (checkUnsafeAssignObject(*this, Loc, Qualifiers::OCL_Weak, RHS, true))
+ return;
}
}
}
OpenPOWER on IntegriCloud