diff options
33 files changed, 656 insertions, 6 deletions
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index d38f5d05ce..2471c60776 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -889,6 +889,8 @@ struct is_convertible_to { <li><code>__is_literal(type)</code>: Determines whether the given type is a literal type</li> <li><code>__is_final</code>: Determines whether the given type is declared with a <code>final</code> class-virt-specifier.</li> <li><code>__underlying_type(type)</code>: Retrieves the underlying type for a given <code>enum</code> type. This trait is required to implement the C++11 standard library.</li> + <li><code>__is_trivially_assignable(totype, fromtype)</code>: Determines whether a value of type <tt>totype</tt> can be assigned to from a value of type <tt>fromtype</tt> such that no non-trivial functions are called as part of that assignment. This trait is required to implement the C++11 standard library.</li> + <li><code>__is_trivially_constructible(type, argtypes...)</code>: Determines whether a value of type <tt>type</tt> can be direct-initialized with arguments of types <tt>argtypes...</tt> such that no non-trivial functions are called as part of that initialization. This trait is required to implement the C++11 standard library.</li> </ul> <!-- ======================================================================= --> diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index f21ba1f3b7..40050c3d2c 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1926,6 +1926,102 @@ public: friend class ASTStmtReader; }; +/// \brief A type trait used in the implementation of various C++11 and +/// Library TR1 trait templates. +/// +/// \code +/// __is_trivially_constructible(vector<int>, int*, int*) +/// \endcode +class TypeTraitExpr : public Expr { + /// \brief The location of the type trait keyword. + SourceLocation Loc; + + /// \brief The location of the closing parenthesis. + SourceLocation RParenLoc; + + // Note: The TypeSourceInfos for the arguments are allocated after the + // TypeTraitExpr. + + TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc, + bool Value); + + TypeTraitExpr(EmptyShell Empty) : Expr(TypeTraitExprClass, Empty) { } + + /// \brief Retrieve the argument types. + TypeSourceInfo **getTypeSourceInfos() { + return reinterpret_cast<TypeSourceInfo **>(this+1); + } + + /// \brief Retrieve the argument types. + TypeSourceInfo * const *getTypeSourceInfos() const { + return reinterpret_cast<TypeSourceInfo * const*>(this+1); + } + +public: + /// \brief Create a new type trait expression. + static TypeTraitExpr *Create(ASTContext &C, QualType T, SourceLocation Loc, + TypeTrait Kind, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc, + bool Value); + + static TypeTraitExpr *CreateDeserialized(ASTContext &C, unsigned NumArgs); + + /// \brief Determine which type trait this expression uses. + TypeTrait getTrait() const { + return static_cast<TypeTrait>(TypeTraitExprBits.Kind); + } + + bool getValue() const { + assert(!isValueDependent()); + return TypeTraitExprBits.Value; + } + + /// \brief Determine the number of arguments to this type trait. + unsigned getNumArgs() const { return TypeTraitExprBits.NumArgs; } + + /// \brief Retrieve the Ith argument. + TypeSourceInfo *getArg(unsigned I) const { + assert(I < getNumArgs() && "Argument out-of-range"); + return getArgs()[I]; + } + + /// \brief Retrieve the argument types. + ArrayRef<TypeSourceInfo *> getArgs() const { + return ArrayRef<TypeSourceInfo *>(getTypeSourceInfos(), getNumArgs()); + } + + typedef TypeSourceInfo **arg_iterator; + arg_iterator arg_begin() { + return getTypeSourceInfos(); + } + arg_iterator arg_end() { + return getTypeSourceInfos() + getNumArgs(); + } + + typedef TypeSourceInfo const * const *arg_const_iterator; + arg_const_iterator arg_begin() const { return getTypeSourceInfos(); } + arg_const_iterator arg_end() const { + return getTypeSourceInfos() + getNumArgs(); + } + + SourceRange getSourceRange() const { return SourceRange(Loc, RParenLoc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == TypeTraitExprClass; + } + static bool classof(const TypeTraitExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +}; + /// ArrayTypeTraitExpr - An Embarcadero array type trait, as used in the /// implementation of __array_rank and __array_extent. /// Example: diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index a0f4950a04..a1214a9d25 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1946,6 +1946,11 @@ DEF_TRAVERSE_STMT(BinaryTypeTraitExpr, { TRY_TO(TraverseTypeLoc(S->getRhsTypeSourceInfo()->getTypeLoc())); }) +DEF_TRAVERSE_STMT(TypeTraitExpr, { + for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I) + TRY_TO(TraverseTypeLoc(S->getArg(I)->getTypeLoc())); +}) + DEF_TRAVERSE_STMT(ArrayTypeTraitExpr, { TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc())); }) diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index be2b706fac..1bc0c11ef5 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -227,6 +227,24 @@ protected: unsigned InitializesStdInitializerList : 1; }; + class TypeTraitExprBitfields { + friend class TypeTraitExpr; + friend class ASTStmtReader; + friend class ASTStmtWriter; + + unsigned : NumExprBits; + + /// \brief The kind of type trait, which is a value of a TypeTrait enumerator. + unsigned Kind : 8; + + /// \brief If this expression is not value-dependent, this indicates whether + /// the trait evaluated true or false. + unsigned Value : 1; + + /// \brief The number of arguments to this type trait. + unsigned NumArgs : 32 - 8 - 1 - NumExprBits; + }; + union { // FIXME: this is wasteful on 64-bit platforms. void *Aligner; @@ -241,9 +259,11 @@ protected: PseudoObjectExprBitfields PseudoObjectExprBits; ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits; InitListExprBitfields InitListExprBits; + TypeTraitExprBitfields TypeTraitExprBits; }; friend class ASTStmtReader; + friend class ASTStmtWriter; public: // Only allow allocation of Stmts using the allocator in ASTContext diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 4e60edf37d..bfece366f1 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4438,6 +4438,10 @@ def note_inequality_comparison_to_or_assign : Note< def err_incomplete_type_used_in_type_trait_expr : Error< "incomplete type %0 used in type trait expression">; +def err_type_trait_arity : Error< + "type trait requires %0%select{| or more}1 argument%select{|s}2; have " + "%3 argument%s3">; + def err_dimension_expr_not_constant_integer : Error< "dimension expression does not evaluate to a constant unsigned int">; def err_expected_ident_or_lparen : Error<"expected identifier or '('">; diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index d728221869..07bb227b82 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -107,6 +107,7 @@ def CXXScalarValueInitExpr : DStmt<Expr>; def CXXNewExpr : DStmt<Expr>; def CXXDeleteExpr : DStmt<Expr>; def CXXPseudoDestructorExpr : DStmt<Expr>; +def TypeTraitExpr : DStmt<Expr>; def UnaryTypeTraitExpr : DStmt<Expr>; def BinaryTypeTraitExpr : DStmt<Expr>; def ArrayTypeTraitExpr : DStmt<Expr>; diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 300db4d886..74072ba16a 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -365,6 +365,7 @@ KEYWORD(__is_trivial , KEYCXX) KEYWORD(__is_union , KEYCXX) // Clang-only C++ Type Traits +KEYWORD(__is_trivially_constructible, KEYCXX) KEYWORD(__is_trivially_copyable , KEYCXX) KEYWORD(__is_trivially_assignable , KEYCXX) KEYWORD(__underlying_type , KEYCXX) diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h index 6ed2adfaf5..721f44f408 100644 --- a/include/clang/Basic/TypeTraits.h +++ b/include/clang/Basic/TypeTraits.h @@ -84,6 +84,12 @@ namespace clang { UETT_AlignOf, UETT_VecStep }; + + /// \brief Names for type traits that operate specifically on types. + enum TypeTrait { + TT_IsTriviallyConstructible + }; + } #endif diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 64736118e1..e7834edac7 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -2170,7 +2170,8 @@ private: // GNU G++: Type Traits [Type-Traits.html in the GCC manual] ExprResult ParseUnaryTypeTrait(); ExprResult ParseBinaryTypeTrait(); - + ExprResult ParseTypeTrait(); + //===--------------------------------------------------------------------===// // Embarcadero: Arary and Expression Traits ExprResult ParseArrayTypeTrait(); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 7aed347d41..8131c6372e 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3317,6 +3317,14 @@ public: TypeSourceInfo *RhsT, SourceLocation RParen); + /// \brief Parsed one of the type trait support pseudo-functions. + ExprResult ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<ParsedType> Args, + SourceLocation RParenLoc); + ExprResult BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc); + /// ActOnArrayTypeTrait - Parsed one of the bianry type trait support /// pseudo-functions. ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT, diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 7ec2cac7ff..7de6b4589a 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -1156,6 +1156,7 @@ namespace clang { EXPR_OPAQUE_VALUE, // OpaqueValueExpr EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator EXPR_BINARY_TYPE_TRAIT, // BinaryTypeTraitExpr + EXPR_TYPE_TRAIT, // TypeTraitExpr EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr EXPR_PACK_EXPANSION, // PackExpansionExpr diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index a1770c915a..37df90407d 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2169,6 +2169,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { case AddrLabelExprClass: case ArrayTypeTraitExprClass: case BinaryTypeTraitExprClass: + case TypeTraitExprClass: case CXXBoolLiteralExprClass: case CXXNoexceptExprClass: case CXXNullPtrLiteralExprClass: diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 7ef3417e6d..da89bf2798 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -199,7 +199,6 @@ SourceRange CXXPseudoDestructorExpr::getSourceRange() const { return SourceRange(Base->getLocStart(), End); } - // UnresolvedLookupExpr UnresolvedLookupExpr * UnresolvedLookupExpr::Create(ASTContext &C, @@ -1262,4 +1261,51 @@ TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const { return TemplateArgument(Arguments, NumArguments); } +TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc, + bool Value) + : Expr(TypeTraitExprClass, T, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, + /*ValueDependent=*/false, + /*InstantiationDependent=*/false, + /*ContainsUnexpandedParameterPack=*/false), + Loc(Loc), RParenLoc(RParenLoc) +{ + TypeTraitExprBits.Kind = Kind; + TypeTraitExprBits.Value = Value; + TypeTraitExprBits.NumArgs = Args.size(); + + TypeSourceInfo **ToArgs = getTypeSourceInfos(); + + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + if (Args[I]->getType()->isDependentType()) + setValueDependent(true); + if (Args[I]->getType()->isInstantiationDependentType()) + setInstantiationDependent(true); + if (Args[I]->getType()->containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(true); + + ToArgs[I] = Args[I]; + } +} + +TypeTraitExpr *TypeTraitExpr::Create(ASTContext &C, QualType T, + SourceLocation Loc, + TypeTrait Kind, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc, + bool Value) { + unsigned Size = sizeof(TypeTraitExpr) + sizeof(TypeSourceInfo*) * Args.size(); + void *Mem = C.Allocate(Size); + return new (Mem) TypeTraitExpr(T, Loc, Kind, Args, RParenLoc, Value); +} + +TypeTraitExpr *TypeTraitExpr::CreateDeserialized(ASTContext &C, + unsigned NumArgs) { + unsigned Size = sizeof(TypeTraitExpr) + sizeof(TypeSourceInfo*) * NumArgs; + void *Mem = C.Allocate(Size); + return new (Mem) TypeTraitExpr(EmptyShell()); +} + void ArrayTypeTraitExpr::anchor() { } diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 79d8dc48fe..1b04428fae 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -151,6 +151,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXScalarValueInitExprClass: case Expr::UnaryTypeTraitExprClass: case Expr::BinaryTypeTraitExprClass: + case Expr::TypeTraitExprClass: case Expr::ArrayTypeTraitExprClass: case Expr::ExpressionTraitExprClass: case Expr::ObjCSelectorExprClass: diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index ed64153f85..85aa5ee81e 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -4119,6 +4119,10 @@ public: return Success(E->getValue(), E); } + bool VisitTypeTraitExpr(const TypeTraitExpr *E) { + return Success(E->getValue(), E); + } + bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) { return Success(E->getValue(), E); } @@ -6360,6 +6364,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXScalarValueInitExprClass: case Expr::UnaryTypeTraitExprClass: case Expr::BinaryTypeTraitExprClass: + case Expr::TypeTraitExprClass: case Expr::ArrayTypeTraitExprClass: case Expr::ExpressionTraitExprClass: case Expr::CXXNoexceptExprClass: diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 5e167f58dc..91e6ee5c97 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -2383,6 +2383,7 @@ recurse: case Expr::StmtExprClass: case Expr::UnaryTypeTraitExprClass: case Expr::BinaryTypeTraitExprClass: + case Expr::TypeTraitExprClass: case Expr::ArrayTypeTraitExprClass: case Expr::ExpressionTraitExprClass: case Expr::VAArgExprClass: diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 51296ad5f4..6d3e783f22 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1555,6 +1555,13 @@ static const char *getTypeTraitName(BinaryTypeTrait BTT) { llvm_unreachable("Binary type trait not covered by switch"); } +static const char *getTypeTraitName(TypeTrait TT) { + switch (TT) { + case clang::TT_IsTriviallyConstructible:return "__is_trivially_constructible"; + } + llvm_unreachable("Type trait not covered by switch"); +} + static const char *getTypeTraitName(ArrayTypeTrait ATT) { switch (ATT) { case ATT_ArrayRank: return "__array_rank"; @@ -1582,6 +1589,16 @@ void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { << E->getRhsType().getAsString(Policy) << ")"; } +void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) { + OS << getTypeTraitName(E->getTrait()) << "("; + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) { + if (I > 0) + OS << ", "; + OS << E->getArg(I)->getType().getAsString(Policy); + } + OS << ")"; +} + void StmtPrinter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { OS << getTypeTraitName(E->getTrait()) << "(" << E->getQueriedType().getAsString(Policy) << ")"; diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index fdd0c8502d..643bca817c 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -868,6 +868,14 @@ void StmtProfiler::VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *S) { VisitType(S->getRhsType()); } +void StmtProfiler::VisitTypeTraitExpr(const TypeTraitExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getTrait()); + ID.AddInteger(S->getNumArgs()); + for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I) + VisitType(S->getArg(I)->getType()); +} + void StmtProfiler::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *S) { VisitExpr(S); ID.AddInteger(S->getTrait()); diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 0e00996410..bc34692702 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -701,6 +701,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("is_polymorphic", LangOpts.CPlusPlus) .Case("is_trivial", LangOpts.CPlusPlus) .Case("is_trivially_assignable", LangOpts.CPlusPlus) + .Case("is_trivially_constructible", LangOpts.CPlusPlus) .Case("is_trivially_copyable", LangOpts.CPlusPlus) .Case("is_union", LangOpts.CPlusPlus) .Case("modules", LangOpts.Modules) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index fdf40e877c..62d1f494be 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1143,6 +1143,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_trivially_assignable: return ParseBinaryTypeTrait(); + case tok::kw___is_trivially_constructible: + return ParseTypeTrait(); + case tok::kw___array_rank: case tok::kw___array_extent: return ParseArrayTypeTrait(); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 19bc22020c..d8663077fd 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -2458,6 +2458,14 @@ static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) { } } +static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) { + switch (kind) { + default: llvm_unreachable("Not a known type trait"); + case tok::kw___is_trivially_constructible: + return TT_IsTriviallyConstructible; + } +} + static ArrayTypeTrait ArrayTypeTraitFromTokKind(tok::TokenKind kind) { switch(kind) { default: llvm_unreachable("Not a known binary type trait"); @@ -2540,6 +2548,58 @@ ExprResult Parser::ParseBinaryTypeTrait() { T.getCloseLocation()); } +/// \brief Parse the built-in type-trait pseudo-functions that allow +/// implementation of the TR1/C++11 type traits templates. +/// +/// primary-expression: +/// type-trait '(' type-id-seq ')' +/// +/// type-id-seq: +/// type-id ...[opt] type-id-seq[opt] +/// +ExprResult Parser::ParseTypeTrait() { + TypeTrait Kind = TypeTraitFromTokKind(Tok.getKind()); + SourceLocation Loc = ConsumeToken(); + + BalancedDelimiterTracker Parens(*this, tok::l_paren); + if (Parens.expectAndConsume(diag::err_expected_lparen)) + return ExprError(); + + llvm::SmallVector<ParsedType, 2> Args; + do { + // Parse the next type. + TypeResult Ty = ParseTypeName(); + if (Ty.isInvalid()) { + Parens.skipToEnd(); + return ExprError(); + } + + // Parse the ellipsis, if present. + if (Tok.is(tok::ellipsis)) { + Ty = Actions.ActOnPackExpansion(Ty.get(), ConsumeToken()); + if (Ty.isInvalid()) { + Parens.skipToEnd(); + return ExprError(); + } + } + + // Add this type to the list of arguments. + Args.push_back(Ty.get()); + + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; + } + + break; + } while (true); + + if (Parens.consumeClose()) + return ExprError(); + + return Actions.ActOnTypeTrait(Kind, Loc, Args, Parens.getCloseLocation()); +} + /// ParseArrayTypeTrait - Parse the built-in array type-trait /// pseudo-functions. /// diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 011c28aaf7..92ae770fa0 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -690,6 +690,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___is_polymorphic: case tok::kw___is_trivial: case tok::kw___is_trivially_assignable: + case tok::kw___is_trivially_constructible: case tok::kw___is_trivially_copyable: case tok::kw___is_union: case tok::kw___uuidof: diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 708db1c9a9..a4ae9be41b 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -3212,6 +3212,127 @@ ExprResult Sema::ActOnBinaryTypeTrait(BinaryTypeTrait BTT, return BuildBinaryTypeTrait(BTT, KWLoc, LhsTSInfo, RhsTSInfo, RParen); } +static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc) { + switch (Kind) { + case clang::TT_IsTriviallyConstructible: { + // C++11 [meta.unary.prop]: + // is_trivially_constructor is defined as: + // + // is_constructible<T, Args...>::value is true and the variable + // + /// definition for is_constructible, as defined below, is known to call no + // operation that is not trivial. + // + // The predicate condition for a template specialization + // is_constructible<T, Args...> shall be satisfied if and only if the + // following variable definition would be well-formed for some invented + // variable t: + // + // T t(create<Args>()...); + if (Args.empty()) { + S.Diag(KWLoc, diag::err_type_trait_arity) + << 1 << 1 << 1 << (int)Args.size(); + return false; + } + + bool SawVoid = false; + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + if (Args[I]->getType()->isVoidType()) { + SawVoid = true; + continue; + } + + if (!Args[I]->getType()->isIncompleteType() && + S.RequireCompleteType(KWLoc, Args[I]->getType(), + diag::err_incomplete_type_used_in_type_trait_expr)) + return false; + } + + // If any argument was 'void', of course it won't type-check. + if (SawVoid) + return false; + + llvm::SmallVector<OpaqueValueExpr, 2> OpaqueArgExprs; + llvm::SmallVector<Expr *, 2> ArgExprs; + ArgExprs.reserve(Args.size() - 1); + for (unsigned I = 1, N = Args.size(); I != N; ++I) { + QualType T = Args[I]->getType(); + if (T->isObjectType() || T->isFunctionType()) + T = S.Context.getRValueReferenceType(T); + OpaqueArgExprs.push_back( + OpaqueValueExpr(Args[I]->getTypeLoc().getSourceRange().getBegin(), + T.getNonLValueExprType(S.Context), + Expr::getValueKindForType(T))); + ArgExprs.push_back(&OpaqueArgExprs.back()); + } + + // Perform the initialization in an unevaluated context within a SFINAE + // trap at translation unit scope. + EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); + Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); + Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); + InitializedEntity To(InitializedEntity::InitializeTemporary(Args[0])); + InitializationKind InitKind(InitializationKind::CreateDirect(KWLoc, KWLoc, + RParenLoc)); + InitializationSequence Init(S, To, InitKind, + ArgExprs.begin(), ArgExprs.size()); + if (Init.Failed()) + return false; + + ExprResult Result = Init.Perform(S, To, InitKind, + MultiExprArg(ArgExprs.data(), + ArgExprs.size())); + if (Result.isInvalid() || SFINAE.hasErrorOccurred()) + return false; + + // The initialization succeeded; not make sure there are no non-trivial + // calls. + return !Result.get()->hasNonTrivialCall(S.Context); + } + } + + return false; +} + +ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc) { + bool Dependent = false; + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + if (Args[I]->getType()->isDependentType()) { + Dependent = true; + break; + } + } + + bool Value = false; + if (!Dependent) + Value = evaluateTypeTrait(*this, Kind, KWLoc, Args, RParenLoc); + + return TypeTraitExpr::Create(Context, Context.BoolTy, KWLoc, Kind, + Args, RParenLoc, Value); +} + +ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<ParsedType> Args, + SourceLocation RParenLoc) { + llvm::SmallVector<TypeSourceInfo *, 4> ConvertedArgs; + ConvertedArgs.reserve(Args.size()); + + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + TypeSourceInfo *TInfo; + QualType T = GetTypeFromParser(Args[I], &TInfo); + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(T, KWLoc); + + ConvertedArgs.push_back(TInfo); + } + + return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc); +} + static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, QualType LhsT, QualType RhsT, SourceLocation KeyLoc) { diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 58d6a22a28..f0b5f4e241 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -2022,6 +2022,17 @@ public: return getSema().BuildBinaryTypeTrait(Trait, StartLoc, LhsT, RhsT, RParenLoc); } + /// \brief Build a new type trait expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildTypeTrait(TypeTrait Trait, + SourceLocation StartLoc, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc) { + return getSema().BuildTypeTrait(Trait, StartLoc, Args, RParenLoc); + } + /// \brief Build a new array type trait expression. /// /// By default, performs semantic analysis to build the new expression. @@ -7436,6 +7447,128 @@ TreeTransform<Derived>::TransformBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) { + bool ArgChanged = false; + llvm::SmallVector<TypeSourceInfo *, 4> Args; + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) { + TypeSourceInfo *From = E->getArg(I); + TypeLoc FromTL = From->getTypeLoc(); + if (!isa<PackExpansionTypeLoc>(FromTL)) { + TypeLocBuilder TLB; + TLB.reserve(FromTL.getFullDataSize()); + QualType To = getDerived().TransformType(TLB, FromTL); + if (To.isNull()) + return ExprError(); + + if (To == From->getType()) + Args.push_back(From); + else { + Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To)); + ArgChanged = true; + } + continue; + } + + ArgChanged = true; + + // We have a pack expansion. Instantiate it. + PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(FromTL); + TypeLoc PatternTL = ExpansionTL.getPatternLoc(); + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SemaRef.collectUnexpandedParameterPacks(PatternTL, Unexpanded); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + llvm::Optional<unsigned> OrigNumExpansions + = ExpansionTL.getTypePtr()->getNumExpansions(); + llvm::Optional<unsigned> NumExpansions = OrigNumExpansions; + if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), + PatternTL.getSourceRange(), + Unexpanded, + Expand, RetainExpansion, + NumExpansions)) + return ExprError(); + + if (!Expand) { + // The transform has determined that we should perform a simple + // transformation on the pack expansion, producing another pack + // expansion. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + + TypeLocBuilder TLB; + TLB.reserve(From->getTypeLoc().getFullDataSize()); + + QualType To = getDerived().TransformType(TLB, PatternTL); + if (To.isNull()) + return ExprError(); + + To = getDerived().RebuildPackExpansionType(To, + PatternTL.getSourceRange(), + ExpansionTL.getEllipsisLoc(), + NumExpansions); + if (To.isNull()) + return ExprError(); + + PackExpansionTypeLoc ToExpansionTL + = TLB.push<PackExpansionTypeLoc>(To); + ToExpansionTL.setEllipsisLoc(ExpansionTL.getEllipsisLoc()); + Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To)); + continue; + } + + // Expand the pack expansion by substituting for each argument in the + // pack(s). + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I); + TypeLocBuilder TLB; + TLB.reserve(PatternTL.getFullDataSize()); + QualType To = getDerived().TransformType(TLB, PatternTL); + if (To.isNull()) + return ExprError(); + + Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To)); + } + + if (!RetainExpansion) + continue; + + // If we're supposed to retain a pack expansion, do so by temporarily + // forgetting the partially-substituted parameter pack. + ForgetPartiallySubstitutedPackRAII Forget(getDerived()); + + TypeLocBuilder TLB; + TLB.reserve(From->getTypeLoc().getFullDataSize()); + + QualType To = getDerived().TransformType(TLB, PatternTL); + if (To.isNull()) + return ExprError(); + + To = getDerived().RebuildPackExpansionType(To, + PatternTL.getSourceRange(), + ExpansionTL.getEllipsisLoc(), + NumExpansions); + if (To.isNull()) + return ExprError(); + + PackExpansionTypeLoc ToExpansionTL + = TLB.push<PackExpansionTypeLoc>(To); + ToExpansionTL.setEllipsisLoc(ExpansionTL.getEllipsisLoc()); + Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To)); + } + + if (!getDerived().AlwaysRebuild() && !ArgChanged) + return SemaRef.Owned(E); + + return getDerived().RebuildTypeTrait(E->getTrait(), + E->getLocStart(), + Args, + E->getLocEnd()); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { TypeSourceInfo *T = getDerived().TransformType(E->getQueriedTypeSourceInfo()); if (!T) diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 77e4541669..2d308fb030 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1327,6 +1327,17 @@ void ASTStmtReader::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { E->RhsType = GetTypeSourceInfo(Record, Idx); } +void ASTStmtReader::VisitTypeTraitExpr(TypeTraitExpr *E) { + VisitExpr(E); + E->TypeTraitExprBits.NumArgs = Record[Idx++]; + E->TypeTraitExprBits.Kind = Record[Idx++]; + E->TypeTraitExprBits.Value = Record[Idx++]; + + TypeSourceInfo **Args = E->getTypeSourceInfos(); + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) + Args[I] = GetTypeSourceInfo(Record, Idx); +} + void ASTStmtReader::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { VisitExpr(E); E->ATT = (ArrayTypeTrait)Record[Idx++]; @@ -2046,6 +2057,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) BinaryTypeTraitExpr(Empty); break; + case EXPR_TYPE_TRAIT: + S = TypeTraitExpr::CreateDeserialized(Context, + Record[ASTStmtReader::NumExprFields]); + break; + case EXPR_ARRAY_TYPE_TRAIT: S = new (Context) ArrayTypeTraitExpr(Empty); break; diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 0ba413df72..f9c3c5de43 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1341,6 +1341,16 @@ void ASTStmtWriter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { Code = serialization::EXPR_BINARY_TYPE_TRAIT; } +void ASTStmtWriter::VisitTypeTraitExpr(TypeTraitExpr *E) { + VisitExpr(E); + Record.push_back(E->TypeTraitExprBits.NumArgs); + Record.push_back(E->TypeTraitExprBits.Kind); // FIXME: Stable encoding + Record.push_back(E->TypeTraitExprBits.Value); + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) + Writer.AddTypeSourceInfo(E->getArg(I), Record); + Code = serialization::EXPR_TYPE_TRAIT; +} + void ASTStmtWriter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { VisitExpr(E); Record.push_back(E->getTrait()); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 34ad23a429..a61c0272b5 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -478,6 +478,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::DependentScopeDeclRefExprClass: case Stmt::UnaryTypeTraitExprClass: case Stmt::BinaryTypeTraitExprClass: + case Stmt::TypeTraitExprClass: case Stmt::ArrayTypeTraitExprClass: case Stmt::ExpressionTraitExprClass: case Stmt::UnresolvedLookupExprClass: diff --git a/test/Index/annotate-tokens-cxx0x.cpp b/test/Index/annotate-tokens-cxx0x.cpp index 89876b28ea..a126b85127 100644 --- a/test/Index/annotate-tokens-cxx0x.cpp +++ b/test/Index/annotate-tokens-cxx0x.cpp @@ -6,6 +6,11 @@ int f(Args ...args) { void test() { int a; decltype(a) b; + + typedef int Integer; + typedef float Float; + typedef bool Bool; + bool b2 = __is_trivially_constructible(Integer, Float, Bool); } // RUN: c-index-test -test-annotate-tokens=%s:1:1:5:1 -fno-delayed-template-parsing -std=c++11 %s | FileCheck %s @@ -14,3 +19,9 @@ void test() { // RUN: c-index-test -test-annotate-tokens=%s:8:1:9:1 -std=c++11 %s | FileCheck -check-prefix=CHECK-DECLTYPE %s // CHECK-DECLTYPE: Identifier: "a" [8:12 - 8:13] DeclRefExpr=a:7:7 + +// RUN: c-index-test -test-annotate-tokens=%s:13:1:14:1 -std=c++11 %s | FileCheck -check-prefix=CHECK-TRAIT %s +// CHECK-TRAIT: Identifier: "Integer" [13:42 - 13:49] TypeRef=Integer:10:15 +// CHECK-TRAIT: Identifier: "Float" [13:51 - 13:56] TypeRef=Float:11:17 +// CHECK-TRAIT: Identifier: "Bool" [13:58 - 13:62] TypeRef=Bool:12:16 + diff --git a/test/PCH/cxx-traits.cpp b/test/PCH/cxx-traits.cpp index 69c64758ae..3df34794f2 100644 --- a/test/PCH/cxx-traits.cpp +++ b/test/PCH/cxx-traits.cpp @@ -1,8 +1,11 @@ // Test this without pch. -// RUN: %clang_cc1 -include %S/cxx-traits.h -fsyntax-only -verify %s +// RUN: %clang_cc1 -include %S/cxx-traits.h -std=c++11 -fsyntax-only -verify %s -// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-traits.h -// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s +// RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -o %t %S/cxx-traits.h +// RUN: %clang_cc1 -std=c++11 -include-pch %t -fsyntax-only -verify %s bool _Is_pod_comparator = __is_pod<int>::__value; bool _Is_empty_check = __is_empty<int>::__value; + +bool default_construct_int = is_trivially_constructible<int>::value; +bool copy_construct_int = is_trivially_constructible<int, const int&>::value; diff --git a/test/PCH/cxx-traits.h b/test/PCH/cxx-traits.h index 62722ab179..8b62002789 100644 --- a/test/PCH/cxx-traits.h +++ b/test/PCH/cxx-traits.h @@ -9,3 +9,8 @@ template<typename _Tp> struct __is_empty { enum { __value }; }; + +template<typename T, typename ...Args> +struct is_trivially_constructible { + static const bool value = __is_trivially_constructible(T, Args...); +}; diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index 50c135d0b7..fd41c17ab2 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -47,6 +47,10 @@ struct TrivialMoveButNotCopy { TrivialMoveButNotCopy &operator=(TrivialMoveButNotCopy&&) = default; TrivialMoveButNotCopy &operator=(const TrivialMoveButNotCopy&); }; +struct NonTrivialDefault { + NonTrivialDefault(); +}; + struct HasDest { ~HasDest(); }; class HasPriv { int priv; }; class HasProt { protected: int prot; }; @@ -104,6 +108,10 @@ class AllPrivate { ~AllPrivate() throw(); }; +struct ThreeArgCtor { + ThreeArgCtor(int*, char*, int); +}; + void is_pod() { { int arr[T(__is_pod(int))]; } @@ -1602,7 +1610,7 @@ void is_trivial() { int arr[F(__is_trivial(cvoid))]; } } -void is_trivially_copyable() +void trivial_checks() { { int arr[T(__is_trivially_copyable(int))]; } { int arr[T(__is_trivially_copyable(Enum))]; } @@ -1646,6 +1654,25 @@ void is_trivially_copyable() { int arr[F(__is_trivially_copyable(void))]; } { int arr[F(__is_trivially_copyable(cvoid))]; } + { int arr[T((__is_trivially_constructible(int)))]; } + { int arr[T((__is_trivially_constructible(int, int)))]; } + { int arr[T((__is_trivially_constructible(int, float)))]; } + { int arr[T((__is_trivially_constructible(int, int&)))]; } + { int arr[T((__is_trivially_constructible(int, const int&)))]; } + { int arr[T((__is_trivially_constructible(int, int)))]; } + { int arr[T((__is_trivially_constructible(HasCopyAssign, HasCopyAssign)))]; } + { int arr[T((__is_trivially_constructible(HasCopyAssign, const HasCopyAssign&)))]; } + { int arr[T((__is_trivially_constructible(HasCopyAssign, HasCopyAssign&&)))]; } + { int arr[T((__is_trivially_constructible(HasCopyAssign)))]; } + { int arr[T((__is_trivially_constructible(NonTrivialDefault, + const NonTrivialDefault&)))]; } + { int arr[T((__is_trivially_constructible(NonTrivialDefault, + NonTrivialDefault&&)))]; } + + { int arr[F((__is_trivially_constructible(int, int*)))]; } + { int arr[F((__is_trivially_constructible(NonTrivialDefault)))]; } + { int arr[F((__is_trivially_constructible(ThreeArgCtor, int*, char*, int&)))]; } + { int arr[T((__is_trivially_assignable(int&, int)))]; } { int arr[T((__is_trivially_assignable(int&, int&)))]; } { int arr[T((__is_trivially_assignable(int&, int&&)))]; } @@ -1680,6 +1707,33 @@ void is_trivially_copyable() TrivialMoveButNotCopy&&)))]; } } +// Instantiation of __is_trivially_constructible +template<typename T, typename ...Args> +struct is_trivially_constructible { + static const bool value = __is_trivially_constructible(T, Args...); +}; + +void is_trivially_constructible_test() { + { int arr[T((is_trivially_constructible<int>::value))]; } + { int arr[T((is_trivially_constructible<int, int>::value))]; } + { int arr[T((is_trivially_constructible<int, float>::value))]; } + { int arr[T((is_trivially_constructible<int, int&>::value))]; } + { int arr[T((is_trivially_constructible<int, const int&>::value))]; } + { int arr[T((is_trivially_constructible<int, int>::value))]; } + { int arr[T((is_trivially_constructible<HasCopyAssign, HasCopyAssign>::value))]; } + { int arr[T((is_trivially_constructible<HasCopyAssign, const HasCopyAssign&>::value))]; } + { int arr[T((is_trivially_constructible<HasCopyAssign, HasCopyAssign&&>::value))]; } + { int arr[T((is_trivially_constructible<HasCopyAssign>::value))]; } + { int arr[T((is_trivially_constructible<NonTrivialDefault, + const NonTrivialDefault&>::value))]; } + { int arr[T((is_trivially_constructible<NonTrivialDefault, + NonTrivialDefault&&>::value))]; } + + { int arr[F((is_trivially_constructible<int, int*>::value))]; } + { int arr[F((is_trivially_constructible<NonTrivialDefault>::value))]; } + { int arr[F((is_trivially_constructible<ThreeArgCtor, int*, char*, int&>::value))]; } +} + void array_rank() { int t01[T(__array_rank(IntAr) == 1)]; int t02[T(__array_rank(ConstIntArAr) == 2)]; diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 8d0f5fa76f..53c7634d46 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1755,6 +1755,7 @@ public: void VisitWhileStmt(WhileStmt *W); void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E); void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E); + void VisitTypeTraitExpr(TypeTraitExpr *E); void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E); void VisitExpressionTraitExpr(ExpressionTraitExpr *E); void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U); @@ -2056,6 +2057,11 @@ void EnqueueVisitor::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { AddTypeLoc(E->getLhsTypeSourceInfo()); } +void EnqueueVisitor::VisitTypeTraitExpr(TypeTraitExpr *E) { + for (unsigned I = E->getNumArgs(); I > 0; --I) + AddTypeLoc(E->getArg(I-1)); +} + void EnqueueVisitor::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { AddTypeLoc(E->getQueriedTypeSourceInfo()); } diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 531e70e17a..1adf552683 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -206,6 +206,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU, case Stmt::AtomicExprClass: case Stmt::BinaryConditionalOperatorClass: case Stmt::BinaryTypeTraitExprClass: + case Stmt::TypeTraitExprClass: case Stmt::CXXBindTemporaryExprClass: case Stmt::CXXDefaultArgExprClass: case Stmt::CXXScalarValueInitExprClass: |