[llvm-commits] [llvm] r165765 - in /llvm/trunk: include/llvm/Support/Casting.h unittests/Support/Casting.cpp

Sean Silva silvas at purdue.edu
Thu Oct 11 16:30:40 PDT 2012


Author: silvas
Date: Thu Oct 11 18:30:40 2012
New Revision: 165765

URL: http://llvm.org/viewvc/llvm-project?rev=165765&view=rev
Log:
Casting.h: Automatically handle isa<Base>(Derived).

Additionally, all such cases are handled with no dynamic check.

All `classof()` of the form

    class Foo {
      [...]
      static bool classof(const Bar *) { return true; }
      [...]
    }

where Foo is an ancestor of Bar are no longer necessary.
Don't write them!

Note: The exact test is `is_base_of<Foo, Bar>`, which is non-strict, so
that Foo is considered an ancestor of itself.

This leads to the following rule of thumb for LLVM-style RTTI:

    The argument type of `classof()` should be a strict ancestor.

For more information about implementing LLVM-style RTTI, see
docs/HowToSetUpLLVMStyleRTTI.rst

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

Modified: llvm/trunk/include/llvm/Support/Casting.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Casting.h?rev=165765&r1=165764&r2=165765&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/Casting.h (original)
+++ llvm/trunk/include/llvm/Support/Casting.h Thu Oct 11 18:30:40 2012
@@ -15,6 +15,7 @@
 #ifndef LLVM_SUPPORT_CASTING_H
 #define LLVM_SUPPORT_CASTING_H
 
+#include "llvm/Support/type_traits.h"
 #include <cassert>
 
 namespace llvm {
@@ -44,13 +45,23 @@
 // The core of the implementation of isa<X> is here; To and From should be
 // the names of classes.  This template can be specialized to customize the
 // implementation of isa<> without rewriting it from scratch.
-template <typename To, typename From>
+template <typename To, typename From, typename Enabler = void>
 struct isa_impl {
   static inline bool doit(const From &Val) {
     return To::classof(&Val);
   }
 };
 
+/// \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
+                >::type
+               > {
+  static inline bool doit(const From &) { return true; }
+};
+
 template <typename To, typename From> struct isa_impl_cl {
   static inline bool doit(const From &Val) {
     return isa_impl<To, From>::doit(Val);

Modified: llvm/trunk/unittests/Support/Casting.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/Casting.cpp?rev=165765&r1=165764&r2=165765&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/Casting.cpp (original)
+++ llvm/trunk/unittests/Support/Casting.cpp Thu Oct 11 18:30:40 2012
@@ -153,3 +153,54 @@
 }  // anonymous namespace
 
 bar *llvm::fub() { return 0; }
+
+namespace {
+namespace inferred_upcasting {
+// This test case verifies correct behavior of inferred upcasts when the
+// types are statically known to be OK to upcast. This is the case when,
+// for example, Derived inherits from Base, and we do `isa<Base>(Derived)`.
+
+// Note: This test will actually fail to compile without inferred
+// upcasting.
+
+class Base {
+public:
+  // No classof. We are testing that the upcast is inferred.
+  Base() {}
+};
+
+class Derived : public Base {
+public:
+  Derived() {}
+};
+
+// Even with no explicit classof() in Base, we should still be able to cast
+// Derived to its base class.
+TEST(CastingTest, UpcastIsInferred) {
+  Derived D;
+  EXPECT_TRUE(isa<Base>(D));
+  Base *BP = dyn_cast<Base>(&D);
+  EXPECT_TRUE(BP != NULL);
+}
+
+
+// This test verifies that the inferred upcast takes precedence over an
+// explicitly written one. This is important because it verifies that the
+// dynamic check gets optimized away.
+class UseInferredUpcast {
+public:
+  int Dummy;
+  static bool classof(const UseInferredUpcast *) {
+    return false;
+  }
+};
+
+TEST(CastingTest, InferredUpcastTakesPrecedence) {
+  UseInferredUpcast UIU;
+  // Since the explicit classof() returns false, this will fail if the
+  // explicit one is used.
+  EXPECT_TRUE(isa<UseInferredUpcast>(&UIU));
+}
+
+} // end namespace inferred_upcasting
+} // end anonymous namespace





More information about the llvm-commits mailing list