Track in the AST whether the operand to a UnaryOperator can overflow and then use that logic when evaluating constant expressions and emitting codegen.

llvm-svn: 322074
This commit is contained in:
Aaron Ballman 2018-01-09 13:07:03 +00:00
parent 1f97363e5f
commit a503855906
18 changed files with 245 additions and 180 deletions

View File

@ -1720,19 +1720,19 @@ public:
private: private:
unsigned Opc : 5; unsigned Opc : 5;
unsigned CanOverflow : 1;
SourceLocation Loc; SourceLocation Loc;
Stmt *Val; Stmt *Val;
public: public:
UnaryOperator(Expr *input, Opcode opc, QualType type, ExprValueKind VK,
UnaryOperator(Expr *input, Opcode opc, QualType type, ExprObjectKind OK, SourceLocation l, bool CanOverflow)
ExprValueKind VK, ExprObjectKind OK, SourceLocation l)
: Expr(UnaryOperatorClass, type, VK, OK, : Expr(UnaryOperatorClass, type, VK, OK,
input->isTypeDependent() || type->isDependentType(), input->isTypeDependent() || type->isDependentType(),
input->isValueDependent(), input->isValueDependent(),
(input->isInstantiationDependent() || (input->isInstantiationDependent() ||
type->isInstantiationDependentType()), type->isInstantiationDependentType()),
input->containsUnexpandedParameterPack()), input->containsUnexpandedParameterPack()),
Opc(opc), Loc(l), Val(input) {} Opc(opc), CanOverflow(CanOverflow), Loc(l), Val(input) {}
/// \brief Build an empty unary operator. /// \brief Build an empty unary operator.
explicit UnaryOperator(EmptyShell Empty) explicit UnaryOperator(EmptyShell Empty)
@ -1748,6 +1748,15 @@ public:
SourceLocation getOperatorLoc() const { return Loc; } SourceLocation getOperatorLoc() const { return Loc; }
void setOperatorLoc(SourceLocation L) { Loc = L; } void setOperatorLoc(SourceLocation L) { Loc = L; }
/// Returns true if the unary operator can cause an overflow. For instance,
/// signed int i = INT_MAX; i++;
/// signed char c = CHAR_MAX; c++;
/// Due to integer promotions, c++ is promoted to an int before the postfix
/// increment, and the result is an int that cannot overflow. However, i++
/// can overflow.
bool canOverflow() const { return CanOverflow; }
void setCanOverflow(bool C) { CanOverflow = C; }
/// isPostfix - Return true if this is a postfix operation, like x++. /// isPostfix - Return true if this is a postfix operation, like x++.
static bool isPostfix(Opcode Op) { static bool isPostfix(Opcode Op) {
return Op == UO_PostInc || Op == UO_PostDec; return Op == UO_PostInc || Op == UO_PostDec;

View File

@ -2217,6 +2217,8 @@ void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) {
VisitExpr(Node); VisitExpr(Node);
OS << " " << (Node->isPostfix() ? "postfix" : "prefix") OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
<< " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
if (!Node->canOverflow())
OS << " cannot overflow";
} }
void ASTDumper::VisitUnaryExprOrTypeTraitExpr( void ASTDumper::VisitUnaryExprOrTypeTraitExpr(

View File

@ -5120,14 +5120,13 @@ Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) {
if (!SubExpr) if (!SubExpr)
return nullptr; return nullptr;
return new (Importer.getToContext()) UnaryOperator(SubExpr, E->getOpcode(), return new (Importer.getToContext()) UnaryOperator(
T, E->getValueKind(), SubExpr, E->getOpcode(), T, E->getValueKind(), E->getObjectKind(),
E->getObjectKind(), Importer.Import(E->getOperatorLoc()), E->canOverflow());
Importer.Import(E->getOperatorLoc()));
} }
Expr *ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr( Expr *
UnaryExprOrTypeTraitExpr *E) { ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
QualType ResultType = Importer.Import(E->getType()); QualType ResultType = Importer.Import(E->getType());
if (E->isArgumentType()) { if (E->isArgumentType()) {

View File

@ -3247,11 +3247,6 @@ static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal,
return Obj && modifySubobject(Info, E, Obj, LVal.Designator, Val); return Obj && modifySubobject(Info, E, Obj, LVal.Designator, Val);
} }
static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) {
return T->isSignedIntegerType() &&
Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy);
}
namespace { namespace {
struct CompoundAssignSubobjectHandler { struct CompoundAssignSubobjectHandler {
EvalInfo &Info; EvalInfo &Info;
@ -3373,7 +3368,7 @@ static bool handleCompoundAssignment(
namespace { namespace {
struct IncDecSubobjectHandler { struct IncDecSubobjectHandler {
EvalInfo &Info; EvalInfo &Info;
const Expr *E; const UnaryOperator *E;
AccessKinds AccessKind; AccessKinds AccessKind;
APValue *Old; APValue *Old;
@ -3445,16 +3440,14 @@ struct IncDecSubobjectHandler {
if (AccessKind == AK_Increment) { if (AccessKind == AK_Increment) {
++Value; ++Value;
if (!WasNegative && Value.isNegative() && if (!WasNegative && Value.isNegative() && E->canOverflow()) {
isOverflowingIntegerType(Info.Ctx, SubobjType)) {
APSInt ActualValue(Value, /*IsUnsigned*/true); APSInt ActualValue(Value, /*IsUnsigned*/true);
return HandleOverflow(Info, E, ActualValue, SubobjType); return HandleOverflow(Info, E, ActualValue, SubobjType);
} }
} else { } else {
--Value; --Value;
if (WasNegative && !Value.isNegative() && if (WasNegative && !Value.isNegative() && E->canOverflow()) {
isOverflowingIntegerType(Info.Ctx, SubobjType)) {
unsigned BitWidth = Value.getBitWidth(); unsigned BitWidth = Value.getBitWidth();
APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false); APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false);
ActualValue.setBit(BitWidth); ActualValue.setBit(BitWidth);
@ -3515,7 +3508,7 @@ static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal,
AccessKinds AK = IsIncrement ? AK_Increment : AK_Decrement; AccessKinds AK = IsIncrement ? AK_Increment : AK_Decrement;
CompleteObject Obj = findCompleteObject(Info, E, AK, LVal, LValType); CompleteObject Obj = findCompleteObject(Info, E, AK, LVal, LValType);
IncDecSubobjectHandler Handler = { Info, E, AK, Old }; IncDecSubobjectHandler Handler = {Info, cast<UnaryOperator>(E), AK, Old};
return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler); return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler);
} }
@ -8878,7 +8871,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
return false; return false;
if (!Result.isInt()) return Error(E); if (!Result.isInt()) return Error(E);
const APSInt &Value = Result.getInt(); const APSInt &Value = Result.getInt();
if (Value.isSigned() && Value.isMinSignedValue() && if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow() &&
!HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1), !HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
E->getType())) E->getType()))
return false; return false;

View File

@ -149,7 +149,8 @@ DeclRefExpr *ASTMaker::makeDeclRefExpr(
UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) { UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty, return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty,
VK_LValue, OK_Ordinary, SourceLocation()); VK_LValue, OK_Ordinary, SourceLocation(),
/*CanOverflow*/ false);
} }
ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) { ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
@ -441,7 +442,8 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
/* opc=*/ UO_LNot, /* opc=*/ UO_LNot,
/* QualType=*/ C.IntTy, /* QualType=*/ C.IntTy,
/* ExprValueKind=*/ VK_RValue, /* ExprValueKind=*/ VK_RValue,
/* ExprObjectKind=*/ OK_Ordinary, SourceLocation()); /* ExprObjectKind=*/ OK_Ordinary, SourceLocation(),
/* CanOverflow*/ false);
// Create assignment. // Create assignment.
BinaryOperator *FlagAssignment = M.makeAssignment( BinaryOperator *FlagAssignment = M.makeAssignment(
@ -505,7 +507,8 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
// (2) Create the assignment to the predicate. // (2) Create the assignment to the predicate.
Expr *DoneValue = Expr *DoneValue =
new (C) UnaryOperator(M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy, new (C) UnaryOperator(M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy,
VK_RValue, OK_Ordinary, SourceLocation()); VK_RValue, OK_Ordinary, SourceLocation(),
/*CanOverflow*/false);
BinaryOperator *B = BinaryOperator *B =
M.makeAssignment( M.makeAssignment(

View File

@ -165,7 +165,7 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
// If a unary op has a widened operand, the op cannot overflow. // If a unary op has a widened operand, the op cannot overflow.
if (const auto *UO = dyn_cast<UnaryOperator>(Op.E)) if (const auto *UO = dyn_cast<UnaryOperator>(Op.E))
return IsWidenedIntegerOp(Ctx, UO->getSubExpr()); return !UO->canOverflow();
// We usually don't need overflow checks for binops with widened operands. // We usually don't need overflow checks for binops with widened operands.
// Multiplication with promoted unsigned operands is a special case. // Multiplication with promoted unsigned operands is a special case.
@ -1873,7 +1873,7 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
return Builder.CreateNSWAdd(InVal, Amount, Name); return Builder.CreateNSWAdd(InVal, Amount, Name);
// Fall through. // Fall through.
case LangOptions::SOB_Trapping: case LangOptions::SOB_Trapping:
if (IsWidenedIntegerOp(CGF.getContext(), E->getSubExpr())) if (!E->canOverflow())
return Builder.CreateNSWAdd(InVal, Amount, Name); return Builder.CreateNSWAdd(InVal, Amount, Name);
return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, InVal, IsInc)); return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, InVal, IsInc));
} }
@ -1955,11 +1955,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
} else if (type->isIntegerType()) { } else if (type->isIntegerType()) {
// Note that signed integer inc/dec with width less than int can't // Note that signed integer inc/dec with width less than int can't
// overflow because of promotion rules; we're just eliding a few steps here. // overflow because of promotion rules; we're just eliding a few steps here.
bool CanOverflow = value->getType()->getIntegerBitWidth() >= if (E->canOverflow() && type->isSignedIntegerOrEnumerationType()) {
CGF.IntTy->getIntegerBitWidth();
if (CanOverflow && type->isSignedIntegerOrEnumerationType()) {
value = EmitIncDecConsiderOverflowBehavior(E, value, isInc); value = EmitIncDecConsiderOverflowBehavior(E, value, isInc);
} else if (CanOverflow && type->isUnsignedIntegerType() && } else if (E->canOverflow() && type->isUnsignedIntegerType() &&
CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) { CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) {
value = value =
EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, value, isInc)); EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, value, isInc));

