r199619 - MSVC 2013 type trait support

Alp Toker alp at nuanti.com
Sun Jan 19 16:24:10 PST 2014


Author: alp
Date: Sun Jan 19 18:24:09 2014
New Revision: 199619

URL: http://llvm.org/viewvc/llvm-project?rev=199619&view=rev
Log:
MSVC 2013 type trait support

Implement type trait primitives used in the latest edition of the Microsoft
standard C++ library type_traits header.

With this change we can parse much of the Visual Studio 2013 standard headers,
particularly anything that includes <type_traits>.

Fully implemented, available in all language modes:

 * __is_constructible()
 * __is_nothrow_constructible()
 * __is_nothrow_assignable()

Partially implemented, semantic analysis WIP, available as MS extensions:

 * __is_destructible()
 * __is_nothrow_destructible()

Modified:
    cfe/trunk/docs/LanguageExtensions.rst
    cfe/trunk/include/clang/Basic/TokenKinds.def
    cfe/trunk/include/clang/Basic/TypeTraits.h
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/test/CXX/except/except.spec/canonical.cpp
    cfe/trunk/test/SemaCXX/type-traits.cpp

Modified: cfe/trunk/docs/LanguageExtensions.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.rst?rev=199619&r1=199618&r2=199619&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.rst (original)
+++ cfe/trunk/docs/LanguageExtensions.rst Sun Jan 19 18:24:09 2014
@@ -998,6 +998,11 @@ The following type trait primitives are
   ``argtypes...`` such that no non-trivial functions are called as part of
   that initialization.  This trait is required to implement the C++11 standard
   library.
+* ``__is_destructible`` (MSVC 2013): partially implemented
+* ``__is_nothrow_destructible`` (MSVC 2013): partially implemented
+* ``__is_nothrow_assignable`` (MSVC 2013, clang)
+* ``__is_constructible`` (MSVC 2013, clang)
+* ``__is_nothrow_constructible`` (MSVC 2013, clang)
 
 Blocks
 ======

Modified: cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=199619&r1=199618&r2=199619&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TokenKinds.def (original)
+++ cfe/trunk/include/clang/Basic/TokenKinds.def Sun Jan 19 18:24:09 2014
@@ -368,6 +368,13 @@ KEYWORD(L__FUNCTION__               , KE
 TYPE_TRAIT_1(__is_interface_class, IsInterfaceClass, KEYMS)
 TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS)
 
+// MSVC12.0 / VS2013 Type Traits
+TYPE_TRAIT_1(__is_destructible, IsDestructible, KEYMS)
+TYPE_TRAIT_1(__is_nothrow_destructible, IsNothrowDestructible, KEYMS)
+TYPE_TRAIT_2(__is_nothrow_assignable, IsNothrowAssignable, KEYCXX)
+TYPE_TRAIT_N(__is_constructible, IsConstructible, KEYCXX)
+TYPE_TRAIT_N(__is_nothrow_constructible, IsNothrowConstructible, KEYCXX)
+
 // GNU and MS Type Traits
 TYPE_TRAIT_1(__has_nothrow_assign, HasNothrowAssign, KEYCXX)
 TYPE_TRAIT_1(__has_nothrow_move_assign, HasNothrowMoveAssign, KEYCXX)

Modified: cfe/trunk/include/clang/Basic/TypeTraits.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TypeTraits.h?rev=199619&r1=199618&r2=199619&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TypeTraits.h (original)
+++ cfe/trunk/include/clang/Basic/TypeTraits.h Sun Jan 19 18:24:09 2014
@@ -37,6 +37,7 @@ namespace clang {
     UTT_IsCompleteType,
     UTT_IsCompound,
     UTT_IsConst,
+    UTT_IsDestructible,
     UTT_IsEmpty,
     UTT_IsEnum,
     UTT_IsFinal,
@@ -50,6 +51,7 @@ namespace clang {
     UTT_IsMemberFunctionPointer,
     UTT_IsMemberObjectPointer,
     UTT_IsMemberPointer,
+    UTT_IsNothrowDestructible,
     UTT_IsObject,
     UTT_IsPOD,
     UTT_IsPointer,
@@ -72,8 +74,11 @@ namespace clang {
     BTT_IsConvertibleTo,
     BTT_IsSame,
     BTT_TypeCompatible,
+    BTT_IsNothrowAssignable,
     BTT_IsTriviallyAssignable,
     BTT_Last = BTT_IsTriviallyAssignable,
+    TT_IsConstructible,
+    TT_IsNothrowConstructible,
     TT_IsTriviallyConstructible
   };
 

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=199619&r1=199618&r2=199619&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sun Jan 19 18:24:09 2014
@@ -3156,6 +3156,8 @@ static bool CheckUnaryTypeTraitTypeCompl
   case UTT_IsPolymorphic:
   case UTT_IsAbstract:
   case UTT_IsInterfaceClass:
+  case UTT_IsDestructible:
+  case UTT_IsNothrowDestructible:
     // Fall-through
 
   // These traits require a complete type.
@@ -3219,7 +3221,7 @@ static bool HasNoThrowOperator(const Rec
         const FunctionProtoType *CPT =
           Operator->getType()->getAs<FunctionProtoType>();
         CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
-        if (!CPT || !CPT->isNothrow(Self.Context))
+        if (!CPT || !CPT->isNothrow(C))
           return false;
       }
     }
@@ -3421,8 +3423,12 @@ static bool EvaluateUnaryTypeTrait(Sema
       return RD->hasTrivialCopyAssignment() &&
              !RD->hasNonTrivialCopyAssignment();
     return false;
+  case UTT_IsDestructible:
+  case UTT_IsNothrowDestructible:
+    // FIXME: Implement UTT_IsDestructible and UTT_IsNothrowDestructible.
+    // For now, let's fall through.
   case UTT_HasTrivialDestructor:
-    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
     //   If __is_pod (type) is true or type is a reference type
     //   then the trait is true, else if type is a cv class or union
     //   type (or array thereof) with a trivial destructor
@@ -3505,7 +3511,7 @@ static bool EvaluateUnaryTypeTrait(Sema
           CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
           if (!CPT)
             return false;
-          // FIXME: check whether evaluating default arguments can throw.
+          // TODO: check whether evaluating default arguments can throw.
           // For now, we'll be conservative and assume that they can throw.
           if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1)
             return false;
@@ -3605,6 +3611,8 @@ static bool evaluateTypeTrait(Sema &S, T
                                    Args[1]->getType(), RParenLoc);
 
   switch (Kind) {
+  case clang::TT_IsConstructible:
+  case clang::TT_IsNothrowConstructible:
   case clang::TT_IsTriviallyConstructible: {
     // C++11 [meta.unary.prop]:
     //   is_trivially_constructible is defined as:
@@ -3663,20 +3671,31 @@ static bool evaluateTypeTrait(Sema &S, T
     InitializationSequence Init(S, To, InitKind, ArgExprs);
     if (Init.Failed())
       return false;
-    
+
     ExprResult Result = Init.Perform(S, To, InitKind, ArgExprs);
     if (Result.isInvalid() || SFINAE.hasErrorOccurred())
       return false;
 
-    // Under Objective-C ARC, if the destination has non-trivial Objective-C
-    // lifetime, this is a non-trivial construction.
-    if (S.getLangOpts().ObjCAutoRefCount &&
-        hasNontrivialObjCLifetime(Args[0]->getType().getNonReferenceType()))
-      return false;
+    if (Kind == clang::TT_IsConstructible)
+      return true;
+
+    if (Kind == clang::TT_IsNothrowConstructible)
+      return S.canThrow(Result.get()) == CT_Cannot;
 
-    // The initialization succeeded; now make sure there are no non-trivial
-    // calls.
-    return !Result.get()->hasNonTrivialCall(S.Context);
+    if (Kind == clang::TT_IsTriviallyConstructible) {
+      // Under Objective-C ARC, if the destination has non-trivial Objective-C
+      // lifetime, this is a non-trivial construction.
+      if (S.getLangOpts().ObjCAutoRefCount &&
+          hasNontrivialObjCLifetime(Args[0]->getType().getNonReferenceType()))
+        return false;
+
+      // The initialization succeeded; now make sure there are no non-trivial
+      // calls.
+      return !Result.get()->hasNonTrivialCall(S.Context);
+    }
+
+    llvm_unreachable("unhandled type trait");
+    return false;
   }
     default: llvm_unreachable("not a TT");
   }
@@ -3831,7 +3850,8 @@ static bool EvaluateBinaryTypeTrait(Sema
     ExprResult Result = Init.Perform(Self, To, Kind, FromPtr);
     return !Result.isInvalid() && !SFINAE.hasErrorOccurred();
   }
-      
+
+  case BTT_IsNothrowAssignable:
   case BTT_IsTriviallyAssignable: {
     // C++11 [meta.unary.prop]p3:
     //   is_trivially_assignable is defined as:
@@ -3877,13 +3897,21 @@ static bool EvaluateBinaryTypeTrait(Sema
     if (Result.isInvalid() || SFINAE.hasErrorOccurred())
       return false;
 
-    // Under Objective-C ARC, if the destination has non-trivial Objective-C
-    // lifetime, this is a non-trivial assignment.
-    if (Self.getLangOpts().ObjCAutoRefCount &&
-        hasNontrivialObjCLifetime(LhsT.getNonReferenceType()))
-      return false;
+    if (BTT == BTT_IsNothrowAssignable)
+      return Self.canThrow(Result.get()) == CT_Cannot;
 
-    return !Result.get()->hasNonTrivialCall(Self.Context);
+    if (BTT == BTT_IsTriviallyAssignable) {
+      // Under Objective-C ARC, if the destination has non-trivial Objective-C
+      // lifetime, this is a non-trivial assignment.
+      if (Self.getLangOpts().ObjCAutoRefCount &&
+          hasNontrivialObjCLifetime(LhsT.getNonReferenceType()))
+        return false;
+
+      return !Result.get()->hasNonTrivialCall(Self.Context);
+    }
+
+    llvm_unreachable("unhandled type trait");
+    return false;
   }
     default: llvm_unreachable("not a BTT");
   }

Modified: cfe/trunk/test/CXX/except/except.spec/canonical.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/canonical.cpp?rev=199619&r1=199618&r2=199619&view=diff
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/canonical.cpp (original)
+++ cfe/trunk/test/CXX/except/except.spec/canonical.cpp Sun Jan 19 18:24:09 2014
@@ -9,7 +9,7 @@ namespace std
 template <class _Tp> _Tp&& declval() noexcept;
 
 template <class _Tp, class... _Args>
-struct __is_nothrow_constructible
+struct _is_nothrow_constructible
 {
   static const bool value = noexcept(_Tp(declval<_Args>()...));
 };
@@ -22,7 +22,7 @@ public:
   typedef _Allocator allocator_type;
 
   basic_string()
-      noexcept(__is_nothrow_constructible<allocator_type>::value);
+      noexcept(_is_nothrow_constructible<allocator_type>::value);
 };
 
 template <class, class, class _Compare>
@@ -30,7 +30,7 @@ struct __map_value_compare
 {
 public:
   __map_value_compare()
-      noexcept(__is_nothrow_constructible<_Compare>::value);
+      noexcept(_is_nothrow_constructible<_Compare>::value);
 };
 
 struct less
@@ -45,10 +45,10 @@ struct map
 
 
 template<class T, class _Traits, class _Allocator>
-basic_string<T, _Traits, _Allocator>::basic_string() noexcept(__is_nothrow_constructible<allocator_type>::value) {}
+basic_string<T, _Traits, _Allocator>::basic_string() noexcept(_is_nothrow_constructible<allocator_type>::value) {}
 
 template <class T, class Value, class _Compare>
 __map_value_compare<T, Value, _Compare>::__map_value_compare()
-  noexcept(__is_nothrow_constructible<_Compare>::value) {}
+  noexcept(_is_nothrow_constructible<_Compare>::value) {}
 
 }  // std

Modified: cfe/trunk/test/SemaCXX/type-traits.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=199619&r1=199618&r2=199619&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/type-traits.cpp (original)
+++ cfe/trunk/test/SemaCXX/type-traits.cpp Sun Jan 19 18:24:09 2014
@@ -1483,6 +1483,10 @@ void has_nothrow_move_assign() {
   { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToUDCopyCtor))]; }
   { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToUDCopyAssign))]; }
   { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToDtor))]; }
