[cfe-commits] r151240 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/Basic/TokenKinds.def include/clang/Basic/TypeTraits.h lib/AST/Expr.cpp lib/AST/StmtPrinter.cpp lib/Lex/PPMacroExpansion.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseTentative.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/type-traits.cpp
Douglas Gregor
dgregor at apple.com
Wed Feb 22 23:33:15 PST 2012
Author: dgregor
Date: Thu Feb 23 01:33:15 2012
New Revision: 151240
URL: http://llvm.org/viewvc/llvm-project?rev=151240&view=rev
Log:
Provide the __is_trivially_assignable type trait, which provides
compiler support for the std::is_trivially_assignable library type
trait.
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/Basic/TokenKinds.def
cfe/trunk/include/clang/Basic/TypeTraits.h
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/AST/StmtPrinter.cpp
cfe/trunk/lib/Lex/PPMacroExpansion.cpp
cfe/trunk/lib/Parse/ParseExpr.cpp
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Parse/ParseTentative.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/test/SemaCXX/type-traits.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=151240&r1=151239&r2=151240&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Thu Feb 23 01:33:15 2012
@@ -512,6 +512,10 @@
/// variable read.
bool HasSideEffects(const ASTContext &Ctx) const;
+ /// \brief Determine whether this expression involves a call to any function
+ /// that is not trivial.
+ bool hasNonTrivialCall(ASTContext &Ctx);
+
/// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded
/// integer. This must be called on an expression that constant folds to an
/// integer.
Modified: cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=151240&r1=151239&r2=151240&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TokenKinds.def (original)
+++ cfe/trunk/include/clang/Basic/TokenKinds.def Thu Feb 23 01:33:15 2012
@@ -366,6 +366,7 @@
// Clang-only C++ Type Traits
KEYWORD(__is_trivially_copyable , KEYCXX)
+KEYWORD(__is_trivially_assignable , KEYCXX)
KEYWORD(__underlying_type , KEYCXX)
// Embarcadero Expression Traits
Modified: cfe/trunk/include/clang/Basic/TypeTraits.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TypeTraits.h?rev=151240&r1=151239&r2=151240&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TypeTraits.h (original)
+++ cfe/trunk/include/clang/Basic/TypeTraits.h Thu Feb 23 01:33:15 2012
@@ -68,7 +68,8 @@
BTT_IsConvertible,
BTT_IsConvertibleTo,
BTT_IsSame,
- BTT_TypeCompatible
+ BTT_TypeCompatible,
+ BTT_IsTriviallyAssignable
};
/// ArrayTypeTrait - Names for the array type traits.
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=151240&r1=151239&r2=151240&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Thu Feb 23 01:33:15 2012
@@ -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 @@
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
Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=151240&r1=151239&r2=151240&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Thu Feb 23 01:33:15 2012
@@ -1545,11 +1545,12 @@
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");
}
Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=151240&r1=151239&r2=151240&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Thu Feb 23 01:33:15 2012
@@ -700,6 +700,7 @@
!= 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)
Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=151240&r1=151239&r2=151240&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Thu Feb 23 01:33:15 2012
@@ -1140,6 +1140,7 @@
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:
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=151240&r1=151239&r2=151240&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Thu Feb 23 01:33:15 2012
@@ -2454,6 +2454,7 @@
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;
}
}
Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=151240&r1=151239&r2=151240&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Thu Feb 23 01:33:15 2012
@@ -689,6 +689,7 @@
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:
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=151240&r1=151239&r2=151240&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Feb 23 01:33:15 2012
@@ -3301,6 +3301,54 @@
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 @@
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,
Modified: cfe/trunk/test/SemaCXX/type-traits.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=151240&r1=151239&r2=151240&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/type-traits.cpp (original)
+++ cfe/trunk/test/SemaCXX/type-traits.cpp Thu Feb 23 01:33:15 2012
@@ -39,6 +39,14 @@
struct HasCons { HasCons(int); };
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); };
+struct HasDefaultTrivialCopyAssign {
+ HasDefaultTrivialCopyAssign &operator =(const HasDefaultTrivialCopyAssign&)
+ = default;
+};
+struct TrivialMoveButNotCopy {
+ TrivialMoveButNotCopy &operator=(TrivialMoveButNotCopy&&) = default;
+ TrivialMoveButNotCopy &operator=(const TrivialMoveButNotCopy&);
+};
struct HasDest { ~HasDest(); };
class HasPriv { int priv; };
class HasProt { protected: int prot; };
@@ -1637,6 +1645,39 @@
{ int arr[F(__is_trivially_copyable(DerivesHasVirt))]; }
{ int arr[F(__is_trivially_copyable(void))]; }
{ int arr[F(__is_trivially_copyable(cvoid))]; }
+
+ { int arr[T((__is_trivially_assignable(int&, int)))]; }
+ { int arr[T((__is_trivially_assignable(int&, int&)))]; }
+ { int arr[T((__is_trivially_assignable(int&, int&&)))]; }
+ { int arr[T((__is_trivially_assignable(int&, const int&)))]; }
+ { int arr[T((__is_trivially_assignable(POD&, POD)))]; }
+ { int arr[T((__is_trivially_assignable(POD&, POD&)))]; }
+ { int arr[T((__is_trivially_assignable(POD&, POD&&)))]; }
+ { int arr[T((__is_trivially_assignable(POD&, const POD&)))]; }
+ { int arr[T((__is_trivially_assignable(int*&, int*)))]; }
+
+ { int arr[F((__is_trivially_assignable(int*&, float*)))]; }
+ { int arr[F((__is_trivially_assignable(HasCopyAssign&, HasCopyAssign)))]; }
+ { int arr[F((__is_trivially_assignable(HasCopyAssign&, HasCopyAssign&)))]; }
+ { int arr[F((__is_trivially_assignable(HasCopyAssign&, const HasCopyAssign&)))]; }
+ { int arr[F((__is_trivially_assignable(HasCopyAssign&, HasCopyAssign&&)))]; }
+ { int arr[F((__is_trivially_assignable(TrivialMoveButNotCopy&,
+ TrivialMoveButNotCopy&)))]; }
+ { int arr[F((__is_trivially_assignable(TrivialMoveButNotCopy&,
+ const TrivialMoveButNotCopy&)))]; }
+
+ // FIXME: The following answers are wrong, because we don't properly
+ // mark user-declared constructors/assignment operators/destructors
+ // that are defaulted on their first declaration as trivial when we
+ // can.
+ { int arr[F((__is_trivially_assignable(HasDefaultTrivialCopyAssign&,
+ HasDefaultTrivialCopyAssign&)))]; }
+ { int arr[F((__is_trivially_assignable(HasDefaultTrivialCopyAssign&,
+ const HasDefaultTrivialCopyAssign&)))]; }
+ { int arr[F((__is_trivially_assignable(TrivialMoveButNotCopy&,
+ TrivialMoveButNotCopy)))]; }
+ { int arr[F((__is_trivially_assignable(TrivialMoveButNotCopy&,
+ TrivialMoveButNotCopy&&)))]; }
}
void array_rank() {
More information about the cfe-commits
mailing list