diff options
Diffstat (limited to 'lib/Sema/SemaCast.cpp')
-rw-r--r-- | lib/Sema/SemaCast.cpp | 142 |
1 files changed, 105 insertions, 37 deletions
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index eb11a57..ba00b71 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -200,8 +200,9 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, unsigned &msg, CastKind &Kind, CXXCastPath &BasePath, bool ListInitialization); -static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, - bool CStyle, unsigned &msg); +static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr, + QualType DestType, bool CStyle, + unsigned &msg); static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, @@ -242,7 +243,9 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, // 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(); + bool TypeDependent = DestType->isDependentType() || + Ex.get()->isTypeDependent() || + Ex.get()->isValueDependent(); CastOperation Op(*this, DestType, E); Op.OpRange = SourceRange(OpLoc, Parens.getEnd()); @@ -383,11 +386,6 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType, SourceRange opRange, Expr *src, QualType destType, bool listInitialization) { - 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, listInitialization)) @@ -515,8 +513,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, 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(); + for (SmallVectorImpl<Qualifiers>::reverse_iterator i1 = cv1.rbegin(), + i2 = cv2.rbegin(); i1 != cv1.rend(); ++i1, ++i2) { SrcConstruct = Context.getPointerType(Context.getQualifiedType(SrcConstruct, *i1)); @@ -558,6 +556,7 @@ void CastOperation::CheckDynamicCast() { } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr) << this->DestType << DestRange; + SrcExpr = ExprError(); return; } @@ -567,11 +566,14 @@ void CastOperation::CheckDynamicCast() { } else if (DestRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee, diag::err_bad_dynamic_cast_incomplete, - DestRange)) + DestRange)) { + SrcExpr = ExprError(); return; + } } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) << DestPointee.getUnqualifiedType() << DestRange; + SrcExpr = ExprError(); return; } @@ -587,6 +589,7 @@ void CastOperation::CheckDynamicCast() { } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr) << OrigSrcType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); return; } } else if (DestReference->isLValueReferenceType()) { @@ -603,11 +606,14 @@ void CastOperation::CheckDynamicCast() { if (SrcRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, diag::err_bad_dynamic_cast_incomplete, - SrcExpr.get())) + SrcExpr.get())) { + SrcExpr = ExprError(); return; + } } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) << SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); return; } @@ -621,6 +627,7 @@ void CastOperation::CheckDynamicCast() { if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away) << CT_Dynamic << OrigSrcType << this->DestType << OpRange; + SrcExpr = ExprError(); return; } @@ -636,8 +643,10 @@ void CastOperation::CheckDynamicCast() { if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) { if (Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee, OpRange.getBegin(), OpRange, - &BasePath)) - return; + &BasePath)) { + SrcExpr = ExprError(); + return; + } Kind = CK_DerivedToBase; @@ -655,10 +664,20 @@ void CastOperation::CheckDynamicCast() { if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic) << SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); } Self.MarkVTableUsed(OpRange.getBegin(), cast<CXXRecordDecl>(SrcRecord->getDecl())); + // dynamic_cast is not available with -fno-rtti. + // As an exception, dynamic_cast to void* is available because it doesn't + // use RTTI. + if (!Self.getLangOpts().RTTI && !DestPointee->isVoidType()) { + Self.Diag(OpRange.getBegin(), diag::err_no_dynamic_cast_with_fno_rtti); + SrcExpr = ExprError(); + return; + } + // Done. Everything else is run-time checks. Kind = CK_Dynamic; } @@ -677,10 +696,12 @@ void CastOperation::CheckConstCast() { return; unsigned msg = diag::err_bad_cxx_cast_generic; - if (TryConstCast(Self, SrcExpr.get(), DestType, /*CStyle*/false, msg) != TC_Success - && msg != 0) + if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success + && msg != 0) { Self.Diag(OpRange.getBegin(), msg) << CT_Const << SrcExpr.get()->getType() << DestType << OpRange; + SrcExpr = ExprError(); + } } /// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast @@ -758,6 +779,7 @@ static void DiagnoseReinterpretUpDownCast(Sema &Self, const Expr *SrcExpr, VirtualBase = VirtualBase && IsVirtual; } + (void) NonZeroOffset; // Silence set but not used warning. assert((VirtualBase || NonZeroOffset) && "Should have returned if has non-virtual base with zero offset"); @@ -768,10 +790,10 @@ static void DiagnoseReinterpretUpDownCast(Sema &Self, const Expr *SrcExpr, SourceLocation BeginLoc = OpRange.getBegin(); Self.Diag(BeginLoc, diag::warn_reinterpret_different_from_static) - << DerivedType << BaseType << !VirtualBase << ReinterpretKind + << DerivedType << BaseType << !VirtualBase << int(ReinterpretKind) << OpRange; Self.Diag(BeginLoc, diag::note_reinterpret_updowncast_use_static) - << ReinterpretKind + << int(ReinterpretKind) << FixItHint::CreateReplacement(BeginLoc, "static_cast"); } @@ -807,6 +829,7 @@ void CastOperation::CheckReinterpretCast() { diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType, /*listInitialization=*/false); } + SrcExpr = ExprError(); } else if (tcr == TC_Success) { if (Self.getLangOpts().ObjCAutoRefCount) checkObjCARCConversion(Sema::CCK_OtherCast); @@ -868,6 +891,7 @@ void CastOperation::CheckStaticCast() { diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType, /*listInitialization=*/false); } + SrcExpr = ExprError(); } else if (tcr == TC_Success) { if (Kind == CK_BitCast) checkCastAlign(); @@ -1447,12 +1471,26 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, /// TryConstCast - See if a const_cast from source to destination is allowed, /// and perform it if it is. -static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, - bool CStyle, unsigned &msg) { +static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr, + QualType DestType, bool CStyle, + unsigned &msg) { DestType = Self.Context.getCanonicalType(DestType); - QualType SrcType = SrcExpr->getType(); + QualType SrcType = SrcExpr.get()->getType(); + bool NeedToMaterializeTemporary = false; + if (const ReferenceType *DestTypeTmp =DestType->getAs<ReferenceType>()) { - if (isa<LValueReferenceType>(DestTypeTmp) && !SrcExpr->isLValue()) { + // C++11 5.2.11p4: + // if a pointer to T1 can be explicitly converted to the type "pointer to + // T2" using a const_cast, then the following conversions can also be + // made: + // -- an lvalue of type T1 can be explicitly converted to an lvalue of + // type T2 using the cast const_cast<T2&>; + // -- a glvalue of type T1 can be explicitly converted to an xvalue of + // type T2 using the cast const_cast<T2&&>; and + // -- if T1 is a class type, a prvalue of type T1 can be explicitly + // converted to an xvalue of type T2 using the cast const_cast<T2&&>. + + if (isa<LValueReferenceType>(DestTypeTmp) && !SrcExpr.get()->isLValue()) { // Cannot const_cast non-lvalue to lvalue reference type. But if this // is C-style, static_cast might find a way, so we simply suggest a // message and tell the parent to keep searching. @@ -1460,18 +1498,29 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_NotApplicable; } + if (isa<RValueReferenceType>(DestTypeTmp) && SrcExpr.get()->isRValue()) { + if (!SrcType->isRecordType()) { + // Cannot const_cast non-class prvalue to rvalue reference type. But if + // this is C-style, static_cast can do this. + msg = diag::err_bad_cxx_cast_rvalue; + return TC_NotApplicable; + } + + // Materialize the class prvalue so that the const_cast can bind a + // reference to it. + NeedToMaterializeTemporary = true; + } + // It's not completely clear under the standard whether we can // const_cast bit-field gl-values. Doing so would not be // intrinsically complicated, but for now, we say no for // consistency with other compilers and await the word of the // committee. - if (SrcExpr->refersToBitField()) { + if (SrcExpr.get()->refersToBitField()) { msg = diag::err_bad_cxx_cast_bitfield; return TC_NotApplicable; } - // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2 - // [...] if a pointer to T1 can be [cast] to the type pointer to T2. DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); SrcType = Self.Context.getPointerType(SrcType); } @@ -1525,6 +1574,13 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, if (SrcType != DestType) return TC_NotApplicable; + if (NeedToMaterializeTemporary) + // This is a const_cast from a class prvalue to an rvalue reference type. + // Materialize a temporary to store the result of the conversion. + SrcExpr = new (Self.Context) MaterializeTemporaryExpr( + SrcType, SrcExpr.take(), /*IsLValueReference*/ false, + /*ExtendingDecl*/ 0); + return TC_Success; } @@ -1614,8 +1670,18 @@ static void checkIntToPointerCast(bool CStyle, SourceLocation Loc, && !SrcType->isBooleanType() && !SrcType->isEnumeralType() && !SrcExpr->isIntegerConstantExpr(Self.Context) - && Self.Context.getTypeSize(DestType) > Self.Context.getTypeSize(SrcType)) - Self.Diag(Loc, diag::warn_int_to_pointer_cast) << SrcType << DestType; + && Self.Context.getTypeSize(DestType) > + Self.Context.getTypeSize(SrcType)) { + // Separate between casts to void* and non-void* pointers. + // Some APIs use (abuse) void* for something like a user context, + // and often that value is an integer even if it isn't a pointer itself. + // Having a separate warning flag allows users to control the warning + // for their workflow. + unsigned Diag = DestType->isVoidPointerType() ? + diag::warn_int_to_void_pointer_cast + : diag::warn_int_to_pointer_cast; + Self.Diag(Loc, Diag) << SrcType << DestType; + } } static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, @@ -1803,10 +1869,12 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, assert(srcIsPtr && "One type must be a pointer"); // C++ 5.2.10p4: A pointer can be explicitly converted to any integral // type large enough to hold it; except in Microsoft mode, where the - // integral type size doesn't matter. + // integral type size doesn't matter (except we don't allow bool). + bool MicrosoftException = Self.getLangOpts().MicrosoftExt && + !DestType->isBooleanType(); if ((Self.Context.getTypeSize(SrcType) > Self.Context.getTypeSize(DestType)) && - !Self.getLangOpts().MicrosoftExt) { + !MicrosoftException) { msg = diag::err_bad_reinterpret_cast_small_int; return TC_Failed; } @@ -1940,14 +2008,12 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, } SrcExpr = Self.IgnoredValueConversions(SrcExpr.take()); - if (SrcExpr.isInvalid()) - return; - return; } // If the type is dependent, we won't do any other semantic analysis now. - if (DestType->isDependentType() || SrcExpr.get()->isTypeDependent()) { + if (DestType->isDependentType() || SrcExpr.get()->isTypeDependent() || + SrcExpr.get()->isValueDependent()) { assert(Kind == CK_Dependent); return; } @@ -1980,8 +2046,10 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, // 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(Self, SrcExpr.get(), DestType, + TryCastResult tcr = TryConstCast(Self, SrcExpr, DestType, /*CStyle*/true, msg); + if (SrcExpr.isInvalid()) + return; if (tcr == TC_Success) Kind = CK_NoOp; @@ -2298,9 +2366,9 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, return ExprError(); if (CXXConstructExpr *ConstructExpr = dyn_cast<CXXConstructExpr>(Op.SrcExpr.get())) - ConstructExpr->setParenRange(SourceRange(LPLoc, RPLoc)); + ConstructExpr->setParenOrBraceRange(SourceRange(LPLoc, RPLoc)); return Op.complete(CXXFunctionalCastExpr::Create(Context, Op.ResultType, - Op.ValueKind, CastTypeInfo, Op.DestRange.getBegin(), - Op.Kind, Op.SrcExpr.take(), &Op.BasePath, RPLoc)); + Op.ValueKind, CastTypeInfo, Op.Kind, + Op.SrcExpr.take(), &Op.BasePath, LPLoc, RPLoc)); } |