diff options
author | Mark Mitchell <mmitchel@gcc.gnu.org> | 2003-07-29 01:14:24 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2003-07-29 01:14:24 +0000 |
commit | 7b6d72fcfbd0aa2bb05d81afcdcf5e4c6027b2e8 (patch) | |
tree | aa422656fa001e4c76605059943c273de869706a /gcc/cp | |
parent | 92a6fb2cf25c126727e85b8d90718ec4cf136cfa (diff) | |
download | gcc-7b6d72fcfbd0aa2bb05d81afcdcf5e4c6027b2e8.zip gcc-7b6d72fcfbd0aa2bb05d81afcdcf5e4c6027b2e8.tar.gz gcc-7b6d72fcfbd0aa2bb05d81afcdcf5e4c6027b2e8.tar.bz2 |
re PR c++/11667 (wider-than-int enums never compare equal to 0)
PR c++/11667
* c-common.c (shorten_compare): Take into account differences
between C and C++ representation for enumeration types.
* tree.h (set_min_and_max_values_for_integral_type): Declare.
* stor-layout.c (set_min_and_max_values_for_integral_type): New
function, broken out from ...
(fixup_signed_type): ... here and ...
(fixup_unsigned_type): ... here.
PR c++/11667
* call.c (standard_conversion): Allow all integral->enumeral
conversions, after marking them as bad.
* decl.c (finish_enum): Make sure that all enumerators are
properly converted to the underlying type.
(build_enumerator): Set DECL_CONTEXT for namespace-scope
enumeration types.
* pt.c (tsubst_copy): Adjust handling of CONST_DECLs accordingly.
(tsubst_enum): Tidy.
* Make-lang.in (typeck.o): Depend on convert.h.
(class.o): Likewise.
(rtti.o): Likewise.
* call.c: Include convert.h.
(convert_arg_to_ellipsis): Use convert_to_real.
* class.c: Include convert.h.
(build_base_path): Use convert_to_integer.
* rtti.c: Include convert.h.
(build_headof): Use convert_to_integer.
* typeck.c: Include convert.h.
(decay_conversion): Use convert_to_integer.
(build_unary_op): Use build_nop.
(get_delta_difference): Use convert_to_integer.
(build_ptrmemfunc): Avoid unncessary conversions.
From-SVN: r69909
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 27 | ||||
-rw-r--r-- | gcc/cp/Make-lang.in | 8 | ||||
-rw-r--r-- | gcc/cp/call.c | 6 | ||||
-rw-r--r-- | gcc/cp/class.c | 6 | ||||
-rw-r--r-- | gcc/cp/decl.c | 120 | ||||
-rw-r--r-- | gcc/cp/pt.c | 15 | ||||
-rw-r--r-- | gcc/cp/rtti.c | 5 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 74 |
8 files changed, 164 insertions, 97 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index abbe9cc..64068a2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,30 @@ +2003-07-28 Mark Mitchell <mark@codesourcery.com> + + PR c++/11667 + * call.c (standard_conversion): Allow all integral->enumeral + conversions, after marking them as bad. + * decl.c (finish_enum): Make sure that all enumerators are + properly converted to the underlying type. + (build_enumerator): Set DECL_CONTEXT for namespace-scope + enumeration types. + * pt.c (tsubst_copy): Adjust handling of CONST_DECLs accordingly. + (tsubst_enum): Tidy. + + * Make-lang.in (typeck.o): Depend on convert.h. + (class.o): Likewise. + (rtti.o): Likewise. + * call.c: Include convert.h. + (convert_arg_to_ellipsis): Use convert_to_real. + * class.c: Include convert.h. + (build_base_path): Use convert_to_integer. + * rtti.c: Include convert.h. + (build_headof): Use convert_to_integer. + * typeck.c: Include convert.h. + (decay_conversion): Use convert_to_integer. + (build_unary_op): Use build_nop. + (get_delta_difference): Use convert_to_integer. + (build_ptrmemfunc): Avoid unncessary conversions. + Mon Jul 28 23:55:10 CEST 2003 Jan Hubicka <jh@suse.cz> * decl2.c (mark_member_pointers): Verify that member pointer points to diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index d16a5bc..05a3a8c 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -244,10 +244,10 @@ cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) flags.h cp/lex.h cp/decl.h $(EXPR_H cp/typeck2.o: cp/typeck2.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h output.h $(TM_P_H) \ diagnostic.h cp/typeck.o: cp/typeck.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) $(EXPR_H) toplev.h \ - diagnostic.h -cp/class.o: cp/class.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h $(RTL_H) $(TARGET_H) + diagnostic.h convert.h +cp/class.o: cp/class.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h $(RTL_H) $(TARGET_H) convert.h cp/call.o: cp/call.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h $(RTL_H) $(EXPR_H) \ - diagnostic.h intl.h gt-cp-call.h + diagnostic.h intl.h gt-cp-call.h convert.h cp/friend.o: cp/friend.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) toplev.h $(EXPR_H) cp/init.o: cp/init.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) $(EXPR_H) toplev.h \ except.h @@ -258,7 +258,7 @@ cp/search.o: cp/search.c $(CXX_TREE_H) $(TM_H) stack.h flags.h toplev.h $(RTL_H) cp/tree.o: cp/tree.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h $(RTL_H) \ insn-config.h integrate.h tree-inline.h real.h gt-cp-tree.h $(TARGET_H) cp/ptree.o: cp/ptree.c $(CXX_TREE_H) $(TM_H) -cp/rtti.o: cp/rtti.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h +cp/rtti.o: cp/rtti.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h convert.h cp/except.o: cp/except.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) except.h toplev.h \ cp/cfns.h $(EXPR_H) libfuncs.h tree-inline.h cp/expr.o: cp/expr.c $(CXX_TREE_H) $(TM_H) $(RTL_H) flags.h $(EXPR_H) toplev.h \ diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 7e3302f..e8b2902 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -37,6 +37,7 @@ Boston, MA 02111-1307, USA. */ #include "expr.h" #include "diagnostic.h" #include "intl.h" +#include "convert.h" static tree build_field_call (tree, tree, tree); static struct z_candidate * tourney (struct z_candidate *); @@ -653,8 +654,7 @@ standard_conversion (tree to, tree from, tree expr) conv = build_conv (STD_CONV, to, conv); ICS_BAD_FLAG (conv) = 1; } - else if (tcode == ENUMERAL_TYPE && fcode == INTEGER_TYPE - && TYPE_PRECISION (to) == TYPE_PRECISION (from)) + else if (tcode == ENUMERAL_TYPE && fcode == INTEGER_TYPE) { /* For backwards brain damage compatibility, allow interconversion of enums and integers with a pedwarn. */ @@ -4201,7 +4201,7 @@ convert_arg_to_ellipsis (tree arg) if (TREE_CODE (TREE_TYPE (arg)) == REAL_TYPE && (TYPE_PRECISION (TREE_TYPE (arg)) < TYPE_PRECISION (double_type_node))) - arg = cp_convert (double_type_node, arg); + arg = convert_to_real (double_type_node, arg); else if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (arg))) arg = perform_integral_promotions (arg); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index d2fb902..b447f70 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -35,6 +35,7 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #include "lex.h" #include "target.h" +#include "convert.h" /* The number of nested classes being processed. If we are not in the scope of any class, this is zero. */ @@ -328,8 +329,9 @@ build_base_path (enum tree_code code, v_offset = build_indirect_ref (v_offset, NULL); TREE_CONSTANT (v_offset) = 1; - offset = cp_convert (ptrdiff_type_node, - size_diffop (offset, BINFO_OFFSET (v_binfo))); + offset = convert_to_integer (ptrdiff_type_node, + size_diffop (offset, + BINFO_OFFSET (v_binfo))); if (!integer_zerop (offset)) v_offset = build (code, ptrdiff_type_node, v_offset, offset); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 4e6da3f..583b874 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13028,7 +13028,9 @@ start_enum (tree name) void finish_enum (tree enumtype) { - tree pair; + tree values; + tree decl; + tree value; tree minnode; tree maxnode; tree t; @@ -13036,6 +13038,8 @@ finish_enum (tree enumtype) int lowprec; int highprec; int precision; + integer_type_kind itk; + tree underlying_type; /* We built up the VALUES in reverse order. */ TYPE_VALUES (enumtype) = nreverse (TYPE_VALUES (enumtype)); @@ -13046,21 +13050,25 @@ finish_enum (tree enumtype) works. */ if (processing_template_decl) { - for (pair = TYPE_VALUES (enumtype); pair; pair = TREE_CHAIN (pair)) - TREE_TYPE (TREE_VALUE (pair)) = enumtype; + for (values = TYPE_VALUES (enumtype); + values; + values = TREE_CHAIN (values)) + TREE_TYPE (TREE_VALUE (values)) = enumtype; if (at_function_scope_p ()) add_stmt (build_min (TAG_DEFN, enumtype)); return; } + /* Determine the minimum and maximum values of the enumerators. */ if (TYPE_VALUES (enumtype)) { minnode = maxnode = NULL_TREE; - for (pair = TYPE_VALUES (enumtype); pair; pair = TREE_CHAIN (pair)) + for (values = TYPE_VALUES (enumtype); + values; + values = TREE_CHAIN (values)) { - tree decl = TREE_VALUE (pair); - tree value = DECL_INITIAL (decl); + decl = TREE_VALUE (values); /* [dcl.enum]: Following the closing brace of an enum-specifier, each enumerator has the type of its enumeration. Prior to the @@ -13068,6 +13076,8 @@ finish_enum (tree enumtype) initializing value. */ TREE_TYPE (decl) = enumtype; + /* Update the minimum and maximum values, if appropriate. */ + value = DECL_INITIAL (decl); /* Figure out what the minimum and maximum values of the enumerators are. */ if (!minnode) @@ -13086,13 +13096,13 @@ finish_enum (tree enumtype) value = DECL_INITIAL (decl) = copy_node (value); TREE_TYPE (value) = enumtype; } - - /* In addition, transform the TYPE_VALUES list to contain the - values, rather than the CONST_DECLs for them. */ - TREE_VALUE (pair) = value; } } else + /* [dcl.enum] + + If the enumerator-list is empty, the underlying type is as if + the enumeration had a single enumerator with value 0. */ minnode = maxnode = integer_zero_node; /* Compute the number of bits require to represent all values of the @@ -13104,35 +13114,75 @@ finish_enum (tree enumtype) highprec = min_precision (maxnode, unsignedp); precision = MAX (lowprec, highprec); - /* DR 377 - - IF no integral type can represent all the enumerator values, the - enumeration is ill-formed. */ - if (precision > TYPE_PRECISION (long_long_integer_type_node)) + /* Determine the underlying type of the enumeration. + + [dcl.enum] + + The underlying type of an enumeration is an integral type that + can represent all the enumerator values defined in the + enumeration. It is implementation-defined which integral type is + used as the underlying type for an enumeration except that the + underlying type shall not be larger than int unless the value of + an enumerator cannot fit in an int or unsigned int. + + We use "int" or an "unsigned int" as the underlying type, even if + a smaller integral type would work, unless the user has + explicitly requested that we use the smallest possible type. */ + for (itk = (flag_short_enums ? itk_char : itk_int); + itk != itk_none; + itk++) { + underlying_type = integer_types[itk]; + if (TYPE_PRECISION (underlying_type) >= precision + && TREE_UNSIGNED (underlying_type) == unsignedp) + break; + } + if (itk == itk_none) + { + /* DR 377 + + IF no integral type can represent all the enumerator values, the + enumeration is ill-formed. */ error ("no integral type can represent all of the enumerator values " "for `%T'", enumtype); precision = TYPE_PRECISION (long_long_integer_type_node); + underlying_type = integer_types[itk_unsigned_long_long]; } - /* Compute the minium and maximum values for the type, the size of - the type, and so forth. */ - TYPE_PRECISION (enumtype) = precision; - TYPE_SIZE (enumtype) = NULL_TREE; - if (unsignedp) - fixup_unsigned_type (enumtype); - else - fixup_signed_type (enumtype); + /* Compute the minium and maximum values for the type. - /* We use "int" or "unsigned int" as the underlying type, unless all - the values will not fit or the user has requested that we try to - use shorter types where possible. */ - if (precision < TYPE_PRECISION (integer_type_node) - && !flag_short_enums) - { - TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node); - TYPE_SIZE (enumtype) = NULL_TREE; - layout_type (enumtype); + [dcl.enum] + + For an enumeration where emin is the smallest enumerator and emax + is the largest, the values of the enumeration are the values of the + underlying type in the range bmin to bmax, where bmin and bmax are, + respectively, the smallest and largest values of the smallest bit- + field that can store emin and emax. */ + TYPE_PRECISION (enumtype) = precision; + set_min_and_max_values_for_integral_type (enumtype, precision, unsignedp); + + /* [dcl.enum] + + The value of sizeof() applied to an enumeration type, an object + of an enumeration type, or an enumerator, is the value of sizeof() + applied to the underlying type. */ + TYPE_SIZE (enumtype) = TYPE_SIZE (underlying_type); + TYPE_SIZE_UNIT (enumtype) = TYPE_SIZE_UNIT (underlying_type); + TYPE_MODE (enumtype) = TYPE_MODE (underlying_type); + TYPE_ALIGN (enumtype) = TYPE_ALIGN (underlying_type); + TYPE_USER_ALIGN (enumtype) = TYPE_USER_ALIGN (underlying_type); + TREE_UNSIGNED (enumtype) = TREE_UNSIGNED (underlying_type); + + /* Convert each of the enumerators to the type of the underlying + type of the enumeration. */ + for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN (values)) + { + decl = TREE_VALUE (values); + value = perform_implicit_conversion (underlying_type, + DECL_INITIAL (decl)); + TREE_TYPE (value) = enumtype; + DECL_INITIAL (decl) = value; + TREE_VALUE (values) = value; } /* Fix up all variant types of this enum type. */ @@ -13215,6 +13265,8 @@ build_enumerator (tree name, tree value, tree enumtype) /* C++ associates enums with global, function, or class declarations. */ context = current_scope (); + if (!context) + context = current_namespace; /* Build the actual enumeration constant. Note that the enumeration constants have the type of their initializers until the @@ -13246,8 +13298,8 @@ build_enumerator (tree name, tree value, tree enumtype) if (context && context == current_class_type) /* In something like `struct S { enum E { i = 7 }; };' we put `i' - on the TYPE_FIELDS list for `S'. (That's so that you can say - things like `S::i' later.) */ + on the TYPE_FIELDS list for `S'. (That's so that you can say + things like `S::i' later.) */ finish_member_declaration (decl); else pushdecl (decl); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 31bde1a..8f10de4 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -7214,8 +7214,9 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (DECL_TEMPLATE_PARM_P (t)) return tsubst_copy (DECL_INITIAL (t), args, complain, in_decl); - if (!DECL_CONTEXT (t)) - /* This is a global enumeration constant. */ + /* There is no need to substitute into namespace-scope + enumerators. */ + if (DECL_NAMESPACE_SCOPE_P (t)) return t; /* Unfortunately, we cannot just call lookup_name here. @@ -11151,18 +11152,20 @@ tsubst_enum (tree tag, tree newtag, tree args) for (e = TYPE_VALUES (tag); e; e = TREE_CHAIN (e)) { tree value; - + tree decl; + + decl = TREE_VALUE (e); /* Note that in a template enum, the TREE_VALUE is the CONST_DECL, not the corresponding INTEGER_CST. */ - value = tsubst_expr (DECL_INITIAL (TREE_VALUE (e)), + value = tsubst_expr (DECL_INITIAL (decl), args, tf_error | tf_warning, NULL_TREE); /* Give this enumeration constant the correct access. */ - set_current_access_from_decl (TREE_VALUE (e)); + set_current_access_from_decl (decl); /* Actually build the enumerator itself. */ - build_enumerator (TREE_PURPOSE (e), value, newtag); + build_enumerator (DECL_NAME (decl), value, newtag); } finish_enum (newtag); diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index fdad47d..baaff74 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -31,6 +31,7 @@ Boston, MA 02111-1307, USA. */ #include "output.h" #include "assert.h" #include "toplev.h" +#include "convert.h" /* C++ returns type information to the user in struct type_info objects. We also use type information to implement dynamic_cast and @@ -159,8 +160,8 @@ build_headof (tree exp) type = build_qualified_type (ptr_type_node, cp_type_quals (TREE_TYPE (exp))); - return build (PLUS_EXPR, type, exp, - cp_convert (ptrdiff_type_node, offset)); + return build (PLUS_EXPR, type, exp, + convert_to_integer (ptrdiff_type_node, offset)); } /* Get a bad_cast node for the program to throw... diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index ec6765b..00fa013 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -44,6 +44,7 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #include "diagnostic.h" #include "target.h" +#include "convert.h" static tree convert_for_assignment (tree, tree, const char *, tree, int); static tree cp_pointer_int_sum (enum tree_code, tree, tree); @@ -1291,20 +1292,8 @@ decay_conversion (tree exp) tree ptrtype; if (TREE_CODE (exp) == INDIRECT_REF) - { - /* Stripping away the INDIRECT_REF is not the right - thing to do for references... */ - tree inner = TREE_OPERAND (exp, 0); - if (TREE_CODE (TREE_TYPE (inner)) == REFERENCE_TYPE) - { - inner = build1 (CONVERT_EXPR, - build_pointer_type (TREE_TYPE - (TREE_TYPE (inner))), - inner); - TREE_CONSTANT (inner) = TREE_CONSTANT (TREE_OPERAND (inner, 0)); - } - return cp_convert (build_pointer_type (TREE_TYPE (type)), inner); - } + return build_nop (build_pointer_type (TREE_TYPE (type)), + TREE_OPERAND (exp, 0)); if (TREE_CODE (exp) == COMPOUND_EXPR) { @@ -4007,8 +3996,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) ba_check, NULL); rval = build_base_path (PLUS_EXPR, rval, binfo, 1); - rval = build1 (NOP_EXPR, argtype, rval); - TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0)); + rval = build_nop (argtype, rval); addr = fold (build (PLUS_EXPR, argtype, rval, cp_convert (argtype, byte_position (field)))); } @@ -5192,8 +5180,9 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs) /* Get difference in deltas for different pointer to member function - types. Return integer_zero_node, if FROM cannot be converted to a - TO type. If FORCE is true, then allow reverse conversions as well. + types. Returns an integer constant of type PTRDIFF_TYPE_NODE. If + the conversion is invalid, the constant is zero. If FORCE is true, + then allow reverse conversions as well. Note that the naming of FROM and TO is kind of backwards; the return value is what we add to a TO in order to get a FROM. They are named @@ -5203,7 +5192,6 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs) static tree get_delta_difference (tree from, tree to, int force) { - tree delta = integer_zero_node; tree binfo; tree virt_binfo; base_kind kind; @@ -5212,7 +5200,7 @@ get_delta_difference (tree from, tree to, int force) if (kind == bk_inaccessible || kind == bk_ambig) { error (" in pointer to member function conversion"); - return delta; + goto error; } if (!binfo) { @@ -5220,44 +5208,38 @@ get_delta_difference (tree from, tree to, int force) { error_not_base_type (from, to); error (" in pointer to member conversion"); - return delta; + goto error; } binfo = lookup_base (from, to, ba_check, &kind); - if (binfo == 0) - return delta; + if (!binfo) + goto error; virt_binfo = binfo_from_vbase (binfo); - if (virt_binfo) { /* This is a reinterpret cast, we choose to do nothing. */ warning ("pointer to member cast via virtual base `%T'", BINFO_TYPE (virt_binfo)); - return delta; + goto error; } - delta = BINFO_OFFSET (binfo); - delta = cp_convert (ptrdiff_type_node, delta); - delta = cp_build_binary_op (MINUS_EXPR, - integer_zero_node, - delta); - - return delta; + return convert_to_integer (ptrdiff_type_node, + size_diffop (size_zero_node, + BINFO_OFFSET (binfo))); } virt_binfo = binfo_from_vbase (binfo); - if (virt_binfo) - { - /* This is a reinterpret cast, we choose to do nothing. */ - if (force) - warning ("pointer to member cast via virtual base `%T'", - BINFO_TYPE (virt_binfo)); - else - error ("pointer to member conversion via virtual base `%T'", - BINFO_TYPE (virt_binfo)); - return delta; - } - delta = BINFO_OFFSET (binfo); + if (!virt_binfo) + return convert_to_integer (ptrdiff_type_node, BINFO_OFFSET (binfo)); + + /* This is a reinterpret cast, we choose to do nothing. */ + if (force) + warning ("pointer to member cast via virtual base `%T'", + BINFO_TYPE (virt_binfo)); + else + error ("pointer to member conversion via virtual base `%T'", + BINFO_TYPE (virt_binfo)); - return cp_convert (ptrdiff_type_node, delta); + error: + return convert_to_integer(ptrdiff_type_node, integer_zero_node); } /* Return a constructor for the pointer-to-member-function TYPE using @@ -5355,7 +5337,7 @@ build_ptrmemfunc (tree type, tree pfn, int force) } /* Just adjust the DELTA field. */ - delta = cp_convert (ptrdiff_type_node, delta); + my_friendly_assert (TREE_TYPE (delta) == ptrdiff_type_node, 20030727); if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_delta) n = cp_build_binary_op (LSHIFT_EXPR, n, integer_one_node); delta = cp_build_binary_op (PLUS_EXPR, delta, n); |