Anastasia created this revision.
Anastasia added reviewers: rjmccall, ebevhan.
Herald added a subscriber: yaxunl.

This change adds extra cast operator `addrspace_cast` described earlier in this 
RFC:
http://lists.llvm.org/pipermail/cfe-dev/2018-December/060546.html

This operator is intended for casting between pointers to objects in different 
address spaces and follows similar logic as `const_cast` in C++.

Example:

  int* gen = ...;
  global int* gl = addrspace_cast<global int*>(gen);

Note that functionality of casting pointers to different address spaces has 
been previously removed from all other cast operators and can only be currently 
done using C style casts.

This commit only enables this change for OpenCL, but if agreed it can be 
changed to apply to C++ too (it needs to be enabled as a valid keyword). 
However, for C++ it might need to be added as a Clang only extension?


https://reviews.llvm.org/D60193

Files:
  include/clang/AST/ExprCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/Basic/DiagnosticParseKinds.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/StmtNodes.td
  include/clang/Basic/TokenKinds.def
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/Expr.cpp
  lib/AST/ExprCXX.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGExpr.cpp
  lib/Parse/ParseExpr.cpp
  lib/Parse/ParseExprCXX.cpp
  lib/Sema/SemaCast.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriter.cpp
  lib/Serialization/ASTWriterStmt.cpp
  test/CodeGenOpenCLCXX/addrspace_cast.cl
  test/SemaOpenCLCXX/addrspace_cast.cl
  test/SemaOpenCLCXX/addrspace_cast_ast_dump.cl

Index: test/SemaOpenCLCXX/addrspace_cast_ast_dump.cl
===================================================================
--- /dev/null
+++ test/SemaOpenCLCXX/addrspace_cast_ast_dump.cl
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -pedantic -verify -ast-dump | FileCheck %s
+
+// expected-no-diagnostics
+
+//CHECK:`-FunctionDecl {{.*}} bar 'void (__global int *)'
+//CHECK:  |-ParmVarDecl {{.*}} used gl '__global int *'
+//CHECK:      `-VarDecl {{.*}} gen '__generic int *' cinit
+//CHECK:        `-CXXAddrspaceCastExpr {{.*}} '__generic int *' addrspace_cast<__generic int *> <AddressSpaceConversion>
+//CHECK:          `-DeclRefExpr {{.*}} '__global int *' lvalue ParmVar {{.*}} 'gl' '__global int *'
+
+void bar(global int *gl) {
+  int *gen = addrspace_cast<int *>(gl);
+}
Index: test/SemaOpenCLCXX/addrspace_cast.cl
===================================================================
--- /dev/null
+++ test/SemaOpenCLCXX/addrspace_cast.cl
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -pedantic -verify -fsyntax-only
+
+void foo(global int *gl, const global int *gl_const, global int &gl_ref) {
+  //FIXME: Diagnostics can be improved to be more specific in some cases.
+  float *gen_fl = addrspace_cast<float *>(gl); //expected-error{{addrspace_cast from '__global int *' to '__generic float *' is not allowed}}
+
+  int i = addrspace_cast<int>(gl); //expected-error{{addrspace_cast from '__global int *' to 'int' is not allowed}}
+
+  int *gen = addrspace_cast<int *>(*gl); //expected-error{{addrspace_cast from '__global int' to '__generic int *' is not allowed}}
+
+  local int *loc = addrspace_cast<local int *>(gl); //expected-error{{addrspace_cast from '__global int *' to '__local int *' converts between mismatching address spaces}}
+
+  int *gen2 = addrspace_cast<int *>(gl_const); //expected-error{{addrspace_cast from 'const __global int *' to '__generic int *' is not allowed}}
+
+  //FIXME: Do we expect this behavior? This will get cast successfully as reinterpret_cast.
+  int &gen_ref = addrspace_cast<int &>(gl_ref); //expected-error{{addrspace_cast from '__global int' to '__generic int &' is not allowed}}
+}
Index: test/CodeGenOpenCLCXX/addrspace_cast.cl
===================================================================
--- /dev/null
+++ test/CodeGenOpenCLCXX/addrspace_cast.cl
@@ -0,0 +1,7 @@
+//RUN: %clang_cc1 %s -triple spir -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s
+
+//CHECK-LABEL: define spir_func void @_Z3barPU3AS1i
+void bar(global int *gl) {
+  //CHECK: addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(4)*
+  int *gen = addrspace_cast<int *>(gl);
+}
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -1411,6 +1411,11 @@
   Code = serialization::EXPR_CXX_CONST_CAST;
 }
 
+void ASTStmtWriter::VisitCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *E) {
+  VisitCXXNamedCastExpr(E);
+  Code = serialization::EXPR_CXX_ADDRSPACE_CAST;
+}
+
 void ASTStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
   VisitExplicitCastExpr(E);
   Record.AddSourceLocation(E->getLParenLoc());
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -1018,6 +1018,7 @@
   RECORD(EXPR_CXX_DYNAMIC_CAST);
   RECORD(EXPR_CXX_REINTERPRET_CAST);
   RECORD(EXPR_CXX_CONST_CAST);
+  RECORD(EXPR_CXX_ADDRSPACE_CAST);
   RECORD(EXPR_CXX_FUNCTIONAL_CAST);
   RECORD(EXPR_USER_DEFINED_LITERAL);
   RECORD(EXPR_CXX_STD_INITIALIZER_LIST);
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -1431,6 +1431,10 @@
   return VisitCXXNamedCastExpr(E);
 }
 
+void ASTStmtReader::VisitCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *E) {
+  return VisitCXXNamedCastExpr(E);
+}
+
 void ASTStmtReader::VisitCXXConstCastExpr(CXXConstCastExpr *E) {
   return VisitCXXNamedCastExpr(E);
 }
@@ -3164,6 +3168,10 @@
       S = CXXConstCastExpr::CreateEmpty(Context);
       break;
 
+    case EXPR_CXX_ADDRSPACE_CAST:
+      S = CXXAddrspaceCastExpr::CreateEmpty(Context);
+      break;
+
     case EXPR_CXX_FUNCTIONAL_CAST:
       S = CXXFunctionalCastExpr::CreateEmpty(Context,
                        /*PathSize*/ Record[ASTStmtReader::NumExprFields]);
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -2532,6 +2532,10 @@
                                                    RAngleLoc, LParenLoc,
                                                    SubExpr, RParenLoc);
 
+    case Stmt::CXXAddrspaceCastExprClass:
+      return getDerived().RebuildCXXAddrspaceCastExpr(
+          OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, SubExpr, RParenLoc);
+
     default:
       llvm_unreachable("Invalid C++ named cast");
     }
@@ -2605,6 +2609,16 @@
                                        SourceRange(LParenLoc, RParenLoc));
   }
 
+  ExprResult
+  RebuildCXXAddrspaceCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc,
+                              TypeSourceInfo *TInfo, SourceLocation RAngleLoc,
+                              SourceLocation LParenLoc, Expr *SubExpr,
+                              SourceLocation RParenLoc) {
+    return getSema().BuildCXXNamedCast(
+        OpLoc, tok::kw_addrspace_cast, TInfo, SubExpr,
+        SourceRange(LAngleLoc, RAngleLoc), SourceRange(LParenLoc, RParenLoc));
+  }
+
   /// Build a new C++ functional-style cast expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -10149,6 +10163,12 @@
   return getDerived().TransformCXXNamedCastExpr(E);
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *E) {
+  return getDerived().TransformCXXNamedCastExpr(E);
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
Index: lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- lib/Sema/SemaExceptionSpec.cpp
+++ lib/Sema/SemaExceptionSpec.cpp
@@ -1176,6 +1176,7 @@
   case Expr::ConditionalOperatorClass:
   case Expr::CompoundLiteralExprClass:
   case Expr::CoyieldExprClass:
+  case Expr::CXXAddrspaceCastExprClass:
   case Expr::CXXConstCastExprClass:
   case Expr::CXXReinterpretCastExprClass:
   case Expr::CXXStdInitializerListExprClass:
Index: lib/Sema/SemaCast.cpp
===================================================================
--- lib/Sema/SemaCast.cpp
+++ lib/Sema/SemaCast.cpp
@@ -43,6 +43,7 @@
 }
 
 enum CastType {
+  CT_Addrspace,   ///< addrspace_cast
   CT_Const,       ///< const_cast
   CT_Static,      ///< static_cast
   CT_Reinterpret, ///< reinterpret_cast
@@ -81,6 +82,7 @@
     SourceRange DestRange;
 
     // Top-level semantics-checking routines.
+    void CheckAddrspaceCast();
     void CheckConstCast();
     void CheckReinterpretCast();
     void CheckStaticCast();
@@ -227,7 +229,9 @@
                                         SourceRange OpRange,
                                         unsigned &msg,
                                         CastKind &Kind);
