From: Douglas Gregor Date: Sat, 3 Dec 2011 18:14:24 +0000 (+0000) Subject: Implement support for the __is_final type trait, to determine whether X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5e9392ba18f5925e26cc5714d1412eda0d219826;p=clang Implement support for the __is_final type trait, to determine whether a class is marked 'final', from Alberto Ganesh Barbati! Fixes PR11462. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145775 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index c8e70202d5..79b96f6ad5 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -724,6 +724,7 @@ struct is_convertible_to {
  • __is_polymorphic (GNU, Microsoft)
  • __is_union (GNU, Microsoft)
  • __is_literal(type): Determines whether the given type is a literal type
  • +
  • __is_final: Determines whether the given type is declared with a final class-virt-specifier.
  • __underlying_type(type): Retrieves the underlying type for a given enum type. This trait is required to implement the C++11 standard library.
  • diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 07cb4ce300..99ccc9ac4e 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -353,6 +353,7 @@ KEYWORD(__is_class , KEYCXX) KEYWORD(__is_convertible_to , KEYCXX) KEYWORD(__is_empty , KEYCXX) KEYWORD(__is_enum , KEYCXX) +KEYWORD(__is_final , KEYCXX) // Tentative name - there's no implementation of std::is_literal_type yet. KEYWORD(__is_literal , KEYCXX) // Name for GCC 4.6 compatibility - people have already written libraries using diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h index a7a45bded8..3ae56afae5 100644 --- a/include/clang/Basic/TypeTraits.h +++ b/include/clang/Basic/TypeTraits.h @@ -35,6 +35,7 @@ namespace clang { UTT_IsConst, UTT_IsEmpty, UTT_IsEnum, + UTT_IsFinal, UTT_IsFloatingPoint, UTT_IsFunction, UTT_IsFundamental, diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 220e50a058..6d9139c000 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1409,6 +1409,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) { case UTT_IsConst: return "__is_const"; case UTT_IsEmpty: return "__is_empty"; case UTT_IsEnum: return "__is_enum"; + case UTT_IsFinal: return "__is_final"; case UTT_IsFloatingPoint: return "__is_floating_point"; case UTT_IsFunction: return "__is_function"; case UTT_IsFundamental: return "__is_fundamental"; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 2e2dd71b08..20ebb40f53 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -675,6 +675,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { PP.getIdentifierInfo("__is_empty")->getTokenID() != tok::identifier) .Case("is_enum", LangOpts.CPlusPlus) + .Case("is_final", LangOpts.CPlusPlus) .Case("is_literal", LangOpts.CPlusPlus) .Case("is_standard_layout", LangOpts.CPlusPlus) // __is_pod is available only if the horrible diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 4b8fd76269..75fc9be5aa 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -565,6 +565,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// '__is_class' /// '__is_empty' [TODO] /// '__is_enum' +/// '__is_final' /// '__is_pod' /// '__is_polymorphic' /// '__is_trivial' @@ -1087,6 +1088,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_trivial: case tok::kw___is_trivially_copyable: case tok::kw___is_union: + case tok::kw___is_final: case tok::kw___has_trivial_constructor: case tok::kw___has_trivial_copy: case tok::kw___has_trivial_assign: diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index dfc77e17d4..d9983d4167 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -2241,6 +2241,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { case tok::kw___is_const: return UTT_IsConst; case tok::kw___is_empty: return UTT_IsEmpty; case tok::kw___is_enum: return UTT_IsEnum; + case tok::kw___is_final: return UTT_IsFinal; case tok::kw___is_floating_point: return UTT_IsFloatingPoint; case tok::kw___is_function: return UTT_IsFunction; case tok::kw___is_fundamental: return UTT_IsFundamental; diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index d53839f3cb..e682cb4218 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -670,6 +670,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___is_convertible_to: case tok::kw___is_empty: case tok::kw___is_enum: + case tok::kw___is_final: case tok::kw___is_literal: case tok::kw___is_literal_type: case tok::kw___is_pod: diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 973e92d214..06837fef84 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2650,6 +2650,9 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, case UTT_IsAbstract: // Fall-through + // These traits require a complete type. + case UTT_IsFinal: + // These trait expressions are designed to help implement predicates in // [meta.unary.prop] despite not being named the same. They are specified // by both GCC and the Embarcadero C++ compiler, and require the complete @@ -2775,6 +2778,10 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->isAbstract(); return false; + case UTT_IsFinal: + if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + return RD->hasAttr(); + return false; case UTT_IsSigned: return T->isSignedIntegerType(); case UTT_IsUnsigned: diff --git a/test/Lexer/has_feature_type_traits.cpp b/test/Lexer/has_feature_type_traits.cpp index 53056a02b7..0c2cfa56c4 100644 --- a/test/Lexer/has_feature_type_traits.cpp +++ b/test/Lexer/has_feature_type_traits.cpp @@ -70,6 +70,11 @@ int is_enum(); #endif // CHECK: int is_enum(); +#if __has_feature(is_final) +int is_final(); +#endif +// CHECK: int is_final(); + #if __has_feature(is_pod) int is_pod(); #endif diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index 0914c7cf94..2b8714b5e0 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -235,6 +235,37 @@ void is_enum() { int arr[F(__is_enum(HasAnonymousUnion))]; } } +struct FinalClass final { +}; + +template +struct PotentiallyFinal { }; + +template +struct PotentiallyFinal final { }; + +template<> +struct PotentiallyFinal final { }; + +void is_final() +{ + { int arr[T(__is_final(FinalClass))]; } + { int arr[T(__is_final(PotentiallyFinal))]; } + { int arr[T(__is_final(PotentiallyFinal))]; } + + { int arr[F(__is_final(int))]; } + { int arr[F(__is_final(Union))]; } + { int arr[F(__is_final(Int))]; } + { int arr[F(__is_final(IntAr))]; } + { int arr[F(__is_final(UnionAr))]; } + { int arr[F(__is_final(Derives))]; } + { int arr[F(__is_final(ClassType))]; } + { int arr[F(__is_final(cvoid))]; } + { int arr[F(__is_final(IntArNB))]; } + { int arr[F(__is_final(HasAnonymousUnion))]; } + { int arr[F(__is_final(PotentiallyFinal))]; } +} + typedef HasVirt Polymorph; struct InheritPolymorph : Polymorph {};