Index: clang/include/clang-c/Index.h =================================================================== --- clang/include/clang-c/Index.h +++ clang/include/clang-c/Index.h @@ -2052,58 +2052,62 @@ */ CXCursor_CXXFunctionalCastExpr = 128, + /** OpenCL's addrspace_cast<> expression. + */ + CXCursor_CXXAddrspaceCastExpr = 129, + /** A C++ typeid expression (C++ [expr.typeid]). */ - CXCursor_CXXTypeidExpr = 129, + CXCursor_CXXTypeidExpr = 130, /** [C++ 2.13.5] C++ Boolean Literal. */ - CXCursor_CXXBoolLiteralExpr = 130, + CXCursor_CXXBoolLiteralExpr = 131, /** [C++0x 2.14.7] C++ Pointer Literal. */ - CXCursor_CXXNullPtrLiteralExpr = 131, + CXCursor_CXXNullPtrLiteralExpr = 132, /** Represents the "this" expression in C++ */ - CXCursor_CXXThisExpr = 132, + CXCursor_CXXThisExpr = 133, /** [C++ 15] C++ Throw Expression. * * This handles 'throw' and 'throw' assignment-expression. When * assignment-expression isn't present, Op will be null. */ - CXCursor_CXXThrowExpr = 133, + CXCursor_CXXThrowExpr = 134, /** A new expression for memory allocation and constructor calls, e.g: * "new CXXNewExpr(foo)". */ - CXCursor_CXXNewExpr = 134, + CXCursor_CXXNewExpr = 135, /** A delete expression for memory deallocation and destructor calls, * e.g. "delete[] pArray". */ - CXCursor_CXXDeleteExpr = 135, + CXCursor_CXXDeleteExpr = 136, /** A unary expression. (noexcept, sizeof, or other traits) */ - CXCursor_UnaryExpr = 136, + CXCursor_UnaryExpr = 137, /** An Objective-C string literal i.e. @"foo". */ - CXCursor_ObjCStringLiteral = 137, + CXCursor_ObjCStringLiteral = 138, /** An Objective-C \@encode expression. */ - CXCursor_ObjCEncodeExpr = 138, + CXCursor_ObjCEncodeExpr = 139, /** An Objective-C \@selector expression. */ - CXCursor_ObjCSelectorExpr = 139, + CXCursor_ObjCSelectorExpr = 140, /** An Objective-C \@protocol expression. */ - CXCursor_ObjCProtocolExpr = 140, + CXCursor_ObjCProtocolExpr = 141, /** An Objective-C "bridged" cast expression, which casts between * Objective-C pointers and C pointers, transferring ownership in the process. @@ -2112,7 +2116,7 @@ * NSString *str = (__bridge_transfer NSString *)CFCreateString(); * \endcode */ - CXCursor_ObjCBridgedCastExpr = 141, + CXCursor_ObjCBridgedCastExpr = 142, /** Represents a C++0x pack expansion that produces a sequence of * expressions. @@ -2127,7 +2131,7 @@ * } * \endcode */ - CXCursor_PackExpansionExpr = 142, + CXCursor_PackExpansionExpr = 143, /** Represents an expression that computes the length of a parameter * pack. @@ -2139,7 +2143,7 @@ * }; * \endcode */ - CXCursor_SizeOfPackExpr = 143, + CXCursor_SizeOfPackExpr = 144, /* Represents a C++ lambda expression that produces a local function * object. @@ -2153,37 +2157,37 @@ * } * \endcode */ - CXCursor_LambdaExpr = 144, + CXCursor_LambdaExpr = 145, /** Objective-c Boolean Literal. */ - CXCursor_ObjCBoolLiteralExpr = 145, + CXCursor_ObjCBoolLiteralExpr = 146, /** Represents the "self" expression in an Objective-C method. */ - CXCursor_ObjCSelfExpr = 146, + CXCursor_ObjCSelfExpr = 147, /** OpenMP 4.0 [2.4, Array Section]. */ - CXCursor_OMPArraySectionExpr = 147, + CXCursor_OMPArraySectionExpr = 148, /** Represents an @available(...) check. */ - CXCursor_ObjCAvailabilityCheckExpr = 148, + CXCursor_ObjCAvailabilityCheckExpr = 149, /** * Fixed point literal */ - CXCursor_FixedPointLiteral = 149, + CXCursor_FixedPointLiteral = 150, /** OpenMP 5.0 [2.1.4, Array Shaping]. */ - CXCursor_OMPArrayShapingExpr = 150, + CXCursor_OMPArrayShapingExpr = 151, /** * OpenMP 5.0 [2.1.6 Iterators] */ - CXCursor_OMPIteratorExpr = 151, + CXCursor_OMPIteratorExpr = 152, CXCursor_LastExpr = CXCursor_OMPIteratorExpr, Index: clang/include/clang/AST/ExprCXX.h =================================================================== --- clang/include/clang/AST/ExprCXX.h +++ clang/include/clang/AST/ExprCXX.h @@ -366,7 +366,8 @@ /// This abstract class is inherited by all of the classes /// representing "named" casts: CXXStaticCastExpr for \c static_cast, /// CXXDynamicCastExpr for \c dynamic_cast, CXXReinterpretCastExpr for -/// reinterpret_cast, and CXXConstCastExpr for \c const_cast. +/// reinterpret_cast, CXXConstCastExpr for \c const_cast and +/// CXXAddrspaceCastExpr for addrspace_cast (in OpenCL). class CXXNamedCastExpr : public ExplicitCastExpr { private: // the location of the casting op @@ -412,6 +413,7 @@ case CXXDynamicCastExprClass: case CXXReinterpretCastExprClass: case CXXConstCastExprClass: + case CXXAddrspaceCastExprClass: return true; default: return false; @@ -569,6 +571,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: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -2332,6 +2332,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: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -814,7 +814,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: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4222,13 +4222,13 @@ "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|" - "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">; + "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|" - "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">; + "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|" - "functional-style cast}0 from %1 to %2 uses deleted function">; + "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< "reference initialization of type %0 with initializer of type %1 is ambiguous">; @@ -6828,34 +6828,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{const_cast|static_cast|reinterpret_cast|dynamic_cast|" + "C-style cast|functional-style cast|addrspace_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|" - "functional-style cast}0 from %1 to %2, which are not related by " + "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|" - "functional-style cast}0 from rvalue to reference type %2">; + "functional-style cast|addrspace_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|" - "functional-style cast}0 from bit-field lvalue to reference type %2">; + "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|" - "functional-style cast}0 from %1 to %2 casts away qualifiers">; + "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{const_cast|static_cast|reinterpret_cast|dynamic_cast|" + "C-style cast|functional-style cast|addrspace_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|" - "functional-style cast}0 from %1 to %2 because it casts away qualifiers, " + "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">; @@ -6868,13 +6868,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 warn_bad_cxx_cast_nested_pointer_addr_space : Warning< "%select{reinterpret_cast|C-style cast}0 from %1 to %2 " @@ -6891,7 +6891,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: clang/include/clang/Basic/StmtNodes.td =================================================================== --- clang/include/clang/Basic/StmtNodes.td +++ clang/include/clang/Basic/StmtNodes.td @@ -120,6 +120,7 @@ def CXXDynamicCastExpr : StmtNode; def CXXReinterpretCastExpr : StmtNode; def CXXConstCastExpr : StmtNode; +def CXXAddrspaceCastExpr : StmtNode; def CXXFunctionalCastExpr : StmtNode; def CXXTypeidExpr : StmtNode; def UserDefinedLiteral : StmtNode; Index: clang/include/clang/Basic/TokenKinds.def =================================================================== --- clang/include/clang/Basic/TokenKinds.def +++ clang/include/clang/Basic/TokenKinds.def @@ -574,12 +574,13 @@ KEYWORD(vec_step , KEYOPENCLC | KEYALTIVEC | KEYZVECTOR) #define GENERIC_IMAGE_TYPE(ImgType, Id) KEYWORD(ImgType##_t, KEYOPENCLC | KEYOPENCLCXX) #include "clang/Basic/OpenCLImageTypes.def" +KEYWORD(pipe , KEYOPENCLC | KEYOPENCLCXX) +// C++ for OpenCL s2.3.1: addrspace_cast operator +KEYWORD(addrspace_cast , KEYOPENCLCXX) // OpenMP Type Traits KEYWORD(__builtin_omp_required_simd_align, KEYALL) -KEYWORD(pipe , KEYOPENCLC | KEYOPENCLCXX) - // Borland Extensions. KEYWORD(__pascal , KEYALL) Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -5706,7 +5706,8 @@ void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, bool IsDereference, SourceRange Range); - /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. + /// ActOnCXXNamedCast - Parse + /// {dynamic,static,reinterpret,const,addrspace}_cast's. ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, Index: clang/include/clang/Serialization/ASTBitCodes.h =================================================================== --- clang/include/clang/Serialization/ASTBitCodes.h +++ clang/include/clang/Serialization/ASTBitCodes.h @@ -1791,6 +1791,9 @@ /// A CXXConstCastExpr record. EXPR_CXX_CONST_CAST, + /// A CXXAddrspaceCastExpr record. + EXPR_CXX_ADDRSPACE_CAST, + /// A CXXFunctionalCastExpr record. EXPR_CXX_FUNCTIONAL_CAST, Index: clang/lib/AST/Expr.cpp =================================================================== --- clang/lib/AST/Expr.cpp +++ clang/lib/AST/Expr.cpp @@ -1711,12 +1711,13 @@ auto Ty = getType(); auto SETy = getSubExpr()->getType(); assert(getValueKindForType(Ty) == Expr::getValueKindForType(SETy)); - if (isRValue()) { + if (isRValue() && !Ty->isDependentType() && !SETy->isDependentType()) { Ty = Ty->getPointeeType(); SETy = SETy->getPointeeType(); } - assert(!Ty.isNull() && !SETy.isNull() && - Ty.getAddressSpace() != SETy.getAddressSpace()); + assert((Ty->isDependentType() || SETy->isDependentType()) || + (!Ty.isNull() && !SETy.isNull() && + Ty.getAddressSpace() != SETy.getAddressSpace())); goto CheckNoBasePath; } // These should not have an inheritance path. @@ -3205,6 +3206,7 @@ case ObjCBridgedCastExprClass: case CXXDynamicCastExprClass: case CXXReinterpretCastExprClass: + case CXXAddrspaceCastExprClass: case CXXConstCastExprClass: { const CastExpr *CE = cast(this); @@ -3496,6 +3498,7 @@ case CXXStaticCastExprClass: case CXXReinterpretCastExprClass: case CXXConstCastExprClass: + case CXXAddrspaceCastExprClass: case CXXFunctionalCastExprClass: case BuiltinBitCastExprClass: { // While volatile reads are side-effecting in both C and C++, we treat them Index: clang/lib/AST/ExprCXX.cpp =================================================================== --- clang/lib/AST/ExprCXX.cpp +++ clang/lib/AST/ExprCXX.cpp @@ -676,6 +676,7 @@ case CXXDynamicCastExprClass: return "dynamic_cast"; case CXXReinterpretCastExprClass: return "reinterpret_cast"; case CXXConstCastExprClass: return "const_cast"; + case CXXAddrspaceCastExprClass: return "addrspace_cast"; default: return ""; } } @@ -800,6 +801,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: clang/lib/AST/ExprClassification.cpp =================================================================== --- clang/lib/AST/ExprClassification.cpp +++ clang/lib/AST/ExprClassification.cpp @@ -352,6 +352,7 @@ case Expr::CXXDynamicCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: + case Expr::CXXAddrspaceCastExprClass: case Expr::ObjCBridgedCastExprClass: case Expr::BuiltinBitCastExprClass: // Only in C++ can casts be interesting at all. Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -14202,6 +14202,7 @@ case Expr::StmtExprClass: case Expr::CXXMemberCallExprClass: case Expr::CUDAKernelCallExprClass: + case Expr::CXXAddrspaceCastExprClass: case Expr::CXXDynamicCastExprClass: case Expr::CXXTypeidExprClass: case Expr::CXXUuidofExprClass: Index: clang/lib/AST/ItaniumMangle.cpp =================================================================== --- clang/lib/AST/ItaniumMangle.cpp +++ clang/lib/AST/ItaniumMangle.cpp @@ -4290,6 +4290,9 @@ case Expr::CXXConstCastExprClass: mangleCastExpression(E, "cc"); break; + case Expr::CXXAddrspaceCastExprClass: + mangleCastExpression(E, "ac"); + break; case Expr::CXXOperatorCallExprClass: { const CXXOperatorCallExpr *CE = cast(E); Index: clang/lib/AST/StmtPrinter.cpp =================================================================== --- clang/lib/AST/StmtPrinter.cpp +++ clang/lib/AST/StmtPrinter.cpp @@ -1788,6 +1788,10 @@ OS << ")"; } +void StmtPrinter::VisitCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *Node) { + VisitCXXNamedCastExpr(Node); +} + void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) { OS << "typeid("; if (Node->isTypeOperand()) { Index: clang/lib/AST/StmtProfile.cpp =================================================================== --- clang/lib/AST/StmtProfile.cpp +++ clang/lib/AST/StmtProfile.cpp @@ -1723,6 +1723,10 @@ VisitType(S->getTypeInfoAsWritten()->getType()); } +void StmtProfiler::VisitCXXAddrspaceCastExpr(const CXXAddrspaceCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + void StmtProfiler::VisitUserDefinedLiteral(const UserDefinedLiteral *S) { VisitCallExpr(S); } Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -1384,6 +1384,7 @@ case Expr::CXXDynamicCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: + case Expr::CXXAddrspaceCastExprClass: case Expr::ObjCBridgedCastExprClass: return EmitCastLValue(cast(E)); Index: clang/lib/Parse/ParseExpr.cpp =================================================================== --- clang/lib/Parse/ParseExpr.cpp +++ clang/lib/Parse/ParseExpr.cpp @@ -1428,6 +1428,7 @@ case tok::kw_dynamic_cast: case tok::kw_reinterpret_cast: case tok::kw_static_cast: + case tok::kw_addrspace_cast: if (NotPrimaryExpression) *NotPrimaryExpression = true; Res = ParseCXXCasts(); Index: clang/lib/Parse/ParseExprCXX.cpp =================================================================== --- clang/lib/Parse/ParseExprCXX.cpp +++ clang/lib/Parse/ParseExprCXX.cpp @@ -31,10 +31,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."); } @@ -1512,12 +1513,15 @@ /// 'reinterpret_cast' '<' type-name '>' '(' expression ')' /// 'const_cast' '<' type-name '>' '(' expression ')' /// +/// C++ for OpenCL s2.3.1 adds: +/// 'addrspace_cast' '<' type-name '>' '(' expression ')' ExprResult Parser::ParseCXXCasts() { tok::TokenKind Kind = Tok.getKind(); const char *CastName = nullptr; // For error messages 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: clang/lib/Sema/SemaCast.cpp =================================================================== --- clang/lib/Sema/SemaCast.cpp +++ clang/lib/Sema/SemaCast.cpp @@ -48,7 +48,8 @@ CT_Reinterpret, ///< reinterpret_cast CT_Dynamic, ///< dynamic_cast CT_CStyle, ///< (Type)expr - CT_Functional ///< Type(expr) + CT_Functional, ///< Type(expr) + CT_Addrspace ///< addrspace_cast }; namespace { @@ -88,6 +89,7 @@ void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization); void CheckCStyleCast(); void CheckBuiltinBitCast(); + void CheckAddrspaceCast(); void updatePartOfExplicitCastFlags(CastExpr *CE) { // Walk down from the CE to the OrigSrcExpr, and mark all immediate @@ -228,9 +230,12 @@ 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. +/// ActOnCXXNamedCast - Parse +/// {dynamic,static,reinterpret,const,addrspace}_cast's. ExprResult Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, Declarator &D, @@ -272,6 +277,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(); @@ -375,6 +392,7 @@ case CT_Const: case CT_Reinterpret: case CT_Dynamic: + case CT_Addrspace: return false; // These do. @@ -878,6 +896,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, @@ -2353,6 +2383,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: clang/lib/Sema/SemaExceptionSpec.cpp =================================================================== --- clang/lib/Sema/SemaExceptionSpec.cpp +++ clang/lib/Sema/SemaExceptionSpec.cpp @@ -1289,6 +1289,7 @@ case Expr::CompoundLiteralExprClass: case Expr::CXXConstCastExprClass: + case Expr::CXXAddrspaceCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::BuiltinBitCastExprClass: // FIXME: Properly determine whether a variably-modified type can throw. Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ clang/lib/Sema/TreeTransform.h @@ -2725,6 +2725,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"); } @@ -2798,6 +2802,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. @@ -11017,6 +11031,12 @@ return getDerived().TransformCXXNamedCastExpr(E); } +template +ExprResult +TreeTransform::TransformCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); +} + template ExprResult TreeTransform::TransformCXXFunctionalCastExpr( Index: clang/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- clang/lib/Serialization/ASTReaderStmt.cpp +++ clang/lib/Serialization/ASTReaderStmt.cpp @@ -1721,6 +1721,10 @@ return VisitCXXNamedCastExpr(E); } +void ASTStmtReader::VisitCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + void ASTStmtReader::VisitCXXConstCastExpr(CXXConstCastExpr *E) { return VisitCXXNamedCastExpr(E); } @@ -3593,6 +3597,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: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -641,6 +641,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: clang/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- clang/lib/Serialization/ASTWriterStmt.cpp +++ clang/lib/Serialization/ASTWriterStmt.cpp @@ -1630,6 +1630,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: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1716,7 +1716,8 @@ case Stmt::CXXConstCastExprClass: case Stmt::CXXFunctionalCastExprClass: case Stmt::BuiltinBitCastExprClass: - case Stmt::ObjCBridgedCastExprClass: { + case Stmt::ObjCBridgedCastExprClass: + case Stmt::CXXAddrspaceCastExprClass: { Bldr.takeNodes(Pred); const auto *C = cast(S); ExplodedNodeSet dstExpr; Index: clang/test/CodeGenOpenCLCXX/addrspace_cast.cl =================================================================== --- /dev/null +++ clang/test/CodeGenOpenCLCXX/addrspace_cast.cl @@ -0,0 +1,7 @@ +//RUN: %clang_cc1 %s -triple spir -cl-std=clc++ -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: clang/test/Index/cxx.cl =================================================================== --- /dev/null +++ clang/test/Index/cxx.cl @@ -0,0 +1,7 @@ +// C++ for OpenCL specific logic. +void test(int *ptr) { + addrspace_cast<__global int*>(ptr); +} + +// RUN: c-index-test -test-load-source all %s -cl-std=clc++ | FileCheck %s +// CHECK: cxx.cl:3:3: CXXAddrspaceCastExpr Index: clang/test/SemaOpenCLCXX/addrspace_cast.cl =================================================================== --- /dev/null +++ clang/test/SemaOpenCLCXX/addrspace_cast.cl @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -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 *__private' to '__generic float *' is not allowed}} + + int i = addrspace_cast(gl); //expected-error{{addrspace_cast from '__global int *__private' 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 *__private' to '__local int *' converts between mismatching address spaces}} + + int *gen2 = addrspace_cast(gl_const); //expected-error{{addrspace_cast from 'const __global int *__private' 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}} +} + +template +void test_temp(__global int *par) { + T *var1 = addrspace_cast(par); + __private T *var2 = addrspace_cast<__private T *>(par); + T var3 = addrspace_cast(par); +} Index: clang/test/SemaOpenCLCXX/addrspace_cast_ast_dump.cl =================================================================== --- /dev/null +++ clang/test/SemaOpenCLCXX/addrspace_cast_ast_dump.cl @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -pedantic -verify -ast-dump | FileCheck %s + +// expected-no-diagnostics + +//CHECK:`-FunctionDecl {{.*}} bar 'void (__global int *__private)' +//CHECK: |-ParmVarDecl {{.*}} used gl '__global int *__private' +//CHECK: `-VarDecl {{.*}} gen '__generic int *__private' cinit +//CHECK: `-CXXAddrspaceCastExpr {{.*}} '__generic int *' addrspace_cast<__generic int *> +//CHECK: `-DeclRefExpr {{.*}} '__global int *__private' lvalue ParmVar {{.*}} 'gl' '__global int *__private' + +void bar(global int *gl) { + int *gen = addrspace_cast(gl); +} Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -5237,6 +5237,8 @@ return cxstring::createRef("CXXConstCastExpr"); case CXCursor_CXXFunctionalCastExpr: return cxstring::createRef("CXXFunctionalCastExpr"); + case CXCursor_CXXAddrspaceCastExpr: + return cxstring::createRef("CXXAddrspaceCastExpr"); case CXCursor_CXXTypeidExpr: return cxstring::createRef("CXXTypeidExpr"); case CXCursor_CXXBoolLiteralExpr: Index: clang/tools/libclang/CXCursor.cpp =================================================================== --- clang/tools/libclang/CXCursor.cpp +++ clang/tools/libclang/CXCursor.cpp @@ -491,6 +491,10 @@ K = CXCursor_CXXFunctionalCastExpr; break; + case Stmt::CXXAddrspaceCastExprClass: + K = CXCursor_CXXAddrspaceCastExpr; + break; + case Stmt::CXXTypeidExprClass: K = CXCursor_CXXTypeidExpr; break;