On Tue, Dec 07, 2021 at 09:59:42AM -0800, apinski--- via Gcc-patches wrote: > From: Andrew Pinski <apin...@marvell.com> > > There are a few issues here with typenames and unions (and even struct > keywords with unions). First in cp_parser_check_class_key, > we need to allow typenames to name union types and union key > to be able to use with typenames. > > The next issue is we need to record if we had a union key, > right now we just record it was a struct/class/typename one > which is wrong. > > OK? Boostrapped and tested on x86_64-linux-gnu with no regressions. > > PR c++/83469 > PR c++/93809 > > gcc/cp/ChangeLog: > > * cp-tree.h (UNION_CLASS_TYPE_P): New define. > (TYPENAME_IS_UNION_P): New Define. > * decl.c (struct typename_info): Add union_p field. > (struct typename_hasher::equal): Compare union_p field. > (build_typename_type): Move union_type to > union_p/TYPENAME_IS_UNION_P. > * error.c (dump_type) <case TYPENAME_TYPE>: Handle TYPENAME_IS_UNION_P > as "union"
Missing "." here. > * module.cc (trees_out::type_node): Handle TYPENAME_IS_UNION_P. > * parser.c (cp_parser_check_class_key): Allow > typename key for union types and allow union keyword for > typename types. > * pt.c (tsubst) <case TYPENAME_TYPE>: For TYPENAME_IS_CLASS_P, > check NON_UNION_CLASS_TYPE_P rather than CLASS_TYPE_P. > Add TYPENAME_IS_UNION_P handling. > > gcc/testsuite/ChangeLog: > > * g++.dg/warn/Wredundant-tags-3.C: Remove xfail. > * g++.dg/pr83469-1.C: New test. > * g++.dg/pr83469-2.C: New test. > * g++.dg/pr83469-3.C: New test. > * g++.dg/pr93809-1.C: New test. > * g++.dg/pr93809-2.C: New test. > * g++.dg/pr93809-3.C: New test. > --- > gcc/cp/cp-tree.h | 11 +++++++++-- > gcc/cp/decl.c | 9 ++++++--- > gcc/cp/error.c | 1 + > gcc/cp/module.cc | 2 ++ > gcc/cp/parser.c | 4 +++- > gcc/cp/pt.c | 10 +++++++++- > gcc/testsuite/g++.dg/pr83469-1.C | 15 +++++++++++++++ > gcc/testsuite/g++.dg/pr83469-2.C | 13 +++++++++++++ > gcc/testsuite/g++.dg/pr83469-3.C | 13 +++++++++++++ > gcc/testsuite/g++.dg/pr93809-1.C | 11 +++++++++++ > gcc/testsuite/g++.dg/pr93809-2.C | 5 +++++ > gcc/testsuite/g++.dg/pr93809-3.C | 4 ++++ > gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C | 2 +- > 13 files changed, 92 insertions(+), 8 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/pr83469-1.C > create mode 100644 gcc/testsuite/g++.dg/pr83469-2.C > create mode 100644 gcc/testsuite/g++.dg/pr83469-3.C > create mode 100644 gcc/testsuite/g++.dg/pr93809-1.C > create mode 100644 gcc/testsuite/g++.dg/pr93809-2.C > create mode 100644 gcc/testsuite/g++.dg/pr93809-3.C > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index 3510512d751..ea9cbb775e6 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -2206,6 +2206,10 @@ enum languages { lang_c, lang_cplusplus }; > #define NON_UNION_CLASS_TYPE_P(T) \ > (TREE_CODE (T) == RECORD_TYPE && TYPE_LANG_FLAG_5 (T)) > > +/* Nonzero if T is a class type and is a union. */ > +#define UNION_CLASS_TYPE_P(T) \ > + (TREE_CODE (T) == UNION_TYPE && TYPE_LANG_FLAG_5 (T)) > + > /* Keep these checks in ascending code order. */ > #define RECORD_OR_UNION_CODE_P(T) \ > ((T) == RECORD_TYPE || (T) == UNION_TYPE) > @@ -4184,11 +4188,14 @@ more_aggr_init_expr_args_p (const > aggr_init_expr_arg_iterator *iter) > #define TYPENAME_IS_ENUM_P(NODE) \ > (TREE_LANG_FLAG_0 (TYPENAME_TYPE_CHECK (NODE))) > > -/* True if a TYPENAME_TYPE was declared as a "class", "struct", or > - "union". */ > +/* True if a TYPENAME_TYPE was declared as a "class", "struct". */ > #define TYPENAME_IS_CLASS_P(NODE) \ > (TREE_LANG_FLAG_1 (TYPENAME_TYPE_CHECK (NODE))) > > +/* True if a TYPENAME_TYPE was declared as an "union". */ "a union" > +#define TYPENAME_IS_UNION_P(NODE) \ > + (TREE_LANG_FLAG_3 (TYPENAME_TYPE_CHECK (NODE))) > + Please document this new flag in "Usage of TREE_LANG_FLAG_?:" above. > /* True if a TYPENAME_TYPE is in the process of being resolved. */ > #define TYPENAME_IS_RESOLVING_P(NODE) \ > (TREE_LANG_FLAG_2 (TYPENAME_TYPE_CHECK (NODE))) > diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c > index 56f80775ca0..8fa07e30d69 100644 > --- a/gcc/cp/decl.c > +++ b/gcc/cp/decl.c > @@ -3930,6 +3930,7 @@ struct typename_info { > tree template_id; > bool enum_p; > bool class_p; > + bool union_p; > }; > > struct typename_hasher : ggc_ptr_hash<tree_node> > @@ -3958,7 +3959,8 @@ struct typename_hasher : ggc_ptr_hash<tree_node> > && TYPE_CONTEXT (t1) == t2->scope > && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id > && TYPENAME_IS_ENUM_P (t1) == t2->enum_p > - && TYPENAME_IS_CLASS_P (t1) == t2->class_p); > + && TYPENAME_IS_CLASS_P (t1) == t2->class_p > + && TYPENAME_IS_UNION_P (t1) == t2->union_p); > } > }; > > @@ -3983,8 +3985,8 @@ build_typename_type (tree context, tree name, tree > fullname, > ti.template_id = fullname; > ti.enum_p = tag_type == enum_type; > ti.class_p = (tag_type == class_type > - || tag_type == record_type > - || tag_type == union_type); > + || tag_type == record_type); Looks like this can fit on a single line now. > + ti.union_p = tag_type == union_type; > hashval_t hash = (htab_hash_pointer (ti.scope) > ^ htab_hash_pointer (ti.name)); > > @@ -4001,6 +4003,7 @@ build_typename_type (tree context, tree name, tree > fullname, > TYPENAME_TYPE_FULLNAME (t) = ti.template_id; > TYPENAME_IS_ENUM_P (t) = ti.enum_p; > TYPENAME_IS_CLASS_P (t) = ti.class_p; > + TYPENAME_IS_UNION_P (t) = ti.union_p; > > /* Build the corresponding TYPE_DECL. */ > tree d = build_decl (input_location, TYPE_DECL, name, t); > diff --git a/gcc/cp/error.c b/gcc/cp/error.c > index daea3b39a15..49b509eef14 100644 > --- a/gcc/cp/error.c > +++ b/gcc/cp/error.c > @@ -671,6 +671,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags) > pp_cxx_ws_string (pp, > TYPENAME_IS_ENUM_P (t) ? "enum" > : TYPENAME_IS_CLASS_P (t) ? "class" > + : TYPENAME_IS_UNION_P (t) ? "union" > : "typename"); > dump_typename (pp, t, flags); > break; > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc > index 71d0fab411f..f956d1d90cb 100644 > --- a/gcc/cp/module.cc > +++ b/gcc/cp/module.cc > @@ -8819,6 +8819,8 @@ trees_out::type_node (tree type) > tag_type = enum_type; > else if (TYPENAME_IS_CLASS_P (type)) > tag_type = class_type; > + else if (TYPENAME_IS_UNION_P (type)) > + tag_type = union_type; > u (int (tag_type)); > } > } > diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c > index 55e6a1a8b3a..bbb1a52e381 100644 > --- a/gcc/cp/parser.c > +++ b/gcc/cp/parser.c > @@ -33304,7 +33304,9 @@ cp_parser_check_class_key (cp_parser *parser, > location_t key_loc, > return; > > bool seen_as_union = TREE_CODE (type) == UNION_TYPE; > - if (seen_as_union != (class_key == union_type)) > + if (class_key != typename_type > + && TREE_CODE (type) != TYPENAME_TYPE > + && seen_as_union != (class_key == union_type)) > { > if (permerror (input_location, "%qs tag used in naming %q#T", > class_key == union_type ? "union" > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index d3efc6ea238..3d7539f62c1 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -16113,7 +16113,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, > tree in_decl) > else > return error_mark_node; > } > - else if (TYPENAME_IS_CLASS_P (t) && !CLASS_TYPE_P (f)) > + else if (TYPENAME_IS_CLASS_P (t) && !NON_UNION_CLASS_TYPE_P (f)) > { > if (complain & tf_error) > error ("%qT resolves to %qT, which is not a class type", > @@ -16121,6 +16121,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, > tree in_decl) > else > return error_mark_node; > } > + else if (TYPENAME_IS_UNION_P (t) && !UNION_CLASS_TYPE_P (f)) > + { > + if (complain & tf_error) > + error ("%qT resolves to %qT, which is not an union type", "a union" > + t, f); > + else > + return error_mark_node; > + } > } > > return cp_build_qualified_type_real > diff --git a/gcc/testsuite/g++.dg/pr83469-1.C > b/gcc/testsuite/g++.dg/pr83469-1.C > new file mode 100644 > index 00000000000..94a21fbbb98 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/pr83469-1.C > @@ -0,0 +1,15 @@ > +// { dg-do compile } > +// PR C++/83469 > + struct S { > + union U { int m; }; > + }; > + > + template <typename T> > + void f() > + { union T::U u; } > + > + int > + main() > + { > + f<S>(); > + } > diff --git a/gcc/testsuite/g++.dg/pr83469-2.C > b/gcc/testsuite/g++.dg/pr83469-2.C > new file mode 100644 > index 00000000000..c202e36b03b > --- /dev/null > +++ b/gcc/testsuite/g++.dg/pr83469-2.C > @@ -0,0 +1,13 @@ > +// { dg-do compile } > +// PR C++/83469 > + struct S { > + union U { int m; }; > + }; > + template <typename T> > + void f() > + { struct T::U u; } // { dg-error "" } Can we expect a particular error here rather than any? > + int > + main() > + { > + f<S>(); > + } > diff --git a/gcc/testsuite/g++.dg/pr83469-3.C > b/gcc/testsuite/g++.dg/pr83469-3.C > new file mode 100644 > index 00000000000..1ffff0af3c9 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/pr83469-3.C > @@ -0,0 +1,13 @@ > +// { dg-do compile } > +// PR C++/83469 > + struct S { > + struct C { int m; }; > + }; > + template <typename T> > + void f() > + { union T::C u; } // { dg-error "" } Likewise. Additionally, can you move the new tests into an existing subdirectory? I guess parse/ would be appropriate for this. Thanks for the patch. Marek