diff mbox series

[2/3] change class-key of PODs to struct and others to class (PR 61339)

Message ID 05c26a42-d2ed-493c-441d-5325dafa6e53@gmail.com
State New
Headers show
Series add support for POD struct convention (PR 61339) | expand

Commit Message

Martin Sebor July 8, 2019, 10 p.m. UTC
The attached patch changes the class-key of class definitions that
satisfy the requirements on a POD struct to 'struct', and that of
struct definitions that aren't POD to class, according to the GCC
coding convention.  The patch is also prerequisite for GCC being
able to compile cleanly with -Wmismatched-tags.

I made the changes building GCC with -Wstruct-not-pod and
-Wclass-is-pod enabled, scanning the build log for instances
of each warning, and using a script replacing the class-key
as necessary and adjusting the access of the members declared
immediately after the class-head.

Martin

Comments

Martin Sebor July 8, 2019, 10:20 p.m. UTC | #1
Hopefully with the right patch this time (thanks Jon).

On 7/8/19 4:00 PM, Martin Sebor wrote:
> The attached patch changes the class-key of class definitions that
> satisfy the requirements on a POD struct to 'struct', and that of
> struct definitions that aren't POD to class, according to the GCC
> coding convention.  The patch is also prerequisite for GCC being
> able to compile cleanly with -Wmismatched-tags.
> 
> I made the changes building GCC with -Wstruct-not-pod and
> -Wclass-is-pod enabled, scanning the build log for instances
> of each warning, and using a script replacing the class-key
> as necessary and adjusting the access of the members declared
> immediately after the class-head.
> 
> Martin
Richard Sandiford July 9, 2019, 1:48 p.m. UTC | #2
Martin Sebor <msebor@gmail.com> writes:
> Hopefully with the right patch this time (thanks Jon).
>
> On 7/8/19 4:00 PM, Martin Sebor wrote:
>> The attached patch changes the class-key of class definitions that
>> satisfy the requirements on a POD struct to 'struct', and that of
>> struct definitions that aren't POD to class, according to the GCC
>> coding convention.  The patch is also prerequisite for GCC being
>> able to compile cleanly with -Wmismatched-tags.
>> 
>> I made the changes building GCC with -Wstruct-not-pod and
>> -Wclass-is-pod enabled, scanning the build log for instances
>> of each warning, and using a script replacing the class-key
>> as necessary and adjusting the access of the members declared
>> immediately after the class-head.
>> 
>> Martin
>
> PR c++/61339 - add mismatch between struct and class [-Wmismatched-tags] to non-bugs
>
> gcc/c/ChangeLog:
>
> 	* c-decl.c: Change class-key from class to struct and vice versa
> 	to match convention and avoid -Wclass-is-pod and -Wstruct-no-pod.
> 	* gimple-parser.c: Same.
>
> gcc/c-family/ChangeLog:
>
> 	* c-format.c (check_argument_type): Change class-key from class to
> 	struct and vice versa to match convention and avoid -Wclass-is-pod
> 	and -Wstruct-no-pod.
> 	* c-pretty-print.h: Same.
>
> gcc/cp/ChangeLog:
>
> 	* constexpr.c (cxx_eval_call_expression): Change class-key from class
> 	to struct and vice versa to match convention and avoid -Wclass-is-pod
> 	and -Wstruct-no-pod.
> 	* constraint.cc (get_concept_definition): Same.
> 	* cp-tree.h: Same.
> 	* cxx-pretty-print.h: Same.
> 	* error.c: Same.
> 	* logic.cc (term_list::replace): Same.
> 	* name-lookup.c (find_local_binding): Same.
> 	* pt.c (tsubst_binary_right_fold): Same.
> 	* search.c (field_accessor_p): Same.
> 	* semantics.c (expand_or_defer_fn): Same.
>
> gcc/lto/ChangeLog:
>
> 	* lto-dump.c: Same.

Need to cut-&-paste the description for this one.

