Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -130,6 +130,7 @@ mutable llvm::FoldingSet AutoTypes; mutable llvm::FoldingSet AtomicTypes; llvm::FoldingSet AttributedTypes; + mutable llvm::FoldingSet PipeTypes; mutable llvm::FoldingSet QualifiedTemplateNames; mutable llvm::FoldingSet DependentTemplateNames; @@ -1078,6 +1079,9 @@ /// blocks. QualType getBlockDescriptorType() const; + /// \brief Return pipe type for the specified type. + QualType getPipeType(QualType T) const; + /// Gets the struct used to keep track of the extended descriptor for /// pointer to blocks. QualType getBlockDescriptorExtendedType() const; Index: include/clang/AST/DataRecursiveASTVisitor.h =================================================================== --- include/clang/AST/DataRecursiveASTVisitor.h +++ include/clang/AST/DataRecursiveASTVisitor.h @@ -951,6 +951,8 @@ DEF_TRAVERSE_TYPE(AtomicType, { TRY_TO(TraverseType(T->getValueType())); }) +DEF_TRAVERSE_TYPE(PipeType, { TRY_TO(TraverseType(T->getElementType())); }) + #undef DEF_TRAVERSE_TYPE // ----------------- TypeLoc traversal ----------------- @@ -1179,6 +1181,8 @@ DEF_TRAVERSE_TYPELOC(AtomicType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); }) +DEF_TRAVERSE_TYPELOC(PipeType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); }) + #undef DEF_TRAVERSE_TYPELOC // ----------------- Decl traversal ----------------- Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -1025,6 +1025,10 @@ DEF_TRAVERSE_TYPE(AtomicType, { TRY_TO(TraverseType(T->getValueType())); }) +DEF_TRAVERSE_TYPE(PipeType, { + TRY_TO(TraverseType(T->getElementType())); + }) + #undef DEF_TRAVERSE_TYPE // ----------------- TypeLoc traversal ----------------- @@ -1253,6 +1257,10 @@ DEF_TRAVERSE_TYPELOC(AtomicType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); }) +DEF_TRAVERSE_TYPELOC(PipeType, { + TRY_TO(TraverseTypeLoc(TL.getValueLoc())); + }) + #undef DEF_TRAVERSE_TYPELOC // ----------------- Decl traversal ----------------- Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -1720,6 +1720,7 @@ bool isNDRangeT() const; // OpenCL ndrange_t bool isReserveIDT() const; // OpenCL reserve_id_t + bool isPipeType() const; // OpenCL pipe type bool isOpenCLSpecificType() const; // Any OpenCL specific type /// Determines if this type, which must satisfy @@ -5013,6 +5014,35 @@ } }; +/// PipeType - OpenCL20. +/// +class PipeType : public Type, public llvm::FoldingSetNode { + QualType ElementType; + + PipeType(QualType elemType, QualType CanonicalPtr) : + Type(Pipe, CanonicalPtr, elemType->isDependentType(), + elemType->isInstantiationDependentType(), + elemType->isVariablyModifiedType(), + elemType->containsUnexpandedParameterPack()), + ElementType(elemType) { + } + friend class ASTContext; // ASTContext creates these. + +public: + + QualType getElementType() const { return ElementType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static void Profile(llvm::FoldingSetNodeID &ID) {} + + static bool classof(const Type *T) { + return T->getTypeClass() == Pipe; + } + +}; + /// A qualifier set is used to build a set of qualifiers. class QualifierCollector : public Qualifiers { public: @@ -5459,9 +5489,13 @@ isImage1dBufferT(); } +inline bool Type::isPipeType() const { + return isa(CanonicalType); +} + inline bool Type::isOpenCLSpecificType() const { return isSamplerT() || isEventT() || isImageType() || isClkEventT() || - isQueueT() || isNDRangeT() || isReserveIDT(); + isQueueT() || isNDRangeT() || isReserveIDT() || isPipeType(); } inline bool Type::isTemplateTypeParmType() const { Index: include/clang/AST/TypeLoc.h =================================================================== --- include/clang/AST/TypeLoc.h +++ include/clang/AST/TypeLoc.h @@ -2034,7 +2034,26 @@ } }; +struct PipeTypeLocInfo { + SourceLocation KWLoc; +}; + +class PipeTypeLoc : public ConcreteTypeLoc { +public: + TypeLoc getValueLoc() const { return this->getInnerTypeLoc(); } + + SourceRange getLocalSourceRange() const { return SourceRange(getKWLoc()); } + + SourceLocation getKWLoc() const { return this->getLocalData()->KWLoc; } + void setKWLoc(SourceLocation Loc) { this->getLocalData()->KWLoc = Loc; } + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setKWLoc(Loc); + } + + QualType getInnerType() const { return this->getTypePtr()->getElementType(); } +}; } #endif Index: include/clang/AST/TypeNodes.def =================================================================== --- include/clang/AST/TypeNodes.def +++ include/clang/AST/TypeNodes.def @@ -104,6 +104,7 @@ TYPE(ObjCObject, Type) TYPE(ObjCInterface, ObjCObjectType) TYPE(ObjCObjectPointer, Type) +TYPE(Pipe, Type) TYPE(Atomic, Type) #ifdef LAST_TYPE Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -1739,7 +1739,7 @@ "'decltype(auto)' can only be used as a return type " "in a function declaration">; def err_decltype_auto_compound_type : Error< - "cannot form %select{pointer to|reference to|array of}0 'decltype(auto)'">; + "cannot form %select{pointer to|reference to|array of|pipe of}0 'decltype(auto)'">; def err_decltype_auto_initializer_list : Error< "cannot deduce 'decltype(auto)' from initializer list">; @@ -7555,6 +7555,8 @@ "sampler type cannot be used with the __local and __global address space qualifiers">; def err_opencl_global_invalid_addr_space : Error< "program scope variable must reside in %0 address space">; +def err_missing_actual_pipe_type : Error< + "missing actual type specifier for pipe">; def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">; def err_opencl_kernel_attr : Error<"attribute %0 can only be applied to a kernel function">; Index: include/clang/Basic/Specifiers.h =================================================================== --- include/clang/Basic/Specifiers.h +++ include/clang/Basic/Specifiers.h @@ -35,6 +35,11 @@ TSS_unsigned }; + enum TypeSpecifiersPipe { + TSP_unspecified, + TSP_pipe + }; + /// \brief Specifies the kind of type. enum TypeSpecifierType { TST_unspecified, Index: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -519,6 +519,8 @@ // OpenMP Type Traits KEYWORD(__builtin_omp_required_simd_align, KEYALL) +KEYWORD(pipe , KEYOPENCL) + // Borland Extensions. KEYWORD(__pascal , KEYALL) Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -342,6 +342,7 @@ unsigned TypeAltiVecPixel : 1; unsigned TypeAltiVecBool : 1; unsigned TypeSpecOwned : 1; + unsigned TypeSpecPipe : 1; // type-qualifiers unsigned TypeQualifiers : 4; // Bitwise OR of TQ. @@ -390,6 +391,7 @@ SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc; SourceLocation FS_forceinlineLoc; SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc, ConceptLoc; + SourceLocation TQ_pipeLoc; WrittenBuiltinSpecs writtenBS; void SaveWrittenBuiltinSpecs(); @@ -425,6 +427,7 @@ TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false), + TypeSpecPipe(false), TypeQualifiers(TQ_unspecified), FS_inline_specified(false), FS_forceinline_specified(false), @@ -478,6 +481,7 @@ bool isTypeAltiVecBool() const { return TypeAltiVecBool; } bool isTypeSpecOwned() const { return TypeSpecOwned; } bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); } + bool isTypeSpecPipe() const { return TypeSpecPipe; } ParsedType getRepAsType() const { assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type"); @@ -537,6 +541,7 @@ SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; } SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; } SourceLocation getAtomicSpecLoc() const { return TQ_atomicLoc; } + SourceLocation getPipeLoc() const { return TQ_pipeLoc; } /// \brief Clear out all of the type qualifiers. void ClearTypeQualifiers() { @@ -545,6 +550,7 @@ TQ_restrictLoc = SourceLocation(); TQ_volatileLoc = SourceLocation(); TQ_atomicLoc = SourceLocation(); + TQ_pipeLoc = SourceLocation(); } // function-specifier @@ -648,6 +654,9 @@ bool SetTypeAltiVecBool(bool isAltiVecBool, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, const PrintingPolicy &Policy); + bool SetTypePipe(bool isPipe, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); bool SetTypeSpecError(); void UpdateDeclRep(Decl *Rep) { assert(isDeclRep((TST) TypeSpecType)); @@ -1087,7 +1096,7 @@ /// This is intended to be a small value object. struct DeclaratorChunk { enum { - Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren + Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren, Pipe } Kind; /// Loc - The place where this type was defined. @@ -1434,6 +1443,7 @@ case DeclaratorChunk::Array: return Arr.destroy(); case DeclaratorChunk::MemberPointer: return Mem.destroy(); case DeclaratorChunk::Paren: return; + case DeclaratorChunk::Pipe: return; } } @@ -1532,6 +1542,17 @@ return I; } + /// \brief Return a DeclaratorChunk for a block. + static DeclaratorChunk getPipe(unsigned TypeQuals, + SourceLocation Loc) { + DeclaratorChunk I; + I.Kind = Pipe; + I.Loc = Loc; + I.Cls.TypeQuals = TypeQuals; + I.Cls.AttrList = 0; + return I; + } + static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS, unsigned TypeQuals, SourceLocation Loc) { @@ -2032,6 +2053,7 @@ case DeclaratorChunk::Array: case DeclaratorChunk::BlockPointer: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: return false; } llvm_unreachable("Invalid type chunk"); Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1251,6 +1251,8 @@ SourceLocation Loc, DeclarationName Entity); QualType BuildParenType(QualType T); QualType BuildAtomicType(QualType T, SourceLocation Loc); + QualType BuildPipeType(QualType T, + SourceLocation Loc); TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -907,7 +907,9 @@ /// \brief A DecayedType record. TYPE_DECAYED = 41, /// \brief An AdjustedType record. - TYPE_ADJUSTED = 42 + TYPE_ADJUSTED = 42, + /// \brief An PipeType record. + TYPE_PIPE = 43 }; /// \brief The type IDs for special types constructed by semantic Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -1838,6 +1838,14 @@ Align = static_cast(Width); } } + break; + + case Type::Pipe: { + TypeInfo Info = getTypeInfo(cast(T)->getElementType()); + Width = Info.Width; + Align = Info.Align; + } + break; } @@ -2654,6 +2662,7 @@ case Type::FunctionProto: case Type::BlockPointer: case Type::MemberPointer: + case Type::Pipe: return type; // These types can be variably-modified. All these modifications @@ -3108,6 +3117,34 @@ return QualType(FTP, 0); } +/// Return pipe type for the specified type. +QualType ASTContext::getPipeType(QualType T) const { + // Unique pointers, to guarantee there is only one pointer of a particular + // structure. + llvm::FoldingSetNodeID ID; + PipeType::Profile(ID); + + void *InsertPos = 0; + if (PipeType *PT = PipeTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(PT, 0); + + // If the pipe element type isn't canonical, this won't be a canonical type + // either, so fill in the canonical type field. + QualType Canonical; + if (!T.isCanonical()) { + Canonical = getPipeType(getCanonicalType(T)); + + // Get the new insert position for the node we care about. + PipeType *NewIP = PipeTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + (void)NewIP; + } + PipeType *New = new (*this, TypeAlignment) PipeType(T, Canonical); + Types.push_back(New); + PipeTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + #ifndef NDEBUG static bool NeedsInjectedClassNameType(const RecordDecl *D) { if (!isa(D)) return false; @@ -5839,6 +5876,7 @@ //FIXME. We should do a better job than gcc. case Type::Vector: case Type::ExtVector: + case Type::Pipe: // Until we have a coherent encoding of these three types, issue warning. { if (NotEncodedT) *NotEncodedT = T; @@ -7785,6 +7823,24 @@ return QualType(); } + case Type::Pipe: + { + // Merge two pointer types, while trying to preserve typedef info + QualType LHSValue = LHS->getAs()->getElementType(); + QualType RHSValue = RHS->getAs()->getElementType(); + if (Unqualified) { + LHSValue = LHSValue.getUnqualifiedType(); + RHSValue = RHSValue.getUnqualifiedType(); + } + QualType ResultType = mergeTypes(LHSValue, RHSValue, false, + Unqualified); + if (ResultType.isNull()) return QualType(); + if (getCanonicalType(LHSValue) == getCanonicalType(ResultType)) + return LHS; + if (getCanonicalType(RHSValue) == getCanonicalType(ResultType)) + return RHS; + return getPipeType(ResultType); + } } llvm_unreachable("Invalid Type::Class!"); Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -878,6 +878,14 @@ break; } + case Type::Pipe: { + if (!IsStructurallyEquivalent(Context, + cast(T1)->getElementType(), + cast(T2)->getElementType())) + return false; + break; + } + } // end switch return true; Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -1507,6 +1507,7 @@ case Type::ObjCInterface: case Type::ObjCObjectPointer: case Type::Atomic: + case Type::Pipe: llvm_unreachable("type is illegal as a nested name specifier"); case Type::SubstTemplateTypeParmPack: @@ -2668,6 +2669,12 @@ mangleType(T->getValueType()); } +void CXXNameMangler::mangleType(const PipeType *T) { + // Pipe type mangling rules are described in SPIR 2.0 specification. + // ::= 8ocl_pipe + Out << "8ocl_pipe"; +} + void CXXNameMangler::mangleIntegerLiteral(QualType T, const llvm::APSInt &Value) { // ::= L E # integer literal Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -2332,6 +2332,15 @@ << Range; } +void MicrosoftCXXNameMangler::mangleType(const PipeType *T, Qualifiers, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this OpenCL pipe type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + void MicrosoftMangleContextImpl::mangleCXXName(const NamedDecl *D, raw_ostream &Out) { assert((isa(D) || isa(D)) && Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -3337,6 +3337,8 @@ return Cache::get(cast(T)->getPointeeType()); case Type::Atomic: return Cache::get(cast(T)->getValueType()); + case Type::Pipe: + return Cache::get(cast(T)->getElementType()); } llvm_unreachable("unhandled type class"); @@ -3419,6 +3421,8 @@ return computeLinkageInfo(cast(T)->getPointeeType()); case Type::Atomic: return computeLinkageInfo(cast(T)->getValueType()); + case Type::Pipe: + return computeLinkageInfo(cast(T)->getElementType()); } llvm_unreachable("unhandled type class"); @@ -3577,6 +3581,7 @@ case Type::ObjCObject: case Type::ObjCInterface: case Type::Atomic: + case Type::Pipe: return false; } llvm_unreachable("bad type kind!"); Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -193,6 +193,7 @@ case Type::ObjCObject: case Type::ObjCInterface: case Type::Atomic: + case Type::Pipe: CanPrefixQualifiers = true; break; @@ -859,6 +860,15 @@ } void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) { } +void TypePrinter::printPipeBefore(const PipeType *T, raw_ostream &OS) { + IncludeStrongLifetimeRAII Strong(Policy); + + OS << "pipe"; + spaceBeforePlaceHolder(OS); +} + +void TypePrinter::printPipeAfter(const PipeType *T, raw_ostream &OS) { +} /// Appends the given scope to the end of a string. void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) { if (DC->isTranslationUnit()) return; Index: lib/CodeGen/CGDebugInfo.h =================================================================== --- lib/CodeGen/CGDebugInfo.h +++ lib/CodeGen/CGDebugInfo.h @@ -168,6 +168,7 @@ llvm::DIType *CreateType(const RValueReferenceType *Ty, llvm::DIFile *Unit); llvm::DIType *CreateType(const MemberPointerType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const AtomicType *Ty, llvm::DIFile *F); + llvm::DIType *CreateType(const PipeType *Ty, llvm::DIFile *F); /// Get enumeration type. llvm::DIType *CreateEnumType(const EnumType *Ty); llvm::DIType *CreateTypeDefinition(const EnumType *Ty); Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -2000,6 +2000,13 @@ return getOrCreateType(Ty->getValueType(), U); } +llvm::DIType* CGDebugInfo::CreateType(const PipeType *Ty, + llvm::DIFile *U) { + // Ignore the atomic wrapping + // FIXME: What is the correct representation? + return getOrCreateType(Ty->getElementType(), U); +} + llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) { const EnumDecl *ED = Ty->getDecl(); @@ -2259,6 +2266,9 @@ case Type::Atomic: return CreateType(cast(Ty), Unit); + case Type::Pipe: + return CreateType(cast(Ty), Unit); + case Type::TemplateSpecialization: return CreateType(cast(Ty), Unit); Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -195,6 +195,7 @@ case Type::FunctionNoProto: case Type::Enum: case Type::ObjCObjectPointer: + case Type::Pipe: return TEK_Scalar; // Complexes. @@ -1709,6 +1710,10 @@ case Type::Atomic: type = cast(ty)->getValueType(); break; + + case Type::Pipe: + type = cast(ty)->getElementType(); + break; } } while (type->isVariablyModifiedType()); } Index: lib/CodeGen/CodeGenTypes.cpp =================================================================== --- lib/CodeGen/CodeGenTypes.cpp +++ lib/CodeGen/CodeGenTypes.cpp @@ -624,6 +624,11 @@ } break; } + case Type::Pipe: { + ResultType = llvm::PointerType::get(llvm::StructType::create( + CGM.getLLVMContext(), "opencl.pipe_t"), 0); + break; + } } assert(ResultType && "Didn't convert a type?"); Index: lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- lib/CodeGen/ItaniumCXXABI.cpp +++ lib/CodeGen/ItaniumCXXABI.cpp @@ -2712,6 +2712,9 @@ case Type::Auto: llvm_unreachable("Undeduced auto type shouldn't get here"); + case Type::Pipe: + llvm_unreachable("Pipe types shouldn't get here"); + case Type::Builtin: // GCC treats vector and complex types as fundamental types. case Type::Vector: @@ -2936,6 +2939,9 @@ case Type::Auto: llvm_unreachable("Undeduced auto type shouldn't get here"); + case Type::Pipe: + llvm_unreachable("Pipe type shouldn't get here"); + case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -3326,6 +3326,15 @@ case tok::kw___bool: isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID, Policy); break; + case tok::kw_pipe: + if (!getLangOpts().OpenCL || (getLangOpts().OpenCLVersion < 200)) { + // OpenCL 2.0 defined this keyword. OpenCL 1.2 and earlier should + // support the "pipe" word as identifier. + Tok.getIdentifierInfo()->revertTokenIDToIdentifier(); + goto DoneWithDeclSpec; + } + isInvalid = DS.SetTypePipe(true, Loc, PrevSpec, DiagID, Policy); + break; case tok::kw___unknown_anytype: isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc, PrevSpec, DiagID, Policy); @@ -4401,6 +4410,9 @@ switch (Tok.getKind()) { default: return false; + case tok::kw_pipe: + return getLangOpts().OpenCL && (getLangOpts().OpenCLVersion >= 200); + case tok::identifier: // foo::bar // Unfortunate hack to support "Class.factoryMethod" notation. if (getLangOpts().ObjC1 && NextToken().is(tok::period)) @@ -4847,6 +4859,9 @@ if (Kind == tok::star || Kind == tok::caret) return true; + if ((Kind == tok::kw_pipe) && Lang.OpenCL && (Lang.OpenCLVersion >= 200)) + return true; + if (!Lang.CPlusPlus) return false; @@ -4941,6 +4956,15 @@ } tok::TokenKind Kind = Tok.getKind(); + + if (D.getDeclSpec().isTypeSpecPipe()) { + DeclSpec &DS = D.getMutableDeclSpec(); + + D.AddTypeInfo( + DeclaratorChunk::getPipe(DS.getTypeQualifiers(), DS.getPipeLoc()), + DS.getAttributes(), SourceLocation()); + } + // Not a pointer, C++ reference, or block. if (!isPtrOperatorToken(Kind, getLangOpts(), D.getContext())) { if (DirectDeclParser) @@ -6083,6 +6107,7 @@ case DeclaratorChunk::Reference: case DeclaratorChunk::BlockPointer: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: NeedParens = true; break; case DeclaratorChunk::Array: Index: lib/Sema/DeclSpec.cpp =================================================================== --- lib/Sema/DeclSpec.cpp +++ lib/Sema/DeclSpec.cpp @@ -280,6 +280,7 @@ case DeclaratorChunk::Array: case DeclaratorChunk::BlockPointer: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: return false; } llvm_unreachable("Invalid type chunk"); @@ -723,6 +724,22 @@ return false; } +bool DeclSpec::SetTypePipe(bool isPipe, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy) { + + if (TypeSpecType != TST_unspecified) { + PrevSpec = DeclSpec::getSpecifierName((TST)TypeSpecType, Policy); + DiagID = diag::err_missing_actual_pipe_type; + return true; + } + + if (isPipe) { + TypeSpecPipe = TSP_pipe; + } + return false; +} + bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, const PrintingPolicy &Policy) { Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -7013,6 +7013,7 @@ case DeclaratorChunk::BlockPointer: case DeclaratorChunk::Reference: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: extendLeft(Before, Chunk.getSourceRange()); break; Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -13069,6 +13069,7 @@ case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: + case Type::Pipe: llvm_unreachable("type class is never variably-modified!"); case Type::Adjusted: QTy = cast(Ty)->getOriginalType(); Index: lib/Sema/SemaLookup.cpp =================================================================== --- lib/Sema/SemaLookup.cpp +++ lib/Sema/SemaLookup.cpp @@ -2581,6 +2581,9 @@ case Type::Atomic: T = cast(T)->getValueType().getTypePtr(); continue; + case Type::Pipe: + T = cast(T)->getElementType().getTypePtr(); + continue; } if (Queue.empty()) Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -4181,6 +4181,10 @@ return Visit(T->getValueType()); } +bool UnnamedLocalNoLinkageFinder::VisitPipeType(const PipeType* T) { + return false; +} + bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) { if (Tag->getDeclContext()->isFunctionOrMethod()) { S.Diag(SR.getBegin(), Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -1643,6 +1643,7 @@ case Type::Auto: case Type::DependentTemplateSpecialization: case Type::PackExpansion: + case Type::Pipe: // No template argument deduction for these types return Sema::TDK_Success; } @@ -4906,6 +4907,7 @@ case Type::ObjCObject: case Type::ObjCObjectPointer: case Type::UnresolvedUsing: + case Type::Pipe: #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) Index: lib/Sema/SemaTemplateVariadic.cpp =================================================================== --- lib/Sema/SemaTemplateVariadic.cpp +++ lib/Sema/SemaTemplateVariadic.cpp @@ -750,6 +750,7 @@ case DeclaratorChunk::Pointer: case DeclaratorChunk::Reference: case DeclaratorChunk::Paren: + case DeclaratorChunk::Pipe: case DeclaratorChunk::BlockPointer: // These declarator chunks cannot contain any parameter packs. break; Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -336,6 +336,7 @@ case DeclaratorChunk::Array: case DeclaratorChunk::Reference: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: return result; // If we do find a function declarator, scan inwards from that, @@ -348,6 +349,7 @@ case DeclaratorChunk::Array: case DeclaratorChunk::Function: case DeclaratorChunk::Reference: + case DeclaratorChunk::Pipe: continue; case DeclaratorChunk::MemberPointer: @@ -428,6 +430,7 @@ // Don't walk through these. case DeclaratorChunk::Reference: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: goto error; } } @@ -460,6 +463,7 @@ case DeclaratorChunk::MemberPointer: case DeclaratorChunk::Paren: case DeclaratorChunk::Array: + case DeclaratorChunk::Pipe: continue; case DeclaratorChunk::Function: @@ -521,6 +525,7 @@ case DeclaratorChunk::Array: case DeclaratorChunk::Reference: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: continue; } } @@ -1565,8 +1570,11 @@ // Apply any type attributes from the decl spec. This may cause the // list of type attributes to be temporarily saved while the type // attributes are pushed around. - if (AttributeList *attrs = DS.getAttributes().getList()) - processTypeAttrs(state, Result, TAL_DeclSpec, attrs); + if (!DS.isTypeSpecPipe()) { // pipe attributes will be handled later ( at + // GetFullTypeForDeclarator ) + if (AttributeList *attrs = DS.getAttributes().getList()) + processTypeAttrs(state, Result, TAL_DeclSpec, attrs); + } // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -1926,6 +1934,23 @@ return Context.getRValueReferenceType(T); } +/// \brief Build a Pipe type. +/// +/// \param T The type to which we'll be building a Pipe. +/// +/// \param Loc The location of the entity whose type involves this pointer type +/// or, if there is no such entity, the location of the type that will have +/// pointer type. +/// +/// \returns A suitable pipe type, if there are no errors. Otherwise, returns a +/// NULL type. +QualType Sema::BuildPipeType(QualType T, SourceLocation Loc) { + assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType"); + + // Build the pipe type. + return Context.getPipeType(T); +} + /// Check whether the specified array size makes the array type a VLA. If so, /// return true, if not, return the size of the array in SizeVal. static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) { @@ -2398,6 +2423,7 @@ case DeclaratorChunk::Array: // suppress if written (id[])? case DeclaratorChunk::Function: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: return; } } @@ -2537,6 +2563,7 @@ case DeclaratorChunk::Reference: case DeclaratorChunk::Array: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: // FIXME: We can't currently provide an accurate source location and a // fix-it hint for these. unsigned AtomicQual = RetTy->isAtomicType() ? DeclSpec::TQ_atomic : 0; @@ -3066,6 +3093,7 @@ switch (chunk.Kind) { case DeclaratorChunk::Array: case DeclaratorChunk::Function: + case DeclaratorChunk::Pipe: break; case DeclaratorChunk::BlockPointer: @@ -3314,6 +3342,9 @@ case DeclaratorChunk::Array: DiagKind = 2; break; + case DeclaratorChunk::Pipe: + DiagKind = 3; + break; } S.Diag(DeclChunk.Loc, DiagId) << DiagKind; @@ -3379,6 +3410,7 @@ switch (chunk.Kind) { case DeclaratorChunk::Array: case DeclaratorChunk::Function: + case DeclaratorChunk::Pipe: break; case DeclaratorChunk::BlockPointer: @@ -3698,6 +3730,7 @@ break; case DeclaratorChunk::Function: case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::Pipe: // These are invalid anyway, so just ignore. break; } @@ -4047,7 +4080,7 @@ break; } - case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::MemberPointer: { // The scope spec must refer to a class, or be dependent. CXXScopeSpec &SS = DeclType.Mem.Scope(); QualType ClsType; @@ -4107,6 +4140,11 @@ break; } + case DeclaratorChunk::Pipe: + T = S.BuildPipeType(T, DeclType.Loc ); + break; + } + if (T.isNull()) { D.setInvalidType(true); T = Context.IntTy; @@ -4402,6 +4440,7 @@ case DeclaratorChunk::Function: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: return; } } @@ -4691,6 +4730,14 @@ } } + void VisitPipeTypeLoc(PipeTypeLoc TL) { + TL.setKWLoc(DS.getTypeSpecTypeLoc()); + + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); + TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc()); + } + void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(Context, DS.getTypeSpecTypeLoc()); @@ -4811,6 +4858,10 @@ TL.setLParenLoc(Chunk.Loc); TL.setRParenLoc(Chunk.EndLoc); } + void VisitPipeTypeLoc(PipeTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Pipe); + TL.setKWLoc(Chunk.Loc); + } void VisitTypeLoc(TypeLoc TL) { llvm_unreachable("unsupported TypeLoc kind in declarator!"); @@ -4824,6 +4875,7 @@ case DeclaratorChunk::Function: case DeclaratorChunk::Array: case DeclaratorChunk::Paren: + case DeclaratorChunk::Pipe: llvm_unreachable("cannot be _Atomic qualified"); case DeclaratorChunk::Pointer: @@ -5727,6 +5779,7 @@ // Don't walk through these. case DeclaratorChunk::Reference: + case DeclaratorChunk::Pipe: return false; } } Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -1046,6 +1046,9 @@ /// Subclasses may override this routine to provide different behavior. QualType RebuildAtomicType(QualType ValueType, SourceLocation KWLoc); + /// \brief Build a new pipe type given its value type. + QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc); + /// \brief Build a new template name given a nested name specifier, a flag /// indicating whether the "template" keyword was provided, and the template /// that the template name refers to. @@ -5246,6 +5249,27 @@ return Result; } +template +QualType TreeTransform::TransformPipeType(TypeLocBuilder &TLB, + PipeTypeLoc TL) { + QualType ValueType = getDerived().TransformType(TLB, TL.getValueLoc()); + if (ValueType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || ValueType != TL.getValueLoc().getType()) { + Result = getDerived().RebuildPipeType(ValueType, TL.getKWLoc()); + if (Result.isNull()) + return QualType(); + } + + PipeTypeLoc NewTL = TLB.push(Result); + NewTL.setKWLoc(TL.getKWLoc()); + + return Result; +} + +namespace { /// \brief Simple iterator that traverses the template arguments in a /// container that provides a \c getArgLoc() member function. /// @@ -5309,6 +5333,7 @@ return !(X == Y); } }; +} template @@ -11134,6 +11159,12 @@ } template +QualType TreeTransform::RebuildPipeType(QualType ValueType, + SourceLocation KWLoc) { + return SemaRef.BuildPipeType(ValueType, KWLoc); +} + +template TemplateName TreeTransform::RebuildTemplateName(CXXScopeSpec &SS, bool TemplateKW, Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -5631,6 +5631,17 @@ QualType ValueType = readType(*Loc.F, Record, Idx); return Context.getAtomicType(ValueType); } + + case TYPE_PIPE: { + if (Record.size() != 1) { + Error("Incorrect encoding of pipe type"); + return QualType(); + } + + // Reading the pipe element type. + QualType ElementType = readType(*Loc.F, Record, Idx); + return Context.getPipeType(ElementType); + } } llvm_unreachable("Invalid TypeCode!"); } @@ -5902,6 +5913,9 @@ TL.setLParenLoc(ReadSourceLocation(Record, Idx)); TL.setRParenLoc(ReadSourceLocation(Record, Idx)); } +void TypeLocReader::VisitPipeTypeLoc(PipeTypeLoc TL) { + TL.setKWLoc(ReadSourceLocation(Record, Idx)); +} TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F, const RecordData &Record, Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -447,6 +447,12 @@ Code = TYPE_ATOMIC; } +void +ASTTypeWriter::VisitPipeType(const PipeType *T) { + Writer.AddTypeRef(T->getElementType(), Record); + Code = TYPE_PIPE; +} + namespace { class TypeLocWriter : public TypeLocVisitor { @@ -673,6 +679,9 @@ Writer.AddSourceLocation(TL.getLParenLoc(), Record); Writer.AddSourceLocation(TL.getRParenLoc(), Record); } +void TypeLocWriter::VisitPipeTypeLoc(PipeTypeLoc TL) { + Writer.AddSourceLocation(TL.getKWLoc(), Record); +} void ASTWriter::WriteTypeAbbrevs() { using namespace llvm; Index: test/CodeGenOpenCL/pipe_types.cl =================================================================== --- /dev/null +++ test/CodeGenOpenCL/pipe_types.cl @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck %s + +// CHECK: %opencl.pipe_t = type opaque +typedef unsigned char __attribute__((ext_vector_type(3))) uchar3; +typedef int __attribute__((ext_vector_type(4))) int4; + +void test1(read_only pipe int p) { +// CHECK: define void @test1(%opencl.pipe_t* %p) + reserve_id_t rid; +// CHECK: %rid = alloca %opencl.reserve_id_t +} + +void test2(write_only pipe float p) { +// CHECK: define void @test2(%opencl.pipe_t* %p) + reserve_id_t rid; +} + +void test3(read_only pipe const int p) { +// CHECK: define void @test3(%opencl.pipe_t* %p) + reserve_id_t rid; +// CHECK: %rid = alloca %opencl.reserve_id_t +} + +void test4(read_only pipe uchar3 p) { +// CHECK: define void @test4(%opencl.pipe_t* %p) + reserve_id_t rid; +// CHECK: %rid = alloca %opencl.reserve_id_t +} + +void test5(read_only pipe int4 p) { +// CHECK: define void @test5(%opencl.pipe_t* %p) + reserve_id_t rid; +// CHECK: %rid = alloca %opencl.reserve_id_t +} Index: test/PCH/ocl_types.h =================================================================== --- test/PCH/ocl_types.h +++ test/PCH/ocl_types.h @@ -44,6 +44,7 @@ // image2d_array_depth_t typedef image2d_array_depth_t img2darr_dep_t; +#pragma OPENCL EXTENSION cl_khr_gl_msaa_sharing : enable // image2d_msaa_t typedef image2d_msaa_t img2dmsaa_t; @@ -56,4 +57,14 @@ // image2d_array_msaa_depth_t typedef image2d_array_msaa_depth_t img2darrmsaadep_t; +// pipe specifier + +typedef struct _person { + int id; + const char *name; +} Person; + +void int_pipe_function(pipe int); + +void person_pipe_function(pipe Person); #endif Index: test/PCH/ocl_types.cl =================================================================== --- test/PCH/ocl_types.cl +++ test/PCH/ocl_types.cl @@ -1,9 +1,9 @@ // Test this without pch. -// RUN: %clang_cc1 -include %S/ocl_types.h -fsyntax-only %s +// RUN: %clang_cc1 -include %S/ocl_types.h -fsyntax-only %s -cl-std=CL2.0 -D__OPENCL_VERSION__=200 // Test with pch. -// RUN: %clang_cc1 -x cl -emit-pch -o %t %S/ocl_types.h -// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s -ast-print +// RUN: %clang_cc1 -x cl -emit-pch -o %t %S/ocl_types.h -cl-std=CL2.0 -D__OPENCL_VERSION__=200 +// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s -ast-print -cl-std=CL2.0 -D__OPENCL_VERSION__=200 void foo1(img1d_t img); @@ -24,3 +24,15 @@ void foo8(evt_t evt) { evt_t loc_evt; } + +#if __OPENCL_VERSION__ >= 200 + +void foo9(pipe int P) { + int_pipe_function(P); +} + +void foo10(pipe Person P) { + person_pipe_function(P); +} + +#endif Index: test/SemaOpenCL/pipes-1.2-negative.cl =================================================================== --- /dev/null +++ test/SemaOpenCL/pipes-1.2-negative.cl @@ -0,0 +1,3 @@ +// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL1.2 + +void foo(read_only pipe int p); // expected-error {{expected parameter declarator}} expected-error {{expected ')'}} expected-note {{to match this '('}} Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -1685,6 +1685,10 @@ return Visit(TL.getValueLoc()); } +bool CursorVisitor::VisitPipeTypeLoc(PipeTypeLoc TL) { + return Visit(TL.getValueLoc()); +} + #define DEFAULT_TYPELOC_IMPL(CLASS, PARENT) \ bool CursorVisitor::Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ return Visit##PARENT##Loc(TL); \