View File

@ -3268,12 +3268,12 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
DeclRefExpr DstExpr(&DstDecl, false, DestTy, DeclRefExpr DstExpr(&DstDecl, false, DestTy,
VK_RValue, SourceLocation()); VK_RValue, SourceLocation());
UnaryOperator DST(&DstExpr, UO_Deref, DestTy->getPointeeType(), UnaryOperator DST(&DstExpr, UO_Deref, DestTy->getPointeeType(),
VK_LValue, OK_Ordinary, SourceLocation()); VK_LValue, OK_Ordinary, SourceLocation(), false);
DeclRefExpr SrcExpr(&SrcDecl, false, SrcTy, DeclRefExpr SrcExpr(&SrcDecl, false, SrcTy,
VK_RValue, SourceLocation()); VK_RValue, SourceLocation());
UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(), UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
VK_LValue, OK_Ordinary, SourceLocation()); VK_LValue, OK_Ordinary, SourceLocation(), false);
Expr *Args[2] = { &DST, &SRC }; Expr *Args[2] = { &DST, &SRC };
CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment()); CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
@ -3351,7 +3351,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
VK_RValue, SourceLocation()); VK_RValue, SourceLocation());
UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(), UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
VK_LValue, OK_Ordinary, SourceLocation()); VK_LValue, OK_Ordinary, SourceLocation(), false);
CXXConstructExpr *CXXConstExpr = CXXConstructExpr *CXXConstExpr =
cast<CXXConstructExpr>(PID->getGetterCXXConstructor()); cast<CXXConstructExpr>(PID->getGetterCXXConstructor());