+
+
+  { int arr[T(__is_nothrow_assignable(HasNoThrowMoveAssign, HasNoThrowMoveAssign))]; }
+  { int arr[F(__is_nothrow_assignable(HasThrowMoveAssign, HasThrowMoveAssign))]; }
 }
 
 void has_trivial_move_assign() {
@@ -1942,6 +1946,26 @@ void trivial_checks()
                                          TrivialMoveButNotCopy&&)))]; }
 }
 
+void constructible_checks() {
+  { int arr[T(__is_constructible(HasNoThrowConstructorWithArgs))]; }
+  { int arr[F(__is_nothrow_constructible(HasNoThrowConstructorWithArgs))]; } // MSVC doesn't look into default args and gets this wrong.
+
+  { int arr[T(__is_constructible(HasNoThrowConstructorWithArgs, HasCons))]; }
+  { int arr[T(__is_nothrow_constructible(HasNoThrowConstructorWithArgs, HasCons))]; }
+
+  { int arr[T(__is_constructible(NonTrivialDefault))]; }
+  { int arr[F(__is_nothrow_constructible(NonTrivialDefault))]; }
+
+  { int arr[T(__is_constructible(int))]; }
+  { int arr[T(__is_nothrow_constructible(int))]; }
+
+  { int arr[F(__is_constructible(NonPOD))]; }
+  { int arr[F(__is_nothrow_constructible(NonPOD))]; }
+
+  { int arr[T(__is_constructible(NonPOD, int))]; }
+  { int arr[F(__is_nothrow_constructible(NonPOD, int))]; }
+}
+
 // Instantiation of __is_trivially_constructible
 template<typename T, typename ...Args>
 struct is_trivially_constructible {





More information about the cfe-commits mailing list