https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/115777
>From 23a8d5af0ab181814885bca6ab6494be9d71f59b Mon Sep 17 00:00:00 2001 From: Joseph Huber <hube...@outlook.com> Date: Wed, 13 Nov 2024 18:14:05 -0600 Subject: [PATCH 1/3] use ASTContext --- .../bugprone/VirtualNearMissCheck.cpp | 2 +- .../SuspiciousCallArgumentCheck.cpp | 33 +++-- clang/include/clang/AST/CanonicalType.h | 9 +- clang/include/clang/AST/Type.h | 59 +++----- clang/include/clang/Basic/TargetInfo.h | 7 + clang/lib/AST/ASTContext.cpp | 2 +- clang/lib/AST/Type.cpp | 32 ++++ clang/lib/Basic/Targets/AMDGPU.h | 12 ++ clang/lib/Basic/Targets/NVPTX.h | 56 ++++--- clang/lib/Sema/SemaARM.cpp | 2 +- clang/lib/Sema/SemaCast.cpp | 19 ++- clang/lib/Sema/SemaCodeComplete.cpp | 10 +- clang/lib/Sema/SemaDeclCXX.cpp | 2 +- clang/lib/Sema/SemaExceptionSpec.cpp | 6 +- clang/lib/Sema/SemaExpr.cpp | 24 +-- clang/lib/Sema/SemaExprCXX.cpp | 9 +- clang/lib/Sema/SemaFixItUtils.cpp | 6 +- clang/lib/Sema/SemaInit.cpp | 19 +-- clang/lib/Sema/SemaObjC.cpp | 2 +- clang/lib/Sema/SemaOpenMP.cpp | 8 +- clang/lib/Sema/SemaOverload.cpp | 48 +++--- clang/lib/Sema/SemaTemplateDeduction.cpp | 5 +- clang/test/CodeGen/target-addrspace.cpp | 140 ++++++++++++++++++ clang/test/Sema/amdgcn-address-spaces.c | 20 +++ clang/test/Sema/nvptx-address-spaces.c | 21 +++ 25 files changed, 401 insertions(+), 152 deletions(-) create mode 100644 clang/test/CodeGen/target-addrspace.cpp create mode 100644 clang/test/Sema/amdgcn-address-spaces.c create mode 100644 clang/test/Sema/nvptx-address-spaces.c diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp index bebdce525e2887..76fa2d916f0e86 100644 --- a/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp @@ -112,7 +112,7 @@ static bool checkOverridingFunctionReturnType(const ASTContext *Context, // The class type D should have the same cv-qualification as or less // cv-qualification than the class type B. - if (DTy.isMoreQualifiedThan(BTy)) + if (DTy.isMoreQualifiedThan(BTy, *Context)) return false; return true; diff --git a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp index 18420d0c8488d2..c5eaff88e0ed3b 100644 --- a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp @@ -299,10 +299,11 @@ static bool applyDiceHeuristic(StringRef Arg, StringRef Param, /// Checks if ArgType binds to ParamType regarding reference-ness and /// cv-qualifiers. -static bool areRefAndQualCompatible(QualType ArgType, QualType ParamType) { +static bool areRefAndQualCompatible(QualType ArgType, QualType ParamType, + const ASTContext &Ctx) { return !ParamType->isReferenceType() || ParamType.getNonReferenceType().isAtLeastAsQualifiedAs( - ArgType.getNonReferenceType()); + ArgType.getNonReferenceType(), Ctx); } static bool isPointerOrArray(QualType TypeToCheck) { @@ -311,12 +312,12 @@ static bool isPointerOrArray(QualType TypeToCheck) { /// Checks whether ArgType is an array type identical to ParamType's array type. /// Enforces array elements' qualifier compatibility as well. -static bool isCompatibleWithArrayReference(QualType ArgType, - QualType ParamType) { +static bool isCompatibleWithArrayReference(QualType ArgType, QualType ParamType, + const ASTContext &Ctx) { if (!ArgType->isArrayType()) return false; // Here, qualifiers belong to the elements of the arrays. - if (!ParamType.isAtLeastAsQualifiedAs(ArgType)) + if (!ParamType.isAtLeastAsQualifiedAs(ArgType, Ctx)) return false; return ParamType.getUnqualifiedType() == ArgType.getUnqualifiedType(); @@ -342,12 +343,13 @@ static QualType convertToPointeeOrArrayElementQualType(QualType TypeToConvert) { /// every * in ParamType to the right of that cv-qualifier, except the last /// one, must also be const-qualified. static bool arePointersStillQualCompatible(QualType ArgType, QualType ParamType, - bool &IsParamContinuouslyConst) { + bool &IsParamContinuouslyConst, + const ASTContext &Ctx) { // The types are compatible, if the parameter is at least as qualified as the // argument, and if it is more qualified, it has to be const on upper pointer // levels. bool AreTypesQualCompatible = - ParamType.isAtLeastAsQualifiedAs(ArgType) && + ParamType.isAtLeastAsQualifiedAs(ArgType, Ctx) && (!ParamType.hasQualifiers() || IsParamContinuouslyConst); // Check whether the parameter's constness continues at the current pointer // level. @@ -359,9 +361,10 @@ static bool arePointersStillQualCompatible(QualType ArgType, QualType ParamType, /// Checks whether multilevel pointers are compatible in terms of levels, /// qualifiers and pointee type. static bool arePointerTypesCompatible(QualType ArgType, QualType ParamType, - bool IsParamContinuouslyConst) { + bool IsParamContinuouslyConst, + const ASTContext &Ctx) { if (!arePointersStillQualCompatible(ArgType, ParamType, - IsParamContinuouslyConst)) + IsParamContinuouslyConst, Ctx)) return false; do { @@ -372,7 +375,7 @@ static bool arePointerTypesCompatible(QualType ArgType, QualType ParamType, // Check whether cv-qualifiers permit compatibility on // current level. if (!arePointersStillQualCompatible(ArgType, ParamType, - IsParamContinuouslyConst)) + IsParamContinuouslyConst, Ctx)) return false; if (ParamType.getUnqualifiedType() == ArgType.getUnqualifiedType()) @@ -396,7 +399,7 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType, return true; // Check for constness and reference compatibility. - if (!areRefAndQualCompatible(ArgType, ParamType)) + if (!areRefAndQualCompatible(ArgType, ParamType, Ctx)) return false; bool IsParamReference = ParamType->isReferenceType(); @@ -434,7 +437,7 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType, // When ParamType is an array reference, ArgType has to be of the same-sized // array-type with cv-compatible element type. if (IsParamReference && ParamType->isArrayType()) - return isCompatibleWithArrayReference(ArgType, ParamType); + return isCompatibleWithArrayReference(ArgType, ParamType, Ctx); bool IsParamContinuouslyConst = !IsParamReference || ParamType.getNonReferenceType().isConstQualified(); @@ -444,7 +447,7 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType, ParamType = convertToPointeeOrArrayElementQualType(ParamType); // Check qualifier compatibility on the next level. - if (!ParamType.isAtLeastAsQualifiedAs(ArgType)) + if (!ParamType.isAtLeastAsQualifiedAs(ArgType, Ctx)) return false; if (ParamType.getUnqualifiedType() == ArgType.getUnqualifiedType()) @@ -472,8 +475,8 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType, if (!(ParamType->isAnyPointerType() && ArgType->isAnyPointerType())) return false; - return arePointerTypesCompatible(ArgType, ParamType, - IsParamContinuouslyConst); + return arePointerTypesCompatible(ArgType, ParamType, IsParamContinuouslyConst, + Ctx); } static bool isOverloadedUnaryOrBinarySymbolOperator(const FunctionDecl *FD) { diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h index 6102eb01793530..06236861e26d01 100644 --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -31,6 +31,7 @@ namespace clang { template<typename T> class CanProxy; template<typename T> struct CanProxyAdaptor; class CXXRecordDecl; +class ASTContext; class EnumDecl; class Expr; class IdentifierInfo; @@ -164,14 +165,14 @@ class CanQual { /// Determines whether this canonical type is more qualified than /// the @p Other canonical type. - bool isMoreQualifiedThan(CanQual<T> Other) const { - return Stored.isMoreQualifiedThan(Other.Stored); + bool isMoreQualifiedThan(CanQual<T> Other, const ASTContext &Ctx) const { + return Stored.isMoreQualifiedThan(Other.Stored, Ctx); } /// Determines whether this canonical type is at least as qualified as /// the @p Other canonical type. - bool isAtLeastAsQualifiedAs(CanQual<T> Other) const { - return Stored.isAtLeastAsQualifiedAs(Other.Stored); + bool isAtLeastAsQualifiedAs(CanQual<T> Other, const ASTContext &Ctx) const { + return Stored.isAtLeastAsQualifiedAs(Other.Stored, Ctx); } /// If the canonical type is a reference type, returns the type that diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 8979129017163b..7f3f413b721bc6 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -31,6 +31,7 @@ #include "clang/Basic/PointerAuthOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Basic/Visibility.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" @@ -323,6 +324,7 @@ class PointerAuthQualifier { /// * Objective C: the GC attributes (none, weak, or strong) class Qualifiers { public: + Qualifiers() = default; enum TQ : uint64_t { // NOTE: These flags must be kept in sync with DeclSpec::TQ. Const = 0x1, @@ -697,45 +699,21 @@ class Qualifiers { /// every address space is a superset of itself. /// CL2.0 adds: /// __generic is a superset of any address space except for __constant. - static bool isAddressSpaceSupersetOf(LangAS A, LangAS B) { - // Address spaces must match exactly. - return A == B || - // Otherwise in OpenCLC v2.0 s6.5.5: every address space except - // for __constant can be used as __generic. - (A == LangAS::opencl_generic && B != LangAS::opencl_constant) || - // We also define global_device and global_host address spaces, - // to distinguish global pointers allocated on host from pointers - // allocated on device, which are a subset of __global. - (A == LangAS::opencl_global && (B == LangAS::opencl_global_device || - B == LangAS::opencl_global_host)) || - (A == LangAS::sycl_global && (B == LangAS::sycl_global_device || - B == LangAS::sycl_global_host)) || - // Consider pointer size address spaces to be equivalent to default. - ((isPtrSizeAddressSpace(A) || A == LangAS::Default) && - (isPtrSizeAddressSpace(B) || B == LangAS::Default)) || - // Default is a superset of SYCL address spaces. - (A == LangAS::Default && - (B == LangAS::sycl_private || B == LangAS::sycl_local || - B == LangAS::sycl_global || B == LangAS::sycl_global_device || - B == LangAS::sycl_global_host)) || - // In HIP device compilation, any cuda address space is allowed - // to implicitly cast into the default address space. - (A == LangAS::Default && - (B == LangAS::cuda_constant || B == LangAS::cuda_device || - B == LangAS::cuda_shared)); - } + static bool isAddressSpaceSupersetOf(LangAS A, LangAS B, + const ASTContext &Ctx); /// Returns true if the address space in these qualifiers is equal to or /// a superset of the address space in the argument qualifiers. - bool isAddressSpaceSupersetOf(Qualifiers other) const { - return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace()); + bool isAddressSpaceSupersetOf(Qualifiers other, const ASTContext &Ctx) const { + return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace(), + Ctx); } /// Determines if these qualifiers compatibly include another set. /// Generally this answers the question of whether an object with the other /// qualifiers can be safely used as an object with these qualifiers. - bool compatiblyIncludes(Qualifiers other) const { - return isAddressSpaceSupersetOf(other) && + bool compatiblyIncludes(Qualifiers other, const ASTContext &Ctx) const { + return isAddressSpaceSupersetOf(other, Ctx) && // ObjC GC qualifiers can match, be added, or be removed, but can't // be changed. (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || @@ -1273,11 +1251,11 @@ class QualType { /// Determine whether this type is more qualified than the other /// given type, requiring exact equality for non-CVR qualifiers. - bool isMoreQualifiedThan(QualType Other) const; + bool isMoreQualifiedThan(QualType Other, const ASTContext &Ctx) const; /// Determine whether this type is at least as qualified as the other /// given type, requiring exact equality for non-CVR qualifiers. - bool isAtLeastAsQualifiedAs(QualType Other) const; + bool isAtLeastAsQualifiedAs(QualType Other, const ASTContext &Ctx) const; QualType getNonReferenceType() const; @@ -1425,11 +1403,12 @@ class QualType { /// address spaces overlap iff they are they same. /// OpenCL C v2.0 s6.5.5 adds: /// __generic overlaps with any address space except for __constant. - bool isAddressSpaceOverlapping(QualType T) const { + bool isAddressSpaceOverlapping(QualType T, const ASTContext &Ctx) const { Qualifiers Q = getQualifiers(); Qualifiers TQ = T.getQualifiers(); // Address spaces overlap if at least one of them is a superset of another - return Q.isAddressSpaceSupersetOf(TQ) || TQ.isAddressSpaceSupersetOf(Q); + return Q.isAddressSpaceSupersetOf(TQ, Ctx) || + TQ.isAddressSpaceSupersetOf(Q, Ctx); } /// Returns gc attribute of this type. @@ -8112,24 +8091,26 @@ inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) { /// is more qualified than "const int", "volatile int", and /// "int". However, it is not more qualified than "const volatile /// int". -inline bool QualType::isMoreQualifiedThan(QualType other) const { +inline bool QualType::isMoreQualifiedThan(QualType other, + const ASTContext &Ctx) const { Qualifiers MyQuals = getQualifiers(); Qualifiers OtherQuals = other.getQualifiers(); - return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals)); + return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals, Ctx)); } /// Determine whether this type is at last /// as qualified as the Other type. For example, "const volatile /// int" is at least as qualified as "const int", "volatile int", /// "int", and "const volatile int". -inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const { +inline bool QualType::isAtLeastAsQualifiedAs(QualType other, + const ASTContext &Ctx) const { Qualifiers OtherQuals = other.getQualifiers(); // Ignore __unaligned qualifier if this type is a void. if (getUnqualifiedType()->isVoidType()) OtherQuals.removeUnaligned(); - return getQualifiers().compatiblyIncludes(OtherQuals); + return getQualifiers().compatiblyIncludes(OtherQuals, Ctx); } /// If Type is a reference type (e.g., const diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 25eda907d20a7b..00d6073d0865a0 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -486,6 +486,13 @@ class TargetInfo : public TransferrableTargetInfo, /// \param AddrSpace address space of pointee in source language. virtual uint64_t getNullPointerValue(LangAS AddrSpace) const { return 0; } + /// Returns true if an address space can be safely converted to another. + /// \param A address space of target in source language. + /// \param B address space of source in source language. + virtual bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const { + return A == B; + } + /// Return the size of '_Bool' and C++ 'bool' for this target, in bits. unsigned getBoolWidth() const { return BoolWidth; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 232081bdb46cff..5226ca6f5d0191 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -11405,7 +11405,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, Qualifiers RHSPteeQual = RHSPointee.getQualifiers(); // Blocks can't be an expression in a ternary operator (OpenCL v2.0 // 6.12.5) thus the following check is asymmetric. - if (!LHSPteeQual.isAddressSpaceSupersetOf(RHSPteeQual)) + if (!LHSPteeQual.isAddressSpaceSupersetOf(RHSPteeQual, *this)) return {}; LHSPteeQual.removeAddressSpace(); RHSPteeQual.removeAddressSpace(); diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 7de13977176f2d..22d9ae17b39c2b 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -73,6 +73,38 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const { (hasObjCLifetime() && !Other.hasObjCLifetime())); } +bool Qualifiers::isAddressSpaceSupersetOf(LangAS A, LangAS B, + const ASTContext &Ctx) { + // Address spaces must match exactly. + return A == B || + // Otherwise in OpenCLC v2.0 s6.5.5: every address space except + // for __constant can be used as __generic. + (A == LangAS::opencl_generic && B != LangAS::opencl_constant) || + // We also define global_device and global_host address spaces, + // to distinguish global pointers allocated on host from pointers + // allocated on device, which are a subset of __global. + (A == LangAS::opencl_global && (B == LangAS::opencl_global_device || + B == LangAS::opencl_global_host)) || + (A == LangAS::sycl_global && + (B == LangAS::sycl_global_device || B == LangAS::sycl_global_host)) || + // Consider pointer size address spaces to be equivalent to default. + ((isPtrSizeAddressSpace(A) || A == LangAS::Default) && + (isPtrSizeAddressSpace(B) || B == LangAS::Default)) || + // Default is a superset of SYCL address spaces. + (A == LangAS::Default && + (B == LangAS::sycl_private || B == LangAS::sycl_local || + B == LangAS::sycl_global || B == LangAS::sycl_global_device || + B == LangAS::sycl_global_host)) || + // In HIP device compilation, any cuda address space is allowed + // to implicitly cast into the default address space. + (A == LangAS::Default && + (B == LangAS::cuda_constant || B == LangAS::cuda_device || + B == LangAS::cuda_shared)) || + // Conversions from target specific address spaces may be legal + // depending on the target information. + Ctx.getTargetInfo().isAddressSpaceSupersetOf(A, B); +} + const IdentifierInfo* QualType::getBaseTypeIdentifier() const { const Type* ty = getTypePtr(); NamedDecl *ND = nullptr; diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h index fac46f215a3736..db7a095ba2a4fe 100644 --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -111,6 +111,18 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { return getPointerWidthV(AddrSpace); } + virtual bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const override { + // The flat address space AS(0) is a superset of all the other address + // spaces used by the backend target. + return A == B || + ((A == LangAS::Default || + (isTargetAddressSpace(A) && + toTargetAddressSpace(A) == llvm::AMDGPUAS::FLAT_ADDRESS)) && + isTargetAddressSpace(B) && + toTargetAddressSpace(B) >= llvm::AMDGPUAS::FLAT_ADDRESS && + toTargetAddressSpace(B) <= llvm::AMDGPUAS::PRIVATE_ADDRESS); + } + uint64_t getMaxPointerWidth() const override { return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32; } diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h index 165b28a60fb2a9..3402f32dbde20c 100644 --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -17,6 +17,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/NVPTXAddrSpace.h" #include "llvm/TargetParser/Triple.h" #include <optional> @@ -24,27 +25,26 @@ namespace clang { namespace targets { static const unsigned NVPTXAddrSpaceMap[] = { - 0, // Default - 1, // opencl_global - 3, // opencl_local - 4, // opencl_constant - 0, // opencl_private - // FIXME: generic has to be added to the target - 0, // opencl_generic - 1, // opencl_global_device - 1, // opencl_global_host - 1, // cuda_device - 4, // cuda_constant - 3, // cuda_shared - 1, // sycl_global - 1, // sycl_global_device - 1, // sycl_global_host - 3, // sycl_local - 0, // sycl_private - 0, // ptr32_sptr - 0, // ptr32_uptr - 0, // ptr64 - 0, // hlsl_groupshared + llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // Default + llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // opencl_global + llvm::NVPTXAS::ADDRESS_SPACE_SHARED, // opencl_local + llvm::NVPTXAS::ADDRESS_SPACE_CONST, // opencl_constant + llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // opencl_private + llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // opencl_generic + llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // opencl_global_device + llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // opencl_global_host + llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // cuda_device + llvm::NVPTXAS::ADDRESS_SPACE_CONST, // cuda_constant + llvm::NVPTXAS::ADDRESS_SPACE_SHARED, // cuda_shared + llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // sycl_global + llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // sycl_global_device + llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // sycl_global_host + llvm::NVPTXAS::ADDRESS_SPACE_SHARED, // sycl_local + llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // sycl_private + llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // ptr32_sptr + llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // ptr32_uptr + llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // ptr64 + llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // hlsl_groupshared // Wasm address space values for this target are dummy values, // as it is only enabled for Wasm targets. 20, // wasm_funcref @@ -89,6 +89,20 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo { bool hasFeature(StringRef Feature) const override; + virtual bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const override { + // The generic address space AS(0) is a superset of all the other address + // spaces used by the backend target. + return A == B || + ((A == LangAS::Default || + (isTargetAddressSpace(A) && + toTargetAddressSpace(A) == + llvm::NVPTXAS::ADDRESS_SPACE_GENERIC)) && + isTargetAddressSpace(B) && + toTargetAddressSpace(B) >= llvm::NVPTXAS::ADDRESS_SPACE_GENERIC && + toTargetAddressSpace(B) <= llvm::NVPTXAS::ADDRESS_SPACE_LOCAL && + toTargetAddressSpace(B) != 2); + } + ArrayRef<const char *> getGCCRegNames() const override; ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp index c3a6e5ef8a9d44..3e93b38143f3b3 100644 --- a/clang/lib/Sema/SemaARM.cpp +++ b/clang/lib/Sema/SemaARM.cpp @@ -907,7 +907,7 @@ bool SemaARM::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, // Issue a warning if the cast is dodgy. CastKind CastNeeded = CK_NoOp; - if (!AddrType.isAtLeastAsQualifiedAs(ValType)) { + if (!AddrType.isAtLeastAsQualifiedAs(ValType, getASTContext())) { CastNeeded = CK_BitCast; Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers) << PointerArg->getType() << Context.getPointerType(AddrType) diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 3eb013e3612d1c..cfb82dcc4df451 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -731,7 +731,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, *CastAwayQualifiers = SrcCvrQuals - DestCvrQuals; // If we removed a cvr-qualifier, this is casting away 'constness'. - if (!DestCvrQuals.compatiblyIncludes(SrcCvrQuals)) { + if (!DestCvrQuals.compatiblyIncludes(SrcCvrQuals, + Self.getASTContext())) { if (TheOffendingSrcType) *TheOffendingSrcType = PrevUnwrappedSrcType; if (TheOffendingDestType) @@ -889,7 +890,7 @@ void CastOperation::CheckDynamicCast() { assert(SrcRecord && "Bad source pointee slipped through."); // C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness. - if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { + if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee, Self.getASTContext())) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away) << CT_Dynamic << OrigSrcType << this->DestType << OpRange; SrcExpr = ExprError(); @@ -1463,7 +1464,8 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, SrcPointeeQuals.removeObjCGCAttr(); SrcPointeeQuals.removeObjCLifetime(); if (DestPointeeQuals != SrcPointeeQuals && - !DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals)) { + !DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals, + Self.getASTContext())) { msg = diag::err_bad_cxx_cast_qualifiers_away; return TC_Failed; } @@ -1695,7 +1697,8 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, // FIXME: Being 100% compliant here would be nice to have. // Must preserve cv, as always, unless we're in C-style mode. - if (!CStyle && !DestType.isAtLeastAsQualifiedAs(SrcType)) { + if (!CStyle && + !DestType.isAtLeastAsQualifiedAs(SrcType, Self.getASTContext())) { msg = diag::err_bad_cxx_cast_qualifiers_away; return TC_Failed; } @@ -2524,7 +2527,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, assert(SrcType->isPointerType() && DestType->isPointerType()); if (!CStyle && !DestType->getPointeeType().getQualifiers().isAddressSpaceSupersetOf( - SrcType->getPointeeType().getQualifiers())) { + SrcType->getPointeeType().getQualifiers(), Self.getASTContext())) { SuccessResult = TC_Failed; } } else if (IsLValueCast) { @@ -2631,7 +2634,8 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, return TC_NotApplicable; auto SrcPointeeType = SrcPtrType->getPointeeType(); auto DestPointeeType = DestPtrType->getPointeeType(); - if (!DestPointeeType.isAddressSpaceOverlapping(SrcPointeeType)) { + if (!DestPointeeType.isAddressSpaceOverlapping(SrcPointeeType, + Self.getASTContext())) { msg = diag::err_bad_cxx_cast_addr_space_mismatch; return TC_Failed; } @@ -2676,7 +2680,8 @@ void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) { QualType SrcPPointee = SrcPPtr->getPointeeType(); if (Nested ? DestPPointee.getAddressSpace() != SrcPPointee.getAddressSpace() - : !DestPPointee.isAddressSpaceOverlapping(SrcPPointee)) { + : !DestPPointee.isAddressSpaceOverlapping(SrcPPointee, + Self.getASTContext())) { Self.Diag(OpRange.getBegin(), DiagID) << SrcType << DestType << AssignmentAction::Casting << SrcExpr.get()->getSourceRange(); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 16a76ff9b5c241..452a8a89709f4c 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -1246,7 +1246,8 @@ enum class OverloadCompare { BothViable, Dominates, Dominated }; static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate, const CXXMethodDecl &Incumbent, const Qualifiers &ObjectQuals, - ExprValueKind ObjectKind) { + ExprValueKind ObjectKind, + const ASTContext &Ctx) { // Base/derived shadowing is handled elsewhere. if (Candidate.getDeclContext() != Incumbent.getDeclContext()) return OverloadCompare::BothViable; @@ -1280,8 +1281,8 @@ static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate, // So make some decision based on the qualifiers. Qualifiers CandidateQual = Candidate.getMethodQualifiers(); Qualifiers IncumbentQual = Incumbent.getMethodQualifiers(); - bool CandidateSuperset = CandidateQual.compatiblyIncludes(IncumbentQual); - bool IncumbentSuperset = IncumbentQual.compatiblyIncludes(CandidateQual); + bool CandidateSuperset = CandidateQual.compatiblyIncludes(IncumbentQual, Ctx); + bool IncumbentSuperset = IncumbentQual.compatiblyIncludes(CandidateQual, Ctx); if (CandidateSuperset == IncumbentSuperset) return OverloadCompare::BothViable; return IncumbentSuperset ? OverloadCompare::Dominates @@ -1452,7 +1453,8 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, Result &Incumbent = Results[Entry.second]; switch (compareOverloads(*Method, *cast<CXXMethodDecl>(Incumbent.Declaration), - ObjectTypeQualifiers, ObjectKind)) { + ObjectTypeQualifiers, ObjectKind, + CurContext->getParentASTContext())) { case OverloadCompare::Dominates: // Replace the dominated overload with this one. // FIXME: if the overload dominates multiple incumbents then we diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 8d76a35b2d2557..96e5f36363bec5 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -18332,7 +18332,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, // The new class type must have the same or less qualifiers as the old type. - if (!OldClassTy.isAtLeastAsQualifiedAs(NewClassTy)) { + if (!OldClassTy.isAtLeastAsQualifiedAs(NewClassTy, getASTContext())) { Diag(New->getLocation(), diag::err_covariant_return_type_class_type_not_same_or_less_qualified) << New->getDeclName() << NewTy << OldTy diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 0d5ab0b3cd09ca..bfcdab91dd6f07 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -717,9 +717,9 @@ bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) { Qualifiers EQuals, HQuals; ExceptionType = Context.getUnqualifiedArrayType( ExceptionType->getPointeeType(), EQuals); - HandlerType = Context.getUnqualifiedArrayType( - HandlerType->getPointeeType(), HQuals); - if (!HQuals.compatiblyIncludes(EQuals)) + HandlerType = + Context.getUnqualifiedArrayType(HandlerType->getPointeeType(), HQuals); + if (!HQuals.compatiblyIncludes(EQuals, getASTContext())) return false; if (HandlerType->isVoidType() && ExceptionType->isObjectType()) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 01d43317e33aed..73647c55986463 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -8025,9 +8025,9 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address // spaces is disallowed. - if (lhQual.isAddressSpaceSupersetOf(rhQual)) + if (lhQual.isAddressSpaceSupersetOf(rhQual, S.getASTContext())) ResultAddrSpace = LAddrSpace; - else if (rhQual.isAddressSpaceSupersetOf(lhQual)) + else if (rhQual.isAddressSpaceSupersetOf(lhQual, S.getASTContext())) ResultAddrSpace = RAddrSpace; else { S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) @@ -8939,17 +8939,17 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType, rhq.removeObjCLifetime(); } - if (!lhq.compatiblyIncludes(rhq)) { + if (!lhq.compatiblyIncludes(rhq, S.getASTContext())) { // Treat address-space mismatches as fatal. - if (!lhq.isAddressSpaceSupersetOf(rhq)) + if (!lhq.isAddressSpaceSupersetOf(rhq, S.getASTContext())) return Sema::IncompatiblePointerDiscardsQualifiers; // It's okay to add or remove GC or lifetime qualifiers when converting to // and from void*. - else if (lhq.withoutObjCGCAttr().withoutObjCLifetime() - .compatiblyIncludes( - rhq.withoutObjCGCAttr().withoutObjCLifetime()) - && (lhptee->isVoidType() || rhptee->isVoidType())) + else if (lhq.withoutObjCGCAttr().withoutObjCLifetime().compatiblyIncludes( + rhq.withoutObjCGCAttr().withoutObjCLifetime(), + S.getASTContext()) && + (lhptee->isVoidType() || rhptee->isVoidType())) ; // keep old // Treat lifetime mismatches as fatal. @@ -9136,7 +9136,7 @@ checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType, QualType lhptee = LHSType->castAs<ObjCObjectPointerType>()->getPointeeType(); QualType rhptee = RHSType->castAs<ObjCObjectPointerType>()->getPointeeType(); - if (!lhptee.isAtLeastAsQualifiedAs(rhptee) && + if (!lhptee.isAtLeastAsQualifiedAs(rhptee, S.getASTContext()) && // make an exception for id<P> !LHSType->isObjCQualifiedIdType()) return Sema::CompatiblePointerDiscardsQualifiers; @@ -10833,7 +10833,8 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc, // if both are pointers check if operation is valid wrt address spaces if (isLHSPointer && isRHSPointer) { - if (!LHSPointeeTy.isAddressSpaceOverlapping(RHSPointeeTy)) { + if (!LHSPointeeTy.isAddressSpaceOverlapping(RHSPointeeTy, + S.getASTContext())) { S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSExpr->getType() << RHSExpr->getType() << 1 /*arithmetic op*/ @@ -12364,7 +12365,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, if (LCanPointeeTy != RCanPointeeTy) { // Treat NULL constant as a special case in OpenCL. if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) { - if (!LCanPointeeTy.isAddressSpaceOverlapping(RCanPointeeTy)) { + if (!LCanPointeeTy.isAddressSpaceOverlapping(RCanPointeeTy, + getASTContext())) { Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSType << RHSType << 0 /* comparison */ diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index ab9367f911cc51..3b5d5c4befc0f7 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -4783,7 +4783,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, ToType->castAs<BlockPointerType>()->getPointeeType().getAddressSpace(); LangAS AddrSpaceR = FromType->castAs<BlockPointerType>()->getPointeeType().getAddressSpace(); - assert(Qualifiers::isAddressSpaceSupersetOf(AddrSpaceL, AddrSpaceR) && + assert(Qualifiers::isAddressSpaceSupersetOf(AddrSpaceL, AddrSpaceR, + getASTContext()) && "Invalid cast"); CastKind Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; @@ -6641,7 +6642,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // same type as, or a base class of, the class of T1, and // [cv2 > cv1]. if (FRec == TRec || FDerivedFromT) { - if (TTy.isAtLeastAsQualifiedAs(FTy)) { + if (TTy.isAtLeastAsQualifiedAs(FTy, Self.getASTContext())) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, From); if (InitSeq) { @@ -7363,8 +7364,8 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, if (Q1.getAddressSpace() == Q2.getAddressSpace()) { Quals.setAddressSpace(Q1.getAddressSpace()); } else if (Steps.size() == 1) { - bool MaybeQ1 = Q1.isAddressSpaceSupersetOf(Q2); - bool MaybeQ2 = Q2.isAddressSpaceSupersetOf(Q1); + bool MaybeQ1 = Q1.isAddressSpaceSupersetOf(Q2, getASTContext()); + bool MaybeQ2 = Q2.isAddressSpaceSupersetOf(Q1, getASTContext()); if (MaybeQ1 == MaybeQ2) { // Exception for ptr size address spaces. Should be able to choose // either address space during comparison. diff --git a/clang/lib/Sema/SemaFixItUtils.cpp b/clang/lib/Sema/SemaFixItUtils.cpp index 2c85a53194301f..1dad46fd6b9401 100644 --- a/clang/lib/Sema/SemaFixItUtils.cpp +++ b/clang/lib/Sema/SemaFixItUtils.cpp @@ -24,7 +24,7 @@ bool ConversionFixItGenerator::compareTypesSimple(CanQualType From, Sema &S, SourceLocation Loc, ExprValueKind FromVK) { - if (!To.isAtLeastAsQualifiedAs(From)) + if (!To.isAtLeastAsQualifiedAs(From, S.getASTContext())) return false; From = From.getNonReferenceType(); @@ -41,8 +41,8 @@ bool ConversionFixItGenerator::compareTypesSimple(CanQualType From, const CanQualType FromUnq = From.getUnqualifiedType(); const CanQualType ToUnq = To.getUnqualifiedType(); - if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq)) ) && - To.isAtLeastAsQualifiedAs(From)) + if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq))) && + To.isAtLeastAsQualifiedAs(From, S.getASTContext())) return true; return false; } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index f13355bb93cbeb..00586dc601997b 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -4718,7 +4718,7 @@ static void TryReferenceListInitialization(Sema &S, if (T1Quals.hasAddressSpace()) { Qualifiers T2Quals; (void)S.Context.getUnqualifiedArrayType(InitList->getType(), T2Quals); - if (!T1Quals.isAddressSpaceSupersetOf(T2Quals)) { + if (!T1Quals.isAddressSpaceSupersetOf(T2Quals, S.getASTContext())) { Sequence.SetFailed( InitializationSequence::FK_ReferenceInitDropsQualifiers); return; @@ -5324,8 +5324,9 @@ static void TryReferenceInitializationCore(Sema &S, // shall be an rvalue reference. // For address spaces, we interpret this to mean that an addr space // of a reference "cv1 T1" is a superset of addr space of "cv2 T2". - if (isLValueRef && !(T1Quals.hasConst() && !T1Quals.hasVolatile() && - T1Quals.isAddressSpaceSupersetOf(T2Quals))) { + if (isLValueRef && + !(T1Quals.hasConst() && !T1Quals.hasVolatile() && + T1Quals.isAddressSpaceSupersetOf(T2Quals, S.getASTContext()))) { if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); else if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) @@ -5334,7 +5335,7 @@ static void TryReferenceInitializationCore(Sema &S, ConvOvlResult); else if (!InitCategory.isLValue()) Sequence.SetFailed( - T1Quals.isAddressSpaceSupersetOf(T2Quals) + T1Quals.isAddressSpaceSupersetOf(T2Quals, S.getASTContext()) ? InitializationSequence:: FK_NonConstLValueReferenceBindingToTemporary : InitializationSequence::FK_ReferenceInitDropsQualifiers); @@ -5519,7 +5520,7 @@ static void TryReferenceInitializationCore(Sema &S, unsigned T2CVRQuals = T2Quals.getCVRQualifiers(); if (RefRelationship == Sema::Ref_Related && ((T1CVRQuals | T2CVRQuals) != T1CVRQuals || - !T1Quals.isAddressSpaceSupersetOf(T2Quals))) { + !T1Quals.isAddressSpaceSupersetOf(T2Quals, S.getASTContext()))) { Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } @@ -5536,8 +5537,8 @@ static void TryReferenceInitializationCore(Sema &S, Sequence.AddReferenceBindingStep(cv1T1IgnoreAS, /*BindingTemporary=*/true); if (T1Quals.hasAddressSpace()) { - if (!Qualifiers::isAddressSpaceSupersetOf(T1Quals.getAddressSpace(), - LangAS::Default)) { + if (!Qualifiers::isAddressSpaceSupersetOf( + T1Quals.getAddressSpace(), LangAS::Default, S.getASTContext())) { Sequence.SetFailed( InitializationSequence::FK_ReferenceAddrspaceMismatchTemporary); return; @@ -8629,7 +8630,7 @@ static void emitBadConversionNotes(Sema &S, const InitializedEntity &entity, !fromDecl->isInvalidDecl() && !destDecl->isInvalidDecl() && !fromDecl->hasDefinition() && destPointeeType.getQualifiers().compatiblyIncludes( - fromPointeeType.getQualifiers())) + fromPointeeType.getQualifiers(), S.getASTContext())) S.Diag(fromDecl->getLocation(), diag::note_forward_class_conversion) << S.getASTContext().getTagDeclType(fromDecl) << S.getASTContext().getTagDeclType(destDecl); @@ -8907,7 +8908,7 @@ bool InitializationSequence::Diagnose(Sema &S, SourceType.getQualifiers() - NonRefType.getQualifiers(); if (!NonRefType.getQualifiers().isAddressSpaceSupersetOf( - SourceType.getQualifiers())) + SourceType.getQualifiers(), S.getASTContext())) S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) << NonRefType << SourceType << 1 /*addr space*/ << Args[0]->getSourceRange(); diff --git a/clang/lib/Sema/SemaObjC.cpp b/clang/lib/Sema/SemaObjC.cpp index 0359d18dd94525..57eda18c2d8e15 100644 --- a/clang/lib/Sema/SemaObjC.cpp +++ b/clang/lib/Sema/SemaObjC.cpp @@ -1350,7 +1350,7 @@ bool SemaObjC::isObjCWritebackConversion(QualType FromType, QualType ToType, // Make sure that we have compatible qualifiers. FromQuals.setObjCLifetime(Qualifiers::OCL_Autoreleasing); - if (!ToQuals.compatiblyIncludes(FromQuals)) + if (!ToQuals.compatiblyIncludes(FromQuals, getASTContext())) return false; // Remove qualifiers from the pointee type we're converting from; they diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index fe8bb99d2db040..dfe0da153fecee 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -18188,7 +18188,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * { if (!D->isInvalidDecl() && SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) && - !Ty.isMoreQualifiedThan(D->getType())) + !Ty.isMoreQualifiedThan(D->getType(), + SemaRef.getASTContext())) return D; return nullptr; })) { @@ -21038,7 +21039,8 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S, Lookups, [&SemaRef, Type, Loc](ValueDecl *D) -> ValueDecl * { if (!D->isInvalidDecl() && SemaRef.IsDerivedFrom(Loc, Type, D->getType()) && - !Type.isMoreQualifiedThan(D->getType())) + !Type.isMoreQualifiedThan(D->getType(), + SemaRef.getASTContext())) return D; return nullptr; })) { @@ -21209,7 +21211,7 @@ static bool hasUserDefinedMapper(Sema &SemaRef, Scope *S, Lookups, [&SemaRef, Type, Loc](ValueDecl *D) -> ValueDecl * { if (!D->isInvalidDecl() && SemaRef.IsDerivedFrom(Loc, Type, D->getType()) && - !Type.isMoreQualifiedThan(D->getType())) + !Type.isMoreQualifiedThan(D->getType(), SemaRef.getASTContext())) return D; return nullptr; }); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 4aeceba128b29b..1b4c76c840fea6 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -2963,7 +2963,7 @@ static QualType AdoptQualifiers(ASTContext &Context, QualType T, Qualifiers Qs){ if (TQs == Qs) return T; - if (Qs.compatiblyIncludes(TQs)) + if (Qs.compatiblyIncludes(TQs, Context)) return Context.getQualifiedType(T, Qs); return Context.getQualifiedType(T.getUnqualifiedType(), Qs); @@ -2997,7 +2997,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, const ObjCInterfaceType* RHS = FromObjCPtr->getInterfaceType(); if (getLangOpts().CPlusPlus && LHS && RHS && !ToObjCPtr->getPointeeType().isAtLeastAsQualifiedAs( - FromObjCPtr->getPointeeType())) + FromObjCPtr->getPointeeType(), getASTContext())) return false; ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr, ToObjCPtr->getPointeeType(), @@ -3604,7 +3604,8 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals, static bool isQualificationConversionStep(QualType FromType, QualType ToType, bool CStyle, bool IsTopLevel, bool &PreviousToQualsIncludeConst, - bool &ObjCLifetimeConversion) { + bool &ObjCLifetimeConversion, + const ASTContext &Ctx) { Qualifiers FromQuals = FromType.getQualifiers(); Qualifiers ToQuals = ToType.getQualifiers(); @@ -3635,7 +3636,7 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType, // -- for every j > 0, if const is in cv 1,j then const is in cv // 2,j, and similarly for volatile. - if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals)) + if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals, Ctx)) return false; // If address spaces mismatch: @@ -3645,8 +3646,8 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType, // - in non-top levels it is not a valid conversion. if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace() && (!IsTopLevel || - !(ToQuals.isAddressSpaceSupersetOf(FromQuals) || - (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals))))) + !(ToQuals.isAddressSpaceSupersetOf(FromQuals, Ctx) || + (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals, Ctx))))) return false; // -- if the cv 1,j and cv 2,j are different, then const is in @@ -3693,9 +3694,10 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, bool PreviousToQualsIncludeConst = true; bool UnwrappedAnyPointer = false; while (Context.UnwrapSimilarTypes(FromType, ToType)) { - if (!isQualificationConversionStep( - FromType, ToType, CStyle, !UnwrappedAnyPointer, - PreviousToQualsIncludeConst, ObjCLifetimeConversion)) + if (!isQualificationConversionStep(FromType, ToType, CStyle, + !UnwrappedAnyPointer, + PreviousToQualsIncludeConst, + ObjCLifetimeConversion, getASTContext())) return false; UnwrappedAnyPointer = true; } @@ -4546,9 +4548,9 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc, T1 = S.Context.getQualifiedType(UnqualT1, T1Quals); if (isa<ArrayType>(T2) && T2Quals) T2 = S.Context.getQualifiedType(UnqualT2, T2Quals); - if (T2.isMoreQualifiedThan(T1)) + if (T2.isMoreQualifiedThan(T1, S.getASTContext())) return ImplicitConversionSequence::Better; - if (T1.isMoreQualifiedThan(T2)) + if (T1.isMoreQualifiedThan(T2, S.getASTContext())) return ImplicitConversionSequence::Worse; } } @@ -4987,7 +4989,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, bool ObjCLifetimeConversion = false; if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, TopLevel, PreviousToQualsIncludeConst, - ObjCLifetimeConversion)) + ObjCLifetimeConversion, getASTContext())) return (ConvertedReferent || Context.hasSimilarType(T1, T2)) ? Ref_Related : Ref_Incompatible; @@ -5318,7 +5320,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, // MS compiler ignores __unaligned qualifier for references; do the same. T1Quals.removeUnaligned(); T2Quals.removeUnaligned(); - if (!T1Quals.compatiblyIncludes(T2Quals)) + if (!T1Quals.compatiblyIncludes(T2Quals, S.getASTContext())) return ICS; } @@ -5836,7 +5838,7 @@ static ImplicitConversionSequence TryObjectArgumentInitialization( if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && !ImplicitParamType.isAtLeastAsQualifiedAs( - withoutUnaligned(S.Context, FromTypeCanon))) { + withoutUnaligned(S.Context, FromTypeCanon), S.getASTContext())) { ICS.setBad(BadConversionSequence::bad_qualifiers, FromType, ImplicitParamType); return ICS; @@ -5845,7 +5847,8 @@ static ImplicitConversionSequence TryObjectArgumentInitialization( if (FromTypeCanon.hasAddressSpace()) { Qualifiers QualsImplicitParamType = ImplicitParamType.getQualifiers(); Qualifiers QualsFromType = FromTypeCanon.getQualifiers(); - if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType)) { + if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType, + S.getASTContext())) { ICS.setBad(BadConversionSequence::bad_qualifiers, FromType, ImplicitParamType); return ICS; @@ -7030,7 +7033,7 @@ void Sema::AddOverloadCandidate( // destination address space. if (!Qualifiers::isAddressSpaceSupersetOf( Constructor->getMethodQualifiers().getAddressSpace(), - CandidateSet.getDestAS())) { + CandidateSet.getDestAS(), getASTContext())) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_object_addrspace_mismatch; } @@ -10678,9 +10681,9 @@ bool clang::isBetterOverloadCandidate( LangAS AS1 = CD1->getMethodQualifiers().getAddressSpace(); LangAS AS2 = CD2->getMethodQualifiers().getAddressSpace(); if (AS1 != AS2) { - if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1)) + if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1, S.getASTContext())) return true; - if (Qualifiers::isAddressSpaceSupersetOf(AS1, AS2)) + if (Qualifiers::isAddressSpaceSupersetOf(AS1, AS2, S.getASTContext())) return false; } } @@ -11285,7 +11288,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, } if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() && - !CToTy.isAtLeastAsQualifiedAs(CFromTy)) { + !CToTy.isAtLeastAsQualifiedAs(CFromTy, S.getASTContext())) { Qualifiers FromQs = CFromTy.getQualifiers(); Qualifiers ToQs = CToTy.getQualifiers(); @@ -11384,7 +11387,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (const PointerType *FromPtrTy = FromTy->getAs<PointerType>()) { if (const PointerType *ToPtrTy = ToTy->getAs<PointerType>()) { if (ToPtrTy->getPointeeType().isAtLeastAsQualifiedAs( - FromPtrTy->getPointeeType()) && + FromPtrTy->getPointeeType(), S.getASTContext()) && !FromPtrTy->getPointeeType()->isIncompleteType() && !ToPtrTy->getPointeeType()->isIncompleteType() && S.IsDerivedFrom(SourceLocation(), ToPtrTy->getPointeeType(), @@ -11398,11 +11401,12 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (const ObjCInterfaceDecl *FromIface = FromPtrTy->getInterfaceDecl()) if (const ObjCInterfaceDecl *ToIface = ToPtrTy->getInterfaceDecl()) if (ToPtrTy->getPointeeType().isAtLeastAsQualifiedAs( - FromPtrTy->getPointeeType()) && + FromPtrTy->getPointeeType(), S.getASTContext()) && FromIface->isSuperClassOf(ToIface)) BaseToDerivedConversion = 2; } else if (const ReferenceType *ToRefTy = ToTy->getAs<ReferenceType>()) { - if (ToRefTy->getPointeeType().isAtLeastAsQualifiedAs(FromTy) && + if (ToRefTy->getPointeeType().isAtLeastAsQualifiedAs(FromTy, + S.getASTContext()) && !FromTy->isIncompleteType() && !ToRefTy->getPointeeType()->isIncompleteType() && S.IsDerivedFrom(SourceLocation(), ToRefTy->getPointeeType(), FromTy)) { diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 2946d8102f9897..8d234c05492a91 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1743,7 +1743,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // C++ [temp.deduct.conv]p4: // If the original A is a reference type, A can be more cv-qualified // than the deduced A - if (!A.getQualifiers().compatiblyIncludes(P.getQualifiers())) + if (!A.getQualifiers().compatiblyIncludes(P.getQualifiers(), + S.getASTContext())) return TemplateDeductionResult::NonDeducedMismatch; // Strip out all extra qualifiers from the argument to figure out the @@ -3772,7 +3773,7 @@ CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info, if (AQuals == DeducedAQuals) { // Qualifiers match; there's nothing to do. - } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) { + } else if (!DeducedAQuals.compatiblyIncludes(AQuals, S.getASTContext())) { return Failed(); } else { // Qualifiers are compatible, so have the argument type adopt the diff --git a/clang/test/CodeGen/target-addrspace.cpp b/clang/test/CodeGen/target-addrspace.cpp new file mode 100644 index 00000000000000..9adf53611bc242 --- /dev/null +++ b/clang/test/CodeGen/target-addrspace.cpp @@ -0,0 +1,140 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -triple nvptx64-nvidia-cuda -emit-llvm \ +// RUN: -fvisibility=hidden -o - %s | FileCheck %s --check-prefix=NVPTX +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -emit-llvm \ +// RUN: -fvisibility=hidden -o - %s | FileCheck %s --check-prefix=AMDGPU + +// NVPTX-LABEL: define hidden void @_Z1fPv( +// NVPTX-SAME: ptr noundef [[P:%.*]]) #[[ATTR0:[0-9]+]] { +// NVPTX-NEXT: [[ENTRY:.*:]] +// NVPTX-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8 +// NVPTX-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8 +// NVPTX-NEXT: ret void +// +// AMDGPU-LABEL: define hidden void @_Z1fPv( +// AMDGPU-SAME: ptr noundef [[P:%.*]]) #[[ATTR0:[0-9]+]] { +// AMDGPU-NEXT: [[ENTRY:.*:]] +// AMDGPU-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// AMDGPU-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr +// AMDGPU-NEXT: store ptr [[P]], ptr [[P_ADDR_ASCAST]], align 8 +// AMDGPU-NEXT: ret void +// +void f(void *p) {} + +// NVPTX-LABEL: define hidden void @_Z2p1Pv( +// NVPTX-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// NVPTX-NEXT: [[ENTRY:.*:]] +// NVPTX-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8 +// NVPTX-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8 +// NVPTX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8 +// NVPTX-NEXT: call void @_Z1fPv(ptr noundef [[TMP0]]) #[[ATTR1:[0-9]+]] +// NVPTX-NEXT: ret void +// +// AMDGPU-LABEL: define hidden void @_Z2p1Pv( +// AMDGPU-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// AMDGPU-NEXT: [[ENTRY:.*:]] +// AMDGPU-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// AMDGPU-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr +// AMDGPU-NEXT: store ptr [[P]], ptr [[P_ADDR_ASCAST]], align 8 +// AMDGPU-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR_ASCAST]], align 8 +// AMDGPU-NEXT: call void @_Z1fPv(ptr noundef [[TMP0]]) #[[ATTR1:[0-9]+]] +// AMDGPU-NEXT: ret void +// +void p1(void [[clang::address_space(0)]] * p) { f(p); } +// NVPTX-LABEL: define hidden noundef ptr @_Z2p2PU3AS3v( +// NVPTX-SAME: ptr addrspace(3) noundef [[P:%.*]]) #[[ATTR0]] { +// NVPTX-NEXT: [[ENTRY:.*:]] +// NVPTX-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(3), align 8 +// NVPTX-NEXT: store ptr addrspace(3) [[P]], ptr [[P_ADDR]], align 8 +// NVPTX-NEXT: [[TMP0:%.*]] = load ptr addrspace(3), ptr [[P_ADDR]], align 8 +// NVPTX-NEXT: [[TMP1:%.*]] = addrspacecast ptr addrspace(3) [[TMP0]] to ptr +// NVPTX-NEXT: ret ptr [[TMP1]] +// +// AMDGPU-LABEL: define hidden noundef ptr @_Z2p2PU3AS3v( +// AMDGPU-SAME: ptr addrspace(3) noundef [[P:%.*]]) #[[ATTR0]] { +// AMDGPU-NEXT: [[ENTRY:.*:]] +// AMDGPU-NEXT: [[RETVAL:%.*]] = alloca ptr, align 8, addrspace(5) +// AMDGPU-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(3), align 4, addrspace(5) +// AMDGPU-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// AMDGPU-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr +// AMDGPU-NEXT: store ptr addrspace(3) [[P]], ptr [[P_ADDR_ASCAST]], align 4 +// AMDGPU-NEXT: [[TMP0:%.*]] = load ptr addrspace(3), ptr [[P_ADDR_ASCAST]], align 4 +// AMDGPU-NEXT: [[TMP1:%.*]] = addrspacecast ptr addrspace(3) [[TMP0]] to ptr +// AMDGPU-NEXT: ret ptr [[TMP1]] +// +void *p2(void [[clang::address_space(3)]] * p) { return p; } +// NVPTX-LABEL: define hidden noundef ptr @_Z2p3PU3AS3v( +// NVPTX-SAME: ptr addrspace(3) noundef [[P:%.*]]) #[[ATTR0]] { +// NVPTX-NEXT: [[ENTRY:.*:]] +// NVPTX-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(3), align 8 +// NVPTX-NEXT: store ptr addrspace(3) [[P]], ptr [[P_ADDR]], align 8 +// NVPTX-NEXT: [[TMP0:%.*]] = load ptr addrspace(3), ptr [[P_ADDR]], align 8 +// NVPTX-NEXT: [[TMP1:%.*]] = addrspacecast ptr addrspace(3) [[TMP0]] to ptr +// NVPTX-NEXT: ret ptr [[TMP1]] +// +// AMDGPU-LABEL: define hidden noundef ptr @_Z2p3PU3AS3v( +// AMDGPU-SAME: ptr addrspace(3) noundef [[P:%.*]]) #[[ATTR0]] { +// AMDGPU-NEXT: [[ENTRY:.*:]] +// AMDGPU-NEXT: [[RETVAL:%.*]] = alloca ptr, align 8, addrspace(5) +// AMDGPU-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(3), align 4, addrspace(5) +// AMDGPU-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// AMDGPU-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr +// AMDGPU-NEXT: store ptr addrspace(3) [[P]], ptr [[P_ADDR_ASCAST]], align 4 +// AMDGPU-NEXT: [[TMP0:%.*]] = load ptr addrspace(3), ptr [[P_ADDR_ASCAST]], align 4 +// AMDGPU-NEXT: [[TMP1:%.*]] = addrspacecast ptr addrspace(3) [[TMP0]] to ptr +// AMDGPU-NEXT: ret ptr [[TMP1]] +// +void *p3(void [[clang::address_space(3)]] * p) { return p; } + +struct S { + S() = default; + ~S() = default; + void foo() {} +}; + +S s1; +S [[clang::address_space(1)]] s2; +S [[clang::address_space(3)]] s3; + +template <typename Ty> void foo(Ty *) {} + +// NVPTX-LABEL: define hidden void @_Z2t1Pv( +// NVPTX-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// NVPTX-NEXT: [[ENTRY:.*:]] +// NVPTX-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8 +// NVPTX-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8 +// NVPTX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8 +// NVPTX-NEXT: call void @_Z3fooIvEvPT_(ptr noundef [[TMP0]]) #[[ATTR1]] +// NVPTX-NEXT: ret void +// +// AMDGPU-LABEL: define hidden void @_Z2t1Pv( +// AMDGPU-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// AMDGPU-NEXT: [[ENTRY:.*:]] +// AMDGPU-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// AMDGPU-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr +// AMDGPU-NEXT: store ptr [[P]], ptr [[P_ADDR_ASCAST]], align 8 +// AMDGPU-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR_ASCAST]], align 8 +// AMDGPU-NEXT: call void @_Z3fooIvEvPT_(ptr noundef [[TMP0]]) #[[ATTR1]] +// AMDGPU-NEXT: ret void +// +void t1(void *p) { foo(p); } +// NVPTX-LABEL: define hidden void @_Z2t3PU3AS3v( +// NVPTX-SAME: ptr addrspace(3) noundef [[P:%.*]]) #[[ATTR0]] { +// NVPTX-NEXT: [[ENTRY:.*:]] +// NVPTX-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(3), align 8 +// NVPTX-NEXT: store ptr addrspace(3) [[P]], ptr [[P_ADDR]], align 8 +// NVPTX-NEXT: [[TMP0:%.*]] = load ptr addrspace(3), ptr [[P_ADDR]], align 8 +// NVPTX-NEXT: call void @_Z3fooIU3AS3vEvPT_(ptr addrspace(3) noundef [[TMP0]]) #[[ATTR1]] +// NVPTX-NEXT: ret void +// +// AMDGPU-LABEL: define hidden void @_Z2t3PU3AS3v( +// AMDGPU-SAME: ptr addrspace(3) noundef [[P:%.*]]) #[[ATTR0]] { +// AMDGPU-NEXT: [[ENTRY:.*:]] +// AMDGPU-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(3), align 4, addrspace(5) +// AMDGPU-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr +// AMDGPU-NEXT: store ptr addrspace(3) [[P]], ptr [[P_ADDR_ASCAST]], align 4 +// AMDGPU-NEXT: [[TMP0:%.*]] = load ptr addrspace(3), ptr [[P_ADDR_ASCAST]], align 4 +// AMDGPU-NEXT: call void @_Z3fooIU3AS3vEvPT_(ptr addrspace(3) noundef [[TMP0]]) #[[ATTR1]] +// AMDGPU-NEXT: ret void +// +void t3(void [[clang::address_space(3)]] *p) { foo(p); } diff --git a/clang/test/Sema/amdgcn-address-spaces.c b/clang/test/Sema/amdgcn-address-spaces.c new file mode 100644 index 00000000000000..50c12993ac69b8 --- /dev/null +++ b/clang/test/Sema/amdgcn-address-spaces.c @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 %s -triple amdgcn-amd-amdhsa -fsyntax-only -verify + +#define _AS0 __attribute__((address_space(0))) +#define _AS1 __attribute__((address_space(1))) +#define _AS2 __attribute__((address_space(2))) +#define _AS3 __attribute__((address_space(3))) +#define _AS4 __attribute__((address_space(4))) +#define _AS5 __attribute__((address_space(5))) +#define _AS999 __attribute__((address_space(999))) + +void *p1(void _AS1 *p) { return p; } +void *p2(void _AS2 *p) { return p; } +void *p3(void _AS3 *p) { return p; } +void *p4(void _AS4 *p) { return p; } +void *p5(void _AS5 *p) { return p; } +void *pi(void _AS999 *p) { return p; } // expected-error {{returning '_AS999 void *' from a function with result type 'void *' changes address space of pointer}} +void *pc(void __attribute__((opencl_local)) *p) { return p; } // expected-error {{returning '__local void *' from a function with result type 'void *' changes address space of pointer}} +void _AS1 *r0(void _AS1 *p) { return p; } +void _AS1 *r1(void *p) { return p; } // expected-error {{returning 'void *' from a function with result type '_AS1 void *' changes address space of pointer}} +void _AS1 *r2(void *p) { return (void _AS1 *)p; } diff --git a/clang/test/Sema/nvptx-address-spaces.c b/clang/test/Sema/nvptx-address-spaces.c new file mode 100644 index 00000000000000..184feef9612e57 --- /dev/null +++ b/clang/test/Sema/nvptx-address-spaces.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 %s -triple nvptx64-nvidia-cuda -fsyntax-only -verify + +#define _AS0 __attribute__((address_space(0))) +#define _AS1 __attribute__((address_space(1))) +#define _AS2 __attribute__((address_space(2))) +#define _AS3 __attribute__((address_space(3))) +#define _AS4 __attribute__((address_space(4))) +#define _AS5 __attribute__((address_space(5))) +#define _AS999 __attribute__((address_space(999))) + +void *p1(void _AS1 *p) { return p; } +void *p2(void _AS2 *p) { return p; } // expected-error {{returning '_AS2 void *' from a function with result type 'void *' changes address space of pointer}} +void *p3(void _AS3 *p) { return p; } +void *p4(void _AS4 *p) { return p; } +void *p5(void _AS5 *p) { return p; } +void *pi(void _AS999 *p) { return p; } // expected-error {{returning '_AS999 void *' from a function with result type 'void *' changes address space of pointer}} +void *pc(void __attribute__((opencl_local)) *p) { return p; } // expected-error {{returning '__local void *' from a function with result type 'void *' changes address space of pointer}} +void _AS1 *r0(void _AS1 *p) { return p; } +void _AS1 *r1(void *p) { return p; } // expected-error {{returning 'void *' from a function with result type '_AS1 void *' changes address space of pointer}} +void _AS1 *r2(void *p) { return (void _AS1 *)p; } + >From 80c497c8aaef809845eda00469c5b510736cdfb0 Mon Sep 17 00:00:00 2001 From: Joseph Huber <hube...@outlook.com> Date: Wed, 13 Nov 2024 18:45:26 -0600 Subject: [PATCH 2/3] Comments --- clang/include/clang/AST/Type.h | 34 ++++++++++++++++++++++++++- clang/lib/AST/Type.cpp | 33 +++----------------------- clang/lib/Basic/Targets/NVPTX.h | 41 +++++++++++++++++---------------- 3 files changed, 57 insertions(+), 51 deletions(-) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 7f3f413b721bc6..3dd0579bd10d60 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -700,7 +700,39 @@ class Qualifiers { /// CL2.0 adds: /// __generic is a superset of any address space except for __constant. static bool isAddressSpaceSupersetOf(LangAS A, LangAS B, - const ASTContext &Ctx); + const ASTContext &Ctx) { + // Address spaces must match exactly. + return A == B || + // Otherwise in OpenCLC v2.0 s6.5.5: every address space except + // for __constant can be used as __generic. + (A == LangAS::opencl_generic && B != LangAS::opencl_constant) || + // We also define global_device and global_host address spaces, + // to distinguish global pointers allocated on host from pointers + // allocated on device, which are a subset of __global. + (A == LangAS::opencl_global && (B == LangAS::opencl_global_device || + B == LangAS::opencl_global_host)) || + (A == LangAS::sycl_global && (B == LangAS::sycl_global_device || + B == LangAS::sycl_global_host)) || + // Consider pointer size address spaces to be equivalent to default. + ((isPtrSizeAddressSpace(A) || A == LangAS::Default) && + (isPtrSizeAddressSpace(B) || B == LangAS::Default)) || + // Default is a superset of SYCL address spaces. + (A == LangAS::Default && + (B == LangAS::sycl_private || B == LangAS::sycl_local || + B == LangAS::sycl_global || B == LangAS::sycl_global_device || + B == LangAS::sycl_global_host)) || + // In HIP device compilation, any cuda address space is allowed + // to implicitly cast into the default address space. + (A == LangAS::Default && + (B == LangAS::cuda_constant || B == LangAS::cuda_device || + B == LangAS::cuda_shared)) || + // Conversions from target specific address spaces may be legal + // depending on the target information. + isTargetAddressSpaceSupersetOf(A, B, Ctx); + } + + static bool isTargetAddressSpaceSupersetOf(LangAS A, LangAS B, + const ASTContext &Ctx); /// Returns true if the address space in these qualifiers is equal to or /// a superset of the address space in the argument qualifiers. diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 22d9ae17b39c2b..43579aaa9d3a4c 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -73,36 +73,9 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const { (hasObjCLifetime() && !Other.hasObjCLifetime())); } -bool Qualifiers::isAddressSpaceSupersetOf(LangAS A, LangAS B, - const ASTContext &Ctx) { - // Address spaces must match exactly. - return A == B || - // Otherwise in OpenCLC v2.0 s6.5.5: every address space except - // for __constant can be used as __generic. - (A == LangAS::opencl_generic && B != LangAS::opencl_constant) || - // We also define global_device and global_host address spaces, - // to distinguish global pointers allocated on host from pointers - // allocated on device, which are a subset of __global. - (A == LangAS::opencl_global && (B == LangAS::opencl_global_device || - B == LangAS::opencl_global_host)) || - (A == LangAS::sycl_global && - (B == LangAS::sycl_global_device || B == LangAS::sycl_global_host)) || - // Consider pointer size address spaces to be equivalent to default. - ((isPtrSizeAddressSpace(A) || A == LangAS::Default) && - (isPtrSizeAddressSpace(B) || B == LangAS::Default)) || - // Default is a superset of SYCL address spaces. - (A == LangAS::Default && - (B == LangAS::sycl_private || B == LangAS::sycl_local || - B == LangAS::sycl_global || B == LangAS::sycl_global_device || - B == LangAS::sycl_global_host)) || - // In HIP device compilation, any cuda address space is allowed - // to implicitly cast into the default address space. - (A == LangAS::Default && - (B == LangAS::cuda_constant || B == LangAS::cuda_device || - B == LangAS::cuda_shared)) || - // Conversions from target specific address spaces may be legal - // depending on the target information. - Ctx.getTargetInfo().isAddressSpaceSupersetOf(A, B); +bool Qualifiers::isTargetAddressSpaceSupersetOf(LangAS A, LangAS B, + const ASTContext &Ctx) { + return Ctx.getTargetInfo().isAddressSpaceSupersetOf(A, B); } const IdentifierInfo* QualType::getBaseTypeIdentifier() const { diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h index 3402f32dbde20c..d81b89a7f24ac0 100644 --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -25,26 +25,27 @@ namespace clang { namespace targets { static const unsigned NVPTXAddrSpaceMap[] = { - llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // Default - llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // opencl_global - llvm::NVPTXAS::ADDRESS_SPACE_SHARED, // opencl_local - llvm::NVPTXAS::ADDRESS_SPACE_CONST, // opencl_constant - llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // opencl_private - llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // opencl_generic - llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // opencl_global_device - llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // opencl_global_host - llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // cuda_device - llvm::NVPTXAS::ADDRESS_SPACE_CONST, // cuda_constant - llvm::NVPTXAS::ADDRESS_SPACE_SHARED, // cuda_shared - llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // sycl_global - llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // sycl_global_device - llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // sycl_global_host - llvm::NVPTXAS::ADDRESS_SPACE_SHARED, // sycl_local - llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // sycl_private - llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // ptr32_sptr - llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // ptr32_uptr - llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // ptr64 - llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // hlsl_groupshared + 0, // Default + 1, // opencl_global + 3, // opencl_local + 4, // opencl_constant + 0, // opencl_private + // FIXME: generic has to be added to the target + 0, // opencl_generic + 1, // opencl_global_device + 1, // opencl_global_host + 1, // cuda_device + 4, // cuda_constant + 3, // cuda_shared + 1, // sycl_global + 1, // sycl_global_device + 1, // sycl_global_host + 3, // sycl_local + 0, // sycl_private + 0, // ptr32_sptr + 0, // ptr32_uptr + 0, // ptr64 + 0, // hlsl_groupshared // Wasm address space values for this target are dummy values, // as it is only enabled for Wasm targets. 20, // wasm_funcref >From cea8a75d36d2f3f04719ea167a3105252b434f43 Mon Sep 17 00:00:00 2001 From: Joseph Huber <hube...@outlook.com> Date: Wed, 13 Nov 2024 18:45:52 -0600 Subject: [PATCH 3/3] comments --- clang/include/clang/AST/CanonicalType.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h index 06236861e26d01..6699284d215bd0 100644 --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -30,8 +30,8 @@ namespace clang { template<typename T> class CanProxy; template<typename T> struct CanProxyAdaptor; -class CXXRecordDecl; class ASTContext; +class CXXRecordDecl; class EnumDecl; class Expr; class IdentifierInfo; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits