[clang] b9d678d - [Clang] Use TargetInfo when deciding if an address space is compatible (#115777)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 15 04:58:41 PST 2024
Author: Joseph Huber
Date: 2024-11-15T06:58:36-06:00
New Revision: b9d678d22f74ebd6e34f0a3501fb01d3d80984e7
URL: https://github.com/llvm/llvm-project/commit/b9d678d22f74ebd6e34f0a3501fb01d3d80984e7
DIFF: https://github.com/llvm/llvm-project/commit/b9d678d22f74ebd6e34f0a3501fb01d3d80984e7.diff
LOG: [Clang] Use TargetInfo when deciding if an address space is compatible (#115777)
Summary:
Address spaces are used in several embedded and GPU targets to describe
accesses to different types of memory. Currently we use the address
space enumerations to control which address spaces are considered
supersets of eachother, however this is also a target level property as
described by the C standard's passing mentions. This patch allows the
address space checks to use the target information to decide if a
pointer conversion is legal. For AMDGPU and NVPTX, all supported address
spaces can be converted to the default address space.
More semantic checks can be added on top of this, for now I'm mainly
looking to get more standard semantics working for C/C++. Right now the
address space conversions must all be done explicitly in C/C++ unlike
the offloading languages which define their own custom address spaces
that just map to the same target specific ones anyway. The main question
is if this behavior is a function of the target or the language.
Added:
clang/test/CodeGen/target-addrspace.cpp
clang/test/Sema/amdgcn-address-spaces.c
clang/test/Sema/nvptx-address-spaces.c
Modified:
clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
clang/include/clang/AST/CanonicalType.h
clang/include/clang/AST/Type.h
clang/include/clang/Basic/TargetInfo.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/Type.cpp
clang/lib/Basic/Targets/AMDGPU.h
clang/lib/Basic/Targets/NVPTX.h
clang/lib/Sema/SemaARM.cpp
clang/lib/Sema/SemaCast.cpp
clang/lib/Sema/SemaCodeComplete.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExceptionSpec.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaFixItUtils.cpp
clang/lib/Sema/SemaInit.cpp
clang/lib/Sema/SemaObjC.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
Removed:
################################################################################
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..6699284d215bd0 100644
--- a/clang/include/clang/AST/CanonicalType.h
+++ b/clang/include/clang/AST/CanonicalType.h
@@ -30,6 +30,7 @@ namespace clang {
template<typename T> class CanProxy;
template<typename T> struct CanProxyAdaptor;
+class ASTContext;
class CXXRecordDecl;
class EnumDecl;
class Expr;
@@ -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..42c7e983dc9e6b 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,27 @@ 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) {
+ static bool 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));
+ return A == B || 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.
- 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 +1257,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 +1409,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 +8097,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 2b3552854e1f9b..019ca25bb57ffd 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..7ecb986e4dc2b5 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -73,6 +73,36 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
(hasObjCLifetime() && !Other.hasObjCLifetime()));
}
+bool Qualifiers::isTargetAddressSpaceSupersetOf(LangAS A, LangAS B,
+ const ASTContext &Ctx) {
+ // In OpenCLC v2.0 s6.5.5: every address space except for __constant can be
+ // used as __generic.
+ return (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..d81b89a7f24ac0 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>
@@ -89,6 +90,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 45fc8a6df52d8f..890ca96790acb5 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 5d81d6db5b0e29..a081602e28aa11 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18329,7 +18329,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 c9de7811adfe0a..e142373b1ab4ab 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -8026,9 +8026,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)
@@ -8940,17 +8940,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.
@@ -9137,7 +9137,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;
@@ -10834,7 +10834,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*/
@@ -12365,7 +12366,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 4e3e9681890f58..616481d62de887 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 19d56759246d3e..47462b1a868de6 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
diff erent, 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 89fe4f42afb011..62a0c30d995020 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; }
+
More information about the cfe-commits
mailing list