forked from OSchip/llvm-project
Provide the __is_trivially_assignable type trait, which provides
compiler support for the std::is_trivially_assignable library type trait. llvm-svn: 151240
This commit is contained in:
parent
64bfb2e88e
commit
1be329d838
|
@ -512,6 +512,10 @@ public:
|
|||
/// 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.
|
||||
|
|
|
@ -366,6 +366,7 @@ KEYWORD(__is_union , KEYCXX)
|
|||
|
||||
// Clang-only C++ Type Traits
|
||||
KEYWORD(__is_trivially_copyable , KEYCXX)
|
||||
KEYWORD(__is_trivially_assignable , KEYCXX)
|
||||
KEYWORD(__underlying_type , KEYCXX)
|
||||
|
||||
// Embarcadero Expression Traits
|
||||
|
|
|
@ -68,7 +68,8 @@ namespace clang {
|
|||
BTT_IsConvertible,
|
||||
BTT_IsConvertibleTo,
|
||||
BTT_IsSame,
|
||||
BTT_TypeCompatible
|
||||
BTT_TypeCompatible,
|
||||
BTT_IsTriviallyAssignable
|
||||
};
|
||||
|
||||
/// ArrayTypeTrait - Names for the array type traits.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -39,6 +39,14 @@ struct DerivesEmpty : Empty {};
|
|||
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 @@ void is_trivially_copyable()
|
|||
{ 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() {
|
||||
|
|
Loading…
Reference in New Issue