From 8d0d1915d9f96a4c9d9418b21b38cfa9c386d7a3 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 2 Jul 2012 15:14:23 -0400 Subject: [PATCH] re PR c++/53524 (Bogus enum comparison warning) PR c++/53524 gcc/cp/ * call.c (build_conditional_expr_1): Don't warn about comparison of two enumerators before their enumeration is complete. (build_new_op_1): Call decay_conversion before warn_logical_operator. * decl.c (build_enumerator): Set DECL_CONTEXT of an enumerator to its enumeration. * decl2.c (mark_used): Call used_types_insert for enums. * semantics.c (finish_id_expression): Don't decay CONST_DECL. (finish_member_declaration): Don't change DECL_CONTEXT of enumerators. * class.c (check_field_decls): Don't change DECL_CONTEXT of enums. * typeck.c (convert_for_assignment): Don't decay CONST_DECL. (build_class_member_access_expr): Look through unscoped enums. * search.c (context_for_name_lookup): Look through unscoped enums. * pt.c (tsubst_copy_and_build): Don't decay CONST_DECL. (tsubst_copy): Use DECL_CONTEXT to find the enumeration. * tree.c (decl_linkage): Likewise. * cvt.c (ocp_convert): Check decayed expr for enum range warning. gcc/c-family/ * c-common.c (get_priority): Call default_conversion. From-SVN: r189174 --- gcc/c-family/ChangeLog | 5 +++++ gcc/c-family/c-common.c | 3 ++- gcc/cp/ChangeLog | 20 +++++++++++++++++++ gcc/cp/call.c | 22 ++++++++++++++++----- gcc/cp/class.c | 3 ++- gcc/cp/cvt.c | 4 ++-- gcc/cp/decl.c | 2 +- gcc/cp/decl2.c | 4 ++++ gcc/cp/pt.c | 13 +----------- gcc/cp/search.c | 7 +++---- gcc/cp/semantics.c | 25 ++++++++++-------------- gcc/cp/tree.c | 2 +- gcc/cp/typeck.c | 6 +----- gcc/testsuite/ChangeLog | 8 ++++++++ gcc/testsuite/g++.dg/cpp0x/scoped_enum.C | 2 +- gcc/testsuite/g++.dg/other/ptrmem10.C | 5 ++--- gcc/testsuite/g++.dg/other/ptrmem11.C | 5 ++--- gcc/testsuite/g++.dg/template/enum7.C | 8 ++++++++ 18 files changed, 90 insertions(+), 54 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/enum7.C diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index e19e703ddeb..8b7c4b789b1 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2012-07-02 Jason Merrill + + PR c++/53524 + * c-common.c (get_priority): Call default_conversion. + 2012-07-01 Uros Bizjak * c-pch.c (c_common_write_pch): Remove unused variables. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 61d756760e3..2a528e22ff9 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -6587,11 +6587,12 @@ get_priority (tree args, bool is_destructor) } arg = TREE_VALUE (args); + arg = default_conversion (arg); if (!host_integerp (arg, /*pos=*/0) || !INTEGRAL_TYPE_P (TREE_TYPE (arg))) goto invalid; - pri = tree_low_cst (TREE_VALUE (args), /*pos=*/0); + pri = tree_low_cst (arg, /*pos=*/0); if (pri < 0 || pri > MAX_INIT_PRIORITY) goto invalid; diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9b5b7c163d6..448dd5caa8e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,23 @@ +2012-07-02 Jason Merrill + + PR c++/53524 + * call.c (build_conditional_expr_1): Don't warn about comparison of + two enumerators before their enumeration is complete. + (build_new_op_1): Call decay_conversion before warn_logical_operator. + * decl.c (build_enumerator): Set DECL_CONTEXT of an enumerator to + its enumeration. + * decl2.c (mark_used): Call used_types_insert for enums. + * semantics.c (finish_id_expression): Don't decay CONST_DECL. + (finish_member_declaration): Don't change DECL_CONTEXT of enumerators. + * class.c (check_field_decls): Don't change DECL_CONTEXT of enums. + * typeck.c (convert_for_assignment): Don't decay CONST_DECL. + (build_class_member_access_expr): Look through unscoped enums. + * search.c (context_for_name_lookup): Look through unscoped enums. + * pt.c (tsubst_copy_and_build): Don't decay CONST_DECL. + (tsubst_copy): Use DECL_CONTEXT to find the enumeration. + * tree.c (decl_linkage): Likewise. + * cvt.c (ocp_convert): Check decayed expr for enum range warning. + 2012-06-29 Steven Bosscher * Make-lang.in: Remove tree-mudflap.o from CXX_AND_OBJCXX_OBJS. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 09965b321cc..72394f4af60 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4365,6 +4365,7 @@ build_conditional_expr_1 (tree arg1, tree arg2, tree arg3, struct z_candidate *candidates = 0; struct z_candidate *cand; void *p; + tree orig_arg2, orig_arg3; /* As a G++ extension, the second argument to the conditional can be omitted. (So that `a ? : c' is roughly equivalent to `a ? a : @@ -4404,6 +4405,8 @@ build_conditional_expr_1 (tree arg1, tree arg2, tree arg3, array-to-pointer (_conv.array_), and function-to-pointer (_conv.func_) standard conversions are performed on the second and third operands. */ + orig_arg2 = arg2; + orig_arg3 = arg3; arg2_type = unlowered_expr_type (arg2); arg3_type = unlowered_expr_type (arg3); if (VOID_TYPE_P (arg2_type) || VOID_TYPE_P (arg3_type)) @@ -4701,7 +4704,12 @@ build_conditional_expr_1 (tree arg1, tree arg2, tree arg3, if (TREE_CODE (arg2_type) == ENUMERAL_TYPE && TREE_CODE (arg3_type) == ENUMERAL_TYPE) { - if (complain & tf_warning) + if (TREE_CODE (orig_arg2) == CONST_DECL + && TREE_CODE (orig_arg3) == CONST_DECL + && DECL_CONTEXT (orig_arg2) == DECL_CONTEXT (orig_arg3)) + /* Two enumerators from the same enumeration can have different + types when the enumeration is still being defined. */; + else if (complain & tf_warning) warning (OPT_Wenum_compare, "enumeral mismatch in conditional expression: %qT vs %qT", arg2_type, arg3_type); @@ -5221,16 +5229,20 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1, if (arg2) { + conv = cand->convs[1]; + if (conv->kind == ck_ref_bind) + conv = next_conversion (conv); + else + arg2 = decay_conversion (arg2, complain); + /* We need to call warn_logical_operator before - converting arg2 to a boolean_type. */ + converting arg2 to a boolean_type, but after + decaying an enumerator to its value. */ if (complain & tf_warning) warn_logical_operator (loc, code, boolean_type_node, code_orig_arg1, arg1, code_orig_arg2, arg2); - conv = cand->convs[1]; - if (conv->kind == ck_ref_bind) - conv = next_conversion (conv); arg2 = convert_like (conv, arg2, complain); } if (arg3) diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 6307e847a40..264258c1dbc 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3114,7 +3114,8 @@ check_field_decls (tree t, tree *access_decls, /* If we've gotten this far, it's a data member, possibly static, or an enumerator. */ - DECL_CONTEXT (x) = t; + if (TREE_CODE (x) != CONST_DECL) + DECL_CONTEXT (x) = t; /* When this goes into scope, it will be a non-local reference. */ DECL_NONLOCAL (x) = 1; diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 998d4eb345e..9550f1580bb 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -741,8 +741,8 @@ ocp_convert (tree type, tree expr, int convtype, int flags, values. Otherwise, the resulting enumeration value is unspecified. */ if ((complain & tf_warning) - && TREE_CODE (expr) == INTEGER_CST - && !int_fits_type_p (expr, ENUM_UNDERLYING_TYPE (type))) + && TREE_CODE (e) == INTEGER_CST + && !int_fits_type_p (e, ENUM_UNDERLYING_TYPE (type))) warning_at (loc, OPT_Wconversion, "the result of the conversion is unspecified because " "%qE is outside the range of type %qT", diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index ab560199ced..18beaa9fc56 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -12570,7 +12570,7 @@ incremented enumerator value is too large for %"); a function could mean local to a class method. */ decl = build_decl (loc, CONST_DECL, name, type); - DECL_CONTEXT (decl) = FROB_CONTEXT (context); + DECL_CONTEXT (decl) = enumtype; TREE_CONSTANT (decl) = 1; TREE_READONLY (decl) = 1; DECL_INITIAL (decl) = value; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index d8c72606f2e..cbb1053b6ed 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -4205,6 +4205,10 @@ mark_used (tree decl) if (DECL_CLONED_FUNCTION_P (decl)) TREE_USED (DECL_CLONED_FUNCTION (decl)) = 1; + /* Mark enumeration types as used. */ + if (TREE_CODE (decl) == CONST_DECL) + used_types_insert (DECL_CONTEXT (decl)); + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DELETED_FN (decl)) { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7e1c46f77c3..f8f416a3b9e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12128,7 +12128,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) When we instantiate f<7>::S::g(), say, lookup_name is not clever enough to find f<7>::a. */ enum_type - = tsubst_aggr_type (TREE_TYPE (t), args, complain, in_decl, + = tsubst_aggr_type (DECL_CONTEXT (t), args, complain, in_decl, /*entering_scope=*/0); for (v = TYPE_VALUES (enum_type); @@ -14385,17 +14385,6 @@ tsubst_copy_and_build (tree t, return stmt_expr; } - case CONST_DECL: - t = tsubst_copy (t, args, complain, in_decl); - /* As in finish_id_expression, we resolve enumeration constants - to their underlying values. */ - if (TREE_CODE (t) == CONST_DECL && !processing_template_decl) - { - used_types_insert (TREE_TYPE (t)); - return DECL_INITIAL (t); - } - return t; - case LAMBDA_EXPR: { tree r = build_lambda_expr (); diff --git a/gcc/cp/search.c b/gcc/cp/search.c index e6d6be814c6..d112c05713c 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -579,7 +579,8 @@ context_for_name_lookup (tree decl) declared. */ tree context = DECL_CONTEXT (decl); - while (context && TYPE_P (context) && ANON_AGGR_TYPE_P (context)) + while (context && TYPE_P (context) + && (ANON_AGGR_TYPE_P (context) || UNSCOPED_ENUM_P (context))) context = TYPE_CONTEXT (context); if (!context) context = global_namespace; @@ -623,9 +624,7 @@ dfs_access_in_type (tree binfo, void *data) else { /* First, check for an access-declaration that gives us more - access to the DECL. The CONST_DECL for an enumeration - constant will not have DECL_LANG_SPECIFIC, and thus no - DECL_ACCESS. */ + access to the DECL. */ if (DECL_LANG_SPECIFIC (decl) && !DECL_DISCRIMINATOR_P (decl)) { tree decl_access = purpose_member (type, DECL_ACCESS (decl)); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index d45a6e2cb10..f1a94c11872 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2631,8 +2631,10 @@ finish_member_declaration (tree decl) TREE_PROTECTED (DECL_TEMPLATE_RESULT (decl)) = TREE_PROTECTED (decl); } - /* Mark the DECL as a member of the current class. */ - DECL_CONTEXT (decl) = current_class_type; + /* Mark the DECL as a member of the current class, unless it's + a member of an enumeration. */ + if (TREE_CODE (decl) != CONST_DECL) + DECL_CONTEXT (decl) = current_class_type; /* Check for bare parameter packs in the member variable declaration. */ if (TREE_CODE (decl) == FIELD_DECL) @@ -3060,18 +3062,6 @@ finish_id_expression (tree id_expression, } return r; } - /* Similarly, we resolve enumeration constants to their - underlying values. */ - else if (TREE_CODE (decl) == CONST_DECL) - { - *idk = CP_ID_KIND_NONE; - if (!processing_template_decl) - { - used_types_insert (TREE_TYPE (decl)); - return DECL_INITIAL (decl); - } - return decl; - } else { bool dependent_p; @@ -3100,6 +3090,9 @@ finish_id_expression (tree id_expression, if (!processing_template_decl) /* No names are dependent outside a template. */ ; + else if (TREE_CODE (decl) == CONST_DECL) + /* We don't want to treat enumerators as dependent. */ + ; /* A template-id where the name of the template was not resolved is definitely dependent. */ else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR @@ -3234,15 +3227,17 @@ finish_id_expression (tree id_expression, marked either below or after overload resolution. */ if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == CONST_DECL || TREE_CODE (decl) == RESULT_DECL) mark_used (decl); /* Only certain kinds of names are allowed in constant - expression. Enumerators and template parameters have already + expression. Template parameters have already been handled above. */ if (! error_operand_p (decl) && integral_constant_expression_p && ! decl_constant_var_p (decl) + && TREE_CODE (decl) != CONST_DECL && ! builtin_valid_in_constant_expr_p (decl)) { if (!allow_non_integral_constant_expression_p) diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 2b541cd5bd5..a03f8459da8 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3212,7 +3212,7 @@ decl_linkage (tree decl) /* Linkage of a CONST_DECL depends on the linkage of the enumeration type. */ if (TREE_CODE (decl) == CONST_DECL) - return decl_linkage (TYPE_NAME (TREE_TYPE (decl))); + return decl_linkage (TYPE_NAME (DECL_CONTEXT (decl))); /* Some things that are not TREE_PUBLIC have external linkage, too. For example, on targets that don't have weak symbols, we make all diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 971f386e56f..3bc3ead187a 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2199,7 +2199,7 @@ build_class_member_access_expr (tree object, tree member, /* If MEMBER is from an anonymous aggregate, MEMBER_SCOPE will presently be the anonymous union. Go outwards until we find a type related to OBJECT_TYPE. */ - while (ANON_AGGR_TYPE_P (member_scope) + while ((ANON_AGGR_TYPE_P (member_scope) || UNSCOPED_ENUM_P (member_scope)) && !same_type_ignoring_top_level_qualifiers_p (member_scope, object_type)) member_scope = TYPE_CONTEXT (member_scope); @@ -7582,10 +7582,6 @@ convert_for_assignment (tree type, tree rhs, return error_mark_node; } - /* Simplify the RHS if possible. */ - if (TREE_CODE (rhs) == CONST_DECL) - rhs = DECL_INITIAL (rhs); - if (c_dialect_objc ()) { int parmno; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 066eb5c2095..5d5a2ce4cf8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2012-07-02 Jason Merrill + + PR c++/53524 + * g++.dg/template/enum7.C: New. + * g++.dg/other/ptrmem10.C: Adjust. + * g++.dg/other/ptrmem11.C: Adjust. + * g++.dg/cpp0x/scoped_enum.C: Adjust. + 2012-07-02 Steven Bosscher * gcc.dg/tree-ssa/pr36881.c: Fix test case to not expand as bit tests. diff --git a/gcc/testsuite/g++.dg/cpp0x/scoped_enum.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum.C index c52a3fe769e..4b0317cfbe0 100644 --- a/gcc/testsuite/g++.dg/cpp0x/scoped_enum.C +++ b/gcc/testsuite/g++.dg/cpp0x/scoped_enum.C @@ -13,7 +13,7 @@ enum struct Color2 { Blue, Indigo = Green + 2, Violet, - Red // { dg-error "redefinition" } + Red // { dg-error "redeclaration" } }; enum Color { diff --git a/gcc/testsuite/g++.dg/other/ptrmem10.C b/gcc/testsuite/g++.dg/other/ptrmem10.C index a17df7fb362..ff8c8434115 100644 --- a/gcc/testsuite/g++.dg/other/ptrmem10.C +++ b/gcc/testsuite/g++.dg/other/ptrmem10.C @@ -3,7 +3,7 @@ template static -void foo(void *obj) // { dg-message "note" } +void foo(void *obj) { C *p = static_cast(obj); (p->*M)(); @@ -13,8 +13,7 @@ template static void bar(C *c, void (C::*m) ()) { - foo((void *)c);// { dg-error "(not a valid template arg|pointer-to-member|no matching fun|could not convert)" } - // { dg-message "candidate" "candidate note" { target *-*-* } 16 } + foo((void *)c);// { dg-error "(not a valid template arg|pointer-to-member|no matching fun|could not convert|constant)" } } struct S diff --git a/gcc/testsuite/g++.dg/other/ptrmem11.C b/gcc/testsuite/g++.dg/other/ptrmem11.C index e73164eef26..e18abddd677 100644 --- a/gcc/testsuite/g++.dg/other/ptrmem11.C +++ b/gcc/testsuite/g++.dg/other/ptrmem11.C @@ -5,7 +5,7 @@ struct A {}; template int -foo(A* q) // { dg-message "note" } +foo(A* q) { return q->*p; } @@ -14,8 +14,7 @@ template int bar(int T::* p) { - return foo

(0);// { dg-error "(not a valid template arg|no matching func|pointer-to-member|could not convert)" } - // { dg-message "candidate" "candidate note" { target *-*-* } 17 } + return foo

(0);// { dg-error "(not a valid template arg|no matching func|pointer-to-member|could not convert|constant)" } } int i = bar(0); diff --git a/gcc/testsuite/g++.dg/template/enum7.C b/gcc/testsuite/g++.dg/template/enum7.C new file mode 100644 index 00000000000..8c464a795d8 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/enum7.C @@ -0,0 +1,8 @@ +// PR c++/53524 + +template struct A { enum EA { ea }; }; +template struct B { + enum EB { eb1 = A::ea, eb2 = A::ea, eb3 = 0 ? eb1 : eb2 }; +}; + +B b;