yaxunl updated this revision to Diff 49232.
yaxunl marked 7 inline comments as done.
yaxunl added a comment.
Revised as Anastasis suggested.
Modified mergeTypes() for un-handled case.
Separate sema tests for condition operator to a new file.
Repository:
rL LLVM
http://reviews.llvm.org/D17412
Files:
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/ASTContext.cpp
lib/Sema/SemaExpr.cpp
test/CodeGenOpenCL/address-spaces-conversions.cl
test/SemaOpenCL/condition-operator-cl2.0.cl
Index: test/SemaOpenCL/condition-operator-cl2.0.cl
===================================================================
--- /dev/null
+++ test/SemaOpenCL/condition-operator-cl2.0.cl
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DCONSTANT -cl-std=CL2.0
+// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DGLOBAL -cl-std=CL2.0
+// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DGENERIC -cl-std=CL2.0
+
+// Testing conditional operator with second and third operands of pointer types.
+
+#ifdef GENERIC
+#define AS generic
+#endif
+
+#ifdef GLOBAL
+#define AS global
+#endif
+
+#ifdef CONSTANT
+#define AS constant
+#endif
+
+void test_conversion(global int *arg_glob, local int *arg_loc,
+ constant int *arg_const, private int *arg_priv,
+ generic int *arg_gen, global char *arg_glob_ch,
+ local char *arg_loc_ch, constant char *arg_const_ch,
+ private char *arg_priv_ch, generic char *arg_gen_ch) {
+
+ AS int *var_cond;
+ arg_gen = 0 ? var_cond : arg_glob;
+#ifdef CONSTANT
+// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__global int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ arg_gen = 0 ? var_cond : arg_loc;
+#ifdef CONSTANT
+// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__local int *') which are pointers to non-overlapping address spaces}}
+#elif defined(GLOBAL)
+// expected-error@-4{{conditional operator with the second and third operands of type ('__global int *' and '__local int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ var_cond = 0 ? var_cond : arg_const;
+#ifdef GENERIC
+// expected-error@-2{{conditional operator with the second and third operands of type ('__generic int *' and '__constant int *') which are pointers to non-overlapping address spaces}}
+#elif defined(GLOBAL)
+// expected-error@-4{{conditional operator with the second and third operands of type ('__global int *' and '__constant int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ arg_gen = 0 ? var_cond : arg_priv;
+#ifdef CONSTANT
+// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and 'int *') which are pointers to non-overlapping address spaces}}
+#elif defined(GLOBAL)
+// expected-error@-4{{conditional operator with the second and third operands of type ('__global int *' and 'int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ arg_gen = 0 ? var_cond : arg_gen;
+#ifdef CONSTANT
+// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__generic int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ void *var_void_gen;
+ constant void*var_void_const;
+ var_void_gen = 0 ? var_cond : arg_glob_ch;
+#ifdef CONSTANT
+// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__global char *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ var_void_gen = 0 ? var_cond : arg_loc_ch;
+#ifdef CONSTANT
+// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__local char *') which are pointers to non-overlapping address spaces}}
+#elif defined(GLOBAL)
+// expected-error@-4{{conditional operator with the second and third operands of type ('__global int *' and '__local char *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ var_void_const = 0 ? var_cond : arg_const_ch;
+#ifdef GENERIC
+// expected-error@-2{{conditional operator with the second and third operands of type ('__generic int *' and '__constant char *') which are pointers to non-overlapping address spaces}}
+#elif defined(GLOBAL)
+// expected-error@-4{{conditional operator with the second and third operands of type ('__global int *' and '__constant char *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ var_void_gen = 0 ? var_cond : arg_priv_ch;
+#ifdef CONSTANT
+// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and 'char *') which are pointers to non-overlapping address spaces}}
+#elif defined(GLOBAL)
+// expected-error@-4{{conditional operator with the second and third operands of type ('__global int *' and 'char *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ var_void_gen = 0 ? var_cond : arg_gen_ch;
+#ifdef CONSTANT
+// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__generic char *') which are pointers to non-overlapping address spaces}}
+#endif
+}
Index: test/CodeGenOpenCL/address-spaces-conversions.cl
===================================================================
--- test/CodeGenOpenCL/address-spaces-conversions.cl
+++ test/CodeGenOpenCL/address-spaces-conversions.cl
@@ -3,20 +3,35 @@
// test that we generate address space casts everywhere we need conversions of
// pointers to different address spaces
-void test(global int *arg_glob, generic int *arg_gen) {
+void test(global int *arg_glob, generic int *arg_gen, global float *arg_glob_f,
+ generic void *arg_gen_v) {
int var_priv;
+
arg_gen = arg_glob; // implicit cast global -> generic
// CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(4)*
+
arg_gen = &var_priv; // implicit cast with obtaining adr, private -> generic
// CHECK: %{{[0-9]+}} = addrspacecast i32* %var_priv to i32 addrspace(4)*
+
arg_glob = (global int *)arg_gen; // explicit cast
// CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(4)* %{{[0-9]+}} to i32 addrspace(1)*
+
global int *var_glob =
(global int *)arg_glob; // explicit cast in the same address space
// CHECK-NOT: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(1)*
+
var_priv = arg_gen - arg_glob; // arithmetic operation
// CHECK: %{{.*}} = ptrtoint i32 addrspace(4)* %{{.*}} to i64
// CHECK: %{{.*}} = ptrtoint i32 addrspace(1)* %{{.*}} to i64
+
var_priv = arg_gen > arg_glob; // comparison
// CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(4)*
+
+ // condition operator
+ arg_gen = arg_glob ? arg_gen : arg_glob; // operands of overlapping addr spaces and the same type
+ // CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(4)*
+
+ arg_gen_v = arg_glob ? arg_gen : arg_glob_f; // operands of overlapping addr spaces and different types
+ // CHECK: %{{[0-9]+}} = bitcast i32 addrspace(4)* %{{[0-9]+}} to i8 addrspace(4)*
+ // CHECK: %{{[0-9]+}} = addrspacecast float addrspace(1)* %{{[0-9]+}} to i8 addrspace(4)*
}
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -171,7 +171,6 @@
// Don't do this for enums, they can't be redeclared.
if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D))
break;
-
bool Warn = !AA->isInherited();
// Objective-C method declarations in categories are not modelled as
// redeclarations, so manually look for a redeclaration in a category
@@ -6168,27 +6167,69 @@
QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee);
if (CompositeTy.isNull()) {
- S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers)
- << LHSTy << RHSTy << LHS.get()->getSourceRange()
- << RHS.get()->getSourceRange();
// In this situation, we assume void* type. No especially good
// reason, but this is what gcc does, and we do have to pick
// to get a consistent AST.
- QualType incompatTy = S.Context.getPointerType(S.Context.VoidTy);
- LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast);
+ QualType incompatTy;
+ if (S.getLangOpts().OpenCL) {
+ // OpenCL v1.1 s6.5 - A pointer to address space A can only be assigned
+ // to a pointer to the same address space A. Casting a pointer to address
+ // space A to a pointer to address space B is illegal.
+ // OpenCL v2.0 s6.5.6 - Clause 6.5.15 Conditional operator, add another
+ // constraint paragraph: If the second and third operands are pointers
+ // into different address spaces, the address spaces must overlap.
+ unsigned ResultAddrSpace;
+ if (lhQual.isAddressSpaceSupersetOf(rhQual)) {
+ ResultAddrSpace = lhQual.getAddressSpace();
+ } else if (rhQual.isAddressSpaceSupersetOf(lhQual)) {
+ ResultAddrSpace = rhQual.getAddressSpace();
+ } else {
+ S.Diag(Loc,
+ diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
+ << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ return QualType();
+ }
+
+ incompatTy = S.Context.getPointerType(
+ S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace));
+ LHS = S.ImpCastExprToType(LHS.get(), incompatTy,
+ (lhQual.getAddressSpace() != ResultAddrSpace)
+ ? CK_AddressSpaceConversion
+ : CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.get(), incompatTy,
+ (rhQual.getAddressSpace() != ResultAddrSpace)
+ ? CK_AddressSpaceConversion
+ : CK_BitCast);
+ } else {
+ S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers)
+ << LHSTy << RHSTy << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ incompatTy = S.Context.getPointerType(S.Context.VoidTy);
+ LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast);
+ }
return incompatTy;
}
// The pointer types are compatible.
QualType ResultTy = CompositeTy.withCVRQualifiers(MergedCVRQual);
+ auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast;
if (IsBlockPointer)
ResultTy = S.Context.getBlockPointerType(ResultTy);
- else
+ else {
+ auto ResultAddrSpace = ResultTy.getQualifiers().getAddressSpace();
+ LHSCastKind = lhQual.getAddressSpace() == ResultAddrSpace
+ ? CK_BitCast
+ : CK_AddressSpaceConversion;
+ RHSCastKind = rhQual.getAddressSpace() == ResultAddrSpace
+ ? CK_BitCast
+ : CK_AddressSpaceConversion;
ResultTy = S.Context.getPointerType(ResultTy);
+ }
- LHS = S.ImpCastExprToType(LHS.get(), ResultTy, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.get(), ResultTy, CK_BitCast);
+ LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind);
+ RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind);
return ResultTy;
}
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -7609,6 +7609,15 @@
Qualifiers LQuals = LHSCan.getLocalQualifiers();
Qualifiers RQuals = RHSCan.getLocalQualifiers();
if (LQuals != RQuals) {
+ if (getLangOpts().OpenCL) {
+ if (LHS.getUnqualifiedType() != RHS.getUnqualifiedType() ||
+ LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers())
+ return QualType();
+ if (LQuals.isAddressSpaceSupersetOf(RQuals))
+ return LHS;
+ if (RQuals.isAddressSpaceSupersetOf(LQuals))
+ return RHS;
+ }
// If any of these qualifiers are different, we have a type
// mismatch.
if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() ||
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -5325,7 +5325,9 @@
"composite pointer type %2">, InGroup<CompareDistinctPointerType>;
def err_typecheck_op_on_nonoverlapping_address_space_pointers : Error<
"%select{comparison between %diff{ ($ and $)|}0,1"
- "|arithmetic operation with operands of type %diff{ ($ and $)|}0,1}2"
+ "|arithmetic operation with operands of type %diff{ ($ and $)|}0,1"
+ "|conditional operator with the second and third operands of type "
+ "%diff{ ($ and $)|}0,1}2"
" which are pointers to non-overlapping address spaces">;
def err_typecheck_assign_const : Error<
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits