From 9cd53db2f9495bac65d470c6213da7ac6596c3b0 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 7 Mar 2011 01:30:20 +0000 Subject: [PATCH] Do a compiler check that we use one of the types from PointerUnion[N], instead of a runtime check. llvm-svn: 127145 --- include/llvm/ADT/PointerUnion.h | 138 ++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 32 deletions(-) diff --git a/include/llvm/ADT/PointerUnion.h b/include/llvm/ADT/PointerUnion.h index 61de042b0ff..975ba8a5f52 100644 --- a/include/llvm/ADT/PointerUnion.h +++ b/include/llvm/ADT/PointerUnion.h @@ -19,16 +19,56 @@ namespace llvm { - /// getPointerUnionTypeNum - If the argument has type PT1* or PT2* return - /// false or true respectively. + /// \brief Statically get an integer for a type. For: + /// @code + /// PointerUnionTypeNum::template NumFor::Result + /// @endcode + /// Result will be 0 if T is PT1, 1 if it is PT2, and -1 otherwise. template - static inline int getPointerUnionTypeNum(PT1 *P) { return 0; } - template - static inline int getPointerUnionTypeNum(PT2 *P) { return 1; } - template - static inline int getPointerUnionTypeNum(...) { return -1; } - - + struct PointerUnionTypeNum { + private: + struct IsNeither { char x; }; + struct IsPT1 { char x[2]; }; + struct IsPT2 { char x[3]; }; + + static IsPT1 determine(PT1 *P); + static IsPT2 determine(PT2 *P); + static IsNeither determine(...); + + public: + template + struct NumFor { + static const int Result = (int)sizeof(determine((T*)0)) - 2; + }; + }; + + template + struct PointerUnionTypeSelectorReturn { + typedef T Return; + }; + + /// \brief Get a type based on whether two types are the same or not. For: + /// @code + /// typedef typename PointerUnionTypeSelector::Return Ret; + /// @endcode + /// Ret will be EQ type if T1 is same as T2 or NE type otherwise. + template + struct PointerUnionTypeSelector { + typedef typename PointerUnionTypeSelectorReturn::Return Return; + }; + + template + struct PointerUnionTypeSelector { + typedef typename PointerUnionTypeSelectorReturn::Return Return; + }; + + template + struct PointerUnionTypeSelectorReturn< + PointerUnionTypeSelector > { + typedef typename PointerUnionTypeSelector::Return + Return; + }; + /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion /// for the two template arguments. template @@ -87,8 +127,10 @@ namespace llvm { /// is() return true if the Union currently holds the type matching T. template int is() const { - int TyNo = ::llvm::getPointerUnionTypeNum((T*)0); - assert(TyNo != -1 && "Type query could never succeed on PointerUnion!"); + static const int TyNo = + ::llvm::PointerUnionTypeNum::template NumFor::Result; + char TYPE_IS_NOT_IN_UNION[TyNo*2+1]; // statically check the type. + (void)TYPE_IS_NOT_IN_UNION; return static_cast(Val.getInt()) == TyNo; } @@ -175,6 +217,34 @@ namespace llvm { typedef PointerUnion ValTy; private: ValTy Val; + + struct IsInnerUnion { + ValTy Val; + IsInnerUnion(ValTy val) : Val(val) { } + template + int is() const { + return Val.template is() && + Val.template get().template is(); + } + template + T get() const { + return Val.template get().template get(); + } + }; + + struct IsPT3 { + ValTy Val; + IsPT3(ValTy val) : Val(val) { } + template + int is() const { + return Val.template is(); + } + template + T get() const { + return Val.template get(); + } + }; + public: PointerUnion3() {} @@ -196,11 +266,12 @@ namespace llvm { /// is() return true if the Union currently holds the type matching T. template int is() const { - // Is it PT1/PT2? - if (::llvm::getPointerUnionTypeNum((T*)0) != -1) - return Val.template is() && - Val.template get().template is(); - return Val.template is(); + // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3. + typedef typename + ::llvm::PointerUnionTypeSelector + >::Return Ty; + return Ty(Val).is(); } /// get() - Return the value of the specified pointer type. If the @@ -208,11 +279,12 @@ namespace llvm { template T get() const { assert(is() && "Invalid accessor called"); - // Is it PT1/PT2? - if (::llvm::getPointerUnionTypeNum((T*)0) != -1) - return Val.template get().template get(); - - return Val.template get(); + // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3. + typedef typename + ::llvm::PointerUnionTypeSelector + >::Return Ty; + return Ty(Val).get(); } /// dyn_cast() - If the current value is of the specified pointer type, @@ -302,12 +374,13 @@ namespace llvm { /// is() return true if the Union currently holds the type matching T. template int is() const { - // Is it PT1/PT2? - if (::llvm::getPointerUnionTypeNum((T*)0) != -1) - return Val.template is() && - Val.template get().template is(); - return Val.template is() && - Val.template get().template is(); + // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2. + typedef typename + ::llvm::PointerUnionTypeSelector + >::Return Ty; + return Val.template is() && + Val.template get().template is(); } /// get() - Return the value of the specified pointer type. If the @@ -315,11 +388,12 @@ namespace llvm { template T get() const { assert(is() && "Invalid accessor called"); - // Is it PT1/PT2? - if (::llvm::getPointerUnionTypeNum((T*)0) != -1) - return Val.template get().template get(); - - return Val.template get().template get(); + // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2. + typedef typename + ::llvm::PointerUnionTypeSelector + >::Return Ty; + return Val.template get().template get(); } /// dyn_cast() - If the current value is of the specified pointer type,