summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2017-08-15 21:42:47 +0000
committerJohn McCall <rjmccall@apple.com>2017-08-15 21:42:47 +0000
commitf1ef796fd9f1fb4412698acffb649d5fa1d55b18 (patch)
tree809b07139f2f4c711728c5bfac5ae8dd475f96de
parent477b123ead3f9044fa98d2173b69e57a39ec3823 (diff)
downloadbcm5719-llvm-f1ef796fd9f1fb4412698acffb649d5fa1d55b18.tar.gz
bcm5719-llvm-f1ef796fd9f1fb4412698acffb649d5fa1d55b18.zip
Allow the target field of a CK_ToUnion to be more easily recovered.
llvm-svn: 310963
-rw-r--r--clang/include/clang/AST/Expr.h10
-rw-r--r--clang/lib/AST/Expr.cpp20
-rw-r--r--clang/lib/Sema/SemaCast.cpp19
3 files changed, 36 insertions, 13 deletions
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 7e5a6b3cc86..aa0eab96789 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 7dc14183513..7c62ccf052c 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<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,
CastKind Kind, Expr *Operand,
const CXXCastPath *BasePath,
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index d603101c3fd..ad6348685b6 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.
OpenPOWER on IntegriCloud