diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2018-07-11 00:19:19 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2018-07-11 00:19:19 +0000 |
commit | 295c88685f7c285358db0d83f1fc315ac23677e3 (patch) | |
tree | 054f8c88ea571d0fddb19dcb52bc312451994ba2 /lib/Sema/SemaCast.cpp | |
parent | 3c6b78637e54fd4bc2f6413e2f34439b51da65fa (diff) | |
download | clang-295c88685f7c285358db0d83f1fc315ac23677e3.tar.gz |
DR330: look through array types when forming the cv-decomposition of a type.
This allows more qualification conversions, eg. conversion from
'int *(*)[]' -> 'const int *const (*)[]'
is now permitted, along with all the consequences of that: more types
are similar, more cases are permitted by const_cast, and conversely,
fewer "casting away constness" cases are permitted by reinterpret_cast.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@336745 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaCast.cpp')
-rw-r--r-- | lib/Sema/SemaCast.cpp | 58 |
1 files changed, 28 insertions, 30 deletions
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index a2e2950556..ec95032c4e 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -456,12 +456,16 @@ enum CastAwayConstnessKind { /// Unwrap one level of types for CastsAwayConstness. /// -/// Like Sema::UnwrapSimilarPointerTypes, this removes one level of -/// indirection from both types, provided that they're both pointer-like. -/// Unlike the Sema function, doesn't care if the unwrapped pieces are related. +/// Like Sema::UnwrapSimilarTypes, this removes one level of indirection from +/// both types, provided that they're both pointer-like or array-like. Unlike +/// the Sema function, doesn't care if the unwrapped pieces are related. static CastAwayConstnessKind unwrapCastAwayConstnessLevel(ASTContext &Context, QualType &T1, QualType &T2) { - if (Context.UnwrapSimilarPointerTypes(T1, T2)) + // Note, even if this returns false, it may have unwrapped some number of + // matching "array of" pieces. That's OK, we don't need to check their + // cv-qualifiers (that check is covered by checking the qualifiers on the + // array types themselves). + if (Context.UnwrapSimilarTypes(T1, T2)) return CastAwayConstnessKind::CACK_Similar; // Special case: if the destination type is a reference type, unwrap it as @@ -473,8 +477,11 @@ unwrapCastAwayConstnessLevel(ASTContext &Context, QualType &T1, QualType &T2) { auto Classify = [](QualType T) { if (T->isAnyPointerType()) return 1; - if (T->getAs<MemberPointerType>()) return 2; - if (T->getAs<BlockPointerType>()) return 3; + if (T->isMemberPointerType()) return 2; + if (T->isBlockPointerType()) return 3; + // We somewhat-arbitrarily don't look through VLA types here. This is at + // least consistent with the behavior of UnwrapSimilarTypes. + if (T->isConstantArrayType() || T->isIncompleteArrayType()) return 4; return 0; }; @@ -486,8 +493,14 @@ unwrapCastAwayConstnessLevel(ASTContext &Context, QualType &T1, QualType &T2) { if (!T2Class) return CastAwayConstnessKind::CACK_None; - T1 = T1->getPointeeType(); - T2 = T2->getPointeeType(); + auto Unwrap = [&](QualType T) { + if (auto *AT = Context.getAsArrayType(T)) + return AT->getElementType(); + return T->getPointeeType(); + }; + + T1 = Unwrap(T1); + T2 = Unwrap(T2); return T1Class == T2Class ? CastAwayConstnessKind::CACK_SimilarKind : CastAwayConstnessKind::CACK_Incoherent; } @@ -1674,29 +1687,14 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr, msg = diag::err_bad_const_cast_dest; return TC_NotApplicable; } - SrcType = Self.Context.getCanonicalType(SrcType); - // Unwrap the pointers. Ignore qualifiers. Terminate early if the types are - // completely equal. - // 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 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. - if (SrcType != DestType) + // C++ [expr.const.cast]p3: + // "For two similar types T1 and T2, [...]" + // + // We only allow a const_cast to change cvr-qualifiers, not other kinds of + // type qualifiers. (Likewise, we ignore other changes when determining + // whether a cast casts away constness.) + if (!Self.Context.hasCvrSimilarType(SrcType, DestType)) return TC_NotApplicable; if (NeedToMaterializeTemporary) |