Fix C++/93809 and C++/83469: typenames and unions

Message ID 1638899982-24312-1-git-send-email-apinski@marvell.com
State New
Headers
Series Fix C++/93809 and C++/83469: typenames and unions |

Commit Message

Li, Pan2 via Gcc-patches Dec. 7, 2021, 5:59 p.m. UTC
  From: Andrew Pinski <apinski@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"
	* 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
  

Comments

Marek Polacek Dec. 7, 2021, 6:32 p.m. UTC | #1
On Tue, Dec 07, 2021 at 09:59:42AM -0800, apinski--- via Gcc-patches wrote:
> From: Andrew Pinski <apinski@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
  

Patch

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".  */
+#define TYPENAME_IS_UNION_P(NODE) \
+  (TREE_LANG_FLAG_3 (TYPENAME_TYPE_CHECK (NODE)))
+
 /* 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);
+  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",
+			 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 "" }
+    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 "" }
+    int
+    main()
+    {
+      f<S>();
+    }
diff --git a/gcc/testsuite/g++.dg/pr93809-1.C b/gcc/testsuite/g++.dg/pr93809-1.C
new file mode 100644
index 00000000000..321ea517cbf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr93809-1.C
@@ -0,0 +1,11 @@ 
+// { dg-do compile }
+// PR C++/93809
+class C { };
+enum E { };
+struct S { };
+union U { };
+
+typedef typename ::C C2;
+typedef typename ::E E2;
+typedef typename ::S S2;
+typedef typename ::U U2;   // error
diff --git a/gcc/testsuite/g++.dg/pr93809-2.C b/gcc/testsuite/g++.dg/pr93809-2.C
new file mode 100644
index 00000000000..a98dada30ee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr93809-2.C
@@ -0,0 +1,5 @@ 
+// { dg-do compile }
+// { dg-require-effective-target c++11 }
+// PR C++/93809
+union a{};
+auto var = new (typename :: a );
diff --git a/gcc/testsuite/g++.dg/pr93809-3.C b/gcc/testsuite/g++.dg/pr93809-3.C
new file mode 100644
index 00000000000..f544b1f059f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr93809-3.C
@@ -0,0 +1,4 @@ 
+// { dg-do compile }
+// PR C++/93809
+typedef union{} typedef_union;
+typename :: typedef_union foo1 () { return typedef_union();  } 
diff --git a/gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C b/gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C
index 0eeee34dae7..dcccdcad22d 100644
--- a/gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C
+++ b/gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C
@@ -28,7 +28,7 @@  struct N::S s3;       // { dg-warning "-Wredundant-tags" }
 
 N::U u1;
 typename N::U u2;     // { dg-bogus "-Wredundant-tags" }
-                      // { dg-bogus "'class' tag used in naming 'union N::U" "pr93809" { xfail *-*-*} .-1 }
+                      // { dg-bogus "'class' tag used in naming 'union N::U" "pr93809" { target *-*-*} .-1 }
 union N::U u3;        // { dg-warning "-Wredundant-tags" }