-
+static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
+                                         QualType DestType, bool CStyle,
+                                         unsigned &msg);
 
 /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
 ExprResult
@@ -271,6 +275,18 @@
   switch (Kind) {
   default: llvm_unreachable("Unknown C++ cast!");
 
+  case tok::kw_addrspace_cast:
+    if (!TypeDependent) {
+      Op.CheckAddrspaceCast();
+      if (Op.SrcExpr.isInvalid())
+        return ExprError();
+    }
+    return Op.complete(CXXAddrspaceCastExpr::Create(Context, Op.ResultType,
+                                    Op.ValueKind, Op.SrcExpr.get(),
+                                                  DestTInfo,
+                                                  OpLoc, Parens.getEnd(),
+                                                  AngleBrackets));
+
   case tok::kw_const_cast:
     if (!TypeDependent) {
       Op.CheckConstCast();
@@ -342,6 +358,7 @@
   case CT_Const:
   case CT_Reinterpret:
   case CT_Dynamic:
+  case CT_Addrspace:
     return false;
 
   // These do.
@@ -845,6 +862,18 @@
     SrcExpr = ExprError();
 }
 
+void CastOperation::CheckAddrspaceCast() {
+  unsigned msg = diag::err_bad_cxx_cast_generic;
+  auto TCR =
+      TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ false, msg);
+  if (TCR != TC_Success && msg != 0) {
+    Self.Diag(OpRange.getBegin(), msg)
+        << CT_Addrspace << SrcExpr.get()->getType() << DestType << OpRange;
+  }
+  if (!isValidCast(TCR))
+    SrcExpr = ExprError();
+}
+
 /// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast
 /// or downcast between respective pointers or references.
 static void DiagnoseReinterpretUpDownCast(Sema &Self, const Expr *SrcExpr,
@@ -2295,6 +2324,9 @@
   // non-OpenCL mode too, we fast-path above because no other languages
   // define overlapping address spaces currently.
   auto SrcType = SrcExpr.get()->getType();
+  // FIXME: Should this be generalized to references? The reference parameter
+  // however becomes a reference pointee type here and therefore rejected.
+  // Perhaps this is the right behavior though according to C++.
   auto SrcPtrType = SrcType->getAs<PointerType>();
   if (!SrcPtrType)
     return TC_NotApplicable;
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -29,10 +29,11 @@
     // template name
     case tok::unknown:             return 0;
     // casts
-    case tok::kw_const_cast:       return 1;
-    case tok::kw_dynamic_cast:     return 2;
-    case tok::kw_reinterpret_cast: return 3;
-    case tok::kw_static_cast:      return 4;
+    case tok::kw_addrspace_cast:   return 1;
+    case tok::kw_const_cast:       return 2;
+    case tok::kw_dynamic_cast:     return 3;
+    case tok::kw_reinterpret_cast: return 4;
+    case tok::kw_static_cast:      return 5;
     default:
       llvm_unreachable("Unknown type for digraph error message.");
   }
@@ -1321,6 +1322,7 @@
 
   switch (Kind) {
   default: llvm_unreachable("Unknown C++ cast!");
+  case tok::kw_addrspace_cast:   CastName = "addrspace_cast";   break;
   case tok::kw_const_cast:       CastName = "const_cast";       break;
   case tok::kw_dynamic_cast:     CastName = "dynamic_cast";     break;
   case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break;
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -1207,6 +1207,7 @@
   case tok::kw_dynamic_cast:
   case tok::kw_reinterpret_cast:
   case tok::kw_static_cast:
+  case tok::kw_addrspace_cast:
     Res = ParseCXXCasts();
     break;
   case tok::kw_typeid:
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -1357,6 +1357,7 @@
   case Expr::CXXDynamicCastExprClass:
   case Expr::CXXReinterpretCastExprClass:
   case Expr::CXXConstCastExprClass:
+  case Expr::CXXAddrspaceCastExprClass:
   case Expr::ObjCBridgedCastExprClass:
     return EmitCastLValue(cast<CastExpr>(E));
 
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -1561,6 +1561,10 @@
   VisitCXXNamedCastExpr(S);
 }
 
+void StmtProfiler::VisitCXXAddrspaceCastExpr(const CXXAddrspaceCastExpr *S) {
+  VisitCXXNamedCastExpr(S);
+}
+
 void StmtProfiler::VisitUserDefinedLiteral(const UserDefinedLiteral *S) {
   VisitCallExpr(S);
 }
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -1691,6 +1691,10 @@
   VisitCXXNamedCastExpr(Node);
 }
 
+void StmtPrinter::VisitCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *Node) {
+  VisitCXXNamedCastExpr(Node);
+}
+
 void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
   OS << "typeid(";
   if (Node->isTypeOperand()) {
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -4042,6 +4042,9 @@
   case Expr::CXXConstCastExprClass:
     mangleCastExpression(E, "cc");
     break;
+  case Expr::CXXAddrspaceCastExprClass:
+    mangleCastExpression(E, "ac");
+    break;
 
   case Expr::CXXOperatorCallExprClass: {
     const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E);
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -11320,6 +11320,7 @@
   case Expr::StmtExprClass:
   case Expr::CXXMemberCallExprClass:
   case Expr::CUDAKernelCallExprClass:
+  case Expr::CXXAddrspaceCastExprClass:
   case Expr::CXXDynamicCastExprClass:
   case Expr::CXXTypeidExprClass:
   case Expr::CXXUuidofExprClass:
Index: lib/AST/ExprClassification.cpp
===================================================================
--- lib/AST/ExprClassification.cpp
+++ lib/AST/ExprClassification.cpp
@@ -341,6 +341,7 @@
   case Expr::CXXDynamicCastExprClass:
   case Expr::CXXReinterpretCastExprClass:
   case Expr::CXXConstCastExprClass:
+  case Expr::CXXAddrspaceCastExprClass:
   case Expr::ObjCBridgedCastExprClass:
     // Only in C++ can casts be interesting at all.
     if (!Lang.CPlusPlus) return Cl::CL_PRValue;
Index: lib/AST/ExprCXX.cpp
===================================================================
--- lib/AST/ExprCXX.cpp
+++ lib/AST/ExprCXX.cpp
@@ -680,6 +680,7 @@
   case CXXDynamicCastExprClass:     return "dynamic_cast";
   case CXXReinterpretCastExprClass: return "reinterpret_cast";
   case CXXConstCastExprClass:       return "const_cast";
+  case CXXAddrspaceCastExprClass:   return "addrspace_cast";
   default:                          return "<invalid cast>";
   }
 }
@@ -804,6 +805,19 @@
   return new (C) CXXConstCastExpr(EmptyShell());
 }
 
