From eff2cd58a897379c7fc46e83447d4619d6f6e9ca Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Thu, 15 Jan 2009 04:51:39 +0000 Subject: [PATCH] PR2746: Implement GCC cast to union extension git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62255 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticKinds.def | 4 ++++ lib/Sema/SemaExpr.cpp | 31 ++++++++++++++++++------- test/Sema/cast-to-union.c | 9 +++++++ 3 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 test/Sema/cast-to-union.c diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index a9c6ea3c25..652c346340 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -1427,6 +1427,10 @@ DIAG(ext_typecheck_cond_one_void, EXTENSION, "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, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 33d73bf106..b8d58c101c 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1929,18 +1929,33 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) { } 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(), diff --git a/test/Sema/cast-to-union.c b/test/Sema/cast-to-union.c new file mode 100644 index 0000000000..f23a34b11c --- /dev/null +++ b/test/Sema/cast-to-union.c @@ -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}} +} -- 2.40.0