UnwrappedDestType = Self.Context.getCanonicalType(DestType);
llvm::SmallVector<Qualifiers, 8> cv1, cv2;
- // Find the qualifications.
+ // Find the qualifiers. We only care about cvr-qualifiers for the
+ // purpose of this check, because other qualifiers (address spaces,
+ // Objective-C GC, etc.) are part of the type's identity.
while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) {
Qualifiers SrcQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals);
- cv1.push_back(SrcQuals);
+ cv1.push_back(Qualifiers::fromCVRMask(SrcQuals.getCVRQualifiers()));
Qualifiers DestQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedDestType, DestQuals);
- cv2.push_back(DestQuals);
+ cv2.push_back(Qualifiers::fromCVRMask(DestQuals.getCVRQualifiers()));
}
if (cv1.empty())
return false;
// C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness.
if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away)
<< CT_Dynamic << OrigSrcType << OrigDestType << OpRange;
return;
}
// This is definitely the intended conversion, but it might fail due
// to a const violation.
if (!CStyle && !DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
- msg = diag::err_bad_cxx_cast_const_away;
+ msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
Kind = CK_BitCast;
// Must preserve cv, as always, unless we're in C-style mode.
if (!CStyle && !DestType.isAtLeastAsQualifiedAs(SrcType)) {
- msg = diag::err_bad_cxx_cast_const_away;
+ msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
// Unwrap the pointers. Ignore qualifiers. Terminate early if the types are
// completely equal.
- // FIXME: const_cast should probably not be able to convert between pointers
- // to different address spaces.
// C++ 5.2.11p3 describes the core semantics of const_cast. All cv specifiers
// in multi-level pointers may change, but the level count must be the same,
// as must be the final pointee type.
while (SrcType != DestType &&
Self.Context.UnwrapSimilarPointerTypes(SrcType, DestType)) {
- Qualifiers Quals;
- SrcType = Self.Context.getUnqualifiedArrayType(SrcType, Quals);
- DestType = Self.Context.getUnqualifiedArrayType(DestType, Quals);
+ Qualifiers SrcQuals, DestQuals;
+ SrcType = Self.Context.getUnqualifiedArrayType(SrcType, SrcQuals);
+ DestType = Self.Context.getUnqualifiedArrayType(DestType, DestQuals);
+
+ // const_cast is permitted to strip cvr-qualifiers, only. Make sure that
+ // the other qualifiers (e.g., address spaces) are identical.
+ SrcQuals.removeCVRQualifiers();
+ DestQuals.removeCVRQualifiers();
+ if (SrcQuals != DestQuals)
+ return TC_NotApplicable;
}
// Since we're dealing in canonical types, the remainder must be the same.
// A reinterpret_cast followed by a const_cast can, though, so in C-style,
// we accept it.
if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
- msg = diag::err_bad_cxx_cast_const_away;
+ msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
// C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
// The C-style cast operator can.
if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
- msg = diag::err_bad_cxx_cast_const_away;
+ msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// This test checks for the various conversions and casting operations
+// with address-space-qualified pointers.
+
+struct A { virtual ~A() {} };
+struct B : A { };
+
+typedef void *void_ptr;
+typedef void __attribute__((address_space(1))) *void_ptr_1;
+typedef void __attribute__((address_space(2))) *void_ptr_2;
+
+typedef int *int_ptr;
+typedef int __attribute__((address_space(1))) *int_ptr_1;
+typedef int __attribute__((address_space(2))) *int_ptr_2;
+
+typedef A *A_ptr;
+typedef A __attribute__((address_space(1))) *A_ptr_1;
+typedef A __attribute__((address_space(2))) *A_ptr_2;
+
+typedef B *B_ptr;
+typedef B __attribute__((address_space(1))) *B_ptr_1;
+typedef B __attribute__((address_space(2))) *B_ptr_2;
+
+void test_const_cast(int_ptr ip, int_ptr_1 ip1, int_ptr_2 ip2,
+ A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
+ const int *cip,
+ const int __attribute__((address_space(1))) *cip1) {
+ // Cannot use const_cast to cast between address spaces, add an
+ // address space, or remove an address space.
+ (void)const_cast<int_ptr>(ip1); // expected-error{{is not allowed}}
+ (void)const_cast<int_ptr>(ip2); // expected-error{{is not allowed}}
+ (void)const_cast<int_ptr_1>(ip); // expected-error{{is not allowed}}
+ (void)const_cast<int_ptr_1>(ip2); // expected-error{{is not allowed}}
+ (void)const_cast<int_ptr_2>(ip); // expected-error{{is not allowed}}
+ (void)const_cast<int_ptr_2>(ip1); // expected-error{{is not allowed}}
+
+ (void)const_cast<A_ptr>(ap1); // expected-error{{is not allowed}}
+ (void)const_cast<A_ptr>(ap2); // expected-error{{is not allowed}}
+ (void)const_cast<A_ptr_1>(ap); // expected-error{{is not allowed}}
+ (void)const_cast<A_ptr_1>(ap2); // expected-error{{is not allowed}}
+ (void)const_cast<A_ptr_2>(ap); // expected-error{{is not allowed}}
+ (void)const_cast<A_ptr_2>(ap1); // expected-error{{is not allowed}}
+
+ // It's acceptable to cast away constness.
+ (void)const_cast<int_ptr>(cip);
+ (void)const_cast<int_ptr_1>(cip1);
+}
+
+void test_static_cast(void_ptr vp, void_ptr_1 vp1, void_ptr_2 vp2,
+ A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
+ B_ptr bp, B_ptr_1 bp1, B_ptr_2 bp2) {
+ // Well-formed upcast
+ (void)static_cast<A_ptr>(bp);
+ (void)static_cast<A_ptr_1>(bp1);
+ (void)static_cast<A_ptr_2>(bp2);
+
+ // Well-formed downcast
+ (void)static_cast<B_ptr>(ap);
+ (void)static_cast<B_ptr_1>(ap1);
+ (void)static_cast<B_ptr_2>(ap2);
+
+ // Well-formed cast to/from void
+ (void)static_cast<void_ptr>(ap);
+ (void)static_cast<void_ptr_1>(ap1);
+ (void)static_cast<void_ptr_2>(ap2);
+ (void)static_cast<A_ptr>(vp);
+ (void)static_cast<A_ptr_1>(vp1);
+ (void)static_cast<A_ptr_2>(vp2);
+
+ // Ill-formed upcasts
+ (void)static_cast<A_ptr>(bp1); // expected-error{{is not allowed}}
+ (void)static_cast<A_ptr>(bp2); // expected-error{{is not allowed}}
+ (void)static_cast<A_ptr_1>(bp); // expected-error{{is not allowed}}
+ (void)static_cast<A_ptr_1>(bp2); // expected-error{{is not allowed}}
+ (void)static_cast<A_ptr_2>(bp); // expected-error{{is not allowed}}
+ (void)static_cast<A_ptr_2>(bp1); // expected-error{{is not allowed}}
+
+ // Ill-formed downcasts
+ (void)static_cast<B_ptr>(ap1); // expected-error{{casts away qualifiers}}
+ (void)static_cast<B_ptr>(ap2); // expected-error{{casts away qualifiers}}
+ (void)static_cast<B_ptr_1>(ap); // expected-error{{casts away qualifiers}}
+ (void)static_cast<B_ptr_1>(ap2); // expected-error{{casts away qualifiers}}
+ (void)static_cast<B_ptr_2>(ap); // expected-error{{casts away qualifiers}}
+ (void)static_cast<B_ptr_2>(ap1); // expected-error{{casts away qualifiers}}
+
+ // Ill-formed cast to/from void
+ (void)static_cast<void_ptr>(ap1); // expected-error{{is not allowed}}
+ (void)static_cast<void_ptr>(ap2); // expected-error{{is not allowed}}
+ (void)static_cast<void_ptr_1>(ap); // expected-error{{is not allowed}}
+ (void)static_cast<void_ptr_1>(ap2); // expected-error{{is not allowed}}
+ (void)static_cast<void_ptr_2>(ap); // expected-error{{is not allowed}}
+ (void)static_cast<void_ptr_2>(ap1); // expected-error{{is not allowed}}
+ (void)static_cast<A_ptr>(vp1); // expected-error{{casts away qualifiers}}
+ (void)static_cast<A_ptr>(vp2); // expected-error{{casts away qualifiers}}
+ (void)static_cast<A_ptr_1>(vp); // expected-error{{casts away qualifiers}}
+ (void)static_cast<A_ptr_1>(vp2); // expected-error{{casts away qualifiers}}
+ (void)static_cast<A_ptr_2>(vp); // expected-error{{casts away qualifiers}}
+ (void)static_cast<A_ptr_2>(vp1); // expected-error{{casts away qualifiers}}
+}
+
+void test_dynamic_cast(A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
+ B_ptr bp, B_ptr_1 bp1, B_ptr_2 bp2) {
+ // Well-formed upcast
+ (void)dynamic_cast<A_ptr>(bp);
+ (void)dynamic_cast<A_ptr_1>(bp1);
+ (void)dynamic_cast<A_ptr_2>(bp2);
+
+ // Well-formed downcast
+ (void)dynamic_cast<B_ptr>(ap);
+ (void)dynamic_cast<B_ptr_1>(ap1);
+ (void)dynamic_cast<B_ptr_2>(ap2);
+
+ // Ill-formed upcasts
+ (void)dynamic_cast<A_ptr>(bp1); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<A_ptr>(bp2); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<A_ptr_1>(bp); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<A_ptr_1>(bp2); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<A_ptr_2>(bp); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<A_ptr_2>(bp1); // expected-error{{casts away qualifiers}}
+
+ // Ill-formed downcasts
+ (void)dynamic_cast<B_ptr>(ap1); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<B_ptr>(ap2); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<B_ptr_1>(ap); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<B_ptr_1>(ap2); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<B_ptr_2>(ap); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<B_ptr_2>(ap1); // expected-error{{casts away qualifiers}}
+}
+
+void test_reinterpret_cast(void_ptr vp, void_ptr_1 vp1, void_ptr_2 vp2,
+ A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
+ B_ptr bp, B_ptr_1 bp1, B_ptr_2 bp2,
+ const void __attribute__((address_space(1))) *cvp1) {
+ // reinterpret_cast can be used to cast to a different address space.
+ (void)reinterpret_cast<A_ptr>(ap1);
+ (void)reinterpret_cast<A_ptr>(ap2);
+ (void)reinterpret_cast<A_ptr>(bp);
+ (void)reinterpret_cast<A_ptr>(bp1);
+ (void)reinterpret_cast<A_ptr>(bp2);
+ (void)reinterpret_cast<A_ptr>(vp);
+ (void)reinterpret_cast<A_ptr>(vp1);
+ (void)reinterpret_cast<A_ptr>(vp2);
+ (void)reinterpret_cast<A_ptr_1>(ap);
+ (void)reinterpret_cast<A_ptr_1>(ap2);
+ (void)reinterpret_cast<A_ptr_1>(bp);
+ (void)reinterpret_cast<A_ptr_1>(bp1);
+ (void)reinterpret_cast<A_ptr_1>(bp2);
+ (void)reinterpret_cast<A_ptr_1>(vp);
+ (void)reinterpret_cast<A_ptr_1>(vp1);
+ (void)reinterpret_cast<A_ptr_1>(vp2);
+
+ // ... but don't try to cast away constness!
+ (void)reinterpret_cast<A_ptr_2>(cvp1); // expected-error{{casts away qualifiers}}
+}
+
+void test_cstyle_cast(void_ptr vp, void_ptr_1 vp1, void_ptr_2 vp2,
+ A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
+ B_ptr bp, B_ptr_1 bp1, B_ptr_2 bp2,
+ const void __attribute__((address_space(1))) *cvp1) {
+ // C-style casts are the wild west of casts.
+ (void)(A_ptr)(ap1);
+ (void)(A_ptr)(ap2);
+ (void)(A_ptr)(bp);
+ (void)(A_ptr)(bp1);
+ (void)(A_ptr)(bp2);
+ (void)(A_ptr)(vp);
+ (void)(A_ptr)(vp1);
+ (void)(A_ptr)(vp2);
+ (void)(A_ptr_1)(ap);
+ (void)(A_ptr_1)(ap2);
+ (void)(A_ptr_1)(bp);
+ (void)(A_ptr_1)(bp1);
+ (void)(A_ptr_1)(bp2);
+ (void)(A_ptr_1)(vp);
+ (void)(A_ptr_1)(vp1);
+ (void)(A_ptr_1)(vp2);
+ (void)(A_ptr_2)(cvp1);
+}
+
+void test_implicit_conversion(void_ptr vp, void_ptr_1 vp1, void_ptr_2 vp2,
+ A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
+ B_ptr bp, B_ptr_1 bp1, B_ptr_2 bp2) {
+ // Well-formed conversions
+ void_ptr vpA = ap;
+ void_ptr_1 vp_1A = ap1;
+ void_ptr_2 vp_2A = ap2;
+ A_ptr ap_A = bp;
+ A_ptr_1 ap_A1 = bp1;
+ A_ptr_2 ap_A2 = bp2;
+
+ // Ill-formed conversions
+ void_ptr vpB = ap1; // expected-error{{cannot initialize a variable of type}}
+ void_ptr_1 vp_1B = ap2; // expected-error{{cannot initialize a variable of type}}
+ A_ptr ap_B = bp1; // expected-error{{cannot initialize a variable of type}}
+ A_ptr_1 ap_B1 = bp2; // expected-error{{cannot initialize a variable of type}}
+}