Skip to content

Commit eee944e

Browse files
committed
[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
1 parent 5613874 commit eee944e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1397
-63
lines changed

clang/include/clang-c/Index.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -2546,7 +2546,11 @@ enum CXCursorKind {
25462546
*/
25472547
CXCursor_OMPTargetTeamsDistributeSimdDirective = 279,
25482548

2549-
CXCursor_LastStmt = CXCursor_OMPTargetTeamsDistributeSimdDirective,
2549+
/** C++2a std::bit_cast expression.
2550+
*/
2551+
CXCursor_BuiltinBitCastExpr = 280,
2552+
2553+
CXCursor_LastStmt = CXCursor_BuiltinBitCastExpr,
25502554

25512555
/**
25522556
* Cursor that represents the translation unit itself.

clang/include/clang/AST/ExprCXX.h

+29
Original file line numberDiff line numberDiff line change
@@ -4716,6 +4716,35 @@ class CoyieldExpr : public CoroutineSuspendExpr {
47164716
}
47174717
};
47184718

4719+
/// Represents a C++2a __builtin_bit_cast(T, v) expression. Used to implement
4720+
/// std::bit_cast. These can sometimes be evaluated as part of a constant
4721+
/// expression, but otherwise CodeGen to a simple memcpy in general.
4722+
class BuiltinBitCastExpr final
4723+
: public ExplicitCastExpr,
4724+
private llvm::TrailingObjects<BuiltinBitCastExpr, CXXBaseSpecifier *> {
4725+
friend class ASTStmtReader;
4726+
friend class CastExpr;
4727+
friend class TrailingObjects;
4728+
4729+
SourceLocation KWLoc;
4730+
SourceLocation RParenLoc;
4731+
4732+
public:
4733+
BuiltinBitCastExpr(QualType T, ExprValueKind VK, CastKind CK, Expr *SrcExpr,
4734+
TypeSourceInfo *DstType, SourceLocation KWLoc,
4735+
SourceLocation RParenLoc)
4736+
: ExplicitCastExpr(BuiltinBitCastExprClass, T, VK, CK, SrcExpr, 0,
4737+
DstType),
4738+
KWLoc(KWLoc), RParenLoc(RParenLoc) {}
4739+
4740+
SourceLocation getBeginLoc() const LLVM_READONLY { return KWLoc; }
4741+
SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; }
4742+
4743+
static bool classof(const Stmt *T) {
4744+
return T->getStmtClass() == BuiltinBitCastExprClass;
4745+
}
4746+
};
4747+
47194748
} // namespace clang
47204749

47214750
#endif // LLVM_CLANG_AST_EXPRCXX_H

clang/include/clang/AST/OperationKinds.def

+4
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ CAST_OPERATION(BitCast)
6666
/// bool b; reinterpret_cast<char&>(b) = 'a';
6767
CAST_OPERATION(LValueBitCast)
6868

69+
/// CK_LValueToRValueBitCast - A conversion that causes us to reinterpret an
70+
/// lvalue as an rvalue of a different type. Created by __builtin_bit_cast.
71+
CAST_OPERATION(LValueToRValueBitCast)
72+
6973
/// CK_LValueToRValue - A conversion which causes the extraction of
7074
/// an r-value from the operand gl-value. The result of an r-value
7175
/// conversion is always unqualified.

clang/include/clang/AST/RecursiveASTVisitor.h

+4
Original file line numberDiff line numberDiff line change
@@ -2282,6 +2282,10 @@ DEF_TRAVERSE_STMT(CXXStaticCastExpr, {
22822282
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
22832283
})
22842284

2285+
DEF_TRAVERSE_STMT(BuiltinBitCastExpr, {
2286+
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
2287+
})
2288+
22852289
template <typename Derived>
22862290
bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
22872291
InitListExpr *S, DataRecursionQueue *Queue) {

clang/include/clang/Basic/DiagnosticASTKinds.td

+13
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,19 @@ def note_constexpr_memcpy_unsupported : Note<
215215
"size to copy (%4) is not a multiple of size of element type %3 (%5)|"
216216
"source is not a contiguous array of at least %4 elements of type %3|"
217217
"destination is not a contiguous array of at least %4 elements of type %3}2">;
218+
def note_constexpr_bit_cast_unsupported_type : Note<
219+
"constexpr bit_cast involving type %0 is not yet supported">;
220+
def note_constexpr_bit_cast_unsupported_bitfield : Note<
221+
"constexpr bit_cast involving bit-field is not yet supported">;
222+
def note_constexpr_bit_cast_invalid_type : Note<
223+
"bit_cast %select{from|to}0 a %select{|type with a }1"
224+
"%select{union|pointer|member pointer|volatile|reference}2 "
225+
"%select{type|member}1 is not allowed in a constant expression">;
226+
def note_constexpr_bit_cast_invalid_subtype : Note<
227+
"invalid type %0 is a %select{member|base}1 of %2">;
228+
def note_constexpr_bit_cast_indet_dest : Note<
229+
"indeterminate value can only initialize an object of type 'unsigned char'"
230+
"%select{, 'char',|}1 or 'std::byte'; %0 is invalid">;
218231

219232
def warn_integer_constant_overflow : Warning<
220233
"overflow in expression; result is %0 with type %1">,

clang/include/clang/Basic/DiagnosticSemaKinds.td

+4
Original file line numberDiff line numberDiff line change
@@ -9734,4 +9734,8 @@ def err_builtin_launder_invalid_arg : Error<
97349734
"%select{non-pointer|function pointer|void pointer}0 argument to "
97359735
"'__builtin_launder' is not allowed">;
97369736

9737+
def err_bit_cast_non_trivially_copyable : Error<
9738+
"__builtin_bit_cast %select{source|destination}0 type must be trivially copyable">;
9739+
def err_bit_cast_type_size_mismatch : Error<
9740+
"__builtin_bit_cast source size does not equal destination size (%0 vs %1)">;
97379741
} // end of sema component.

clang/include/clang/Basic/StmtNodes.td

+1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ def ConvertVectorExpr : DStmt<Expr>;
192192
def BlockExpr : DStmt<Expr>;
193193
def OpaqueValueExpr : DStmt<Expr>;
194194
def TypoExpr : DStmt<Expr>;
195+
def BuiltinBitCastExpr : DStmt<ExplicitCastExpr>;
195196

196197
// Microsoft Extensions.
197198
def MSPropertyRefExpr : DStmt<Expr>;

clang/include/clang/Basic/TokenKinds.def

+1-1
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ ALIAS("_pascal" , __pascal , KEYBORLAND)
670670
KEYWORD(__builtin_convertvector , KEYALL)
671671
ALIAS("__char16_t" , char16_t , KEYCXX)
672672
ALIAS("__char32_t" , char32_t , KEYCXX)
673-
673+
KEYWORD(__builtin_bit_cast , KEYALL)
674674
KEYWORD(__builtin_available , KEYALL)
675675

676676
// Clang-specific keywords enabled only in testing.

clang/include/clang/Parse/Parser.h

+3
Original file line numberDiff line numberDiff line change
@@ -1780,6 +1780,9 @@ class Parser : public CodeCompletionHandler {
17801780
// C++ 5.2p1: C++ Casts
17811781
ExprResult ParseCXXCasts();
17821782

1783+
/// Parse a __builtin_bit_cast(T, E), used to implement C++2a std::bit_cast.
1784+
ExprResult ParseBuiltinBitCast();
1785+
17831786
//===--------------------------------------------------------------------===//
17841787
// C++ 5.2p1: C++ Type Identification
17851788
ExprResult ParseCXXTypeid();

clang/include/clang/Sema/Sema.h

+7
Original file line numberDiff line numberDiff line change
@@ -5236,6 +5236,13 @@ class Sema {
52365236
SourceRange AngleBrackets,
52375237
SourceRange Parens);
52385238

5239+
ExprResult ActOnBuiltinBitCastExpr(SourceLocation KWLoc, Declarator &Dcl,
5240+
ExprResult Operand,
5241+
SourceLocation RParenLoc);
5242+
5243+
ExprResult BuildBuiltinBitCastExpr(SourceLocation KWLoc, TypeSourceInfo *TSI,
5244+
Expr *Operand, SourceLocation RParenLoc);
5245+
52395246
ExprResult BuildCXXTypeId(QualType TypeInfoType,
52405247
SourceLocation TypeidLoc,
52415248
TypeSourceInfo *Operand,

clang/lib/AST/Expr.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -1862,6 +1862,7 @@ bool CastExpr::CastConsistency() const {
18621862
case CK_FloatingComplexToBoolean:
18631863
case CK_IntegralComplexToBoolean:
18641864
case CK_LValueBitCast: // -> bool&
1865+
case CK_LValueToRValueBitCast:
18651866
case CK_UserDefinedConversion: // operator bool()
18661867
case CK_BuiltinFnToFnPtr:
18671868
case CK_FixedPointToBoolean:
@@ -3506,7 +3507,8 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
35063507
case CXXStaticCastExprClass:
35073508
case CXXReinterpretCastExprClass:
35083509
case CXXConstCastExprClass:
3509-
case CXXFunctionalCastExprClass: {
3510+
case CXXFunctionalCastExprClass:
3511+
case BuiltinBitCastExprClass: {
35103512
// While volatile reads are side-effecting in both C and C++, we treat them
35113513
// as having possible (not definite) side-effects. This allows idiomatic
35123514
// code to behave without warning, such as sizeof(*v) for a volatile-

clang/lib/AST/ExprClassification.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
343343
case Expr::CXXReinterpretCastExprClass:
344344
case Expr::CXXConstCastExprClass:
345345
case Expr::ObjCBridgedCastExprClass:
346+
case Expr::BuiltinBitCastExprClass:
346347
// Only in C++ can casts be interesting at all.
347348
if (!Lang.CPlusPlus) return Cl::CL_PRValue;
348349
return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten());

0 commit comments

Comments
 (0)