@@ -5627,6 +5627,77 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
5627
5627
static bool EvaluateBinaryTypeTrait (Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs,
5628
5628
const TypeSourceInfo *Rhs, SourceLocation KeyLoc);
5629
5629
5630
+ static ExprResult CheckConvertibilityForTypeTraits (Sema &Self,
5631
+ const TypeSourceInfo *Lhs,
5632
+ const TypeSourceInfo *Rhs,
5633
+ SourceLocation KeyLoc) {
5634
+
5635
+ QualType LhsT = Lhs->getType ();
5636
+ QualType RhsT = Rhs->getType ();
5637
+
5638
+ // C++0x [meta.rel]p4:
5639
+ // Given the following function prototype:
5640
+ //
5641
+ // template <class T>
5642
+ // typename add_rvalue_reference<T>::type create();
5643
+ //
5644
+ // the predicate condition for a template specialization
5645
+ // is_convertible<From, To> shall be satisfied if and only if
5646
+ // the return expression in the following code would be
5647
+ // well-formed, including any implicit conversions to the return
5648
+ // type of the function:
5649
+ //
5650
+ // To test() {
5651
+ // return create<From>();
5652
+ // }
5653
+ //
5654
+ // Access checking is performed as if in a context unrelated to To and
5655
+ // From. Only the validity of the immediate context of the expression
5656
+ // of the return-statement (including conversions to the return type)
5657
+ // is considered.
5658
+ //
5659
+ // We model the initialization as a copy-initialization of a temporary
5660
+ // of the appropriate type, which for this expression is identical to the
5661
+ // return statement (since NRVO doesn't apply).
5662
+
5663
+ // Functions aren't allowed to return function or array types.
5664
+ if (RhsT->isFunctionType () || RhsT->isArrayType ())
5665
+ return ExprError ();
5666
+
5667
+ // A function definition requires a complete, non-abstract return type.
5668
+ if (!Self.isCompleteType (Rhs->getTypeLoc ().getBeginLoc (), RhsT) ||
5669
+ Self.isAbstractType (Rhs->getTypeLoc ().getBeginLoc (), RhsT))
5670
+ return ExprError ();
5671
+
5672
+ // Compute the result of add_rvalue_reference.
5673
+ if (LhsT->isObjectType () || LhsT->isFunctionType ())
5674
+ LhsT = Self.Context .getRValueReferenceType (LhsT);
5675
+
5676
+ // Build a fake source and destination for initialization.
5677
+ InitializedEntity To (InitializedEntity::InitializeTemporary (RhsT));
5678
+ OpaqueValueExpr From (KeyLoc, LhsT.getNonLValueExprType (Self.Context ),
5679
+ Expr::getValueKindForType (LhsT));
5680
+ Expr *FromPtr = &From;
5681
+ InitializationKind Kind =
5682
+ InitializationKind::CreateCopy (KeyLoc, SourceLocation ());
5683
+
5684
+ // Perform the initialization in an unevaluated context within a SFINAE
5685
+ // trap at translation unit scope.
5686
+ EnterExpressionEvaluationContext Unevaluated (
5687
+ Self, Sema::ExpressionEvaluationContext::Unevaluated);
5688
+ Sema::SFINAETrap SFINAE (Self, /* AccessCheckingSFINAE=*/ true );
5689
+ Sema::ContextRAII TUContext (Self, Self.Context .getTranslationUnitDecl ());
5690
+ InitializationSequence Init (Self, To, Kind, FromPtr);
5691
+ if (Init.Failed ())
5692
+ return ExprError ();
5693
+
5694
+ ExprResult Result = Init.Perform (Self, To, Kind, FromPtr);
5695
+ if (Result.isInvalid () || SFINAE.hasErrorOccurred ())
5696
+ return ExprError ();
5697
+
5698
+ return Result;
5699
+ }
5700
+
5630
5701
static bool EvaluateBooleanTypeTrait (Sema &S, TypeTrait Kind,
5631
5702
SourceLocation KWLoc,
5632
5703
ArrayRef<TypeSourceInfo *> Args,
@@ -5640,13 +5711,16 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
5640
5711
5641
5712
// Evaluate ReferenceBindsToTemporary and ReferenceConstructsFromTemporary
5642
5713
// alongside the IsConstructible traits to avoid duplication.
5643
- if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary && Kind != BTT_ReferenceConstructsFromTemporary)
5714
+ if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary &&
5715
+ Kind != BTT_ReferenceConstructsFromTemporary &&
5716
+ Kind != BTT_ReferenceConvertsFromTemporary)
5644
5717
return EvaluateBinaryTypeTrait (S, Kind, Args[0 ],
5645
5718
Args[1 ], RParenLoc);
5646
5719
5647
5720
switch (Kind) {
5648
5721
case clang::BTT_ReferenceBindsToTemporary:
5649
5722
case clang::BTT_ReferenceConstructsFromTemporary:
5723
+ case clang::BTT_ReferenceConvertsFromTemporary:
5650
5724
case clang::TT_IsConstructible:
5651
5725
case clang::TT_IsNothrowConstructible:
5652
5726
case clang::TT_IsTriviallyConstructible: {
@@ -5710,8 +5784,10 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
5710
5784
Sema::ContextRAII TUContext (S, S.Context .getTranslationUnitDecl ());
5711
5785
InitializedEntity To (
5712
5786
InitializedEntity::InitializeTemporary (S.Context , Args[0 ]));
5713
- InitializationKind InitKind (InitializationKind::CreateDirect (KWLoc, KWLoc,
5714
- RParenLoc));
5787
+ InitializationKind InitKind (
5788
+ Kind == clang::BTT_ReferenceConvertsFromTemporary
5789
+ ? InitializationKind::CreateCopy (KWLoc, KWLoc)
5790
+ : InitializationKind::CreateDirect (KWLoc, KWLoc, RParenLoc));
5715
5791
InitializationSequence Init (S, To, InitKind, ArgExprs);
5716
5792
if (Init.Failed ())
5717
5793
return false ;
@@ -5723,7 +5799,9 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
5723
5799
if (Kind == clang::TT_IsConstructible)
5724
5800
return true ;
5725
5801
5726
- if (Kind == clang::BTT_ReferenceBindsToTemporary || Kind == clang::BTT_ReferenceConstructsFromTemporary) {
5802
+ if (Kind == clang::BTT_ReferenceBindsToTemporary ||
5803
+ Kind == clang::BTT_ReferenceConstructsFromTemporary ||
5804
+ Kind == clang::BTT_ReferenceConvertsFromTemporary) {
5727
5805
if (!T->isReferenceType ())
5728
5806
return false ;
5729
5807
@@ -5737,9 +5815,12 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
5737
5815
if (U->isReferenceType ())
5738
5816
return false ;
5739
5817
5740
- TypeSourceInfo *TPtr = S.Context .CreateTypeSourceInfo (S.Context .getPointerType (S.BuiltinRemoveReference (T, UnaryTransformType::RemoveCVRef, {})));
5741
- TypeSourceInfo *UPtr = S.Context .CreateTypeSourceInfo (S.Context .getPointerType (S.BuiltinRemoveReference (U, UnaryTransformType::RemoveCVRef, {})));
5742
- return EvaluateBinaryTypeTrait (S, TypeTrait::BTT_IsConvertibleTo, UPtr, TPtr, RParenLoc);
5818
+ TypeSourceInfo *TPtr = S.Context .CreateTypeSourceInfo (
5819
+ S.Context .getPointerType (T.getNonReferenceType ()));
5820
+ TypeSourceInfo *UPtr = S.Context .CreateTypeSourceInfo (
5821
+ S.Context .getPointerType (U.getNonReferenceType ()));
5822
+ return !CheckConvertibilityForTypeTraits (S, UPtr, TPtr, RParenLoc)
5823
+ .isInvalid ();
5743
5824
}
5744
5825
5745
5826
if (Kind == clang::TT_IsNothrowConstructible)
@@ -5945,68 +6026,12 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
5945
6026
case BTT_IsConvertible:
5946
6027
case BTT_IsConvertibleTo:
5947
6028
case BTT_IsNothrowConvertible: {
5948
- // C++0x [meta.rel]p4:
5949
- // Given the following function prototype:
5950
- //
5951
- // template <class T>
5952
- // typename add_rvalue_reference<T>::type create();
5953
- //
5954
- // the predicate condition for a template specialization
5955
- // is_convertible<From, To> shall be satisfied if and only if
5956
- // the return expression in the following code would be
5957
- // well-formed, including any implicit conversions to the return
5958
- // type of the function:
5959
- //
5960
- // To test() {
5961
- // return create<From>();
5962
- // }
5963
- //
5964
- // Access checking is performed as if in a context unrelated to To and
5965
- // From. Only the validity of the immediate context of the expression
5966
- // of the return-statement (including conversions to the return type)
5967
- // is considered.
5968
- //
5969
- // We model the initialization as a copy-initialization of a temporary
5970
- // of the appropriate type, which for this expression is identical to the
5971
- // return statement (since NRVO doesn't apply).
5972
-
5973
- // Functions aren't allowed to return function or array types.
5974
- if (RhsT->isFunctionType () || RhsT->isArrayType ())
5975
- return false ;
5976
-
5977
- // A return statement in a void function must have void type.
5978
6029
if (RhsT->isVoidType ())
5979
6030
return LhsT->isVoidType ();
5980
6031
5981
- // A function definition requires a complete, non-abstract return type.
5982
- if (!Self.isCompleteType (Rhs->getTypeLoc ().getBeginLoc (), RhsT) ||
5983
- Self.isAbstractType (Rhs->getTypeLoc ().getBeginLoc (), RhsT))
5984
- return false ;
5985
-
5986
- // Compute the result of add_rvalue_reference.
5987
- if (LhsT->isObjectType () || LhsT->isFunctionType ())
5988
- LhsT = Self.Context .getRValueReferenceType (LhsT);
5989
-
5990
- // Build a fake source and destination for initialization.
5991
- InitializedEntity To (InitializedEntity::InitializeTemporary (RhsT));
5992
- OpaqueValueExpr From (KeyLoc, LhsT.getNonLValueExprType (Self.Context ),
5993
- Expr::getValueKindForType (LhsT));
5994
- Expr *FromPtr = &From;
5995
- InitializationKind Kind (InitializationKind::CreateCopy (KeyLoc,
5996
- SourceLocation ()));
5997
-
5998
- // Perform the initialization in an unevaluated context within a SFINAE
5999
- // trap at translation unit scope.
6000
- EnterExpressionEvaluationContext Unevaluated (
6001
- Self, Sema::ExpressionEvaluationContext::Unevaluated);
6002
- Sema::SFINAETrap SFINAE (Self, /* AccessCheckingSFINAE=*/ true );
6003
- Sema::ContextRAII TUContext (Self, Self.Context .getTranslationUnitDecl ());
6004
- InitializationSequence Init (Self, To, Kind, FromPtr);
6005
- if (Init.Failed ())
6006
- return false ;
6007
-
6008
- ExprResult Result = Init.Perform (Self, To, Kind, FromPtr);
6009
- if (Result.isInvalid () || SFINAE.hasErrorOccurred ())
6032
+ ExprResult Result =
6033
+ CheckConvertibilityForTypeTraits (Self, Lhs, Rhs, KeyLoc);
6034
+ if (Result.isInvalid ())
6010
6035
return false ;
6011
6036
6012
6037
if (BTT != BTT_IsNothrowConvertible)
0 commit comments