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,12 @@ TRY_TO(TraverseStmt(T->getSizeExpr())); }) +DEF_TRAVERSE_TYPE(DependentAddressSpaceType, { + if (T->getAddrSpaceExpr()) + TRY_TO(TraverseStmt(T->getAddrSpaceExpr())); + TRY_TO(TraverseType(T->getPointeeType())); +}) + DEF_TRAVERSE_TYPE(DependentSizedExtVectorType, { if (T->getSizeExpr()) TRY_TO(TraverseStmt(T->getSizeExpr())); @@ -1199,6 +1205,14 @@ return TraverseArrayTypeLocHelper(TL); }) +// Based on DependentSizedExtVectorType, so any fixes it requires should +// be considered here as well +DEF_TRAVERSE_TYPELOC(DependentAddressSpaceType, { + if (TL.getTypePtr()->getAddrSpaceExpr()) + 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. This in essence is a wrapper class that is thrown away +/// for the underlying type when the real value can be substituted in. +/// +/// 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,71 @@ } }; +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 getPointeeType() const { + return getTypePtr()->getPointeeType(); + } + + 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,30 @@ 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; + + // The idea is just to remove the address space, if removeAddrSpaceQualType + // removes any + // other qualifiers then the implementation is incorrect and requires fixing. + 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 +2776,7 @@ case Type::Vector: case Type::ExtVector: case Type::DependentSizedExtVector: + case Type::DependentAddressSpace: case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: @@ -3100,6 +3125,46 @@ return QualType(New, 0); } +QualType ASTContext::getDependentAddressSpaceType( + QualType PointeeType, Expr *AddrSpaceExpr, SourceLocation AttrLoc) const { + llvm::FoldingSetNodeID ID; + QualType CanonASTy = getCanonicalType(PointeeType); + DependentAddressSpaceType::Profile( + ID, *this, CanonASTy, AddrSpaceExpr); + + void *InsertPos = nullptr; + DependentAddressSpaceType *Canon = + DependentAddressSpaceTypes.FindNodeOrInsertPos(ID, InsertPos); + DependentAddressSpaceType *New; + if (Canon) { + // We already have a canonical version of this type; use it as + // the canonical type for a newly-built type. + New = new (*this, TypeAlignment) DependentAddressSpaceType( + *this, PointeeType, QualType(Canon, 0), AddrSpaceExpr, AttrLoc); + } else { + + if (CanonASTy == PointeeType) { + New = new (*this, TypeAlignment) DependentAddressSpaceType( + *this, PointeeType, QualType(), AddrSpaceExpr, AttrLoc); + + DependentAddressSpaceType *CanonCheck = + DependentAddressSpaceTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CanonCheck && + "Dependent address_space canonical type broken"); + (void)CanonCheck; + DependentAddressSpaceTypes.InsertNode(New, InsertPos); + } else { + QualType Canon = getDependentAddressSpaceType(CanonASTy, AddrSpaceExpr, + SourceLocation()); + New = new (*this, TypeAlignment) DependentAddressSpaceType( + *this, PointeeType, Canon, AddrSpaceExpr, AttrLoc); + } + } + + Types.push_back(New); + return QualType(New, 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: @@ -3038,6 +3046,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"; 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,11 @@ } // TR 18037 does not allow fields to be declared with address spaces. - if (T.getQualifiers().hasAddressSpace()) { + if (T.getQualifiers().hasAddressSpace() || + isa(T) || + isa(T.getCanonicalType()) || + (T->isArrayType() && + T->getPointeeOrArrayElementType()->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 @@ -5401,6 +5401,14 @@ } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + + if (const DependentAddressSpaceType *DAST = + CurrTL.getType()->getAs()) { + TypeSourceInfo *InternalTInfo = + Context.CreateTypeSourceInfo(DAST->getPointeeType()); + CurrTL = InternalTInfo->getTypeLoc().getUnqualifiedLoc(); + } + // An AtomicTypeLoc might be produced by an atomic qualifier in this // declarator chunk. if (AtomicTypeLoc ATL = CurrTL.getAs()) { @@ -5489,10 +5497,149 @@ return CreateParsedType(T, TInfo); } -//===----------------------------------------------------------------------===// -// 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() && + !AddrSpace->isInstantiationDependent()) { + + // 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. +static void HandleAddressSpaceTypeAttribute(QualType &Type, + const AttributeList &Attr, Sema &S){ + + // 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 (Type.getAddressSpace()) { + S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); + Attr.setInvalid(); + return; + } + + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "A function type shall not be + // qualified by an address-space qualifier." + if (Type->isFunctionType()) { + S.Diag(Attr.getLoc(), diag::err_attribute_address_function_type); + Attr.setInvalid(); + return; + } + + 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; + 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; + + ASArgExpr = static_cast(AddrSpace.get()); + } else { + ASArgExpr = static_cast(Attr.getArgAsExpr(0)); + } + + // 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(); + } else { + // The keyword-based type attributes imply which address space to use. + switch (Attr.getKind()) { + case AttributeList::AT_OpenCLGlobalAddressSpace: + ASIdx = LangAS::opencl_global; break; + case AttributeList::AT_OpenCLLocalAddressSpace: + ASIdx = LangAS::opencl_local; break; + case AttributeList::AT_OpenCLConstantAddressSpace: + ASIdx = LangAS::opencl_constant; break; + case AttributeList::AT_OpenCLGenericAddressSpace: + ASIdx = LangAS::opencl_generic; break; + default: + assert(Attr.getKind() == AttributeList::AT_OpenCLPrivateAddressSpace); + ASIdx = 0; break; + } + + Type = S.Context.getAddrSpaceQualType(Type, ASIdx); + } +} +/* /// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. @@ -5575,7 +5722,7 @@ Type = S.Context.getAddrSpaceQualType(Type, ASIdx); } - +*/ /// Does this type have a "direct" ownership qualifier? That is, /// is it written like "__strong id", as opposed to something like /// "typeof(foo)", where that happens to be strong? 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)