[PATCH] MSVC 2013 type trait support

Alp Toker alp at nuanti.com
Fri Jan 17 06:52:40 PST 2014


Ping

Need this to parse MSVC headers, patch rebased to ToT.

Alp.


On 12/12/2013 17:13, Alp Toker wrote:
> This patch adds support for the MSVC12.0 / 2013 type trait builtin 
> primitives sufficiently to support the new type_trait facilities added 
> to the C++ standard library.
>
> With these clang is now more or less able to parse itself with the 
> Visual Studio 2013 SDK.
>
> Fully Implemented:
>
> * __is_constructible()
> * __is_nothrow_constructible()
>
> Implemented through fallback to other type traits (WIP, noted with two 
> TODOs):
>
> * __is_destructible()
> * __is_nothrow_destructible()
> * __is_nothrow_assignable()
>
> The patch is built on top of the other two posted earlier today 
> unifying (1) contextual keywords and (2) the new type traits 
> implementation.
>
> Alp.
>

-- 
http://www.nuanti.com
the browser experts

-------------- next part --------------
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 54f7853..0d8a749 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -368,6 +368,13 @@ KEYWORD(L__FUNCTION__               , KEYMS)
 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, KEYMS)
+TYPE_TRAIT_N(__is_constructible, IsConstructible, KEYMS)
+TYPE_TRAIT_N(__is_nothrow_constructible, IsNothrowConstructible, KEYMS)
+
 // GNU and MS Type Traits
 TYPE_TRAIT_1(__has_nothrow_assign, HasNothrowAssign, KEYCXX)
 TYPE_TRAIT_1(__has_nothrow_move_assign, HasNothrowMoveAssign, KEYCXX)
diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h
index a36c8b8..d7d2b18 100644
--- a/include/clang/Basic/TypeTraits.h
+++ b/include/clang/Basic/TypeTraits.h
@@ -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
   };
 
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 363c771..e376e07 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -3158,6 +3158,8 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
   // These traits require a complete type.
   case UTT_IsFinal:
   case UTT_IsSealed:
+  case UTT_IsDestructible:
+  case UTT_IsNothrowDestructible:
 
     // These trait expressions are designed to help implement predicates in
     // [meta.unary.prop] despite not being named the same. They are specified
@@ -3418,6 +3420,10 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
       return RD->hasTrivialCopyAssignment() &&
              !RD->hasNonTrivialCopyAssignment();
     return false;
+  case UTT_IsDestructible:
+  case UTT_IsNothrowDestructible:
+    // TODO: Implement UTT_IsDestructible and UTT_IsNothrowDestructible.
+    // For now, let's fall through.
   case UTT_HasTrivialDestructor:
     // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
     //   If __is_pod (type) is true or type is a reference type
@@ -3598,6 +3604,8 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
                                    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:
@@ -3661,15 +3669,35 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
     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;
 
-    // The initialization succeeded; now make sure there are no non-trivial
-    // calls.
-    return !Result.get()->hasNonTrivialCall(S.Context);
+    if (Kind == clang::TT_IsNothrowConstructible &&
+        isa<CXXConstructExpr>(Result.get())) {
+      CXXConstructExpr *CE = cast<CXXConstructExpr>(Result.get());
+      CXXConstructorDecl *Constructor = CE->getConstructor();
+      const FunctionProtoType *CPT =
+          Constructor->getType()->getAs<FunctionProtoType>();
+      CPT = S.ResolveExceptionSpec(KWLoc, CPT);
+      if (CPT && CPT->isNothrow(S.Context))
+        return true;
+    }
+
+    if (Kind == clang::TT_IsTriviallyConstructible ||
+        Kind == clang::TT_IsNothrowConstructible) {
+      // 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");
   }
@@ -3824,7 +3852,10 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
     ExprResult Result = Init.Perform(Self, To, Kind, FromPtr);
     return !Result.isInvalid() && !SFINAE.hasErrorOccurred();
   }
-      
+
+  case BTT_IsNothrowAssignable:
+    // TODO: Implement nothrow checking shared with TT_IsNothrowConstructible.
+    // Until then, let's fall back to the trivial assign check.
   case BTT_IsTriviallyAssignable: {
     // C++11 [meta.unary.prop]p3:
     //   is_trivially_assignable is defined as:
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index 3e47921..336e5ca 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -1889,6 +1889,19 @@ void trivial_checks()
   { int arr[F((__is_trivially_constructible(class_forward[])))]; }
   { int arr[F((__is_trivially_constructible(void)))]; }
 
+  { int arr[T(__is_nothrow_constructible(HasNoThrowConstructorWithArgs))]; }
+  { int arr[T(__is_nothrow_constructible(HasNoThrowConstructorWithArgs, HasCons))]; }
+  { int arr[F(__is_nothrow_constructible(NonTrivialDefault))]; }
+  { int arr[T(__is_nothrow_constructible(int))]; }
+  { int arr[F(__is_nothrow_constructible(NonPOD))]; }
+  { int arr[F(__is_nothrow_constructible(NonPOD, int))]; }
+
+  { int arr[T(__is_constructible(HasNoThrowConstructorWithArgs))]; }
+  { int arr[T(__is_constructible(HasNoThrowConstructorWithArgs, HasCons))]; }
+  { int arr[T(__is_constructible(NonTrivialDefault))]; }
+  { int arr[F(__is_constructible(NonPOD))]; }
+  { int arr[T(__is_constructible(NonPOD, int))]; }
+
   { int arr[T((__is_trivially_assignable(int&, int)))]; }
   { int arr[T((__is_trivially_assignable(int&, int&)))]; }
   { int arr[T((__is_trivially_assignable(int&, int&&)))]; }


More information about the cfe-commits mailing list