summaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorErik Pilkington <erik.pilkington@gmail.com>2019-07-02 18:28:13 +0000
committerErik Pilkington <erik.pilkington@gmail.com>2019-07-02 18:28:13 +0000
commit159cd770e3ea0c5cba37006c4dc96b3235670f0d (patch)
tree0f7c041619d7593e111a77c1f79954b83b6dbf99 /lib/Sema
parent54b8029400637989d16f8467643c46296e62e1d3 (diff)
downloadclang-159cd770e3ea0c5cba37006c4dc96b3235670f0d.tar.gz
[C++2a] Add __builtin_bit_cast, used to implement std::bit_cast
This commit adds a new builtin, __builtin_bit_cast(T, v), which performs a bit_cast from a value v to a type T. This expression can be evaluated at compile time under specific circumstances. The compile time evaluation currently doesn't support bit-fields, but I'm planning on fixing this in a follow up (some of the logic for figuring this out is in CodeGen). I'm also planning follow-ups for supporting some more esoteric types that the constexpr evaluator supports, as well as extending __builtin_memcpy constexpr evaluation to use the same infrastructure. rdar://44987528 Differential revision: https://reviews.llvm.org/D62825 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@364954 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/SemaCast.cpp70
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp1
-rw-r--r--lib/Sema/TreeTransform.h26
3 files changed, 97 insertions, 0 deletions
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index 46d0f57dc7..9ca6e4ab0e 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -87,6 +87,7 @@ namespace {
void CheckDynamicCast();
void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization);
void CheckCStyleCast();
+ void CheckBuiltinBitCast();
void updatePartOfExplicitCastFlags(CastExpr *CE) {
// Walk down from the CE to the OrigSrcExpr, and mark all immediate
@@ -331,6 +332,38 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
}
}
+ExprResult Sema::ActOnBuiltinBitCastExpr(SourceLocation KWLoc, Declarator &D,
+ ExprResult Operand,
+ SourceLocation RParenLoc) {
+ assert(!D.isInvalidType());
+
+ TypeSourceInfo *TInfo = GetTypeForDeclaratorCast(D, Operand.get()->getType());
+ if (D.isInvalidType())
+ return ExprError();
+
+ return BuildBuiltinBitCastExpr(KWLoc, TInfo, Operand.get(), RParenLoc);
+}
+
+ExprResult Sema::BuildBuiltinBitCastExpr(SourceLocation KWLoc,
+ TypeSourceInfo *TSI, Expr *Operand,
+ SourceLocation RParenLoc) {
+ CastOperation Op(*this, TSI->getType(), Operand);
+ Op.OpRange = SourceRange(KWLoc, RParenLoc);
+ TypeLoc TL = TSI->getTypeLoc();
+ Op.DestRange = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
+
+ if (!Operand->isTypeDependent() && !TSI->getType()->isDependentType()) {
+ Op.CheckBuiltinBitCast();
+ if (Op.SrcExpr.isInvalid())
+ return ExprError();
+ }
+
+ BuiltinBitCastExpr *BCE =
+ new (Context) BuiltinBitCastExpr(Op.ResultType, Op.ValueKind, Op.Kind,
+ Op.SrcExpr.get(), TSI, KWLoc, RParenLoc);
+ return Op.complete(BCE);
+}
+
/// Try to diagnose a failed overloaded cast. Returns true if
/// diagnostics were emitted.
static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
@@ -2764,6 +2797,43 @@ void CastOperation::CheckCStyleCast() {
checkCastAlign();
}
+void CastOperation::CheckBuiltinBitCast() {
+ QualType SrcType = SrcExpr.get()->getType();
+ if (SrcExpr.get()->isRValue())
+ SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcType, SrcExpr.get(),
+ /*IsLValueReference=*/false);
+
+ CharUnits DestSize = Self.Context.getTypeSizeInChars(DestType);
+ CharUnits SourceSize = Self.Context.getTypeSizeInChars(SrcType);
+ if (DestSize != SourceSize) {
+ Self.Diag(OpRange.getBegin(), diag::err_bit_cast_type_size_mismatch)
+ << (int)SourceSize.getQuantity() << (int)DestSize.getQuantity();
+ SrcExpr = ExprError();
+ return;
+ }
+
+ if (!DestType.isTriviallyCopyableType(Self.Context)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bit_cast_non_trivially_copyable)
+ << 1;
+ SrcExpr = ExprError();
+ return;
+ }
+
+ if (!SrcType.isTriviallyCopyableType(Self.Context)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bit_cast_non_trivially_copyable)
+ << 0;
+ SrcExpr = ExprError();
+ return;
+ }
+
+ if (Self.Context.hasSameUnqualifiedType(DestType, SrcType)) {
+ Kind = CK_NoOp;
+ return;
+ }
+
+ Kind = CK_LValueToRValueBitCast;
+}
+
/// DiagnoseCastQual - Warn whenever casts discards a qualifiers, be it either
/// const, volatile or both.
static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr,
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 5274532b0f..9fd924a8ca 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -1201,6 +1201,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::CoyieldExprClass:
case Expr::CXXConstCastExprClass:
case Expr::CXXReinterpretCastExprClass:
+ case Expr::BuiltinBitCastExprClass:
case Expr::CXXStdInitializerListExprClass:
case Expr::DesignatedInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 953889c6a0..7edb2a8d80 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -2652,6 +2652,16 @@ public:
ListInitialization);
}
+ /// Build a new C++ __builtin_bit_cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildBuiltinBitCastExpr(SourceLocation KWLoc,
+ TypeSourceInfo *TSI, Expr *Sub,
+ SourceLocation RParenLoc) {
+ return getSema().BuildBuiltinBitCastExpr(KWLoc, TSI, Sub, RParenLoc);
+ }
+
/// Build a new C++ typeid(type) expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -10247,6 +10257,22 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformBuiltinBitCastExpr(BuiltinBitCastExpr *BCE) {
+ TypeSourceInfo *TSI =
+ getDerived().TransformType(BCE->getTypeInfoAsWritten());
+ if (!TSI)
+ return ExprError();
+
+ ExprResult Sub = getDerived().TransformExpr(BCE->getSubExpr());
+ if (Sub.isInvalid())
+ return ExprError();
+
+ return getDerived().RebuildBuiltinBitCastExpr(BCE->getBeginLoc(), TSI,
+ Sub.get(), BCE->getEndLoc());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) {
return getDerived().TransformCXXNamedCastExpr(E);
}