Index: test/Sema/cast-to-union.c =================================================================== --- test/Sema/cast-to-union.c (revision 0) +++ test/Sema/cast-to-union.c (revision 0) @@ -0,0 +1,9 @@ +// RUN: clang -fsyntax-only -verify -pedantic %s + +union u { int i; }; +void f(union u); + +void test(int x) { + f((union u)x); // expected-warning {{C99 forbids casts to union type}} + f((union u)&x); // expected-error {{cast to union type from type 'int *' not present in union}} +} Index: include/clang/Basic/DiagnosticKinds.def =================================================================== --- include/clang/Basic/DiagnosticKinds.def (revision 62247) +++ include/clang/Basic/DiagnosticKinds.def (working copy) @@ -1427,6 +1427,10 @@ "C99 forbids conditional expressions with only one void side") DIAG(ext_typecheck_cast_nonscalar, EXTENSION, "C99 forbids casting nonscalar type %0 to the same type") +DIAG(ext_typecheck_cast_to_union, EXTENSION, + "C99 forbids casts to union type") +DIAG(err_typecheck_cast_to_union_no_type, ERROR, + "cast to union type from type %0 not present in union") DIAG(err_typecheck_expect_scalar_operand, ERROR, "operand of type %0 where arithmetic or pointer type is required") DIAG(err_typecheck_cond_incompatible_operands, ERROR, Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp (revision 62247) +++ lib/Sema/SemaExpr.cpp (working copy) @@ -1929,18 +1929,33 @@ } else if (castType->isDependentType() || castExpr->isTypeDependent()) { // We can't check any more until template instantiation time. } else if (!castType->isScalarType() && !castType->isVectorType()) { - // GCC struct/union extension: allow cast to self. - if (Context.getCanonicalType(castType).getUnqualifiedType() != - Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) || - (!castType->isStructureType() && !castType->isUnionType())) { + if (Context.getCanonicalType(castType).getUnqualifiedType() == + Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) && + (castType->isStructureType() || castType->isUnionType())) { + // GCC struct/union extension: allow cast to self. + Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar) + << castType << castExpr->getSourceRange(); + } else if (castType->isUnionType()) { + // GCC cast to union extension + RecordDecl *RD = castType->getAsRecordType()->getDecl(); + RecordDecl::field_iterator Field, FieldEnd; + for (Field = RD->field_begin(), FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + if (Context.getCanonicalType(Field->getType()).getUnqualifiedType() == + Context.getCanonicalType(castExpr->getType()).getUnqualifiedType()) { + Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union) + << castExpr->getSourceRange(); + break; + } + } + if (Field == FieldEnd) + return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type) + << castExpr->getType() << castExpr->getSourceRange(); + } else { // Reject any other conversions to non-scalar types. return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) << castType << castExpr->getSourceRange(); } - - // accept this, but emit an ext-warn. - Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar) - << castType << castExpr->getSourceRange(); } else if (!castExpr->getType()->isScalarType() && !castExpr->getType()->isVectorType()) { return Diag(castExpr->getLocStart(),