]> granicus.if.org Git - clang/commitdiff
Track in the AST whether the operand to a UnaryOperator can overflow and then use...
authorAaron Ballman <aaron@aaronballman.com>
Tue, 9 Jan 2018 13:07:03 +0000 (13:07 +0000)
committerAaron Ballman <aaron@aaronballman.com>
Tue, 9 Jan 2018 13:07:03 +0000 (13:07 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@322074 91177308-0d34-0410-b5e6-96231b3b80d8

18 files changed:
include/clang/AST/Expr.h
lib/AST/ASTDumper.cpp
lib/AST/ASTImporter.cpp
lib/AST/ExprConstant.cpp
lib/Analysis/BodyFarm.cpp
lib/CodeGen/CGExprScalar.cpp
lib/CodeGen/CGObjC.cpp
lib/CodeGen/CGStmtOpenMP.cpp
lib/Frontend/Rewrite/RewriteModernObjC.cpp
lib/Frontend/Rewrite/RewriteObjC.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprObjC.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaPseudoObject.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
test/Misc/ast-dump-stmt.c

index f2770940372fd12b6e7ed09a3f4ad7161d433337..9d7a29e909f9b9d788744ed45f047d059ca43f48 100644 (file)
@@ -1720,19 +1720,19 @@ public:
 
 private:
   unsigned Opc : 5;
+  unsigned CanOverflow : 1;
   SourceLocation Loc;
   Stmt *Val;
 public:
-
-  UnaryOperator(Expr *input, Opcode opc, QualType type,
-                ExprValueKind VK, ExprObjectKind OK, SourceLocation l)
-    : Expr(UnaryOperatorClass, type, VK, OK,
-           input->isTypeDependent() || type->isDependentType(),
-           input->isValueDependent(),
-           (input->isInstantiationDependent() ||
-            type->isInstantiationDependentType()),
-           input->containsUnexpandedParameterPack()),
-      Opc(opc), Loc(l), Val(input) {}
+  UnaryOperator(Expr *input, Opcode opc, QualType type, ExprValueKind VK,
+                ExprObjectKind OK, SourceLocation l, bool CanOverflow)
+      : Expr(UnaryOperatorClass, type, VK, OK,
+             input->isTypeDependent() || type->isDependentType(),
+             input->isValueDependent(),
+             (input->isInstantiationDependent() ||
+              type->isInstantiationDependentType()),
+             input->containsUnexpandedParameterPack()),
+        Opc(opc), CanOverflow(CanOverflow), Loc(l), Val(input) {}
 
   /// \brief Build an empty unary operator.
   explicit UnaryOperator(EmptyShell Empty)
@@ -1748,6 +1748,15 @@ public:
   SourceLocation getOperatorLoc() const { return Loc; }
   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++.
   static bool isPostfix(Opcode Op) {
     return Op == UO_PostInc || Op == UO_PostDec;
index 22b71e3cf53e1cac0aec1bd833380927a0b10138..e553ba7e7a3f84f33d1ffb15430afe4ea6cb35da 100644 (file)
@@ -2214,12 +2214,14 @@ void ASTDumper::VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E) {
 }
 
 void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) {
-  VisitExpr(Node);
-  OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
-     << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
-}
-
-void ASTDumper::VisitUnaryExprOrTypeTraitExpr(
+  VisitExpr(Node);\r
+  OS << " " << (Node->isPostfix() ? "postfix" : "prefix")\r
+     << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";\r
+  if (!Node->canOverflow())\r
+    OS << " cannot overflow";\r
+}\r
+\r
+void ASTDumper::VisitUnaryExprOrTypeTraitExpr(\r
     const UnaryExprOrTypeTraitExpr *Node) {
   VisitExpr(Node);
   switch(Node->getKind()) {
index 0d1d9807549f59090f070f1948b6aec3364f3254..cca43eed3e62bc11db042d68780fcf9d0416acd4 100644 (file)
@@ -5120,14 +5120,13 @@ Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) {
   if (!SubExpr)
     return nullptr;
 
-  return new (Importer.getToContext()) UnaryOperator(SubExpr, E->getOpcode(),
-                                                     T, E->getValueKind(),
-                                                     E->getObjectKind(),
-                                         Importer.Import(E->getOperatorLoc()));                                        
+  return new (Importer.getToContext()) UnaryOperator(
+      SubExpr, E->getOpcode(), T, E->getValueKind(), E->getObjectKind(),
+      Importer.Import(E->getOperatorLoc()), E->canOverflow());
 }
 
-Expr *ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr(
-                                            UnaryExprOrTypeTraitExpr *E) {
+Expr *
+ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
   QualType ResultType = Importer.Import(E->getType());
   
   if (E->isArgumentType()) {
index 6cbb498abdefec9fec39fe3cfa3f89a8d6c2f049..61bd1e5f129885b4639c5cd924653e81556197be 100644 (file)
@@ -3244,17 +3244,12 @@ static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal,
   }
 
   CompleteObject Obj = findCompleteObject(Info, E, AK_Assign, LVal, LValType);
-  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 {
-struct CompoundAssignSubobjectHandler {
-  EvalInfo &Info;
+  return Obj && modifySubobject(Info, E, Obj, LVal.Designator, Val);\r
+}\r
+\r
+namespace {\r
+struct CompoundAssignSubobjectHandler {\r
+  EvalInfo &Info;\r
   const Expr *E;
   QualType PromotedLHSType;
   BinaryOperatorKind Opcode;
@@ -3370,13 +3365,13 @@ static bool handleCompoundAssignment(
   return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler);
 }
 
-namespace {
-struct IncDecSubobjectHandler {
-  EvalInfo &Info;
-  const Expr *E;
-  AccessKinds AccessKind;
-  APValue *Old;
-
+namespace {\r
+struct IncDecSubobjectHandler {\r
+  EvalInfo &Info;\r
+  const UnaryOperator *E;\r
+  AccessKinds AccessKind;\r
+  APValue *Old;\r
+\r
   typedef bool result_type;
 
   bool checkConst(QualType QT) {
@@ -3442,22 +3437,20 @@ struct IncDecSubobjectHandler {
     }
 
     bool WasNegative = Value.isNegative();
-    if (AccessKind == AK_Increment) {
-      ++Value;
-
-      if (!WasNegative && Value.isNegative() &&
-          isOverflowingIntegerType(Info.Ctx, SubobjType)) {
-        APSInt ActualValue(Value, /*IsUnsigned*/true);
-        return HandleOverflow(Info, E, ActualValue, SubobjType);
-      }
-    } else {
-      --Value;
-
-      if (WasNegative && !Value.isNegative() &&
-          isOverflowingIntegerType(Info.Ctx, SubobjType)) {
-        unsigned BitWidth = Value.getBitWidth();
-        APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false);
-        ActualValue.setBit(BitWidth);
+    if (AccessKind == AK_Increment) {\r
+      ++Value;\r
+\r
+      if (!WasNegative && Value.isNegative() && E->canOverflow()) {\r
+        APSInt ActualValue(Value, /*IsUnsigned*/true);\r
+        return HandleOverflow(Info, E, ActualValue, SubobjType);\r
+      }\r
+    } else {\r
+      --Value;\r
+\r
+      if (WasNegative && !Value.isNegative() && E->canOverflow()) {\r
+        unsigned BitWidth = Value.getBitWidth();\r
+        APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false);\r
+        ActualValue.setBit(BitWidth);\r
         return HandleOverflow(Info, E, ActualValue, SubobjType);
       }
     }
@@ -3512,13 +3505,13 @@ static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal,
     Info.FFDiag(E);
     return false;
   }
-
-  AccessKinds AK = IsIncrement ? AK_Increment : AK_Decrement;
-  CompleteObject Obj = findCompleteObject(Info, E, AK, LVal, LValType);
-  IncDecSubobjectHandler Handler = { Info, E, AK, Old };
-  return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler);
-}
-
+\r
+  AccessKinds AK = IsIncrement ? AK_Increment : AK_Decrement;\r
+  CompleteObject Obj = findCompleteObject(Info, E, AK, LVal, LValType);\r
+  IncDecSubobjectHandler Handler = {Info, cast<UnaryOperator>(E), AK, Old};\r
+  return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler);\r
+}\r
+\r
 /// Build an lvalue for the object argument of a member function call.
 static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
                                    LValue &This) {
@@ -8875,13 +8868,13 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
     return Visit(E->getSubExpr());
   case UO_Minus: {
     if (!Visit(E->getSubExpr()))
-      return false;
-    if (!Result.isInt()) return Error(E);
-    const APSInt &Value = Result.getInt();
-    if (Value.isSigned() && Value.isMinSignedValue() &&
-        !HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
-                        E->getType()))
-      return false;
+      return false;\r
+    if (!Result.isInt()) return Error(E);\r
+    const APSInt &Value = Result.getInt();\r
+    if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow() &&\r
+        !HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),\r
+                        E->getType()))\r
+      return false;\r
     return Success(-Value, E);
   }
   case UO_Not: {
index 89ca8484819d181f3e3baed21090f36c2614fdd7..492d01f6c98e86f143bd42e3e4bec1defcfb457d 100644 (file)
@@ -149,7 +149,8 @@ DeclRefExpr *ASTMaker::makeDeclRefExpr(
 
 UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType 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) {
@@ -441,7 +442,8 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
       /* opc=*/ UO_LNot,
       /* QualType=*/ C.IntTy,
       /* ExprValueKind=*/ VK_RValue,
-      /* ExprObjectKind=*/ OK_Ordinary, SourceLocation());
+      /* ExprObjectKind=*/ OK_Ordinary, SourceLocation(),
+      /* CanOverflow*/ false);
 
   // Create assignment.
   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.
   Expr *DoneValue =
       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 =
     M.makeAssignment(
index c46215067a68c47244cc6194a4b3b9954bbf89f7..668c572942fd559bbae467855c1dd9ec7e311634 100644 (file)
@@ -162,13 +162,13 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
   // we can elide the overflow check.
   if (!Op.mayHaveIntegerOverflow())
     return true;
-
-  // If a unary op has a widened operand, the op cannot overflow.
-  if (const auto *UO = dyn_cast<UnaryOperator>(Op.E))
-    return IsWidenedIntegerOp(Ctx, UO->getSubExpr());
-
-  // We usually don't need overflow checks for binops with widened operands.
-  // Multiplication with promoted unsigned operands is a special case.
+\r
+  // If a unary op has a widened operand, the op cannot overflow.\r
+  if (const auto *UO = dyn_cast<UnaryOperator>(Op.E))\r
+    return !UO->canOverflow();\r
+\r
+  // We usually don't need overflow checks for binops with widened operands.\r
+  // Multiplication with promoted unsigned operands is a special case.\r
   const auto *BO = cast<BinaryOperator>(Op.E);
   auto OptionalLHSTy = getUnwidenedIntegerType(Ctx, BO->getLHS());
   if (!OptionalLHSTy)
@@ -1870,13 +1870,13 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
     return Builder.CreateAdd(InVal, Amount, Name);
   case LangOptions::SOB_Undefined:
     if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
-      return Builder.CreateNSWAdd(InVal, Amount, Name);
-    // Fall through.
-  case LangOptions::SOB_Trapping:
-    if (IsWidenedIntegerOp(CGF.getContext(), E->getSubExpr()))
-      return Builder.CreateNSWAdd(InVal, Amount, Name);
-    return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, InVal, IsInc));
-  }
+      return Builder.CreateNSWAdd(InVal, Amount, Name);\r
+    // Fall through.\r
+  case LangOptions::SOB_Trapping:\r
+    if (!E->canOverflow())\r
+      return Builder.CreateNSWAdd(InVal, Amount, Name);\r
+    return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, InVal, IsInc));\r
+  }\r
   llvm_unreachable("Unknown SignedOverflowBehaviorTy");
 }
 
@@ -1952,17 +1952,15 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
     value = Builder.getTrue();
 
   // Most common case by far: integer increment.
-  } else if (type->isIntegerType()) {
-    // 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.
-    bool CanOverflow = value->getType()->getIntegerBitWidth() >=
-                       CGF.IntTy->getIntegerBitWidth();
-    if (CanOverflow && type->isSignedIntegerOrEnumerationType()) {
-      value = EmitIncDecConsiderOverflowBehavior(E, value, isInc);
-    } else if (CanOverflow && type->isUnsignedIntegerType() &&
-               CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) {
-      value =
-          EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, value, isInc));
+  } else if (type->isIntegerType()) {\r
+    // Note that signed integer inc/dec with width less than int can't\r
+    // overflow because of promotion rules; we're just eliding a few steps here.\r
+    if (E->canOverflow() && type->isSignedIntegerOrEnumerationType()) {\r
+      value = EmitIncDecConsiderOverflowBehavior(E, value, isInc);\r
+    } else if (E->canOverflow() && type->isUnsignedIntegerType() &&\r
+               CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) {\r
+      value =\r
+          EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, value, isInc));\r
     } else {
       llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount, true);
       value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
index f26263d9472d37a740582a9401cfaba2f80aa002..894d0d5fe2f35c5cee6124fd2183ab28ee59ec1c 100644 (file)
@@ -3268,12 +3268,12 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
   DeclRefExpr DstExpr(&DstDecl, false, DestTy,
                       VK_RValue, SourceLocation());
   UnaryOperator DST(&DstExpr, UO_Deref, DestTy->getPointeeType(),
-                    VK_LValue, OK_Ordinary, SourceLocation());
+                    VK_LValue, OK_Ordinary, SourceLocation(), false);
   
   DeclRefExpr SrcExpr(&SrcDecl, false, SrcTy,
                       VK_RValue, SourceLocation());
   UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
-                    VK_LValue, OK_Ordinary, SourceLocation());
+                    VK_LValue, OK_Ordinary, SourceLocation(), false);
   
   Expr *Args[2] = { &DST, &SRC };
   CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
@@ -3351,7 +3351,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
                       VK_RValue, SourceLocation());
   
   UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
-                    VK_LValue, OK_Ordinary, SourceLocation());
+                    VK_LValue, OK_Ordinary, SourceLocation(), false);
   
   CXXConstructExpr *CXXConstExpr = 
     cast<CXXConstructExpr>(PID->getGetterCXXConstructor());
index 07c1e3aa5150543140d4065c580849d9da2f807b..7221ad95b664f53693c7ede4a74a897f3366db83 100644 (file)
@@ -2483,7 +2483,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
                         OK_Ordinary, S.getLocStart(), FPOptions());
     // Increment for loop counter.
     UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
-                      S.getLocStart());
+                      S.getLocStart(), true);
     auto BodyGen = [Stmt, CS, &S, &IV](CodeGenFunction &CGF) {
       // Iterate through all sections and emit a switch construct:
       // switch (IV) {
index 1954b24aedad3bf23148327b59a17a532c714a44..55f81c2860836637e845c426261150cd945bbb50 100644 (file)
@@ -2590,7 +2590,7 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
   Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
                                  Context->getPointerType(DRE->getType()),
                                            VK_RValue, OK_Ordinary,
-                                           SourceLocation());
+                                           SourceLocation(), false);
   // cast to NSConstantString *
   CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
                                             CK_CPointerToObjCPointerCast, Unop);
@@ -3295,7 +3295,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
       SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
                                Context->getPointerType(SuperRep->getType()),
                                              VK_RValue, OK_Ordinary,
-                                             SourceLocation());
+                                             SourceLocation(), false);
       SuperRep = NoTypeInfoCStyleCastExpr(Context,
                                           Context->getPointerType(superType),
                                           CK_BitCast, SuperRep);
@@ -3313,7 +3313,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
       SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
                                Context->getPointerType(SuperRep->getType()),
                                              VK_RValue, OK_Ordinary,
-                                             SourceLocation());
+                                             SourceLocation(), false);
     }
     MsgExprs.push_back(SuperRep);
     break;
@@ -3389,7 +3389,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
       SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
                                Context->getPointerType(SuperRep->getType()),
                                VK_RValue, OK_Ordinary,
-                               SourceLocation());
+                               SourceLocation(), false);
       SuperRep = NoTypeInfoCStyleCastExpr(Context,
                                Context->getPointerType(superType),
                                CK_BitCast, SuperRep);
@@ -4720,7 +4720,7 @@ Stmt *RewriteModernObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
       return DRE;
   Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(),
                                           VK_LValue, OK_Ordinary,
-                                          DRE->getLocation());
+                                          DRE->getLocation(), false);
   // Need parens to enforce precedence.
   ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), 
                                           Exp);
@@ -5314,7 +5314,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
                                 UO_AddrOf,
                                 Context->getPointerType(Context->VoidPtrTy), 
                                 VK_RValue, OK_Ordinary,
-                                SourceLocation());
+                                SourceLocation(), false);
   InitExprs.push_back(DescRefExpr); 
   
   // Add initializers for any closure decl refs.
@@ -5332,7 +5332,8 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
           QualType QT = (*I)->getType();
           QT = Context->getPointerType(QT);
           Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
-                                            OK_Ordinary, SourceLocation());
+                                            OK_Ordinary, SourceLocation(),
+                                            false);
         }
       } else if (isTopLevelBlockPointerType((*I)->getType())) {
         FD = SynthBlockInitFunctionDecl((*I)->getName());
@@ -5348,7 +5349,8 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
           QualType QT = (*I)->getType();
           QT = Context->getPointerType(QT);
           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)
           Exp = new (Context) UnaryOperator(Exp, UO_AddrOf,
                                      Context->getPointerType(Exp->getType()),
-                                     VK_RValue, OK_Ordinary, SourceLocation());
+                                     VK_RValue, OK_Ordinary, SourceLocation(),
+                                     false);
       Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
       InitExprs.push_back(Exp);
     }
@@ -5414,7 +5417,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
   
   NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
                              Context->getPointerType(NewRep->getType()),
-                             VK_RValue, OK_Ordinary, SourceLocation());
+                             VK_RValue, OK_Ordinary, SourceLocation(), false);
   NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
                                     NewRep);
   // Put Paren around the call.
@@ -7558,7 +7561,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
       
       Expr *Exp = new (Context) UnaryOperator(castExpr, UO_Deref, IvarT,
                                               VK_LValue, OK_Ordinary,
-                                              SourceLocation());
+                                              SourceLocation(), false);
       PE = new (Context) ParenExpr(OldRange.getBegin(),
                                    OldRange.getEnd(),
                                    Exp);
index 096b81bc3f08cbd62d87bf9b09e0ad667b076e1f..37398e5de0612aa4566f20d58293b75890a7fad7 100644 (file)
@@ -2511,7 +2511,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
   Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
                                  Context->getPointerType(DRE->getType()),
                                            VK_RValue, OK_Ordinary,
-                                           SourceLocation());
+                                           SourceLocation(), false);
   // cast to NSConstantString *
   CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
                                             CK_CPointerToObjCPointerCast, Unop);
@@ -2712,7 +2712,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
       SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
                                Context->getPointerType(SuperRep->getType()),
                                              VK_RValue, OK_Ordinary,
-                                             SourceLocation());
+                                             SourceLocation(), false);
       SuperRep = NoTypeInfoCStyleCastExpr(Context,
                                           Context->getPointerType(superType),
                                           CK_BitCast, SuperRep);
@@ -2730,7 +2730,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
       SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
                                Context->getPointerType(SuperRep->getType()),
                                              VK_RValue, OK_Ordinary,
-                                             SourceLocation());
+                                             SourceLocation(), false);
     }
     MsgExprs.push_back(SuperRep);
     break;
@@ -2806,7 +2806,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
       SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
                                Context->getPointerType(SuperRep->getType()),
                                VK_RValue, OK_Ordinary,
-                               SourceLocation());
+                               SourceLocation(), false);
       SuperRep = NoTypeInfoCStyleCastExpr(Context,
                                Context->getPointerType(superType),
                                CK_BitCast, SuperRep);
@@ -3045,7 +3045,7 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
                                                VK_LValue, SourceLocation());
   Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf,
                              Context->getPointerType(DRE->getType()),
-                             VK_RValue, OK_Ordinary, SourceLocation());
+                             VK_RValue, OK_Ordinary, SourceLocation(), false);
   CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(),
                                                 CK_BitCast,
                                                 DerefExpr);
@@ -3875,7 +3875,7 @@ Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
       return DRE;
   Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(),
                                           VK_LValue, OK_Ordinary,
-                                          DRE->getLocation());
+                                          DRE->getLocation(), false);
   // Need parens to enforce precedence.
   ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), 
                                           Exp);
@@ -4438,7 +4438,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
                                 UO_AddrOf,
                                 Context->getPointerType(Context->VoidPtrTy), 
                                 VK_RValue, OK_Ordinary,
-                                SourceLocation());
+                                SourceLocation(), false);
   InitExprs.push_back(DescRefExpr); 
   
   // Add initializers for any closure decl refs.
@@ -4456,7 +4456,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
           QualType QT = (*I)->getType();
           QT = Context->getPointerType(QT);
           Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
-                                            OK_Ordinary, SourceLocation());
+                                            OK_Ordinary, SourceLocation(),
+                                            false);
         }
       } else if (isTopLevelBlockPointerType((*I)->getType())) {
         FD = SynthBlockInitFunctionDecl((*I)->getName());
@@ -4472,7 +4473,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
           QualType QT = (*I)->getType();
           QT = Context->getPointerType(QT);
           Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
-                                            OK_Ordinary, SourceLocation());
+                                            OK_Ordinary, SourceLocation(),
+                                            false);
         }
       }
       InitExprs.push_back(Exp);
@@ -4509,9 +4511,9 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
       // captured nested byref variable has its address passed. Do not take
       // its address again.
       if (!isNestedCapturedVar)
-          Exp = new (Context) UnaryOperator(Exp, UO_AddrOf,
-                                     Context->getPointerType(Exp->getType()),
-                                     VK_RValue, OK_Ordinary, SourceLocation());
+        Exp = new (Context) UnaryOperator(
+            Exp, UO_AddrOf, Context->getPointerType(Exp->getType()), VK_RValue,
+            OK_Ordinary, SourceLocation(), false);
       Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
       InitExprs.push_back(Exp);
     }
@@ -4529,7 +4531,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
                                   FType, VK_LValue, SourceLocation());
   NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
                              Context->getPointerType(NewRep->getType()),
-                             VK_RValue, OK_Ordinary, SourceLocation());
+                             VK_RValue, OK_Ordinary, SourceLocation(), false);
   NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
                                     NewRep);
   BlockDeclRefs.clear();
index 5e24649c71beada341d798b3b7cab5a99d6ff8b9..f0a176b14cff79f8021bd1dade60fefc859414e7 100644 (file)
@@ -10990,11 +10990,11 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
   Expr *From = FromB.build(S, Loc);
   From = new (S.Context) UnaryOperator(From, UO_AddrOf,
                          S.Context.getPointerType(From->getType()),
-                         VK_RValue, OK_Ordinary, Loc);
+                         VK_RValue, OK_Ordinary, Loc, false);
   Expr *To = ToB.build(S, Loc);
   To = new (S.Context) UnaryOperator(To, UO_AddrOf,
                        S.Context.getPointerType(To->getType()),
-                       VK_RValue, OK_Ordinary, Loc);
+                       VK_RValue, OK_Ordinary, Loc, false);
 
   const Type *E = T->getBaseElementTypeUnsafe();
   bool NeedsCollectableMemCpy =
@@ -11230,16 +11230,18 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
   Expr *Comparison
     = new (S.Context) BinaryOperator(IterationVarRefRVal.build(S, Loc),
                      IntegerLiteral::Create(S.Context, Upper, SizeType, Loc),
-                                     BO_NE, S.Context.BoolTy,
-                                     VK_RValue, OK_Ordinary, Loc, FPOptions());
-
-  // Create the pre-increment of the iteration variable.
-  Expr *Increment
-    = new (S.Context) UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc,
-                                    SizeType, VK_LValue, OK_Ordinary, Loc);
-
-  // Construct the loop that copies all elements of this array.
-  return S.ActOnForStmt(
+                                     BO_NE, S.Context.BoolTy,\r
+                                     VK_RValue, OK_Ordinary, Loc, FPOptions());\r
+\r
+  // Create the pre-increment of the iteration variable. We can determine\r
+  // whether the increment will overflow based on the value of the array\r
+  // bound.\r
+  Expr *Increment = new (S.Context)\r
+      UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc, SizeType,\r
+                    VK_LValue, OK_Ordinary, Loc, Upper.isMaxValue());\r
+\r
+  // Construct the loop that copies all elements of this array.\r
+  return S.ActOnForStmt(\r
       Loc, Loc, InitStmt,
       S.ActOnCondition(nullptr, Loc, Comparison, Sema::ConditionKind::Boolean),
       S.MakeFullDiscardedValueExpr(Increment), Loc, Copy.get());
index a6f3ee2c09475b5fb0c3ace4254e7caa2f29cb58..1d7a5d2e128b30431ccff43478beb00b9155df52 100644 (file)
@@ -12178,6 +12178,16 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
   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,
                                       UnaryOperatorKind Opc,
                                       Expr *InputExpr) {
@@ -12185,6 +12195,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
   ExprValueKind VK = VK_RValue;
   ExprObjectKind OK = OK_Ordinary;
   QualType resultType;
+  bool CanOverflow = false;
+
   bool ConvertHalfVec = false;
   if (getLangOpts().OpenCL) {
     QualType Ty = InputExpr->getType();
@@ -12210,6 +12222,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
                                                 Opc == UO_PostInc,
                                                 Opc == UO_PreInc ||
                                                 Opc == UO_PreDec);
+    CanOverflow = isOverflowingIntegerType(Context, resultType);
     break;
   case UO_AddrOf:
     resultType = CheckAddressOfOperand(Input, OpLoc);
@@ -12223,6 +12236,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
   }
   case UO_Plus:
   case UO_Minus:
+    CanOverflow = Opc == UO_Minus &&
+                  isOverflowingIntegerType(Context, Input.get()->getType());
     Input = UsualUnaryConversions(Input.get());
     if (Input.isInvalid()) return ExprError();
     // 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())
       return ExprError();
     resultType = Input.get()->getType();
+
     if (resultType->isDependentType())
       break;
     // 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());
 
   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.
   if (ConvertHalfVec)
     return convertVector(UO, Context.HalfTy, *this);
index cd0c2c47ae4c5a1b9ebdd3c4a3c282a4d0ff1e10..6a725c485d57e2481d5b39b6b263a0d3fd86f7bd 100644 (file)
@@ -4276,9 +4276,9 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) {
   } else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) {
     assert(uo->getOpcode() == UO_Extension);
     Expr *sub = stripARCUnbridgedCast(uo->getSubExpr());
-    return new (Context) UnaryOperator(sub, UO_Extension, sub->getType(),
-                                   sub->getValueKind(), sub->getObjectKind(),
-                                       uo->getOperatorLoc());
+    return new (Context)
+        UnaryOperator(sub, UO_Extension, sub->getType(), sub->getValueKind(),
+                      sub->getObjectKind(), uo->getOperatorLoc(), false);
   } else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
     assert(!gse->isResultDependent());
 
index b760cdcd34e57d72181deea979d1f699a52177e8..e7eb309c40b4aa18677238dcfd8112fded97f230 100644 (file)
@@ -12022,7 +12022,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
   if (Input->isTypeDependent()) {
     if (Fns.empty())
       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
     UnresolvedLookupExpr *Fn
@@ -13552,7 +13552,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
 
         return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType,
                                            VK_RValue, OK_Ordinary,
-                                           UnOp->getOperatorLoc());
+                                           UnOp->getOperatorLoc(), false);
       }
     }
     Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
@@ -13563,7 +13563,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
     return new (Context) UnaryOperator(SubExpr, UO_AddrOf,
                                      Context.getPointerType(SubExpr->getType()),
                                        VK_RValue, OK_Ordinary,
-                                       UnOp->getOperatorLoc());
+                                       UnOp->getOperatorLoc(), false);
   }
 
   // C++ [except.spec]p17:
index 58980be64a30fc9421b09e14d2de888b4c7e4564..f09a6f7158fbd46345ec544939f76e3b67d923e1 100644 (file)
@@ -132,7 +132,8 @@ namespace {
                                              uop->getType(),
                                              uop->getValueKind(),
                                              uop->getObjectKind(),
-                                             uop->getOperatorLoc());
+                                             uop->getOperatorLoc(),
+                                             uop->canOverflow());
       }
 
       if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
@@ -524,15 +525,18 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
   addSemanticExpr(result.get());
   if (UnaryOperator::isPrefix(opcode) && !captureSetValueAsResult() &&
       !result.get()->getType()->isVoidType() &&
-      (result.get()->isTypeDependent() || CanCaptureValue(result.get())))
-    setResultToLastSemantic();
-
-  UnaryOperator *syntactic =
-    new (S.Context) UnaryOperator(syntacticOp, opcode, resultType,
-                                  VK_LValue, OK_Ordinary, opcLoc);
-  return complete(syntactic);
-}
-
+      (result.get()->isTypeDependent() || CanCaptureValue(result.get())))\r
+    setResultToLastSemantic();\r
+\r
+  UnaryOperator *syntactic = new (S.Context) UnaryOperator(\r
+      syntacticOp, opcode, resultType, VK_LValue, OK_Ordinary, opcLoc,\r
+      !resultType->isDependentType()\r
+          ? S.Context.getTypeSize(resultType) >=\r
+                S.Context.getTypeSize(S.Context.IntTy)\r
+          : false);\r
+  return complete(syntactic);\r
+}\r
+\r
 
 //===----------------------------------------------------------------------===//
 //  Objective-C @property and implicit property references
@@ -1550,7 +1554,7 @@ ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc,
   // Do nothing if the operand is dependent.
   if (op->isTypeDependent())
     return new (Context) UnaryOperator(op, opcode, Context.DependentTy,
-                                       VK_RValue, OK_Ordinary, opcLoc);
+                                       VK_RValue, OK_Ordinary, opcLoc, false);
 
   assert(UnaryOperator::isIncrementDecrementOp(opcode));
   Expr *opaqueRef = op->IgnoreParens();
