diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 7e5a6b3cc861..aa0eab96789a 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2772,6 +2772,16 @@ public: path_const_iterator path_begin() const { return path_buffer(); } path_const_iterator path_end() const { return path_buffer() + path_size(); } + const FieldDecl *getTargetUnionField() const { + assert(getCastKind() == CK_ToUnion); + return getTargetFieldForToUnionCast(getType(), getSubExpr()->getType()); + } + + static const FieldDecl *getTargetFieldForToUnionCast(QualType unionType, + QualType opType); + static const FieldDecl *getTargetFieldForToUnionCast(const RecordDecl *RD, + QualType opType); + static bool classof(const Stmt *T) { return T->getStmtClass() >= firstCastExprConstant && T->getStmtClass() <= lastCastExprConstant; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 7dc141835135..7c62ccf052cf 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1695,6 +1695,26 @@ CXXBaseSpecifier **CastExpr::path_buffer() { } } +const FieldDecl *CastExpr::getTargetFieldForToUnionCast(QualType unionType, + QualType opType) { + auto RD = unionType->castAs()->getDecl(); + return getTargetFieldForToUnionCast(RD, opType); +} + +const FieldDecl *CastExpr::getTargetFieldForToUnionCast(const RecordDecl *RD, + QualType OpType) { + auto &Ctx = RD->getASTContext(); + RecordDecl::field_iterator Field, FieldEnd; + for (Field = RD->field_begin(), FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + if (Ctx.hasSameUnqualifiedType(Field->getType(), OpType) && + !Field->isUnnamedBitfield()) { + return *Field; + } + } + return nullptr; +} + ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T, CastKind Kind, Expr *Operand, const CXXCastPath *BasePath, diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index d603101c3fd9..ad6348685b64 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2458,24 +2458,17 @@ void CastOperation::CheckCStyleCast() { // GCC's cast to union extension. if (DestRecordTy && DestRecordTy->getDecl()->isUnion()) { RecordDecl *RD = DestRecordTy->getDecl(); - RecordDecl::field_iterator Field, FieldEnd; - for (Field = RD->field_begin(), FieldEnd = RD->field_end(); - Field != FieldEnd; ++Field) { - if (Self.Context.hasSameUnqualifiedType(Field->getType(), SrcType) && - !Field->isUnnamedBitfield()) { - Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union) - << SrcExpr.get()->getSourceRange(); - break; - } - } - if (Field == FieldEnd) { + if (CastExpr::getTargetFieldForToUnionCast(RD, SrcType)) { + Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union) + << SrcExpr.get()->getSourceRange(); + Kind = CK_ToUnion; + return; + } else { Self.Diag(OpRange.getBegin(), diag::err_typecheck_cast_to_union_no_type) << SrcType << SrcExpr.get()->getSourceRange(); SrcExpr = ExprError(); return; } - Kind = CK_ToUnion; - return; } // OpenCL v2.0 s6.13.10 - Allow casts from '0' to event_t type.