View File

@ -2483,7 +2483,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
OK_Ordinary, S.getLocStart(), FPOptions()); OK_Ordinary, S.getLocStart(), FPOptions());
// Increment for loop counter. // Increment for loop counter.
UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary, UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
S.getLocStart()); S.getLocStart(), true);
auto BodyGen = [Stmt, CS, &S, &IV](CodeGenFunction &CGF) { auto BodyGen = [Stmt, CS, &S, &IV](CodeGenFunction &CGF) {
// Iterate through all sections and emit a switch construct: // Iterate through all sections and emit a switch construct:
// switch (IV) { // switch (IV) {

View File

@ -2590,7 +2590,7 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
Context->getPointerType(DRE->getType()), Context->getPointerType(DRE->getType()),
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary,
SourceLocation()); SourceLocation(), false);
// cast to NSConstantString * // cast to NSConstantString *
CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
CK_CPointerToObjCPointerCast, Unop); CK_CPointerToObjCPointerCast, Unop);
@ -3295,7 +3295,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
Context->getPointerType(SuperRep->getType()), Context->getPointerType(SuperRep->getType()),
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary,
SourceLocation()); SourceLocation(), false);
SuperRep = NoTypeInfoCStyleCastExpr(Context, SuperRep = NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(superType), Context->getPointerType(superType),
CK_BitCast, SuperRep); CK_BitCast, SuperRep);
@ -3313,7 +3313,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
Context->getPointerType(SuperRep->getType()), Context->getPointerType(SuperRep->getType()),
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary,
SourceLocation()); SourceLocation(), false);
} }
MsgExprs.push_back(SuperRep); MsgExprs.push_back(SuperRep);
break; break;
@ -3389,7 +3389,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
Context->getPointerType(SuperRep->getType()), Context->getPointerType(SuperRep->getType()),
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary,
SourceLocation()); SourceLocation(), false);
SuperRep = NoTypeInfoCStyleCastExpr(Context, SuperRep = NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(superType), Context->getPointerType(superType),
CK_BitCast, SuperRep); CK_BitCast, SuperRep);
@ -4720,7 +4720,7 @@ Stmt *RewriteModernObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
return DRE; return DRE;
Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(),
VK_LValue, OK_Ordinary, VK_LValue, OK_Ordinary,
DRE->getLocation()); DRE->getLocation(), false);
// Need parens to enforce precedence. // Need parens to enforce precedence.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
Exp); Exp);
@ -5314,7 +5314,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
UO_AddrOf, UO_AddrOf,
Context->getPointerType(Context->VoidPtrTy), Context->getPointerType(Context->VoidPtrTy),
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary,
SourceLocation()); SourceLocation(), false);
InitExprs.push_back(DescRefExpr); InitExprs.push_back(DescRefExpr);
// Add initializers for any closure decl refs. // Add initializers for any closure decl refs.
@ -5332,7 +5332,8 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
QualType QT = (*I)->getType(); QualType QT = (*I)->getType();
QT = Context->getPointerType(QT); QT = Context->getPointerType(QT);
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
OK_Ordinary, SourceLocation()); OK_Ordinary, SourceLocation(),
false);
} }
} else if (isTopLevelBlockPointerType((*I)->getType())) { } else if (isTopLevelBlockPointerType((*I)->getType())) {
FD = SynthBlockInitFunctionDecl((*I)->getName()); FD = SynthBlockInitFunctionDecl((*I)->getName());
@ -5348,7 +5349,8 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
QualType QT = (*I)->getType(); QualType QT = (*I)->getType();
QT = Context->getPointerType(QT); QT = Context->getPointerType(QT);
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
OK_Ordinary, SourceLocation()); OK_Ordinary, SourceLocation(),
false);
} }
} }
@ -5388,7 +5390,8 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
if (!isNestedCapturedVar) if (!isNestedCapturedVar)
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, Exp = new (Context) UnaryOperator(Exp, UO_AddrOf,
Context->getPointerType(Exp->getType()), Context->getPointerType(Exp->getType()),
VK_RValue, OK_Ordinary, SourceLocation()); VK_RValue, OK_Ordinary, SourceLocation(),
false);
Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
InitExprs.push_back(Exp); InitExprs.push_back(Exp);
} }
@ -5414,7 +5417,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
Context->getPointerType(NewRep->getType()), Context->getPointerType(NewRep->getType()),
VK_RValue, OK_Ordinary, SourceLocation()); VK_RValue, OK_Ordinary, SourceLocation(), false);
NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
NewRep); NewRep);
// Put Paren around the call. // Put Paren around the call.
@ -7558,7 +7561,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
Expr *Exp = new (Context) UnaryOperator(castExpr, UO_Deref, IvarT, Expr *Exp = new (Context) UnaryOperator(castExpr, UO_Deref, IvarT,
VK_LValue, OK_Ordinary, VK_LValue, OK_Ordinary,
SourceLocation()); SourceLocation(), false);
PE = new (Context) ParenExpr(OldRange.getBegin(), PE = new (Context) ParenExpr(OldRange.getBegin(),
OldRange.getEnd(), OldRange.getEnd(),
Exp); Exp);

View File

@ -2511,7 +2511,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
Context->getPointerType(DRE->getType()), Context->getPointerType(DRE->getType()),
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary,
SourceLocation()); SourceLocation(), false);
// cast to NSConstantString * // cast to NSConstantString *
CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
CK_CPointerToObjCPointerCast, Unop); CK_CPointerToObjCPointerCast, Unop);
@ -2712,7 +2712,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
Context->getPointerType(SuperRep->getType()), Context->getPointerType(SuperRep->getType()),
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary,
SourceLocation()); SourceLocation(), false);
SuperRep = NoTypeInfoCStyleCastExpr(Context, SuperRep = NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(superType), Context->getPointerType(superType),
CK_BitCast, SuperRep); CK_BitCast, SuperRep);
@ -2730,7 +2730,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
Context->getPointerType(SuperRep->getType()), Context->getPointerType(SuperRep->getType()),
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary,
SourceLocation()); SourceLocation(), false);
} }
MsgExprs.push_back(SuperRep); MsgExprs.push_back(SuperRep);
break; break;
@ -2806,7 +2806,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
Context->getPointerType(SuperRep->getType()), Context->getPointerType(SuperRep->getType()),
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary,
SourceLocation()); SourceLocation(), false);
SuperRep = NoTypeInfoCStyleCastExpr(Context, SuperRep = NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(superType), Context->getPointerType(superType),
CK_BitCast, SuperRep); CK_BitCast, SuperRep);
@ -3045,7 +3045,7 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
VK_LValue, SourceLocation()); VK_LValue, SourceLocation());
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf, Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf,
Context->getPointerType(DRE->getType()), Context->getPointerType(DRE->getType()),
VK_RValue, OK_Ordinary, SourceLocation()); VK_RValue, OK_Ordinary, SourceLocation(), false);
CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(),
CK_BitCast, CK_BitCast,
DerefExpr); DerefExpr);
@ -3875,7 +3875,7 @@ Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
return DRE; return DRE;
Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(),
VK_LValue, OK_Ordinary, VK_LValue, OK_Ordinary,
DRE->getLocation()); DRE->getLocation(), false);
// Need parens to enforce precedence. // Need parens to enforce precedence.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
Exp); Exp);
@ -4438,7 +4438,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
UO_AddrOf, UO_AddrOf,
Context->getPointerType(Context->VoidPtrTy), Context->getPointerType(Context->VoidPtrTy),
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary,
SourceLocation()); SourceLocation(), false);
InitExprs.push_back(DescRefExpr); InitExprs.push_back(DescRefExpr);
// Add initializers for any closure decl refs. // Add initializers for any closure decl refs.
@ -4456,7 +4456,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
QualType QT = (*I)->getType(); QualType QT = (*I)->getType();
QT = Context->getPointerType(QT); QT = Context->getPointerType(QT);
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
OK_Ordinary, SourceLocation()); OK_Ordinary, SourceLocation(),
false);
} }
} else if (isTopLevelBlockPointerType((*I)->getType())) { } else if (isTopLevelBlockPointerType((*I)->getType())) {
FD = SynthBlockInitFunctionDecl((*I)->getName()); FD = SynthBlockInitFunctionDecl((*I)->getName());
@ -4472,7 +4473,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
QualType QT = (*I)->getType(); QualType QT = (*I)->getType();
QT = Context->getPointerType(QT); QT = Context->getPointerType(QT);
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
OK_Ordinary, SourceLocation()); OK_Ordinary, SourceLocation(),
false);
} }
} }
InitExprs.push_back(Exp); InitExprs.push_back(Exp);
@ -4509,9 +4511,9 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
// captured nested byref variable has its address passed. Do not take // captured nested byref variable has its address passed. Do not take
// its address again. // its address again.
if (!isNestedCapturedVar) if (!isNestedCapturedVar)
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, Exp = new (Context) UnaryOperator(
Context->getPointerType(Exp->getType()), Exp, UO_AddrOf, Context->getPointerType(Exp->getType()), VK_RValue,
VK_RValue, OK_Ordinary, SourceLocation()); OK_Ordinary, SourceLocation(), false);
Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
InitExprs.push_back(Exp); InitExprs.push_back(Exp);
} }
@ -4529,7 +4531,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
FType, VK_LValue, SourceLocation()); FType, VK_LValue, SourceLocation());
NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
Context->getPointerType(NewRep->getType()), Context->getPointerType(NewRep->getType()),
VK_RValue, OK_Ordinary, SourceLocation()); VK_RValue, OK_Ordinary, SourceLocation(), false);
NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
NewRep); NewRep);
BlockDeclRefs.clear(); BlockDeclRefs.clear();

View File

@ -10990,11 +10990,11 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
Expr *From = FromB.build(S, Loc); Expr *From = FromB.build(S, Loc);
From = new (S.Context) UnaryOperator(From, UO_AddrOf, From = new (S.Context) UnaryOperator(From, UO_AddrOf,
S.Context.getPointerType(From->getType()), S.Context.getPointerType(From->getType()),
VK_RValue, OK_Ordinary, Loc); VK_RValue, OK_Ordinary, Loc, false);
Expr *To = ToB.build(S, Loc); Expr *To = ToB.build(S, Loc);
To = new (S.Context) UnaryOperator(To, UO_AddrOf, To = new (S.Context) UnaryOperator(To, UO_AddrOf,
S.Context.getPointerType(To->getType()), S.Context.getPointerType(To->getType()),
VK_RValue, OK_Ordinary, Loc); VK_RValue, OK_Ordinary, Loc, false);
const Type *E = T->getBaseElementTypeUnsafe(); const Type *E = T->getBaseElementTypeUnsafe();
bool NeedsCollectableMemCpy = bool NeedsCollectableMemCpy =
@ -11233,10 +11233,12 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
BO_NE, S.Context.BoolTy, BO_NE, S.Context.BoolTy,
VK_RValue, OK_Ordinary, Loc, FPOptions()); VK_RValue, OK_Ordinary, Loc, FPOptions());
// Create the pre-increment of the iteration variable. // Create the pre-increment of the iteration variable. We can determine
Expr *Increment // whether the increment will overflow based on the value of the array
= new (S.Context) UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc, // bound.
SizeType, VK_LValue, OK_Ordinary, Loc); Expr *Increment = new (S.Context)
UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc, SizeType,
VK_LValue, OK_Ordinary, Loc, Upper.isMaxValue());
// Construct the loop that copies all elements of this array. // Construct the loop that copies all elements of this array.
return S.ActOnForStmt( return S.ActOnForStmt(

View File

@ -12178,6 +12178,16 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr); return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr);
} }
static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) {
if (T.isNull() || T->isDependentType())
return false;
if (!T->isPromotableIntegerType())
return true;
return Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy);
}
ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
UnaryOperatorKind Opc, UnaryOperatorKind Opc,
Expr *InputExpr) { Expr *InputExpr) {
@ -12185,6 +12195,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
ExprValueKind VK = VK_RValue; ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary; ExprObjectKind OK = OK_Ordinary;
QualType resultType; QualType resultType;
bool CanOverflow = false;
bool ConvertHalfVec = false; bool ConvertHalfVec = false;
if (getLangOpts().OpenCL) { if (getLangOpts().OpenCL) {
QualType Ty = InputExpr->getType(); QualType Ty = InputExpr->getType();
@ -12210,6 +12222,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
Opc == UO_PostInc, Opc == UO_PostInc,
Opc == UO_PreInc || Opc == UO_PreInc ||
Opc == UO_PreDec); Opc == UO_PreDec);
CanOverflow = isOverflowingIntegerType(Context, resultType);
break; break;
case UO_AddrOf: case UO_AddrOf:
resultType = CheckAddressOfOperand(Input, OpLoc); resultType = CheckAddressOfOperand(Input, OpLoc);
@ -12223,6 +12236,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
} }
case UO_Plus: case UO_Plus:
case UO_Minus: case UO_Minus:
CanOverflow = Opc == UO_Minus &&
isOverflowingIntegerType(Context, Input.get()->getType());
Input = UsualUnaryConversions(Input.get()); Input = UsualUnaryConversions(Input.get());
if (Input.isInvalid()) return ExprError(); if (Input.isInvalid()) return ExprError();
// Unary plus and minus require promoting an operand of half vector to a // Unary plus and minus require promoting an operand of half vector to a
@ -12259,6 +12274,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (Input.isInvalid()) if (Input.isInvalid())
return ExprError(); return ExprError();
resultType = Input.get()->getType(); resultType = Input.get()->getType();
if (resultType->isDependentType()) if (resultType->isDependentType())
break; break;
// C99 6.5.3.3p1. We allow complex int and float as a GCC extension. // C99 6.5.3.3p1. We allow complex int and float as a GCC extension.
@ -12373,7 +12389,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
CheckArrayAccess(Input.get()); CheckArrayAccess(Input.get());
auto *UO = new (Context) auto *UO = new (Context)
UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc); UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc, CanOverflow);
// Convert the result back to a half vector. // Convert the result back to a half vector.
if (ConvertHalfVec) if (ConvertHalfVec)
return convertVector(UO, Context.HalfTy, *this); return convertVector(UO, Context.HalfTy, *this);

