jhuber6 created this revision. jhuber6 added reviewers: rjmccall, ebevhan, jdoerfert, JonChesterfield, aaron.ballman. Herald added subscribers: arichardson, Anastasia. Herald added a project: All. jhuber6 requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Previously, D58346 <https://reviews.llvm.org/D58346> changed the rules to not permit address space casts in C++. The cited reason was that `reinterpret_cast` is not allowed to remove qualifiers, however the standard only explicitly says that `const` and `volatile` qualifiers cannot be removed, see http://eel.is/c++draft/expr.reinterpret.cast#7. The current behaviour is suboptimal as it means there is no way in C++ to change address spaces and we need to rely on unsafe C style casts that aren't permitted by many styles. This patch changes the handling to only apply to OpenCL. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D151087 Files: clang/lib/Sema/SemaCast.cpp clang/test/SemaCXX/address-space-conversion.cpp Index: clang/test/SemaCXX/address-space-conversion.cpp =================================================================== --- clang/test/SemaCXX/address-space-conversion.cpp +++ clang/test/SemaCXX/address-space-conversion.cpp @@ -132,23 +132,23 @@ 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't be used to cast to a different address space unless they are matching (i.e. overlapping). - (void)reinterpret_cast<A_ptr>(ap1); // expected-error{{reinterpret_cast from 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') to 'A_ptr' (aka 'A *') is not allowed}} - (void)reinterpret_cast<A_ptr>(ap2); // expected-error{{reinterpret_cast from 'A_ptr_2' (aka '__attribute__((address_space(2))) A *') to 'A_ptr' (aka 'A *') is not allowed}} + // 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); // expected-error{{reinterpret_cast from 'B_ptr_1' (aka '__attribute__((address_space(1))) B *') to 'A_ptr' (aka 'A *') is not allowed}} - (void)reinterpret_cast<A_ptr>(bp2); // expected-error{{reinterpret_cast from 'B_ptr_2' (aka '__attribute__((address_space(2))) B *') to 'A_ptr' (aka 'A *') is not allowed}} + (void)reinterpret_cast<A_ptr>(bp1); + (void)reinterpret_cast<A_ptr>(bp2); (void)reinterpret_cast<A_ptr>(vp); - (void)reinterpret_cast<A_ptr>(vp1); // expected-error{{reinterpret_cast from 'void_ptr_1' (aka '__attribute__((address_space(1))) void *') to 'A_ptr' (aka 'A *') is not allowed}} - (void)reinterpret_cast<A_ptr>(vp2); // expected-error{{reinterpret_cast from 'void_ptr_2' (aka '__attribute__((address_space(2))) void *') to 'A_ptr' (aka 'A *') is not allowed}} - (void)reinterpret_cast<A_ptr_1>(ap); // expected-error{{reinterpret_cast from 'A_ptr' (aka 'A *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} - (void)reinterpret_cast<A_ptr_1>(ap2); // expected-error{{reinterpret_cast from 'A_ptr_2' (aka '__attribute__((address_space(2))) A *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} - (void)reinterpret_cast<A_ptr_1>(bp); // expected-error{{reinterpret_cast from 'B_ptr' (aka 'B *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} + (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); // expected-error{{reinterpret_cast from 'B_ptr_2' (aka '__attribute__((address_space(2))) B *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} - (void)reinterpret_cast<A_ptr_1>(vp); // expected-error{{reinterpret_cast from 'void_ptr' (aka 'void *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} + (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); // expected-error{{reinterpret_cast from 'void_ptr_2' (aka '__attribute__((address_space(2))) void *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} + (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}} Index: clang/lib/Sema/SemaCast.cpp =================================================================== --- clang/lib/Sema/SemaCast.cpp +++ clang/lib/Sema/SemaCast.cpp @@ -2481,7 +2481,11 @@ if (IsAddressSpaceConversion(SrcType, DestType)) { Kind = CK_AddressSpaceConversion; assert(SrcType->isPointerType() && DestType->isPointerType()); + // C++ 7.6.1.10: The reinterpret_cast operator is only forbidden from + // casting away constness or volatile qualifiers. We permit changing the + // the address space qualifier in C++ while OpenCL uses more strict rules. if (!CStyle && + (Self.getLangOpts().OpenCL || Self.getLangOpts().OpenCLCPlusPlus) && !DestType->getPointeeType().getQualifiers().isAddressSpaceSupersetOf( SrcType->getPointeeType().getQualifiers())) { SuccessResult = TC_Failed;
Index: clang/test/SemaCXX/address-space-conversion.cpp =================================================================== --- clang/test/SemaCXX/address-space-conversion.cpp +++ clang/test/SemaCXX/address-space-conversion.cpp @@ -132,23 +132,23 @@ 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't be used to cast to a different address space unless they are matching (i.e. overlapping). - (void)reinterpret_cast<A_ptr>(ap1); // expected-error{{reinterpret_cast from 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') to 'A_ptr' (aka 'A *') is not allowed}} - (void)reinterpret_cast<A_ptr>(ap2); // expected-error{{reinterpret_cast from 'A_ptr_2' (aka '__attribute__((address_space(2))) A *') to 'A_ptr' (aka 'A *') is not allowed}} + // 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); // expected-error{{reinterpret_cast from 'B_ptr_1' (aka '__attribute__((address_space(1))) B *') to 'A_ptr' (aka 'A *') is not allowed}} - (void)reinterpret_cast<A_ptr>(bp2); // expected-error{{reinterpret_cast from 'B_ptr_2' (aka '__attribute__((address_space(2))) B *') to 'A_ptr' (aka 'A *') is not allowed}} + (void)reinterpret_cast<A_ptr>(bp1); + (void)reinterpret_cast<A_ptr>(bp2); (void)reinterpret_cast<A_ptr>(vp); - (void)reinterpret_cast<A_ptr>(vp1); // expected-error{{reinterpret_cast from 'void_ptr_1' (aka '__attribute__((address_space(1))) void *') to 'A_ptr' (aka 'A *') is not allowed}} - (void)reinterpret_cast<A_ptr>(vp2); // expected-error{{reinterpret_cast from 'void_ptr_2' (aka '__attribute__((address_space(2))) void *') to 'A_ptr' (aka 'A *') is not allowed}} - (void)reinterpret_cast<A_ptr_1>(ap); // expected-error{{reinterpret_cast from 'A_ptr' (aka 'A *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} - (void)reinterpret_cast<A_ptr_1>(ap2); // expected-error{{reinterpret_cast from 'A_ptr_2' (aka '__attribute__((address_space(2))) A *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} - (void)reinterpret_cast<A_ptr_1>(bp); // expected-error{{reinterpret_cast from 'B_ptr' (aka 'B *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} + (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); // expected-error{{reinterpret_cast from 'B_ptr_2' (aka '__attribute__((address_space(2))) B *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} - (void)reinterpret_cast<A_ptr_1>(vp); // expected-error{{reinterpret_cast from 'void_ptr' (aka 'void *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} + (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); // expected-error{{reinterpret_cast from 'void_ptr_2' (aka '__attribute__((address_space(2))) void *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} + (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}} Index: clang/lib/Sema/SemaCast.cpp =================================================================== --- clang/lib/Sema/SemaCast.cpp +++ clang/lib/Sema/SemaCast.cpp @@ -2481,7 +2481,11 @@ if (IsAddressSpaceConversion(SrcType, DestType)) { Kind = CK_AddressSpaceConversion; assert(SrcType->isPointerType() && DestType->isPointerType()); + // C++ 7.6.1.10: The reinterpret_cast operator is only forbidden from + // casting away constness or volatile qualifiers. We permit changing the + // the address space qualifier in C++ while OpenCL uses more strict rules. if (!CStyle && + (Self.getLangOpts().OpenCL || Self.getLangOpts().OpenCLCPlusPlus) && !DestType->getPointeeType().getQualifiers().isAddressSpaceSupersetOf( SrcType->getPointeeType().getQualifiers())) { SuccessResult = TC_Failed;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits