From d27ee8f21eebc00294112a46121537238cdda59f Mon Sep 17 00:00:00 2001 From: Andrew Gozillon Date: Mon, 2 Oct 2017 06:25:51 +0000 Subject: [PATCH] Dependent Address Space Support This patch relates to: https://reviews.llvm.org/D33666 This adds support for template parameters to be passed to the address_space attribute. The main goal is to add further flexibility to the attribute and allow for it to be used easily with templates. The main additions are a new type (DependentAddressSpaceType) alongside its TypeLoc and its mangling. As well as the logic required to support dependent address spaces which mainly resides in TreeTransform.h and SemaType.cpp. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@314649 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 13 ++ include/clang/AST/RecursiveASTVisitor.h | 10 ++ include/clang/AST/Type.h | 47 ++++++++ include/clang/AST/TypeLoc.h | 70 +++++++++++ include/clang/AST/TypeNodes.def | 1 + include/clang/Sema/Sema.h | 2 + include/clang/Serialization/ASTBitCodes.h | 4 +- lib/AST/ASTContext.cpp | 57 +++++++++ lib/AST/ASTStructuralEquivalence.cpp | 15 +++ lib/AST/ItaniumMangle.cpp | 44 +++++-- lib/AST/MicrosoftMangle.cpp | 9 ++ lib/AST/Type.cpp | 21 ++++ lib/AST/TypePrinter.cpp | 14 +++ lib/Sema/SemaDecl.cpp | 4 +- lib/Sema/SemaTemplate.cpp | 5 + lib/Sema/SemaTemplateDeduction.cpp | 65 ++++++++++ lib/Sema/SemaType.cpp | 137 +++++++++++++++++----- lib/Sema/TreeTransform.h | 76 +++++++++++- lib/Serialization/ASTReader.cpp | 23 ++++ lib/Serialization/ASTWriter.cpp | 18 +++ tools/libclang/CIndex.cpp | 1 + 21 files changed, 591 insertions(+), 45 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index eadd69c595..7bb0e60a12 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -143,6 +143,8 @@ class ASTContext : public RefCountedBase { 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 @@ public: /// 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 @@ public: 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; diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 5baf23caa5..7459504703 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -988,6 +988,11 @@ DEF_TRAVERSE_TYPE(DependentSizedArrayType, { 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())); @@ -1198,6 +1203,11 @@ DEF_TRAVERSE_TYPELOC(DependentSizedArrayType, { 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, { diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 98ab767ca0..52a1ff8bd2 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1705,6 +1705,7 @@ public: 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 @@ public: 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. /// @@ -5791,6 +5835,9 @@ inline bool Type::isVectorType() const { inline bool Type::isExtVectorType() const { return isa(CanonicalType); } +inline bool Type::isDependentAddressSpaceType() const { + return isa(CanonicalType); +} inline bool Type::isObjCObjectPointerType() const { return isa(CanonicalType); } diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index ad95f6f8ef..283c421425 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -1664,6 +1664,76 @@ private: } }; +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. diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 3ee9202b52..66697fa0d0 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -73,6 +73,7 @@ TYPE(IncompleteArray, ArrayType) 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) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 754b6c17c1..80b6978b92 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1378,6 +1378,8 @@ public: 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); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 5ecba87aa3..42c62257ad 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -940,7 +940,9 @@ namespace clang { /// \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 diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 2a60799653..a657eed2fb 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2302,6 +2302,27 @@ ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) const { 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 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { 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 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType, 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() && diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp index ea7faab767..0df8e5653f 100644 --- a/lib/AST/ASTStructuralEquivalence.cpp +++ b/lib/AST/ASTStructuralEquivalence.cpp @@ -365,6 +365,21 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, 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); diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 8c5ebd0113..9ebde498ac 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -520,7 +520,7 @@ private: 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); @@ -1930,6 +1930,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::IncompleteArray: case Type::VariableArray: case Type::DependentSizedArray: + case Type::DependentAddressSpace: case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: @@ -2201,10 +2202,17 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { } } -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: @@ -2400,11 +2408,19 @@ void CXXNameMangler::mangleType(QualType T) { // 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) @@ -3052,6 +3068,12 @@ void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) { 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"; @@ -4215,7 +4237,13 @@ void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) { // 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) { diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 685dc62296..c8048544ab 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -2430,6 +2430,15 @@ void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T, << 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. diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index bf49dfd8de..cc5a00b584 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -169,6 +169,26 @@ DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID, 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) {} @@ -3651,6 +3671,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: + case Type::DependentAddressSpace: case Type::FunctionProto: case Type::FunctionNoProto: case Type::Record: diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 1f5b483489..97cb3f90c7 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -222,6 +222,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, 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 @@ void TypePrinter::printDependentSizedArrayAfter( 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) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 57f78cc03b..fa781194f3 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -14345,7 +14345,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, } // 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(); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 050e18944a..c621ba1323 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -5125,6 +5125,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDependentSizedExtVectorType( return Visit(T->getElementType()); } +bool UnnamedLocalNoLinkageFinder::VisitDependentAddressSpaceType( + const DependentAddressSpaceType *T) { + return Visit(T->getPointeeType()); +} + bool UnnamedLocalNoLinkageFinder::VisitVectorType(const VectorType* T) { return Visit(T->getElementType()); } diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 0dcf52aec5..a4f7e8d791 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1843,6 +1843,60 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, 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 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, 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, diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 556f1ed763..fb3f41ec0f 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -5487,6 +5487,18 @@ static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) { 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. @@ -5509,6 +5521,13 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, } 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()) { @@ -5601,6 +5620,67 @@ ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) { // 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. @@ -5625,44 +5705,41 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, 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()) { @@ -5678,9 +5755,9 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, 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, diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 6fb9eca9a9..a9ecf721db 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -835,6 +835,18 @@ public: 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 @@ QualType TreeTransform::TransformDependentSizedExtVectorType( 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(); @@ -12313,10 +12371,18 @@ TreeTransform::RebuildDependentSizedArrayType(QualType ElementType, 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); } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 7d745447a8..4ac8aa3855 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -6269,6 +6269,18 @@ QualType ASTReader::readTypeRecord(unsigned Index) { 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!"); } @@ -6402,6 +6414,17 @@ void TypeLocReader::VisitDependentSizedArrayTypeLoc( 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()); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 4c22067b83..166db2c1af 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -433,6 +433,15 @@ ASTTypeWriter::VisitDependentSizedExtVectorType( 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 @@ void TypeLocWriter::VisitDependentSizedArrayTypeLoc( 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()); diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 26b1f5e2b1..3921c055b8 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1742,6 +1742,7 @@ DEFAULT_TYPELOC_IMPL(ConstantArray, ArrayType) 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) -- 2.40.0