Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -1405,6 +1405,10 @@ QualType BuildVectorType(QualType T, Expr *VecSize, SourceLocation AttrLoc); QualType BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc); + QualType BuildAddressSpaceAttr(QualType &T, LangAS ASIdx, Expr *AddrSpace, + SourceLocation AttrLoc); + + /// Same as above, but constructs the AddressSpace index if not provided. QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, SourceLocation AttrLoc); Index: clang/lib/AST/TypePrinter.cpp =================================================================== --- clang/lib/AST/TypePrinter.cpp +++ clang/lib/AST/TypePrinter.cpp @@ -249,11 +249,17 @@ case Type::FunctionProto: case Type::FunctionNoProto: case Type::Paren: - case Type::Attributed: case Type::PackExpansion: case Type::SubstTemplateTypeParm: CanPrefixQualifiers = false; break; + + case Type::Attributed: { + // We still want to print the address_space before the type if it is an + // address_space attribute. + const auto *AttrTy = cast(T); + CanPrefixQualifiers = AttrTy->getAttrKind() == attr::AddressSpace; + } } return CanPrefixQualifiers; Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -5740,28 +5740,27 @@ // 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) { +/// Build an AddressSpace index from a constant expression and diagnose any +/// errors related to invalid address_spaces. Returns true on successfully +/// building an AddressSpace index. +static bool BuildAddressSpaceIndex(Sema &S, LangAS &ASIdx, + const Expr *AddrSpace, + SourceLocation AttrLoc) { if (!AddrSpace->isValueDependent()) { - llvm::APSInt addrSpace(32); - if (!AddrSpace->isIntegerConstantExpr(addrSpace, Context)) { - Diag(AttrLoc, diag::err_attribute_argument_type) + if (!AddrSpace->isIntegerConstantExpr(addrSpace, S.Context)) { + S.Diag(AttrLoc, diag::err_attribute_argument_type) << "'address_space'" << AANT_ArgumentIntegerConstant << AddrSpace->getSourceRange(); - return QualType(); + return false; } // Bounds checking. if (addrSpace.isSigned()) { if (addrSpace.isNegative()) { - Diag(AttrLoc, diag::err_attribute_address_space_negative) + S.Diag(AttrLoc, diag::err_attribute_address_space_negative) << AddrSpace->getSourceRange(); - return QualType(); + return false; } addrSpace.setIsSigned(false); } @@ -5770,14 +5769,28 @@ max = Qualifiers::MaxAddressSpace - (unsigned)LangAS::FirstTargetAddressSpace; if (addrSpace > max) { - Diag(AttrLoc, diag::err_attribute_address_space_too_high) + S.Diag(AttrLoc, diag::err_attribute_address_space_too_high) << (unsigned)max.getZExtValue() << AddrSpace->getSourceRange(); - return QualType(); + return false; } - LangAS ASIdx = + ASIdx = getLangASFromTargetAS(static_cast(addrSpace.getZExtValue())); + return true; + } + // Default value for DependentAddressSpaceTypes + ASIdx = LangAS::Default; + return true; +} + +/// 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, LangAS ASIdx, Expr *AddrSpace, + SourceLocation AttrLoc) { + if (!AddrSpace->isValueDependent()) { // If this type is already address space qualified with a different // address space, reject it. // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified @@ -5808,6 +5821,14 @@ return Context.getDependentAddressSpaceType(T, AddrSpace, AttrLoc); } +QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, + SourceLocation AttrLoc) { + LangAS ASIdx; + if (!BuildAddressSpaceIndex(*this, ASIdx, AddrSpace, AttrLoc)) + return QualType(); + return BuildAddressSpaceAttr(T, ASIdx, 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. @@ -5853,19 +5874,26 @@ 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()) { - ASTContext &Ctx = S.Context; - auto *ASAttr = ::new (Ctx) AddressSpaceAttr( - Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), - static_cast(T.getQualifiers().getAddressSpace())); - Type = State.getAttributedType(ASAttr, T, T); - } else { + LangAS ASIdx; + if (!BuildAddressSpaceIndex(S, ASIdx, ASArgExpr, Attr.getLoc())) { Attr.setInvalid(); + return; } + + ASTContext &Ctx = S.Context; + auto *ASAttr = ::new (Ctx) AddressSpaceAttr( + Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), + static_cast(ASIdx)); + QualType T = State.getAttributedType(ASAttr, Type, Type); + + // Create the DependentAddressSpaceType or append an address space onto + // the attributed type. + T = S.BuildAddressSpaceAttr(T, ASIdx, 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()) { @@ -7326,9 +7354,11 @@ if (!IsTypeAttr) continue; } - } else if (TAL != TAL_DeclChunk) { + } else if (TAL != TAL_DeclChunk && + attr.getKind() != ParsedAttr::AT_AddressSpace) { // Otherwise, only consider type processing for a C++11 attribute if // it's actually been applied to a type. + // We also allow C++11 address_space attributes to pass through. continue; } } Index: clang/test/AST/address_space_attribute.cpp =================================================================== --- /dev/null +++ clang/test/AST/address_space_attribute.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 %s -ast-dump | FileCheck %s + +// Veryify the ordering of the address_space attribute still comes before the +// type whereas other attributes are still printed after. + +template +void func() { + // CHECK: VarDecl {{.*}} x '__attribute__((address_space(1))) int *' + __attribute__((address_space(1))) int *x; + + // CHECK: VarDecl {{.*}} a 'int * __attribute__((noderef))' + int __attribute__((noderef)) * a; + + // CHECK: VarDecl {{.*}} y '__attribute__((address_space(2))) int *' + __attribute__((address_space(I))) int *y; + + // CHECK: VarDecl {{.*}} z '__attribute__((address_space(3))) int *' + [[clang::address_space(3)]] int *z; +} + +void func2() { + func<2>(); +} Index: clang/tools/libclang/CXType.cpp =================================================================== --- clang/tools/libclang/CXType.cpp +++ clang/tools/libclang/CXType.cpp @@ -126,10 +126,15 @@ CXTypeKind TK = CXType_Invalid; if (TU && !T.isNull()) { + ASTContext &Ctx = cxtu::getASTUnit(TU)->getASTContext(); + // Handle attributed types as the original type if (auto *ATT = T->getAs()) { if (!(TU->ParsingOptions & CXTranslationUnit_IncludeAttributedTypes)) { - return MakeCXType(ATT->getModifiedType(), TU); + QualType ResultTy = ATT->getModifiedType(); + if (ATT->getAttrKind() == attr::AddressSpace) + ResultTy = Ctx.getAddrSpaceQualType(ResultTy, T.getAddressSpace()); + return MakeCXType(ResultTy, TU); } } // Handle paren types as the original type @@ -137,7 +142,6 @@ return MakeCXType(PTT->getInnerType(), TU); } - ASTContext &Ctx = cxtu::getASTUnit(TU)->getASTContext(); if (Ctx.getLangOpts().ObjC) { QualType UnqualT = T.getUnqualifiedType(); if (Ctx.isObjCIdType(UnqualT))