diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h --- a/clang/include/clang-c/Index.h +++ b/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, diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h --- a/clang/include/clang/AST/ExprCXX.h +++ b/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,41 @@ } }; +/// 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, CastKind Kind, Expr *op, + TypeSourceInfo *writtenTy, SourceLocation l, + SourceLocation RParenLoc, SourceRange AngleBrackets) + : CXXNamedCastExpr(CXXAddrspaceCastExprClass, ty, VK, Kind, 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, CastKind Kind, + 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]). /// diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2355,6 +2355,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())); }) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -833,7 +833,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< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4221,13 +4221,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">; @@ -6843,34 +6843,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">; @@ -6883,13 +6883,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 " @@ -6906,7 +6906,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">; diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td --- a/clang/include/clang/Basic/StmtNodes.td +++ b/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; diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def --- a/clang/include/clang/Basic/TokenKinds.def +++ b/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) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5710,7 +5710,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, diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/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, diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/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 diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp --- a/clang/lib/AST/ExprCXX.cpp +++ b/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, + CastKind K, Expr *Op, TypeSourceInfo *WrittenTy, + SourceLocation L, SourceLocation RParenLoc, + SourceRange AngleBrackets) { + return new (C) CXXAddrspaceCastExpr(T, VK, K, 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, diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp --- a/clang/lib/AST/ExprClassification.cpp +++ b/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. diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -14203,6 +14203,7 @@ case Expr::StmtExprClass: case Expr::CXXMemberCallExprClass: case Expr::CUDAKernelCallExprClass: + case Expr::CXXAddrspaceCastExprClass: case Expr::CXXDynamicCastExprClass: case Expr::CXXTypeidExprClass: case Expr::CXXUuidofExprClass: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4317,6 +4317,9 @@ case Expr::CXXConstCastExprClass: mangleCastExpression(E, "cc"); break; + case Expr::CXXAddrspaceCastExprClass: + mangleCastExpression(E, "ac"); + break; case Expr::CXXOperatorCallExprClass: { const CXXOperatorCallExpr *CE = cast(E); diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp --- a/clang/lib/AST/StmtPrinter.cpp +++ b/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()) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp --- a/clang/lib/AST/StmtProfile.cpp +++ b/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); } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1395,6 +1395,7 @@ case Expr::CXXDynamicCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: + case Expr::CXXAddrspaceCastExprClass: case Expr::ObjCBridgedCastExprClass: return EmitCastLValue(cast(E)); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp --- a/clang/lib/Parse/ParseExpr.cpp +++ b/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(); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/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; diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp --- a/clang/lib/Sema/SemaCast.cpp +++ b/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 @@ -225,12 +227,14 @@ unsigned &msg); static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, - SourceRange OpRange, - unsigned &msg, + SourceRange OpRange, unsigned &msg, CastKind &Kind); +static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, + QualType DestType, bool CStyle, + unsigned &msg, CastKind &Kind); - -/// 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 +276,16 @@ 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.Kind, Op.SrcExpr.get(), + DestTInfo, OpLoc, Parens.getEnd(), AngleBrackets)); + case tok::kw_const_cast: if (!TypeDependent) { Op.CheckConstCast(); @@ -375,6 +389,7 @@ case CT_Const: case CT_Reinterpret: case CT_Dynamic: + case CT_Addrspace: return false; // These do. @@ -878,6 +893,18 @@ SrcExpr = ExprError(); } +void CastOperation::CheckAddrspaceCast() { + unsigned msg = diag::err_bad_cxx_cast_generic; + auto TCR = + TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ false, msg, Kind); + 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, @@ -2344,7 +2371,7 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, - unsigned &msg) { + unsigned &msg, CastKind &Kind) { if (!Self.getLangOpts().OpenCL) // FIXME: As compiler doesn't have any information about overlapping addr // spaces at the moment we have to be permissive here. @@ -2353,6 +2380,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; @@ -2361,8 +2391,6 @@ return TC_NotApplicable; auto SrcPointeeType = SrcPtrType->getPointeeType(); auto DestPointeeType = DestPtrType->getPointeeType(); - if (SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace()) - return TC_NotApplicable; if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) { msg = diag::err_bad_cxx_cast_addr_space_mismatch; return TC_Failed; @@ -2371,10 +2399,15 @@ Self.Context.removeAddrSpaceQualType(SrcPointeeType.getCanonicalType()); auto DestPointeeTypeWithoutAS = Self.Context.removeAddrSpaceQualType(DestPointeeType.getCanonicalType()); - return Self.Context.hasSameType(SrcPointeeTypeWithoutAS, - DestPointeeTypeWithoutAS) - ? TC_Success - : TC_NotApplicable; + if (Self.Context.hasSameType(SrcPointeeTypeWithoutAS, + DestPointeeTypeWithoutAS)) { + Kind = SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace() + ? CK_NoOp + : CK_AddressSpaceConversion; + return TC_Success; + } else { + return TC_NotApplicable; + } } void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) { @@ -2505,22 +2538,21 @@ Sema::CheckedConversionKind CCK = FunctionalStyle ? Sema::CCK_FunctionalCast : Sema::CCK_CStyleCast; if (tcr == TC_NotApplicable) { - tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg); + tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg, + Kind); if (SrcExpr.isInvalid()) return; - if (isValidCast(tcr)) - Kind = CK_AddressSpaceConversion; - if (tcr == TC_NotApplicable) { - // ... or if that is not possible, a static_cast, ignoring const, ... + // ... or if that is not possible, a static_cast, ignoring const and + // addr space, ... tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange, msg, Kind, BasePath, ListInitialization); if (SrcExpr.isInvalid()) return; if (tcr == TC_NotApplicable) { - // ... and finally a reinterpret_cast, ignoring const. + // ... and finally a reinterpret_cast, ignoring const and addr space. tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/ true, OpRange, msg, Kind); if (SrcExpr.isInvalid()) diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/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. diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2735,6 +2735,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"); } @@ -2808,6 +2812,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. @@ -11109,6 +11123,12 @@ template ExprResult +TreeTransform::TransformCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); +} + +template +ExprResult TreeTransform::TransformCXXFunctionalCastExpr( CXXFunctionalCastExpr *E) { TypeSourceInfo *Type = diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/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]); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -660,6 +660,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); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/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()); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/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; diff --git a/clang/test/CodeGenOpenCLCXX/addrspace_cast.cl b/clang/test/CodeGenOpenCLCXX/addrspace_cast.cl new file mode 100644 --- /dev/null +++ b/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); +} diff --git a/clang/test/Index/cxx.cl b/clang/test/Index/cxx.cl new file mode 100644 --- /dev/null +++ b/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 diff --git a/clang/test/SemaOpenCLCXX/addrspace_cast.cl b/clang/test/SemaOpenCLCXX/addrspace_cast.cl new file mode 100644 --- /dev/null +++ b/clang/test/SemaOpenCLCXX/addrspace_cast.cl @@ -0,0 +1,39 @@ +// 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}} + + __private int *priv = addrspace_cast<__private int *>(&i); +} + +template +void test_temp(__global int *par) { + T *var1 = addrspace_cast(par); //expected-error{{addrspace_cast from '__global int *__private' to '__private int *' converts between mismatching address spaces}} + __private T *var2 = addrspace_cast<__private T *>(par); //expected-error{{addrspace_cast from '__global int *__private' to '__private int *' converts between mismatching address spaces}} + T var3 = addrspace_cast(par); //expected-error{{addrspace_cast from '__global int *__private' to '__private int' is not allowed}} +} + +void bar() { + __global int* var; + test_temp<__private int>(var); //expected-note{{in instantiation of function template specialization 'test_temp<__private int>' requested here}} +} +// We don't give any errors on non-instantiated template as types are not concrete yet. +template +void test_temp1(__global int *par) { + T *var1 = addrspace_cast(par); + __private T *var2 = addrspace_cast<__private T *>(par); + T var3 = addrspace_cast(par); +} + diff --git a/clang/test/SemaOpenCLCXX/addrspace_cast_ast_dump.cl b/clang/test/SemaOpenCLCXX/addrspace_cast_ast_dump.cl new file mode 100644 --- /dev/null +++ b/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); +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -5239,6 +5239,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: diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp --- a/clang/tools/libclang/CXCursor.cpp +++ b/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;