diff options
| author | Poul-Henning Kamp <phk@FreeBSD.org> | 1994-11-03 06:52:42 +0000 |
|---|---|---|
| committer | Poul-Henning Kamp <phk@FreeBSD.org> | 1994-11-03 06:52:42 +0000 |
| commit | fe7dee47009525e334f1bde385b69753f007085c (patch) | |
| tree | 50f1f9fa63ff73191f024d12c1c848e9cdcf55f8 /gnu/usr.bin/cc/cc1 | |
| parent | e0115bffa0ca4536902354411d53074e91a944ff (diff) | |
Notes
Diffstat (limited to 'gnu/usr.bin/cc/cc1')
| -rw-r--r-- | gnu/usr.bin/cc/cc1/c-decl.c | 71 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/cc1/c-parse.c | 49 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/cc1/c-typeck.c | 120 |
3 files changed, 136 insertions, 104 deletions
diff --git a/gnu/usr.bin/cc/cc1/c-decl.c b/gnu/usr.bin/cc/cc1/c-decl.c index c1a8dc99393e..995009a46354 100644 --- a/gnu/usr.bin/cc/cc1/c-decl.c +++ b/gnu/usr.bin/cc/cc1/c-decl.c @@ -1303,6 +1303,7 @@ duplicate_decls (newdecl, olddecl) && DECL_INITIAL (newdecl) != 0); tree oldtype = TREE_TYPE (olddecl); tree newtype = TREE_TYPE (newdecl); + char *errmsg = 0; if (TREE_CODE (newtype) == ERROR_MARK || TREE_CODE (oldtype) == ERROR_MARK) @@ -1528,7 +1529,7 @@ duplicate_decls (newdecl, olddecl) } else { - char *errmsg = redeclaration_error_message (newdecl, olddecl); + errmsg = redeclaration_error_message (newdecl, olddecl); if (errmsg) { error_with_decl (newdecl, errmsg); @@ -1625,7 +1626,7 @@ duplicate_decls (newdecl, olddecl) } /* Optionally warn about more than one declaration for the same name. */ - if (warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0 + if (errmsg == 0 && warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0 /* Dont warn about a function declaration followed by a definition. */ && !(TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) != 0 @@ -2439,6 +2440,21 @@ shadow_label (name) if (decl != 0) { + register tree dup; + + /* Check to make sure that the label hasn't already been declared + at this label scope */ + for (dup = named_labels; dup; dup = TREE_CHAIN (dup)) + if (TREE_VALUE (dup) == decl) + { + error ("duplicate label declaration `%s'", + IDENTIFIER_POINTER (name)); + error_with_decl (TREE_VALUE (dup), + "this is a previous declaration"); + /* Just use the previous declaration. */ + return lookup_label (name); + } + shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels); IDENTIFIER_LABEL_VALUE (name) = decl = 0; } @@ -3673,7 +3689,7 @@ finish_decl (decl, init, asmspec_tree) references to it. */ /* This test used to include TREE_STATIC, but this won't be set for function level initializers. */ - if (TREE_READONLY (decl)) + if (TREE_READONLY (decl) || ITERATOR_P (decl)) { preserve_initializer (); /* Hack? Set the permanent bit for something that is permanent, @@ -5418,7 +5434,7 @@ finish_struct (t, fieldlist) #endif } } - else + else if (TREE_TYPE (x) != error_mark_node) { int min_align = (DECL_PACKED (x) ? BITS_PER_UNIT : TYPE_ALIGN (TREE_TYPE (x))); @@ -5646,37 +5662,6 @@ start_enum (name) return enumtype; } -/* Return the minimum number of bits needed to represent VALUE in a - signed or unsigned type, UNSIGNEDP says which. */ - -static int -min_precision (value, unsignedp) - tree value; - int unsignedp; -{ - int log; - - /* If the value is negative, compute its negative minus 1. The latter - adjustment is because the absolute value of the largest negative value - is one larger than the largest positive value. This is equivalent to - a bit-wise negation, so use that operation instead. */ - - if (tree_int_cst_sgn (value) < 0) - value = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (value), value)); - - /* Return the number of bits needed, taking into account the fact - that we need one more bit for a signed than unsigned type. */ - - if (integer_zerop (value)) - log = 0; - else if (TREE_INT_CST_HIGH (value) != 0) - log = HOST_BITS_PER_WIDE_INT + floor_log2 (TREE_INT_CST_HIGH (value)); - else - log = floor_log2 (TREE_INT_CST_LOW (value)); - - return log + 1 + ! unsignedp; -} - /* After processing and defining all the values of an enumeration type, install their decls in the enumeration type and finish it off. ENUMTYPE is the type object and VALUES a list of decl-value pairs. @@ -5868,6 +5853,7 @@ start_function (declspecs, declarator, nested) { tree decl1, old_decl; tree restype; + int old_immediate_size_expand = immediate_size_expand; current_function_returns_value = 0; /* Assume, until we see it does. */ current_function_returns_null = 0; @@ -5877,6 +5863,9 @@ start_function (declspecs, declarator, nested) named_labels = 0; shadowed_labels = 0; + /* Don't expand any sizes in the return type of the function. */ + immediate_size_expand = 0; + decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1); /* If the declarator is not suitable for a function definition, @@ -5922,6 +5911,11 @@ start_function (declspecs, declarator, nested) current_function_prototype_line = DECL_SOURCE_LINE (old_decl); } + /* If there is no explicit declaration, look for any out-of-scope implicit + declarations. */ + if (old_decl == 0) + old_decl = IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)); + /* Optionally warn of old-fashioned def with no previous prototype. */ if (warn_strict_prototypes && TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0 @@ -5937,7 +5931,7 @@ start_function (declspecs, declarator, nested) if the function has already been used. */ else if (warn_missing_prototypes && old_decl != 0 && TREE_USED (old_decl) - && !(old_decl != 0 && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0)) + && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) == 0) warning_with_decl (decl1, "`%s' was used with no prototype before its definition"); /* Optionally warn of any global def with no previous declaration. */ @@ -5949,7 +5943,8 @@ start_function (declspecs, declarator, nested) /* Optionally warn of any def with no previous declaration if the function has already been used. */ else if (warn_missing_declarations - && old_decl != 0 && TREE_USED (old_decl)) + && old_decl != 0 && TREE_USED (old_decl) + && old_decl == IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1))) warning_with_decl (decl1, "`%s' was used with no declaration before its definition"); @@ -6006,6 +6001,8 @@ start_function (declspecs, declarator, nested) if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl))) TREE_ADDRESSABLE (current_function_decl) = 1; + immediate_size_expand = old_immediate_size_expand; + return 1; } diff --git a/gnu/usr.bin/cc/cc1/c-parse.c b/gnu/usr.bin/cc/cc1/c-parse.c index 5120144ad412..8a6465cb397d 100644 --- a/gnu/usr.bin/cc/cc1/c-parse.c +++ b/gnu/usr.bin/cc/cc1/c-parse.c @@ -395,9 +395,9 @@ static const short yyrline[] = { 0, 1576, 1585, 1590, 1595, 1600, 1604, 1608, 1619, 1626, 1633, 1640, 1651, 1655, 1658, 1663, 1686, 1720, 1745, 1774, 1789, 1800, 1804, 1808, 1811, 1816, 1818, 1821, 1823, 1827, 1832, - 1835, 1841, 1846, 1851, 1853, 1862, 1863, 1869, 1871, 1876, - 1878, 1882, 1885, 1891, 1894, 1896, 1898, 1900, 1907, 1912, - 1917, 1919, 1928, 1931, 1936, 1939 + 1835, 1841, 1846, 1851, 1853, 1862, 1863, 1869, 1871, 1881, + 1883, 1887, 1890, 1896, 1899, 1901, 1903, 1905, 1912, 1917, + 1922, 1924, 1933, 1936, 1941, 1944 }; static const char * const yytname[] = { "$","error","$illegal.","IDENTIFIER", @@ -3252,60 +3252,65 @@ case 348: case 349: #line 1872 "c-parse.y" { yyval.ttype = get_parm_info (0); - if (pedantic) - pedwarn ("ANSI C requires a named argument before `...'"); + /* Gcc used to allow this as an extension. However, it does + not work for all targets, and thus has been disabled. + Also, since func (...) and func () are indistinguishable, + it caused problems with the code in expand_builtin which + tries to verify that BUILT_IN_NEXT_ARG is being used + correctly. */ + error ("ANSI C requires a named argument before `...'"); ; break;} case 350: -#line 1877 "c-parse.y" +#line 1882 "c-parse.y" { yyval.ttype = get_parm_info (1); ; break;} case 351: -#line 1879 "c-parse.y" +#line 1884 "c-parse.y" { yyval.ttype = get_parm_info (0); ; break;} case 352: -#line 1884 "c-parse.y" +#line 1889 "c-parse.y" { push_parm_decl (yyvsp[0].ttype); ; break;} case 353: -#line 1886 "c-parse.y" +#line 1891 "c-parse.y" { push_parm_decl (yyvsp[0].ttype); ; break;} case 354: -#line 1893 "c-parse.y" +#line 1898 "c-parse.y" { yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype) ; ; break;} case 355: -#line 1895 "c-parse.y" +#line 1900 "c-parse.y" { yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype) ; ; break;} case 356: -#line 1897 "c-parse.y" +#line 1902 "c-parse.y" { yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype); ; break;} case 357: -#line 1899 "c-parse.y" +#line 1904 "c-parse.y" { yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype) ; ; break;} case 358: -#line 1901 "c-parse.y" +#line 1906 "c-parse.y" { yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype); ; break;} case 359: -#line 1908 "c-parse.y" +#line 1913 "c-parse.y" { pushlevel (0); clear_parm_order (); declare_parm_level (1); ; break;} case 360: -#line 1912 "c-parse.y" +#line 1917 "c-parse.y" { yyval.ttype = yyvsp[0].ttype; parmlist_tags_warning (); poplevel (0, 0, 0); ; break;} case 362: -#line 1920 "c-parse.y" +#line 1925 "c-parse.y" { tree t; for (t = yyvsp[-1].ttype; t; t = TREE_CHAIN (t)) if (TREE_VALUE (t) == NULL_TREE) @@ -3313,19 +3318,19 @@ case 362: yyval.ttype = tree_cons (NULL_TREE, NULL_TREE, yyvsp[-1].ttype); ; break;} case 363: -#line 1930 "c-parse.y" +#line 1935 "c-parse.y" { yyval.ttype = build_tree_list (NULL_TREE, yyvsp[0].ttype); ; break;} case 364: -#line 1932 "c-parse.y" +#line 1937 "c-parse.y" { yyval.ttype = chainon (yyvsp[-2].ttype, build_tree_list (NULL_TREE, yyvsp[0].ttype)); ; break;} case 365: -#line 1938 "c-parse.y" +#line 1943 "c-parse.y" { yyval.ttype = build_tree_list (NULL_TREE, yyvsp[0].ttype); ; break;} case 366: -#line 1940 "c-parse.y" +#line 1945 "c-parse.y" { yyval.ttype = chainon (yyvsp[-2].ttype, build_tree_list (NULL_TREE, yyvsp[0].ttype)); ; break;} } @@ -3526,5 +3531,5 @@ yyerrhandle: yystate = yyn; goto yynewstate; } -#line 1943 "c-parse.y" +#line 1948 "c-parse.y" diff --git a/gnu/usr.bin/cc/cc1/c-typeck.c b/gnu/usr.bin/cc/cc1/c-typeck.c index d5283c6982b9..c40d08ab0026 100644 --- a/gnu/usr.bin/cc/cc1/c-typeck.c +++ b/gnu/usr.bin/cc/cc1/c-typeck.c @@ -655,7 +655,8 @@ type_lists_compatible_p (args1, args2) /* Allow wait (union {union wait *u; int *i} *) and wait (union wait *) to be compatible. */ if (TREE_CODE (TREE_VALUE (args1)) == UNION_TYPE - && TYPE_NAME (TREE_VALUE (args1)) == 0 + && (TYPE_NAME (TREE_VALUE (args1)) == 0 + || TYPE_TRANSPARENT_UNION (TREE_VALUE (args1))) && TREE_CODE (TYPE_SIZE (TREE_VALUE (args1))) == INTEGER_CST && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args1)), TYPE_SIZE (TREE_VALUE (args2)))) @@ -669,7 +670,8 @@ type_lists_compatible_p (args1, args2) return 0; } else if (TREE_CODE (TREE_VALUE (args2)) == UNION_TYPE - && TYPE_NAME (TREE_VALUE (args2)) == 0 + && (TYPE_NAME (TREE_VALUE (args2)) == 0 + || TYPE_TRANSPARENT_UNION (TREE_VALUE (args2))) && TREE_CODE (TYPE_SIZE (TREE_VALUE (args2))) == INTEGER_CST && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args2)), TYPE_SIZE (TREE_VALUE (args1)))) @@ -990,8 +992,11 @@ default_conversion (exp) /* Constants can be used directly unless they're not loadable. */ if (TREE_CODE (exp) == CONST_DECL) exp = DECL_INITIAL (exp); - /* Replace a nonvolatile const static variable with its value. */ - else if (optimize && TREE_CODE (exp) == VAR_DECL) + + /* Replace a nonvolatile const static variable with its value unless + it is an array, in which case we must be sure that taking the + address of the array produces consistent results. */ + else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE) { exp = decl_constant_value (exp); type = TREE_TYPE (exp); @@ -1630,37 +1635,28 @@ convert_arguments (typelist, values, name, fundecl) } else { -#if 0 /* This turns out not to win--there's no way to write a prototype - for a function whose arg type is a union with no tag. */ - /* Nameless union automatically casts the types it contains. */ - if (TREE_CODE (type) == UNION_TYPE && TYPE_NAME (type) == 0) - { - tree field; - - for (field = TYPE_FIELDS (type); field; - field = TREE_CHAIN (field)) - if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)), - TYPE_MAIN_VARIANT (TREE_TYPE (val)))) - break; - - if (field) - val = build1 (CONVERT_EXPR, type, val); - } -#endif - /* Optionally warn about conversions that differ from the default conversions. */ if (warn_conversion) { int formal_prec = TYPE_PRECISION (type); - if (TREE_CODE (type) != REAL_TYPE + if (INTEGRAL_TYPE_P (type) && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE) warn_for_assignment ("%s as integer rather than floating due to prototype", (char *) 0, name, parmnum + 1); + else if (TREE_CODE (type) == COMPLEX_TYPE + && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE) + warn_for_assignment ("%s as complex rather than floating due to prototype", (char *) 0, name, parmnum + 1); else if (TREE_CODE (type) == REAL_TYPE - && TREE_CODE (TREE_TYPE (val)) != REAL_TYPE) + && INTEGRAL_TYPE_P (TREE_TYPE (val))) warn_for_assignment ("%s as floating rather than integer due to prototype", (char *) 0, name, parmnum + 1); else if (TREE_CODE (type) == REAL_TYPE + && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE) + warn_for_assignment ("%s as floating rather than complex due to prototype", (char *) 0, name, parmnum + 1); + /* ??? At some point, messages should be written about + conversions between complex types, but that's too messy + to do now. */ + else if (TREE_CODE (type) == REAL_TYPE && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE) { /* Warn if any argument is passed as `float', @@ -1669,10 +1665,8 @@ convert_arguments (typelist, values, name, fundecl) warn_for_assignment ("%s as `float' rather than `double' due to prototype", (char *) 0, name, parmnum + 1); } /* Detect integer changing in width or signedness. */ - else if ((TREE_CODE (type) == INTEGER_TYPE - || TREE_CODE (type) == ENUMERAL_TYPE) - && (TREE_CODE (TREE_TYPE (val)) == INTEGER_TYPE - || TREE_CODE (TREE_TYPE (val)) == ENUMERAL_TYPE)) + else if (INTEGRAL_TYPE_P (type) + && INTEGRAL_TYPE_P (TREE_TYPE (val))) { tree would_have_been = default_conversion (val); tree type1 = TREE_TYPE (would_have_been); @@ -2798,7 +2792,7 @@ build_unary_op (code, xarg, noconvert) ((code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) ? "increment" : "decrement")); - inc = c_sizeof_nowarn (TREE_TYPE (result_type)); + inc = c_size_in_bytes (TREE_TYPE (result_type)); } else inc = integer_one_node; @@ -3211,6 +3205,18 @@ mark_addressable (exp) IDENTIFIER_POINTER (DECL_NAME (x))); return 0; } + + /* If we are making this addressable due to its having + volatile components, give a different error message. Also + handle the case of an unnamed parameter by not trying + to give the name. */ + + else if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (x))) + { + error ("cannot put object with volatile field into register"); + return 0; + } + pedwarn ("address of register variable `%s' requested", IDENTIFIER_POINTER (DECL_NAME (x))); } @@ -3868,14 +3874,15 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum) /* Arithmetic types all interconvert, and enum is treated like int. */ if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE) - && - (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE - || coder == COMPLEX_TYPE)) + && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE + || coder == COMPLEX_TYPE)) return convert_and_check (type, rhs); + /* Conversion to a union from its member types. */ else if (codel == UNION_TYPE) { tree memb_types; + for (memb_types = TYPE_FIELDS (type); memb_types; memb_types = TREE_CHAIN (memb_types)) { @@ -3886,6 +3893,7 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum) pedwarn ("ANSI C prohibits argument conversion to union type"); return build1 (NOP_EXPR, type, rhs); } + else if (coder == POINTER_TYPE && TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE) { @@ -3895,44 +3903,59 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum) /* Any non-function converts to a [const][volatile] void * and vice versa; otherwise, targets must be the same. - Meanwhile, the lhs target must have all the qualifiers of the rhs. */ + Meanwhile, the lhs target must have all the qualifiers of + the rhs. */ if (TYPE_MAIN_VARIANT (ttl) == void_type_node || TYPE_MAIN_VARIANT (ttr) == void_type_node || comp_target_types (memb_type, rhstype)) { - /* Const and volatile mean something different for function types, - so the usual warnings are not appropriate. */ + /* Const and volatile mean something different for function + types, so the usual warnings are not appropriate. */ if (TREE_CODE (ttr) != FUNCTION_TYPE || TREE_CODE (ttl) != FUNCTION_TYPE) { if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr)) warn_for_assignment ("%s discards `const' from pointer target type", - get_spelling (errtype), funname, parmnum); + get_spelling (errtype), funname, + parmnum); if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr)) warn_for_assignment ("%s discards `volatile' from pointer target type", - get_spelling (errtype), funname, parmnum); + get_spelling (errtype), funname, + parmnum); } else { - /* Because const and volatile on functions are restrictions - that say the function will not do certain things, - it is okay to use a const or volatile function - where an ordinary one is wanted, but not vice-versa. */ + /* Because const and volatile on functions are + restrictions that say the function will not do + certain things, it is okay to use a const or volatile + function where an ordinary one is wanted, but not + vice-versa. */ if (TYPE_READONLY (ttl) && ! TYPE_READONLY (ttr)) warn_for_assignment ("%s makes `const *' function pointer from non-const", - get_spelling (errtype), funname, parmnum); + get_spelling (errtype), funname, + parmnum); if (TYPE_VOLATILE (ttl) && ! TYPE_VOLATILE (ttr)) warn_for_assignment ("%s makes `volatile *' function pointer from non-volatile", - get_spelling (errtype), funname, parmnum); + get_spelling (errtype), funname, + parmnum); } + if (pedantic && !(fundecl != 0 && DECL_IN_SYSTEM_HEADER (fundecl))) pedwarn ("ANSI C prohibits argument conversion to union type"); return build1 (NOP_EXPR, type, rhs); } } + + /* Can convert integer zero to any pointer type. */ + else if (TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE + && (integer_zerop (rhs) + || (TREE_CODE (rhs) == NOP_EXPR + && integer_zerop (TREE_OPERAND (rhs, 0))))) + return build1 (NOP_EXPR, type, null_pointer_node); } } + /* Conversions among pointers */ else if (codel == POINTER_TYPE && coder == POINTER_TYPE) { @@ -5155,8 +5178,8 @@ push_init_level (implicit) /* Structure elements may require alignment. Do this now if necessary for the subaggregate. */ - if (constructor_incremental && TREE_CODE (constructor_type) == RECORD_TYPE - && constructor_fields) + if (constructor_incremental && constructor_type != 0 + && TREE_CODE (constructor_type) == RECORD_TYPE && constructor_fields) { /* Advance to offset of this element. */ if (! tree_int_cst_equal (constructor_bit_index, @@ -6020,6 +6043,7 @@ process_init_element (value) /* Otherwise, if we have come to a subaggregate, and we don't have an element of its type, push into it. */ else if (value != 0 && !constructor_no_implicit + && value != error_mark_node && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE || fieldcode == UNION_TYPE)) @@ -6083,6 +6107,7 @@ process_init_element (value) /* Otherwise, if we have come to a subaggregate, and we don't have an element of its type, push into it. */ else if (value != 0 && !constructor_no_implicit + && value != error_mark_node && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE || fieldcode == UNION_TYPE)) @@ -6126,6 +6151,7 @@ process_init_element (value) /* Otherwise, if we have come to a subaggregate, and we don't have an element of its type, push into it. */ else if (value != 0 && !constructor_no_implicit + && value != error_mark_node && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != elttype && (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE || eltcode == UNION_TYPE)) @@ -6142,6 +6168,10 @@ process_init_element (value) break; } + /* In the case of [LO .. HI] = VALUE, only evaluate VALUE once. */ + if (constructor_range_end) + value = save_expr (value); + /* Now output the actual element. Ordinarily, output once. If there is a range, repeat it till we advance past the range. */ |
