[llvm] r175819 - Limit cast machinery to preserve const and not accept temporaries

David Blaikie dblaikie at gmail.com
Thu Feb 21 14:48:34 PST 2013


Author: dblaikie
Date: Thu Feb 21 16:48:34 2013
New Revision: 175819

URL: http://llvm.org/viewvc/llvm-project?rev=175819&view=rev
Log:
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.

Modified:
    llvm/trunk/include/llvm/Support/Casting.h

Modified: llvm/trunk/include/llvm/Support/Casting.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Casting.h?rev=175819&r1=175818&r2=175819&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/Casting.h (original)
+++ llvm/trunk/include/llvm/Support/Casting.h Thu Feb 21 16:48:34 2013
@@ -55,8 +55,8 @@ struct isa_impl {
 /// \brief Always allow upcasts, and perform no dynamic check for them.
 template <typename To, typename From>
 struct isa_impl<To, From,
-                typename llvm::enable_if_c<
-                  llvm::is_base_of<To, From>::value
+                typename enable_if<
+                  llvm::is_base_of<To, From>
                 >::type
                > {
   static inline bool doit(const From &) { return true; }
@@ -204,12 +204,35 @@ template<class To, class FromTy> struct
 //  cast<Instruction>(myVal)->getParent()
 //
 template <class X, class Y>
-inline typename cast_retty<X, Y>::ret_type cast(const Y &Val) {
+inline typename enable_if_c<
+  !is_same<Y, typename simplify_type<Y>::SimpleType>::value,
+  typename cast_retty<X, Y>::ret_type
+>::type cast(const Y &Val) {
   assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
   return cast_convert_val<X, Y,
                           typename simplify_type<Y>::SimpleType>::doit(Val);
 }
 
+template <class X, class Y>
+inline typename enable_if<
+  is_same<Y, typename simplify_type<Y>::SimpleType>,
+  typename cast_retty<X, Y>::ret_type
+>::type cast(Y &Val) {
+  assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
+  return cast_convert_val<X, Y,
+                          typename simplify_type<Y>::SimpleType>::doit(Val);
+}
+
+template <class X, class Y>
+inline typename enable_if<
+  is_same<Y, typename simplify_type<Y>::SimpleType>,
+  typename cast_retty<X, Y*>::ret_type
+>::type cast(Y *Val) {
+  assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
+  return cast_convert_val<X, Y*,
+                          typename simplify_type<Y*>::SimpleType>::doit(Val);
+}
+
 // cast_or_null<X> - Functionally identical to cast, except that a null value is
 // accepted.
 //
@@ -230,8 +253,27 @@ inline typename cast_retty<X, Y*>::ret_t
 //
 
 template <class X, class Y>
-inline typename cast_retty<X, Y>::ret_type dyn_cast(const Y &Val) {
-  return isa<X>(Val) ? cast<X, Y>(Val) : 0;
+inline typename enable_if_c<
+  !is_same<Y, typename simplify_type<Y>::SimpleType>::value,
+  typename cast_retty<X, Y>::ret_type
+>::type dyn_cast(const Y &Val) {
+  return isa<X>(Val) ? cast<X>(Val) : 0;
+}
+
+template <class X, class Y>
+inline typename enable_if<
+  is_same<Y, typename simplify_type<Y>::SimpleType>,
+  typename cast_retty<X, Y>::ret_type
+>::type dyn_cast(Y &Val) {
+  return isa<X>(Val) ? cast<X>(Val) : 0;
+}
+
+template <class X, class Y>
+inline typename enable_if<
+  is_same<Y, typename simplify_type<Y>::SimpleType>,
+  typename cast_retty<X, Y*>::ret_type
+>::type dyn_cast(Y *Val) {
+  return isa<X>(Val) ? cast<X>(Val) : 0;
 }
 
 // dyn_cast_or_null<X> - Functionally identical to dyn_cast, except that a null





More information about the llvm-commits mailing list