+CXXAddrspaceCastExpr *
+CXXAddrspaceCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK,
+                             Expr *Op, TypeSourceInfo *WrittenTy,
+                             SourceLocation L, SourceLocation RParenLoc,
+                             SourceRange AngleBrackets) {
+  return new (C)
+      CXXAddrspaceCastExpr(T, VK, Op, WrittenTy, L, RParenLoc, AngleBrackets);
+}
+
+CXXAddrspaceCastExpr *CXXAddrspaceCastExpr::CreateEmpty(const ASTContext &C) {
+  return new (C) CXXAddrspaceCastExpr(EmptyShell());
+}
+
 CXXFunctionalCastExpr *
 CXXFunctionalCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK,
                               TypeSourceInfo *Written, CastKind K, Expr *Op,
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -3020,6 +3020,7 @@
   case ObjCBridgedCastExprClass:
   case CXXDynamicCastExprClass:
   case CXXReinterpretCastExprClass:
+  case CXXAddrspaceCastExprClass:
   case CXXConstCastExprClass: {
     const CastExpr *CE = cast<CastExpr>(this);
 
@@ -3269,7 +3270,6 @@
     // If we've not yet parsed the initializer, assume it has side-effects.
     return true;
   }
-
   case CXXDynamicCastExprClass: {
     // A dynamic_cast expression has side-effects if it can throw.
     const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(this);
@@ -3283,6 +3283,7 @@
   case CXXStaticCastExprClass:
   case CXXReinterpretCastExprClass:
   case CXXConstCastExprClass:
+  case CXXAddrspaceCastExprClass:
   case CXXFunctionalCastExprClass: {
     // While volatile reads are side-effecting in both C and C++, we treat them
     // as having possible (not definite) side-effects. This allows idiomatic
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1854,6 +1854,9 @@
       /// A CXXConstCastExpr record.
       EXPR_CXX_CONST_CAST,
 
+      /// A CXXAddrspaceCastExpr record.
+      EXPR_CXX_ADDRSPACE_CAST,
+
       /// A CXXFunctionalCastExpr record.
       EXPR_CXX_FUNCTIONAL_CAST,
 
Index: include/clang/Basic/TokenKinds.def
===================================================================
--- include/clang/Basic/TokenKinds.def
+++ include/clang/Basic/TokenKinds.def
@@ -558,11 +558,14 @@
 #define GENERIC_IMAGE_TYPE(ImgType, Id) KEYWORD(ImgType##_t, KEYOPENCLC | KEYOPENCLCXX)
 #include "clang/Basic/OpenCLImageTypes.def"
 
+// OpenCL pipe type specifier
+KEYWORD(pipe                        , KEYOPENCLC)
+// OpenCL addrspace_cast operator
+KEYWORD(addrspace_cast              , KEYOPENCLCXX)
+
 // OpenMP Type Traits
 KEYWORD(__builtin_omp_required_simd_align, KEYALL)
 
-KEYWORD(pipe                        , KEYOPENCLC)
-
 // Borland Extensions.
 KEYWORD(__pascal                    , KEYALL)
 
Index: include/clang/Basic/StmtNodes.td
===================================================================
--- include/clang/Basic/StmtNodes.td
+++ include/clang/Basic/StmtNodes.td
@@ -118,6 +118,7 @@
 def CXXDynamicCastExpr : DStmt<CXXNamedCastExpr>;
 def CXXReinterpretCastExpr : DStmt<CXXNamedCastExpr>;
 def CXXConstCastExpr : DStmt<CXXNamedCastExpr>;
+def CXXAddrspaceCastExpr : DStmt<CXXNamedCastExpr>;
 def CXXFunctionalCastExpr : DStmt<ExplicitCastExpr>;
 def CXXTypeidExpr : DStmt<Expr>;
 def UserDefinedLiteral : DStmt<CallExpr>;
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -3806,13 +3806,13 @@
 def err_ovl_no_conversion_in_cast : Error<
   "cannot convert %1 to %2 without a conversion operator">;
 def err_ovl_no_viable_conversion_in_cast : Error<
-  "no matching conversion for %select{|static_cast|reinterpret_cast|"
+  "no matching conversion for %select{||static_cast|reinterpret_cast|"
   "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">;
 def err_ovl_ambiguous_conversion_in_cast : Error<
-  "ambiguous conversion for %select{|static_cast|reinterpret_cast|"
+  "ambiguous conversion for %select{||static_cast|reinterpret_cast|"
   "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">;
 def err_ovl_deleted_conversion_in_cast : Error<
-  "%select{|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+  "%select{||static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
   "functional-style cast}0 from %1 to %2 uses deleted function">;
 def err_ovl_ambiguous_init : Error<"call to constructor of %0 is ambiguous">;
 def err_ref_init_ambiguous : Error<
@@ -6256,34 +6256,34 @@
 
 
 def err_bad_cxx_cast_generic : Error<
-  "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
-  "functional-style cast}0 from %1 to %2 is not allowed">;
+  "%select{addrspace_cast|const_cast|static_cast|reinterpret_cast|dynamic_cast|"
+  "C-style cast|functional-style cast}0 from %1 to %2 is not allowed">;
 def err_bad_cxx_cast_unrelated_class : Error<
-  "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+  "%select{|const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
   "functional-style cast}0 from %1 to %2, which are not related by "
   "inheritance, is not allowed">;
 def note_type_incomplete : Note<"%0 is incomplete">;
 def err_bad_cxx_cast_rvalue : Error<
-  "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+  "%select{|const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
   "functional-style cast}0 from rvalue to reference type %2">;
 def err_bad_cxx_cast_bitfield : Error<
-  "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+  "%select{|const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
   "functional-style cast}0 from bit-field lvalue to reference type %2">;
 def err_bad_cxx_cast_qualifiers_away : Error<
-  "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+  "%select{|const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
   "functional-style cast}0 from %1 to %2 casts away qualifiers">;
 def err_bad_cxx_cast_addr_space_mismatch : Error<
-  "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
-  "functional-style cast}0 from %1 to %2 converts between mismatching address"
+  "%select{addrspace_cast|const_cast|static_cast|reinterpret_cast|dynamic_cast|"
+  "C-style cast|functional-style cast}0 from %1 to %2 converts between mismatching address"
   " spaces">;
 def ext_bad_cxx_cast_qualifiers_away_incoherent : ExtWarn<
   "ISO C++ does not allow "
-  "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+  "%select{|const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
   "functional-style cast}0 from %1 to %2 because it casts away qualifiers, "
   "even though the source and destination types are unrelated">,
   SFINAEFailure, InGroup<DiagGroup<"cast-qual-unrelated">>;
 def err_bad_const_cast_dest : Error<
-  "%select{const_cast||||C-style cast|functional-style cast}0 to %2, "
+  "%select{|const_cast||||C-style cast|functional-style cast}0 to %2, "
   "which is not a reference, pointer-to-object, or pointer-to-data-member">;
 def ext_cast_fn_obj : Extension<
   "cast between pointer-to-function and pointer-to-object is an extension">;
@@ -6296,13 +6296,13 @@
 def err_bad_reinterpret_cast_small_int : Error<
   "cast from pointer to smaller type %2 loses information">;
 def err_bad_cxx_cast_vector_to_scalar_different_size : Error<
-  "%select{||reinterpret_cast||C-style cast|}0 from vector %1 "
+  "%select{|||reinterpret_cast||C-style cast|}0 from vector %1 "
   "to scalar %2 of different size">;
 def err_bad_cxx_cast_scalar_to_vector_different_size : Error<
-  "%select{||reinterpret_cast||C-style cast|}0 from scalar %1 "
+  "%select{|||reinterpret_cast||C-style cast|}0 from scalar %1 "
   "to vector %2 of different size">;
 def err_bad_cxx_cast_vector_to_vector_different_size : Error<
-  "%select{||reinterpret_cast||C-style cast|}0 from vector %1 "
+  "%select{|||reinterpret_cast||C-style cast|}0 from vector %1 "
   "to vector %2 of different size">;
 def err_bad_lvalue_to_rvalue_cast : Error<
   "cannot cast from lvalue of type %1 to rvalue reference type %2; types are "
@@ -6315,7 +6315,7 @@
 def err_bad_static_cast_member_pointer_nonmp : Error<
   "cannot cast from type %1 to member pointer type %2">;
 def err_bad_cxx_cast_member_pointer_size : Error<
-  "cannot %select{||reinterpret_cast||C-style cast|}0 from member pointer "
+  "cannot %select{|||reinterpret_cast||C-style cast|}0 from member pointer "
   "type %1 to member pointer type %2 of different size">;
 def err_bad_reinterpret_cast_reference : Error<
   "reinterpret_cast of a %0 to %1 needs its address, which is not allowed">;
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -767,7 +767,7 @@
   "cannot define a type in a friend declaration">;
 def err_missing_whitespace_digraph : Error<
   "found '<::' after a "
-  "%select{template name|const_cast|dynamic_cast|reinterpret_cast|static_cast}0"
+  "%select{template name|addrspace_cast|const_cast|dynamic_cast|reinterpret_cast|static_cast}0"
   " which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?">;
 
 def ext_defaulted_deleted_function : ExtWarn<
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2260,6 +2260,10 @@
   TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
 })
 
+DEF_TRAVERSE_STMT(CXXAddrspaceCastExpr, {
+  TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
+})
+
 DEF_TRAVERSE_STMT(CXXConstCastExpr, {
   TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
 })
Index: include/clang/AST/ExprCXX.h
===================================================================
--- include/clang/AST/ExprCXX.h
+++ include/clang/AST/ExprCXX.h
@@ -311,6 +311,7 @@
     case CXXDynamicCastExprClass:
     case CXXReinterpretCastExprClass:
     case CXXConstCastExprClass:
+    case CXXAddrspaceCastExprClass:
       return true;
     default:
       return false;
@@ -468,6 +469,42 @@
   }
 };
 
+/// A C++ addrspace_cast expression (currently only enabled for OpenCL).
+///
+/// This expression node represents a cast between pointers to objects in
+/// different, address spaces e.g.,
+/// \c addrspace_cast<global int*>(PtrToGenericInt).
+///
+/// A addrspace_cast can cast address space type qualifiers but does not change
+/// the underlying value.
+class CXXAddrspaceCastExpr final
+    : public CXXNamedCastExpr,
+      private llvm::TrailingObjects<CXXAddrspaceCastExpr, CXXBaseSpecifier *> {
+  CXXAddrspaceCastExpr(QualType ty, ExprValueKind VK, Expr *op,
+                       TypeSourceInfo *writtenTy, SourceLocation l,
+                       SourceLocation RParenLoc, SourceRange AngleBrackets)
+      : CXXNamedCastExpr(CXXAddrspaceCastExprClass, ty, VK,
+                         CK_AddressSpaceConversion, op, 0, writtenTy, l,
+                         RParenLoc, AngleBrackets) {}
+
+  explicit CXXAddrspaceCastExpr(EmptyShell Empty)
+      : CXXNamedCastExpr(CXXAddrspaceCastExprClass, Empty, 0) {}
+
+public:
+  friend class CastExpr;
+  friend TrailingObjects;
+
+  static CXXAddrspaceCastExpr *
+  Create(const ASTContext &Context, QualType T, ExprValueKind VK, Expr *Op,
+         TypeSourceInfo *WrittenTy, SourceLocation L, SourceLocation RParenLoc,
+         SourceRange AngleBrackets);
+  static CXXAddrspaceCastExpr *CreateEmpty(const ASTContext &Context);
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXAddrspaceCastExprClass;
+  }
+};
+
 /// A call to a literal operator (C++11 [over.literal])
 /// written as a user-defined literal (C++11 [lit.ext]).
 ///
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D60193: [OpenCL]... Anastasia Stulova via Phabricator via cfe-commits

Reply via email to