[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
llvm-svn: 364954
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 46d0f57..9ca6e4a 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -87,6 +87,7 @@
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 @@
}
}
+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 @@
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/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 5274532..9fd924a 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1201,6 +1201,7 @@
case Expr::CoyieldExprClass:
case Expr::CXXConstCastExprClass:
case Expr::CXXReinterpretCastExprClass:
+ case Expr::BuiltinBitCastExprClass:
case Expr::CXXStdInitializerListExprClass:
case Expr::DesignatedInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 953889c..7edb2a8 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2652,6 +2652,16 @@
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 @@
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);
}