diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-02-23 07:33:15 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-02-23 07:33:15 +0000 |
commit | 25d0a0f67d9e949ffbfc57bf487012f5cbfd886e (patch) | |
tree | 2c7d3cf3e2b66d16d367e5ac545593d970f89621 /lib | |
parent | 46e021e897b8319b192115954f0b2c82fe0e504d (diff) |
Provide the __is_trivially_assignable type trait, which provides
compiler support for the std::is_trivially_assignable library type
trait.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151240 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/Expr.cpp | 55 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 11 | ||||
-rw-r--r-- | lib/Lex/PPMacroExpansion.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 49 |
7 files changed, 114 insertions, 5 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index f95ca17306..326459046b 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -18,6 +18,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/Lex/LiteralSupport.h" @@ -2664,6 +2665,60 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { return isEvaluatable(Ctx); } +namespace { + /// \brief Look for a call to a non-trivial function within an expression. + class NonTrivialCallFinder : public EvaluatedExprVisitor<NonTrivialCallFinder> + { + typedef EvaluatedExprVisitor<NonTrivialCallFinder> Inherited; + + bool NonTrivial; + + public: + explicit NonTrivialCallFinder(ASTContext &Context) + : EvaluatedExprVisitor(Context), NonTrivial(false) { } + + bool hasNonTrivialCall() const { return NonTrivial; } + + void VisitCallExpr(CallExpr *E) { + if (CXXMethodDecl *Method + = dyn_cast_or_null<CXXMethodDecl>(E->getCalleeDecl())) { + if (Method->isTrivial()) { + // Recurse to children of the call. + Inherited::VisitStmt(E); + return; + } + } + + NonTrivial = true; + } + + void VisitCXXConstructExpr(CXXConstructExpr *E) { + if (E->getConstructor()->isTrivial()) { + // Recurse to children of the call. + Inherited::VisitStmt(E); + return; + } + + NonTrivial = true; + } + + void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { + if (E->getTemporary()->getDestructor()->isTrivial()) { + Inherited::VisitStmt(E); + return; + } + + NonTrivial = true; + } + }; +} + +bool Expr::hasNonTrivialCall(ASTContext &Ctx) { + NonTrivialCallFinder Finder(Ctx); + Finder.Visit(this); + return Finder.hasNonTrivialCall(); +} + /// isNullPointerConstant - C99 6.3.2.3p3 - Return whether this is a null /// pointer constant or not, as well as the specific kind of constant detected. /// Null pointer constants can be integer constant expressions with the diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index c83bfad1c2..51296ad5f4 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1545,11 +1545,12 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) { static const char *getTypeTraitName(BinaryTypeTrait BTT) { switch (BTT) { - case BTT_IsBaseOf: return "__is_base_of"; - case BTT_IsConvertible: return "__is_convertible"; - case BTT_IsSame: return "__is_same"; - case BTT_TypeCompatible: return "__builtin_types_compatible_p"; - case BTT_IsConvertibleTo: return "__is_convertible_to"; + case BTT_IsBaseOf: return "__is_base_of"; + case BTT_IsConvertible: return "__is_convertible"; + case BTT_IsSame: return "__is_same"; + case BTT_TypeCompatible: return "__builtin_types_compatible_p"; + case BTT_IsConvertibleTo: return "__is_convertible_to"; + case BTT_IsTriviallyAssignable: return "__is_trivially_assignable"; } llvm_unreachable("Binary type trait not covered by switch"); } diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index a9993f97d4..0e00996410 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -700,6 +700,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { != tok::identifier) .Case("is_polymorphic", LangOpts.CPlusPlus) .Case("is_trivial", LangOpts.CPlusPlus) + .Case("is_trivially_assignable", 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 d2e8752468..fdf40e877c 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1140,6 +1140,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_same: case tok::kw___is_convertible: case tok::kw___is_convertible_to: + case tok::kw___is_trivially_assignable: return ParseBinaryTypeTrait(); case tok::kw___array_rank: diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index ccd038cb21..19bc22020c 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -2454,6 +2454,7 @@ static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) { case tok::kw___is_same: return BTT_IsSame; case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible; case tok::kw___is_convertible_to: return BTT_IsConvertibleTo; + case tok::kw___is_trivially_assignable: return BTT_IsTriviallyAssignable; } } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 35c418cb7e..011c28aaf7 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -689,6 +689,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___is_pod: case tok::kw___is_polymorphic: case tok::kw___is_trivial: + case tok::kw___is_trivially_assignable: 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 30f143a825..708db1c9a9 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -3301,6 +3301,54 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1)); return !Result.isInvalid() && !SFINAE.hasErrorOccurred(); } + + case BTT_IsTriviallyAssignable: { + // C++11 [meta.unary.prop]p3: + // is_trivially_assignable is defined as: + // is_assignable<T, U>::value is true and the assignment, as defined by + // is_assignable, is known to call no operation that is not trivial + // + // is_assignable is defined as: + // The expression declval<T>() = declval<U>() is well-formed when + // treated as an unevaluated operand (Clause 5). + // + // For both, T and U shall be complete types, (possibly cv-qualified) + // void, or arrays of unknown bound. + if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() && + Self.RequireCompleteType(KeyLoc, LhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) + return false; + if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() && + Self.RequireCompleteType(KeyLoc, RhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) + return false; + + // cv void is never assignable. + if (LhsT->isVoidType() || RhsT->isVoidType()) + return false; + + // Build expressions that emulate the effect of declval<T>() and + // declval<U>(). + if (LhsT->isObjectType() || LhsT->isFunctionType()) + LhsT = Self.Context.getRValueReferenceType(LhsT); + if (RhsT->isObjectType() || RhsT->isFunctionType()) + RhsT = Self.Context.getRValueReferenceType(RhsT); + OpaqueValueExpr Lhs(KeyLoc, LhsT.getNonLValueExprType(Self.Context), + Expr::getValueKindForType(LhsT)); + OpaqueValueExpr Rhs(KeyLoc, RhsT.getNonLValueExprType(Self.Context), + Expr::getValueKindForType(RhsT)); + + // Attempt the assignment in an unevaluated context within a SFINAE + // trap at translation unit scope. + EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated); + Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); + Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); + ExprResult Result = Self.BuildBinOp(/*S=*/0, KeyLoc, BO_Assign, &Lhs, &Rhs); + if (Result.isInvalid() || SFINAE.hasErrorOccurred()) + return false; + + return !Result.get()->hasNonTrivialCall(Self.Context); + } } llvm_unreachable("Unknown type trait or not implemented"); } @@ -3333,6 +3381,7 @@ ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT, case BTT_IsSame: ResultType = Context.BoolTy; break; case BTT_TypeCompatible: ResultType = Context.IntTy; break; case BTT_IsConvertibleTo: ResultType = Context.BoolTy; break; + case BTT_IsTriviallyAssignable: ResultType = Context.BoolTy; } return Owned(new (Context) BinaryTypeTraitExpr(KWLoc, BTT, LhsTSInfo, |