diff options
author | John McCall <rjmccall@apple.com> | 2011-10-05 07:41:44 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-10-05 07:41:44 +0000 |
commit | b45ae256cfd5ef3ab22b4d715159f978d8120d45 (patch) | |
tree | 2fe68bc2dceead134824b5cc97f67cac3d38b7fe /lib/Sema/SemaCXXCast.cpp | |
parent | 1203600d227aefa1600973dd848417d31751a3a2 (diff) |
Refactor the analysis of C++ cast expressions so that even
C-style and functional casts are built in SemaCXXCast.cpp.
Introduce a helper class to encapsulate most of the random
state being passed around, at least one level down.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141170 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaCXXCast.cpp')
-rw-r--r-- | lib/Sema/SemaCXXCast.cpp | 334 |
1 files changed, 172 insertions, 162 deletions
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 583a7fa3dd..5c5c702fd5 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -39,29 +39,43 @@ enum CastType { 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) {} + + Sema &Self; + ExprResult SrcExpr; + QualType DestType; + QualType ResultType; + ExprValueKind ValueKind; + CastKind Kind; + bool IsARCUnbridgedCast; + CXXCastPath BasePath; + SourceRange OpRange; + SourceRange DestRange; + void CheckConstCast(); + void CheckReinterpretCast(); + void CheckStaticCast(); + void CheckDynamicCast(); + void CheckCStyleCast(bool FunctionalCast); -static void CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, - const SourceRange &OpRange, - const SourceRange &DestRange); -static void CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, - const SourceRange &OpRange, - const SourceRange &DestRange, - CastKind &Kind); -static void CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, - const SourceRange &OpRange, - CastKind &Kind, - CXXCastPath &BasePath); -static void CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, - const SourceRange &OpRange, - const SourceRange &DestRange, - CastKind &Kind, - CXXCastPath &BasePath); + 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; + } + }; +} static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, bool CheckCVR, bool CheckObjCLifetime); @@ -162,70 +176,61 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, ExprResult Ex = Owned(E); QualType DestType = DestTInfo->getType(); - SourceRange OpRange(OpLoc, Parens.getEnd()); - SourceRange DestRange = AngleBrackets; - // 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(); - ExprValueKind VK = VK_RValue; - if (TypeDependent) - VK = Expr::getValueKindForType(DestType); + 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) { - CheckConstCast(*this, Ex, DestType, VK, OpRange, DestRange); - if (Ex.isInvalid()) + Op.CheckConstCast(); + if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXConstCastExpr::Create(Context, - DestType.getNonLValueExprType(Context), - VK, Ex.take(), DestTInfo, OpLoc, + return Owned(CXXConstCastExpr::Create(Context, Op.ResultType, Op.ValueKind, + Op.SrcExpr.take(), DestTInfo, OpLoc, Parens.getEnd())); case tok::kw_dynamic_cast: { - CastKind Kind = CK_Dependent; - CXXCastPath BasePath; if (!TypeDependent) { - CheckDynamicCast(*this, Ex, DestType, VK, OpRange, DestRange, - Kind, BasePath); - if (Ex.isInvalid()) + Op.CheckDynamicCast(); + if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXDynamicCastExpr::Create(Context, - DestType.getNonLValueExprType(Context), - VK, Kind, Ex.take(), &BasePath, DestTInfo, - OpLoc, Parens.getEnd())); + 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: { - CastKind Kind = CK_Dependent; if (!TypeDependent) { - CheckReinterpretCast(*this, Ex, DestType, VK, OpRange, DestRange, Kind); - if (Ex.isInvalid()) + Op.CheckReinterpretCast(); + if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXReinterpretCastExpr::Create(Context, - DestType.getNonLValueExprType(Context), - VK, Kind, Ex.take(), 0, - DestTInfo, OpLoc, Parens.getEnd())); + return Owned(CXXReinterpretCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, Op.Kind, + Op.SrcExpr.take(), 0, + DestTInfo, OpLoc, + Parens.getEnd())); } case tok::kw_static_cast: { - CastKind Kind = CK_Dependent; - CXXCastPath BasePath; if (!TypeDependent) { - CheckStaticCast(*this, Ex, DestType, VK, OpRange, Kind, BasePath); - if (Ex.isInvalid()) + Op.CheckStaticCast(); + if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXStaticCastExpr::Create(Context, - DestType.getNonLValueExprType(Context), - VK, Kind, Ex.take(), &BasePath, - DestTInfo, OpLoc, Parens.getEnd())); + return Owned(CXXStaticCastExpr::Create(Context, Op.ResultType, Op.ValueKind, + Op.Kind, Op.SrcExpr.take(), + &Op.BasePath, DestTInfo, OpLoc, + Parens.getEnd())); } } @@ -461,13 +466,9 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, /// 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. -static void -CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, const SourceRange &OpRange, - const SourceRange &DestRange, CastKind &Kind, - CXXCastPath &BasePath) { - QualType OrigDestType = DestType, OrigSrcType = SrcExpr.get()->getType(); - DestType = Self.Context.getCanonicalType(DestType); +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". @@ -479,12 +480,9 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, DestPointee = DestPointer->getPointeeType(); } else if ((DestReference = DestType->getAs<ReferenceType>())) { DestPointee = DestReference->getPointeeType(); - VK = isa<LValueReferenceType>(DestReference) ? VK_LValue - : isa<RValueReferenceType>(DestReference) ? VK_XValue - : VK_RValue; } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr) - << OrigDestType << DestRange; + << this->DestType << DestRange; return; } @@ -519,7 +517,7 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, } else if (DestReference->isLValueReferenceType()) { if (!SrcExpr.get()->isLValue()) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) - << CT_Dynamic << OrigSrcType << OrigDestType << OpRange; + << CT_Dynamic << OrigSrcType << this->DestType << OpRange; } SrcPointee = SrcType; } else { @@ -547,7 +545,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_qualifiers_away) - << CT_Dynamic << OrigSrcType << OrigDestType << OpRange; + << CT_Dynamic << OrigSrcType << this->DestType << OpRange; return; } @@ -595,11 +593,8 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, /// like this: /// const char *str = "literal"; /// legacy_function(const_cast\<char*\>(str)); -void -CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK, - const SourceRange &OpRange, const SourceRange &DestRange) { - VK = Expr::getValueKindForType(DestType); - if (VK == VK_RValue) { +void CastOperation::CheckConstCast() { + if (ValueKind == VK_RValue) { SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); if (SrcExpr.isInvalid()) // if conversion failed, don't report another error return; @@ -617,12 +612,8 @@ CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind /// 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 -CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, const SourceRange &OpRange, - const SourceRange &DestRange, CastKind &Kind) { - VK = Expr::getValueKindForType(DestType); - if (VK == VK_RValue) { +void CastOperation::CheckReinterpretCast() { + if (ValueKind == VK_RValue) { SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); if (SrcExpr.isInvalid()) // if conversion failed, don't report another error return; @@ -647,10 +638,7 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType); } } else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) { - Expr *Exp = SrcExpr.get(); - // Note that Exp does not change with CCK_OtherCast cast type - Self.CheckObjCARCConversion(OpRange, DestType, - Exp, Sema::CCK_OtherCast); + checkObjCARCConversion(Sema::CCK_OtherCast); } } @@ -658,10 +646,7 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, /// 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 -CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, const SourceRange &OpRange, - CastKind &Kind, CXXCastPath &BasePath) { +void CastOperation::CheckStaticCast() { // 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". @@ -686,8 +671,7 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, return; } - VK = Expr::getValueKindForType(DestType); - if (VK == VK_RValue && !DestType->isRecordType()) { + if (ValueKind == VK_RValue && !DestType->isRecordType()) { SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); if (SrcExpr.isInvalid()) // if conversion failed, don't report another error return; @@ -711,16 +695,12 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, } } else if (tcr == TC_Success) { if (Kind == CK_BitCast) - Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); - if (Self.getLangOptions().ObjCAutoRefCount) { - Expr *Exp = SrcExpr.get(); - // Note that Exp does not change with CCK_OtherCast cast type - Self.CheckObjCARCConversion(OpRange, DestType, - Exp, Sema::CCK_OtherCast); - } + checkCastAlign(); + if (Self.getLangOptions().ObjCAutoRefCount) + checkObjCARCConversion(Sema::CCK_OtherCast); + } else if (Kind == CK_BitCast) { + checkCastAlign(); } - else if (Kind == CK_BitCast) - Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); } /// TryStaticCast - Check if a static cast can be performed, and do so if @@ -1686,65 +1666,63 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_Success; } -ExprResult -Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, - Expr *CastExpr, CastKind &Kind, - CXXCastPath &BasePath, - bool FunctionalStyle) { +void CastOperation::CheckCStyleCast(bool FunctionalStyle) { + // Check for casts from __unknown_any before anything else. + if (SrcExpr.get()->getType() == Self.Context.UnknownAnyTy) { + SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType, + SrcExpr.get(), Kind, + ValueKind, BasePath); + 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 (CastTy->isVoidType()) { + if (DestType->isVoidType()) { Kind = CK_ToVoid; - ExprResult CastExprRes = IgnoredValueConversions(CastExpr); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = CastExprRes.take(); - - if (CastExpr->getType() == Context.BoundMemberTy) - return CheckPlaceholderExpr(CastExpr); // will always fail + SrcExpr = Self.IgnoredValueConversions(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; - if (CastExpr->getType() == Context.OverloadTy) { - ExprResult SingleFunctionExpr = - ResolveAndFixSingleFunctionTemplateSpecialization( - CastExpr, /* Decay Function to ptr */ false, - /* Complain */ true, R, CastTy, + if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { + SrcExpr = Self.ResolveAndFixSingleFunctionTemplateSpecialization( + SrcExpr.take(), /* Decay Function to ptr */ false, + /* Complain */ true, DestRange, DestType, diag::err_bad_cstyle_cast_overload); - if (SingleFunctionExpr.isInvalid()) - return ExprError(); - CastExpr = SingleFunctionExpr.take(); + if (SrcExpr.isInvalid()) + return; } - assert(!CastExpr->getType()->isPlaceholderType()); + if (SrcExpr.get()->getType() == Self.Context.BoundMemberTy) { + Self.CheckPlaceholderExpr(SrcExpr.take()); // will always fail + return; + } - return Owned(CastExpr); - } + assert(!SrcExpr.get()->getType()->isPlaceholderType()); - // Make sure we determine the value kind before we bail out for - // dependent types. - VK = Expr::getValueKindForType(CastTy); + return; + } // If the type is dependent, we won't do any other semantic analysis now. - if (CastTy->isDependentType() || CastExpr->isTypeDependent()) { - Kind = CK_Dependent; - return Owned(CastExpr); + if (DestType->isDependentType() || SrcExpr.get()->isTypeDependent()) { + assert(Kind == CK_Dependent); + return; } - if (VK == VK_RValue && !CastTy->isRecordType()) { - ExprResult CastExprRes = DefaultFunctionArrayLvalueConversion(CastExpr); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = CastExprRes.take(); + if (ValueKind == VK_RValue && !DestType->isRecordType()) { + SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; } // AltiVec vector initialization with a single literal. - if (const VectorType *vecTy = CastTy->getAs<VectorType>()) + if (const VectorType *vecTy = DestType->getAs<VectorType>()) if (vecTy->getVectorKind() == VectorType::AltiVecVector - && (CastExpr->getType()->isIntegerType() - || CastExpr->getType()->isFloatingType())) { + && (SrcExpr.get()->getType()->isIntegerType() + || SrcExpr.get()->getType()->isFloatingType())) { Kind = CK_VectorSplat; - return Owned(CastExpr); + return; } // C++ [expr.cast]p5: The conversions performed by @@ -1759,8 +1737,8 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, // even if a cast resulting from that interpretation is ill-formed. // In plain language, this means trying a const_cast ... unsigned msg = diag::err_bad_cxx_cast_generic; - TryCastResult tcr = TryConstCast(*this, CastExpr, CastTy, /*CStyle*/true, - msg); + TryCastResult tcr = TryConstCast(Self, SrcExpr.get(), DestType, + /*CStyle*/true, msg); if (tcr == TC_Success) Kind = CK_NoOp; @@ -1769,47 +1747,79 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, : Sema::CCK_CStyleCast; if (tcr == TC_NotApplicable) { // ... or if that is not possible, a static_cast, ignoring const, ... - ExprResult CastExprRes = Owned(CastExpr); - tcr = TryStaticCast(*this, CastExprRes, CastTy, CCK, R, msg, Kind, - BasePath); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = CastExprRes.take(); + tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange, + msg, Kind, BasePath); + if (SrcExpr.isInvalid()) + return; + if (tcr == TC_NotApplicable) { // ... and finally a reinterpret_cast, ignoring const. - CastExprRes = Owned(CastExpr); - tcr = TryReinterpretCast(*this, CastExprRes, CastTy, /*CStyle*/true, R, - msg, Kind); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = CastExprRes.take(); + tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/true, + OpRange, msg, Kind); + if (SrcExpr.isInvalid()) + return; } } - if (getLangOptions().ObjCAutoRefCount && tcr == TC_Success) - CheckObjCARCConversion(R, CastTy, CastExpr, CCK); + if (Self.getLangOptions().ObjCAutoRefCount && tcr == TC_Success) + checkObjCARCConversion(CCK); if (tcr != TC_Success && msg != 0) { - if (CastExpr->getType() == Context.OverloadTy) { + if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { DeclAccessPair Found; - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(CastExpr, - CastTy, - /* Complain */ true, + FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(), + DestType, + /*Complain*/ true, Found); assert(!Fn && "cast failed but able to resolve overload expression!!"); (void)Fn; } else { - diagnoseBadCast(*this, msg, (FunctionalStyle ? CT_Functional : CT_CStyle), - R, CastExpr, CastTy); + diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle), + OpRange, SrcExpr.get(), DestType); } + } else if (Kind == CK_BitCast) { + checkCastAlign(); } - else if (Kind == CK_BitCast) - CheckCastAlign(CastExpr, CastTy, R); + // Clear out SrcExpr if there was a fatal error. if (tcr != TC_Success) + SrcExpr = ExprError(); +} + +ExprResult Sema::CXXBuildCStyleCastExpr(SourceLocation LPLoc, + TypeSourceInfo *CastTypeInfo, + SourceLocation RPLoc, + Expr *CastExpr) { + CastOperation Op(*this, CastTypeInfo->getType(), CastExpr); + Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); + Op.OpRange = SourceRange(LPLoc, CastExpr->getLocEnd()); + + Op.CheckCStyleCast(/*FunctionalStyle=*/ false); + if (Op.SrcExpr.isInvalid()) + return ExprError(); + + return Owned(CStyleCastExpr::Create(Context, Op.ResultType, Op.ValueKind, + Op.Kind, Op.SrcExpr.take(), &Op.BasePath, + CastTypeInfo, LPLoc, RPLoc)); +} + +ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, + SourceLocation LPLoc, + Expr *CastExpr, + SourceLocation RPLoc) { + CastOperation Op(*this, CastTypeInfo->getType(), CastExpr); + Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); + Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd()); + + Op.CheckCStyleCast(/*FunctionalStyle=*/ true); + if (Op.SrcExpr.isInvalid()) return ExprError(); - return Owned(CastExpr); + return Owned(CXXFunctionalCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, CastTypeInfo, + Op.DestRange.getBegin(), + Op.Kind, Op.SrcExpr.take(), + &Op.BasePath, RPLoc)); } |