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(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(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]). /// 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/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/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>; 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/StmtNodes.td =================================================================== --- include/clang/Basic/StmtNodes.td +++ include/clang/Basic/StmtNodes.td @@ -118,6 +118,7 @@ def CXXDynamicCastExpr : DStmt; def CXXReinterpretCastExpr : DStmt; def CXXConstCastExpr : DStmt; +def CXXAddrspaceCastExpr : DStmt; def CXXFunctionalCastExpr : DStmt; def CXXTypeidExpr : DStmt; def UserDefinedLiteral : DStmt; 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/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: 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(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(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: 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 ""; } } @@ -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/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/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/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(E); 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/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/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(E)); 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/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/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\(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(); if (!SrcPtrType) return TC_NotApplicable; 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/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 +ExprResult +TreeTransform::TransformCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); +} + template ExprResult TreeTransform::TransformCXXFunctionalCastExpr( 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/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/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: 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(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(gl); //expected-error{{addrspace_cast from '__global int *' to '__generic float *' is not allowed}} + + int i = addrspace_cast(gl); //expected-error{{addrspace_cast from '__global int *' to 'int' is not allowed}} + + int *gen = addrspace_cast(*gl); //expected-error{{addrspace_cast from '__global int' to '__generic int *' is not allowed}} + + local int *loc = addrspace_cast(gl); //expected-error{{addrspace_cast from '__global int *' to '__local int *' converts between mismatching address spaces}} + + int *gen2 = addrspace_cast(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(gl_ref); //expected-error{{addrspace_cast from '__global int' to '__generic int &' is not allowed}} +} 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 *> +//CHECK: `-DeclRefExpr {{.*}} '__global int *' lvalue ParmVar {{.*}} 'gl' '__global int *' + +void bar(global int *gl) { + int *gen = addrspace_cast(gl); +}