Skip to content

Commit

Permalink
[C++2a] Add __builtin_bit_cast, used to implement std::bit_cast
Browse files Browse the repository at this point in the history
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
  • Loading branch information
epilk committed Jul 2, 2019
1 parent 5613874 commit eee944e
Show file tree
Hide file tree
Showing 41 changed files with 1,397 additions and 63 deletions.
6 changes: 5 additions & 1 deletion clang/include/clang-c/Index.h
Expand Up @@ -2546,7 +2546,11 @@ enum CXCursorKind {
*/
CXCursor_OMPTargetTeamsDistributeSimdDirective = 279,

CXCursor_LastStmt = CXCursor_OMPTargetTeamsDistributeSimdDirective,
/** C++2a std::bit_cast expression.
*/
CXCursor_BuiltinBitCastExpr = 280,

CXCursor_LastStmt = CXCursor_BuiltinBitCastExpr,

/**
* Cursor that represents the translation unit itself.
Expand Down
29 changes: 29 additions & 0 deletions clang/include/clang/AST/ExprCXX.h
Expand Up @@ -4716,6 +4716,35 @@ class CoyieldExpr : public CoroutineSuspendExpr {
}
};

/// Represents a C++2a __builtin_bit_cast(T, v) expression. Used to implement
/// std::bit_cast. These can sometimes be evaluated as part of a constant
/// expression, but otherwise CodeGen to a simple memcpy in general.
class BuiltinBitCastExpr final
: public ExplicitCastExpr,
private llvm::TrailingObjects<BuiltinBitCastExpr, CXXBaseSpecifier *> {
friend class ASTStmtReader;
friend class CastExpr;
friend class TrailingObjects;

SourceLocation KWLoc;
SourceLocation RParenLoc;

public:
BuiltinBitCastExpr(QualType T, ExprValueKind VK, CastKind CK, Expr *SrcExpr,
TypeSourceInfo *DstType, SourceLocation KWLoc,
SourceLocation RParenLoc)
: ExplicitCastExpr(BuiltinBitCastExprClass, T, VK, CK, SrcExpr, 0,
DstType),
KWLoc(KWLoc), RParenLoc(RParenLoc) {}

SourceLocation getBeginLoc() const LLVM_READONLY { return KWLoc; }
SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; }

static bool classof(const Stmt *T) {
return T->getStmtClass() == BuiltinBitCastExprClass;
}
};

} // namespace clang

#endif // LLVM_CLANG_AST_EXPRCXX_H
4 changes: 4 additions & 0 deletions clang/include/clang/AST/OperationKinds.def
Expand Up @@ -66,6 +66,10 @@ CAST_OPERATION(BitCast)
/// bool b; reinterpret_cast<char&>(b) = 'a';
CAST_OPERATION(LValueBitCast)

/// CK_LValueToRValueBitCast - A conversion that causes us to reinterpret an
/// lvalue as an rvalue of a different type. Created by __builtin_bit_cast.
CAST_OPERATION(LValueToRValueBitCast)

/// CK_LValueToRValue - A conversion which causes the extraction of
/// an r-value from the operand gl-value. The result of an r-value
/// conversion is always unqualified.
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Expand Up @@ -2282,6 +2282,10 @@ DEF_TRAVERSE_STMT(CXXStaticCastExpr, {
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
})

DEF_TRAVERSE_STMT(BuiltinBitCastExpr, {
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
})

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
InitListExpr *S, DataRecursionQueue *Queue) {
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/Basic/DiagnosticASTKinds.td
Expand Up @@ -215,6 +215,19 @@ def note_constexpr_memcpy_unsupported : Note<
"size to copy (%4) is not a multiple of size of element type %3 (%5)|"
"source is not a contiguous array of at least %4 elements of type %3|"
"destination is not a contiguous array of at least %4 elements of type %3}2">;
def note_constexpr_bit_cast_unsupported_type : Note<
"constexpr bit_cast involving type %0 is not yet supported">;
def note_constexpr_bit_cast_unsupported_bitfield : Note<
"constexpr bit_cast involving bit-field is not yet supported">;
def note_constexpr_bit_cast_invalid_type : Note<
"bit_cast %select{from|to}0 a %select{|type with a }1"
"%select{union|pointer|member pointer|volatile|reference}2 "
"%select{type|member}1 is not allowed in a constant expression">;
def note_constexpr_bit_cast_invalid_subtype : Note<
"invalid type %0 is a %select{member|base}1 of %2">;
def note_constexpr_bit_cast_indet_dest : Note<
"indeterminate value can only initialize an object of type 'unsigned char'"
"%select{, 'char',|}1 or 'std::byte'; %0 is invalid">;

def warn_integer_constant_overflow : Warning<
"overflow in expression; result is %0 with type %1">,
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -9734,4 +9734,8 @@ def err_builtin_launder_invalid_arg : Error<
"%select{non-pointer|function pointer|void pointer}0 argument to "
"'__builtin_launder' is not allowed">;

def err_bit_cast_non_trivially_copyable : Error<
"__builtin_bit_cast %select{source|destination}0 type must be trivially copyable">;
def err_bit_cast_type_size_mismatch : Error<
"__builtin_bit_cast source size does not equal destination size (%0 vs %1)">;
} // end of sema component.
1 change: 1 addition & 0 deletions clang/include/clang/Basic/StmtNodes.td
Expand Up @@ -192,6 +192,7 @@ def ConvertVectorExpr : DStmt<Expr>;
def BlockExpr : DStmt<Expr>;
def OpaqueValueExpr : DStmt<Expr>;
def TypoExpr : DStmt<Expr>;
def BuiltinBitCastExpr : DStmt<ExplicitCastExpr>;

// Microsoft Extensions.
def MSPropertyRefExpr : DStmt<Expr>;
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/TokenKinds.def
Expand Up @@ -670,7 +670,7 @@ ALIAS("_pascal" , __pascal , KEYBORLAND)
KEYWORD(__builtin_convertvector , KEYALL)
ALIAS("__char16_t" , char16_t , KEYCXX)
ALIAS("__char32_t" , char32_t , KEYCXX)

KEYWORD(__builtin_bit_cast , KEYALL)
KEYWORD(__builtin_available , KEYALL)

// Clang-specific keywords enabled only in testing.
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Parse/Parser.h
Expand Up @@ -1780,6 +1780,9 @@ class Parser : public CodeCompletionHandler {
// C++ 5.2p1: C++ Casts
ExprResult ParseCXXCasts();

/// Parse a __builtin_bit_cast(T, E), used to implement C++2a std::bit_cast.
ExprResult ParseBuiltinBitCast();

//===--------------------------------------------------------------------===//
// C++ 5.2p1: C++ Type Identification
ExprResult ParseCXXTypeid();
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -5236,6 +5236,13 @@ class Sema {
SourceRange AngleBrackets,
SourceRange Parens);

ExprResult ActOnBuiltinBitCastExpr(SourceLocation KWLoc, Declarator &Dcl,
ExprResult Operand,
SourceLocation RParenLoc);

ExprResult BuildBuiltinBitCastExpr(SourceLocation KWLoc, TypeSourceInfo *TSI,
Expr *Operand, SourceLocation RParenLoc);

ExprResult BuildCXXTypeId(QualType TypeInfoType,
SourceLocation TypeidLoc,
TypeSourceInfo *Operand,
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/Expr.cpp
Expand Up @@ -1862,6 +1862,7 @@ bool CastExpr::CastConsistency() const {
case CK_FloatingComplexToBoolean:
case CK_IntegralComplexToBoolean:
case CK_LValueBitCast: // -> bool&
case CK_LValueToRValueBitCast:
case CK_UserDefinedConversion: // operator bool()
case CK_BuiltinFnToFnPtr:
case CK_FixedPointToBoolean:
Expand Down Expand Up @@ -3506,7 +3507,8 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case CXXStaticCastExprClass:
case CXXReinterpretCastExprClass:
case CXXConstCastExprClass:
case CXXFunctionalCastExprClass: {
case CXXFunctionalCastExprClass:
case BuiltinBitCastExprClass: {
// While volatile reads are side-effecting in both C and C++, we treat them
// as having possible (not definite) side-effects. This allows idiomatic
// code to behave without warning, such as sizeof(*v) for a volatile-
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ExprClassification.cpp
Expand Up @@ -343,6 +343,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXConstCastExprClass:
case Expr::ObjCBridgedCastExprClass:
case Expr::BuiltinBitCastExprClass:
// Only in C++ can casts be interesting at all.
if (!Lang.CPlusPlus) return Cl::CL_PRValue;
return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten());
Expand Down

0 comments on commit eee944e

Please sign in to comment.