]> granicus.if.org Git - clang/commitdiff
Implement the Microsoft __is_convertible_to type trait, modeling the
authorDouglas Gregor <dgregor@apple.com>
Thu, 27 Jan 2011 20:28:01 +0000 (20:28 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 27 Jan 2011 20:28:01 +0000 (20:28 +0000)
semantics after the C++0x is_convertible type trait. This
implementation is not 100% complete, because it allows access errors
to be hard errors (rather than just evaluating false).

Original patch by Steven Watanabe!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124425 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/TokenKinds.def
include/clang/Basic/TypeTraits.h
lib/AST/StmtPrinter.cpp
lib/Parse/ParseExpr.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/ParseTentative.cpp
lib/Sema/SemaExprCXX.cpp
test/SemaCXX/type-traits.cpp

index 86f6d1ddadf6ba8b17d0a8dd7bd4309b14763ed3..5c21cd6ccde2f44adb03d31bddad05691b9c2f9a 100644 (file)
@@ -319,6 +319,7 @@ KEYWORD(__has_virtual_destructor    , KEYCXX)
 KEYWORD(__is_abstract               , KEYCXX)
 KEYWORD(__is_base_of                , KEYCXX)
 KEYWORD(__is_class                  , KEYCXX)
+KEYWORD(__is_convertible_to         , KEYCXX)
 KEYWORD(__is_empty                  , KEYCXX)
 KEYWORD(__is_enum                   , KEYCXX)
 KEYWORD(__is_pod                    , KEYCXX)
@@ -326,7 +327,6 @@ KEYWORD(__is_polymorphic            , KEYCXX)
 KEYWORD(__is_union                  , KEYCXX)
 // Tentative name - there's no implementation of std::is_literal_type yet.
 KEYWORD(__is_literal                , KEYCXX)
-// FIXME: Add MS's traits, too.
 
 // Apple Extension.
 KEYWORD(__private_extern__          , KEYALL)
index aecc813d31b617956aa4e3df57d9006b89d48dc0..00c6e9ed50009e60576fe34dc2a8e81668d0f558 100644 (file)
@@ -39,7 +39,8 @@ namespace clang {
   /// BinaryTypeTrait - Names for the binary type traits.
   enum BinaryTypeTrait {
     BTT_IsBaseOf,
-    BTT_TypeCompatible
+    BTT_TypeCompatible,
+    BTT_IsConvertibleTo
   };
 }
 
index 74429ce31df4a072b11538dc7b5e6ce4d9f2523f..201115c7eb96554e841dceb5e9403a8ac8757355 100644 (file)
@@ -1225,9 +1225,9 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
 
 static const char *getTypeTraitName(BinaryTypeTrait BTT) {
   switch (BTT) {
-  default: llvm_unreachable("Unknown binary type trait");
   case BTT_IsBaseOf:         return "__is_base_of";
   case BTT_TypeCompatible:   return "__builtin_types_compatible_p";
+  case BTT_IsConvertibleTo:  return "__is_convertible_to";
   }
   return "";
 }
index 67351f7e2fc92b6d7543bf905ce71a5b4703335a..5928871987f8ebdd1504e5252d8208049198052a 100644 (file)
@@ -537,8 +537,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
 ///                   '__is_polymorphic'
 ///                   '__is_union'
 ///
-/// [GNU] binary-type-trait:
-///                   '__is_base_of'                          [TODO]
+///       binary-type-trait:
+/// [GNU]             '__is_base_of'       
+/// [MS]              '__is_convertible_to'
 ///
 ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
                                        bool isAddressOfOperand,
@@ -988,6 +989,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
 
   case tok::kw___builtin_types_compatible_p:
   case tok::kw___is_base_of:
+  case tok::kw___is_convertible_to:
     return ParseBinaryTypeTrait();
 
   case tok::at: {
index 5a16729d80a4ce835425e3186f024de300fa5025..e769ecac503a010f3bfe2c2fc91dc875e4e83d29 100644 (file)
@@ -1828,6 +1828,7 @@ static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) {
   default: llvm_unreachable("Not a known binary type trait");
   case tok::kw___is_base_of:                 return BTT_IsBaseOf;
   case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible;
+  case tok::kw___is_convertible_to:          return BTT_IsConvertibleTo;
   }
 }
 
index 35d72547cd3f4e02a7243dff6d7f965924ad32af..a603c37a53e598f31aa2f3cbeb7b1f9b49d2f9e9 100644 (file)
@@ -655,6 +655,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
   case tok::kw___is_abstract:
   case tok::kw___is_base_of:
   case tok::kw___is_class:
+  case tok::kw___is_convertible_to:
   case tok::kw___is_empty:
   case tok::kw___is_enum:
   case tok::kw___is_pod:
index e95bad4d0a698d730bf15fdd07a4955f730625c1..df4103a9a1b12ff921c26c432c85575654b406d5 100644 (file)
@@ -2499,6 +2499,52 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
   case BTT_TypeCompatible:
     return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(),
                                            RhsT.getUnqualifiedType());
+      
+  case BTT_IsConvertibleTo: {
+    // C++0x [meta.rel]p4:
+    //   Given the following function prototype:
+    //
+    //     template <class T> 
+    //       typename add_rvalue_reference<T>::type create();
+    //
+    //   the predicate condition for a template specialization 
+    //   is_convertible<From, To> shall be satisfied if and only if 
+    //   the return expression in the following code would be 
+    //   well-formed, including any implicit conversions to the return
+    //   type of the function:
+    //
+    //     To test() { 
+    //       return create<From>();
+    //     }
+    //
+    //   Access checking is performed as if in a context unrelated to To and 
+    //   From. Only the validity of the immediate context of the expression 
+    //   of the return-statement (including conversions to the return type)
+    //   is considered.
+    //
+    // We model the initialization as a copy-initialization of a temporary
+    // of the appropriate type, which for this expression is identical to the
+    // return statement (since NRVO doesn't apply).
+    if (LhsT->isObjectType() || LhsT->isFunctionType())
+      LhsT = Self.Context.getRValueReferenceType(LhsT);
+    
+    InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT));
+    OpaqueValueExpr From(LhsT.getNonLValueExprType(Self.Context),
+                         Expr::getValueKindForType(LhsT));
+    Expr *FromPtr = &From;
+    InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, 
+                                                           SourceLocation()));
+    
+    // Perform the initialization within a SFINAE trap.
+    // FIXME: We don't implement the access-checking bits yet, because we don't
+    // handle access control as part of SFINAE.
+    Sema::SFINAETrap SFINAE(Self);
+    InitializationSequence Init(Self, To, Kind, &FromPtr, 1);
+    if (Init.getKind() == InitializationSequence::FailedSequence)
+      return false;
+    ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1));
+    return !Result.isInvalid() && !SFINAE.hasErrorOccurred();
+  }
   }
   llvm_unreachable("Unknown type trait or not implemented");
 }
@@ -2538,9 +2584,9 @@ ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT,
   // Select trait result type.
   QualType ResultType;
   switch (BTT) {
-  default: llvm_unreachable("Unknown type trait or not implemented");
   case BTT_IsBaseOf:       ResultType = Context.BoolTy; break;
   case BTT_TypeCompatible: ResultType = Context.IntTy; break;
+  case BTT_IsConvertibleTo: ResultType = Context.BoolTy; break;
   }
 
   return Owned(new (Context) BinaryTypeTraitExpr(KWLoc, BTT, LhsTSInfo,
index 7962dffe32a3602ca91b93fda6b255777031ee10..54d1236dd85e5256bd7219feb3ac226cce65d766 100644 (file)
@@ -497,3 +497,31 @@ void is_base_of() {
   isBaseOfT<BaseA<int>, DerivedB<int> >();
   isBaseOfF<DerivedB<int>, BaseA<int> >();
 }
+
+struct FromInt { FromInt(int); };
+struct ToInt { operator int(); };
+typedef void Function();
+
+void is_convertible_to() {
+  int t01[T(__is_convertible_to(Int, Int))];
+  int t02[F(__is_convertible_to(Int, IntAr))];
+  int t03[F(__is_convertible_to(IntAr, IntAr))];
+  int t04[T(__is_convertible_to(void, void))];
+  int t05[T(__is_convertible_to(cvoid, void))];
+  int t06[T(__is_convertible_to(void, cvoid))];
+  int t07[T(__is_convertible_to(cvoid, cvoid))];
+  int t08[T(__is_convertible_to(int, FromInt))];
+  int t09[T(__is_convertible_to(long, FromInt))];
+  int t10[T(__is_convertible_to(double, FromInt))];
+  int t11[T(__is_convertible_to(const int, FromInt))];
+  int t12[T(__is_convertible_to(const int&, FromInt))];
+  int t13[T(__is_convertible_to(ToInt, int))];
+  int t14[T(__is_convertible_to(ToInt, const int&))];
+  int t15[T(__is_convertible_to(ToInt, long))];
+  int t16[F(__is_convertible_to(ToInt, int&))];
+  int t17[F(__is_convertible_to(ToInt, FromInt))];
+  int t18[T(__is_convertible_to(IntAr&, IntAr&))];
+  int t19[T(__is_convertible_to(IntAr&, const IntAr&))];
+  int t20[F(__is_convertible_to(const IntAr&, IntAr&))];
+  int t21[F(__is_convertible_to(Function, Function))];
+}