@@ -1630,15 +1634,15 @@ static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) {
 /// capable of rebuilding a tree without stripping implicit
 /// operations.
 Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
-  Expr *syntax = E->getSyntacticForm();
-  if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) {
-    Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr());
-    return new (Context) UnaryOperator(op, uop->getOpcode(), uop->getType(),
-                                       uop->getValueKind(), uop->getObjectKind(),
-                                       uop->getOperatorLoc());
-  } else if (CompoundAssignOperator *cop
-               = dyn_cast<CompoundAssignOperator>(syntax)) {
-    Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS());
+  Expr *syntax = E->getSyntacticForm();\r
+  if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) {\r
+    Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr());\r
+    return new (Context) UnaryOperator(\r
+        op, uop->getOpcode(), uop->getType(), uop->getValueKind(),\r
+        uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow());\r
+  } else if (CompoundAssignOperator *cop\r
+               = dyn_cast<CompoundAssignOperator>(syntax)) {\r
+    Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS());\r
     Expr *rhs = cast<OpaqueValueExpr>(cop->getRHS())->getSourceExpr();
     return new (Context) CompoundAssignOperator(lhs, rhs, cop->getOpcode(),
                                                 cop->getType(),
index 6163b811c7691d4aa9a5422fe6f86b50f682a472..4938b0e9026a1137a72d5a0b49e6ec9dd45158a6 100644 (file)
@@ -550,12 +550,13 @@ void ASTStmtReader::VisitParenListExpr(ParenListExpr *E) {
 
 void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) {
   VisitExpr(E);
-  E->setSubExpr(Record.readSubExpr());
-  E->setOpcode((UnaryOperator::Opcode)Record.readInt());
-  E->setOperatorLoc(ReadSourceLocation());
-}
-
-void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
+  E->setSubExpr(Record.readSubExpr());\r
+  E->setOpcode((UnaryOperator::Opcode)Record.readInt());\r
+  E->setOperatorLoc(ReadSourceLocation());\r
+  E->setCanOverflow(Record.readInt());\r
+}\r
+\r
+void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {\r
   VisitExpr(E);
   assert(E->getNumComponents() == Record.peekInt());
   Record.skipInts(1);
index c5f4495d2f01341ac4ca63cfaa3f32168084de19..6fd03725d43dbc2607b497ed1009cc9f01230ce2 100644 (file)
@@ -506,12 +506,13 @@ void ASTStmtWriter::VisitParenListExpr(ParenListExpr *E) {
 
 void ASTStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
   VisitExpr(E);
-  Record.AddStmt(E->getSubExpr());
-  Record.push_back(E->getOpcode()); // FIXME: stable encoding
-  Record.AddSourceLocation(E->getOperatorLoc());
-  Code = serialization::EXPR_UNARY_OPERATOR;
-}
-
+  Record.AddStmt(E->getSubExpr());\r
+  Record.push_back(E->getOpcode()); // FIXME: stable encoding\r
+  Record.AddSourceLocation(E->getOperatorLoc());\r
+  Record.push_back(E->canOverflow());\r
+  Code = serialization::EXPR_UNARY_OPERATOR;\r
+}\r
+\r
 void ASTStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) {
   VisitExpr(E);
   Record.push_back(E->getNumComponents());
index 1f21cf03f6956346c29387436504d942146b35f2..461893188a1648565aefff0879ec925c66cca553 100644 (file)
@@ -30,6 +30,38 @@ int TestOpaqueValueExpr = 0 ?: 1;
 // CHECK-NEXT:   IntegerLiteral
 // CHECK-NEXT:   OpaqueValueExpr
 // CHECK-NEXT:     IntegerLiteral
-// CHECK-NEXT:   OpaqueValueExpr
-// CHECK-NEXT:     IntegerLiteral
-// CHECK-NEXT:   IntegerLiteral
+// CHECK-NEXT:   OpaqueValueExpr\r
+// CHECK-NEXT:     IntegerLiteral\r
+// CHECK-NEXT:   IntegerLiteral\r
+\r
+void TestUnaryOperatorExpr(void) {\r
+  char T1 = 1;\r
+  int T2 = 1;\r
+\r
+  T1++;\r
+  T2++;\r
+  // CHECK:      UnaryOperator{{.*}}postfix '++' cannot overflow\r
+  // CHECK-NEXT:   DeclRefExpr{{.*}}'T1' 'char'\r
+  // CHECK-NOT:  UnaryOperator{{.*}}postfix '++' cannot overflow\r
+  // CHECK:        DeclRefExpr{{.*}}'T2' 'int'\r
+\r
+  -T1;\r
+  -T2;\r
+  // CHECK:      UnaryOperator{{.*}}prefix '-' cannot overflow\r
+  // CHECK-NEXT:   ImplicitCastExpr\r
+  // CHECK-NEXT:     ImplicitCastExpr\r
+  // CHECK-NEXT:       DeclRefExpr{{.*}}'T1' 'char'\r
+  // CHECK-NOT:  UnaryOperator{{.*}}prefix '-' cannot overflow\r
+  // CHECK:        ImplicitCastExpr\r
+  // CHECK:          DeclRefExpr{{.*}}'T2' 'int'\r
+\r
+  ~T1;\r
+  ~T2;\r
+  // CHECK:      UnaryOperator{{.*}}prefix '~' cannot overflow\r
+  // CHECK-NEXT:   ImplicitCastExpr\r
+  // CHECK-NEXT:     ImplicitCastExpr\r
+  // CHECK-NEXT:       DeclRefExpr{{.*}}'T1' 'char'\r
+  // CHECK:     UnaryOperator{{.*}}prefix '~' cannot overflow\r
+  // CHECK-NEXT:     ImplicitCastExpr\r
+  // CHECK-NEXT:       DeclRefExpr{{.*}}'T2' 'int'\r
+}\r