> gcc/ChangeLog:
>
> 	* align.h: Change class-key from class to struct and vice versa
> 	to match convention and avoid -Wclass-is-pod and -Wstruct-no-pod.
> 	* alloc-pool.h: Same.
> 	* asan.c (shadow_mem_size): Same.
> 	* auto-profile.c: Same.
> 	* basic-block.h: Same.
> 	* bitmap.h: Same.
> 	* cfgexpand.c (set_rtl): Same.
> 	(expand_one_stack_var_at): Same.
> 	* cfghooks.h: Same.
> 	* cfgloop.h: Same.
> 	* cgraph.h: Same.
> 	* config/i386/i386.h: Same.
> 	* df-problems.c (df_print_bb_index): Same.
> 	* df-scan.c: Same.
> 	* df.h (df_single_use): Same.
> 	* diagnostic-show-locus.c (layout::print_annotation_line): Same.
> 	(layout::annotation_line_showed_range_p): Same.
> 	(get_printed_columns): Same.
> 	(correction::ensure_terminated): Same.
> 	(line_corrections::~line_corrections): Same.
> 	* dojump.h: Same.
> 	* dse.c: Same.
> 	* dump-context.h: Same.
> 	* dumpfile.h: Same.
> 	* dwarf2out.c: Same.
> 	* edit-context.c: Same.
> 	* fibonacci_heap.c (test_union_of_equal_heaps): Same.
> 	* flags.h: Same.
> 	* function.c (assign_stack_local): Same.
> 	* function.h: Same.
> 	* gcc.c: Same.
> 	* gcov.c (block_info::block_info): Same.
> 	* genattrtab.c: Same.
> 	* genextract.c: Same.
> 	* genmatch.c (comparison_code_p): Same.
> 	(id_base::id_base): Same.
> 	(decision_tree::print): Same.
> 	* genoutput.c: Same.
> 	* genpreds.c (write_one_predicate_function): Same.
> 	* genrecog.c (validate_pattern): Same.
> 	(find_operand_positions): Same.
> 	(optimize_subroutine_group): Same.
> 	(merge_pattern_transition::merge_pattern_transition): Same.
> 	(merge_pattern_info::merge_pattern_info): Same.
> 	(merge_state_result::merge_state_result): Same.
> 	(merge_into_state): Same.
> 	* gensupport.c: Same.
> 	* gensupport.h: Same.
> 	* ggc-common.c (init_ggc_heuristics): Same.
> 	* ggc-tests.c (test_union): Same.
> 	* gimple-loop-interchange.cc (dump_induction): Same.
> 	* gimple-loop-versioning.cc: Same.
> 	* gimple-match.h (gimple_match_cond::any_else): Same.
> 	* gimple-ssa-backprop.c: Same.
> 	* gimple-ssa-sprintf.c: Same.
> 	* gimple-ssa-store-merging.c (store_operand_info::store_operand_info): Same.
> 	(store_immediate_info::store_immediate_info): Same.
> 	(merged_store_group::apply_stores): Same.
> 	(get_location_for_stmts): Same.
> 	* gimple-ssa-strength-reduction.c: Same.
> 	* gimple-ssa-warn-alloca.c: Same.
> 	* gimple-ssa-warn-restrict.c (pass_wrestrict::execute): Same.
> 	* godump.c (go_type_decl): Same.
> 	* hash-map-tests.c (test_map_of_strings_to_int): Same.
> 	* hash-map.h: Same.
> 	* hash-set-tests.c (test_set_of_strings): Same.
> 	* hsa-brig.c: Same.
> 	* hsa-common.h: Same.
> 	* hsa-gen.c (transformable_switch_to_sbr_p): Same.
> 	* input.c (assert_loceq): Same.
> 	* input.h: Same.
> 	* ipa-cp.c: Same.
> 	* ipa-devirt.c (possible_polymorphic_call_targets_1): Same.
> 	* ipa-fnsummary.h: Same.
> 	* ipa-inline.h: Same.
> 	* ipa-prop.h: Same.
> 	* ipa-split.c (visit_bb): Same.
> 	* ira-int.h (minmax_set_iter_next): Same.
> 	* loop-invariant.c: Same.
> 	* loop-iv.c: Same.
> 	* lra-eliminations.c: Same.
> 	* lra-int.h: Same.
> 	* lra-lives.c (mark_regno_dead): Same.
> 	* lra-remat.c: Same.
> 	* lra-spills.c: Same.
> 	* lto-streamer.h: Same.
> 	* mem-stats.h: Same.
> 	* omp-grid.c (omp_grid_lastprivate_predicate): Same.
> 	* omp-low.c (omp_clause_aligned_alignment): Same.
> 	* optabs-query.h (get_vcond_eq_icode): Same.
> 	* optabs.h: Same.
> 	* opts.c (wrap_help): Same.
> 	* poly-int.h: Same.
> 	* predict.c (predict_paths_leading_to_edge): Same.
> 	* pretty-print.h: Same.
> 	* profile-count.h: Same.
> 	* read-md.h: Same.
> 	* read-rtl-function.c: Same.
> 	* ree.c: Same.
> 	* reginfo.c: Same.
> 	* regrename.c: Same.
> 	* regrename.h: Same.
> 	* reload.h: Same.
> 	* rtl-iter.h: Same.
> 	* rtl.h (costs_add_n_insns): Same.
> 	* sanopt.c: Same.
> 	* sched-int.h: Same.
> 	* sel-sched-ir.h: Same.
> 	* selftest.h: Same.
> 	* sese.h (vec_find): Same.
> 	* stmt.c: Same.
> 	* target-globals.h: Same.
> 	* tree-affine.c (aff_combination_find_elt): Same.
> 	* tree-affine.h: Same.
> 	* tree-data-ref.h: Same.
> 	* tree-outof-ssa.c (ssa_is_replaceable_p): Same.
> 	* tree-predcom.c: Same.
> 	* tree-scalar-evolution.c (find_var_scev_info): Same.
> 	* tree-ssa-alias.h: Same.
> 	* tree-ssa-ccp.c: Same.
> 	* tree-ssa-coalesce.c (ssa_conflicts_dump): Same.
> 	* tree-ssa-loop-im.c (for_all_locs_in_loop): Same.
> 	(rewrite_mem_refs): Same.
> 	(execute_sm_if_changed): Same.
> 	(hoist_memory_references): Same.
> 	* tree-ssa-loop-ivopts.c (operator<=): Same.
> 	* tree-ssa-loop.h: Same.
> 	* tree-ssa-pre.c (get_or_alloc_expr_for_name): Same.
> 	* tree-ssa-structalias.c: Same.
> 	* tree-switch-conversion.h (cluster::cluster): Same.
> 	(simple_cluster::simple_cluster): Same.
> 	* tree-vect-patterns.c (type_conversion_p): Same.
> 	* tree-vectorizer.c (dump_stmt_cost): Same.
> 	* tree-vectorizer.h (loop_vec_info_for_loop): Same.
> 	* tree.c (protected_set_expr_location): Same.
> 	* tree.h (desired_pro_or_demotion_p): Same.
> 	(fndecl_built_in_p): Same.
> 	* unique-ptr-tests.cc: Same.
> 	* var-tracking.c (delete_variable_part): Same.
> 	* varasm.c (assemble_real): Same.
> 	(tree_output_constant_def): Same.
> 	* vec.c: Same.
> 	* wide-int-bitmask.h: Same.
> 	* wide-int.h (decompose): Same.
>
> libcpp/ChangeLog:
>
> 	* include/line-map.h: Change class-key from class to struct and vice
> 	versa to match convention and avoid -Wclass-is-pod and -Wstruct-no-pod.
> 	* mkdeps.c: Same.yyy