View File

@ -4276,9 +4276,9 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) {
} else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) { } else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) {
assert(uo->getOpcode() == UO_Extension); assert(uo->getOpcode() == UO_Extension);
Expr *sub = stripARCUnbridgedCast(uo->getSubExpr()); Expr *sub = stripARCUnbridgedCast(uo->getSubExpr());
return new (Context) UnaryOperator(sub, UO_Extension, sub->getType(), return new (Context)
sub->getValueKind(), sub->getObjectKind(), UnaryOperator(sub, UO_Extension, sub->getType(), sub->getValueKind(),
uo->getOperatorLoc()); sub->getObjectKind(), uo->getOperatorLoc(), false);
} else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { } else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
assert(!gse->isResultDependent()); assert(!gse->isResultDependent());

View File

@ -12022,7 +12022,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
if (Input->isTypeDependent()) { if (Input->isTypeDependent()) {
if (Fns.empty()) if (Fns.empty())
return new (Context) UnaryOperator(Input, Opc, Context.DependentTy, return new (Context) UnaryOperator(Input, Opc, Context.DependentTy,
VK_RValue, OK_Ordinary, OpLoc); VK_RValue, OK_Ordinary, OpLoc, false);
CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
UnresolvedLookupExpr *Fn UnresolvedLookupExpr *Fn
@ -13552,7 +13552,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType, return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType,
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary,
UnOp->getOperatorLoc()); UnOp->getOperatorLoc(), false);
} }
} }
Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
@ -13563,7 +13563,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
return new (Context) UnaryOperator(SubExpr, UO_AddrOf, return new (Context) UnaryOperator(SubExpr, UO_AddrOf,
Context.getPointerType(SubExpr->getType()), Context.getPointerType(SubExpr->getType()),
VK_RValue, OK_Ordinary, VK_RValue, OK_Ordinary,
UnOp->getOperatorLoc()); UnOp->getOperatorLoc(), false);
} }
// C++ [except.spec]p17: // C++ [except.spec]p17:

View File

@ -132,7 +132,8 @@ namespace {
uop->getType(), uop->getType(),
uop->getValueKind(), uop->getValueKind(),
uop->getObjectKind(), uop->getObjectKind(),
uop->getOperatorLoc()); uop->getOperatorLoc(),
uop->canOverflow());
} }
if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
@ -527,9 +528,12 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
(result.get()->isTypeDependent() || CanCaptureValue(result.get()))) (result.get()->isTypeDependent() || CanCaptureValue(result.get())))
setResultToLastSemantic(); setResultToLastSemantic();
UnaryOperator *syntactic = UnaryOperator *syntactic = new (S.Context) UnaryOperator(
new (S.Context) UnaryOperator(syntacticOp, opcode, resultType, syntacticOp, opcode, resultType, VK_LValue, OK_Ordinary, opcLoc,
VK_LValue, OK_Ordinary, opcLoc); !resultType->isDependentType()
? S.Context.getTypeSize(resultType) >=
S.Context.getTypeSize(S.Context.IntTy)
: false);
return complete(syntactic); return complete(syntactic);
} }
@ -1550,7 +1554,7 @@ ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc,
// Do nothing if the operand is dependent. // Do nothing if the operand is dependent.
if (op->isTypeDependent()) if (op->isTypeDependent())
return new (Context) UnaryOperator(op, opcode, Context.DependentTy, return new (Context) UnaryOperator(op, opcode, Context.DependentTy,
VK_RValue, OK_Ordinary, opcLoc); VK_RValue, OK_Ordinary, opcLoc, false);
assert(UnaryOperator::isIncrementDecrementOp(opcode)); assert(UnaryOperator::isIncrementDecrementOp(opcode));
Expr *opaqueRef = op->IgnoreParens(); Expr *opaqueRef = op->IgnoreParens();
@ -1633,9 +1637,9 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
Expr *syntax = E->getSyntacticForm(); Expr *syntax = E->getSyntacticForm();
if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) { if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) {
Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr()); Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr());
return new (Context) UnaryOperator(op, uop->getOpcode(), uop->getType(), return new (Context) UnaryOperator(
uop->getValueKind(), uop->getObjectKind(), op, uop->getOpcode(), uop->getType(), uop->getValueKind(),
uop->getOperatorLoc()); uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow());
} else if (CompoundAssignOperator *cop } else if (CompoundAssignOperator *cop
= dyn_cast<CompoundAssignOperator>(syntax)) { = dyn_cast<CompoundAssignOperator>(syntax)) {
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS()); Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS());

