Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -143,6 +143,8 @@ mutable llvm::FoldingSet DependentSizedArrayTypes; mutable llvm::FoldingSet DependentSizedExtVectorTypes; + mutable llvm::FoldingSet + DependentAddressSpaceTypes; mutable llvm::FoldingSet VectorTypes; mutable llvm::FoldingSet FunctionNoProtoTypes; mutable llvm::ContextualFoldingSet @@ -1070,6 +1072,13 @@ /// replaced. QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const; + /// \brief Remove any existing address space on the type and returns the type + /// with qualifiers intact (or that's the idea anyway) + /// + /// The return type should be T with all prior qualifiers minus the address + /// space. + QualType removeAddrSpaceQualType(QualType T) const; + /// \brief Apply Objective-C protocol qualifiers to the given type. /// \param allowOnPointerType specifies if we can apply protocol /// qualifiers on ObjCObjectPointerType. It can be set to true when @@ -1270,6 +1279,10 @@ Expr *SizeExpr, SourceLocation AttrLoc) const; + QualType getDependentAddressSpaceType(QualType PointeeType, + Expr *AddrSpaceExpr, + SourceLocation AttrLoc) const; + /// \brief Return a K&R style C function type like 'int()'. QualType getFunctionNoProtoType(QualType ResultTy, const FunctionType::ExtInfo &Info) const; Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -989,6 +989,11 @@ TRY_TO(TraverseStmt(T->getSizeExpr())); }) +DEF_TRAVERSE_TYPE(DependentAddressSpaceType, { + TRY_TO(TraverseStmt(T->getAddrSpaceExpr())); + TRY_TO(TraverseType(T->getPointeeType())); +}) + DEF_TRAVERSE_TYPE(DependentSizedExtVectorType, { if (T->getSizeExpr()) TRY_TO(TraverseStmt(T->getSizeExpr())); @@ -1199,6 +1204,11 @@ return TraverseArrayTypeLocHelper(TL); }) +DEF_TRAVERSE_TYPELOC(DependentAddressSpaceType, { + TRY_TO(TraverseStmt(TL.getTypePtr()->getAddrSpaceExpr())); + TRY_TO(TraverseType(TL.getTypePtr()->getPointeeType())); +}) + // FIXME: order? why not size expr first? // FIXME: base VectorTypeLoc is unfinished DEF_TRAVERSE_TYPELOC(DependentSizedExtVectorType, { Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -1705,6 +1705,7 @@ bool isComplexIntegerType() const; // GCC _Complex integer type. bool isVectorType() const; // GCC vector type. bool isExtVectorType() const; // Extended vector type. + bool isDependentAddressSpaceType() const; // value-dependent address space qualifier bool isObjCObjectPointerType() const; // pointer to ObjC object bool isObjCRetainableType() const; // ObjC object or block pointer bool isObjCLifetimeType() const; // (array of)* retainable type @@ -2743,6 +2744,49 @@ unsigned TypeQuals, Expr *E); }; +/// Represents an extended address space qualifier where the input address space +/// value is dependent. Non-dependent address spaces are not represented with a +/// special Type subclass; they are stored on an ExtQuals node as part of a QualType. +/// +/// For example: +/// \code +/// template +/// class AddressSpace { +/// typedef T __attribute__((address_space(AddrSpace))) type; +/// } +/// \endcode +class DependentAddressSpaceType : public Type, public llvm::FoldingSetNode { + const ASTContext &Context; + Expr *AddrSpaceExpr; + QualType PointeeType; + SourceLocation loc; + + DependentAddressSpaceType(const ASTContext &Context, QualType PointeeType, + QualType can, Expr *AddrSpaceExpr, + SourceLocation loc); + + friend class ASTContext; + +public: + Expr *getAddrSpaceExpr() const { return AddrSpaceExpr; } + QualType getPointeeType() const { return PointeeType; } + SourceLocation getAttributeLoc() const { return loc; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentAddressSpace; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getPointeeType(), getAddrSpaceExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType PointeeType, Expr *AddrSpaceExpr); +}; + /// Represents an extended vector type where either the type or size is /// dependent. /// @@ -5778,6 +5822,9 @@ inline bool Type::isExtVectorType() const { return isa(CanonicalType); } +inline bool Type::isDependentAddressSpaceType() const { + return isa(CanonicalType); +} inline bool Type::isObjCObjectPointerType() const { return isa(CanonicalType); } Index: include/clang/AST/TypeLoc.h =================================================================== --- include/clang/AST/TypeLoc.h +++ include/clang/AST/TypeLoc.h @@ -1664,6 +1664,76 @@ } }; +struct DependentAddressSpaceLocInfo { + Expr *ExprOperand; + SourceRange OperandParens; + SourceLocation AttrLoc; +}; + +class DependentAddressSpaceTypeLoc + : public ConcreteTypeLoc { + + public: + + /// The location of the attribute name, i.e. + /// int * __attribute__((address_space(11))) + /// ^~~~~~~~~~~~~ + SourceLocation getAttrNameLoc() const { + return getLocalData()->AttrLoc; + } + void setAttrNameLoc(SourceLocation loc) { + getLocalData()->AttrLoc = loc; + } + + /// The attribute's expression operand, if it has one. + /// int * __attribute__((address_space(11))) + /// ^~ + Expr *getAttrExprOperand() const { + return getLocalData()->ExprOperand; + } + void setAttrExprOperand(Expr *e) { + getLocalData()->ExprOperand = e; + } + + /// The location of the parentheses around the operand, if there is + /// an operand. + /// int * __attribute__((address_space(11))) + /// ^ ^ + SourceRange getAttrOperandParensRange() const { + return getLocalData()->OperandParens; + } + void setAttrOperandParensRange(SourceRange range) { + getLocalData()->OperandParens = range; + } + + SourceRange getLocalSourceRange() const { + SourceRange range(getAttrNameLoc()); + range.setEnd(getAttrOperandParensRange().getEnd()); + return range; + } + + /// Returns the type before the address space attribute application + /// area. + /// int * __attribute__((address_space(11))) * + /// ^ ^ + QualType getInnerType() const { + return this->getTypePtr()->getPointeeType(); + } + + TypeLoc getPointeeTypeLoc() const { + return this->getInnerTypeLoc(); + } + + void initializeLocal(ASTContext &Context, SourceLocation loc) { + setAttrNameLoc(loc); + setAttrOperandParensRange(SourceRange(loc)); + setAttrExprOperand(getTypePtr()->getAddrSpaceExpr()); + } +}; + //===----------------------------------------------------------------------===// // // All of these need proper implementations. Index: include/clang/AST/TypeNodes.def =================================================================== --- include/clang/AST/TypeNodes.def +++ include/clang/AST/TypeNodes.def @@ -73,6 +73,7 @@ TYPE(VariableArray, ArrayType) DEPENDENT_TYPE(DependentSizedArray, ArrayType) DEPENDENT_TYPE(DependentSizedExtVector, Type) +DEPENDENT_TYPE(DependentAddressSpace, Type) TYPE(Vector, Type) TYPE(ExtVector, VectorType) ABSTRACT_TYPE(Function, Type) Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1369,6 +1369,8 @@ SourceRange Brackets, DeclarationName Entity); QualType BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc); + QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, + SourceLocation AttrLoc); bool CheckFunctionReturnType(QualType T, SourceLocation Loc); Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -937,7 +937,9 @@ /// \brief A DeducedTemplateSpecializationType record. TYPE_DEDUCED_TEMPLATE_SPECIALIZATION = 45, /// \brief A DependentSizedExtVectorType record. - TYPE_DEPENDENT_SIZED_EXT_VECTOR = 46 + TYPE_DEPENDENT_SIZED_EXT_VECTOR = 46, + /// \brief A DependentAddressSpaceType record. + TYPE_DEPENDENT_ADDRESS_SPACE = 47 }; /// \brief The type IDs for special types constructed by semantic Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -2302,6 +2302,27 @@ return getExtQualType(TypeNode, Quals); } +QualType ASTContext::removeAddrSpaceQualType(QualType T) const { + // If we are composing extended qualifiers together, merge together + // into one ExtQuals node. + QualifierCollector Quals; + const Type *TypeNode = Quals.strip(T); + + // If the qualifier doesn't have an address space just return it. + if (!Quals.hasAddressSpace()) + return T; + + Quals.removeAddressSpace(); + + // Removal of the address space can mean there are no longer any + // non-fast qualifiers, so creating an ExtQualType isn't possible (asserts) + // or required. + if (Quals.hasNonFastQualifiers()) + return getExtQualType(TypeNode, Quals); + else + return QualType(TypeNode, Quals.getFastQualifiers()); +} + QualType ASTContext::getObjCGCQualType(QualType T, Qualifiers::GC GCAttr) const { QualType CanT = getCanonicalType(T); @@ -2752,6 +2773,7 @@ case Type::Vector: case Type::ExtVector: case Type::DependentSizedExtVector: + case Type::DependentAddressSpace: case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: @@ -3100,6 +3122,41 @@ return QualType(New, 0); } +QualType ASTContext::getDependentAddressSpaceType(QualType PointeeType, + Expr *AddrSpaceExpr, + SourceLocation AttrLoc) const { + assert(AddrSpaceExpr->isInstantiationDependent()); + + QualType canonPointeeType = getCanonicalType(PointeeType); + + void *insertPos = nullptr; + llvm::FoldingSetNodeID ID; + DependentAddressSpaceType::Profile(ID, *this, canonPointeeType, + AddrSpaceExpr); + + DependentAddressSpaceType *canonTy = + DependentAddressSpaceTypes.FindNodeOrInsertPos(ID, insertPos); + + if (!canonTy) { + canonTy = new (*this, TypeAlignment) + DependentAddressSpaceType(*this, canonPointeeType, + QualType(), AddrSpaceExpr, AttrLoc); + DependentAddressSpaceTypes.InsertNode(canonTy, insertPos); + Types.push_back(canonTy); + } + + if (canonPointeeType == PointeeType && + canonTy->getAddrSpaceExpr() == AddrSpaceExpr) + return QualType(canonTy, 0); + + DependentAddressSpaceType *sugaredType + = new (*this, TypeAlignment) + DependentAddressSpaceType(*this, PointeeType, QualType(canonTy, 0), + AddrSpaceExpr, AttrLoc); + Types.push_back(sugaredType); + return QualType(sugaredType, 0); +} + /// \brief Determine whether \p T is canonical as the result type of a function. static bool isCanonicalResultType(QualType T) { return T.isCanonical() && Index: lib/AST/ASTStructuralEquivalence.cpp =================================================================== --- lib/AST/ASTStructuralEquivalence.cpp +++ lib/AST/ASTStructuralEquivalence.cpp @@ -365,6 +365,21 @@ break; } + case Type::DependentAddressSpace: { + const DependentAddressSpaceType *DepAddressSpace1 = + cast(T1); + const DependentAddressSpaceType *DepAddressSpace2 = + cast(T2); + if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getAddrSpaceExpr(), + DepAddressSpace2->getAddrSpaceExpr())) + return false; + if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getPointeeType(), + DepAddressSpace2->getPointeeType())) + return false; + + break; + } + case Type::DependentSizedExtVector: { const DependentSizedExtVectorType *Vec1 = cast(T1); Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -520,7 +520,7 @@ void mangleOperatorName(DeclarationName Name, unsigned Arity); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); void mangleVendorQualifier(StringRef qualifier); - void mangleQualifiers(Qualifiers Quals); + void mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST = nullptr); void mangleRefQualifier(RefQualifierKind RefQualifier); void mangleObjCMethodName(const ObjCMethodDecl *MD); @@ -1919,6 +1919,7 @@ case Type::IncompleteArray: case Type::VariableArray: case Type::DependentSizedArray: + case Type::DependentAddressSpace: case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: @@ -2190,10 +2191,17 @@ } } -void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { +void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST) { // Vendor qualifiers come first and if they are order-insensitive they must // be emitted in reversed alphabetical order, see Itanium ABI 5.1.5. + // ::= U + if (DAST) { + Out << "U2ASI"; + mangleExpression(DAST->getAddrSpaceExpr()); + Out << "E"; + } + // Address space qualifiers start with an ordinary letter. if (Quals.hasAddressSpace()) { // Address space extension: @@ -2389,11 +2397,19 @@ // substitution at the original type. } - if (quals) { - mangleQualifiers(quals); - // Recurse: even if the qualified type isn't yet substitutable, - // the unqualified type might be. - mangleType(QualType(ty, 0)); + if (quals || ty->isDependentAddressSpaceType()) { + if (const DependentAddressSpaceType *DAST = + dyn_cast(ty)) { + SplitQualType splitDAST = DAST->getPointeeType().split(); + mangleQualifiers(splitDAST.Quals, DAST); + mangleType(QualType(splitDAST.Ty, 0)); + } else { + mangleQualifiers(quals); + + // Recurse: even if the qualified type isn't yet substitutable, + // the unqualified type might be. + mangleType(QualType(ty, 0)); + } } else { switch (ty->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) @@ -3038,6 +3054,12 @@ mangleType(T->getElementType()); } +void CXXNameMangler::mangleType(const DependentAddressSpaceType *T) { + SplitQualType split = T->getPointeeType().split(); + mangleQualifiers(split.Quals, T); + mangleType(QualType(split.Ty, 0)); +} + void CXXNameMangler::mangleType(const PackExpansionType *T) { // ::= Dp # pack expansion (C++0x) Out << "Dp"; @@ -4201,7 +4223,13 @@ // get mangled if used as an rvalue of a known non-class type? assert(!parm->getType()->isArrayType() && "parameter's type is still an array type?"); - mangleQualifiers(parm->getType().getQualifiers()); + + if (const DependentAddressSpaceType *DAST = + dyn_cast(parm->getType())) { + mangleQualifiers(DAST->getPointeeType().getQualifiers(), DAST); + } else { + mangleQualifiers(parm->getType().getQualifiers()); + } // Parameter index. if (parmIndex != 0) { Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -2430,6 +2430,15 @@ << Range; } +void MicrosoftCXXNameMangler::mangleType(const DependentAddressSpaceType *T, + Qualifiers, SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, + "cannot mangle this dependent address space type yet"); + Diags.Report(Range.getBegin(), DiagID) << Range; +} + void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T, Qualifiers, SourceRange) { // ObjC interfaces have structs underlying them. Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -169,6 +169,26 @@ SizeExpr->Profile(ID, Context, true); } +DependentAddressSpaceType::DependentAddressSpaceType( + const ASTContext &Context, QualType PointeeType, QualType can, + Expr *AddrSpaceExpr, SourceLocation loc) + : Type(DependentAddressSpace, can, /*Dependent=*/true, + /*InstantiationDependent=*/true, + PointeeType->isVariablyModifiedType(), + (PointeeType->containsUnexpandedParameterPack() || + (AddrSpaceExpr && + AddrSpaceExpr->containsUnexpandedParameterPack()))), + Context(Context), AddrSpaceExpr(AddrSpaceExpr), PointeeType(PointeeType), + loc(loc) {} + +void DependentAddressSpaceType::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context, + QualType PointeeType, + Expr *AddrSpaceExpr) { + ID.AddPointer(PointeeType.getAsOpaquePtr()); + AddrSpaceExpr->Profile(ID, Context, true); +} + VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind) : VectorType(Vector, vecType, nElements, canonType, vecKind) {} @@ -3638,6 +3658,7 @@ case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: + case Type::DependentAddressSpace: case Type::FunctionProto: case Type::FunctionNoProto: case Type::Record: Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -222,6 +222,7 @@ case Type::LValueReference: case Type::RValueReference: case Type::MemberPointer: + case Type::DependentAddressSpace: case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: @@ -527,6 +528,19 @@ printAfter(T->getElementType(), OS); } +void TypePrinter::printDependentAddressSpaceBefore( + const DependentAddressSpaceType *T, raw_ostream &OS) { + printBefore(T->getPointeeType(), OS); +} +void TypePrinter::printDependentAddressSpaceAfter( + const DependentAddressSpaceType *T, raw_ostream &OS) { + OS << " __attribute__((address_space("; + if (T->getAddrSpaceExpr()) + T->getAddrSpaceExpr()->printPretty(OS, nullptr, Policy); + OS << ")))"; + printAfter(T->getPointeeType(), OS); +} + void TypePrinter::printDependentSizedExtVectorBefore( const DependentSizedExtVectorType *T, raw_ostream &OS) { Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -14345,7 +14345,9 @@ } // TR 18037 does not allow fields to be declared with address spaces. - if (T.getQualifiers().hasAddressSpace()) { + if (T.getQualifiers().hasAddressSpace() || + T->isDependentAddressSpaceType() || + T->getBaseElementTypeUnsafe()->isDependentAddressSpaceType()) { Diag(Loc, diag::err_field_with_address_space); D.setInvalidType(); } Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -5116,6 +5116,11 @@ return Visit(T->getElementType()); } +bool UnnamedLocalNoLinkageFinder::VisitDependentAddressSpaceType( + const DependentAddressSpaceType *T) { + return Visit(T->getPointeeType()); +} + bool UnnamedLocalNoLinkageFinder::VisitVectorType(const VectorType* T) { return Visit(T->getElementType()); } Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -1843,6 +1843,60 @@ return Sema::TDK_NonDeducedMismatch; } + // (clang extension) + // + // T __attribute__(((address_space(N)))) + case Type::DependentAddressSpace: { + const DependentAddressSpaceType *AddressSpaceParam = + cast(Param); + + if (const DependentAddressSpaceType *AddressSpaceArg = + dyn_cast(Arg)) { + // Perform deduction on the pointer type. + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, AddressSpaceParam->getPointeeType(), + AddressSpaceArg->getPointeeType(), Info, Deduced, TDF)) + return Result; + + // Perform deduction on the address space, if we can. + NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( + Info, AddressSpaceParam->getAddrSpaceExpr()); + if (!NTTP) + return Sema::TDK_Success; + + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, AddressSpaceArg->getAddrSpaceExpr(), Info, + Deduced); + } + + if (Arg.getAddressSpace() >= LangAS::FirstTargetAddressSpace) { + llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy), + false); + ArgAddressSpace = + (Arg.getAddressSpace() - LangAS::FirstTargetAddressSpace); + + // Perform deduction on the pointer types. + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, AddressSpaceParam->getPointeeType(), + S.Context.removeAddrSpaceQualType(Arg), Info, Deduced, TDF)) + return Result; + + // Perform deduction on the address space, if we can. + NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( + Info, AddressSpaceParam->getAddrSpaceExpr()); + if (!NTTP) + return Sema::TDK_Success; + + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + ArgAddressSpace, S.Context.IntTy, + true, Info, Deduced); + } + + return Sema::TDK_NonDeducedMismatch; + } + case Type::TypeOfExpr: case Type::TypeOf: case Type::DependentName: @@ -5227,6 +5281,17 @@ break; } + case Type::DependentAddressSpace: { + const DependentAddressSpaceType *DependentASType = + cast(T); + MarkUsedTemplateParameters(Ctx, DependentASType->getPointeeType(), + OnlyDeduced, Depth, Used); + MarkUsedTemplateParameters(Ctx, + DependentASType->getAddrSpaceExpr(), + OnlyDeduced, Depth, Used); + break; + } + case Type::FunctionProto: { const FunctionProtoType *Proto = cast(T); MarkUsedTemplateParameters(Ctx, Proto->getReturnType(), OnlyDeduced, Depth, Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5379,6 +5378,18 @@ ATL.setParensRange(SourceRange()); } +static void fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL, + const AttributeList *Attrs) { + while (Attrs && Attrs->getKind() != AttributeList::AT_AddressSpace) + Attrs = Attrs->getNext(); + + assert(Attrs && "no address_space attribute found at the expected location!"); + + DASTL.setAttrNameLoc(Attrs->getLoc()); + DASTL.setAttrExprOperand(Attrs->getArgAsExpr(0)); + DASTL.setAttrOperandParensRange(SourceRange()); +} + /// \brief Create and instantiate a TypeSourceInfo with type source information. /// /// \param T QualType referring to the type as written in source code. @@ -5401,6 +5412,13 @@ } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + + if (DependentAddressSpaceTypeLoc DASTL = + CurrTL.getAs()) { + fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs()); + CurrTL = DASTL.getPointeeTypeLoc().getUnqualifiedLoc(); + } + // An AtomicTypeLoc might be produced by an atomic qualifier in this // declarator chunk. if (AtomicTypeLoc ATL = CurrTL.getAs()) { @@ -5493,6 +5511,67 @@ // Type Attribute Processing //===----------------------------------------------------------------------===// +/// BuildAddressSpaceAttr - Builds a DependentAddressSpaceType if an expression +/// is uninstantiated. If instantiated it will apply the appropriate address space +/// to the type. This function allows dependent template variables to be used in +/// conjunction with the address_space attribute +QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, + SourceLocation AttrLoc) { + if (!AddrSpace->isValueDependent()) { + + // If this type is already address space qualified, reject it. + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified + // by qualifiers for two or more different address spaces." + if (T.getAddressSpace()) { + Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers); + return QualType(); + } + + llvm::APSInt addrSpace(32); + if (!AddrSpace->isIntegerConstantExpr(addrSpace, Context)) { + Diag(AttrLoc, diag::err_attribute_argument_type) + << "'address_space'" << AANT_ArgumentIntegerConstant + << AddrSpace->getSourceRange(); + return QualType(); + } + + // Bounds checking. + if (addrSpace.isSigned()) { + if (addrSpace.isNegative()) { + Diag(AttrLoc, diag::err_attribute_address_space_negative) + << AddrSpace->getSourceRange(); + return QualType(); + } + addrSpace.setIsSigned(false); + } + + llvm::APSInt max(addrSpace.getBitWidth()); + max = Qualifiers::MaxAddressSpace - LangAS::FirstTargetAddressSpace; + if (addrSpace > max) { + Diag(AttrLoc, diag::err_attribute_address_space_too_high) + << (unsigned)max.getZExtValue() << AddrSpace->getSourceRange(); + return QualType(); + } + + unsigned ASIdx = static_cast(addrSpace.getZExtValue()) + + LangAS::FirstTargetAddressSpace; + + return Context.getAddrSpaceQualType(T, ASIdx); + } + + // A check with similar intentions as checking if a type already has an + // address space except for on a dependent types, basically if the + // current type is already a DependentAddressSpaceType then its already + // lined up to have another address space on it and we can't have + // multiple address spaces on the one pointer indirection + if (T->getAs()) { + Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers); + return QualType(); + } + + return Context.getDependentAddressSpaceType(T, AddrSpace, AttrLoc); +} + /// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. @@ -5518,44 +5597,41 @@ unsigned ASIdx; if (Attr.getKind() == AttributeList::AT_AddressSpace) { + // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; - Attr.setInvalid(); - return; - } - Expr *ASArgExpr = static_cast(Attr.getArgAsExpr(0)); - llvm::APSInt addrSpace(32); - if (ASArgExpr->isTypeDependent() || ASArgExpr->isValueDependent() || - !ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant - << ASArgExpr->getSourceRange(); + << Attr.getName() << 1; Attr.setInvalid(); return; } - // Bounds checking. - if (addrSpace.isSigned()) { - if (addrSpace.isNegative()) { - S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative) - << ASArgExpr->getSourceRange(); - Attr.setInvalid(); + Expr *ASArgExpr; + if (Attr.isArgIdent(0)) { + // Special case where the argument is a template id. + CXXScopeSpec SS; + SourceLocation TemplateKWLoc; + UnqualifiedId id; + id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc()); + + ExprResult AddrSpace = S.ActOnIdExpression( + S.getCurScope(), SS, TemplateKWLoc, id, false, false); + if (AddrSpace.isInvalid()) return; - } - addrSpace.setIsSigned(false); + + ASArgExpr = static_cast(AddrSpace.get()); + } else { + ASArgExpr = static_cast(Attr.getArgAsExpr(0)); } - llvm::APSInt max(addrSpace.getBitWidth()); - max = Qualifiers::MaxAddressSpace - LangAS::FirstTargetAddressSpace; - if (addrSpace > max) { - S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high) - << (unsigned)max.getZExtValue() << ASArgExpr->getSourceRange(); + + // Create the DependentAddressSpaceType or append an address space onto + // the type. + QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc()); + + if (!T.isNull()) + Type = T; + else Attr.setInvalid(); - return; - } - ASIdx = static_cast(addrSpace.getZExtValue()) + - LangAS::FirstTargetAddressSpace; } else { // The keyword-based type attributes imply which address space to use. switch (Attr.getKind()) { @@ -5571,9 +5647,9 @@ assert(Attr.getKind() == AttributeList::AT_OpenCLPrivateAddressSpace); ASIdx = 0; break; } + + Type = S.Context.getAddrSpaceQualType(Type, ASIdx); } - - Type = S.Context.getAddrSpaceQualType(Type, ASIdx); } /// Does this type have a "direct" ownership qualifier? That is, Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -835,6 +835,18 @@ Expr *SizeExpr, SourceLocation AttributeLoc); + /// \brief Build a new DependentAddressSpaceType or return the pointee + /// type variable with the correct address space (retrieved from + /// AddrSpaceExpr) applied to it. The former will be returned in cases + /// where the address space remains dependent. + /// + /// By default, performs semantic analysis when building the type with address + /// space applied. Subclasses may override this routine to provide different + /// behavior. + QualType RebuildDependentAddressSpaceType(QualType PointeeType, + Expr *AddrSpaceExpr, + SourceLocation AttributeLoc); + /// \brief Build a new function type. /// /// By default, performs semantic analysis when building the function type. @@ -4785,7 +4797,53 @@ return Result; } -template +template +QualType TreeTransform::TransformDependentAddressSpaceType( + TypeLocBuilder &TLB, DependentAddressSpaceTypeLoc TL) { + const DependentAddressSpaceType *T = TL.getTypePtr(); + + QualType pointeeType = getDerived().TransformType(T->getPointeeType()); + + if (pointeeType.isNull()) + return QualType(); + + // Address spaces are constant expressions. + EnterExpressionEvaluationContext Unevaluated( + SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + ExprResult AddrSpace = getDerived().TransformExpr(T->getAddrSpaceExpr()); + AddrSpace = SemaRef.ActOnConstantExpression(AddrSpace); + if (AddrSpace.isInvalid()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || pointeeType != T->getPointeeType() || + AddrSpace.get() != T->getAddrSpaceExpr()) { + Result = getDerived().RebuildDependentAddressSpaceType( + pointeeType, AddrSpace.get(), T->getAttributeLoc()); + if (Result.isNull()) + return QualType(); + } + + // Result might be dependent or not. + if (isa(Result)) { + DependentAddressSpaceTypeLoc NewTL = + TLB.push(Result); + + NewTL.setAttrOperandParensRange(TL.getAttrOperandParensRange()); + NewTL.setAttrExprOperand(TL.getAttrExprOperand()); + NewTL.setAttrNameLoc(TL.getAttrNameLoc()); + + } else { + TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo( + Result, getDerived().getBaseLocation()); + TransformType(TLB, DI->getTypeLoc()); + } + + return Result; +} + +template QualType TreeTransform::TransformVectorType(TypeLocBuilder &TLB, VectorTypeLoc TL) { const VectorType *T = TL.getTypePtr(); @@ -12314,10 +12372,18 @@ IndexTypeQuals, BracketsRange); } -template -QualType TreeTransform::RebuildVectorType(QualType ElementType, - unsigned NumElements, - VectorType::VectorKind VecKind) { +template +QualType TreeTransform::RebuildDependentAddressSpaceType( + QualType PointeeType, Expr *AddrSpaceExpr, SourceLocation AttributeLoc) { + return SemaRef.BuildAddressSpaceAttr(PointeeType, AddrSpaceExpr, + AttributeLoc); +} + +template +QualType +TreeTransform::RebuildVectorType(QualType ElementType, + unsigned NumElements, + VectorType::VectorKind VecKind) { // FIXME: semantic checking! return SemaRef.Context.getVectorType(ElementType, NumElements, VecKind); } Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6264,6 +6264,18 @@ return Context.getDependentSizedExtVectorType(ElementType, SizeExpr, AttrLoc); } + + case TYPE_DEPENDENT_ADDRESS_SPACE: { + unsigned Idx = 0; + + // DependentAddressSpaceType + QualType PointeeType = readType(*Loc.F, Record, Idx); + Expr *AddrSpaceExpr = ReadExpr(*Loc.F); + SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx); + + return Context.getDependentAddressSpaceType(PointeeType, AddrSpaceExpr, + AttrLoc); + } } llvm_unreachable("Invalid TypeCode!"); } @@ -6397,6 +6409,17 @@ VisitArrayTypeLoc(TL); } +void TypeLocReader::VisitDependentAddressSpaceTypeLoc( + DependentAddressSpaceTypeLoc TL) { + + TL.setAttrNameLoc(ReadSourceLocation()); + SourceRange range; + range.setBegin(ReadSourceLocation()); + range.setEnd(ReadSourceLocation()); + TL.setAttrOperandParensRange(range); + TL.setAttrExprOperand(Reader->ReadExpr(*F)); +} + void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( DependentSizedExtVectorTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -433,6 +433,15 @@ Code = TYPE_DEPENDENT_SIZED_EXT_VECTOR; } +void +ASTTypeWriter::VisitDependentAddressSpaceType( + const DependentAddressSpaceType *T) { + Record.AddTypeRef(T->getPointeeType()); + Record.AddStmt(T->getAddrSpaceExpr()); + Record.AddSourceLocation(T->getAttributeLoc()); + Code = TYPE_DEPENDENT_ADDRESS_SPACE; +} + void ASTTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) { Record.push_back(T->getDepth()); @@ -627,6 +636,15 @@ VisitArrayTypeLoc(TL); } +void TypeLocWriter::VisitDependentAddressSpaceTypeLoc( + DependentAddressSpaceTypeLoc TL) { + Record.AddSourceLocation(TL.getAttrNameLoc()); + SourceRange range = TL.getAttrOperandParensRange(); + Record.AddSourceLocation(range.getBegin()); + Record.AddSourceLocation(range.getEnd()); + Record.AddStmt(TL.getAttrExprOperand()); +} + void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc( DependentSizedExtVectorTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); Index: test/Sema/address_space-dependent.cpp =================================================================== --- /dev/null +++ test/Sema/address_space-dependent.cpp @@ -0,0 +1,102 @@ +// RUN: %clang_cc1 -x c++ -std=c++14 -fsyntax-only -verify %s + +template +void car() { + int __attribute__((address_space(I))) __attribute__((address_space(J))) * Y; // expected-error {{multiple address spaces specified for type}} + int *__attribute__((address_space(I))) __attribute__((address_space(J))) * Z; // expected-error {{multiple address spaces specified for type}} + + __attribute__((address_space(I))) int local; // expected-error {{automatic variable qualified with an address space}} + __attribute__((address_space(J))) int array[5]; // expected-error {{automatic variable qualified with an address space}} + __attribute__((address_space(I))) int arrarr[5][5]; // expected-error {{automatic variable qualified with an address space}} + + __attribute__((address_space(J))) * x; // expected-error {{C++ requires a type specifier for all declarations}} + + __attribute__((address_space(I))) float *B; + + typedef __attribute__((address_space(J))) int AS2Int; + struct HasASFields { + AS2Int typedef_as_field; // expected-error {{field may not be qualified with an address space}} + }; + + struct _st { + int x, y; + } s __attribute((address_space(I))) = {1, 1}; +} + +template +struct HasASTemplateFields { + __attribute__((address_space(I))) int as_field; // expected-error {{field may not be qualified with an address space}} +}; + +template +void foo(__attribute__((address_space(I))) float *a, // expected-note {{candidate template ignored: substitution failure [with I = 1, J = 2]: parameter may not be qualified with an address space}} + __attribute__((address_space(J))) float b) { + *a = 5.0f + b; +} + +template void foo<1, 2>(float *, float); // expected-error {{explicit instantiation of 'foo' does not refer to a function template, variable template, member function, member class, or static data member}} + +template +void neg() { + __attribute__((address_space(I))) int *bounds; // expected-error {{address space is negative}} +} + +template +void toBig() { + __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388599)}} +} + +template +void correct() { + __attribute__((address_space(I))) int *bounds; +} + +template +char *cmp(__attribute__((address_space(I))) char *x, __attribute__((address_space(J))) char *y) { + return x < y ? x : y; // expected-error {{comparison of distinct pointer types ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *')}} +} + +typedef void ft(void); + +template +struct fooFunction { + __attribute__((address_space(I))) void **const base = 0; + + void *get_0(void) { + return base[0]; // expected-error {{cannot initialize return object of type 'void *' with an lvalue of type '__attribute__((address_space(1))) void *}} + } + + __attribute__((address_space(I))) ft qf; // expected-error {{function type may not be qualified with an address space}} + __attribute__((address_space(I))) char *test3_val; + + void test3(void) { + extern void test3_helper(char *p); // expected-note {{passing argument to parameter 'p' here}} + test3_helper(test3_val); // expected-error {{cannot initialize a parameter of type 'char *' with an lvalue of type '__attribute__((address_space(1))) char *'}} + } +}; + +template +int GetAddressSpaceValue(T __attribute__((address_space(N))) * p) { + return N; +} + +int main() { + int __attribute__((address_space(1))) * p1; + int p = GetAddressSpaceValue(p1); + + car<1, 2, 3>(); // expected-note {{in instantiation of function template specialization 'car<1, 2, 3>' requested here}} + HasASTemplateFields<1> HASTF; + neg<-1>(); // expected-note {{in instantiation of function template specialization 'neg<-1>' requested here}} + correct<0x7FFFF7>(); + toBig<4294967500>(); // expected-note {{in instantiation of function template specialization 'toBig<4294967500>' requested here}} + + __attribute__((address_space(1))) char *x; + __attribute__((address_space(2))) char *y; + cmp<1, 2>(x, y); // expected-note {{in instantiation of function template specialization 'cmp<1, 2>' requested here}} + + fooFunction<1> ff; + ff.get_0(); // expected-note {{in instantiation of member function 'fooFunction<1>::get_0' requested here}} + ff.qf(); + ff.test3(); // expected-note {{in instantiation of member function 'fooFunction<1>::test3' requested here}} + return 0; +} Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -1742,6 +1742,7 @@ DEFAULT_TYPELOC_IMPL(IncompleteArray, ArrayType) DEFAULT_TYPELOC_IMPL(VariableArray, ArrayType) DEFAULT_TYPELOC_IMPL(DependentSizedArray, ArrayType) +DEFAULT_TYPELOC_IMPL(DependentAddressSpace, Type) DEFAULT_TYPELOC_IMPL(DependentSizedExtVector, Type) DEFAULT_TYPELOC_IMPL(Vector, Type) DEFAULT_TYPELOC_IMPL(ExtVector, VectorType)