Message ID | 4EE91FBA.1070204@redhat.com |
---|---|
State | New |
Headers | show |
On Wed, Dec 14, 2011 at 05:14:18PM -0500, Jason Merrill wrote: > --- a/gcc/c-family/c-common.c > +++ b/gcc/c-family/c-common.c > @@ -6286,13 +6286,21 @@ handle_transparent_union_attribute (tree *node, tree name, > > if (TREE_CODE (type) == UNION_TYPE) > { > - /* When IN_PLACE is set, leave the check for FIELDS and MODE to > - the code in finish_struct. */ > + /* Make sure that the first field will work for a transparent union. > + If the type isn't complete yet, leave the check to the code in > + finish_struct. */ > + if (TYPE_SIZE (type)) > + { > + tree first = first_field (type); > + if (first == NULL_TREE > + || TYPE_MODE (type) != DECL_MODE (first)) > + goto ignored; > + } I'd think it would be nicer to emit the same diagnostic from this spot as we do if handle_transparent_union_attribute is called on an incomplete type and finish_struct is called later. Unfortunately that varies between C and C++ FEs, we'd need a langhook for that, which is perhaps an overkill for such rarely used attribute. So, I'm fine with this patch for the trunk too, though perhaps you want also || first == error_mark_node || DECL_ARTIFICIAL (first) for the condition to catch what finish_struct_1 does for C++? Jakub
commit f3b9daf04363159ed8707df50ed77989e1ee31be Author: Jason Merrill <jason@redhat.com> Date: Wed Dec 14 14:05:57 2011 -0500 PR c++/51228 * c-common.c (handle_transparent_union_attribute): Check the first field if the type is complete. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index fbbcb38..87eee79 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -6286,13 +6286,21 @@ handle_transparent_union_attribute (tree *node, tree name, if (TREE_CODE (type) == UNION_TYPE) { - /* When IN_PLACE is set, leave the check for FIELDS and MODE to - the code in finish_struct. */ + /* Make sure that the first field will work for a transparent union. + If the type isn't complete yet, leave the check to the code in + finish_struct. */ + if (TYPE_SIZE (type)) + { + tree first = first_field (type); + if (first == NULL_TREE + || TYPE_MODE (type) != DECL_MODE (first)) + goto ignored; + } + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) { - if (TYPE_FIELDS (type) == NULL_TREE - || c_dialect_cxx () - || TYPE_MODE (type) != DECL_MODE (TYPE_FIELDS (type))) + /* build_duplicate_type doesn't work for C++. */ + if (c_dialect_cxx ()) goto ignored; /* A type variant isn't good enough, since we don't a cast diff --git a/gcc/testsuite/c-c++-common/transparent-union-1.c b/gcc/testsuite/c-c++-common/transparent-union-1.c new file mode 100644 index 0000000..3fb6e78 --- /dev/null +++ b/gcc/testsuite/c-c++-common/transparent-union-1.c @@ -0,0 +1,5 @@ +/* PR c++/51228 */ + +typedef union {} U __attribute__((transparent_union)); /* { dg-warning "ignored" } */ + +void foo(U u) {}