/// 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 CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, const SourceRange &DestRange) { QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); DestType = Self.Context.getCanonicalType(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->getAsPointerType(); const ReferenceType *DestReference = DestType->getAsReferenceType(); if (DestPointer) { DestPointee = DestPointer->getPointeeType(); } else if (DestReference) { DestPointee = DestReference->getPointeeType(); } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr) << OrigDestType << DestRange; return; } const RecordType *DestRecord = DestPointee->getAsRecordType(); if (DestPointee->isVoidType()) { assert(DestPointer && "Reference to void is not possible"); } else if (DestRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee, 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 effective class type, // [...] QualType SrcType = Self.Context.getCanonicalType(OrigSrcType); QualType SrcPointee; if (DestPointer) { if (const PointerType *SrcPointer = SrcType->getAsPointerType()) { SrcPointee = SrcPointer->getPointeeType(); } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr) << OrigSrcType << SrcExpr->getSourceRange(); return; } } else if (DestReference->isLValueReferenceType()) { if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) << "dynamic_cast" << OrigDestType << OpRange; } SrcPointee = SrcType; } else { SrcPointee = SrcType; } const RecordType *SrcRecord = SrcPointee->getAsRecordType(); if (SrcRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, diag::err_bad_dynamic_cast_incomplete, SrcExpr->getSourceRange())) return; } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) << SrcPointee.getUnqualifiedType() << SrcExpr->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_const_away) << "dynamic_cast" << OrigDestType << OrigSrcType << 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) { return; } // C++ 5.2.7p5 // Upcasts are resolved statically. if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) { Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee, OpRange.getBegin(), OpRange); // Diagnostic already emitted on error. return; } // C++ 5.2.7p6: Otherwise, v shall be [polymorphic]. const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Self.Context); assert(SrcDecl && "Definition missing"); if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic) << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); } // Done. Everything else is run-time checks. }