forked from OSchip/llvm-project
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() llvm-svn: 199619
This commit is contained in:
parent
b4bca41491
commit
73287bfe40
|
@ -998,6 +998,11 @@ The following type trait primitives are supported by Clang:
|
|||
``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
|
||||
======
|
||||
|
|
|
@ -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, 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)
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -3156,6 +3156,8 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
|
|||
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 RecordType *RT, OverloadedOperatorKind Op,
|
|||
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 &Self, TypeTrait UTT,
|
|||
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 &Self, TypeTrait UTT,
|
|||
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, 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:
|
||||
|
@ -3663,20 +3671,31 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
|
|||
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;
|
||||
|
||||
// The initialization succeeded; now make sure there are no non-trivial
|
||||
// calls.
|
||||
return !Result.get()->hasNonTrivialCall(S.Context);
|
||||
if (Kind == clang::TT_IsNothrowConstructible)
|
||||
return S.canThrow(Result.get()) == CT_Cannot;
|
||||
|
||||
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 &Self, TypeTrait BTT, QualType LhsT,
|
|||
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 &Self, TypeTrait BTT, QualType LhsT,
|
|||
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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue