From 65615996b9db7c9a5700277007d71477f3cb745a Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Thu, 21 Feb 2013 22:48:34 +0000 Subject: [PATCH] Limit cast machinery to preserve const and not accept temporaries After cleaning up the following type hierarchies: * TypeLoc: r175462 * SVal: r175594 * CFGElement: r175462 * ProgramPoint: r175812 that all invoked undefined behavior by causing a derived copy construction of a base object through an invalid cast (thus supporting code that relied on casting temporaries that were direct base objects) Clang/LLVM is now clean of casts of temporaries. So here's some fun SFINAE machinery (courtesy of Eli Friedman, with some porting back from C++11 to LLVM's traits by me) to cause compile-time failures if llvm::cast & friends are ever passed an rvalue. This should avoid a repeat of anything even remotely like PR14321/r168124. Thanks to Jordan Rose for the help with the various Static Analyzer related hierarchies that needed cleaning up, Eli for the SFINAE, Richard Smith, John McCall, Ted Kremenek, and Anna Zaks for their input/reviews/patience along the way. llvm-svn: 175819 --- llvm/include/llvm/Support/Casting.h | 52 +++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/llvm/include/llvm/Support/Casting.h b/llvm/include/llvm/Support/Casting.h index 0c71882..80f09db4 100644 --- a/llvm/include/llvm/Support/Casting.h +++ b/llvm/include/llvm/Support/Casting.h @@ -55,8 +55,8 @@ struct isa_impl { /// \brief Always allow upcasts, and perform no dynamic check for them. template struct isa_impl::value + typename enable_if< + llvm::is_base_of >::type > { static inline bool doit(const From &) { return true; } @@ -204,12 +204,35 @@ template struct cast_convert_val { // cast(myVal)->getParent() // template -inline typename cast_retty::ret_type cast(const Y &Val) { +inline typename enable_if_c< + !is_same::SimpleType>::value, + typename cast_retty::ret_type +>::type cast(const Y &Val) { assert(isa(Val) && "cast() argument of incompatible type!"); return cast_convert_val::SimpleType>::doit(Val); } +template +inline typename enable_if< + is_same::SimpleType>, + typename cast_retty::ret_type +>::type cast(Y &Val) { + assert(isa(Val) && "cast() argument of incompatible type!"); + return cast_convert_val::SimpleType>::doit(Val); +} + +template +inline typename enable_if< + is_same::SimpleType>, + typename cast_retty::ret_type +>::type cast(Y *Val) { + assert(isa(Val) && "cast() argument of incompatible type!"); + return cast_convert_val::SimpleType>::doit(Val); +} + // cast_or_null - Functionally identical to cast, except that a null value is // accepted. // @@ -230,8 +253,27 @@ inline typename cast_retty::ret_type cast_or_null(Y *Val) { // template -inline typename cast_retty::ret_type dyn_cast(const Y &Val) { - return isa(Val) ? cast(Val) : 0; +inline typename enable_if_c< + !is_same::SimpleType>::value, + typename cast_retty::ret_type +>::type dyn_cast(const Y &Val) { + return isa(Val) ? cast(Val) : 0; +} + +template +inline typename enable_if< + is_same::SimpleType>, + typename cast_retty::ret_type +>::type dyn_cast(Y &Val) { + return isa(Val) ? cast(Val) : 0; +} + +template +inline typename enable_if< + is_same::SimpleType>, + typename cast_retty::ret_type +>::type dyn_cast(Y *Val) { + return isa(Val) ? cast(Val) : 0; } // dyn_cast_or_null - Functionally identical to dyn_cast, except that a null -- 2.7.4