View File

@ -553,6 +553,7 @@ void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) {
E->setSubExpr(Record.readSubExpr()); E->setSubExpr(Record.readSubExpr());
E->setOpcode((UnaryOperator::Opcode)Record.readInt()); E->setOpcode((UnaryOperator::Opcode)Record.readInt());
E->setOperatorLoc(ReadSourceLocation()); E->setOperatorLoc(ReadSourceLocation());
E->setCanOverflow(Record.readInt());
} }
void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {

View File

@ -509,6 +509,7 @@ void ASTStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
Record.AddStmt(E->getSubExpr()); Record.AddStmt(E->getSubExpr());
Record.push_back(E->getOpcode()); // FIXME: stable encoding Record.push_back(E->getOpcode()); // FIXME: stable encoding
Record.AddSourceLocation(E->getOperatorLoc()); Record.AddSourceLocation(E->getOperatorLoc());
Record.push_back(E->canOverflow());
Code = serialization::EXPR_UNARY_OPERATOR; Code = serialization::EXPR_UNARY_OPERATOR;
} }

View File

@ -33,3 +33,35 @@ int TestOpaqueValueExpr = 0 ?: 1;
// CHECK-NEXT: OpaqueValueExpr // CHECK-NEXT: OpaqueValueExpr
// CHECK-NEXT: IntegerLiteral // CHECK-NEXT: IntegerLiteral
// CHECK-NEXT: IntegerLiteral // CHECK-NEXT: IntegerLiteral
void TestUnaryOperatorExpr(void) {
char T1 = 1;
int T2 = 1;
T1++;
T2++;
// CHECK: UnaryOperator{{.*}}postfix '++' cannot overflow
// CHECK-NEXT: DeclRefExpr{{.*}}'T1' 'char'
// CHECK-NOT: UnaryOperator{{.*}}postfix '++' cannot overflow
// CHECK: DeclRefExpr{{.*}}'T2' 'int'
-T1;
-T2;
// CHECK: UnaryOperator{{.*}}prefix '-' cannot overflow
// CHECK-NEXT: ImplicitCastExpr
// CHECK-NEXT: ImplicitCastExpr
// CHECK-NEXT: DeclRefExpr{{.*}}'T1' 'char'
// CHECK-NOT: UnaryOperator{{.*}}prefix '-' cannot overflow
// CHECK: ImplicitCastExpr
// CHECK: DeclRefExpr{{.*}}'T2' 'int'
~T1;
~T2;
// CHECK: UnaryOperator{{.*}}prefix '~' cannot overflow
// CHECK-NEXT: ImplicitCastExpr
// CHECK-NEXT: ImplicitCastExpr
// CHECK-NEXT: DeclRefExpr{{.*}}'T1' 'char'
// CHECK: UnaryOperator{{.*}}prefix '~' cannot overflow
// CHECK-NEXT: ImplicitCastExpr
// CHECK-NEXT: DeclRefExpr{{.*}}'T2' 'int'
}