lebedev.ri updated this revision to Diff 156568.
lebedev.ri marked 4 inline comments as done.
lebedev.ri added a comment.

- Use `unsigned`, not bool.
- Serialization, although without tests, and likely incompatible with previous 
versions.


Repository:
  rC Clang

https://reviews.llvm.org/D49508

Files:
  include/clang/AST/Expr.h
  include/clang/AST/Stmt.h
  lib/AST/ASTDumper.cpp
  lib/Sema/SemaCast.cpp
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterDecl.cpp
  lib/Serialization/ASTWriterStmt.cpp
  test/Sema/multistep-explicit-cast.c
  test/SemaCXX/multistep-explicit-cast.cpp

Index: test/SemaCXX/multistep-explicit-cast.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/multistep-explicit-cast.cpp
@@ -0,0 +1,155 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -ast-dump %s | FileCheck %s
+
+// We are checking that implicit casts don't get marked with 'PartOfExplicitCast',
+// while in explicit casts, the implicitly-inserted implicit casts are marked with 'PartOfExplicitCast'
+
+unsigned char implicitcast_0(unsigned int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} implicitcast_0 'unsigned char (unsigned int)'{{$}}
+  // CHECK: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned char' <IntegralCast>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned int' <LValueToRValue>{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'unsigned int' lvalue ParmVar {{.*}} 'x' 'unsigned int'{{$}}
+  return x;
+}
+
+signed char implicitcast_1(unsigned int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} implicitcast_1 'signed char (unsigned int)'{{$}}
+  // CHECK: ImplicitCastExpr {{.*}} <col:{{.*}}> 'signed char' <IntegralCast>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned int' <LValueToRValue>{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'unsigned int' lvalue ParmVar {{.*}} 'x' 'unsigned int'{{$}}
+  return x;
+}
+
+unsigned char implicitcast_2(signed int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} implicitcast_2 'unsigned char (int)'{{$}}
+  // CHECK: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned char' <IntegralCast>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'int' <LValueToRValue>{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'int' lvalue ParmVar {{.*}} 'x' 'int'{{$}}
+  return x;
+}
+
+signed char implicitcast_3(signed int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} implicitcast_3 'signed char (int)'{{$}}
+  // CHECK: ImplicitCastExpr {{.*}} <col:{{.*}}> 'signed char' <IntegralCast>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'int' <LValueToRValue>{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'int' lvalue ParmVar {{.*}} 'x' 'int'{{$}}
+  return x;
+}
+
+//----------------------------------------------------------------------------//
+
+unsigned char cstylecast_0(unsigned int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cstylecast_0 'unsigned char (unsigned int)'{{$}}
+  // CHECK: CStyleCastExpr {{.*}} <col:{{.*}}> 'unsigned char' <NoOp>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned char' <IntegralCast> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'unsigned int' lvalue ParmVar {{.*}} 'x' 'unsigned int'{{$}}
+  return (unsigned char)x;
+}
+
+signed char cstylecast_1(unsigned int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cstylecast_1 'signed char (unsigned int)'{{$}}
+  // CHECK: CStyleCastExpr {{.*}} <col:{{.*}}> 'signed char' <NoOp>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'signed char' <IntegralCast> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'unsigned int' lvalue ParmVar {{.*}} 'x' 'unsigned int'{{$}}
+  return (signed char)x;
+}
+
+unsigned char cstylecast_2(signed int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cstylecast_2 'unsigned char (int)'{{$}}
+  // CHECK: CStyleCastExpr {{.*}} <col:{{.*}}> 'unsigned char' <NoOp>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned char' <IntegralCast> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'int' lvalue ParmVar {{.*}} 'x' 'int'{{$}}
+  return (unsigned char)x;
+}
+
+signed char cstylecast_3(signed int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cstylecast_3 'signed char (int)'{{$}}
+  // CHECK: CStyleCastExpr {{.*}} <col:{{.*}}> 'signed char' <NoOp>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'signed char' <IntegralCast> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'int' lvalue ParmVar {{.*}} 'x' 'int'{{$}}
+  return (signed char)x;
+}
+
+//----------------------------------------------------------------------------//
+
+unsigned char cxxstaticcast_0(unsigned int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cxxstaticcast_0 'unsigned char (unsigned int)'{{$}}
+  // CHECK: CXXStaticCastExpr {{.*}} <col:{{.*}}> 'unsigned char' static_cast<unsigned char> <NoOp>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned char' <IntegralCast> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'unsigned int' lvalue ParmVar {{.*}} 'x' 'unsigned int'{{$}}
+  return static_cast<unsigned char>(x);
+}
+
+signed char cxxstaticcast_1(unsigned int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cxxstaticcast_1 'signed char (unsigned int)'{{$}}
+  // CHECK: CXXStaticCastExpr {{.*}} <col:{{.*}}> 'signed char' static_cast<signed char> <NoOp>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'signed char' <IntegralCast> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'unsigned int' lvalue ParmVar {{.*}} 'x' 'unsigned int'{{$}}
+  return static_cast<signed char>(x);
+}
+
+unsigned char cxxstaticcast_2(signed int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cxxstaticcast_2 'unsigned char (int)'{{$}}
+  // CHECK: CXXStaticCastExpr {{.*}} <col:{{.*}}> 'unsigned char' static_cast<unsigned char> <NoOp>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned char' <IntegralCast> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'int' lvalue ParmVar {{.*}} 'x' 'int'{{$}}
+  return static_cast<unsigned char>(x);
+}
+
+signed char cxxstaticcast_3(signed int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cxxstaticcast_3 'signed char (int)'{{$}}
+  // CHECK: CXXStaticCastExpr {{.*}} <col:{{.*}}> 'signed char' static_cast<signed char> <NoOp>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'signed char' <IntegralCast> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'int' lvalue ParmVar {{.*}} 'x' 'int'{{$}}
+  return static_cast<signed char>(x);
+}
+
+//----------------------------------------------------------------------------//
+
+using UnsignedChar = unsigned char;
+using SignedChar = signed char;
+using UnsignedInt = unsigned int;
+using SignedInt = signed int;
+
+UnsignedChar cxxfunctionalcast_0(UnsignedInt x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cxxfunctionalcast_0 'UnsignedChar (UnsignedInt)'{{$}}
+  // CHECK: CXXFunctionalCastExpr {{.*}} <col:{{.*}}> 'UnsignedChar':'unsigned char' functional cast to UnsignedChar <NoOp>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'UnsignedChar':'unsigned char' <IntegralCast> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'UnsignedInt':'unsigned int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'UnsignedInt':'unsigned int' lvalue ParmVar {{.*}} 'x' 'UnsignedInt':'unsigned int'{{$}}
+  return UnsignedChar(x);
+}
+
+SignedChar cxxfunctionalcast_1(UnsignedInt x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cxxfunctionalcast_1 'SignedChar (UnsignedInt)'{{$}}
+  // CHECK: CXXFunctionalCastExpr {{.*}} <col:{{.*}}> 'SignedChar':'signed char' functional cast to SignedChar <NoOp>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'SignedChar':'signed char' <IntegralCast> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'UnsignedInt':'unsigned int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'UnsignedInt':'unsigned int' lvalue ParmVar {{.*}} 'x' 'UnsignedInt':'unsigned int'{{$}}
+  return SignedChar(x);
+}
+
+UnsignedChar cxxfunctionalcast_2(SignedInt x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cxxfunctionalcast_2 'UnsignedChar (SignedInt)'{{$}}
+  // CHECK: CXXFunctionalCastExpr {{.*}} <col:{{.*}}> 'UnsignedChar':'unsigned char' functional cast to UnsignedChar <NoOp>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'UnsignedChar':'unsigned char' <IntegralCast> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'SignedInt':'int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'SignedInt':'int' lvalue ParmVar {{.*}} 'x' 'SignedInt':'int'{{$}}
+  return UnsignedChar(x);
+}
+
+SignedChar cxxfunctionalcast_3(SignedInt x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cxxfunctionalcast_3 'SignedChar (SignedInt)'{{$}}
+  // CHECK: CXXFunctionalCastExpr {{.*}} <col:{{.*}}> 'SignedChar':'signed char' functional cast to SignedChar <NoOp>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'SignedChar':'signed char' <IntegralCast> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'SignedInt':'int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'SignedInt':'int' lvalue ParmVar {{.*}} 'x' 'SignedInt':'int'{{$}}
+  return SignedChar(x);
+}
Index: test/Sema/multistep-explicit-cast.c
===================================================================
--- /dev/null
+++ test/Sema/multistep-explicit-cast.c
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -ast-dump %s | FileCheck %s
+
+// We are checking that implicit casts don't get marked with 'PartOfExplicitCast',
+// while in explicit casts, the implicitly-inserted implicit casts are marked with 'PartOfExplicitCast'
+
+unsigned char implicitcast_0(unsigned int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} implicitcast_0 'unsigned char (unsigned int)'{{$}}
+  // CHECK: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned char' <IntegralCast>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned int' <LValueToRValue>{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'unsigned int' lvalue ParmVar {{.*}} 'x' 'unsigned int'{{$}}
+  return x;
+}
+
+signed char implicitcast_1(unsigned int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} implicitcast_1 'signed char (unsigned int)'{{$}}
+  // CHECK: ImplicitCastExpr {{.*}} <col:{{.*}}> 'signed char' <IntegralCast>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned int' <LValueToRValue>{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'unsigned int' lvalue ParmVar {{.*}} 'x' 'unsigned int'{{$}}
+  return x;
+}
+
+unsigned char implicitcast_2(signed int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} implicitcast_2 'unsigned char (int)'{{$}}
+  // CHECK: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned char' <IntegralCast>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'int' <LValueToRValue>{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'int' lvalue ParmVar {{.*}} 'x' 'int'{{$}}
+  return x;
+}
+
+signed char implicitcast_3(signed int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} implicitcast_3 'signed char (int)'{{$}}
+  // CHECK: ImplicitCastExpr {{.*}} <col:{{.*}}> 'signed char' <IntegralCast>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'int' <LValueToRValue>{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'int' lvalue ParmVar {{.*}} 'x' 'int'{{$}}
+  return x;
+}
+
+//----------------------------------------------------------------------------//
+
+unsigned char cstylecast_0(unsigned int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cstylecast_0 'unsigned char (unsigned int)'{{$}}
+  // CHECK: CStyleCastExpr {{.*}} <col:{{.*}}> 'unsigned char' <IntegralCast>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'unsigned int' lvalue ParmVar {{.*}} 'x' 'unsigned int'{{$}}
+  return (unsigned char)x;
+}
+
+signed char cstylecast_1(unsigned int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cstylecast_1 'signed char (unsigned int)'{{$}}
+  // CHECK: CStyleCastExpr {{.*}} <col:{{.*}}> 'signed char' <IntegralCast>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'unsigned int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'unsigned int' lvalue ParmVar {{.*}} 'x' 'unsigned int'{{$}}
+  return (signed char)x;
+}
+
+unsigned char cstylecast_2(signed int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cstylecast_2 'unsigned char (int)'{{$}}
+  // CHECK: CStyleCastExpr {{.*}} <col:{{.*}}> 'unsigned char' <IntegralCast>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'int' lvalue ParmVar {{.*}} 'x' 'int'{{$}}
+  return (unsigned char)x;
+}
+
+signed char cstylecast_3(signed int x) {
+  // CHECK: FunctionDecl {{.*}} <{{.*}}, line:{{.*}}> line:{{.*}} cstylecast_3 'signed char (int)'{{$}}
+  // CHECK: CStyleCastExpr {{.*}} <col:{{.*}}> 'signed char' <IntegralCast>{{$}}
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'int' <LValueToRValue> PartOfExplicitCast{{$}}
+  // CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'int' lvalue ParmVar {{.*}} 'x' 'int'{{$}}
+  return (signed char)x;
+}
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -665,6 +665,7 @@
   Record.push_back(E->path_size());
   Record.AddStmt(E->getSubExpr());
   Record.push_back(E->getCastKind()); // FIXME: stable encoding
+  Record.push_back(E->getIsPartOfExplicitCast());
 
   for (CastExpr::path_iterator
          PI = E->path_begin(), PE = E->path_end(); PI != PE; ++PI)
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -2192,6 +2192,7 @@
   // CastExpr
   Abv->Add(BitCodeAbbrevOp(0)); // PathSize
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 6)); // CastKind
+  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // PartOfExplicitCast
   // ImplicitCastExpr
   ExprImplicitCastAbbrev = Stream.EmitAbbrev(std::move(Abv));
 
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -723,6 +723,7 @@
   assert(NumBaseSpecs == E->path_size());
   E->setSubExpr(Record.readSubExpr());
   E->setCastKind((CastKind)Record.readInt());
+  E->setIsPartOfExplicitCast(Record.readInt());
   CastExpr::path_iterator BaseI = E->path_begin();
   while (NumBaseSpecs--) {
     auto *BaseSpec = new (Record.getContext()) CXXBaseSpecifier;
Index: lib/Sema/SemaCast.cpp
===================================================================
--- lib/Sema/SemaCast.cpp
+++ lib/Sema/SemaCast.cpp
@@ -55,7 +55,7 @@
 namespace {
   struct CastOperation {
     CastOperation(Sema &S, QualType destType, ExprResult src)
-      : Self(S), SrcExpr(src), DestType(destType),
+      : Self(S), SrcExpr(src), OrigSrcExpr(SrcExpr), DestType(destType),
         ResultType(destType.getNonLValueExprType(S.Context)),
         ValueKind(Expr::getValueKindForType(destType)),
         Kind(CK_Dependent), IsARCUnbridgedCast(false) {
@@ -70,6 +70,8 @@
 
     Sema &Self;
     ExprResult SrcExpr;
+    const ExprResult OrigSrcExpr;
+    // SrcExpr will be modified, but OrigSrcExpr will retain the original value.
     QualType DestType;
     QualType ResultType;
     ExprValueKind ValueKind;
@@ -89,6 +91,15 @@
     void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization);
     void CheckCStyleCast();
 
+    void updatePartOfExplicitCastFlags(CastExpr *CE) {
+      // Walk down from the CE to the OrigSrcExpr, and mark all immediate
+      // ImplicitCastExpr's as being part of ExplicitCastExpr. The original CE
+      // (which is a ExplicitCastExpr), and the OrigSrcExpr are not touched.
+      while (OrigSrcExpr.get() != CE->getSubExpr() &&
+             (CE = dyn_cast<ImplicitCastExpr>(CE->getSubExpr())))
+        CE->setIsPartOfExplicitCast(true);
+    }
+
     /// Complete an apparently-successful cast operation that yields
     /// the given expression.
     ExprResult complete(CastExpr *castExpr) {
@@ -100,6 +111,7 @@
                                             CK_Dependent, castExpr, nullptr,
                                             castExpr->getValueKind());
       }
+      updatePartOfExplicitCastFlags(castExpr);
       return castExpr;
     }
 
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -2117,6 +2117,9 @@
   }
   dumpBasePath(OS, Node);
   OS << ">";
+
+  if (Node->getIsPartOfExplicitCast())
+    OS << " PartOfExplicitCast";
 }
 
 void ASTDumper::VisitDeclRefExpr(const DeclRefExpr *Node) {
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -202,7 +202,8 @@
     unsigned : NumExprBits;
 
     unsigned Kind : 6;
-    unsigned BasePathSize : 32 - 6 - NumExprBits;
+    unsigned PartOfExplicitCast : 1;
+    unsigned BasePathSize : 32 - 6 - 1 - NumExprBits;
   };
 
   class CallExprBitfields {
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -2821,6 +2821,7 @@
               (op && op->containsUnexpandedParameterPack()))),
         Op(op) {
     CastExprBits.Kind = kind;
+    CastExprBits.PartOfExplicitCast = false;
     setBasePathSize(BasePathSize);
     assert(CastConsistency());
   }
@@ -2835,6 +2836,13 @@
   CastKind getCastKind() const { return (CastKind) CastExprBits.Kind; }
   void setCastKind(CastKind K) { CastExprBits.Kind = K; }
 
+  bool getIsPartOfExplicitCast() const {
+    return CastExprBits.PartOfExplicitCast;
+  }
+  void setIsPartOfExplicitCast(bool PartOfExplicitCast) {
+    CastExprBits.PartOfExplicitCast = PartOfExplicitCast;
+  }
+
   static const char *getCastKindName(CastKind CK);
   const char *getCastKindName() const { return getCastKindName(getCastKind()); }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to