s/yyy// :-)

The changelog format is outdoing itself in usefulness here...

> diff --git a/gcc/cgraph.h b/gcc/cgraph.h
> index 18839a4a5ec..ca2a34afbae 100644
> --- a/gcc/cgraph.h
> +++ b/gcc/cgraph.h
> @@ -100,7 +100,7 @@ enum symbol_partitioning_class
>  
>  /* Base of all entries in the symbol table.
>     The symtab_node is inherited by cgraph and varpol nodes.  */
> -class GTY((desc ("%h.type"), tag ("SYMTAB_SYMBOL"),
> +struct GTY((desc ("%h.type"), tag ("SYMTAB_SYMBOL"),
>  	   chain_next ("%h.next"), chain_prev ("%h.previous")))
>    symtab_node

Second line should get an extra space of indentation.

> @@ -1673,8 +1675,10 @@ struct GTY(()) cgraph_indirect_call_info
>    unsigned vptr_changed : 1;
>  };
>  
> -struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
> -	    for_user)) cgraph_edge {
> +class GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
> +	    for_user)) cgraph_edge

Similarly one fewer space here.

> diff --git a/gcc/gcc.c b/gcc/gcc.c
> index 9bd65508b00..9f73ce0e47f 100644
> --- a/gcc/gcc.c
> +++ b/gcc/gcc.c
> @@ -57,7 +57,7 @@ compilation is specified by a string called a "spec".  */
>       getenv ();
>     Hence we need to use "get" for the accessor method, not "getenv".  */
> 
> -class env_manager
> +struct env_manager
>  {
>   public:
>    void init (bool can_restore, bool debug);
> @@ -8574,7 +8574,7 @@ static int n_mdswitches;
>  /* Check whether a particular argument was used.  The first time we
>     canonicalize the switches to keep only the ones we care about.  */
> 
> -class used_arg_t
> +struct used_arg_t
>  {
>   public:
>    int operator () (const char *p, int len);
> diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
> index b6e781f7450..e62a9a03ef9 100644
> --- a/gcc/ipa-cp.c
> +++ b/gcc/ipa-cp.c
> @@ -130,7 +130,7 @@ template <typename valtype> class ipcp_value;
>  /* Describes a particular source for an IPA-CP value.  */
> 
>  template <typename valtype>
> -class ipcp_value_source
> +struct ipcp_value_source
>  {
>  public:
>    /* Aggregate offset of the source, negative if the source is scalar value of
> @@ -209,7 +209,7 @@ public:
>     contains_variable flag should be disregarded.  */
> 
>  template <typename valtype>
> -class ipcp_lattice
> +struct ipcp_lattice
>  {
>  public:
>    /* The list of known values and types in this lattice.  Note that values are
> @@ -236,7 +236,7 @@ public:
>  /* Lattice of tree values with an offset to describe a part of an
>     aggregate.  */
> 
> -class ipcp_agg_lattice : public ipcp_lattice<tree>
> +struct ipcp_agg_lattice : public ipcp_lattice<tree>
>  {
>  public:
>    /* Offset that is being described by this lattice. */
> diff --git a/gcc/poly-int.h b/gcc/poly-int.h
> index d68a652b5fa..635f1ebeef6 100644
> --- a/gcc/poly-int.h
> +++ b/gcc/poly-int.h
> @@ -335,7 +335,7 @@ struct poly_result<T1, T2, 2>
>  /* A base POD class for polynomial integers.  The polynomial has N
>     coefficients of type C.  */
>  template<unsigned int N, typename C>
> -class poly_int_pod
> +struct poly_int_pod
>  {
>  public:
>    template<typename Ca>
> diff --git a/gcc/profile-count.h b/gcc/profile-count.h
> index cbab5965ed6..e584aab641f 100644
> --- a/gcc/profile-count.h
> +++ b/gcc/profile-count.h
> @@ -676,7 +676,7 @@ public:
>  
>  class sreal;
>  
> -class GTY(()) profile_count
> +struct GTY(()) profile_count
>  {
>  public:
>    /* Use 62bit to hold basic block counters.  Should be at least
> diff --git a/gcc/rtl.h b/gcc/rtl.h
> index 31fba823435..fc1a66416cc 100644
> --- a/gcc/rtl.h
> +++ b/gcc/rtl.h
> @@ -589,7 +594,7 @@ class GTY(()) rtx_nonjump_insn : public rtx_insn
>       from rtl.def.  */
>  };
> 
> -class GTY(()) rtx_jump_insn : public rtx_insn
> +struct GTY(()) rtx_jump_insn : public rtx_insn
>  {
>  public:
>    /* No extra fields, but adds the invariant:
> @@ -533,7 +538,7 @@ is_a_helper <const rtx_sequence *>::test (const_rtx rt)
>    return rt->code == SEQUENCE;
>  }
> 
> -class GTY(()) rtx_insn : public rtx_def
> +struct GTY(()) rtx_insn : public rtx_def
>  {
>  public:
>    /* No extra fields, but adds the invariant:

Might as well get rid of these "public:"s too, unless you feel they
should be kept.

OK with those changes (or without the last one), thanks.

Richard
Martin Sebor July 9, 2019, 4:37 p.m. UTC | #3
On 7/9/19 7:48 AM, Richard Sandiford wrote:
> Martin Sebor <msebor@gmail.com> writes:
>> Hopefully with the right patch this time (thanks Jon).
>>
>> On 7/8/19 4:00 PM, Martin Sebor wrote:
>>> The attached patch changes the class-key of class definitions that
>>> satisfy the requirements on a POD struct to 'struct', and that of
>>> struct definitions that aren't POD to class, according to the GCC
>>> coding convention.  The patch is also prerequisite for GCC being
>>> able to compile cleanly with -Wmismatched-tags.
>>>
>>> I made the changes building GCC with -Wstruct-not-pod and
>>> -Wclass-is-pod enabled, scanning the build log for instances
>>> of each warning, and using a script replacing the class-key
>>> as necessary and adjusting the access of the members declared
>>> immediately after the class-head.
>>>
>>> Martin
>>
>> PR c++/61339 - add mismatch between struct and class [-Wmismatched-tags] to non-bugs
>>
...
>> gcc/lto/ChangeLog:
>>
>> 	* lto-dump.c: Same.
> 
> Need to cut-&-paste the description for this one.

Done.

...
>>
>> libcpp/ChangeLog:
>>
>> 	* include/line-map.h: Change class-key from class to struct and vice
>> 	versa to match convention and avoid -Wclass-is-pod and -Wstruct-no-pod.
>> 	* mkdeps.c: Same.yyy
> 
> s/yyy// :-)

Ditto.

> 
> The changelog format is outdoing itself in usefulness here...
> 
>> diff --git a/gcc/cgraph.h b/gcc/cgraph.h
>> index 18839a4a5ec..ca2a34afbae 100644
>> --- a/gcc/cgraph.h
>> +++ b/gcc/cgraph.h
>> @@ -100,7 +100,7 @@ enum symbol_partitioning_class
>>   
>>   /* Base of all entries in the symbol table.
>>      The symtab_node is inherited by cgraph and varpol nodes.  */
>> -class GTY((desc ("%h.type"), tag ("SYMTAB_SYMBOL"),
>> +struct GTY((desc ("%h.type"), tag ("SYMTAB_SYMBOL"),
>>   	   chain_next ("%h.next"), chain_prev ("%h.previous")))
>>     symtab_node
> 
> Second line should get an extra space of indentation.
> 
>> @@ -1673,8 +1675,10 @@ struct GTY(()) cgraph_indirect_call_info
>>     unsigned vptr_changed : 1;
>>   };
>>   
>> -struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
>> -	    for_user)) cgraph_edge {
>> +class GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
>> +	    for_user)) cgraph_edge
> 
> Similarly one fewer space here.

Done.  My simple script handles just one space issue but not this
one.

...
>> diff --git a/gcc/rtl.h b/gcc/rtl.h
>> index 31fba823435..fc1a66416cc 100644
>> --- a/gcc/rtl.h
>> +++ b/gcc/rtl.h
>> @@ -589,7 +594,7 @@ class GTY(()) rtx_nonjump_insn : public rtx_insn
>>        from rtl.def.  */
>>   };
>>
>> -class GTY(()) rtx_jump_insn : public rtx_insn
>> +struct GTY(()) rtx_jump_insn : public rtx_insn
>>   {
>>   public:
>>     /* No extra fields, but adds the invariant:
>> @@ -533,7 +538,7 @@ is_a_helper <const rtx_sequence *>::test (const_rtx rt)
>>     return rt->code == SEQUENCE;
>>   }
>>
>> -class GTY(()) rtx_insn : public rtx_def
>> +struct GTY(()) rtx_insn : public rtx_def
>>   {
>>   public:
>>     /* No extra fields, but adds the invariant:
> 
> Might as well get rid of these "public:"s too, unless you feel they
> should be kept.

I think my script did that but gengtype choked on the struct when
it had no members so I had to put it back.  I'll try to remember
to reproduce it and open a bug for it.

> 
> OK with those changes (or without the last one), thanks.

Committed in r273308.

Martin
diff mbox series

Patch

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" }
+{ };
+}