forked from OSchip/llvm-project
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:
parent
1f97363e5f
commit
a503855906
|
@ -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;
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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'
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue