diff options
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaCXXCast.cpp | 33 | ||||
| -rw-r--r-- | clang/test/SemaCXX/address-space-conversion.cpp | 197 | ||||
| -rw-r--r-- | clang/test/SemaCXX/reinterpret-cast.cpp | 8 | ||||
| -rw-r--r-- | clang/test/SemaCXX/static-cast.cpp | 6 | ||||
| -rw-r--r-- | clang/test/SemaTemplate/instantiate-cast.cpp | 2 |
6 files changed, 227 insertions, 23 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 747a657a4b2..40f0fc091b0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2839,9 +2839,9 @@ def err_bad_cxx_cast_generic : Error< def err_bad_cxx_cast_rvalue : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from rvalue to reference type %2">; -def err_bad_cxx_cast_const_away : Error< +def err_bad_cxx_cast_qualifiers_away : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" - "functional-style cast}0 from %1 to %2 casts away constness">; + "functional-style cast}0 from %1 to %2 casts away qualifiers">; def err_bad_const_cast_dest : Error< "%select{const_cast||||C-style cast|functional-style cast}0 to %2, " "which is not a reference, pointer-to-object, or pointer-to-data-member">; diff --git a/clang/lib/Sema/SemaCXXCast.cpp b/clang/lib/Sema/SemaCXXCast.cpp index 31a772a5d8e..a27a5debec9 100644 --- a/clang/lib/Sema/SemaCXXCast.cpp +++ b/clang/lib/Sema/SemaCXXCast.cpp @@ -390,15 +390,17 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { 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; @@ -510,7 +512,7 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, // 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; } @@ -792,7 +794,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, // 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; @@ -983,7 +985,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, // 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; } @@ -1261,16 +1263,21 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, // 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. @@ -1345,7 +1352,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // 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; } @@ -1458,7 +1465,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // 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; } diff --git a/clang/test/SemaCXX/address-space-conversion.cpp b/clang/test/SemaCXX/address-space-conversion.cpp new file mode 100644 index 00000000000..d21d4194235 --- /dev/null +++ b/clang/test/SemaCXX/address-space-conversion.cpp @@ -0,0 +1,197 @@ +// 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}} +} diff --git a/clang/test/SemaCXX/reinterpret-cast.cpp b/clang/test/SemaCXX/reinterpret-cast.cpp index 74dbc01ee5a..9e5211cb1b2 100644 --- a/clang/test/SemaCXX/reinterpret-cast.cpp +++ b/clang/test/SemaCXX/reinterpret-cast.cpp @@ -45,9 +45,9 @@ void constness() // Valid: T1* -> T2 const* int const *icp = reinterpret_cast<int const*>(ipppc); // Invalid: T1 const* -> T2* - (void)reinterpret_cast<int*>(icp); // expected-error {{reinterpret_cast from 'const int *' to 'int *' casts away constness}} + (void)reinterpret_cast<int*>(icp); // expected-error {{reinterpret_cast from 'const int *' to 'int *' casts away qualifiers}} // Invalid: T1*** -> T2 const* const** - int const *const **icpcpp = reinterpret_cast<int const* const**>(ipppc); // expected-error {{reinterpret_cast from 'int ***' to 'const int *const **' casts away constness}} + int const *const **icpcpp = reinterpret_cast<int const* const**>(ipppc); // expected-error {{reinterpret_cast from 'int ***' to 'const int *const **' casts away qualifiers}} // Valid: T1* -> T2* int *ip = reinterpret_cast<int*>(icpcpp); // Valid: T* -> T const* @@ -77,7 +77,7 @@ void memptrs() { const int structure::*psi = 0; (void)reinterpret_cast<const float structure::*>(psi); - (void)reinterpret_cast<int structure::*>(psi); // expected-error {{reinterpret_cast from 'const int structure::*' to 'int structure::*' casts away constness}} + (void)reinterpret_cast<int structure::*>(psi); // expected-error {{reinterpret_cast from 'const int structure::*' to 'int structure::*' casts away qualifiers}} void (structure::*psf)() = 0; (void)reinterpret_cast<int (structure::*)()>(psf); @@ -105,6 +105,6 @@ void const_arrays() { const STRING *s; const char *c; - (void)reinterpret_cast<char *>(s); // expected-error {{reinterpret_cast from 'const STRING *' (aka 'char const (*)[10]') to 'char *' casts away constness}} + (void)reinterpret_cast<char *>(s); // expected-error {{reinterpret_cast from 'const STRING *' (aka 'char const (*)[10]') to 'char *' casts away qualifiers}} (void)reinterpret_cast<const STRING *>(c); } diff --git a/clang/test/SemaCXX/static-cast.cpp b/clang/test/SemaCXX/static-cast.cpp index 46c6eee2c4e..7fb016ea86d 100644 --- a/clang/test/SemaCXX/static-cast.cpp +++ b/clang/test/SemaCXX/static-cast.cpp @@ -84,8 +84,8 @@ void t_529_5_8() (void)static_cast<C1&>(*((A*)0)); // expected-error {{cannot cast 'A' to 'C1 &' via virtual base 'B'}} (void)static_cast<D*>((A*)0); // expected-error {{cannot cast 'A *' to 'D *' via virtual base 'B'}} (void)static_cast<D&>(*((A*)0)); // expected-error {{cannot cast 'A' to 'D &' via virtual base 'B'}} - (void)static_cast<B*>((const A*)0); // expected-error {{static_cast from 'const A *' to 'B *' casts away constness}} - (void)static_cast<B&>(*((const A*)0)); // expected-error {{static_cast from 'const A' to 'B &' casts away constness}} + (void)static_cast<B*>((const A*)0); // expected-error {{static_cast from 'const A *' to 'B *' casts away qualifiers}} + (void)static_cast<B&>(*((const A*)0)); // expected-error {{static_cast from 'const A' to 'B &' casts away qualifiers}} (void)static_cast<E*>((A*)0); // expected-error {{cannot cast private base class 'A' to 'E'}} (void)static_cast<E&>(*((A*)0)); // expected-error {{cannot cast private base class 'A' to 'E'}} (void)static_cast<H*>((A*)0); // expected-error {{ambiguous cast from base 'A' to derived 'H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}} @@ -119,7 +119,7 @@ void t_529_10() // Bad code below - (void)static_cast<int*>((const void*)0); // expected-error {{static_cast from 'const void *' to 'int *' casts away constness}} + (void)static_cast<int*>((const void*)0); // expected-error {{static_cast from 'const void *' to 'int *' casts away qualifiers}} (void)static_cast<void (*)()>((void*)0); // expected-error {{static_cast from 'void *' to 'void (*)()' is not allowed}} } diff --git a/clang/test/SemaTemplate/instantiate-cast.cpp b/clang/test/SemaTemplate/instantiate-cast.cpp index abf1b3c31d7..b3babf12981 100644 --- a/clang/test/SemaTemplate/instantiate-cast.cpp +++ b/clang/test/SemaTemplate/instantiate-cast.cpp @@ -63,7 +63,7 @@ template struct DynamicCast0<Base*, A>; // expected-note{{instantiation}} template<typename T, typename U> struct ReinterpretCast0 { void f(T t) { - (void)reinterpret_cast<U>(t); // expected-error{{constness}} + (void)reinterpret_cast<U>(t); // expected-error{{qualifiers}} } }; |

