PR c++/61339 - add mismatch between struct and class [-Wmismatched-tags] to non-bugs

gcc/c-family/ChangeLog:

	PR c++/61339
	* c.opt: 

gcc/cp/ChangeLog:

	PR c++/61339
	* parser.c (cp_parser_type_specifier): 
	(cp_parser_function_definition_after_declarator): 
	(cp_parser_template_declaration_after_parameters): 

gcc/testsuite/ChangeLog:

	PR c++/61339
	* g++.dg/warn/Wclass-is-pod.C: New test.
	* g++.dg/warn/Wstruct-not-pod.C: New test.

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 080066fa608..27b413115e3 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -794,6 +794,14 @@ Wstringop-truncation
 C ObjC C++ LTO ObjC++ Var(warn_stringop_truncation) Warning Init (1) LangEnabledBy(C ObjC C++ LTO ObjC++, Wall)
 Warn about truncation in string manipulation functions like strncat and strncpy.
 
+Wstruct-not-pod
+C++ ObjC++ Var(warn_struct_not_pod) Init (1) LangEnabledBy(C++ ObjC++, Wall)
+Warn about structs that are not POD.
+
+Wclass-is-pod
+C++ ObjC++ Var(warn_class_is_pod) Init (1) LangEnabledBy(C++ ObjC++, Wall)
+Warn about classes that are POD.
+
 Wsuggest-attribute=format
 C ObjC C++ ObjC++ Var(warn_suggest_attribute_format) Warning
 Warn about functions which might be candidates for format attributes.
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 12814102465..e20c26b7ecd 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -262,6 +262,8 @@ static bool cp_parser_omp_declare_reduction_exprs
 static void cp_finalize_oacc_routine
   (cp_parser *, tree, bool);
 
+static void maybe_warn_struct_vs_class (location_t, tree);
+
 /* Manifest constants.  */
 #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token))
 #define CP_SAVED_TOKEN_STACK 5
@@ -17442,6 +17444,8 @@ cp_parser_type_specifier (cp_parser* parser,
 					  type_spec,
 					  token,
 					  /*type_definition_p=*/true);
+
+	  maybe_warn_struct_vs_class (token->location, type_spec);
 	  return type_spec;
 	}
 
@@ -28039,6 +28043,118 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
   return fn;
 }
 
+/* Return true if the template TYPE appears to meet the requirements
+   of a POD type even if some of its instantiations may not.  */
+
+static bool
+template_pod_p (tree type)
+{
+  if (TYPE_HAS_USER_CONSTRUCTOR (type)
+      || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
+      || (TYPE_HAS_COPY_ASSIGN (type)
+	  && (cxx_dialect != cxx98
+	      || !TYPE_HAS_TRIVIAL_COPY_ASSIGN (type))))
+    return false;
+
+  for (tree fld = TYPE_FIELDS (type); fld; fld = TREE_CHAIN (fld))
+    {
+      if (TREE_CODE (fld) == FIELD_DECL
+	  && !TREE_STATIC (fld)
+	  && TREE_TYPE (fld))
+	{
+	  tree fldtype = TREE_TYPE (fld);
+	  if (TREE_CODE (fldtype) == REFERENCE_TYPE)
+	    return false;
+	  if (TREE_CODE (fldtype) == RECORD_TYPE
+	      && !template_pod_p (fldtype))
+	    return false;
+	}
+      else if (TREE_CODE (fld) == FUNCTION_DECL
+	  && DECL_NONSTATIC_MEMBER_FUNCTION_P (fld)
+	  && DECL_VIRTUAL_P (fld))
+	return false;
+    }
+
+  return true;
+}
+
+/* For a DECL of class type, issue a warning when it is a POD type
+   and is declared with the class-key class, or when it is not a POD
+   type and is declared withe the class-key struct.  When DECL refers
+   to a class template, consider instead whether it has a ctor, dtor,
+   or copy assignment operator as a proxy.  */
+
+static void
+maybe_warn_struct_vs_class (location_t loc, tree type)
+{
+  if (TREE_CODE (type) != RECORD_TYPE)
+    return;
+
+  const char *key = class_key_or_enum_as_string (type);
+  if (processing_template_decl)
+    {
+      if (template_pod_p (type))
+	{
+	  if (!strcmp (key, "class"))
+	    warning_at (loc, OPT_Wclass_is_pod,
+			"POD-like template %qT declared with class-key %qs; "
+			"use %qs instead",
+			type, key, "struct");
+	  else
+	    inform (loc,
+		    "POD-like template %qT declared with class-key %qs "
+		    "as expected",
+		    type, key);
+	}
+      else if (strcmp (key, "class"))
+	warning_at (loc, OPT_Wstruct_not_pod,
+		    "non-POD-like template %qT declared with class-key %qs; "
+		    "use %qs instead",
+		    type, key, "class");
+      else
+	inform (loc,
+		"non-POD-like template %qT declared with class-key %qs "
+		"as expected",
+		type, key);
+    }
+  else
+    {
+      if (pod_type_p (type))
+	{
+	  if (!strcmp (key, "class"))
+	    warning_at (loc, OPT_Wclass_is_pod,
+			"POD type %qT declared with class-key %qs; "
+			"use %qs instead",
+			type, key, "struct");
+	  else
+	    inform (loc,
+		    "POD type %qT declared with class-key %qs as expected",
+		    type, key);
+	}
+      else if (cxx_dialect == cxx98 && template_pod_p (type))
+	{
+	  if (!strcmp (key, "class"))
+	    warning_at (loc, OPT_Wstruct_not_pod,
+			"C++11 POD type %qT declared with class-key %qs; "
+			"use %qs instead",
+			type, key, "struct");
+	  else
+	    inform (loc,
+		    "C++11 POD type %qT declared with class-key %qs as expected",
+		    type, key);
+	}
+      else if (strcmp (key, "class"))
+	warning_at (loc, OPT_Wstruct_not_pod,
+		    "non-POD type %qT declared with class-key %qs; "
+		    "use %qs instead",
+		    type, key, "class");
+      else
+	inform (loc,
+		"non-POD type %qT declared with class-key %qs as expected",
+		type, key);
+    }
+}
+
 /* Parse a template-declaration body (following argument list).  */
 
 static void
@@ -28076,6 +28192,8 @@ cp_parser_template_declaration_after_parameters (cp_parser* parser,
 					   member_p,
                                            /*explicit_specialization_p=*/false,
 					   &friend_p);
+      // maybe_warn_struct_vs_class (token->location, TREE_TYPE (decl));
+
       pop_deferring_access_checks ();
 
       /* If this is a member template declaration, let the front
diff --git a/gcc/testsuite/g++.dg/warn/Wclass-is-pod.C b/gcc/testsuite/g++.dg/warn/Wclass-is-pod.C
new file mode 100644
index 00000000000..c276b469783
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wclass-is-pod.C
@@ -0,0 +1,127 @@
+// { dg-do compile }
+// { dg-options "-Wclass-is-pod" }
+
+namespace Pod
+{
+class A                 // { dg-warning "POD type 'Pod::A' declared with class-key 'class'; use 'struct' instead" }
+{ };
+class B                 // { dg-warning "\\\[-Wclass-is-pod" }
+{ public: int i; };
+class C                 // { dg-warning "\\\[-Wclass-is-pod" }
+{ public: void f (); };
+class D                 // { dg-warning "\\\[-Wclass-is-pod" }
+{ void operator= (int); };
+
+#if __cplusplus > 199711L
+class E                 // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } }
+  : A { };
+class F                 // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } }
+  : E { };
+class G                 // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } }
+  : private A { };
+#endif
+}
+
+
+namespace PodTemplate
+{
+template <class>
+class A                 // { dg-warning "\\\[-Wclass-is-pod" }
+{ };
+template <class>
+class B                 // { dg-warning "\\\[-Wclass-is-pod" }
+{ public: int i; };
+template <class>
+class C                 // { dg-warning "\\\[-Wclass-is-pod" }
+{ public: void f (); };
+template <class>
+class D                 // { dg-warning "\\\[-Wclass-is-pod" }
+{ void operator= (int); };
+
+#if __cplusplus > 199711L
+template <class T>
+class E                 // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } }
+  : A<T> { };
+template <class T>
+class F                 // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } }
+  : E<T> { };
+template <class T>
+class G                 // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } }
+  : private A<T> { };
+#endif
+}
+
+
+namespace NonPodDueToSpecialFunctions
+{
+class A
+{ public: A (); };
+class B
+{ public: B (int); };
+
+class C
+{ public: C (C&); };
+
+class D
+{ public: ~D (); };
+
+class E
+{ public: void operator= (E&); };
+}
+
+
+namespace NonPodDueToVirtuals
+{
+class A
+{ public: virtual void f (); };
+
+}
+
+
+namespace NonPodDueToNonPodMembers
+{
+class A
+{ public: int &r; };
+
+class B { public: B (); };
+
+class C
+{ public: B b; };
+}
+
+
+namespace NonPodTemplateDueToNonPodMembers
+{
+template <class T>
+class A
+{ public: T &r; };
+
+class B { public: B (); };
+
+template <class>
+class C
+{ public: B b; };
+}
+
+
+
+namespace NonPodDueToAccess
+{
+class A
+{ int i; public: int j; };
+
+class B
+{ int i; protected: int j; };
+}
+
+
+namespace NonPodDueToBases
+{
+struct A { };
+struct B { };
+class C: A, B           // { dg-bogus "\\\[-Wclass-is-pod" "pr91064" { xfail c++11 } }
+{ };
+
+class D: virtual A
+{ };
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wstruct-not-pod.C b/gcc/testsuite/g++.dg/warn/Wstruct-not-pod.C
new file mode 100644
index 00000000000..3e238eedef3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wstruct-not-pod.C
@@ -0,0 +1,336 @@
+// Test to verify that -Wstruct-not-pod is issued for struct definitions
+// that don't meet the requirements for a POD class.
+// { dg-do compile }
+// { dg-options "-Wstruct-not-pod" }
+
+#define ASSERT_POD(T) static_assert (__is_pod (T), #T "is pod")
+
+namespace PodStruct
+{
+struct A { }; ASSERT_POD (A);
+struct B { int i; const int j; }; ASSERT_POD (B);
+struct C { void f (); }; ASSERT_POD (C);
+struct D { void operator= (int); }; ASSERT_POD (D);
+
+#if __cplusplus > 199711L
+struct E: A { };
+struct F: E { };
+struct G: private A { }; ASSERT_POD (G);
+#endif
+
+struct H { public: int i; }; ASSERT_POD (H);
+
+#if __cplusplus > 199711L
+struct I { protected: int i; protected: int j; }; ASSERT_POD (J);
+#endif
+
+class J { J (); ~J (); };
+struct K { static const int i; static int &r; static J j; int k; };
+ASSERT_POD (K);
+}
+
+
+namespace PodTemplate
+{
+template <class> struct A { };
+template struct A<int> { };
+
+template <class> struct B { int i; };
+template struct B<int> { };
+
+template <class> struct C { void f (); };
+template struct C<int> { };
+
+template <class> struct D { void operator= (int); };
+template struct D<int> { };
+
+#if __cplusplus > 199711L
+template <class T> struct E: A<T> { };
+template struct E<int>;
+
+template <class T> struct F: E<T> { };
+template struct F<int>;
+
+template <class T> struct G: private A<T> { };
+template struct G<int>;
+#endif
+
+template <class> struct H { public: int i; };
+template struct H<int>;
+
+#if __cplusplus > 199711L
+template <class> struct I { protected: int i; protected: int j; };
+template struct I<int>;
+#endif
+
+// This is considered a POD even though instantiating it on a non-POD
+// will prevent it from being one.
+template <class T> struct J { T i; };
+template struct J<int>;
+
+template <class> struct K {
+  /* Template ctor and assignment operator are not special members.  */
+  template <class T> K (const K<T>&);
+  template <class T> K& operator= (const K<T>&);
+};
+ASSERT_POD (K<int>);
+}
+
+
+namespace PodExplicitSpecialization
+{
+template <class> class A;
+template <> struct A<int> { };
+
+template <class> class B;
+template <> struct B<int> { int i; };
+template <class> class C;
+template <> struct C<int> { void f (); };
+template <class> class D;
+template <> struct D<int> { void operator= (int); };
+
+#if __cplusplus > 199711L
+template <class> class E;
+template <> struct E<int>: A<int> { };
+
+template <class> class F;
+template <> struct F<int>: E<int> { };
+
+template <class> class G;
+template <> struct G<int>: private A<int> { };
+#endif
+
+template <class> class H;
+template <> struct H<int> { public: int i; };
+
+#if __cplusplus > 199711L
+template <class> class I;
+template <> struct I<int> { protected: int i; protected: int j; };
+#endif
+
+}
+
+
+namespace PodPartialSpecialization
+{
+template <class> class A;
+template <class T> struct A<const T> { };
+template struct A<const int>;
+
+template <class> class B;
+template <class T> struct B<const T> { int i; };
+template struct B<const int>;
+
+template <class> class C;
+template <class T> struct C<const T> { void f (); };
+template struct C<const int>;
+
+template <class> class D;
+template <class T> struct D<const T> { void operator= (int); };
+template struct D<const int>;
+
+#if __cplusplus > 199711L
+template <class> class E;
+template <class T> struct E<const T>: A<const T> { };
+template struct E<const int>;
+
+template <class> class F;
+template <class T> struct F<const T>: E<const T> { };
+template struct F<const int>;
+
+template <class> class G;
+template <class T> struct G<const T>: private A<const T> { };
+template struct G<const int>;
+#endif
+
+template <class> class H;
+template <class T> struct H<const T> { public: int i; };
+template struct H<const int>;
+
+#if __cplusplus > 199711L
+template <class> class I;
+template <class T> struct I<const T> { protected: int i; protected: int j; };
+template struct I<const int>;
+#endif
+
+// Similar to the case of the primary template, this is considered a POD
+// even though instantiating it on a non-POD will prevent it from being
+// one.
+template <class T> class J;
+template <class T> struct J<const T> { T i; };
+template struct J<const int>;
+}
+
+
+namespace NonPodStructDueToSpecialFunctions
+{
+struct A                // { dg-warning "non-POD type '\[A-Za-z\]\*::A' declared with class-key 'struct'; use 'class' instead" }
+{ A (); };
+
+struct B                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ B (int); };
+
+struct C                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ C (C&); };
+
+struct D                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ ~D (); };
+
+struct E                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ void operator= (E&); };
+}
+
+
+namespace NonPodTemplateDueToSpecialFunctions
+{
+template <class>
+struct A                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ A (); };
+
+template <class>
+struct B                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ B (int); };
+
+template <class>
+struct C                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ C (C&); };
+
+template <class>
+struct D                // { dg-warning "\\\[-Wstruct-not-pod" "FIXME" { xfail *-*-* } }
+{ ~D (); };
+
+template <class>
+struct E                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ void operator= (E&); };
+}
+
+
+namespace NonPodExplicitSpecializationDueToSpecialFunctions
+{
+template <class> class A;
+template <>
+struct A<int>           // { dg-warning "\\\[-Wstruct-not-pod" }
+{ A (); };
+
+template <class> class B;
+template <>
+struct B<int>          // { dg-warning "\\\[-Wstruct-not-pod" }
+{ B (int); };
+
+template <class> class C;
+template <>
+struct C<int>           // { dg-warning "\\\[-Wstruct-not-pod" }
+{ C (C&); };
+
+template <class> class D;
+template <>
+struct D<int>           // { dg-warning "\\\[-Wstruct-not-pod" }
+{ ~D (); };
+
+template <class> class E;
+template <>
+struct E<int>           // { dg-warning "\\\[-Wstruct-not-pod" }
+{ void operator= (E&); };
+}
+
+
+namespace NonPodPartialSpecializationDueToSpecialFunctions
+{
+template <class> class A;
+template <class T>
+struct A<T*>            // { dg-warning "\\\[-Wstruct-not-pod" }
+{ A (); };
+template struct A<int*>;
+
+template <class> class B;
+template <class T>
+struct B<T*>            // { dg-warning "\\\[-Wstruct-not-pod" }
+{ B (int); };
+template struct B<int*>;
+
+template <class> class C;
+template <class T>
+struct C<T*>            // { dg-warning "\\\[-Wstruct-not-pod" }
+{ C (C&); };
+template struct C<int*>;
+
+template <class> class D;
+template <class T>
+struct D<T*>            // { dg-warning "\\\[-Wstruct-not-pod" "FIXME" { xfail *-*-* } }
+{ ~D (); };
+template struct D<int*>;
+
+template <class> class E;
+template <class T>
+struct E<T*>            // { dg-warning "\\\[-Wstruct-not-pod" }
+{ void operator= (E&); };
+template struct E<int*>;
+}
+
+
+namespace NonPodDueToVirtuals
+{
+struct A                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ virtual void f (); };
+
+}
+
+
+namespace NonPodDueToNonPodMembers
+{
+struct A                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ int &r; };
+
+class B { public: B (); };
+
+struct C                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ B b; };
+}
+
+
+namespace NonPodTemplateDueToNonPodMembers
+{
+template <class>
+struct A                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ int &r; };
+
+class B { public: B (); };
+
+template <class>
+struct C                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ B b; };
+}
+
+
+namespace NonPodDueToAccess
+{
+struct A                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ int i; private: int j; };
+
+struct B                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ int i; protected: int j; };
+}
+
+
+namespace NonPodTemplateDueToAccess
+{
+template <class>
+struct A                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ int i; private: int j; };
+
+template <class>
+struct B                // { dg-warning "\\\[-Wstruct-not-pod" }
+{ int i; protected: int j; };
+}
+
+
+namespace NonPodDueToBases
+{
+struct A { };
+struct B { };
+struct C: A, B          // { dg-warning "\\\[-Wstruct-not-pod" "pr91064" { xfail c++11 } }
+{ };
+
+struct D: virtual A     // { dg-warning "\\\[-Wstruct-not-pod" }
+{ };
+}
