Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -135,8 +135,7 @@ mutable llvm::FoldingSet AutoTypes; mutable llvm::FoldingSet AtomicTypes; llvm::FoldingSet AttributedTypes; - mutable llvm::FoldingSet ReadPipeTypes; - mutable llvm::FoldingSet WritePipeTypes; + mutable llvm::FoldingSet PipeTypes; mutable llvm::FoldingSet QualifiedTemplateNames; mutable llvm::FoldingSet DependentTemplateNames; @@ -1012,6 +1011,8 @@ QualType getTypeDeclTypeSlow(const TypeDecl *Decl) const; + QualType getPipeType(QualType T, bool ReadOnly) const; + public: /// \brief Return the uniqued reference to the type for an address space /// qualified type with the specified type and address space. Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -5285,7 +5285,6 @@ /// PipeType - OpenCL20. class PipeType : public Type, public llvm::FoldingSetNode { -protected: QualType ElementType; bool isRead; @@ -5295,6 +5294,7 @@ elemType->isVariablyModifiedType(), elemType->containsUnexpandedParameterPack()), ElementType(elemType), isRead(isRead) {} + friend class ASTContext; // ASTContext creates these. public: QualType getElementType() const { return ElementType; } @@ -5304,11 +5304,12 @@ QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getElementType()); + Profile(ID, getElementType(), isReadOnly()); } - static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { + static void Profile(llvm::FoldingSetNodeID &ID, QualType T, bool isRead) { ID.AddPointer(T.getAsOpaquePtr()); + ID.AddBoolean(isRead); } static bool classof(const Type *T) { @@ -5318,18 +5319,6 @@ bool isReadOnly() const { return isRead; } }; -class ReadPipeType : public PipeType { - ReadPipeType(QualType elemType, QualType CanonicalPtr) : - PipeType(elemType, CanonicalPtr, true) {} - friend class ASTContext; // ASTContext creates these. -}; - -class WritePipeType : public PipeType { - WritePipeType(QualType elemType, QualType CanonicalPtr) : - PipeType(elemType, CanonicalPtr, false) {} - friend class ASTContext; // ASTContext creates these. -}; - /// A qualifier set is used to build a set of qualifiers. class QualifierCollector : public Qualifiers { public: Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -905,12 +905,10 @@ TYPE_DECAYED = 41, /// \brief An AdjustedType record. TYPE_ADJUSTED = 42, - /// \brief A ReadPipeType record. - TYPE_READ_PIPE = 43, + /// \brief A PipeType record. + TYPE_PIPE = 43, /// \brief An ObjCTypeParamType record. - TYPE_OBJC_TYPE_PARAM = 44, - /// \brief A WritePipeType record. - TYPE_WRITE_PIPE = 45, + TYPE_OBJC_TYPE_PARAM = 44 }; /// \brief The type IDs for special types constructed by semantic Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -3338,54 +3338,37 @@ return QualType(FTP, 0); } -QualType ASTContext::getReadPipeType(QualType T) const { +QualType ASTContext::getPipeType(QualType T, bool ReadOnly) const { llvm::FoldingSetNodeID ID; - ReadPipeType::Profile(ID, T); + PipeType::Profile(ID, T, ReadOnly); void *InsertPos = 0; - if (ReadPipeType *PT = ReadPipeTypes.FindNodeOrInsertPos(ID, InsertPos)) + 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 = getReadPipeType(getCanonicalType(T)); + Canonical = getPipeType(getCanonicalType(T), ReadOnly); // Get the new insert position for the node we care about. - ReadPipeType *NewIP = ReadPipeTypes.FindNodeOrInsertPos(ID, InsertPos); + PipeType *NewIP = PipeTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - ReadPipeType *New = new (*this, TypeAlignment) ReadPipeType(T, Canonical); + PipeType *New = new (*this, TypeAlignment) PipeType(T, Canonical, ReadOnly); Types.push_back(New); - ReadPipeTypes.InsertNode(New, InsertPos); + PipeTypes.InsertNode(New, InsertPos); return QualType(New, 0); } -QualType ASTContext::getWritePipeType(QualType T) const { - llvm::FoldingSetNodeID ID; - WritePipeType::Profile(ID, T); - - void *InsertPos = 0; - if (WritePipeType *PT = WritePipeTypes.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 = getWritePipeType(getCanonicalType(T)); +QualType ASTContext::getReadPipeType(QualType T) const { + return getPipeType(T, true); +} - // Get the new insert position for the node we care about. - WritePipeType *NewIP = WritePipeTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(!NewIP && "Shouldn't be in the map!"); - (void)NewIP; - } - WritePipeType *New = new (*this, TypeAlignment) WritePipeType(T, Canonical); - Types.push_back(New); - WritePipeTypes.InsertNode(New, InsertPos); - return QualType(New, 0); +QualType ASTContext::getWritePipeType(QualType T) const { + return getPipeType(T, false); } #ifndef NDEBUG @@ -8258,22 +8241,9 @@ } 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 isa(LHS) ? getReadPipeType(ResultType) - : getWritePipeType(ResultType); + assert(LHS != RHS && + "Equivalent pipe types should have already been handled!"); + return QualType(); } } Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -5793,27 +5793,21 @@ return Context.getAtomicType(ValueType); } - case TYPE_READ_PIPE: { - if (Record.size() != 1) { + case TYPE_PIPE: { + if (Record.size() != 2) { Error("Incorrect encoding of pipe type"); return QualType(); } // Reading the pipe element type. QualType ElementType = readType(*Loc.F, Record, Idx); - return Context.getReadPipeType(ElementType); + unsigned ReadOnly = Record[1]; + if (ReadOnly) + return Context.getReadPipeType(ElementType); + else + return Context.getWritePipeType(ElementType); } - case TYPE_WRITE_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.getWritePipeType(ElementType); - } } llvm_unreachable("Invalid TypeCode!"); } Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -516,10 +516,8 @@ void ASTTypeWriter::VisitPipeType(const PipeType *T) { Record.AddTypeRef(T->getElementType()); - if (T->isReadOnly()) - Code = TYPE_READ_PIPE; - else - Code = TYPE_WRITE_PIPE; + Record.push_back(T->isReadOnly()); + Code = TYPE_PIPE; } namespace { Index: test/SemaOpenCL/invalid-pipes-cl2.0.cl =================================================================== --- test/SemaOpenCL/invalid-pipes-cl2.0.cl +++ test/SemaOpenCL/invalid-pipes-cl2.0.cl @@ -20,3 +20,12 @@ typedef pipe int pipe_int_t; pipe_int_t test6() {} // expected-error{{declaring function return value of type 'pipe_int_t' (aka 'read_only pipe int') is not allowed}} + +// Tests ASTContext::mergeTypes rejects this. +int f(pipe int x, int y); +int f(x, y) +pipe short x; +int y; +{ + return y; +}