Allow the target field of a CK_ToUnion to be more easily recovered.

llvm-svn: 310963
This commit is contained in:
John McCall 2017-08-15 21:42:47 +00:00
parent 477b123ead
commit f1ef796fd9
3 changed files with 36 additions and 13 deletions

View File

@ -2772,6 +2772,16 @@ public:
path_const_iterator path_begin() const { return path_buffer(); } path_const_iterator path_begin() const { return path_buffer(); }
path_const_iterator path_end() const { return path_buffer() + path_size(); } 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) { static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstCastExprConstant && return T->getStmtClass() >= firstCastExprConstant &&
T->getStmtClass() <= lastCastExprConstant; T->getStmtClass() <= lastCastExprConstant;

View File

@ -1695,6 +1695,26 @@ CXXBaseSpecifier **CastExpr::path_buffer() {
} }
} }
const FieldDecl *CastExpr::getTargetFieldForToUnionCast(QualType unionType,
QualType opType) {
auto RD = unionType->castAs<RecordType>()->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, ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T,
CastKind Kind, Expr *Operand, CastKind Kind, Expr *Operand,
const CXXCastPath *BasePath, const CXXCastPath *BasePath,

View File

@ -2458,24 +2458,17 @@ void CastOperation::CheckCStyleCast() {
// GCC's cast to union extension. // GCC's cast to union extension.
if (DestRecordTy && DestRecordTy->getDecl()->isUnion()) { if (DestRecordTy && DestRecordTy->getDecl()->isUnion()) {
RecordDecl *RD = DestRecordTy->getDecl(); RecordDecl *RD = DestRecordTy->getDecl();
RecordDecl::field_iterator Field, FieldEnd; if (CastExpr::getTargetFieldForToUnionCast(RD, SrcType)) {
for (Field = RD->field_begin(), FieldEnd = RD->field_end(); Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union)
Field != FieldEnd; ++Field) { << SrcExpr.get()->getSourceRange();
if (Self.Context.hasSameUnqualifiedType(Field->getType(), SrcType) && Kind = CK_ToUnion;
!Field->isUnnamedBitfield()) { return;
Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union) } else {
<< SrcExpr.get()->getSourceRange();
break;
}
}
if (Field == FieldEnd) {
Self.Diag(OpRange.getBegin(), diag::err_typecheck_cast_to_union_no_type) Self.Diag(OpRange.getBegin(), diag::err_typecheck_cast_to_union_no_type)
<< SrcType << SrcExpr.get()->getSourceRange(); << SrcType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError(); SrcExpr = ExprError();
return; return;
} }
Kind = CK_ToUnion;
return;
} }
// OpenCL v2.0 s6.13.10 - Allow casts from '0' to event_t type. // OpenCL v2.0 s6.13.10 - Allow casts from '0' to event_t type.