Message ID | 05c26a42-d2ed-493c-441d-5325dafa6e53@gmail.com |
---|---|
State | New |
Headers | show |
Series | add support for POD struct convention (PR 61339) | expand |
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
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
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
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" } +{ }; +}