diff options
author | John McCall <rjmccall@apple.com> | 2011-10-11 17:38:55 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-10-11 17:38:55 +0000 |
commit | d8d3ced6f5d7fa55272194b7165a2321a3be31dc (patch) | |
tree | 48cc85a5b0d5753382d5461020c62694909879b5 /lib/Sema/SemaCXXCast.cpp | |
parent | e1677d97281d7e5059e15ed456e03cb02e475f08 (diff) |
Rename SemaCXXCast.cpp to SemaCast.cpp.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141686 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaCXXCast.cpp')
-rw-r--r-- | lib/Sema/SemaCXXCast.cpp | 2062 |
1 files changed, 0 insertions, 2062 deletions
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp deleted file mode 100644 index 1f386388be..0000000000 --- a/lib/Sema/SemaCXXCast.cpp +++ /dev/null @@ -1,2062 +0,0 @@ -//===--- SemaCXXCast.cpp - Semantic Analysis for Casts --------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements semantic analysis for casts. -// -//===----------------------------------------------------------------------===// - -#include "clang/Sema/SemaInternal.h" -#include "clang/Sema/Initialization.h" -#include "clang/AST/ExprCXX.h" -#include "clang/AST/ExprObjC.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/CXXInheritance.h" -#include "clang/Basic/PartialDiagnostic.h" -#include "llvm/ADT/SmallVector.h" -#include <set> -using namespace clang; - - - -enum TryCastResult { - TC_NotApplicable, ///< The cast method is not applicable. - TC_Success, ///< The cast method is appropriate and successful. - TC_Failed ///< The cast method is appropriate, but failed. A - ///< diagnostic has been emitted. -}; - -enum CastType { - CT_Const, ///< const_cast - CT_Static, ///< static_cast - CT_Reinterpret, ///< reinterpret_cast - CT_Dynamic, ///< dynamic_cast - CT_CStyle, ///< (Type)expr - CT_Functional ///< Type(expr) -}; - -namespace { - struct CastOperation { - CastOperation(Sema &S, QualType destType, ExprResult src) - : Self(S), SrcExpr(src), DestType(destType), - ResultType(destType.getNonLValueExprType(S.Context)), - ValueKind(Expr::getValueKindForType(destType)), - Kind(CK_Dependent), IsARCUnbridgedCast(false) { - - if (const BuiltinType *placeholder = - src.get()->getType()->getAsPlaceholderType()) { - PlaceholderKind = placeholder->getKind(); - } else { - PlaceholderKind = (BuiltinType::Kind) 0; - } - } - - Sema &Self; - ExprResult SrcExpr; - QualType DestType; - QualType ResultType; - ExprValueKind ValueKind; - CastKind Kind; - bool IsARCUnbridgedCast; - BuiltinType::Kind PlaceholderKind; - CXXCastPath BasePath; - - SourceRange OpRange; - SourceRange DestRange; - - // Top-level semantics-checking routines. - void CheckConstCast(); - void CheckReinterpretCast(); - void CheckStaticCast(); - void CheckDynamicCast(); - void CheckCXXCStyleCast(bool FunctionalCast); - void CheckCStyleCast(); - - // Internal convenience methods. - - /// Try to handle the given placeholder expression kind. Return - /// true if the source expression has the appropriate placeholder - /// kind. A placeholder can only be claimed once. - bool claimPlaceholder(BuiltinType::Kind K) { - if (PlaceholderKind != K) return false; - - PlaceholderKind = (BuiltinType::Kind) 0; - return true; - } - - bool isPlaceholder() const { - return PlaceholderKind != 0; - } - bool isPlaceholder(BuiltinType::Kind K) const { - return PlaceholderKind == K; - } - - void checkCastAlign() { - Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); - } - - void checkObjCARCConversion(Sema::CheckedConversionKind CCK) { - Expr *src = SrcExpr.get(); - Self.CheckObjCARCConversion(OpRange, DestType, src, CCK); - SrcExpr = src; - } - - /// Check for and handle non-overload placeholder expressions. - void checkNonOverloadPlaceholders() { - if (!isPlaceholder() || isPlaceholder(BuiltinType::Overload)) - return; - - SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take()); - if (SrcExpr.isInvalid()) - return; - PlaceholderKind = (BuiltinType::Kind) 0; - } - }; -} - -static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, - bool CheckCVR, bool CheckObjCLifetime); - -// The Try functions attempt a specific way of casting. If they succeed, they -// return TC_Success. If their way of casting is not appropriate for the given -// arguments, they return TC_NotApplicable and *may* set diag to a diagnostic -// to emit if no other way succeeds. If their way of casting is appropriate but -// fails, they return TC_Failed and *must* set diag; they can set it to 0 if -// they emit a specialized diagnostic. -// All diagnostics returned by these functions must expect the same three -// arguments: -// %0: Cast Type (a value from the CastType enumeration) -// %1: Source Type -// %2: Destination Type -static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, - QualType DestType, bool CStyle, - CastKind &Kind, - CXXCastPath &BasePath, - unsigned &msg); -static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, - QualType DestType, bool CStyle, - const SourceRange &OpRange, - unsigned &msg, - CastKind &Kind, - CXXCastPath &BasePath); -static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType, - QualType DestType, bool CStyle, - const SourceRange &OpRange, - unsigned &msg, - CastKind &Kind, - CXXCastPath &BasePath); -static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType, - CanQualType DestType, bool CStyle, - const SourceRange &OpRange, - QualType OrigSrcType, - QualType OrigDestType, unsigned &msg, - CastKind &Kind, - CXXCastPath &BasePath); -static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, - QualType SrcType, - QualType DestType,bool CStyle, - const SourceRange &OpRange, - unsigned &msg, - CastKind &Kind, - CXXCastPath &BasePath); - -static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, - QualType DestType, - Sema::CheckedConversionKind CCK, - const SourceRange &OpRange, - unsigned &msg, - CastKind &Kind); -static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, - QualType DestType, - Sema::CheckedConversionKind CCK, - const SourceRange &OpRange, - unsigned &msg, - CastKind &Kind, - CXXCastPath &BasePath); -static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, - bool CStyle, unsigned &msg); -static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, - QualType DestType, bool CStyle, - const SourceRange &OpRange, - unsigned &msg, - CastKind &Kind); - - -/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. -ExprResult -Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, - SourceLocation LAngleBracketLoc, Declarator &D, - SourceLocation RAngleBracketLoc, - SourceLocation LParenLoc, Expr *E, - SourceLocation RParenLoc) { - - assert(!D.isInvalidType()); - - TypeSourceInfo *TInfo = GetTypeForDeclaratorCast(D, E->getType()); - if (D.isInvalidType()) - return ExprError(); - - if (getLangOptions().CPlusPlus) { - // Check that there are no default arguments (C++ only). - CheckExtraCXXDefaultArguments(D); - } - - return BuildCXXNamedCast(OpLoc, Kind, TInfo, move(E), - SourceRange(LAngleBracketLoc, RAngleBracketLoc), - SourceRange(LParenLoc, RParenLoc)); -} - -ExprResult -Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, - TypeSourceInfo *DestTInfo, Expr *E, - SourceRange AngleBrackets, SourceRange Parens) { - ExprResult Ex = Owned(E); - QualType DestType = DestTInfo->getType(); - - // If the type is dependent, we won't do the semantic analysis now. - // FIXME: should we check this in a more fine-grained manner? - bool TypeDependent = DestType->isDependentType() || Ex.get()->isTypeDependent(); - - CastOperation Op(*this, DestType, E); - Op.OpRange = SourceRange(OpLoc, Parens.getEnd()); - Op.DestRange = AngleBrackets; - - switch (Kind) { - default: llvm_unreachable("Unknown C++ cast!"); - - case tok::kw_const_cast: - if (!TypeDependent) { - Op.CheckConstCast(); - if (Op.SrcExpr.isInvalid()) - return ExprError(); - } - return Owned(CXXConstCastExpr::Create(Context, Op.ResultType, Op.ValueKind, - Op.SrcExpr.take(), DestTInfo, OpLoc, - Parens.getEnd())); - - case tok::kw_dynamic_cast: { - if (!TypeDependent) { - Op.CheckDynamicCast(); - if (Op.SrcExpr.isInvalid()) - return ExprError(); - } - return Owned(CXXDynamicCastExpr::Create(Context, Op.ResultType, - Op.ValueKind, Op.Kind, - Op.SrcExpr.take(), &Op.BasePath, - DestTInfo, OpLoc, Parens.getEnd())); - } - case tok::kw_reinterpret_cast: { - if (!TypeDependent) { - Op.CheckReinterpretCast(); - if (Op.SrcExpr.isInvalid()) - return ExprError(); - } - return Owned(CXXReinterpretCastExpr::Create(Context, Op.ResultType, - Op.ValueKind, Op.Kind, - Op.SrcExpr.take(), 0, - DestTInfo, OpLoc, - Parens.getEnd())); - } - case tok::kw_static_cast: { - if (!TypeDependent) { - Op.CheckStaticCast(); - if (Op.SrcExpr.isInvalid()) - return ExprError(); - } - - return Owned(CXXStaticCastExpr::Create(Context, Op.ResultType, Op.ValueKind, - Op.Kind, Op.SrcExpr.take(), - &Op.BasePath, DestTInfo, OpLoc, - Parens.getEnd())); - } - } - - return ExprError(); -} - -/// Try to diagnose a failed overloaded cast. Returns true if -/// diagnostics were emitted. -static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, - SourceRange range, Expr *src, - QualType destType) { - switch (CT) { - // These cast kinds don't consider user-defined conversions. - case CT_Const: - case CT_Reinterpret: - case CT_Dynamic: - return false; - - // These do. - case CT_Static: - case CT_CStyle: - case CT_Functional: - break; - } - - QualType srcType = src->getType(); - if (!destType->isRecordType() && !srcType->isRecordType()) - return false; - - InitializedEntity entity = InitializedEntity::InitializeTemporary(destType); - InitializationKind initKind - = (CT == CT_CStyle)? InitializationKind::CreateCStyleCast(range.getBegin(), - range) - : (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range) - : InitializationKind::CreateCast(/*type range?*/ range); - InitializationSequence sequence(S, entity, initKind, &src, 1); - - assert(sequence.Failed() && "initialization succeeded on second try?"); - switch (sequence.getFailureKind()) { - default: return false; - - case InitializationSequence::FK_ConstructorOverloadFailed: - case InitializationSequence::FK_UserConversionOverloadFailed: - break; - } - - OverloadCandidateSet &candidates = sequence.getFailedCandidateSet(); - - unsigned msg = 0; - OverloadCandidateDisplayKind howManyCandidates = OCD_AllCandidates; - - switch (sequence.getFailedOverloadResult()) { - case OR_Success: llvm_unreachable("successful failed overload"); - return false; - case OR_No_Viable_Function: - if (candidates.empty()) - msg = diag::err_ovl_no_conversion_in_cast; - else - msg = diag::err_ovl_no_viable_conversion_in_cast; - howManyCandidates = OCD_AllCandidates; - break; - - case OR_Ambiguous: - msg = diag::err_ovl_ambiguous_conversion_in_cast; - howManyCandidates = OCD_ViableCandidates; - break; - - case OR_Deleted: - msg = diag::err_ovl_deleted_conversion_in_cast; - howManyCandidates = OCD_ViableCandidates; - break; - } - - S.Diag(range.getBegin(), msg) - << CT << srcType << destType - << range << src->getSourceRange(); - - candidates.NoteCandidates(S, howManyCandidates, &src, 1); - - return true; -} - -/// Diagnose a failed cast. -static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType, - SourceRange opRange, Expr *src, QualType destType) { - if (src->getType() == S.Context.BoundMemberTy) { - (void) S.CheckPlaceholderExpr(src); // will always fail - return; - } - - if (msg == diag::err_bad_cxx_cast_generic && - tryDiagnoseOverloadedCast(S, castType, opRange, src, destType)) - return; - - S.Diag(opRange.getBegin(), msg) << castType - << src->getType() << destType << opRange << src->getSourceRange(); -} - -/// UnwrapDissimilarPointerTypes - Like Sema::UnwrapSimilarPointerTypes, -/// this removes one level of indirection from both types, provided that they're -/// the same kind of pointer (plain or to-member). Unlike the Sema function, -/// this one doesn't care if the two pointers-to-member don't point into the -/// same class. This is because CastsAwayConstness doesn't care. -static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { - const PointerType *T1PtrType = T1->getAs<PointerType>(), - *T2PtrType = T2->getAs<PointerType>(); - if (T1PtrType && T2PtrType) { - T1 = T1PtrType->getPointeeType(); - T2 = T2PtrType->getPointeeType(); - return true; - } - const ObjCObjectPointerType *T1ObjCPtrType = - T1->getAs<ObjCObjectPointerType>(), - *T2ObjCPtrType = - T2->getAs<ObjCObjectPointerType>(); - if (T1ObjCPtrType) { - if (T2ObjCPtrType) { - T1 = T1ObjCPtrType->getPointeeType(); - T2 = T2ObjCPtrType->getPointeeType(); - return true; - } - else if (T2PtrType) { - T1 = T1ObjCPtrType->getPointeeType(); - T2 = T2PtrType->getPointeeType(); - return true; - } - } - else if (T2ObjCPtrType) { - if (T1PtrType) { - T2 = T2ObjCPtrType->getPointeeType(); - T1 = T1PtrType->getPointeeType(); - return true; - } - } - - const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(), - *T2MPType = T2->getAs<MemberPointerType>(); - if (T1MPType && T2MPType) { - T1 = T1MPType->getPointeeType(); - T2 = T2MPType->getPointeeType(); - return true; - } - - const BlockPointerType *T1BPType = T1->getAs<BlockPointerType>(), - *T2BPType = T2->getAs<BlockPointerType>(); - if (T1BPType && T2BPType) { - T1 = T1BPType->getPointeeType(); - T2 = T2BPType->getPointeeType(); - return true; - } - - return false; -} - -/// CastsAwayConstness - Check if the pointer conversion from SrcType to -/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by -/// the cast checkers. Both arguments must denote pointer (possibly to member) -/// types. -/// -/// \param CheckCVR Whether to check for const/volatile/restrict qualifiers. -/// -/// \param CheckObjCLifetime Whether to check Objective-C lifetime qualifiers. -static bool -CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, - bool CheckCVR, bool CheckObjCLifetime) { - // If the only checking we care about is for Objective-C lifetime qualifiers, - // and we're not in ARC mode, there's nothing to check. - if (!CheckCVR && CheckObjCLifetime && - !Self.Context.getLangOptions().ObjCAutoRefCount) - return false; - - // Casting away constness is defined in C++ 5.2.11p8 with reference to - // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since - // the rules are non-trivial. So first we construct Tcv *...cv* as described - // in C++ 5.2.11p8. - assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType() || - SrcType->isBlockPointerType()) && - "Source type is not pointer or pointer to member."); - assert((DestType->isAnyPointerType() || DestType->isMemberPointerType() || - DestType->isBlockPointerType()) && - "Destination type is not pointer or pointer to member."); - - QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType), - UnwrappedDestType = Self.Context.getCanonicalType(DestType); - SmallVector<Qualifiers, 8> cv1, cv2; - - // 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)) { - // Determine the relevant qualifiers at this level. - Qualifiers SrcQuals, DestQuals; - Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals); - Self.Context.getUnqualifiedArrayType(UnwrappedDestType, DestQuals); - - Qualifiers RetainedSrcQuals, RetainedDestQuals; - if (CheckCVR) { - RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers()); - RetainedDestQuals.setCVRQualifiers(DestQuals.getCVRQualifiers()); - } - - if (CheckObjCLifetime && - !DestQuals.compatiblyIncludesObjCLifetime(SrcQuals)) - return true; - - cv1.push_back(RetainedSrcQuals); - cv2.push_back(RetainedDestQuals); - } - if (cv1.empty()) - return false; - - // Construct void pointers with those qualifiers (in reverse order of - // unwrapping, of course). - QualType SrcConstruct = Self.Context.VoidTy; - QualType DestConstruct = Self.Context.VoidTy; - ASTContext &Context = Self.Context; - for (SmallVector<Qualifiers, 8>::reverse_iterator i1 = cv1.rbegin(), - i2 = cv2.rbegin(); - i1 != cv1.rend(); ++i1, ++i2) { - SrcConstruct - = Context.getPointerType(Context.getQualifiedType(SrcConstruct, *i1)); - DestConstruct - = Context.getPointerType(Context.getQualifiedType(DestConstruct, *i2)); - } - - // Test if they're compatible. - bool ObjCLifetimeConversion; - return SrcConstruct != DestConstruct && - !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false, - ObjCLifetimeConversion); -} - -/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid. -/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime- -/// checked downcasts in class hierarchies. -void CastOperation::CheckDynamicCast() { - QualType OrigSrcType = SrcExpr.get()->getType(); - QualType DestType = Self.Context.getCanonicalType(this->DestType); - - // C++ 5.2.7p1: T shall be a pointer or reference to a complete class type, - // or "pointer to cv void". - - QualType DestPointee; - const PointerType *DestPointer = DestType->getAs<PointerType>(); - const ReferenceType *DestReference = 0; - if (DestPointer) { - DestPointee = DestPointer->getPointeeType(); - } else if ((DestReference = DestType->getAs<ReferenceType>())) { - DestPointee = DestReference->getPointeeType(); - } else { - Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr) - << this->DestType << DestRange; - return; - } - - const RecordType *DestRecord = DestPointee->getAs<RecordType>(); - if (DestPointee->isVoidType()) { - assert(DestPointer && "Reference to void is not possible"); - } else if (DestRecord) { - if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee, - Self.PDiag(diag::err_bad_dynamic_cast_incomplete) - << DestRange)) - return; - } else { - Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) - << DestPointee.getUnqualifiedType() << DestRange; - return; - } - - // C++0x 5.2.7p2: If T is a pointer type, v shall be an rvalue of a pointer to - // complete class type, [...]. If T is an lvalue reference type, v shall be - // an lvalue of a complete class type, [...]. If T is an rvalue reference - // type, v shall be an expression having a complete class type, [...] - QualType SrcType = Self.Context.getCanonicalType(OrigSrcType); - QualType SrcPointee; - if (DestPointer) { - if (const PointerType *SrcPointer = SrcType->getAs<PointerType>()) { - SrcPointee = SrcPointer->getPointeeType(); - } else { - Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr) - << OrigSrcType << SrcExpr.get()->getSourceRange(); - return; - } - } else if (DestReference->isLValueReferenceType()) { - if (!SrcExpr.get()->isLValue()) { - Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) - << CT_Dynamic << OrigSrcType << this->DestType << OpRange; - } - SrcPointee = SrcType; - } else { - SrcPointee = SrcType; - } - - const RecordType *SrcRecord = SrcPointee->getAs<RecordType>(); - if (SrcRecord) { - if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, - Self.PDiag(diag::err_bad_dynamic_cast_incomplete) - << SrcExpr.get()->getSourceRange())) - return; - } else { - Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) - << SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange(); - return; - } - - assert((DestPointer || DestReference) && - "Bad destination non-ptr/ref slipped through."); - assert((DestRecord || DestPointee->isVoidType()) && - "Bad destination pointee slipped through."); - assert(SrcRecord && "Bad source pointee slipped through."); - - // 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_qualifiers_away) - << CT_Dynamic << OrigSrcType << this->DestType << OpRange; - return; - } - - // C++ 5.2.7p3: If the type of v is the same as the required result type, - // [except for cv]. - if (DestRecord == SrcRecord) { - Kind = CK_NoOp; - return; - } - - // C++ 5.2.7p5 - // Upcasts are resolved statically. - if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) { - if (Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee, - OpRange.getBegin(), OpRange, - &BasePath)) - return; - - Kind = CK_DerivedToBase; - - // If we are casting to or through a virtual base class, we need a - // vtable. - if (Self.BasePathInvolvesVirtualBase(BasePath)) - Self.MarkVTableUsed(OpRange.getBegin(), - cast<CXXRecordDecl>(SrcRecord->getDecl())); - return; - } - - // C++ 5.2.7p6: Otherwise, v shall be [polymorphic]. - const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(); - assert(SrcDecl && "Definition missing"); - if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) { - Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic) - << SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange(); - } - Self.MarkVTableUsed(OpRange.getBegin(), - cast<CXXRecordDecl>(SrcRecord->getDecl())); - - // Done. Everything else is run-time checks. - Kind = CK_Dynamic; -} - -/// CheckConstCast - Check that a const_cast\<DestType\>(SrcExpr) is valid. -/// Refer to C++ 5.2.11 for details. const_cast is typically used in code -/// like this: -/// const char *str = "literal"; -/// legacy_function(const_cast\<char*\>(str)); -void CastOperation::CheckConstCast() { - if (ValueKind == VK_RValue) { - SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); - if (SrcExpr.isInvalid()) // if conversion failed, don't report another error - return; - } - - unsigned msg = diag::err_bad_cxx_cast_generic; - if (TryConstCast(Self, SrcExpr.get(), DestType, /*CStyle*/false, msg) != TC_Success - && msg != 0) - Self.Diag(OpRange.getBegin(), msg) << CT_Const - << SrcExpr.get()->getType() << DestType << OpRange; -} - -/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is -/// valid. -/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code -/// like this: -/// char *bytes = reinterpret_cast\<char*\>(int_ptr); -void CastOperation::CheckReinterpretCast() { - if (ValueKind == VK_RValue) { - SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); - if (SrcExpr.isInvalid()) // if conversion failed, don't report another error - return; - } - - unsigned msg = diag::err_bad_cxx_cast_generic; - TryCastResult tcr = - TryReinterpretCast(Self, SrcExpr, DestType, - /*CStyle*/false, OpRange, msg, Kind); - if (tcr != TC_Success && msg != 0) - { - if (SrcExpr.isInvalid()) // if conversion failed, don't report another error - return; - if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { - //FIXME: &f<int>; is overloaded and resolvable - Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_overload) - << OverloadExpr::find(SrcExpr.get()).Expression->getName() - << DestType << OpRange; - Self.NoteAllOverloadCandidates(SrcExpr.get()); - - } else { - diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType); - } - } else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) { - checkObjCARCConversion(Sema::CCK_OtherCast); - } -} - - -/// CheckStaticCast - Check that a static_cast\<DestType\>(SrcExpr) is valid. -/// Refer to C++ 5.2.9 for details. Static casts are mostly used for making -/// implicit conversions explicit and getting rid of data loss warnings. -void CastOperation::CheckStaticCast() { - if (isPlaceholder()) { - checkNonOverloadPlaceholders(); - if (SrcExpr.isInvalid()) - return; - } - - // This test is outside everything else because it's the only case where - // a non-lvalue-reference target type does not lead to decay. - // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". - if (DestType->isVoidType()) { - Kind = CK_ToVoid; - - if (claimPlaceholder(BuiltinType::Overload)) { - ExprResult SingleFunctionExpression = - Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr.get(), - false, // Decay Function to ptr - true, // Complain - OpRange, DestType, diag::err_bad_static_cast_overload); - if (SingleFunctionExpression.isUsable()) - SrcExpr = SingleFunctionExpression; - } - - SrcExpr = Self.IgnoredValueConversions(SrcExpr.take()); - return; - } - - if (ValueKind == VK_RValue && !DestType->isRecordType()) { - SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); - if (SrcExpr.isInvalid()) // if conversion failed, don't report another error - return; - } - - unsigned msg = diag::err_bad_cxx_cast_generic; - TryCastResult tcr - = TryStaticCast(Self, SrcExpr, DestType, Sema::CCK_OtherCast, OpRange, msg, - Kind, BasePath); - if (tcr != TC_Success && msg != 0) { - if (SrcExpr.isInvalid()) - return; - if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { - OverloadExpr* oe = OverloadExpr::find(SrcExpr.get()).Expression; - Self.Diag(OpRange.getBegin(), diag::err_bad_static_cast_overload) - << oe->getName() << DestType << OpRange - << oe->getQualifierLoc().getSourceRange(); - Self.NoteAllOverloadCandidates(SrcExpr.get()); - } else { - diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType); - } - } else if (tcr == TC_Success) { - if (Kind == CK_BitCast) - checkCastAlign(); - if (Self.getLangOptions().ObjCAutoRefCount) - checkObjCARCConversion(Sema::CCK_OtherCast); - } else if (Kind == CK_BitCast) { - checkCastAlign(); - } -} - -/// TryStaticCast - Check if a static cast can be performed, and do so if -/// possible. If @p CStyle, ignore access restrictions on hierarchy casting -/// and casting away constness. -static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, - QualType DestType, - Sema::CheckedConversionKind CCK, - const SourceRange &OpRange, unsigned &msg, - CastKind &Kind, - CXXCastPath &BasePath) { - // Determine whether we have the semantics of a C-style cast. - bool CStyle - = (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast); - - // The order the tests is not entirely arbitrary. There is one conversion - // that can be handled in two different ways. Given: - // struct A {}; - // struct B : public A { - // B(); B(const A&); - // }; - // const A &a = B(); - // the cast static_cast<const B&>(a) could be seen as either a static - // reference downcast, or an explicit invocation of the user-defined - // conversion using B's conversion constructor. - // DR 427 specifies that the downcast is to be applied here. - - // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". - // Done outside this function. - - TryCastResult tcr; - - // C++ 5.2.9p5, reference downcast. - // See the function for details. - // DR 427 specifies that this is to be applied before paragraph 2. - tcr = TryStaticReferenceDowncast(Self, SrcExpr.get(), DestType, CStyle, OpRange, - msg, Kind, BasePath); - if (tcr != TC_NotApplicable) - return tcr; - - // C++0x [expr.static.cast]p3: - // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2 - // T2" if "cv2 T2" is reference-compatible with "cv1 T1". - tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind, BasePath, - msg); - if (tcr != TC_NotApplicable) - return tcr; - - // C++ 5.2.9p2: An expression e can be explicitly converted to a type T - // [...] if the declaration "T t(e);" is well-formed, [...]. - tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CCK, OpRange, msg, - Kind); - if (SrcExpr.isInvalid()) - return TC_Failed; - if (tcr != TC_NotApplicable) - return tcr; - - // C++ 5.2.9p6: May apply the reverse of any standard conversion, except - // lvalue-to-rvalue, array-to-pointer, function-to-pointer, and boolean - // conversions, subject to further restrictions. - // Also, C++ 5.2.9p1 forbids casting away constness, which makes reversal - // of qualification conversions impossible. - // In the CStyle case, the earlier attempt to const_cast should have taken - // care of reverse qualification conversions. - - QualType SrcType = Self.Context.getCanonicalType(SrcExpr.get()->getType()); - - // C++0x 5.2.9p9: A value of a scoped enumeration type can be explicitly - // converted to an integral type. [...] A value of a scoped enumeration type - // can also be explicitly converted to a floating-point type [...]. - if (const EnumType *Enum = SrcType->getAs<EnumType>()) { - if (Enum->getDecl()->isScoped()) { - if (DestType->isBooleanType()) { - Kind = CK_IntegralToBoolean; - return TC_Success; - } else if (DestType->isIntegralType(Self.Context)) { - Kind = CK_IntegralCast; - return TC_Success; - } else if (DestType->isRealFloatingType()) { - Kind = CK_IntegralToFloating; - return TC_Success; - } - } - } - - // Reverse integral promotion/conversion. All such conversions are themselves - // again integral promotions or conversions and are thus already handled by - // p2 (TryDirectInitialization above). - // (Note: any data loss warnings should be suppressed.) - // The exception is the reverse of enum->integer, i.e. integer->enum (and - // enum->enum). See also C++ 5.2.9p7. - // The same goes for reverse floating point promotion/conversion and - // floating-integral conversions. Again, only floating->enum is relevant. - if (DestType->isEnumeralType()) { - if (SrcType->isIntegralOrEnumerationType()) { - Kind = CK_IntegralCast; - return TC_Success; - } else if (SrcType->isRealFloatingType()) { - Kind = CK_FloatingToIntegral; - return TC_Success; - } - } - - // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast. - // C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance. - tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg, - Kind, BasePath); - if (tcr != TC_NotApplicable) - return tcr; - - // Reverse member pointer conversion. C++ 4.11 specifies member pointer - // conversion. C++ 5.2.9p9 has additional information. - // DR54's access restrictions apply here also. - tcr = TryStaticMemberPointerUpcast(Self, SrcExpr, SrcType, DestType, CStyle, - OpRange, msg, Kind, BasePath); - if (tcr != TC_NotApplicable) - return tcr; - - // Reverse pointer conversion to void*. C++ 4.10.p2 specifies conversion to - // void*. C++ 5.2.9p10 specifies additional restrictions, which really is - // just the usual constness stuff. - if (const PointerType *SrcPointer = SrcType->getAs<PointerType>()) { - QualType SrcPointee = SrcPointer->getPointeeType(); - if (SrcPointee->isVoidType()) { - if (const PointerType *DestPointer = DestType->getAs<PointerType>()) { - QualType DestPointee = DestPointer->getPointeeType(); - if (DestPointee->isIncompleteOrObjectType()) { - // This is definitely the intended conversion, but it might fail due - // to a qualifier violation. Note that we permit Objective-C lifetime - // and GC qualifier mismatches here. - if (!CStyle) { - Qualifiers DestPointeeQuals = DestPointee.getQualifiers(); - Qualifiers SrcPointeeQuals = SrcPointee.getQualifiers(); - DestPointeeQuals.removeObjCGCAttr(); - DestPointeeQuals.removeObjCLifetime(); - SrcPointeeQuals.removeObjCGCAttr(); - SrcPointeeQuals.removeObjCLifetime(); - if (DestPointeeQuals != SrcPointeeQuals && - !DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals)) { - msg = diag::err_bad_cxx_cast_qualifiers_away; - return TC_Failed; - } - } - Kind = CK_BitCast; - return TC_Success; - } - } - else if (DestType->isObjCObjectPointerType()) { - // allow both c-style cast and static_cast of objective-c pointers as - // they are pervasive. - Kind = CK_CPointerToObjCPointerCast; - return TC_Success; - } - else if (CStyle && DestType->isBlockPointerType()) { - // allow c-style cast of void * to block pointers. - Kind = CK_AnyPointerToBlockPointerCast; - return TC_Success; - } - } - } - // Allow arbitray objective-c pointer conversion with static casts. |