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.
|
/// variable read.
|
||||||
bool HasSideEffects(const ASTContext &Ctx) const;
|
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
|
/// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded
|
||||||
/// integer. This must be called on an expression that constant folds to an
|
/// integer. This must be called on an expression that constant folds to an
|
||||||
/// integer.
|
/// integer.
|
||||||
|
|
|
@ -366,6 +366,7 @@ KEYWORD(__is_union , KEYCXX)
|
||||||
|
|
||||||
// Clang-only C++ Type Traits
|
// Clang-only C++ Type Traits
|
||||||
KEYWORD(__is_trivially_copyable , KEYCXX)
|
KEYWORD(__is_trivially_copyable , KEYCXX)
|
||||||
|
KEYWORD(__is_trivially_assignable , KEYCXX)
|
||||||
KEYWORD(__underlying_type , KEYCXX)
|
KEYWORD(__underlying_type , KEYCXX)
|
||||||
|
|
||||||
// Embarcadero Expression Traits
|
// Embarcadero Expression Traits
|
||||||
|
|
|
@ -68,7 +68,8 @@ namespace clang {
|
||||||
BTT_IsConvertible,
|
BTT_IsConvertible,
|
||||||
BTT_IsConvertibleTo,
|
BTT_IsConvertibleTo,
|
||||||
BTT_IsSame,
|
BTT_IsSame,
|
||||||
BTT_TypeCompatible
|
BTT_TypeCompatible,
|
||||||
|
BTT_IsTriviallyAssignable
|
||||||
};
|
};
|
||||||
|
|
||||||
/// ArrayTypeTrait - Names for the array type traits.
|
/// ArrayTypeTrait - Names for the array type traits.
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "clang/AST/DeclObjC.h"
|
#include "clang/AST/DeclObjC.h"
|
||||||
#include "clang/AST/DeclCXX.h"
|
#include "clang/AST/DeclCXX.h"
|
||||||
#include "clang/AST/DeclTemplate.h"
|
#include "clang/AST/DeclTemplate.h"
|
||||||
|
#include "clang/AST/EvaluatedExprVisitor.h"
|
||||||
#include "clang/AST/RecordLayout.h"
|
#include "clang/AST/RecordLayout.h"
|
||||||
#include "clang/AST/StmtVisitor.h"
|
#include "clang/AST/StmtVisitor.h"
|
||||||
#include "clang/Lex/LiteralSupport.h"
|
#include "clang/Lex/LiteralSupport.h"
|
||||||
|
@ -2664,6 +2665,60 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
|
||||||
return isEvaluatable(Ctx);
|
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
|
/// 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.
|
/// pointer constant or not, as well as the specific kind of constant detected.
|
||||||
/// Null pointer constants can be integer constant expressions with the
|
/// 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) {
|
static const char *getTypeTraitName(BinaryTypeTrait BTT) {
|
||||||
switch (BTT) {
|
switch (BTT) {
|
||||||
case BTT_IsBaseOf: return "__is_base_of";
|
case BTT_IsBaseOf: return "__is_base_of";
|
||||||
case BTT_IsConvertible: return "__is_convertible";
|
case BTT_IsConvertible: return "__is_convertible";
|
||||||
case BTT_IsSame: return "__is_same";
|
case BTT_IsSame: return "__is_same";
|
||||||
case BTT_TypeCompatible: return "__builtin_types_compatible_p";
|
case BTT_TypeCompatible: return "__builtin_types_compatible_p";
|
||||||
case BTT_IsConvertibleTo: return "__is_convertible_to";
|
case BTT_IsConvertibleTo: return "__is_convertible_to";
|
||||||
|
case BTT_IsTriviallyAssignable: return "__is_trivially_assignable";
|
||||||
}
|
}
|
||||||
llvm_unreachable("Binary type trait not covered by switch");
|
llvm_unreachable("Binary type trait not covered by switch");
|
||||||
}
|
}
|
||||||
|
|
|
@ -700,6 +700,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
|
||||||
!= tok::identifier)
|
!= tok::identifier)
|
||||||
.Case("is_polymorphic", LangOpts.CPlusPlus)
|
.Case("is_polymorphic", LangOpts.CPlusPlus)
|
||||||
.Case("is_trivial", LangOpts.CPlusPlus)
|
.Case("is_trivial", LangOpts.CPlusPlus)
|
||||||
|
.Case("is_trivially_assignable", LangOpts.CPlusPlus)
|
||||||
.Case("is_trivially_copyable", LangOpts.CPlusPlus)
|
.Case("is_trivially_copyable", LangOpts.CPlusPlus)
|
||||||
.Case("is_union", LangOpts.CPlusPlus)
|
.Case("is_union", LangOpts.CPlusPlus)
|
||||||
.Case("modules", LangOpts.Modules)
|
.Case("modules", LangOpts.Modules)
|
||||||
|
|
|
@ -1140,6 +1140,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
||||||
case tok::kw___is_same:
|
case tok::kw___is_same:
|
||||||
case tok::kw___is_convertible:
|
case tok::kw___is_convertible:
|
||||||
case tok::kw___is_convertible_to:
|
case tok::kw___is_convertible_to:
|
||||||
|
case tok::kw___is_trivially_assignable:
|
||||||
return ParseBinaryTypeTrait();
|
return ParseBinaryTypeTrait();
|
||||||
|
|
||||||
case tok::kw___array_rank:
|
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___is_same: return BTT_IsSame;
|
||||||
case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible;
|
case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible;
|
||||||
case tok::kw___is_convertible_to: return BTT_IsConvertibleTo;
|
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_pod:
|
||||||
case tok::kw___is_polymorphic:
|
case tok::kw___is_polymorphic:
|
||||||
case tok::kw___is_trivial:
|
case tok::kw___is_trivial:
|
||||||
|
case tok::kw___is_trivially_assignable:
|
||||||
case tok::kw___is_trivially_copyable:
|
case tok::kw___is_trivially_copyable:
|
||||||
case tok::kw___is_union:
|
case tok::kw___is_union:
|
||||||
case tok::kw___uuidof:
|
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));
|
ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1));
|
||||||
return !Result.isInvalid() && !SFINAE.hasErrorOccurred();
|
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");
|
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_IsSame: ResultType = Context.BoolTy; break;
|
||||||
case BTT_TypeCompatible: ResultType = Context.IntTy; break;
|
case BTT_TypeCompatible: ResultType = Context.IntTy; break;
|
||||||
case BTT_IsConvertibleTo: ResultType = Context.BoolTy; break;
|
case BTT_IsConvertibleTo: ResultType = Context.BoolTy; break;
|
||||||
|
case BTT_IsTriviallyAssignable: ResultType = Context.BoolTy;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Owned(new (Context) BinaryTypeTraitExpr(KWLoc, BTT, LhsTSInfo,
|
return Owned(new (Context) BinaryTypeTraitExpr(KWLoc, BTT, LhsTSInfo,
|
||||||
|
|
|
@ -39,6 +39,14 @@ struct DerivesEmpty : Empty {};
|
||||||
struct HasCons { HasCons(int); };
|
struct HasCons { HasCons(int); };
|
||||||
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
|
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
|
||||||
struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); };
|
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(); };
|
struct HasDest { ~HasDest(); };
|
||||||
class HasPriv { int priv; };
|
class HasPriv { int priv; };
|
||||||
class HasProt { protected: int prot; };
|
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(DerivesHasVirt))]; }
|
||||||
{ int arr[F(__is_trivially_copyable(void))]; }
|
{ int arr[F(__is_trivially_copyable(void))]; }
|
||||||
{ int arr[F(__is_trivially_copyable(cvoid))]; }
|
{ 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() {
|
void array_rank() {
|
||||||
|
|
Loading…
Reference in New Issue