From: Douglas Gregor Date: Thu, 27 Jan 2011 20:28:01 +0000 (+0000) Subject: Implement the Microsoft __is_convertible_to type trait, modeling the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9f3611365d0f2297a910cf246e056708726ed10a;p=clang Implement the Microsoft __is_convertible_to type trait, modeling the 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 --- diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 86f6d1ddad..5c21cd6ccd 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -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) diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h index aecc813d31..00c6e9ed50 100644 --- a/include/clang/Basic/TypeTraits.h +++ b/include/clang/Basic/TypeTraits.h @@ -39,7 +39,8 @@ namespace clang { /// BinaryTypeTrait - Names for the binary type traits. enum BinaryTypeTrait { BTT_IsBaseOf, - BTT_TypeCompatible + BTT_TypeCompatible, + BTT_IsConvertibleTo }; } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 74429ce31d..201115c7eb 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -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 ""; } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 67351f7e2f..5928871987 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -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: { diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 5a16729d80..e769ecac50 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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; } } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 35d72547cd..a603c37a53 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -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: diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index e95bad4d0a..df4103a9a1 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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 + // typename add_rvalue_reference::type create(); + // + // the predicate condition for a template specialization + // is_convertible 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(); + // } + // + // 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, diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index 7962dffe32..54d1236dd8 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -497,3 +497,31 @@ void is_base_of() { isBaseOfT, DerivedB >(); isBaseOfF, BaseA >(); } + +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))]; +}