diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 110c4a73235a..4ef29642d1cc 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2183,6 +2183,7 @@ private: // These should not have an inheritance path. case CK_BitCast: case CK_Dynamic: + case CK_DynamicToNull: case CK_ToUnion: case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: diff --git a/clang/include/clang/AST/OperationKinds.h b/clang/include/clang/AST/OperationKinds.h index ab9d97dbb794..6e16d2196a31 100644 --- a/clang/include/clang/AST/OperationKinds.h +++ b/clang/include/clang/AST/OperationKinds.h @@ -82,6 +82,10 @@ enum CastKind { /// CK_Dynamic - A C++ dynamic_cast. CK_Dynamic, + /// CK_DynamicToNull - A C++ dynamic_cast that can be proven to + /// always yield a null result. + CK_DynamicToNull, + /// CK_ToUnion - The GCC cast-to-union extension. /// int -> union { int x; float y; } /// float -> union { int x; float y; } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 28f42124f984..227d6569ddc7 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -987,6 +987,8 @@ const char *CastExpr::getCastKindName() const { return "UncheckedDerivedToBase"; case CK_Dynamic: return "Dynamic"; + case CK_DynamicToNull: + return "DynamicToNull"; case CK_ToUnion: return "ToUnion"; case CK_ArrayToPointerDecay: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index e0f995829820..aa8d91a6d6d4 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1768,6 +1768,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { case CK_DerivedToBase: case CK_UncheckedDerivedToBase: case CK_Dynamic: + case CK_DynamicToNull: case CK_ToUnion: case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: @@ -2315,6 +2316,7 @@ bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) { case CK_DerivedToBase: case CK_UncheckedDerivedToBase: case CK_Dynamic: + case CK_DynamicToNull: case CK_ToUnion: case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index a35f81ca2066..ad51316a1f5c 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1867,7 +1867,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { return MakeAddrLValue(V, E->getType()); } - case CK_Dynamic: { + case CK_Dynamic: + case CK_DynamicToNull: { LValue LV = EmitLValue(E->getSubExpr()); llvm::Value *V = LV.getAddress(); const CXXDynamicCastExpr *DCE = cast(E); diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 75e3a7879d42..5e1ac3cbacb4 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -255,7 +255,10 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { } switch (E->getCastKind()) { - case CK_Dynamic: { + case CK_Dynamic: + case CK_DynamicToNull: { + + // FIXME: Actually handle DynamicToNull here. assert(isa(E) && "CK_Dynamic without a dynamic_cast?"); LValue LV = CGF.EmitCheckedLValue(E->getSubExpr()); // FIXME: Do we also need to handle property references here? diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 822a999b963d..578a37f0fcf5 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -552,6 +552,7 @@ public: case CK_GetObjCProperty: case CK_ToVoid: case CK_Dynamic: + case CK_DynamicToNull: case CK_ResolveUnknownAnyType: return 0; diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 65aa46fff06d..322b6e0c498e 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1053,7 +1053,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { CE->path_begin(), CE->path_end(), ShouldNullCheckClassCastValue(CE)); } - case CK_Dynamic: { + case CK_Dynamic: + case CK_DynamicToNull: { Value *V = Visit(const_cast(E)); const CXXDynamicCastExpr *DCE = cast(CE); return CGF.EmitDynamicCast(V, DCE); diff --git a/clang/lib/Sema/SemaCXXCast.cpp b/clang/lib/Sema/SemaCXXCast.cpp index 31a772a5d8ef..52a13ef5b298 100644 --- a/clang/lib/Sema/SemaCXXCast.cpp +++ b/clang/lib/Sema/SemaCXXCast.cpp @@ -522,6 +522,14 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, return; } + // If the source class is marked 'final', and the destination class does not + // derive from the source class, then we know that the result is always null. + if (SrcRecord->getDecl()->hasAttr() && + !Self.IsDerivedFrom(DestPointee, SrcPointee)) { + Kind = CK_DynamicToNull; + return; + } + // C++ 5.2.7p5 // Upcasts are resolved statically. if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) { diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 0a7f1e93af19..6a7637097b0c 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -2178,6 +2178,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, // Various C++ casts that are not handled yet. case CK_ResolveUnknownAnyType: case CK_Dynamic: + case CK_DynamicToNull: case CK_ToUnion: case CK_BaseToDerived: case CK_NullToMemberPointer: