diff -uNr gcc-2.95.2.ORIG/Makefile.libiberty gcc-2.95.2/Makefile.libiberty --- gcc-2.95.2.ORIG/Makefile.libiberty Wed May 31 09:32:54 2000 +++ gcc-2.95.2/Makefile.libiberty Wed Dec 20 02:56:03 2000 @@ -19,7 +19,5 @@ ## might as well make it fat while we're here... libiberty.a : $(SOURCES) cc -arch ppc -O2 -c -I $(SRCROOT)/include $(SOURCES) - libtool -o libibertyppc.a *.o - cc -arch i386 -O2 -c -I $(SRCROOT)/include $(SOURCES) - libtool -o libiberty.a *.o libibertyppc.a + libtool -o libiberty.a *.o diff -uNr gcc-2.95.2.ORIG/build_gcc gcc-2.95.2/build_gcc --- gcc-2.95.2.ORIG/build_gcc Wed Aug 9 09:28:09 2000 +++ gcc-2.95.2/build_gcc Sat Dec 23 00:43:02 2000 @@ -59,7 +59,7 @@ BUILDROOT=$TEMP # what compilers to build. On NeXT, we only really need objc and objc++. -LANGUAGES="objc c++" # was: "objc objc++ c++" +LANGUAGES="c objc c++ f77" # was: "objc objc++ c++" # flags to use when compiling the compiler CFLAGS="-g -dynamic" diff -uNr gcc-2.95.2.ORIG/gcc/Makefile.in gcc-2.95.2/gcc/Makefile.in --- gcc-2.95.2.ORIG/gcc/Makefile.in Wed May 31 09:32:58 2000 +++ gcc-2.95.2/gcc/Makefile.in Sun Jan 7 00:06:42 2001 @@ -679,6 +679,7 @@ # Language-specific object files for C and Objective C. C_AND_OBJC_OBJS = c-lex.o c-pragma.o c-decl.o c-typeck.o c-convert.o \ c-aux-info.o c-common.o c-iterate.o @extra_c_objs@ +F_OBJS = f-common.o f-decl.o f-typeck.o # Language-specific object files for C. C_OBJS = c-parse.o c-lang.o $(C_AND_OBJC_OBJS) @@ -924,7 +925,7 @@ gcc-cross: xgcc$(exeext) cp xgcc$(exeext) gcc-cross$(exeext) -cc1$(exeext): $(P) $(OBJS) $(C_OBJS) $(LIBDEPS) +cc1$(exeext): $(P) $(OBJS) $(C_OBJS) $(LIBDEPS) $(F_OBJS) $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(C_OBJS) $(LIBS) cc1obj$(exeext): $(P) $(OBJC_OBJS) $(OBJS) $(LIBDEPS) @@ -1376,6 +1377,10 @@ # -k1,3,$$ $(srcdir)/c-parse.gperf >tmp-gperf.h # $(srcdir)/move-if-change tmp-gperf.h $(srcdir)/c-gperf.h +f-decl.o : f-decl.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-lex.h flags.h \ + output.h toplev.h +f-typeck.o : f-typeck.c $(CONFIG_H) system.h $(TREE_H) c-tree.h flags.h \ + intl.h output.h $(EXPR_H) $(RTL_H) toplev.h c-decl.o : c-decl.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-lex.h flags.h \ output.h toplev.h c-typeck.o : c-typeck.c $(CONFIG_H) system.h $(TREE_H) c-tree.h flags.h \ @@ -1446,6 +1451,8 @@ # A file used by all variants of C. +f-common.o : f-common.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-lex.h \ + flags.h toplev.h output.h c-pragma.h $(RTL_H) c-common.o : c-common.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-lex.h \ flags.h toplev.h output.h c-pragma.h $(RTL_H) diff -uNr gcc-2.95.2.ORIG/gcc/c-tree.h gcc-2.95.2/gcc/c-tree.h --- gcc-2.95.2.ORIG/gcc/c-tree.h Wed May 31 09:33:00 2000 +++ gcc-2.95.2/gcc/c-tree.h Thu Dec 21 21:46:00 2000 @@ -256,6 +256,7 @@ extern tree complex_float_type_node; extern tree complex_double_type_node; extern tree complex_long_double_type_node; +#ifndef __GNUFORTAN__ extern tree vector_unsigned_char_type_node; extern tree vector_signed_char_type_node; extern tree vector_boolean_char_type_node; @@ -267,6 +268,7 @@ extern tree vector_boolean_long_type_node; extern tree vector_float_type_node; extern tree vector_pixel_type_node; +#endif extern tree ptr_type_node; extern tree ptrdiff_type_node; extern tree short_integer_type_node; @@ -415,7 +417,9 @@ int, char *, int)); extern void c_expand_return PROTO((tree)); extern tree c_expand_start_case PROTO((tree)); +#ifndef __GNUFORTRAN__ extern tree build_vector_constant PROTO((tree, tree)); +#endif /* in c-iterate.c */ extern void init_iterators PROTO((void)); @@ -467,7 +471,9 @@ /* Nonzero for -faltivec: Enable the SIMD programming model. */ +#ifndef __GNUFORTRAN__ extern int flag_altivec; +#endif /* Nonzero means warn about implicit declarations. */ diff -uNr gcc-2.95.2.ORIG/gcc/convert.h gcc-2.95.2/gcc/convert.h --- gcc-2.95.2.ORIG/gcc/convert.h Wed May 31 09:33:02 2000 +++ gcc-2.95.2/gcc/convert.h Thu Dec 21 21:46:15 2000 @@ -22,4 +22,6 @@ extern tree convert_to_pointer PROTO ((tree, tree)); extern tree convert_to_real PROTO ((tree, tree)); extern tree convert_to_complex PROTO ((tree, tree)); +#ifndef __GNUFORTRAN__ extern tree convert_to_vector PROTO ((tree, tree)); +#endif diff -uNr gcc-2.95.2.ORIG/gcc/f/Makefile.in gcc-2.95.2/gcc/f/Makefile.in --- gcc-2.95.2.ORIG/gcc/f/Makefile.in Thu May 20 19:51:36 1999 +++ gcc-2.95.2/gcc/f/Makefile.in Sun Jan 7 00:53:46 2001 @@ -206,7 +206,8 @@ where.o # Language-independent object files. -OBJS = `cat ../stamp-objlist` +OBJS = `cat ../stamp-objlist` \ + ../f-common.o ../f-typeck.o ../f-decl.o ../c-aux-info.o OBJDEPS = ../stamp-objlist compiler: ../f771$(exeext) diff -uNr gcc-2.95.2.ORIG/gcc/f/com.c gcc-2.95.2/gcc/f/com.c --- gcc-2.95.2.ORIG/gcc/f/com.c Thu Dec 21 22:09:38 2000 +++ gcc-2.95.2/gcc/f/com.c Tue Dec 26 16:00:59 2000 @@ -17445,3 +17445,72 @@ -------- (end output file from f2c) */ + +#ifdef MACOSX + +int doing_objc_thang; +tree ridpointers[(int) 1024]; + + +/*--------------------------------------------------------------*/ +/* (Modification Record) */ +/* 2000/12/21 K.Fujii Added for MacOSX */ +/*--------------------------------------------------------------*/ +/*----------------------*/ +/* From c-lang.c */ +/*----------------------*/ + +int +is_protocol_qualified_id (type) + tree type; +{ + return 0; +} + +tree +maybe_building_objc_message_expr () +{ + return 0; +} + +int +maybe_objc_comptypes (lhs, rhs, reflexive) + tree lhs ATTRIBUTE_UNUSED; + tree rhs ATTRIBUTE_UNUSED; + int reflexive ATTRIBUTE_UNUSED; +{ + return -1; +} + +void +maybe_objc_check_decl (decl) + tree decl ATTRIBUTE_UNUSED; +{ +} + +/*----------------------*/ +/* From objc-act.c */ +/*----------------------*/ + + +static tree saved_objc_implementation_context; + +void objc_begin_function_pragma() +{ +} /* Dummy */ + +void objc_end_function_pragma() +{ +} /* Dummy */ + +void objc_selector_alias_pragma(objcname, alias) + tree objcname; + tree alias; +{ +} /* Dummy */ + + + + + +#endif diff -uNr gcc-2.95.2.ORIG/gcc/f/config.j gcc-2.95.2/gcc/f/config.j --- gcc-2.95.2.ORIG/gcc/f/config.j Thu May 20 19:51:36 1999 +++ gcc-2.95.2/gcc/f/config.j Tue Dec 26 10:30:15 2000 @@ -22,6 +22,7 @@ #ifndef MAKING_DEPENDENCIES #ifndef _J_f_config #define _J_f_config +#define __GNUFORTRAN__ #include "config.h" #endif #endif diff -uNr gcc-2.95.2.ORIG/gcc/f/global.c gcc-2.95.2/gcc/f/global.c --- gcc-2.95.2.ORIG/gcc/f/global.c Thu May 20 19:51:36 1999 +++ gcc-2.95.2/gcc/f/global.c Wed Dec 20 15:57:32 2000 @@ -62,6 +62,7 @@ static ffenameSpace ffeglobal_filewide_ = NULL; static const char *ffeglobal_type_string_[] = { +#ifndef MACOSX [FFEGLOBAL_typeNONE] "??", [FFEGLOBAL_typeMAIN] "main program", [FFEGLOBAL_typeEXT] "external", @@ -70,6 +71,17 @@ [FFEGLOBAL_typeBDATA] "block data", [FFEGLOBAL_typeCOMMON] "common block", [FFEGLOBAL_typeANY] "?any?" +#else /* MACOSX */ +/* Very Temporary: enumeration should be consistent with that in global.h */ + "??", + "main program", + "external", + "subroutine", + "function", + "block data", + "common block", + "?any?" +#endif }; #endif diff -uNr gcc-2.95.2.ORIG/gcc/f-common.c gcc-2.95.2/gcc/f-common.c --- gcc-2.95.2.ORIG/gcc/f-common.c Thu Jan 1 09:00:00 1970 +++ gcc-2.95.2/gcc/f-common.c Tue Dec 26 15:17:19 2000 @@ -0,0 +1,3367 @@ +/* Subroutines shared by all languages that are variants of C. + Copyright (C) 1992, 93-98, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef __GNUFORTRAN__ +#define __GNUFORTRAN__ +#endif + +#include "config.h" +#include "system.h" +#include "tree.h" +#include "c-lex.h" +#include "c-tree.h" +#include "flags.h" +#include "obstack.h" +#include "toplev.h" +#include "output.h" +#include "c-pragma.h" +#include "rtl.h" + +#if USE_CPPLIB +#include "cpplib.h" +cpp_reader parse_in; +cpp_options parse_options; +static enum cpp_token cpp_token; +#endif + +#ifndef WCHAR_TYPE_SIZE +#ifdef INT_TYPE_SIZE +#define WCHAR_TYPE_SIZE INT_TYPE_SIZE +#else +#define WCHAR_TYPE_SIZE BITS_PER_WORD +#endif +#endif + +extern struct obstack permanent_obstack; + +/* Nonzero means the expression being parsed will never be evaluated. + This is a count, since unevaluated expressions can nest. */ +int skip_evaluation; + +enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION, + A_NO_CHECK_MEMORY_USAGE, A_NO_INSTRUMENT_FUNCTION, + A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED, + A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS}; + +enum format_type { printf_format_type, scanf_format_type, + strftime_format_type }; + +static void declare_hidden_char_array PROTO((const char *, const char *)); +static void add_attribute PROTO((enum attrs, const char *, + int, int, int)); +static void init_attributes PROTO((void)); +static void record_function_format PROTO((tree, tree, enum format_type, + int, int)); +static void record_international_format PROTO((tree, tree, int)); +static tree c_find_base_decl PROTO((tree)); +static int default_valid_lang_attribute PROTO ((tree, tree, tree, tree)); + +/* Keep a stack of if statements. We record the number of compound + statements seen up to the if keyword, as well as the line number + and file of the if. If a potentially ambiguous else is seen, that + fact is recorded; the warning is issued when we can be sure that + the enclosing if statement does not have an else branch. */ +typedef struct +{ + int compstmt_count; + int line; + const char *file; + int needs_warning; +} if_elt; +static void tfaff PROTO((void)); + +static if_elt *if_stack; + +/* Amount of space in the if statement stack. */ +static int if_stack_space = 0; + +/* Stack pointer. */ +static int if_stack_pointer = 0; + +/* Generate RTL for the start of an if-then, and record the start of it + for ambiguous else detection. */ + +void +c_expand_start_cond (cond, exitflag, compstmt_count) + tree cond; + int exitflag; + int compstmt_count; +{ + /* Make sure there is enough space on the stack. */ + if (if_stack_space == 0) + { + if_stack_space = 10; + if_stack = (if_elt *)xmalloc (10 * sizeof (if_elt)); + } + else if (if_stack_space == if_stack_pointer) + { + if_stack_space += 10; + if_stack = (if_elt *)xrealloc (if_stack, if_stack_space * sizeof (if_elt)); + } + + /* Record this if statement. */ + if_stack[if_stack_pointer].compstmt_count = compstmt_count; + if_stack[if_stack_pointer].file = input_filename; + if_stack[if_stack_pointer].line = lineno; + if_stack[if_stack_pointer].needs_warning = 0; + if_stack_pointer++; + + expand_start_cond (cond, exitflag); +} + +/* Generate RTL for the end of an if-then. Optionally warn if a nested + if statement had an ambiguous else clause. */ + +void +c_expand_end_cond () +{ + if_stack_pointer--; + if (if_stack[if_stack_pointer].needs_warning) + warning_with_file_and_line (if_stack[if_stack_pointer].file, + if_stack[if_stack_pointer].line, + "suggest explicit braces to avoid ambiguous `else'"); + expand_end_cond (); +} + +/* Generate RTL between the then-clause and the else-clause + of an if-then-else. */ + +void +c_expand_start_else () +{ + /* An ambiguous else warning must be generated for the enclosing if + statement, unless we see an else branch for that one, too. */ + if (warn_parentheses + && if_stack_pointer > 1 + && (if_stack[if_stack_pointer - 1].compstmt_count + == if_stack[if_stack_pointer - 2].compstmt_count)) + if_stack[if_stack_pointer - 2].needs_warning = 1; + + /* Even if a nested if statement had an else branch, it can't be + ambiguous if this one also has an else. So don't warn in that + case. Also don't warn for any if statements nested in this else. */ + if_stack[if_stack_pointer - 1].needs_warning = 0; + if_stack[if_stack_pointer - 1].compstmt_count--; + + expand_start_else (); +} + +/* Make bindings for __FUNCTION__, __PRETTY_FUNCTION__, and __func__. */ + +void +declare_function_name () +{ + const char *name, *printable_name; + + if (current_function_decl == NULL) + { + name = ""; + printable_name = "top level"; + } + else + { + /* Allow functions to be nameless (such as artificial ones). */ + if (DECL_NAME (current_function_decl)) + name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl)); + else + name = ""; + printable_name = (*decl_printable_name) (current_function_decl, 2); + } + + declare_hidden_char_array ("__FUNCTION__", name); + declare_hidden_char_array ("__PRETTY_FUNCTION__", printable_name); + /* The ISO C people "of course" couldn't use __FUNCTION__ in the + ISO C 9x standard; instead a new variable is invented. */ + declare_hidden_char_array ("__func__", name); +} + +static void +declare_hidden_char_array (name, value) + const char *name, *value; +{ + tree decl, type, init; + int vlen; + + /* If the default size of char arrays isn't big enough for the name, + or if we want to give warnings for large objects, make a bigger one. */ + vlen = strlen (value) + 1; + type = char_array_type_node; + if (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < vlen + || warn_larger_than) + type = build_array_type (char_type_node, + build_index_type (build_int_2 (vlen, 0))); + push_obstacks_nochange (); + decl = build_decl (VAR_DECL, get_identifier (name), type); + TREE_STATIC (decl) = 1; + TREE_READONLY (decl) = 1; + TREE_ASM_WRITTEN (decl) = 1; + DECL_SOURCE_LINE (decl) = 0; + DECL_ARTIFICIAL (decl) = 1; + DECL_IN_SYSTEM_HEADER (decl) = 1; + DECL_IGNORED_P (decl) = 1; + init = build_string (vlen, value); + TREE_TYPE (init) = type; + DECL_INITIAL (decl) = init; + finish_decl (pushdecl (decl), init, NULL_TREE); +} + + +/* Given a wide flag and a pascal_string flag, + return the node indicating the type for combine_strings + to assign to the resulting string. */ + +tree +choose_string_type ( wide_flag, ps_flag ) + int wide_flag, ps_flag; +{ + if (wide_flag) + return wchar_type_node; + +#ifndef PASCAL_STRINGS + return char_type_node; +#else + + return ps_flag? unsigned_char_type_node : char_type_node ; + +#endif +} + + +/* Given a chain of STRING_CST nodes, + concatenate them into one STRING_CST + and give it a suitable array-of-chars data type. */ + +tree +combine_strings (strings) + tree strings; +{ + register tree value, t; + register int length = 1; + int wide_length = 0; + int wide_flag = 0; + int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT; + int nchars; + + /* This flag is ignored by choose_string_type_node when + PASCAL_STRINGS is not defined. */ + int is_pascal_string = 0; + +#ifdef PASCAL_STRINGS + + /* If first string is a pascal-string, that "wins". */ + if (TREE_TYPE (strings) == unsigned_char_array_type_node) + { + is_pascal_string = 1; + length = 2; /* account for the \p length byte, and the NUL. */ + } +#endif + + if (TREE_CHAIN (strings)) + { + /* More than one in the chain, so concatenate. */ + register char *p, *q; + + /* Don't include the \0 at the end of each substring, + except for the last one. + Count wide strings and ordinary strings separately. */ + for (t = strings; t; t = TREE_CHAIN (t)) + { + if (TREE_TYPE (t) == wchar_array_type_node) + { + wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes); + wide_flag = 1; + } +#ifdef PASCAL_STRINGS + else if (TREE_TYPE (t) == unsigned_char_array_type_node) + { + /* This one is a pascal-string -- don't count its + length byte. */ + length += (TREE_STRING_LENGTH (t) - 2); + + /* If it's not the first one, complain. */ + if (t != strings) + if (is_pascal_string) + warning ("pascal-string length escape (\"\\p\") ignored"); + else + error ("pascal-string length escape (\"\\p\") ignored"); + } +#endif + else + length += (TREE_STRING_LENGTH (t) - 1); + } + + /* If anything is wide, the non-wides will be converted, + which makes them take more space. */ + if (wide_flag) + length = length * wchar_bytes + wide_length; + + p = savealloc (length); + + /* Copy the individual strings into the new combined string. + If the combined string is wide, convert the chars to ints + for any individual strings that are not wide. */ + + q = p; +#ifdef PASCAL_STRINGS + if (is_pascal_string) ++q; +#endif + for (t = strings; t; t = TREE_CHAIN (t)) + { + int len = (TREE_STRING_LENGTH (t) + - ((TREE_TYPE (t) == wchar_array_type_node) + ? wchar_bytes : 1)); + char *string_ptr = TREE_STRING_POINTER (t); +#ifdef PASCAL_STRINGS + /* Skip the length byte of all of the strings, even the 1st. */ + if (TREE_TYPE (t) == unsigned_char_array_type_node) + ++string_ptr, --len; +#endif + if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag) + { + memcpy (q, string_ptr, len); + q += len; + } + else + { + int i; + for (i = 0; i < len; i++) + { + if (WCHAR_TYPE_SIZE == HOST_BITS_PER_SHORT) + ((short *) q)[i] = string_ptr[i]; + else + ((int *) q)[i] = string_ptr[i]; + } + q += len * wchar_bytes; + } + } + if (wide_flag) + { + int i; + for (i = 0; i < wchar_bytes; i++) + *q++ = 0; + } + else + *q = 0; + +#ifdef PASCAL_STRINGS + if (is_pascal_string) + { + *p = length -2; + if (length -2 > 255) + { + error ("pascal-string too long"); + } + } +#endif + + value = make_node (STRING_CST); + TREE_STRING_POINTER (value) = p; + TREE_STRING_LENGTH (value) = length; + } + else + { + value = strings; + length = TREE_STRING_LENGTH (value); + if (TREE_TYPE (value) == wchar_array_type_node) + wide_flag = 1; + } + + /* Compute the number of elements, for the array type. */ + nchars = wide_flag ? length / wchar_bytes : length; + + /* Create the array type for the string constant. + -Wwrite-strings says make the string constant an array of const char + so that copying it to a non-const pointer will get a warning. + For C++, this is the standard behavior. */ + if (flag_const_strings + && (! flag_traditional && ! flag_writable_strings)) + { + tree elements + = build_type_variant (choose_string_type(wide_flag, is_pascal_string), + 1, 0); + TREE_TYPE (value) + = build_array_type (elements, + build_index_type (build_int_2 (nchars - 1, 0))); + } + else + TREE_TYPE (value) + = build_array_type (choose_string_type(wide_flag, is_pascal_string), + build_index_type (build_int_2 (nchars - 1, 0))); + + TREE_READONLY (value) = TREE_CONSTANT (value) = ! flag_writable_strings; + TREE_STATIC (value) = 1; + return value; +} + +/* To speed up processing of attributes, we maintain an array of + IDENTIFIER_NODES and the corresponding attribute types. */ + +/* Array to hold attribute information. */ + +static struct {enum attrs id; tree name; int min, max, decl_req;} attrtab[50]; + +static int attrtab_idx = 0; + +/* Add an entry to the attribute table above. */ + +static void +add_attribute (id, string, min_len, max_len, decl_req) + enum attrs id; + const char *string; + int min_len, max_len; + int decl_req; +{ + char buf[100]; + + attrtab[attrtab_idx].id = id; + attrtab[attrtab_idx].name = get_identifier (string); + attrtab[attrtab_idx].min = min_len; + attrtab[attrtab_idx].max = max_len; + attrtab[attrtab_idx++].decl_req = decl_req; + + sprintf (buf, "__%s__", string); + + attrtab[attrtab_idx].id = id; + attrtab[attrtab_idx].name = get_identifier (buf); + attrtab[attrtab_idx].min = min_len; + attrtab[attrtab_idx].max = max_len; + attrtab[attrtab_idx++].decl_req = decl_req; +} + +/* Initialize attribute table. */ + +static void +init_attributes () +{ + add_attribute (A_PACKED, "packed", 0, 0, 0); + add_attribute (A_NOCOMMON, "nocommon", 0, 0, 1); + add_attribute (A_COMMON, "common", 0, 0, 1); + add_attribute (A_NORETURN, "noreturn", 0, 0, 1); + add_attribute (A_NORETURN, "volatile", 0, 0, 1); + add_attribute (A_UNUSED, "unused", 0, 0, 0); + add_attribute (A_CONST, "const", 0, 0, 1); + add_attribute (A_T_UNION, "transparent_union", 0, 0, 0); + add_attribute (A_CONSTRUCTOR, "constructor", 0, 0, 1); + add_attribute (A_DESTRUCTOR, "destructor", 0, 0, 1); + add_attribute (A_MODE, "mode", 1, 1, 1); + add_attribute (A_SECTION, "section", 1, 1, 1); + add_attribute (A_ALIGNED, "aligned", 0, 1, 0); + add_attribute (A_FORMAT, "format", 3, 3, 1); + add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1); + add_attribute (A_WEAK, "weak", 0, 0, 1); + add_attribute (A_ALIAS, "alias", 1, 1, 1); + add_attribute (A_NO_INSTRUMENT_FUNCTION, "no_instrument_function", 0, 0, 1); + add_attribute (A_NO_CHECK_MEMORY_USAGE, "no_check_memory_usage", 0, 0, 1); +} + +/* Default implementation of valid_lang_attribute, below. By default, there + are no language-specific attributes. */ + +static int +default_valid_lang_attribute (attr_name, attr_args, decl, type) + tree attr_name ATTRIBUTE_UNUSED; + tree attr_args ATTRIBUTE_UNUSED; + tree decl ATTRIBUTE_UNUSED; + tree type ATTRIBUTE_UNUSED; +{ + return 0; +} + +/* Return a 1 if ATTR_NAME and ATTR_ARGS denote a valid language-specific + attribute for either declaration DECL or type TYPE and 0 otherwise. */ + +int (*valid_lang_attribute) PROTO ((tree, tree, tree, tree)) + = default_valid_lang_attribute; + +/* Process the attributes listed in ATTRIBUTES and PREFIX_ATTRIBUTES + and install them in NODE, which is either a DECL (including a TYPE_DECL) + or a TYPE. PREFIX_ATTRIBUTES can appear after the declaration specifiers + and declaration modifiers but before the declaration proper. */ + +void +decl_attributes (node, attributes, prefix_attributes) + tree node, attributes, prefix_attributes; +{ + tree decl = 0, type = 0; + int is_type = 0; + tree a; + + if (attrtab_idx == 0) + init_attributes (); + + if (TREE_CODE_CLASS (TREE_CODE (node)) == 'd') + { + decl = node; + type = TREE_TYPE (decl); + is_type = TREE_CODE (node) == TYPE_DECL; + } + else if (TREE_CODE_CLASS (TREE_CODE (node)) == 't') + type = node, is_type = 1; + +#ifdef PRAGMA_INSERT_ATTRIBUTES + /* If the code in c-pragma.c wants to insert some attributes then + allow it to do so. Do this before allowing machine back ends to + insert attributes, so that they have the opportunity to override + anything done here. */ + PRAGMA_INSERT_ATTRIBUTES (node, & attributes, & prefix_attributes); +#endif + +#ifdef INSERT_ATTRIBUTES + INSERT_ATTRIBUTES (node, & attributes, & prefix_attributes); +#endif + + attributes = chainon (prefix_attributes, attributes); + + for (a = attributes; a; a = TREE_CHAIN (a)) + { + tree name = TREE_PURPOSE (a); + tree args = TREE_VALUE (a); + int i; + enum attrs id; + + for (i = 0; i < attrtab_idx; i++) + if (attrtab[i].name == name) + break; + + if (i == attrtab_idx) + { + if (! valid_machine_attribute (name, args, decl, type) + && ! (* valid_lang_attribute) (name, args, decl, type)) + warning ("`%s' attribute directive ignored", + IDENTIFIER_POINTER (name)); + else if (decl != 0) + type = TREE_TYPE (decl); + continue; + } + else if (attrtab[i].decl_req && decl == 0) + { + warning ("`%s' attribute does not apply to types", + IDENTIFIER_POINTER (name)); + continue; + } + else if (list_length (args) < attrtab[i].min + || list_length (args) > attrtab[i].max) + { + error ("wrong number of arguments specified for `%s' attribute", + IDENTIFIER_POINTER (name)); + continue; + } + + id = attrtab[i].id; + switch (id) + { + case A_PACKED: + if (is_type) + TYPE_PACKED (type) = 1; + else if (TREE_CODE (decl) == FIELD_DECL) + DECL_PACKED (decl) = 1; + /* We can't set DECL_PACKED for a VAR_DECL, because the bit is + used for DECL_REGISTER. It wouldn't mean anything anyway. */ + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_NOCOMMON: + if (TREE_CODE (decl) == VAR_DECL) + DECL_COMMON (decl) = 0; + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_COMMON: + if (TREE_CODE (decl) == VAR_DECL) + DECL_COMMON (decl) = 1; + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_NORETURN: + if (TREE_CODE (decl) == FUNCTION_DECL) + TREE_THIS_VOLATILE (decl) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (decl) = type + = build_pointer_type + (build_type_variant (TREE_TYPE (type), + TREE_READONLY (TREE_TYPE (type)), 1)); + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_UNUSED: + if (is_type) + TREE_USED (type) = 1; + else if (TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == LABEL_DECL) + TREE_USED (decl) = 1; + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_CONST: + if (TREE_CODE (decl) == FUNCTION_DECL) + TREE_READONLY (decl) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (decl) = type + = build_pointer_type + (build_type_variant (TREE_TYPE (type), 1, + TREE_THIS_VOLATILE (TREE_TYPE (type)))); + else + warning ( "`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_T_UNION: + if (is_type + && TREE_CODE (type) == UNION_TYPE + && (decl == 0 + || (TYPE_FIELDS (type) != 0 + && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type))))) + TYPE_TRANSPARENT_UNION (type) = 1; + else if (decl != 0 && TREE_CODE (decl) == PARM_DECL + && TREE_CODE (type) == UNION_TYPE + && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type))) + DECL_TRANSPARENT_UNION (decl) = 1; + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_CONSTRUCTOR: + if (TREE_CODE (decl) == FUNCTION_DECL + && TREE_CODE (type) == FUNCTION_TYPE + && decl_function_context (decl) == 0) + { + DECL_STATIC_CONSTRUCTOR (decl) = 1; + TREE_USED (decl) = 1; + } + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_DESTRUCTOR: + if (TREE_CODE (decl) == FUNCTION_DECL + && TREE_CODE (type) == FUNCTION_TYPE + && decl_function_context (decl) == 0) + { + DECL_STATIC_DESTRUCTOR (decl) = 1; + TREE_USED (decl) = 1; + } + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_MODE: + if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE) + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + else + { + int j; + const char *p = IDENTIFIER_POINTER (TREE_VALUE (args)); + int len = strlen (p); + enum machine_mode mode = VOIDmode; + tree typefm; + + if (len > 4 && p[0] == '_' && p[1] == '_' + && p[len - 1] == '_' && p[len - 2] == '_') + { + char *newp = (char *) alloca (len - 1); + + strcpy (newp, &p[2]); + newp[len - 4] = '\0'; + p = newp; + } + + /* Give this decl a type with the specified mode. + First check for the special modes. */ + if (! strcmp (p, "byte")) + mode = byte_mode; + else if (!strcmp (p, "word")) + mode = word_mode; + else if (! strcmp (p, "pointer")) + mode = ptr_mode; + else + for (j = 0; j < NUM_MACHINE_MODES; j++) + if (!strcmp (p, GET_MODE_NAME (j))) + mode = (enum machine_mode) j; + + if (mode == VOIDmode) + error ("unknown machine mode `%s'", p); + else if (0 == (typefm = type_for_mode (mode, + TREE_UNSIGNED (type)))) + error ("no data type for mode `%s'", p); + else + { + TREE_TYPE (decl) = type = typefm; + DECL_SIZE (decl) = 0; + layout_decl (decl, 0); + } + } + break; + + case A_SECTION: +#ifdef ASM_OUTPUT_SECTION_NAME + if ((TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == VAR_DECL) + && TREE_CODE (TREE_VALUE (args)) == STRING_CST) + { + if (TREE_CODE (decl) == VAR_DECL + && current_function_decl != NULL_TREE + && ! TREE_STATIC (decl)) + error_with_decl (decl, + "section attribute cannot be specified for local variables"); + /* The decl may have already been given a section attribute from + a previous declaration. Ensure they match. */ + else if (DECL_SECTION_NAME (decl) != NULL_TREE + && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), + TREE_STRING_POINTER (TREE_VALUE (args))) != 0) + error_with_decl (node, + "section of `%s' conflicts with previous declaration"); + else + DECL_SECTION_NAME (decl) = TREE_VALUE (args); + } + else + error_with_decl (node, + "section attribute not allowed for `%s'"); +#else + error_with_decl (node, + "section attributes are not supported for this target"); +#endif + break; + + case A_ALIGNED: + { + tree align_expr + = (args ? TREE_VALUE (args) + : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); + int align; + + /* Strip any NOPs of any kind. */ + while (TREE_CODE (align_expr) == NOP_EXPR + || TREE_CODE (align_expr) == CONVERT_EXPR + || TREE_CODE (align_expr) == NON_LVALUE_EXPR) + align_expr = TREE_OPERAND (align_expr, 0); + + if (TREE_CODE (align_expr) != INTEGER_CST) + { + error ("requested alignment is not a constant"); + continue; + } + + align = TREE_INT_CST_LOW (align_expr) * BITS_PER_UNIT; + + if (exact_log2 (align) == -1) + error ("requested alignment is not a power of 2"); + else if (is_type) + TYPE_ALIGN (type) = align; + else if (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != FIELD_DECL) + error_with_decl (decl, + "alignment may not be specified for `%s'"); + else + DECL_ALIGN (decl) = align; + } + break; + + case A_FORMAT: + { + tree format_type_id = TREE_VALUE (args); + tree format_num_expr = TREE_VALUE (TREE_CHAIN (args)); + tree first_arg_num_expr + = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); + int format_num; + int first_arg_num; + enum format_type format_type; + tree argument; + int arg_num; + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "argument format specified for non-function `%s'"); + continue; + } + + if (TREE_CODE (format_type_id) != IDENTIFIER_NODE) + { + error ("unrecognized format specifier"); + continue; + } + else + { + const char *p = IDENTIFIER_POINTER (format_type_id); + + if (!strcmp (p, "printf") || !strcmp (p, "__printf__")) + format_type = printf_format_type; + else if (!strcmp (p, "scanf") || !strcmp (p, "__scanf__")) + format_type = scanf_format_type; + else if (!strcmp (p, "strftime") + || !strcmp (p, "__strftime__")) + format_type = strftime_format_type; + else + { + warning ("`%s' is an unrecognized format function type", p); + continue; + } + } + + /* Strip any conversions from the string index and first arg number + and verify they are constants. */ + while (TREE_CODE (format_num_expr) == NOP_EXPR + || TREE_CODE (format_num_expr) == CONVERT_EXPR + || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR) + format_num_expr = TREE_OPERAND (format_num_expr, 0); + + while (TREE_CODE (first_arg_num_expr) == NOP_EXPR + || TREE_CODE (first_arg_num_expr) == CONVERT_EXPR + || TREE_CODE (first_arg_num_expr) == NON_LVALUE_EXPR) + first_arg_num_expr = TREE_OPERAND (first_arg_num_expr, 0); + + if (TREE_CODE (format_num_expr) != INTEGER_CST + || TREE_CODE (first_arg_num_expr) != INTEGER_CST) + { + error ("format string has non-constant operand number"); + continue; + } + + format_num = TREE_INT_CST_LOW (format_num_expr); + first_arg_num = TREE_INT_CST_LOW (first_arg_num_expr); + if (first_arg_num != 0 && first_arg_num <= format_num) + { + error ("format string arg follows the args to be formatted"); + continue; + } + + /* If a parameter list is specified, verify that the format_num + argument is actually a string, in case the format attribute + is in error. */ + argument = TYPE_ARG_TYPES (type); + if (argument) + { + for (arg_num = 1; ; ++arg_num) + { + if (argument == 0 || arg_num == format_num) + break; + argument = TREE_CHAIN (argument); + } + if (! argument + || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument))) + != char_type_node)) + { + error ("format string arg not a string type"); + continue; + } + if (first_arg_num != 0) + { + /* Verify that first_arg_num points to the last arg, + the ... */ + while (argument) + arg_num++, argument = TREE_CHAIN (argument); + if (arg_num != first_arg_num) + { + error ("args to be formatted is not ..."); + continue; + } + } + } + + record_function_format (DECL_NAME (decl), + DECL_ASSEMBLER_NAME (decl), + format_type, format_num, first_arg_num); + break; + } + + case A_FORMAT_ARG: + { + tree format_num_expr = TREE_VALUE (args); + int format_num, arg_num; + tree argument; + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "argument format specified for non-function `%s'"); + continue; + } + + /* Strip any conversions from the first arg number and verify it + is a constant. */ + while (TREE_CODE (format_num_expr) == NOP_EXPR + || TREE_CODE (format_num_expr) == CONVERT_EXPR + || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR) + format_num_expr = TREE_OPERAND (format_num_expr, 0); + + if (TREE_CODE (format_num_expr) != INTEGER_CST) + { + error ("format string has non-constant operand number"); + continue; + } + + format_num = TREE_INT_CST_LOW (format_num_expr); + + /* If a parameter list is specified, verify that the format_num + argument is actually a string, in case the format attribute + is in error. */ + argument = TYPE_ARG_TYPES (type); + if (argument) + { + for (arg_num = 1; ; ++arg_num) + { + if (argument == 0 || arg_num == format_num) + break; + argument = TREE_CHAIN (argument); + } + if (! argument + || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument))) + != char_type_node)) + { + error ("format string arg not a string type"); + continue; + } + } + + if (TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_TYPE (decl)))) + != char_type_node)) + { + error ("function does not return string type"); + continue; + } + + record_international_format (DECL_NAME (decl), + DECL_ASSEMBLER_NAME (decl), + format_num); + break; + } + + case A_WEAK: + declare_weak (decl); + break; + + case A_ALIAS: + if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) + || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl))) + error_with_decl (decl, + "`%s' defined both normally and as an alias"); + else if (decl_function_context (decl) == 0) + { + tree id; + + id = TREE_VALUE (args); + if (TREE_CODE (id) != STRING_CST) + { + error ("alias arg not a string"); + break; + } + id = get_identifier (TREE_STRING_POINTER (id)); + + if (TREE_CODE (decl) == FUNCTION_DECL) + DECL_INITIAL (decl) = error_mark_node; + else + DECL_EXTERNAL (decl) = 0; + assemble_alias (decl, id); + } + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_NO_CHECK_MEMORY_USAGE: + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "`%s' attribute applies only to functions", + IDENTIFIER_POINTER (name)); + } + else if (DECL_INITIAL (decl)) + { + error_with_decl (decl, + "can't set `%s' attribute after definition", + IDENTIFIER_POINTER (name)); + } + else + DECL_NO_CHECK_MEMORY_USAGE (decl) = 1; + break; + + case A_NO_INSTRUMENT_FUNCTION: + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "`%s' attribute applies only to functions", + IDENTIFIER_POINTER (name)); + } + else if (DECL_INITIAL (decl)) + { + error_with_decl (decl, + "can't set `%s' attribute after definition", + IDENTIFIER_POINTER (name)); + } + else + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; + break; + } + } +} + +/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two + lists. SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE). + + The head of the declspec list is stored in DECLSPECS. + The head of the attribute list is stored in PREFIX_ATTRIBUTES. + + Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of + the list elements. We drop the containing TREE_LIST nodes and link the + resulting attributes together the way decl_attributes expects them. */ + +void +split_specs_attrs (specs_attrs, declspecs, prefix_attributes) + tree specs_attrs; + tree *declspecs, *prefix_attributes; +{ + tree t, s, a, next, specs, attrs; + + /* This can happen in c++ (eg: decl: typespec initdecls ';'). */ + if (specs_attrs != NULL_TREE + && TREE_CODE (specs_attrs) != TREE_LIST) + { + *declspecs = specs_attrs; + *prefix_attributes = NULL_TREE; + return; + } + + /* Remember to keep the lists in the same order, element-wise. */ + + specs = s = NULL_TREE; + attrs = a = NULL_TREE; + for (t = specs_attrs; t; t = next) + { + next = TREE_CHAIN (t); + /* Declspecs have a non-NULL TREE_VALUE. */ + if (TREE_VALUE (t) != NULL_TREE) + { + if (specs == NULL_TREE) + specs = s = t; + else + { + TREE_CHAIN (s) = t; + s = t; + } + } + else + { + if (attrs == NULL_TREE) + attrs = a = TREE_PURPOSE (t); + else + { + TREE_CHAIN (a) = TREE_PURPOSE (t); + a = TREE_PURPOSE (t); + } + /* More attrs can be linked here, move A to the end. */ + while (TREE_CHAIN (a) != NULL_TREE) + a = TREE_CHAIN (a); + } + } + + /* Terminate the lists. */ + if (s != NULL_TREE) + TREE_CHAIN (s) = NULL_TREE; + if (a != NULL_TREE) + TREE_CHAIN (a) = NULL_TREE; + + /* All done. */ + *declspecs = specs; + *prefix_attributes = attrs; +} + +/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes. + This function is used by the parser when a rule will accept attributes + in a particular position, but we don't want to support that just yet. + + A warning is issued for every ignored attribute. */ + +tree +strip_attrs (specs_attrs) + tree specs_attrs; +{ + tree specs, attrs; + + split_specs_attrs (specs_attrs, &specs, &attrs); + + while (attrs) + { + warning ("`%s' attribute ignored", + IDENTIFIER_POINTER (TREE_PURPOSE (attrs))); + attrs = TREE_CHAIN (attrs); + } + + return specs; +} + +/* Check a printf/fprintf/sprintf/scanf/fscanf/sscanf format against + a parameter list. */ + +#define T_I &integer_type_node +#define T_L &long_integer_type_node +#define T_LL &long_long_integer_type_node +#define T_S &short_integer_type_node +#define T_UI &unsigned_type_node +#define T_UL &long_unsigned_type_node +#define T_ULL &long_long_unsigned_type_node +#define T_US &short_unsigned_type_node +#define T_F &float_type_node +#define T_D &double_type_node +#define T_LD &long_double_type_node +#define T_C &char_type_node +#define T_UC &unsigned_char_type_node +#define T_V &void_type_node +#define T_W &wchar_type_node +#define T_ST &sizetype + +typedef struct { + const char *format_chars; + int pointer_count; + /* Type of argument if no length modifier is used. */ + tree *nolen; + /* Type of argument if length modifier for shortening to byte is used. + If NULL, then this modifier is not allowed. */ + tree *hhlen; + /* Type of argument if length modifier for shortening is used. + If NULL, then this modifier is not allowed. */ + tree *hlen; + /* Type of argument if length modifier `l' is used. + If NULL, then this modifier is not allowed. */ + tree *llen; + /* Type of argument if length modifier `q' or `ll' is used. + If NULL, then this modifier is not allowed. */ + tree *qlen; + /* Type of argument if length modifier `L' is used. + If NULL, then this modifier is not allowed. */ + tree *bigllen; + /* Type of argument if length modifier `Z' is used. + If NULL, then this modifier is not allowed. */ + tree *zlen; + /* List of other modifier characters allowed with these options. */ + const char *flag_chars; +} format_char_info; + +static format_char_info print_char_table[] = { + { "di", 0, T_I, T_I, T_I, T_L, T_LL, T_LL, T_ST, "-wp0 +" }, + { "oxX", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0#" }, + { "u", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0" }, +/* A GNU extension. */ + { "m", 0, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" }, + { "feEgGaA", 0, T_D, NULL, NULL, NULL, NULL, T_LD, NULL, "-wp0 +#" }, + { "c", 0, T_I, NULL, NULL, T_W, NULL, NULL, NULL, "-w" }, + { "C", 0, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "-w" }, + { "s", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "-wp" }, + { "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" }, + { "p", 1, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "-w" }, + { "n", 1, T_I, NULL, T_S, T_L, T_LL, NULL, NULL, "" }, + { NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +}; + +static format_char_info scan_char_table[] = { + { "di", 1, T_I, T_C, T_S, T_L, T_LL, T_LL, NULL, "*" }, + { "ouxX", 1, T_UI, T_UC, T_US, T_UL, T_ULL, T_ULL, NULL, "*" }, + { "efgEGaA", 1, T_F, NULL, NULL, T_D, NULL, T_LD, NULL, "*" }, + { "c", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "*" }, + { "s", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "*a" }, + { "[", 1, T_C, NULL, NULL, NULL, NULL, NULL, NULL, "*a" }, + { "C", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "*" }, + { "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "*a" }, + { "p", 2, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "*" }, + { "n", 1, T_I, T_C, T_S, T_L, T_LL, NULL, NULL, "" }, + { NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +}; + +/* Handle format characters recognized by glibc's strftime.c. + '2' - MUST do years as only two digits + '3' - MAY do years as only two digits (depending on locale) + 'E' - E modifier is acceptable + 'O' - O modifier is acceptable to Standard C + 'o' - O modifier is acceptable as a GNU extension + 'G' - other GNU extensions */ + +static format_char_info time_char_table[] = { + { "y", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2EO-_0w" }, + { "D", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2" }, + { "g", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2O-_0w" }, + { "cx", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "3E" }, + { "%RTXnrt", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "" }, + { "P", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "G" }, + { "HIMSUWdemw", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Ow" }, + { "Vju", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Oow" }, + { "Gklsz", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0OGw" }, + { "ABZa", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^#" }, + { "p", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "#" }, + { "bh", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^" }, + { "CY", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0EOw" }, + { NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +}; + +typedef struct function_format_info +{ + struct function_format_info *next; /* next structure on the list */ + tree name; /* identifier such as "printf" */ + tree assembler_name; /* optional mangled identifier (for C++) */ + enum format_type format_type; /* type of format (printf, scanf, etc.) */ + int format_num; /* number of format argument */ + int first_arg_num; /* number of first arg (zero for varargs) */ +} function_format_info; + +static function_format_info *function_format_list = NULL; + +typedef struct international_format_info +{ + struct international_format_info *next; /* next structure on the list */ + tree name; /* identifier such as "gettext" */ + tree assembler_name; /* optional mangled identifier (for C++) */ + int format_num; /* number of format argument */ +} international_format_info; + +static international_format_info *international_format_list = NULL; + +static void check_format_info PROTO((function_format_info *, tree)); + +/* Initialize the table of functions to perform format checking on. + The ANSI functions are always checked (whether is + included or not), since it is common to call printf without + including . There shouldn't be a problem with this, + since ANSI reserves these function names whether you include the + header file or not. In any case, the checking is harmless. + + Also initialize the name of function that modify the format string for + internationalization purposes. */ + +void +init_function_format_info () +{ + record_function_format (get_identifier ("printf"), NULL_TREE, + printf_format_type, 1, 2); + record_function_format (get_identifier ("fprintf"), NULL_TREE, + printf_format_type, 2, 3); + record_function_format (get_identifier ("sprintf"), NULL_TREE, + printf_format_type, 2, 3); + record_function_format (get_identifier ("scanf"), NULL_TREE, + scanf_format_type, 1, 2); + record_function_format (get_identifier ("fscanf"), NULL_TREE, + scanf_format_type, 2, 3); + record_function_format (get_identifier ("sscanf"), NULL_TREE, + scanf_format_type, 2, 3); + record_function_format (get_identifier ("vprintf"), NULL_TREE, + printf_format_type, 1, 0); + record_function_format (get_identifier ("vfprintf"), NULL_TREE, + printf_format_type, 2, 0); + record_function_format (get_identifier ("vsprintf"), NULL_TREE, + printf_format_type, 2, 0); +#ifndef NEXT_SEMANTICS /* Apple's strftime syntax not the same as glibc's! */ + record_function_format (get_identifier ("strftime"), NULL_TREE, + strftime_format_type, 3, 0); +#endif + + record_international_format (get_identifier ("gettext"), NULL_TREE, 1); + record_international_format (get_identifier ("dgettext"), NULL_TREE, 2); + record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2); +} + +/* Record information for argument format checking. FUNCTION_IDENT is + the identifier node for the name of the function to check (its decl + need not exist yet). + FORMAT_TYPE specifies the type of format checking. FORMAT_NUM is the number + of the argument which is the format control string (starting from 1). + FIRST_ARG_NUM is the number of the first actual argument to check + against the format string, or zero if no checking is not be done + (e.g. for varargs such as vfprintf). */ + +static void +record_function_format (name, assembler_name, format_type, + format_num, first_arg_num) + tree name; + tree assembler_name; + enum format_type format_type; + int format_num; + int first_arg_num; +{ + function_format_info *info; + + /* Re-use existing structure if it's there. */ + + for (info = function_format_list; info; info = info->next) + { + if (info->name == name && info->assembler_name == assembler_name) + break; + } + if (! info) + { + info = (function_format_info *) xmalloc (sizeof (function_format_info)); + info->next = function_format_list; + function_format_list = info; + + info->name = name; + info->assembler_name = assembler_name; + } + + info->format_type = format_type; + info->format_num = format_num; + info->first_arg_num = first_arg_num; +} + +/* Record information for the names of function that modify the format + argument to format functions. FUNCTION_IDENT is the identifier node for + the name of the function (its decl need not exist yet) and FORMAT_NUM is + the number of the argument which is the format control string (starting + from 1). */ + +static void +record_international_format (name, assembler_name, format_num) + tree name; + tree assembler_name; + int format_num; +{ + international_format_info *info; + + /* Re-use existing structure if it's there. */ + + for (info = international_format_list; info; info = info->next) + { + if (info->name == name && info->assembler_name == assembler_name) + break; + } + + if (! info) + { + info + = (international_format_info *) + xmalloc (sizeof (international_format_info)); + info->next = international_format_list; + international_format_list = info; + + info->name = name; + info->assembler_name = assembler_name; + } + + info->format_num = format_num; +} + +static void +tfaff () +{ + warning ("too few arguments for format"); +} + +/* Check the argument list of a call to printf, scanf, etc. + NAME is the function identifier. + ASSEMBLER_NAME is the function's assembler identifier. + (Either NAME or ASSEMBLER_NAME, but not both, may be NULL_TREE.) + PARAMS is the list of argument values. */ + +void +check_function_format (name, assembler_name, params) + tree name; + tree assembler_name; + tree params; +{ + function_format_info *info; + + /* See if this function is a format function. */ + for (info = function_format_list; info; info = info->next) + { + if (info->assembler_name + ? (info->assembler_name == assembler_name) + : (info->name == name)) + { + /* Yup; check it. */ + check_format_info (info, params); + break; + } + } +} + +/* Check the argument list of a call to printf, scanf, etc. + INFO points to the function_format_info structure. + PARAMS is the list of argument values. */ + +static void +check_format_info (info, params) + function_format_info *info; + tree params; +{ + int i; + int arg_num; + int suppressed, wide, precise; + int length_char = 0; + int format_char; + int format_length; + tree format_tree; + tree cur_param; + tree cur_type; + tree wanted_type; + tree first_fillin_param; + const char *format_chars; + format_char_info *fci = NULL; + char flag_chars[8]; + int has_operand_number = 0; + + /* Skip to format argument. If the argument isn't available, there's + no work for us to do; prototype checking will catch the problem. */ + for (arg_num = 1; ; ++arg_num) + { + if (params == 0) + return; + if (arg_num == info->format_num) + break; + params = TREE_CHAIN (params); + } + format_tree = TREE_VALUE (params); + params = TREE_CHAIN (params); + if (format_tree == 0) + return; + + /* We can only check the format if it's a string constant. */ + while (TREE_CODE (format_tree) == NOP_EXPR) + format_tree = TREE_OPERAND (format_tree, 0); /* strip coercion */ + + if (TREE_CODE (format_tree) == CALL_EXPR + && TREE_CODE (TREE_OPERAND (format_tree, 0)) == ADDR_EXPR + && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0)) + == FUNCTION_DECL)) + { + tree function = TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0); + + /* See if this is a call to a known internationalization function + that modifies the format arg. */ + international_format_info *info; + + for (info = international_format_list; info; info = info->next) + if (info->assembler_name + ? (info->assembler_name == DECL_ASSEMBLER_NAME (function)) + : (info->name == DECL_NAME (function))) + { + tree inner_args; + int i; + + for (inner_args = TREE_OPERAND (format_tree, 1), i = 1; + inner_args != 0; + inner_args = TREE_CHAIN (inner_args), i++) + if (i == info->format_num) + { + format_tree = TREE_VALUE (inner_args); + + while (TREE_CODE (format_tree) == NOP_EXPR) + format_tree = TREE_OPERAND (format_tree, 0); + } + } + } + + if (integer_zerop (format_tree)) + { + warning ("null format string"); + return; + } + if (TREE_CODE (format_tree) != ADDR_EXPR) + return; + format_tree = TREE_OPERAND (format_tree, 0); + if (TREE_CODE (format_tree) != STRING_CST) + return; + format_chars = TREE_STRING_POINTER (format_tree); + format_length = TREE_STRING_LENGTH (format_tree); + if (format_length <= 1) + warning ("zero-length format string"); + if (format_chars[--format_length] != 0) + { + warning ("unterminated format string"); + return; + } + /* Skip to first argument to check. */ + while (arg_num + 1 < info->first_arg_num) + { + if (params == 0) + return; + params = TREE_CHAIN (params); + ++arg_num; + } + + first_fillin_param = params; + while (1) + { + int aflag; + if (*format_chars == 0) + { + if (format_chars - TREE_STRING_POINTER (format_tree) != format_length) + warning ("embedded `\\0' in format"); + if (info->first_arg_num != 0 && params != 0 && ! has_operand_number) + warning ("too many arguments for format"); + return; + } + if (*format_chars++ != '%') + continue; + if (*format_chars == 0) + { + warning ("spurious trailing `%%' in format"); + continue; + } + if (*format_chars == '%') + { + ++format_chars; + continue; + } + flag_chars[0] = 0; + suppressed = wide = precise = FALSE; + if (info->format_type == scanf_format_type) + { + suppressed = *format_chars == '*'; + if (suppressed) + ++format_chars; + while (ISDIGIT (*format_chars)) + ++format_chars; + } + else if (info->format_type == strftime_format_type) + { + while (*format_chars != 0 && index ("_-0^#", *format_chars) != 0) + { + if (pedantic) + warning ("ANSI C does not support the strftime `%c' flag", + *format_chars); + if (index (flag_chars, *format_chars) != 0) + { + warning ("repeated `%c' flag in format", + *format_chars); + ++format_chars; + } + else + { + i = strlen (flag_chars); + flag_chars[i++] = *format_chars++; + flag_chars[i] = 0; + } + } + while (ISDIGIT ((unsigned char) *format_chars)) + { + wide = TRUE; + ++format_chars; + } + if (wide && pedantic) + warning ("ANSI C does not support strftime format width"); + if (*format_chars == 'E' || *format_chars == 'O') + { + i = strlen (flag_chars); + flag_chars[i++] = *format_chars++; + flag_chars[i] = 0; + if (*format_chars == 'E' || *format_chars == 'O') + { + warning ("multiple E/O modifiers in format"); + while (*format_chars == 'E' || *format_chars == 'O') + ++format_chars; + } + } + } + else if (info->format_type == printf_format_type) + { + /* See if we have a number followed by a dollar sign. If we do, + it is an operand number, so set PARAMS to that operand. */ + if (*format_chars >= '0' && *format_chars <= '9') + { + const char *p = format_chars; + + while (*p >= '0' && *p++ <= '9') + ; + + if (*p == '$') + { + int opnum = atoi (format_chars); + + params = first_fillin_param; + format_chars = p + 1; + has_operand_number = 1; + + for (i = 1; i < opnum && params != 0; i++) + params = TREE_CHAIN (params); + + if (opnum == 0 || params == 0) + { + warning ("operand number out of range in format"); + return; + } + } + } + + while (*format_chars != 0 && index (" +#0-", *format_chars) != 0) + { + if (index (flag_chars, *format_chars) != 0) + warning ("repeated `%c' flag in format", *format_chars++); + else + { + i = strlen (flag_chars); + flag_chars[i++] = *format_chars++; + flag_chars[i] = 0; + } + } + /* "If the space and + flags both appear, + the space flag will be ignored." */ + if (index (flag_chars, ' ') != 0 + && index (flag_chars, '+') != 0) + warning ("use of both ` ' and `+' flags in format"); + /* "If the 0 and - flags both appear, + the 0 flag will be ignored." */ + if (index (flag_chars, '0') != 0 + && index (flag_chars, '-') != 0) + warning ("use of both `0' and `-' flags in format"); + if (*format_chars == '*') + { + wide = TRUE; + /* "...a field width...may be indicated by an asterisk. + In this case, an int argument supplies the field width..." */ + ++format_chars; + if (params == 0) + { + tfaff (); + return; + } + if (info->first_arg_num != 0) + { + cur_param = TREE_VALUE (params); + params = TREE_CHAIN (params); + ++arg_num; + /* size_t is generally not valid here. + It will work on most machines, because size_t and int + have the same mode. But might as well warn anyway, + since it will fail on other machines. */ + if ((TYPE_MAIN_VARIANT (TREE_TYPE (cur_param)) + != integer_type_node) + && + (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param)) + != unsigned_type_node)) + warning ("field width is not type int (arg %d)", arg_num); + } + } + else + { + while (ISDIGIT (*format_chars)) + { + wide = TRUE; + ++format_chars; + } + } + if (*format_chars == '.') + { + precise = TRUE; + ++format_chars; + if (*format_chars != '*' && !ISDIGIT (*format_chars)) + warning ("`.' not followed by `*' or digit in format"); + /* "...a...precision...may be indicated by an asterisk. + In this case, an int argument supplies the...precision." */ + if (*format_chars == '*') + { + if (info->first_arg_num != 0) + { + ++format_chars; + if (params == 0) + { + tfaff (); + return; + } + cur_param = TREE_VALUE (params); + params = TREE_CHAIN (params); + ++arg_num; + if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param)) + != integer_type_node) + warning ("field width is not type int (arg %d)", + arg_num); + } + } + else + { + while (ISDIGIT (*format_chars)) + ++format_chars; + } + } + } + if (*format_chars == 'h' || *format_chars == 'l') + length_char = *format_chars++; + else if (*format_chars == 'q' || *format_chars == 'L') + { + length_char = *format_chars++; + if (pedantic) + pedwarn ("ANSI C does not support the `%c' length modifier", + length_char); + } + else + length_char = 0; + if (length_char == 'l' && *format_chars == 'l') + { + length_char = 'q', format_chars++; + if (pedantic) + pedwarn ("ANSI C does not support the `ll' length modifier"); + } + + aflag = 0; + + if (info->format_type != strftime_format_type) + { + if (*format_chars == 'h' || *format_chars == 'l') + length_char = *format_chars++; + else if (*format_chars == 'q' || *format_chars == 'L') + { + length_char = *format_chars++; + if (pedantic) + warning ("ANSI C does not support the `%c' length modifier", + length_char); + } + else if (*format_chars == 'Z') + { + length_char = *format_chars++; + if (pedantic) + warning ("ANSI C does not support the `Z' length modifier"); + } +#if !defined (NEXT_SEMANTICS) && !defined (NEXT_PDO) /* Otherwise, %ld does not match long int. */ + else + length_char = 0; +#endif + if (length_char == 'l' && *format_chars == 'l') + { + length_char = 'q', format_chars++; + /* FIXME: Is allowed in ISO C 9x. */ + if (pedantic) + warning ("ANSI C does not support the `ll' length modifier"); + } + else if (length_char == 'h' && *format_chars == 'h') + { + length_char = 'H', format_chars++; + /* FIXME: Is allowed in ISO C 9x. */ + if (pedantic) + warning ("ANSI C does not support the `hh' length modifier"); + } + if (*format_chars == 'a' && info->format_type == scanf_format_type) + { + if (format_chars[1] == 's' || format_chars[1] == 'S' + || format_chars[1] == '[') + { + /* `a' is used as a flag. */ + aflag = 1; + format_chars++; + } + } + if (suppressed && length_char != 0) + warning ("use of `*' and `%c' together in format", length_char); + } + format_char = *format_chars; + if (format_char == 0 + || (info->format_type != strftime_format_type && format_char == '%')) + { + warning ("conversion lacks type at end of format"); + continue; + } + /* The m, C, and S formats are GNU extensions. */ + if (pedantic && info->format_type != strftime_format_type + && (format_char == 'm' || format_char == 'C' || format_char == 'S')) + warning ("ANSI C does not support the `%c' format", format_char); + /* ??? The a and A formats are C9X extensions, and should be allowed + when a C9X option is added. */ + if (pedantic && info->format_type != strftime_format_type + && (format_char == 'a' || format_char == 'A')) + warning ("ANSI C does not support the `%c' format", format_char); + format_chars++; + switch (info->format_type) + { + case printf_format_type: + fci = print_char_table; + break; + case scanf_format_type: + fci = scan_char_table; + break; + case strftime_format_type: + fci = time_char_table; + break; + default: + abort (); + } + while (fci->format_chars != 0 + && index (fci->format_chars, format_char) == 0) + ++fci; + if (fci->format_chars == 0) + { + if (format_char >= 040 && format_char < 0177) + warning ("unknown conversion type character `%c' in format", + format_char); + else + warning ("unknown conversion type character 0x%x in format", + format_char); + continue; + } + if (pedantic) + { + if (index (fci->flag_chars, 'G') != 0) + warning ("ANSI C does not support `%%%c'", format_char); + if (index (fci->flag_chars, 'o') != 0 + && index (flag_chars, 'O') != 0) + warning ("ANSI C does not support `%%O%c'", format_char); + } + if (wide && index (fci->flag_chars, 'w') == 0) + warning ("width used with `%c' format", format_char); + if (index (fci->flag_chars, '2') != 0) + warning ("`%%%c' yields only last 2 digits of year", format_char); + else if (index (fci->flag_chars, '3') != 0) + warning ("`%%%c' yields only last 2 digits of year in some locales", + format_char); + if (precise && index (fci->flag_chars, 'p') == 0) + warning ("precision used with `%c' format", format_char); + if (aflag && index (fci->flag_chars, 'a') == 0) + { + warning ("`a' flag used with `%c' format", format_char); + /* To simplify the following code. */ + aflag = 0; + } + /* The a flag is a GNU extension. */ + else if (pedantic && aflag) + warning ("ANSI C does not support the `a' flag"); + if (info->format_type == scanf_format_type && format_char == '[') + { + /* Skip over scan set, in case it happens to have '%' in it. */ + if (*format_chars == '^') + ++format_chars; + /* Find closing bracket; if one is hit immediately, then + it's part of the scan set rather than a terminator. */ + if (*format_chars == ']') + ++format_chars; + while (*format_chars && *format_chars != ']') + ++format_chars; + if (*format_chars != ']') + /* The end of the format string was reached. */ + warning ("no closing `]' for `%%[' format"); + } + if (suppressed) + { + if (index (fci->flag_chars, '*') == 0) + warning ("suppression of `%c' conversion in format", format_char); + continue; + } + for (i = 0; flag_chars[i] != 0; ++i) + { + if (index (fci->flag_chars, flag_chars[i]) == 0) + warning ("flag `%c' used with type `%c'", + flag_chars[i], format_char); + } + if (info->format_type == strftime_format_type) + continue; + if (precise && index (flag_chars, '0') != 0 + && (format_char == 'd' || format_char == 'i' + || format_char == 'o' || format_char == 'u' + || format_char == 'x' || format_char == 'X')) + warning ("`0' flag ignored with precision specifier and `%c' format", + format_char); + switch (length_char) + { + default: wanted_type = fci->nolen ? *(fci->nolen) : 0; break; + case 'H': wanted_type = fci->hhlen ? *(fci->hhlen) : 0; break; + case 'h': wanted_type = fci->hlen ? *(fci->hlen) : 0; break; + case 'l': wanted_type = fci->llen ? *(fci->llen) : 0; break; + case 'q': wanted_type = fci->qlen ? *(fci->qlen) : 0; break; + case 'L': wanted_type = fci->bigllen ? *(fci->bigllen) : 0; break; + case 'Z': wanted_type = fci->zlen ? *fci->zlen : 0; break; + } + if (wanted_type == 0) + warning ("use of `%c' length character with `%c' type character", + length_char, format_char); + + /* Finally. . .check type of argument against desired type! */ + if (info->first_arg_num == 0) + continue; + if (fci->pointer_count == 0 && wanted_type == void_type_node) + /* This specifier takes no argument. */ + continue; + if (params == 0) + { + tfaff (); + return; + } + cur_param = TREE_VALUE (params); + params = TREE_CHAIN (params); + ++arg_num; + cur_type = TREE_TYPE (cur_param); + + STRIP_NOPS (cur_param); + + /* Check the types of any additional pointer arguments + that precede the "real" argument. */ + for (i = 0; i < fci->pointer_count + aflag; ++i) + { + if (TREE_CODE (cur_type) == POINTER_TYPE) + { + cur_type = TREE_TYPE (cur_type); + + if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR) + cur_param = TREE_OPERAND (cur_param, 0); + else + cur_param = 0; + + continue; + } + if (TREE_CODE (cur_type) != ERROR_MARK) + warning ((fci->pointer_count + aflag == 1 + ? "format argument is not a pointer (arg %d)" + : "format argument is not a pointer to a pointer (arg %d)"), + arg_num); + break; + } + + /* See if this is an attempt to write into a const type with + scanf or with printf "%n". */ + if ((info->format_type == scanf_format_type + || (info->format_type == printf_format_type + && format_char == 'n')) + && i == fci->pointer_count + aflag + && wanted_type != 0 + && TREE_CODE (cur_type) != ERROR_MARK + && (TYPE_READONLY (cur_type) + || (cur_param != 0 + && (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'c' + || (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'd' + && TREE_READONLY (cur_param)))))) + warning ("writing into constant object (arg %d)", arg_num); + + /* Check the type of the "real" argument, if there's a type we want. */ + if (i == fci->pointer_count + aflag && wanted_type != 0 + && TREE_CODE (cur_type) != ERROR_MARK + && wanted_type != TYPE_MAIN_VARIANT (cur_type) + /* If we want `void *', allow any pointer type. + (Anything else would already have got a warning.) */ + && ! (wanted_type == void_type_node + && fci->pointer_count > 0) + /* Don't warn about differences merely in signedness. */ + && !(TREE_CODE (wanted_type) == INTEGER_TYPE + && TREE_CODE (TYPE_MAIN_VARIANT (cur_type)) == INTEGER_TYPE + && (TREE_UNSIGNED (wanted_type) + ? wanted_type == (cur_type = unsigned_type (cur_type)) + : wanted_type == (cur_type = signed_type (cur_type)))) + /* Likewise, "signed char", "unsigned char" and "char" are + equivalent but the above test won't consider them equivalent. */ + && ! (wanted_type == char_type_node + && (TYPE_MAIN_VARIANT (cur_type) == signed_char_type_node + || TYPE_MAIN_VARIANT (cur_type) == unsigned_char_type_node))) + { + register const char *this; + register const char *that; + + this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type))); + that = 0; + if (TREE_CODE (cur_type) != ERROR_MARK + && TYPE_NAME (cur_type) != 0 + && TREE_CODE (cur_type) != INTEGER_TYPE + && !(TREE_CODE (cur_type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (cur_type)) == INTEGER_TYPE)) + { + if (TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (cur_type)) != 0) + that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type))); + else + that = IDENTIFIER_POINTER (TYPE_NAME (cur_type)); + } + + /* A nameless type can't possibly match what the format wants. + So there will be a warning for it. + Make up a string to describe vaguely what it is. */ + if (that == 0) + { + if (TREE_CODE (cur_type) == POINTER_TYPE) + that = "pointer"; + else + that = "different type"; + } + + /* Make the warning better in case of mismatch of int vs long. */ + if (TREE_CODE (cur_type) == INTEGER_TYPE + && TREE_CODE (wanted_type) == INTEGER_TYPE + && TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type) + && TYPE_NAME (cur_type) != 0 + && TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL) + that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type))); + + if (strcmp (this, that) != 0) + warning ("%s format, %s arg (arg %d)", this, that, arg_num); + } + } +} + +/* Print a warning if a constant expression had overflow in folding. + Invoke this function on every expression that the language + requires to be a constant expression. + Note the ANSI C standard says it is erroneous for a + constant expression to overflow. */ + +void +constant_expression_warning (value) + tree value; +{ + if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST + || TREE_CODE (value) == COMPLEX_CST || TREE_CODE (value) == VECTOR_CST) + && TREE_CONSTANT_OVERFLOW (value) && pedantic) + pedwarn ("overflow in constant expression"); +} + +/* Print a warning if an expression had overflow in folding. + Invoke this function on every expression that + (1) appears in the source code, and + (2) might be a constant expression that overflowed, and + (3) is not already checked by convert_and_check; + however, do not invoke this function on operands of explicit casts. */ + +void +overflow_warning (value) + tree value; +{ + if ((TREE_CODE (value) == INTEGER_CST + || (TREE_CODE (value) == COMPLEX_CST + && TREE_CODE (TREE_REALPART (value)) == INTEGER_CST)) + && TREE_OVERFLOW (value)) + { + TREE_OVERFLOW (value) = 0; + if (skip_evaluation == 0) + warning ("integer overflow in expression"); + } + else if ((TREE_CODE (value) == REAL_CST + || (TREE_CODE (value) == COMPLEX_CST + && TREE_CODE (TREE_REALPART (value)) == REAL_CST)) + && TREE_OVERFLOW (value)) + { + TREE_OVERFLOW (value) = 0; + if (skip_evaluation == 0) + warning ("floating point overflow in expression"); + } + else if (TREE_CODE (value) == VECTOR_CST && TREE_OVERFLOW (value)) + { + TREE_OVERFLOW (value) = 0; + if (skip_evaluation == 0) + warning ("vector overflow in expression"); + } +} + +/* Print a warning if a large constant is truncated to unsigned, + or if -Wconversion is used and a constant < 0 is converted to unsigned. + Invoke this function on every expression that might be implicitly + converted to an unsigned type. */ + +void +unsigned_conversion_warning (result, operand) + tree result, operand; +{ + if (TREE_CODE (operand) == INTEGER_CST + && TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE + && TREE_UNSIGNED (TREE_TYPE (result)) + && skip_evaluation == 0 + && !int_fits_type_p (operand, TREE_TYPE (result))) + { + if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result)))) + /* This detects cases like converting -129 or 256 to unsigned char. */ + warning ("large integer implicitly truncated to unsigned type"); + else if (warn_conversion) + warning ("negative integer implicitly converted to unsigned type"); + } +} + +/* Convert EXPR to TYPE, warning about conversion problems with constants. + Invoke this function on every expression that is converted implicitly, + i.e. because of language rules and not because of an explicit cast. */ + +tree +convert_and_check (type, expr) + tree type, expr; +{ + tree t = convert (type, expr); + if (TREE_CODE (t) == INTEGER_CST) + { + if (TREE_OVERFLOW (t)) + { + TREE_OVERFLOW (t) = 0; + + /* Do not diagnose overflow in a constant expression merely + because a conversion overflowed. */ + TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (expr); + + /* No warning for converting 0x80000000 to int. */ + if (!(TREE_UNSIGNED (type) < TREE_UNSIGNED (TREE_TYPE (expr)) + && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE + && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (expr)))) + /* If EXPR fits in the unsigned version of TYPE, + don't warn unless pedantic. */ + if ((pedantic + || TREE_UNSIGNED (type) + || ! int_fits_type_p (expr, unsigned_type (type))) + && skip_evaluation == 0) + warning ("overflow in implicit constant conversion"); + } + else + unsigned_conversion_warning (t, expr); + } + return t; +} + +void +c_expand_expr_stmt (expr) + tree expr; +{ + /* Do default conversion if safe and possibly important, + in case within ({...}). */ + if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr)) + || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE) + expr = default_conversion (expr); + + if (TREE_TYPE (expr) != error_mark_node + && TYPE_SIZE (TREE_TYPE (expr)) == 0 + && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE) + error ("expression statement has incomplete type"); + + expand_expr_stmt (expr); +} + +/* Validate the expression after `case' and apply default promotions. */ + +tree +check_case_value (value) + tree value; +{ + if (value == NULL_TREE) + return value; + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (value); + + if (TREE_CODE (value) != INTEGER_CST + && value != error_mark_node) + { + error ("case label does not reduce to an integer constant"); + value = error_mark_node; + } + else + /* Promote char or short to int. */ + value = default_conversion (value); + + constant_expression_warning (value); + + return value; +} + +/* Return an integer type with BITS bits of precision, + that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ + +#ifndef __GNUFORTRAN__ +tree +type_for_size (bits, unsignedp) + unsigned bits; + int unsignedp; +{ + if (bits == TYPE_PRECISION (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (bits == TYPE_PRECISION (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + + if (bits == TYPE_PRECISION (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + + if (bits == TYPE_PRECISION (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (bits == TYPE_PRECISION (long_long_integer_type_node)) + return (unsignedp ? long_long_unsigned_type_node + : long_long_integer_type_node); + + if (bits <= TYPE_PRECISION (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + + if (bits <= TYPE_PRECISION (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + + if (bits <= TYPE_PRECISION (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + + if (bits <= TYPE_PRECISION (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + + return 0; +} + +/* Return a data type that has machine mode MODE. + If the mode is an integer, + then UNSIGNEDP selects between signed and unsigned types. */ + +tree +type_for_mode (mode, unsignedp) + enum machine_mode mode; + int unsignedp; +{ + if (mode == TYPE_MODE (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (mode == TYPE_MODE (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + + if (mode == TYPE_MODE (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + + if (mode == TYPE_MODE (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (mode == TYPE_MODE (long_long_integer_type_node)) + return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node; + + if (mode == TYPE_MODE (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + + if (mode == TYPE_MODE (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + + if (mode == TYPE_MODE (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + + if (mode == TYPE_MODE (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + +#if HOST_BITS_PER_WIDE_INT >= 64 + if (mode == TYPE_MODE (intTI_type_node)) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; +#endif + + if (mode == TYPE_MODE (float_type_node)) + return float_type_node; + + if (mode == TYPE_MODE (double_type_node)) + return double_type_node; + + if (mode == TYPE_MODE (long_double_type_node)) + return long_double_type_node; + + if (mode == TYPE_MODE (build_pointer_type (char_type_node))) + return build_pointer_type (char_type_node); + + if (mode == TYPE_MODE (build_pointer_type (integer_type_node))) + return build_pointer_type (integer_type_node); + + return 0; +} +#endif + + +/* Return the minimum number of bits needed to represent VALUE in a + signed or unsigned type, UNSIGNEDP says which. */ + +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; +} + +/* Print an error message for invalid operands to arith operation CODE. + NOP_EXPR is used as a special case (see truthvalue_conversion). */ + +void +binary_op_error (code) + enum tree_code code; +{ + register const char *opname; + + switch (code) + { + case NOP_EXPR: + error ("invalid truth-value expression"); + return; + + case PLUS_EXPR: + opname = "+"; break; + case MINUS_EXPR: + opname = "-"; break; + case MULT_EXPR: + opname = "*"; break; + case MAX_EXPR: + opname = "max"; break; + case MIN_EXPR: + opname = "min"; break; + case EQ_EXPR: + opname = "=="; break; + case NE_EXPR: + opname = "!="; break; + case LE_EXPR: + opname = "<="; break; + case GE_EXPR: + opname = ">="; break; + case LT_EXPR: + opname = "<"; break; + case GT_EXPR: + opname = ">"; break; + case LSHIFT_EXPR: + opname = "<<"; break; + case RSHIFT_EXPR: + opname = ">>"; break; + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: + opname = "%"; break; + case TRUNC_DIV_EXPR: + case FLOOR_DIV_EXPR: + opname = "/"; break; + case BIT_AND_EXPR: + opname = "&"; break; + case BIT_IOR_EXPR: + opname = "|"; break; + case TRUTH_ANDIF_EXPR: + opname = "&&"; break; + case TRUTH_ORIF_EXPR: + opname = "||"; break; + case BIT_XOR_EXPR: + opname = "^"; break; + case LROTATE_EXPR: + case RROTATE_EXPR: + opname = "rotate"; break; + default: + opname = "unknown"; break; + } + error ("invalid operands to binary %s", opname); +} + +/* Subroutine of build_binary_op, used for comparison operations. + See if the operands have both been converted from subword integer types + and, if so, perhaps change them both back to their original type. + This function is also responsible for converting the two operands + to the proper common type for comparison. + + The arguments of this function are all pointers to local variables + of build_binary_op: OP0_PTR is &OP0, OP1_PTR is &OP1, + RESTYPE_PTR is &RESULT_TYPE and RESCODE_PTR is &RESULTCODE. + + If this function returns nonzero, it means that the comparison has + a constant value. What this function returns is an expression for + that value. */ + +tree +shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr) + tree *op0_ptr, *op1_ptr; + tree *restype_ptr; + enum tree_code *rescode_ptr; +{ + register tree type; + tree op0 = *op0_ptr; + tree op1 = *op1_ptr; + int unsignedp0, unsignedp1; + int real1, real2; + tree primop0, primop1; + enum tree_code code = *rescode_ptr; + + /* Throw away any conversions to wider types + already present in the operands. */ + + primop0 = get_narrower (op0, &unsignedp0); + primop1 = get_narrower (op1, &unsignedp1); + + /* Handle the case that OP0 does not *contain* a conversion + but it *requires* conversion to FINAL_TYPE. */ + + if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr) + unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0)); + if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr) + unsignedp1 = TREE_UNSIGNED (TREE_TYPE (op1)); + + /* If one of the operands must be floated, we cannot optimize. */ + real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE; + real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE; + + /* If first arg is constant, swap the args (changing operation + so value is preserved), for canonicalization. Don't do this if + the second arg is 0. */ + + if (TREE_CONSTANT (primop0) + && ! integer_zerop (primop1) && ! real_zerop (primop1)) + { + register tree tem = primop0; + register int temi = unsignedp0; + primop0 = primop1; + primop1 = tem; + tem = op0; + op0 = op1; + op1 = tem; + *op0_ptr = op0; + *op1_ptr = op1; + unsignedp0 = unsignedp1; + unsignedp1 = temi; + temi = real1; + real1 = real2; + real2 = temi; + + switch (code) + { + case LT_EXPR: + code = GT_EXPR; + break; + case GT_EXPR: + code = LT_EXPR; + break; + case LE_EXPR: + code = GE_EXPR; + break; + case GE_EXPR: + code = LE_EXPR; + break; + default: + break; + } + *rescode_ptr = code; + } + + /* If comparing an integer against a constant more bits wide, + maybe we can deduce a value of 1 or 0 independent of the data. + Or else truncate the constant now + rather than extend the variable at run time. + + This is only interesting if the constant is the wider arg. + Also, it is not safe if the constant is unsigned and the + variable arg is signed, since in this case the variable + would be sign-extended and then regarded as unsigned. + Our technique fails in this case because the lowest/highest + possible unsigned results don't follow naturally from the + lowest/highest possible values of the variable operand. + For just EQ_EXPR and NE_EXPR there is another technique that + could be used: see if the constant can be faithfully represented + in the other operand's type, by truncating it and reextending it + and see if that preserves the constant's value. */ + + if (!real1 && !real2 + && TREE_CODE (primop1) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)) + { + int min_gt, max_gt, min_lt, max_lt; + tree maxval, minval; + /* 1 if comparison is nominally unsigned. */ + int unsignedp = TREE_UNSIGNED (*restype_ptr); + tree val; + + type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)); + + /* If TYPE is an enumeration, then we need to get its min/max + values from it's underlying integral type, not the enumerated + type itself. */ + if (TREE_CODE (type) == ENUMERAL_TYPE) + type = type_for_size (TYPE_PRECISION (type), unsignedp0); + + maxval = TYPE_MAX_VALUE (type); + minval = TYPE_MIN_VALUE (type); + + if (unsignedp && !unsignedp0) + *restype_ptr = signed_type (*restype_ptr); + + if (TREE_TYPE (primop1) != *restype_ptr) + primop1 = convert (*restype_ptr, primop1); + if (type != *restype_ptr) + { + minval = convert (*restype_ptr, minval); + maxval = convert (*restype_ptr, maxval); + } + + if (unsignedp && unsignedp0) + { + min_gt = INT_CST_LT_UNSIGNED (primop1, minval); + max_gt = INT_CST_LT_UNSIGNED (primop1, maxval); + min_lt = INT_CST_LT_UNSIGNED (minval, primop1); + max_lt = INT_CST_LT_UNSIGNED (maxval, primop1); + } + else + { + min_gt = INT_CST_LT (primop1, minval); + max_gt = INT_CST_LT (primop1, maxval); + min_lt = INT_CST_LT (minval, primop1); + max_lt = INT_CST_LT (maxval, primop1); + } + + val = 0; + /* This used to be a switch, but Genix compiler can't handle that. */ + if (code == NE_EXPR) + { + if (max_lt || min_gt) + val = boolean_true_node; + } + else if (code == EQ_EXPR) + { + if (max_lt || min_gt) + val = boolean_false_node; + } + else if (code == LT_EXPR) + { + if (max_lt) + val = boolean_true_node; + if (!min_lt) + val = boolean_false_node; + } + else if (code == GT_EXPR) + { + if (min_gt) + val = boolean_true_node; + if (!max_gt) + val = boolean_false_node; + } + else if (code == LE_EXPR) + { + if (!max_gt) + val = boolean_true_node; + if (min_gt) + val = boolean_false_node; + } + else if (code == GE_EXPR) + { + if (!min_lt) + val = boolean_true_node; + if (max_lt) + val = boolean_false_node; + } + + /* If primop0 was sign-extended and unsigned comparison specd, + we did a signed comparison above using the signed type bounds. + But the comparison we output must be unsigned. + + Also, for inequalities, VAL is no good; but if the signed + comparison had *any* fixed result, it follows that the + unsigned comparison just tests the sign in reverse + (positive values are LE, negative ones GE). + So we can generate an unsigned comparison + against an extreme value of the signed type. */ + + if (unsignedp && !unsignedp0) + { + if (val != 0) + switch (code) + { + case LT_EXPR: + case GE_EXPR: + primop1 = TYPE_MIN_VALUE (type); + val = 0; + break; + + case LE_EXPR: + case GT_EXPR: + primop1 = TYPE_MAX_VALUE (type); + val = 0; + break; + + default: + break; + } + type = unsigned_type (type); + } + + if (!max_gt && !unsignedp0 && TREE_CODE (primop0) != INTEGER_CST) + { + /* This is the case of (char)x >?< 0x80, which people used to use + expecting old C compilers to change the 0x80 into -0x80. */ + if (val == boolean_false_node) + warning ("comparison is always false due to limited range of data type"); + if (val == boolean_true_node) + warning ("comparison is always true due to limited range of data type"); + } + + if (!min_lt && unsignedp0 && TREE_CODE (primop0) != INTEGER_CST) + { + /* This is the case of (unsigned char)x >?< -1 or < 0. */ + if (val == boolean_false_node) + warning ("comparison is always false due to limited range of data type"); + if (val == boolean_true_node) + warning ("comparison is always true due to limited range of data type"); + } + + if (val != 0) + { + /* Don't forget to evaluate PRIMOP0 if it has side effects. */ + if (TREE_SIDE_EFFECTS (primop0)) + return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val); + return val; + } + + /* Value is not predetermined, but do the comparison + in the type of the operand that is not constant. + TYPE is already properly set. */ + } + else if (real1 && real2 + && (TYPE_PRECISION (TREE_TYPE (primop0)) + == TYPE_PRECISION (TREE_TYPE (primop1)))) + type = TREE_TYPE (primop0); + + /* If args' natural types are both narrower than nominal type + and both extend in the same manner, compare them + in the type of the wider arg. + Otherwise must actually extend both to the nominal + common type lest different ways of extending + alter the result. + (eg, (short)-1 == (unsigned short)-1 should be 0.) */ + + else if (unsignedp0 == unsignedp1 && real1 == real2 + && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr) + && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)) + { + type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)); + type = signed_or_unsigned_type (unsignedp0 + || TREE_UNSIGNED (*restype_ptr), + type); + /* Make sure shorter operand is extended the right way + to match the longer operand. */ + primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)), + primop0); + primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)), + primop1); + } + else + { + /* Here we must do the comparison on the nominal type + using the args exactly as we received them. */ + type = *restype_ptr; + primop0 = op0; + primop1 = op1; + + if (!real1 && !real2 && integer_zerop (primop1) + && TREE_UNSIGNED (*restype_ptr)) + { + tree value = 0; + switch (code) + { + case GE_EXPR: + /* All unsigned values are >= 0, so we warn if extra warnings + are requested. However, if OP0 is a constant that is + >= 0, the signedness of the comparison isn't an issue, + so suppress the warning. */ + if (extra_warnings + && ! (TREE_CODE (primop0) == INTEGER_CST + && ! TREE_OVERFLOW (convert (signed_type (type), + primop0)))) + warning ("comparison of unsigned expression >= 0 is always true"); + value = boolean_true_node; + break; + + case LT_EXPR: + if (extra_warnings + && ! (TREE_CODE (primop0) == INTEGER_CST + && ! TREE_OVERFLOW (convert (signed_type (type), + primop0)))) + warning ("comparison of unsigned expression < 0 is always false"); + value = boolean_false_node; + break; + + default: + break; + } + + if (value != 0) + { + /* Don't forget to evaluate PRIMOP0 if it has side effects. */ + if (TREE_SIDE_EFFECTS (primop0)) + return build (COMPOUND_EXPR, TREE_TYPE (value), + primop0, value); + return value; + } + } + } + + *op0_ptr = convert (type, primop0); + *op1_ptr = convert (type, primop1); + + *restype_ptr = boolean_type_node; + + return 0; +} + +/* Prepare expr to be an argument of a TRUTH_NOT_EXPR, + or validate its data type for an `if' or `while' statement or ?..: exp. + + This preparation consists of taking the ordinary + representation of an expression expr and producing a valid tree + boolean expression describing whether expr is nonzero. We could + simply always do build_binary_op (NE_EXPR, expr, boolean_false_node, 1), + but we optimize comparisons, &&, ||, and !. + + The resulting type should always be `boolean_type_node'. */ + +#ifndef __GNUFORTRAN__ +tree +truthvalue_conversion (expr) + tree expr; +{ + if (TREE_CODE (expr) == ERROR_MARK) + return expr; + +#if 0 /* This appears to be wrong for C++. */ + /* These really should return error_mark_node after 2.4 is stable. + But not all callers handle ERROR_MARK properly. */ + switch (TREE_CODE (TREE_TYPE (expr))) + { + case RECORD_TYPE: + error ("struct type value used where scalar is required"); + return boolean_false_node; + + case UNION_TYPE: + error ("union type value used where scalar is required"); + return boolean_false_node; + + case ARRAY_TYPE: + error ("array type value used where scalar is required"); + return boolean_false_node; + + default: + break; + } +#endif /* 0 */ + + switch (TREE_CODE (expr)) + { + /* It is simpler and generates better code to have only TRUTH_*_EXPR + or comparison expressions as truth values at this level. */ +#if 0 + case COMPONENT_REF: + /* A one-bit unsigned bit-field is already acceptable. */ + if (1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1))) + && TREE_UNSIGNED (TREE_OPERAND (expr, 1))) + return expr; + break; +#endif + + case EQ_EXPR: + /* It is simpler and generates better code to have only TRUTH_*_EXPR + or comparison expressions as truth values at this level. */ +#if 0 + if (integer_zerop (TREE_OPERAND (expr, 1))) + return build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (expr, 0), 0); +#endif + case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + case TRUTH_NOT_EXPR: + TREE_TYPE (expr) = boolean_type_node; + return expr; + + case ERROR_MARK: + return expr; + + case INTEGER_CST: + return integer_zerop (expr) ? boolean_false_node : boolean_true_node; + + case REAL_CST: + return real_zerop (expr) ? boolean_false_node : boolean_true_node; + + case ADDR_EXPR: + /* If we are taking the address of a external decl, it might be zero + if it is weak, so we cannot optimize. */ + if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (expr, 0))) == 'd' + && DECL_EXTERNAL (TREE_OPERAND (expr, 0))) + break; + + if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0))) + return build (COMPOUND_EXPR, boolean_type_node, + TREE_OPERAND (expr, 0), boolean_true_node); + else + return boolean_true_node; + + case COMPLEX_EXPR: + return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)) + ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), + truthvalue_conversion (TREE_OPERAND (expr, 0)), + truthvalue_conversion (TREE_OPERAND (expr, 1)), + 0); + + case NEGATE_EXPR: + case ABS_EXPR: + case FLOAT_EXPR: + case FFS_EXPR: + /* These don't change whether an object is non-zero or zero. */ + return truthvalue_conversion (TREE_OPERAND (expr, 0)); + + case LROTATE_EXPR: + case RROTATE_EXPR: + /* These don't change whether an object is zero or non-zero, but + we can't ignore them if their second arg has side-effects. */ + if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))) + return build (COMPOUND_EXPR, boolean_type_node, TREE_OPERAND (expr, 1), + truthvalue_conversion (TREE_OPERAND (expr, 0))); + else + return truthvalue_conversion (TREE_OPERAND (expr, 0)); + + case COND_EXPR: + /* Distribute the conversion into the arms of a COND_EXPR. */ + return fold (build (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0), + truthvalue_conversion (TREE_OPERAND (expr, 1)), + truthvalue_conversion (TREE_OPERAND (expr, 2)))); + + case CONVERT_EXPR: + /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE, + since that affects how `default_conversion' will behave. */ + if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE + || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE) + break; + /* fall through... */ + case NOP_EXPR: + /* If this is widening the argument, we can ignore it. */ + if (TYPE_PRECISION (TREE_TYPE (expr)) + >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))) + return truthvalue_conversion (TREE_OPERAND (expr, 0)); + break; + + case MINUS_EXPR: + /* With IEEE arithmetic, x - x may not equal 0, so we can't optimize + this case. */ + if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT + && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE) + break; + /* fall through... */ + case BIT_XOR_EXPR: + /* This and MINUS_EXPR can be changed into a comparison of the + two objects. */ + if (TREE_TYPE (TREE_OPERAND (expr, 0)) + == TREE_TYPE (TREE_OPERAND (expr, 1))) + return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0), + TREE_OPERAND (expr, 1), 1); + return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0), + fold (build1 (NOP_EXPR, + TREE_TYPE (TREE_OPERAND (expr, 0)), + TREE_OPERAND (expr, 1))), 1); + + case BIT_AND_EXPR: + if (integer_onep (TREE_OPERAND (expr, 1)) + && TREE_TYPE (expr) != boolean_type_node) + /* Using convert here would cause infinite recursion. */ + return build1 (NOP_EXPR, boolean_type_node, expr); + break; + + case MODIFY_EXPR: + if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR) + warning ("suggest parentheses around assignment used as truth value"); + break; + + default: + break; + } + + if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE) + { + tree tem = save_expr (expr); + return (build_binary_op + ((TREE_SIDE_EFFECTS (expr) + ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), + truthvalue_conversion (build_unary_op (REALPART_EXPR, tem, 0)), + truthvalue_conversion (build_unary_op (IMAGPART_EXPR, tem, 0)), + 0)); + } + + return build_binary_op (NE_EXPR, expr, integer_zero_node, 1); +} +#endif + + +#if USE_CPPLIB +/* Read the rest of a #-directive from input stream FINPUT. + In normal use, the directive name and the white space after it + have already been read, so they won't be included in the result. + We allow for the fact that the directive line may contain + a newline embedded within a character or string literal which forms + a part of the directive. + + The value is a string in a reusable buffer. It remains valid + only until the next time this function is called. */ +unsigned char *yy_cur, *yy_lim; + +#define GETC() (yy_cur < yy_lim ? *yy_cur++ : yy_get_token ()) +#define UNGETC(c) ((c) == EOF ? 0 : yy_cur--) + +int +yy_get_token () +{ + for (;;) + { + parse_in.limit = parse_in.token_buffer; + cpp_token = cpp_get_token (&parse_in); + if (cpp_token == CPP_EOF) + return -1; + yy_lim = CPP_PWRITTEN (&parse_in); + yy_cur = parse_in.token_buffer; + if (yy_cur < yy_lim) + return *yy_cur++; + } +} + +char * +get_directive_line () +{ + static char *directive_buffer = NULL; + static unsigned buffer_length = 0; + register char *p; + register char *buffer_limit; + register int looking_for = 0; + register int char_escaped = 0; + + if (buffer_length == 0) + { + directive_buffer = (char *)xmalloc (128); + buffer_length = 128; + } + + buffer_limit = &directive_buffer[buffer_length]; + + for (p = directive_buffer; ; ) + { + int c; + + /* Make buffer bigger if it is full. */ + if (p >= buffer_limit) + { + register unsigned bytes_used = (p - directive_buffer); + + buffer_length *= 2; + directive_buffer + = (char *)xrealloc (directive_buffer, buffer_length); + p = &directive_buffer[bytes_used]; + buffer_limit = &directive_buffer[buffer_length]; + } + + c = GETC (); + + /* Discard initial whitespace. */ + if ((c == ' ' || c == '\t') && p == directive_buffer) + continue; + + /* Detect the end of the directive. */ + if (c == '\n' && looking_for == 0) + { + UNGETC (c); + c = '\0'; + } + + *p++ = c; + + if (c == 0) + return directive_buffer; + + /* Handle string and character constant syntax. */ + if (looking_for) + { + if (looking_for == c && !char_escaped) + looking_for = 0; /* Found terminator... stop looking. */ + } + else + if (c == '\'' || c == '"') + looking_for = c; /* Don't stop buffering until we see another + another one of these (or an EOF). */ + + /* Handle backslash. */ + char_escaped = (c == '\\' && ! char_escaped); + } +} +#else +/* Read the rest of a #-directive from input stream FINPUT. + In normal use, the directive name and the white space after it + have already been read, so they won't be included in the result. + We allow for the fact that the directive line may contain + a newline embedded within a character or string literal which forms + a part of the directive. + + The value is a string in a reusable buffer. It remains valid + only until the next time this function is called. + + The terminating character ('\n' or EOF) is left in FINPUT for the + caller to re-read. */ + +char * +get_directive_line (finput) + register FILE *finput; +{ + static char *directive_buffer = NULL; + static unsigned buffer_length = 0; + register char *p; + register char *buffer_limit; + register int looking_for = 0; + register int char_escaped = 0; + + if (buffer_length == 0) + { + directive_buffer = (char *)xmalloc (128); + buffer_length = 128; + } + + buffer_limit = &directive_buffer[buffer_length]; + + for (p = directive_buffer; ; ) + { + int c; + + /* Make buffer bigger if it is full. */ + if (p >= buffer_limit) + { + register unsigned bytes_used = (p - directive_buffer); + + buffer_length *= 2; + directive_buffer + = (char *)xrealloc (directive_buffer, buffer_length); + p = &directive_buffer[bytes_used]; + buffer_limit = &directive_buffer[buffer_length]; + } + + c = getc (finput); + + /* Discard initial whitespace. */ + if ((c == ' ' || c == '\t') && p == directive_buffer) + continue; + + /* Detect the end of the directive. */ + if (looking_for == 0 + && (c == '\n' || c == EOF)) + { + ungetc (c, finput); + c = '\0'; + } + + *p++ = c; + + if (c == 0) + return directive_buffer; + + /* Handle string and character constant syntax. */ + if (looking_for) + { + if (looking_for == c && !char_escaped) + looking_for = 0; /* Found terminator... stop looking. */ + } + else + if (c == '\'' || c == '"') + looking_for = c; /* Don't stop buffering until we see another + one of these (or an EOF). */ + + /* Handle backslash. */ + char_escaped = (c == '\\' && ! char_escaped); + } +} +#endif /* !USE_CPPLIB */ + +/* Make a variant type in the proper way for C/C++, propagating qualifiers + down to the element type of an array. */ + +tree +c_build_qualified_type (type, type_quals) + tree type; + int type_quals; +{ + /* A restrict-qualified pointer type must be a pointer to object or + incomplete type. Note that the use of POINTER_TYPE_P also allows + REFERENCE_TYPEs, which is appropriate for C++. Unfortunately, + the C++ front-end also use POINTER_TYPE for pointer-to-member + values, so even though it should be illegal to use `restrict' + with such an entity we don't flag that here. Thus, special case + code for that case is required in the C++ front-end. */ + if ((type_quals & TYPE_QUAL_RESTRICT) + && (!POINTER_TYPE_P (type) + || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))) + { + error ("invalid use of `restrict'"); + type_quals &= ~TYPE_QUAL_RESTRICT; + } + + if (TREE_CODE (type) == ARRAY_TYPE) + return build_array_type (c_build_qualified_type (TREE_TYPE (type), + type_quals), + TYPE_DOMAIN (type)); + return build_qualified_type (type, type_quals); +} + +tree +maybe_objc_method_name (decl) + tree decl; +{ +#ifdef OBJC_TREE_CODES + if (TREE_CODE (decl) == INSTANCE_METHOD_DECL + || TREE_CODE (decl) == CLASS_METHOD_DECL) + return 1; +#endif + return 0; +} + + +/* Apply the TYPE_QUALS to the new DECL. */ + +void +c_apply_type_quals_to_decl (type_quals, decl) + int type_quals; + tree decl; +{ + if (type_quals & TYPE_QUAL_CONST) + TREE_READONLY (decl) = 1; + if (type_quals & TYPE_QUAL_VOLATILE) + { + TREE_SIDE_EFFECTS (decl) = 1; + TREE_THIS_VOLATILE (decl) = 1; + } + if (type_quals & TYPE_QUAL_RESTRICT) + { + if (!TREE_TYPE (decl) + || !POINTER_TYPE_P (TREE_TYPE (decl)) + || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (TREE_TYPE (decl)))) + error ("invalid use of `restrict'"); + else if (flag_strict_aliasing) + { + /* No two restricted pointers can point at the same thing. + However, a restricted pointer can point at the same thing + as an unrestricted pointer, if that unrestricted pointer + is based on the restricted pointer. So, we make the + alias set for the restricted pointer a subset of the + alias set for the type pointed to by the type of the + decl. */ + + int pointed_to_alias_set + = get_alias_set (TREE_TYPE (TREE_TYPE (decl))); + + if (!pointed_to_alias_set) + /* It's not legal to make a subset of alias set zero. */ + ; + else + { + DECL_POINTER_ALIAS_SET (decl) = new_alias_set (); + record_alias_subset (pointed_to_alias_set, + DECL_POINTER_ALIAS_SET (decl)); + } + } + } +} + +/* T is an expression with pointer type. Find the DECL on which this + expression is based. (For example, in `a[i]' this would be `a'.) + If there is no such DECL, or a unique decl cannot be determined, + NULL_TREE is retured. */ + +static tree +c_find_base_decl (t) + tree t; +{ + int i; + tree decl; + + if (t == NULL_TREE || t == error_mark_node) + return NULL_TREE; + + if (!POINTER_TYPE_P (TREE_TYPE (t))) + return NULL_TREE; + + decl = NULL_TREE; + + if (TREE_CODE (t) == FIELD_DECL + || TREE_CODE (t) == PARM_DECL + || TREE_CODE (t) == VAR_DECL) + /* Aha, we found a pointer-typed declaration. */ + return t; + + /* It would be nice to deal with COMPONENT_REFs here. If we could + tell that `a' and `b' were the same, then `a->f' and `b->f' are + also the same. */ + + /* Handle general expressions. */ + switch (TREE_CODE_CLASS (TREE_CODE (t))) + { + case '1': + case '2': + case '3': + for (i = tree_code_length [(int) TREE_CODE (t)]; --i >= 0;) + { + tree d = c_find_base_decl (TREE_OPERAND (t, i)); + if (d) + { + if (!decl) + decl = d; + else if (d && d != decl) + /* Two different declarations. That's confusing; let's + just assume we don't know what's going on. */ + decl = NULL_TREE; + } + } + break; + + default: + break; + } + + return decl; +} + +/* Return the typed-based alias set for T, which may be an expression + or a type. */ + +int +c_get_alias_set (t) + tree t; +{ + tree type; + tree u; + + if (t == error_mark_node) + return 0; + + type = (TREE_CODE_CLASS (TREE_CODE (t)) == 't') + ? t : TREE_TYPE (t); + + if (type == error_mark_node) + return 0; + + /* Deal with special cases first; for certain kinds of references + we're interested in more than just the type. */ + + if (TREE_CODE (t) == BIT_FIELD_REF) + /* Perhaps reads and writes to this piece of data alias fields + neighboring the bitfield. Perhaps that's impossible. For now, + let's just assume that bitfields can alias everything, which is + the conservative assumption. */ + return 0; + + /* Permit type-punning when accessing a union, provided the access + is directly through the union. For example, this code does not + permit taking the address of a union member and then storing + through it. Even the type-punning allowed here is a GCC + extension, albeit a common and useful one; the C standard says + that such accesses have implementation-defined behavior. */ + for (u = t; + TREE_CODE (u) == COMPONENT_REF || TREE_CODE (u) == ARRAY_REF; + u = TREE_OPERAND (u, 0)) + if (TREE_CODE (u) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE) + return 0; + + if (TREE_CODE (t) == INDIRECT_REF) + { + /* Check for accesses through restrict-qualified pointers. */ + tree decl = c_find_base_decl (TREE_OPERAND (t, 0)); + + if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl)) + /* We use the alias set indicated in the declaration. */ + return DECL_POINTER_ALIAS_SET (decl); + } + + /* From here on, only the type matters. */ + + if (TREE_CODE (t) == COMPONENT_REF + && DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1))) + /* Since build_modify_expr calls get_unwidened for stores to + component references, the type of a bit field can be changed + from (say) `unsigned int : 16' to `unsigned short' or from + `enum E : 16' to `short'. We want the real type of the + bit-field in this case, not some the integral equivalent. */ + type = DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1)); + + if (TYPE_ALIAS_SET_KNOWN_P (type)) + /* If we've already calculated the value, just return it. */ + return TYPE_ALIAS_SET (type); + else if (TYPE_MAIN_VARIANT (type) != type) + /* The C standard specifically allows aliasing between + cv-qualified variants of types. */ + TYPE_ALIAS_SET (type) = c_get_alias_set (TYPE_MAIN_VARIANT (type)); + else if (TREE_CODE (type) == INTEGER_TYPE) + { + tree signed_variant; + + /* The C standard specifically allows aliasing between signed and + unsigned variants of the same type. We treat the signed + variant as canonical. */ + signed_variant = signed_type (type); + + if (signed_variant != type) + TYPE_ALIAS_SET (type) = c_get_alias_set (signed_variant); + else if (signed_variant == signed_char_type_node) + /* The C standard guarantess that any object may be accessed + via an lvalue that has character type. We don't have to + check for unsigned_char_type_node or char_type_node because + we are specifically looking at the signed variant. */ + TYPE_ALIAS_SET (type) = 0; + } + else if (TREE_CODE (type) == ARRAY_TYPE) + /* Anything that can alias one of the array elements can alias + the entire array as well. */ + TYPE_ALIAS_SET (type) = c_get_alias_set (TREE_TYPE (type)); + else if (TREE_CODE (type) == FUNCTION_TYPE) + /* There are no objects of FUNCTION_TYPE, so there's no point in + using up an alias set for them. (There are, of course, + pointers and references to functions, but that's + different.) */ + TYPE_ALIAS_SET (type) = 0; + else if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + /* If TYPE is a struct or union type then we're reading or + writing an entire struct. Thus, we don't know anything about + aliasing. (In theory, such an access can only alias objects + whose type is the same as one of the fields, recursively, but + we don't yet make any use of that information.) */ + TYPE_ALIAS_SET (type) = 0; + + else if (TREE_CODE (type) == POINTER_TYPE + || TREE_CODE (type) == REFERENCE_TYPE) + { + tree t; + + /* Unfortunately, there is no canonical form of a pointer type. + In particular, if we have `typedef int I', then `int *', and + `I *' are different types. So, we have to pick a canonical + representative. We do this below. + + Note that this approach is actually more conservative that it + needs to be. In particular, `const int *' and `int *' should + be in different alias sets, but this approach puts them in + the same alias set. */ + + t = TYPE_MAIN_VARIANT (TREE_TYPE (type)); + t = ((TREE_CODE (type) == POINTER_TYPE) + ? build_pointer_type (t) : build_reference_type (t)); + if (t != type) + TYPE_ALIAS_SET (type) = c_get_alias_set (t); + } + + if (!TYPE_ALIAS_SET_KNOWN_P (type)) + { + /* Types that are not allocated on the permanent obstack are not + placed in the type hash table. Thus, there can be multiple + copies of identical types in local scopes. In the long run, + all types should be permanent. */ + if (! TREE_PERMANENT (type)) + TYPE_ALIAS_SET (type) = 0; + else + /* TYPE is something we haven't seen before. Put it in a new + alias set. */ + TYPE_ALIAS_SET (type) = new_alias_set (); + } + + return TYPE_ALIAS_SET (type); +} diff -uNr gcc-2.95.2.ORIG/gcc/f-decl.c gcc-2.95.2/gcc/f-decl.c --- gcc-2.95.2.ORIG/gcc/f-decl.c Thu Jan 1 09:00:00 1970 +++ gcc-2.95.2/gcc/f-decl.c Tue Dec 26 15:31:10 2000 @@ -0,0 +1,8037 @@ +/* Process declarations and variables for C compiler. + Copyright (C) 1988, 92-98, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Process declarations and symbol lookup for C front end. + Also constructs types; the standard scalar types at initialization, + and structure, union, array and enum types when they are declared. */ + +/* ??? not all decl nodes are given the most useful possible + line numbers. For example, the CONST_DECLs for enum values. */ + +#ifndef __GNUFORTRAN__ +#define __GNUFORTRAN__ +#endif + +#include "config.h" +#include "system.h" +#include "tree.h" +#include "flags.h" +#include "output.h" +#include "c-tree.h" +#include "c-lex.h" +#include "toplev.h" + +#if defined (_WIN32) && defined (NEXT_PDO) +extern char* exportNamesForDLL; +#endif + +#if USE_CPPLIB +#include "cpplib.h" +extern cpp_reader parse_in; +#endif + +/* In grokdeclarator, distinguish syntactic contexts of declarators. */ +enum decl_context +{ NORMAL, /* Ordinary declaration */ + FUNCDEF, /* Function definition */ + PARM, /* Declaration of parm before function body */ + FIELD, /* Declaration inside struct or union */ + BITFIELD, /* Likewise but with specified width */ + TYPENAME}; /* Typename (inside cast or sizeof) */ + +#ifndef CHAR_TYPE_SIZE +#define CHAR_TYPE_SIZE BITS_PER_UNIT +#endif + +#ifndef SHORT_TYPE_SIZE +#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2)) +#endif + +#ifndef INT_TYPE_SIZE +#define INT_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef LONG_TYPE_SIZE +#define LONG_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef LONG_LONG_TYPE_SIZE +#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + +#ifndef WCHAR_UNSIGNED +#define WCHAR_UNSIGNED 0 +#endif + +#ifndef FLOAT_TYPE_SIZE +#define FLOAT_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef DOUBLE_TYPE_SIZE +#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + +#ifndef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + +/* We let tm.h override the types used here, to handle trivial differences + such as the choice of unsigned int or long unsigned int for size_t. + When machines start needing nontrivial differences in the size type, + it would be best to do something here to figure out automatically + from other information what type to use. */ + +#ifndef SIZE_TYPE +#define SIZE_TYPE "long unsigned int" +#endif + +#ifndef PTRDIFF_TYPE +#define PTRDIFF_TYPE "long int" +#endif + +#ifndef WCHAR_TYPE +#define WCHAR_TYPE "int" +#endif + +/* a node which has tree code ERROR_MARK, and whose type is itself. + All erroneous expressions are replaced with this node. All functions + that accept nodes as arguments should avoid generating error messages + if this node is one of the arguments, since it is undesirable to get + multiple error messages from one error in the input. */ + +tree error_mark_node; + +/* INTEGER_TYPE and REAL_TYPE nodes for the standard data types */ + +tree short_integer_type_node; +tree integer_type_node; +tree long_integer_type_node; +tree long_long_integer_type_node; + +tree short_unsigned_type_node; +tree unsigned_type_node; +tree long_unsigned_type_node; +tree long_long_unsigned_type_node; + +tree boolean_type_node; +tree boolean_false_node; +tree boolean_true_node; + +tree ptrdiff_type_node; + +tree unsigned_char_type_node; +tree signed_char_type_node; +tree char_type_node; +tree wchar_type_node; +tree signed_wchar_type_node; +tree unsigned_wchar_type_node; + +tree float_type_node; +tree double_type_node; +tree long_double_type_node; + +tree complex_integer_type_node; +tree complex_float_type_node; +tree complex_double_type_node; +tree complex_long_double_type_node; + +tree vector_unsigned_char_type_node; +tree vector_signed_char_type_node; +tree vector_boolean_char_type_node; +tree vector_unsigned_short_type_node; +tree vector_signed_short_type_node; +tree vector_boolean_short_type_node; +tree vector_unsigned_long_type_node; +tree vector_signed_long_type_node; +tree vector_boolean_long_type_node; +tree vector_float_type_node; +tree vector_pixel_type_node; + +tree intQI_type_node; +tree intHI_type_node; +tree intSI_type_node; +tree intDI_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 +tree intTI_type_node; +#endif + +tree unsigned_intQI_type_node; +tree unsigned_intHI_type_node; +tree unsigned_intSI_type_node; +tree unsigned_intDI_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 +tree unsigned_intTI_type_node; +#endif + +/* a VOID_TYPE node. */ + +tree void_type_node; + +/* Nodes for types `void *' and `const void *'. */ + +tree ptr_type_node, const_ptr_type_node; + +/* Nodes for types `char *' and `const char *'. */ + +tree string_type_node, const_string_type_node; + +/* Type `char[SOMENUMBER]'. + Used when an array of char is needed and the size is irrelevant. */ + +tree char_array_type_node; + +#ifdef PASCAL_STRINGS +/* Type `unsigned char[SOMENUMBER]'. + Used for pascal-type strings ("\pstring"). */ + +tree unsigned_char_array_type_node; +#endif + +/* Type `int[SOMENUMBER]' or something like it. + Used when an array of int needed and the size is irrelevant. */ + +tree int_array_type_node; + +/* Type `wchar_t[SOMENUMBER]' or something like it. + Used when a wide string literal is created. */ + +tree wchar_array_type_node; + +/* type `int ()' -- used for implicit declaration of functions. */ + +tree default_function_type; + +/* function types `double (double)' and `double (double, double)', etc. */ + +tree double_ftype_double, double_ftype_double_double; +tree int_ftype_int, long_ftype_long; +tree float_ftype_float; +tree ldouble_ftype_ldouble; + +/* Function type `void (void *, void *, int)' and similar ones */ + +tree void_ftype_ptr_ptr_int, int_ftype_ptr_ptr_int, void_ftype_ptr_int_int; + +/* Function type `char *(char *, char *)' and similar ones */ +tree string_ftype_ptr_ptr, int_ftype_string_string; + +/* Function type `int (const void *, const void *, size_t)' */ +tree int_ftype_cptr_cptr_sizet; + +/* Two expressions that are constants with value zero. + The first is of type `int', the second of type `void *'. */ + +tree integer_zero_node; +tree null_pointer_node; + +/* A node for the integer constant 1. */ + +tree integer_one_node; + +/* Nonzero if we have seen an invalid cross reference + to a struct, union, or enum, but not yet printed the message. */ + +tree pending_invalid_xref; +/* File and line to appear in the eventual error message. */ +char *pending_invalid_xref_file; +int pending_invalid_xref_line; + +/* While defining an enum type, this is 1 plus the last enumerator + constant value. Note that will do not have to save this or `enum_overflow' + around nested function definition since such a definition could only + occur in an enum value expression and we don't use these variables in + that case. */ + +static tree enum_next_value; + +/* Nonzero means that there was overflow computing enum_next_value. */ + +static int enum_overflow; + +/* Parsing a function declarator leaves a list of parameter names + or a chain or parameter decls here. */ + +static tree last_function_parms; + +/* Parsing a function declarator leaves here a chain of structure + and enum types declared in the parmlist. */ + +static tree last_function_parm_tags; + +/* After parsing the declarator that starts a function definition, + `start_function' puts here the list of parameter names or chain of decls. + `store_parm_decls' finds it here. */ + +static tree current_function_parms; + +/* Similar, for last_function_parm_tags. */ +static tree current_function_parm_tags; + +/* Similar, for the file and line that the prototype came from if this is + an old-style definition. */ +static char *current_function_prototype_file; +static int current_function_prototype_line; + +/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function + that have names. Here so we can clear out their names' definitions + at the end of the function. */ + +static tree named_labels; + +/* A list of LABEL_DECLs from outer contexts that are currently shadowed. */ + +static tree shadowed_labels; + +/* Nonzero when store_parm_decls is called indicates a varargs function. + Value not meaningful after store_parm_decls. */ + +static int c_function_varargs; + +/* The FUNCTION_DECL for the function currently being compiled, + or 0 if between functions. */ +tree current_function_decl; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement that specifies a return value is seen. */ + +int current_function_returns_value; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement with no argument is seen. */ + +int current_function_returns_null; + +/* Set to nonzero by `grokdeclarator' for a function + whose return type is defaulted, if warnings for this are desired. */ + +static int warn_about_return_type; + +/* Nonzero when starting a function declared `extern inline'. */ + +static int current_extern_inline; + +/* For each binding contour we allocate a binding_level structure + * which records the names defined in that contour. + * Contours include: + * 0) the global one + * 1) one for each function definition, + * where internal declarations of the parameters appear. + * 2) one for each compound statement, + * to record its declarations. + * + * The current meaning of a name can be found by searching the levels from + * the current one out to the global one. + */ + +/* Note that the information in the `names' component of the global contour + is duplicated in the IDENTIFIER_GLOBAL_VALUEs of all identifiers. */ + +struct binding_level + { + /* A chain of _DECL nodes for all variables, constants, functions, + and typedef types. These are in the reverse of the order supplied. + */ + tree names; + + /* A list of structure, union and enum definitions, + * for looking up tag names. + * It is a chain of TREE_LIST nodes, each of whose TREE_PURPOSE is a name, + * or NULL_TREE; and whose TREE_VALUE is a RECORD_TYPE, UNION_TYPE, + * or ENUMERAL_TYPE node. + */ + tree tags; + + /* For each level, a list of shadowed outer-level local definitions + to be restored when this level is popped. + Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and + whose TREE_VALUE is its old definition (a kind of ..._DECL node). */ + tree shadowed; + + /* For each level (except not the global one), + a chain of BLOCK nodes for all the levels + that were entered and exited one level down. */ + tree blocks; + + /* The BLOCK node for this level, if one has been preallocated. + If 0, the BLOCK is allocated (if needed) when the level is popped. */ + tree this_block; + + /* The binding level which this one is contained in (inherits from). */ + struct binding_level *level_chain; + + /* Nonzero for the level that holds the parameters of a function. */ + char parm_flag; + + /* Nonzero if this level "doesn't exist" for tags. */ + char tag_transparent; + + /* Nonzero if sublevels of this level "don't exist" for tags. + This is set in the parm level of a function definition + while reading the function body, so that the outermost block + of the function body will be tag-transparent. */ + char subblocks_tag_transparent; + + /* Nonzero means make a BLOCK for this level regardless of all else. */ + char keep; + + /* Nonzero means make a BLOCK if this level has any subblocks. */ + char keep_if_subblocks; + + /* list of decls in `names' that have incomplete struct/union types. */ + tree incomplete_list; + + /* A list of decls giving the (reversed) specified order of parms, + not including any forward-decls in the parmlist. + This is so we can put the parms in proper order for assign_parms. */ + tree parm_order; + }; + +#define NULL_BINDING_LEVEL (struct binding_level *) NULL + +/* The binding level currently in effect. */ + +static struct binding_level *current_binding_level; + +/* A chain of binding_level structures awaiting reuse. */ + +static struct binding_level *free_binding_level; + +/* The outermost binding level, for names of file scope. + This is created when the compiler is started and exists + through the entire run. */ + +static struct binding_level *global_binding_level; + +/* Binding level structures are initialized by copying this one. */ + +static struct binding_level clear_binding_level + = {NULL, NULL, NULL, NULL, NULL, NULL_BINDING_LEVEL, 0, 0, 0, 0, 0, 0, + NULL}; + +/* Nonzero means unconditionally make a BLOCK for the next level pushed. */ + +static int keep_next_level_flag; + +/* Nonzero means make a BLOCK for the next level pushed + if it has subblocks. */ + +static int keep_next_if_subblocks; + +/* The chain of outer levels of label scopes. + This uses the same data structure used for binding levels, + but it works differently: each link in the chain records + saved values of named_labels and shadowed_labels for + a label binding level outside the current one. */ + +static struct binding_level *label_level_chain; + +/* Functions called automatically at the beginning and end of execution. */ + +tree static_ctors, static_dtors; + +/* Forward declarations. */ + +static struct binding_level * make_binding_level PROTO((void)); +static void clear_limbo_values PROTO((tree)); +static int duplicate_decls PROTO((tree, tree, int)); +static int redeclaration_error_message PROTO((tree, tree)); +static void storedecls PROTO((tree)); +static void storetags PROTO((tree)); +static tree lookup_tag PROTO((enum tree_code, tree, + struct binding_level *, int)); +static tree lookup_tag_reverse PROTO((tree)); +static tree grokdeclarator PROTO((tree, tree, enum decl_context, + int)); +static tree grokparms PROTO((tree, int)); +static int field_decl_cmp PROTO((const GENERIC_PTR, const GENERIC_PTR)); +static void layout_array_type PROTO((tree)); + +/* C-specific option variables. */ + +/* Nonzero means allow type mismatches in conditional expressions; + just make their values `void'. */ + +int flag_cond_mismatch; + +/* Nonzero means give `double' the same size as `float'. */ + +int flag_short_double; + +/* Nonzero means don't recognize the keyword `asm'. */ + +int flag_no_asm; + +/* Nonzero means don't recognize any builtin functions. */ + +int flag_no_builtin; + +/* Nonzero means don't recognize the non-ANSI builtin functions. + -ansi sets this. */ + +int flag_no_nonansi_builtin; + +/* Nonzero for -faltivec: Enable the SIMD programming model. */ + +int flag_altivec; + +/* Nonzero means do some things the same way PCC does. */ + +int flag_traditional; + +/* Nonzero means use the ISO C9x dialect of C. */ + +int flag_isoc9x = 0; + +/* Nonzero means that we have builtin functions, and main is an int */ + +int flag_hosted = 1; + +/* Nonzero means to allow single precision math even if we're generally + being traditional. */ +int flag_allow_single_precision = 0; + +/* Nonzero means to treat bitfields as signed unless they say `unsigned'. */ + +int flag_signed_bitfields = 1; +int explicit_flag_signed_bitfields = 0; + +#ifdef PASCAL_STRINGS +/* Nonzero means initial "\p" in string becomes a length byte and + string type becomes _unsigned_ char* . */ + +int flag_pascal_strings; +#endif + +/* Nonzero means warn about use of implicit int. */ + +int warn_implicit_int; + +/* Nonzero means warn about usage of long long when `-pedantic'. */ + +int warn_long_long = 1; + +/* Nonzero means message about use of implicit function declarations; + 1 means warning; 2 means error. */ + +int mesg_implicit_function_declaration; + +/* Nonzero means give string constants the type `const char *' + to get extra warnings from them. These warnings will be too numerous + to be useful, except in thoroughly ANSIfied programs. */ + +/*int warn_write_strings; */ +int flag_const_strings; + +#ifdef FOUR_CHAR_CONSTANTS +/* Nonzero (the default) means give warnings for any four-character + character constants. Zero means be quiet about them. These are + used often in Mac code, as "OSTypes". */ + +int warn_four_char_constants = 1; +#endif + +/* Nonzero means warn about pointer casts that can drop a type qualifier + from the pointer target type. */ + +int warn_cast_qual; + +/* Nonzero means warn when casting a function call to a type that does + not match the return type (e.g. (float)sqrt() or (anything*)malloc() + when there is no previous declaration of sqrt or malloc. */ + +int warn_bad_function_cast; + +/* Warn about functions which might be candidates for attribute noreturn. */ + +int warn_missing_noreturn; + +/* Warn about traditional constructs whose meanings changed in ANSI C. */ + +int warn_traditional; + +/* Nonzero means warn about sizeof(function) or addition/subtraction + of function pointers. */ + +int warn_pointer_arith; + +/* Nonzero means warn for non-prototype function decls + or non-prototyped defs without previous prototype. */ + +int warn_strict_prototypes; + +/* Nonzero means warn for any global function def + without separate previous prototype decl. */ + +int warn_missing_prototypes; + +/* Nonzero means warn for any global function def + without separate previous decl. */ + +int warn_missing_declarations; + +/* Nonzero means warn about multiple (redundant) decls for the same single + variable or function. */ + +int warn_redundant_decls = 0; + +/* Nonzero means warn about extern declarations of objects not at + file-scope level and about *all* declarations of functions (whether + extern or static) not at file-scope level. Note that we exclude + implicit function declarations. To get warnings about those, use + -Wimplicit. */ + +int warn_nested_externs = 0; + +/* Warn about *printf or *scanf format/argument anomalies. */ + +int warn_format; + +/* Warn about a subscript that has type char. */ + +int warn_char_subscripts = 0; + +/* Warn if a type conversion is done that might have confusing results. */ + +int warn_conversion; + +/* Warn if adding () is suggested. */ + +int warn_parentheses; + +/* Warn if initializer is not completely bracketed. */ + +int warn_missing_braces; + +/* Warn if main is suspicious. */ + +int warn_main; + +/* Warn about #pragma directives that are not recognised. */ + +int warn_unknown_pragmas = 0; /* Tri state variable. */ + +/* Warn about comparison of signed and unsigned values. + If -1, neither -Wsign-compare nor -Wno-sign-compare has been specified. */ + +int warn_sign_compare = -1; + +#if defined (NEXT_SEMANTICS) || defined (NEXT_PDO) +/* Nonzero if the -Wmost switch was encountered; reset to zero if -Wall is + encountered. (-Wmost is very similar to -Wall, except that it omits + warnings we don't find particularly useful.) */ + +int warn_most = 0; +#endif + +/* Nonzero means warn about use of multicharacter literals. */ + +int warn_multichar = 1; + +/* Nonzero means `$' can be in an identifier. */ + +#ifndef DOLLARS_IN_IDENTIFIERS +#define DOLLARS_IN_IDENTIFIERS 1 +#endif +int dollars_in_ident = DOLLARS_IN_IDENTIFIERS; + +/* Decode the string P as a language-specific option for C. + Return the number of strings consumed. */ + +int +c_decode_option (argc, argv) + int argc ATTRIBUTE_UNUSED; + char **argv; +{ + int strings_processed; + char *p = argv[0]; +#if USE_CPPLIB + strings_processed = cpp_handle_option (&parse_in, argc, argv); +#else + strings_processed = 0; +#endif /* ! USE_CPPLIB */ + + if (!strcmp (p, "-ftraditional") || !strcmp (p, "-traditional")) + { + flag_traditional = 1; + flag_writable_strings = 1; + } + else if (!strcmp (p, "-fallow-single-precision")) + flag_allow_single_precision = 1; + else if (!strcmp (p, "-fhosted") || !strcmp (p, "-fno-freestanding")) + { + flag_hosted = 1; + flag_no_builtin = 0; + } + else if (!strcmp (p, "-ffreestanding") || !strcmp (p, "-fno-hosted")) + { + flag_hosted = 0; + flag_no_builtin = 1; + /* warn_main will be 2 if set by -Wall, 1 if set by -Wmain */ + if (warn_main == 2) + warn_main = 0; + } + else if (!strcmp (p, "-fnotraditional") || !strcmp (p, "-fno-traditional")) + { + flag_traditional = 0; + flag_writable_strings = 0; + } + else if (!strncmp (p, "-std=", 5)) + { + /* Select the appropriate language standard. We currently + recognize: + -std=iso9899:1990 same as -ansi + -std=iso9899:199409 ISO C as modified in amend. 1 + -std=iso9899:199x ISO C 9x + -std=c89 same as -std=iso9899:1990 + -std=c9x same as -std=iso9899:199x + -std=gnu89 default, iso9899:1990 + gnu extensions + -std=gnu9x iso9899:199x + gnu extensions + */ + const char *argstart = &p[5]; + + if (!strcmp (argstart, "iso9899:1990") + || !strcmp (argstart, "c89")) + { + iso_1990: + flag_traditional = 0; + flag_writable_strings = 0; + flag_no_asm = 1; + flag_no_nonansi_builtin = 1; + flag_isoc9x = 0; + } + else if (!strcmp (argstart, "iso9899:199409")) + { + /* ??? The changes since ISO C 1990 are not supported. */ + goto iso_1990; + } + else if (!strcmp (argstart, "iso9899:199x") + || !strcmp (argstart, "c9x")) + { + flag_traditional = 0; + flag_writable_strings = 0; + flag_no_asm = 1; + flag_no_nonansi_builtin = 1; + flag_isoc9x = 1; + } + else if (!strcmp (argstart, "gnu89")) + { + flag_traditional = 0; + flag_writable_strings = 0; + flag_no_asm = 0; + flag_no_nonansi_builtin = 0; + flag_isoc9x = 0; + } + else if (!strcmp (argstart, "gnu9x")) + { + flag_traditional = 0; + flag_writable_strings = 0; + flag_no_asm = 0; + flag_no_nonansi_builtin = 0; + flag_isoc9x = 1; + } + else + error ("unknown C standard `%s'", argstart); + } + else if (!strcmp (p, "-fdollars-in-identifiers")) + dollars_in_ident = 1; + else if (!strcmp (p, "-fno-dollars-in-identifiers")) + dollars_in_ident = 0; + else if (!strcmp (p, "-fsigned-char")) + flag_signed_char = 1; + else if (!strcmp (p, "-funsigned-char")) + flag_signed_char = 0; + else if (!strcmp (p, "-fno-signed-char")) + flag_signed_char = 0; + else if (!strcmp (p, "-fno-unsigned-char")) + flag_signed_char = 1; + else if (!strcmp (p, "-fsigned-bitfields") + || !strcmp (p, "-fno-unsigned-bitfields")) + { + flag_signed_bitfields = 1; + explicit_flag_signed_bitfields = 1; + } + else if (!strcmp (p, "-funsigned-bitfields") + || !strcmp (p, "-fno-signed-bitfields")) + { + flag_signed_bitfields = 0; + explicit_flag_signed_bitfields = 1; + } + else if (!strcmp (p, "-fshort-enums")) + flag_short_enums = 1; + else if (!strcmp (p, "-fno-short-enums")) + flag_short_enums = 0; + else if (!strcmp (p, "-fcond-mismatch")) + flag_cond_mismatch = 1; + else if (!strcmp (p, "-fno-cond-mismatch")) + flag_cond_mismatch = 0; + else if (!strcmp (p, "-fshort-double")) + flag_short_double = 1; + else if (!strcmp (p, "-fno-short-double")) + flag_short_double = 0; + else if (!strcmp (p, "-fasm")) + flag_no_asm = 0; + else if (!strcmp (p, "-fno-asm")) + flag_no_asm = 1; + else if (!strcmp (p, "-fbuiltin")) + flag_no_builtin = 0; + else if (!strcmp (p, "-fno-builtin")) + flag_no_builtin = 1; + else if (!strcmp (p, "-faltivec") || !strcmp (p, "-fvec")) + flag_altivec = 1; + else if (!strcmp (p, "-fno-altivec") || !strcmp (p, "-fno-vec")) + flag_altivec = 0; + else if (!strcmp (p, "-fno-ident")) + flag_no_ident = 1; + else if (!strcmp (p, "-fident")) + flag_no_ident = 0; + else if (!strcmp (p, "-ansi")) + goto iso_1990; +#ifdef PASCAL_STRINGS + else if (!strcmp (p, "-fpascal-strings")) + flag_pascal_strings = 1; + else if (!strcmp (p, "-fno-pascal-strings")) + flag_pascal_strings = 0; +#endif +#ifdef FOUR_CHAR_CONSTANTS + else if (!strcmp (p, "-Wfour-char-constants")) + warn_four_char_constants = 1; + else if (!strcmp (p, "-Wno-four-char-constants")) + warn_four_char_constants = 0; +#endif + else if (!strcmp (p, "-Werror-implicit-function-declaration")) + mesg_implicit_function_declaration = 2; + else if (!strcmp (p, "-Wimplicit-function-declaration")) + mesg_implicit_function_declaration = 1; + else if (!strcmp (p, "-Wno-implicit-function-declaration")) + mesg_implicit_function_declaration = 0; + else if (!strcmp (p, "-Wimplicit-int")) + warn_implicit_int = 1; + else if (!strcmp (p, "-Wno-implicit-int")) + warn_implicit_int = 0; + else if (!strcmp (p, "-Wimplicit")) + { + warn_implicit_int = 1; + if (mesg_implicit_function_declaration != 2) + mesg_implicit_function_declaration = 1; + } + else if (!strcmp (p, "-Wno-implicit")) + warn_implicit_int = 0, mesg_implicit_function_declaration = 0; + else if (!strcmp (p, "-Wlong-long")) + warn_long_long = 1; + else if (!strcmp (p, "-Wno-long-long")) + warn_long_long = 0; + else if (!strcmp (p, "-Wwrite-strings")) + flag_const_strings = 1; + else if (!strcmp (p, "-Wno-write-strings")) + flag_const_strings = 0; + else if (!strcmp (p, "-Wcast-qual")) + warn_cast_qual = 1; + else if (!strcmp (p, "-Wno-cast-qual")) + warn_cast_qual = 0; + else if (!strcmp (p, "-Wbad-function-cast")) + warn_bad_function_cast = 1; + else if (!strcmp (p, "-Wno-bad-function-cast")) + warn_bad_function_cast = 0; + else if (!strcmp (p, "-Wmissing-noreturn")) + warn_missing_noreturn = 1; + else if (!strcmp (p, "-Wno-missing-noreturn")) + warn_missing_noreturn = 0; + else if (!strcmp (p, "-Wpointer-arith")) + warn_pointer_arith = 1; + else if (!strcmp (p, "-Wno-pointer-arith")) + warn_pointer_arith = 0; + else if (!strcmp (p, "-Wstrict-prototypes")) + warn_strict_prototypes = 1; + else if (!strcmp (p, "-Wno-strict-prototypes")) + warn_strict_prototypes = 0; + else if (!strcmp (p, "-Wmissing-prototypes")) + warn_missing_prototypes = 1; + else if (!strcmp (p, "-Wno-missing-prototypes")) + warn_missing_prototypes = 0; + else if (!strcmp (p, "-Wmissing-declarations")) + warn_missing_declarations = 1; + else if (!strcmp (p, "-Wno-missing-declarations")) + warn_missing_declarations = 0; + else if (!strcmp (p, "-Wredundant-decls")) + warn_redundant_decls = 1; + else if (!strcmp (p, "-Wno-redundant-decls")) + warn_redundant_decls = 0; + else if (!strcmp (p, "-Wnested-externs")) + warn_nested_externs = 1; + else if (!strcmp (p, "-Wno-nested-externs")) + warn_nested_externs = 0; + else if (!strcmp (p, "-Wtraditional")) + warn_traditional = 1; + else if (!strcmp (p, "-Wno-traditional")) + warn_traditional = 0; + else if (!strcmp (p, "-Wformat")) + warn_format = 1; + else if (!strcmp (p, "-Wno-format")) + warn_format = 0; +#if defined(OPENSTEP) || defined(NEXT_PDO) + else if (!strcmp (p, "-Wnoformat")) + warn_format = 0; +#endif + else if (!strcmp (p, "-Wchar-subscripts")) + warn_char_subscripts = 1; + else if (!strcmp (p, "-Wno-char-subscripts")) + warn_char_subscripts = 0; + else if (!strcmp (p, "-Wconversion")) + warn_conversion = 1; + else if (!strcmp (p, "-Wno-conversion")) + warn_conversion = 0; + else if (!strcmp (p, "-Wparentheses")) + warn_parentheses = 1; + else if (!strcmp (p, "-Wno-parentheses")) + warn_parentheses = 0; + else if (!strcmp (p, "-Wreturn-type")) + warn_return_type = 1; + else if (!strcmp (p, "-Wno-return-type")) + warn_return_type = 0; + else if (!strcmp (p, "-Wcomment")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wno-comment")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wcomments")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wno-comments")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wtrigraphs")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wno-trigraphs")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wundef")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wno-undef")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wimport")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wno-import")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wmissing-braces")) + warn_missing_braces = 1; + else if (!strcmp (p, "-Wno-missing-braces")) + warn_missing_braces = 0; + else if (!strcmp (p, "-Wmain")) + warn_main = 1; + else if (!strcmp (p, "-Wno-main")) + warn_main = -1; + else if (!strcmp (p, "-Wsign-compare")) + warn_sign_compare = 1; + else if (!strcmp (p, "-Wno-sign-compare")) + warn_sign_compare = 0; + else if (!strcmp (p, "-Wmultichar")) + warn_multichar = 1; + else if (!strcmp (p, "-Wno-multichar")) + warn_multichar = 0; + else if (!strcmp (p, "-Wunknown-pragmas")) + /* Set to greater than 1, so that even unknown pragmas in system + headers will be warned about. */ + warn_unknown_pragmas = 2; + else if (!strcmp (p, "-Wno-unknown-pragmas")) + warn_unknown_pragmas = 0; +#if defined (NEXT_SEMANTICS) || defined (NEXT_PDO) + else if (!strcmp (p, "-Wall") || !strcmp (p, "-Wmost")) +#else + else if (!strcmp (p, "-Wall")) +#endif + { + /* We save the value of warn_uninitialized, since if they put + -Wuninitialized on the command line, we need to generate a + warning about not using it without also specifying -O. */ + if (warn_uninitialized != 1) + warn_uninitialized = 2; + warn_implicit_int = 1; + mesg_implicit_function_declaration = 1; + warn_return_type = 1; + warn_unused = 1; + warn_switch = 1; + warn_format = 1; + warn_char_subscripts = 1; +#if defined (NEXT_SEMANTICS) || defined (NEXT_PDO) + if (!strcmp (p, "-Wall")) +#endif + warn_parentheses = 1; + warn_missing_braces = 1; + /* We set this to 2 here, but 1 in -Wmain, so -ffreestanding can turn + it off only if it's not explicit. */ + warn_main = 2; +#if defined (NEXT_SEMANTICS) || defined (NEXT_PDO) + if (!strcmp (p, "-Wall")) + { +#endif + /* Only warn about unknown pragmas that are not in system headers. */ + warn_unknown_pragmas = 1; +#if defined (NEXT_SEMANTICS) || defined (NEXT_PDO) + warn_most = 0; + } + else if (!strcmp (p, "-Wmost")) + { + warn_most = 1; + /* Set to -1 so we can tell it was turned on by -Wmost. */ + warn_unused = -1; + } +#endif + } + else + return strings_processed; + + return 1; +} + +/* Hooks for print_node. */ + +#ifndef __GNUFORTRAN__ +void +print_lang_decl (file, node, indent) + FILE *file ATTRIBUTE_UNUSED; + tree node ATTRIBUTE_UNUSED; + int indent ATTRIBUTE_UNUSED; +{ +} + +void +print_lang_type (file, node, indent) + FILE *file ATTRIBUTE_UNUSED; + tree node ATTRIBUTE_UNUSED; + int indent ATTRIBUTE_UNUSED; +{ +} + +void +print_lang_identifier (file, node, indent) + FILE *file; + tree node; + int indent; +{ + print_node (file, "global", IDENTIFIER_GLOBAL_VALUE (node), indent + 4); + print_node (file, "local", IDENTIFIER_LOCAL_VALUE (node), indent + 4); + print_node (file, "label", IDENTIFIER_LABEL_VALUE (node), indent + 4); + print_node (file, "implicit", IDENTIFIER_IMPLICIT_DECL (node), indent + 4); + print_node (file, "error locus", IDENTIFIER_ERROR_LOCUS (node), indent + 4); + print_node (file, "limbo value", IDENTIFIER_LIMBO_VALUE (node), indent + 4); +} +#endif + + +/* Hook called at end of compilation to assume 1 elt + for a top-level array decl that wasn't complete before. */ + +void +finish_incomplete_decl (decl) + tree decl; +{ + if (TREE_CODE (decl) == VAR_DECL) + { + tree type = TREE_TYPE (decl); + if (type != error_mark_node + && TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type) == 0) + { + if (! DECL_EXTERNAL (decl)) + warning_with_decl (decl, "array `%s' assumed to have one element"); + + complete_array_type (type, NULL_TREE, 1); + + layout_decl (decl, 0); + } + } +} + +/* Create a new `struct binding_level'. */ + +static +struct binding_level * +make_binding_level () +{ + /* NOSTRICT */ + return (struct binding_level *) xmalloc (sizeof (struct binding_level)); +} + +/* Nonzero if we are currently in the global binding level. */ + +#ifndef __GNUFORTRAN__ +int +global_bindings_p () +{ + return current_binding_level == global_binding_level; +} +#endif + +void +keep_next_level () +{ + keep_next_level_flag = 1; +} + +/* Nonzero if the current level needs to have a BLOCK made. */ + +int +kept_level_p () +{ + return ((current_binding_level->keep_if_subblocks + && current_binding_level->blocks != 0) + || current_binding_level->keep + || current_binding_level->names != 0 + || (current_binding_level->tags != 0 + && !current_binding_level->tag_transparent)); +} + +/* Identify this binding level as a level of parameters. + DEFINITION_FLAG is 1 for a definition, 0 for a declaration. + But it turns out there is no way to pass the right value for + DEFINITION_FLAG, so we ignore it. */ + +void +declare_parm_level (definition_flag) + int definition_flag ATTRIBUTE_UNUSED; +{ + current_binding_level->parm_flag = 1; +} + +/* Nonzero if currently making parm declarations. */ + +int +in_parm_level_p () +{ + return current_binding_level->parm_flag; +} + +/* Enter a new binding level. + If TAG_TRANSPARENT is nonzero, do so only for the name space of variables, + not for that of tags. */ + +#ifndef __GNUFORTRAN__ +void +pushlevel (tag_transparent) + int tag_transparent; +{ + register struct binding_level *newlevel = NULL_BINDING_LEVEL; + + /* If this is the top level of a function, + just make sure that NAMED_LABELS is 0. */ + + if (current_binding_level == global_binding_level) + { + named_labels = 0; + } + + /* Reuse or create a struct for this binding level. */ + + if (free_binding_level) + { + newlevel = free_binding_level; + free_binding_level = free_binding_level->level_chain; + } + else + { + newlevel = make_binding_level (); + } + + /* Add this level to the front of the chain (stack) of levels that + are active. */ + + *newlevel = clear_binding_level; + newlevel->tag_transparent + = (tag_transparent + || (current_binding_level + ? current_binding_level->subblocks_tag_transparent + : 0)); + newlevel->level_chain = current_binding_level; + current_binding_level = newlevel; + newlevel->keep = keep_next_level_flag; + keep_next_level_flag = 0; + newlevel->keep_if_subblocks = keep_next_if_subblocks; + keep_next_if_subblocks = 0; +} +#endif + +/* Clear the limbo values of all identifiers defined in BLOCK or a subblock. */ + +static void +clear_limbo_values (block) + tree block; +{ + tree tem; + + for (tem = BLOCK_VARS (block); tem; tem = TREE_CHAIN (tem)) + if (DECL_NAME (tem) != 0) + IDENTIFIER_LIMBO_VALUE (DECL_NAME (tem)) = 0; + + for (tem = BLOCK_SUBBLOCKS (block); tem; tem = TREE_CHAIN (tem)) + clear_limbo_values (tem); +} + +/* Exit a binding level. + Pop the level off, and restore the state of the identifier-decl mappings + that were in effect when this level was entered. + + If KEEP is nonzero, this level had explicit declarations, so + and create a "block" (a BLOCK node) for the level + to record its declarations and subblocks for symbol table output. + + If FUNCTIONBODY is nonzero, this level is the body of a function, + so create a block as if KEEP were set and also clear out all + label names. + + If REVERSE is nonzero, reverse the order of decls before putting + them into the BLOCK. */ + +#ifndef __GNUFORTRAN__ +tree +poplevel (keep, reverse, functionbody) + int keep; + int reverse; + int functionbody; +{ + register tree link; + /* The chain of decls was accumulated in reverse order. + Put it into forward order, just for cleanliness. */ + tree decls; + tree tags = current_binding_level->tags; + tree subblocks = current_binding_level->blocks; + tree block = 0; + tree decl; + int block_previously_created; + + keep |= current_binding_level->keep; + + /* This warning is turned off because it causes warnings for + declarations like `extern struct foo *x'. */ +#if 0 + /* Warn about incomplete structure types in this level. */ + for (link = tags; link; link = TREE_CHAIN (link)) + if (TYPE_SIZE (TREE_VALUE (link)) == 0) + { + tree type = TREE_VALUE (link); + tree type_name = TYPE_NAME (type); + char *id = IDENTIFIER_POINTER (TREE_CODE (type_name) == IDENTIFIER_NODE + ? type_name + : DECL_NAME (type_name)); + switch (TREE_CODE (type)) + { + case RECORD_TYPE: + error ("`struct %s' incomplete in scope ending here", id); + break; + case UNION_TYPE: + error ("`union %s' incomplete in scope ending here", id); + break; + case ENUMERAL_TYPE: + error ("`enum %s' incomplete in scope ending here", id); + break; + } + } +#endif /* 0 */ + + /* Get the decls in the order they were written. + Usually current_binding_level->names is in reverse order. + But parameter decls were previously put in forward order. */ + + if (reverse) + current_binding_level->names + = decls = nreverse (current_binding_level->names); + else + decls = current_binding_level->names; + + /* Output any nested inline functions within this block + if they weren't already output. */ + + for (decl = decls; decl; decl = TREE_CHAIN (decl)) + if (TREE_CODE (decl) == FUNCTION_DECL + && ! TREE_ASM_WRITTEN (decl) + && DECL_INITIAL (decl) != 0 + && TREE_ADDRESSABLE (decl)) + { + /* If this decl was copied from a file-scope decl + on account of a block-scope extern decl, + propagate TREE_ADDRESSABLE to the file-scope decl. + + DECL_ABSTRACT_ORIGIN can be set to itself if warn_return_type is + true, since then the decl goes through save_for_inline_copying. */ + if (DECL_ABSTRACT_ORIGIN (decl) != 0 + && DECL_ABSTRACT_ORIGIN (decl) != decl) + TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; + else if (DECL_SAVED_INSNS (decl) != 0) + { + push_function_context (); + output_inline_function (decl); + pop_function_context (); + } + } + + /* If there were any declarations or structure tags in that level, + or if this level is a function body, + create a BLOCK to record them for the life of this function. */ + + block = 0; + block_previously_created = (current_binding_level->this_block != 0); + if (block_previously_created) + block = current_binding_level->this_block; + else if (keep || functionbody + || (current_binding_level->keep_if_subblocks && subblocks != 0)) + block = make_node (BLOCK); + if (block != 0) + { + BLOCK_VARS (block) = decls; + BLOCK_TYPE_TAGS (block) = tags; + BLOCK_SUBBLOCKS (block) = subblocks; + remember_end_note (block); + } + + /* In each subblock, record that this is its superior. */ + + for (link = subblocks; link; link = TREE_CHAIN (link)) + BLOCK_SUPERCONTEXT (link) = block; + + /* Clear out the meanings of the local variables of this level. */ + + for (link = decls; link; link = TREE_CHAIN (link)) + { + if (DECL_NAME (link) != 0) + { + /* If the ident. was used or addressed via a local extern decl, + don't forget that fact. */ + if (DECL_EXTERNAL (link)) + { + if (TREE_USED (link)) + TREE_USED (DECL_NAME (link)) = 1; + if (TREE_ADDRESSABLE (link)) + TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1; + } + IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0; + } + } + + /* Restore all name-meanings of the outer levels + that were shadowed by this level. */ + + for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link)) + IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + + /* If the level being exited is the top level of a function, + check over all the labels, and clear out the current + (function local) meanings of their names. */ + + if (functionbody) + { + clear_limbo_values (block); + + /* If this is the top level block of a function, + the vars are the function's parameters. + Don't leave them in the BLOCK because they are + found in the FUNCTION_DECL instead. */ + + BLOCK_VARS (block) = 0; + + /* Clear out the definitions of all label names, + since their scopes end here, + and add them to BLOCK_VARS. */ + + for (link = named_labels; link; link = TREE_CHAIN (link)) + { + register tree label = TREE_VALUE (link); + + if (DECL_INITIAL (label) == 0) + { + error_with_decl (label, "label `%s' used but not defined"); + /* Avoid crashing later. */ + define_label (input_filename, lineno, + DECL_NAME (label)); + } + else if (warn_unused && !TREE_USED (label)) +#ifdef NEXT_PDO + if (!warn_most) +#endif + warning_with_decl (label, "label `%s' defined but not used"); + IDENTIFIER_LABEL_VALUE (DECL_NAME (label)) = 0; + + /* Put the labels into the "variables" of the + top-level block, so debugger can see them. */ + TREE_CHAIN (label) = BLOCK_VARS (block); + BLOCK_VARS (block) = label; + } + } + + /* Pop the current level, and free the structure for reuse. */ + + { + register struct binding_level *level = current_binding_level; + current_binding_level = current_binding_level->level_chain; + + level->level_chain = free_binding_level; + free_binding_level = level; + } + + /* Dispose of the block that we just made inside some higher level. */ + if (functionbody) + DECL_INITIAL (current_function_decl) = block; + else if (block) + { + if (!block_previously_created) + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); + } + /* If we did not make a block for the level just exited, + any blocks made for inner levels + (since they cannot be recorded as subblocks in that level) + must be carried forward so they will later become subblocks + of something else. */ + else if (subblocks) + current_binding_level->blocks + = chainon (current_binding_level->blocks, subblocks); + + /* Set the TYPE_CONTEXTs for all of the tagged types belonging to this + binding contour so that they point to the appropriate construct, i.e. + either to the current FUNCTION_DECL node, or else to the BLOCK node + we just constructed. + + Note that for tagged types whose scope is just the formal parameter + list for some function type specification, we can't properly set + their TYPE_CONTEXTs here, because we don't have a pointer to the + appropriate FUNCTION_TYPE node readily available to us. For those + cases, the TYPE_CONTEXTs of the relevant tagged type nodes get set + in `grokdeclarator' as soon as we have created the FUNCTION_TYPE + node which will represent the "scope" for these "parameter list local" + tagged types. + */ + + if (functionbody) + for (link = tags; link; link = TREE_CHAIN (link)) + TYPE_CONTEXT (TREE_VALUE (link)) = current_function_decl; + else if (block) + for (link = tags; link; link = TREE_CHAIN (link)) + TYPE_CONTEXT (TREE_VALUE (link)) = block; + + if (block) + TREE_USED (block) = 1; + return block; +} +#endif + +/* Delete the node BLOCK from the current binding level. + This is used for the block inside a stmt expr ({...}) + so that the block can be reinserted where appropriate. */ + +void +delete_block (block) + tree block; +{ + tree t; + if (current_binding_level->blocks == block) + current_binding_level->blocks = TREE_CHAIN (block); + for (t = current_binding_level->blocks; t;) + { + if (TREE_CHAIN (t) == block) + TREE_CHAIN (t) = TREE_CHAIN (block); + else + t = TREE_CHAIN (t); + } + TREE_CHAIN (block) = NULL; + /* Clear TREE_USED which is always set by poplevel. + The flag is set again if insert_block is called. */ + TREE_USED (block) = 0; +} + +/* Insert BLOCK at the end of the list of subblocks of the + current binding level. This is used when a BIND_EXPR is expanded, + to handle the BLOCK node inside the BIND_EXPR. */ + +#ifndef __GNUFORTRAN__ +void +insert_block (block) + tree block; +{ + TREE_USED (block) = 1; + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); +} +#endif + +/* Set the BLOCK node for the innermost scope + (the one we are currently in). */ + +#ifndef __GNUFORTRAN__ +void +set_block (block) + register tree block; +{ + current_binding_level->this_block = block; +} +#endif + + +void +push_label_level () +{ + register struct binding_level *newlevel; + + /* Reuse or create a struct for this binding level. */ + + if (free_binding_level) + { + newlevel = free_binding_level; + free_binding_level = free_binding_level->level_chain; + } + else + { + newlevel = make_binding_level (); + } + + /* Add this level to the front of the chain (stack) of label levels. */ + + newlevel->level_chain = label_level_chain; + label_level_chain = newlevel; + + newlevel->names = named_labels; + newlevel->shadowed = shadowed_labels; + named_labels = 0; + shadowed_labels = 0; +} + +void +pop_label_level () +{ + register struct binding_level *level = label_level_chain; + tree link, prev; + + /* Clear out the definitions of the declared labels in this level. + Leave in the list any ordinary, non-declared labels. */ + for (link = named_labels, prev = 0; link;) + { + if (C_DECLARED_LABEL_FLAG (TREE_VALUE (link))) + { + if (DECL_SOURCE_LINE (TREE_VALUE (link)) == 0) + { + error_with_decl (TREE_VALUE (link), + "label `%s' used but not defined"); + /* Avoid crashing later. */ + define_label (input_filename, lineno, + DECL_NAME (TREE_VALUE (link))); + } + else if (warn_unused && !TREE_USED (TREE_VALUE (link))) + warning_with_decl (TREE_VALUE (link), + "label `%s' defined but not used"); + IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link))) = 0; + + /* Delete this element from the list. */ + link = TREE_CHAIN (link); + if (prev) + TREE_CHAIN (prev) = link; + else + named_labels = link; + } + else + { + prev = link; + link = TREE_CHAIN (link); + } + } + + /* Bring back all the labels that were shadowed. */ + for (link = shadowed_labels; link; link = TREE_CHAIN (link)) + if (DECL_NAME (TREE_VALUE (link)) != 0) + IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link))) + = TREE_VALUE (link); + + named_labels = chainon (named_labels, level->names); + shadowed_labels = level->shadowed; + + /* Pop the current level, and free the structure for reuse. */ + label_level_chain = label_level_chain->level_chain; + level->level_chain = free_binding_level; + free_binding_level = level; +} + +/* Push a definition or a declaration of struct, union or enum tag "name". + "type" should be the type node. + We assume that the tag "name" is not already defined. + + Note that the definition may really be just a forward reference. + In that case, the TYPE_SIZE will be zero. */ + +void +pushtag (name, type) + tree name, type; +{ + register struct binding_level *b; + + /* Find the proper binding level for this type tag. */ + + for (b = current_binding_level; b->tag_transparent; b = b->level_chain) + continue; + + if (name) + { + /* Record the identifier as the type's name if it has none. */ + + if (TYPE_NAME (type) == 0) + TYPE_NAME (type) = name; + } + + if (b == global_binding_level) + b->tags = perm_tree_cons (name, type, b->tags); + else + b->tags = saveable_tree_cons (name, type, b->tags); + + /* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE will be the + tagged type we just added to the current binding level. This fake + NULL-named TYPE_DECL node helps dwarfout.c to know when it needs + to output a representation of a tagged type, and it also gives + us a convenient place to record the "scope start" address for the + tagged type. */ + + TYPE_STUB_DECL (type) = pushdecl (build_decl (TYPE_DECL, NULL_TREE, type)); + + /* An approximation for now, so we can tell this is a function-scope tag. + This will be updated in poplevel. */ + TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type)); +} + +/* Handle when a new declaration NEWDECL + has the same name as an old one OLDDECL + in the same binding contour. + Prints an error message if appropriate. + + If safely possible, alter OLDDECL to look like NEWDECL, and return 1. + Otherwise, return 0. + + When DIFFERENT_BINDING_LEVEL is true, NEWDECL is an external declaration, + and OLDDECL is in an outer binding level and should thus not be changed. */ + +static int +duplicate_decls (newdecl, olddecl, different_binding_level) + register tree newdecl, olddecl; + int different_binding_level; +{ + int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl)); + int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_INITIAL (newdecl) != 0); + tree oldtype = TREE_TYPE (olddecl); + tree newtype = TREE_TYPE (newdecl); + int errmsg = 0; + + if (TREE_CODE_CLASS (TREE_CODE (olddecl)) == 'd') + DECL_MACHINE_ATTRIBUTES (newdecl) + = merge_machine_decl_attributes (olddecl, newdecl); + + if (TREE_CODE (newtype) == ERROR_MARK + || TREE_CODE (oldtype) == ERROR_MARK) + types_match = 0; + + /* New decl is completely inconsistent with the old one => + tell caller to replace the old one. + This is always an error except in the case of shadowing a builtin. */ + if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) + { + if (TREE_CODE (olddecl) == FUNCTION_DECL + && (DECL_BUILT_IN (olddecl) + || DECL_BUILT_IN_NONANSI (olddecl))) + { + /* If you declare a built-in or predefined function name as static, + the old definition is overridden, + but optionally warn this was a bad choice of name. */ + if (!TREE_PUBLIC (newdecl)) + { + if (!warn_shadow) + ; + else if (DECL_BUILT_IN (olddecl)) + warning_with_decl (newdecl, "shadowing built-in function `%s'"); + else + warning_with_decl (newdecl, "shadowing library function `%s'"); + } + /* Likewise, if the built-in is not ansi, then programs can + override it even globally without an error. */ + else if (! DECL_BUILT_IN (olddecl)) + warning_with_decl (newdecl, + "library function `%s' declared as non-function"); + + else if (DECL_BUILT_IN_NONANSI (olddecl)) + warning_with_decl (newdecl, + "built-in function `%s' declared as non-function"); + else + warning_with_decl (newdecl, + "built-in function `%s' declared as non-function"); + } + else + { + error_with_decl (newdecl, "`%s' redeclared as different kind of symbol"); + error_with_decl (olddecl, "previous declaration of `%s'"); + } + + return 0; + } + + /* For real parm decl following a forward decl, + return 1 so old decl will be reused. */ + if (types_match && TREE_CODE (newdecl) == PARM_DECL + && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl)) + return 1; + + /* The new declaration is the same kind of object as the old one. + The declarations may partially match. Print warnings if they don't + match enough. Ultimately, copy most of the information from the new + decl to the old one, and keep using the old one. */ + + if (flag_traditional && TREE_CODE (newdecl) == FUNCTION_DECL + && IDENTIFIER_IMPLICIT_DECL (DECL_NAME (newdecl)) == olddecl + && DECL_INITIAL (olddecl) == 0) + /* If -traditional, avoid error for redeclaring fcn + after implicit decl. */ + ; + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_BUILT_IN (olddecl)) + { + /* A function declaration for a built-in function. */ + if (!TREE_PUBLIC (newdecl)) + { + /* If you declare a built-in function name as static, the + built-in definition is overridden, + but optionally warn this was a bad choice of name. */ + if (warn_shadow) + warning_with_decl (newdecl, "shadowing built-in function `%s'"); + /* Discard the old built-in function. */ + return 0; + } + else if (!types_match) + { + /* Accept the return type of the new declaration if same modes. */ + tree oldreturntype = TREE_TYPE (oldtype); + tree newreturntype = TREE_TYPE (newtype); + + /* Make sure we put the new type in the same obstack as the old ones. + If the old types are not both in the same obstack, use the + permanent one. */ + if (TYPE_OBSTACK (oldtype) == TYPE_OBSTACK (newtype)) + push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype)); + else + { + push_obstacks_nochange (); + end_temporary_allocation (); + } + + if (TYPE_MODE (oldreturntype) == TYPE_MODE (newreturntype)) + { + /* Function types may be shared, so we can't just modify + the return type of olddecl's function type. */ + tree trytype + = build_function_type (newreturntype, + TYPE_ARG_TYPES (oldtype)); + + types_match = comptypes (newtype, trytype); + if (types_match) + oldtype = trytype; + } + /* Accept harmless mismatch in first argument type also. + This is for ffs. */ + if (TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0 + && TYPE_ARG_TYPES (oldtype) != 0 + && TREE_VALUE (TYPE_ARG_TYPES (newtype)) != 0 + && TREE_VALUE (TYPE_ARG_TYPES (oldtype)) != 0 + && (TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (newtype))) + == TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (oldtype))))) + { + /* Function types may be shared, so we can't just modify + the return type of olddecl's function type. */ + tree trytype + = build_function_type (TREE_TYPE (oldtype), + tree_cons (NULL_TREE, + TREE_VALUE (TYPE_ARG_TYPES (newtype)), + TREE_CHAIN (TYPE_ARG_TYPES (oldtype)))); + + types_match = comptypes (newtype, trytype); + if (types_match) + oldtype = trytype; + } + if (! different_binding_level) + TREE_TYPE (olddecl) = oldtype; + + pop_obstacks (); + } + if (!types_match) + { + /* If types don't match for a built-in, throw away the built-in. */ + warning_with_decl (newdecl, "conflicting types for built-in function `%s'"); + return 0; + } + } + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_SOURCE_LINE (olddecl) == 0) + { + /* A function declaration for a predeclared function + that isn't actually built in. */ + if (!TREE_PUBLIC (newdecl)) + { + /* If you declare it as static, the + default definition is overridden. */ + return 0; + } + else if (!types_match) + { + /* If the types don't match, preserve volatility indication. + Later on, we will discard everything else about the + default declaration. */ + TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); + } + } + /* Permit char *foo () to match void *foo (...) if not pedantic, + if one of them came from a system header file. */ + else if (!types_match + && TREE_CODE (olddecl) == FUNCTION_DECL + && TREE_CODE (newdecl) == FUNCTION_DECL + && TREE_CODE (TREE_TYPE (oldtype)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (newtype)) == POINTER_TYPE + && (DECL_IN_SYSTEM_HEADER (olddecl) + || DECL_IN_SYSTEM_HEADER (newdecl)) + && ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (newtype))) == void_type_node + && TYPE_ARG_TYPES (oldtype) == 0 + && self_promoting_args_p (TYPE_ARG_TYPES (newtype)) + && TREE_TYPE (TREE_TYPE (oldtype)) == char_type_node) + || + (TREE_TYPE (TREE_TYPE (newtype)) == char_type_node + && TYPE_ARG_TYPES (newtype) == 0 + && self_promoting_args_p (TYPE_ARG_TYPES (oldtype)) + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (oldtype))) == void_type_node))) + { + if (pedantic) + pedwarn_with_decl (newdecl, "conflicting types for `%s'"); + /* Make sure we keep void * as ret type, not char *. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (oldtype))) == void_type_node) + TREE_TYPE (newdecl) = newtype = oldtype; + + /* Set DECL_IN_SYSTEM_HEADER, so that if we see another declaration + we will come back here again. */ + DECL_IN_SYSTEM_HEADER (newdecl) = 1; + } + else if (!types_match + /* Permit char *foo (int, ...); followed by char *foo (); + if not pedantic. */ + && ! (TREE_CODE (olddecl) == FUNCTION_DECL + && ! pedantic + /* Return types must still match. */ + && comptypes (TREE_TYPE (oldtype), + TREE_TYPE (newtype)) + && TYPE_ARG_TYPES (newtype) == 0)) + { + error_with_decl (newdecl, "conflicting types for `%s'"); + /* Check for function type mismatch + involving an empty arglist vs a nonempty one. */ + if (TREE_CODE (olddecl) == FUNCTION_DECL + && comptypes (TREE_TYPE (oldtype), + TREE_TYPE (newtype)) + && ((TYPE_ARG_TYPES (oldtype) == 0 + && DECL_INITIAL (olddecl) == 0) + || + (TYPE_ARG_TYPES (newtype) == 0 + && DECL_INITIAL (newdecl) == 0))) + { + /* Classify the problem further. */ + register tree t = TYPE_ARG_TYPES (oldtype); + if (t == 0) + t = TYPE_ARG_TYPES (newtype); + for (; t; t = TREE_CHAIN (t)) + { + register tree type = TREE_VALUE (t); + + if (TREE_CHAIN (t) == 0 + && TYPE_MAIN_VARIANT (type) != void_type_node) + { + error ("A parameter list with an ellipsis can't match an empty parameter name list declaration."); + break; + } + + if (TYPE_MAIN_VARIANT (type) == float_type_node + || C_PROMOTING_INTEGER_TYPE_P (type)) + { + error ("An argument type that has a default promotion can't match an empty parameter name list declaration."); + break; + } + } + } + error_with_decl (olddecl, "previous declaration of `%s'"); + } + else + { + errmsg = redeclaration_error_message (newdecl, olddecl); + if (errmsg) + { + switch (errmsg) + { + case 1: + error_with_decl (newdecl, "redefinition of `%s'"); + break; + case 2: + error_with_decl (newdecl, "redeclaration of `%s'"); + break; + case 3: + error_with_decl (newdecl, "conflicting declarations of `%s'"); + break; + default: + abort (); + } + + error_with_decl (olddecl, + ((DECL_INITIAL (olddecl) + && current_binding_level == global_binding_level) + ? "`%s' previously defined here" + : "`%s' previously declared here")); + } + else if (TREE_CODE (newdecl) == TYPE_DECL + && (DECL_IN_SYSTEM_HEADER (olddecl) + || DECL_IN_SYSTEM_HEADER (newdecl))) + { + warning_with_decl (newdecl, "redefinition of `%s'"); + warning_with_decl + (olddecl, + ((DECL_INITIAL (olddecl) + && current_binding_level == global_binding_level) + ? "`%s' previously defined here" + : "`%s' previously declared here")); + } + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_INITIAL (olddecl) != 0 + && TYPE_ARG_TYPES (oldtype) == 0 + && TYPE_ARG_TYPES (newtype) != 0 + && TYPE_ACTUAL_ARG_TYPES (oldtype) != 0) + { + register tree type, parm; + register int nargs; + /* Prototype decl follows defn w/o prototype. */ + + for (parm = TYPE_ACTUAL_ARG_TYPES (oldtype), + type = TYPE_ARG_TYPES (newtype), + nargs = 1; + ; + parm = TREE_CHAIN (parm), type = TREE_CHAIN (type), nargs++) + { + if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node + && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) + { + warning_with_decl (newdecl, "prototype for `%s' follows"); + warning_with_decl (olddecl, "non-prototype definition here"); + break; + } + if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node + || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) + { + error_with_decl (newdecl, "prototype for `%s' follows and number of arguments doesn't match"); + error_with_decl (olddecl, "non-prototype definition here"); + errmsg = 1; + break; + } + /* Type for passing arg must be consistent + with that declared for the arg. */ + if (! comptypes (TREE_VALUE (parm), TREE_VALUE (type)) + /* If -traditional, allow `unsigned int' instead of `int' + in the prototype. */ + && (! (flag_traditional + && TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == integer_type_node + && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == unsigned_type_node))) + { + error_with_decl (newdecl, + "prototype for `%s' follows and argument %d doesn't match", + nargs); + error_with_decl (olddecl, "non-prototype definition here"); + errmsg = 1; + break; + } + } + } + /* Warn about mismatches in various flags. */ + else + { + /* Warn if function is now inline + but was previously declared not inline and has been called. */ + if (TREE_CODE (olddecl) == FUNCTION_DECL + && ! DECL_INLINE (olddecl) && DECL_INLINE (newdecl) + && TREE_USED (olddecl)) + warning_with_decl (newdecl, + "`%s' declared inline after being called"); + if (TREE_CODE (olddecl) == FUNCTION_DECL + && ! DECL_INLINE (olddecl) && DECL_INLINE (newdecl) + && DECL_INITIAL (olddecl) != 0) + warning_with_decl (newdecl, + "`%s' declared inline after its definition"); + + /* If pedantic, warn when static declaration follows a non-static + declaration. Otherwise, do so only for functions. */ + if ((pedantic || TREE_CODE (olddecl) == FUNCTION_DECL) + && TREE_PUBLIC (olddecl) + && !TREE_PUBLIC (newdecl)) + warning_with_decl (newdecl, "static declaration for `%s' follows non-static"); + + /* If warn_traditional, warn when a non-static function + declaration follows a static one. */ + if (warn_traditional + && TREE_CODE (olddecl) == FUNCTION_DECL + && !TREE_PUBLIC (olddecl) + && TREE_PUBLIC (newdecl)) + warning_with_decl (newdecl, "non-static declaration for `%s' follows static"); + + /* Warn when const declaration follows a non-const + declaration, but not for functions. */ + if (TREE_CODE (olddecl) != FUNCTION_DECL + && !TREE_READONLY (olddecl) + && TREE_READONLY (newdecl)) + warning_with_decl (newdecl, "const declaration for `%s' follows non-const"); + /* These bits are logically part of the type, for variables. + But not for functions + (where qualifiers are not valid ANSI anyway). */ + else if (pedantic && TREE_CODE (olddecl) != FUNCTION_DECL + && (TREE_READONLY (newdecl) != TREE_READONLY (olddecl) + || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl))) + pedwarn_with_decl (newdecl, "type qualifiers for `%s' conflict with previous decl"); + } + } + + /* Optionally warn about more than one declaration for the same name. */ + if (errmsg == 0 && warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0 + /* Don't warn about a function declaration + followed by a definition. */ + && !(TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) != 0 + && DECL_INITIAL (olddecl) == 0) + /* Don't warn about extern decl followed by (tentative) definition. */ + && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl))) + { + warning_with_decl (newdecl, "redundant redeclaration of `%s' in same scope"); + warning_with_decl (olddecl, "previous declaration of `%s'"); + } + + /* Copy all the DECL_... slots specified in the new decl + except for any that we copy here from the old type. + + Past this point, we don't change OLDTYPE and NEWTYPE + even if we change the types of NEWDECL and OLDDECL. */ + + if (types_match) + { + /* When copying info to olddecl, we store into write_olddecl + instead. This allows us to avoid modifying olddecl when + different_binding_level is true. */ + tree write_olddecl = different_binding_level ? newdecl : olddecl; + + /* Make sure we put the new type in the same obstack as the old ones. + If the old types are not both in the same obstack, use the permanent + one. */ + if (TYPE_OBSTACK (oldtype) == TYPE_OBSTACK (newtype)) + push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype)); + else + { + push_obstacks_nochange (); + end_temporary_allocation (); + } + + /* Merge the data types specified in the two decls. */ + if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl)) + { + if (different_binding_level) + TREE_TYPE (newdecl) + = build_type_attribute_variant + (newtype, + merge_attributes (TYPE_ATTRIBUTES (newtype), + TYPE_ATTRIBUTES (oldtype))); + else + TREE_TYPE (newdecl) + = TREE_TYPE (olddecl) + = common_type (newtype, oldtype); + } + + /* Lay the type out, unless already done. */ + if (oldtype != TREE_TYPE (newdecl)) + { + if (TREE_TYPE (newdecl) != error_mark_node) + layout_type (TREE_TYPE (newdecl)); + if (TREE_CODE (newdecl) != FUNCTION_DECL + && TREE_CODE (newdecl) != TYPE_DECL + && TREE_CODE (newdecl) != CONST_DECL) + layout_decl (newdecl, 0); + } + else + { + /* Since the type is OLDDECL's, make OLDDECL's size go with. */ + DECL_SIZE (newdecl) = DECL_SIZE (olddecl); + if (TREE_CODE (olddecl) != FUNCTION_DECL) + if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) + DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl); + } + + /* Keep the old rtl since we can safely use it. */ + DECL_RTL (newdecl) = DECL_RTL (olddecl); + + /* Merge the type qualifiers. */ + if (DECL_BUILT_IN_NONANSI (olddecl) && TREE_THIS_VOLATILE (olddecl) + && !TREE_THIS_VOLATILE (newdecl)) + TREE_THIS_VOLATILE (write_olddecl) = 0; + if (TREE_READONLY (newdecl)) + TREE_READONLY (write_olddecl) = 1; + if (TREE_THIS_VOLATILE (newdecl)) + { + TREE_THIS_VOLATILE (write_olddecl) = 1; + if (TREE_CODE (newdecl) == VAR_DECL) + make_var_volatile (newdecl); + } + + /* Keep source location of definition rather than declaration. */ + /* When called with different_binding_level set, keep the old + information so that meaningful diagnostics can be given. */ + if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0 + && ! different_binding_level) + { + DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl); + DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl); + } + + /* Merge the unused-warning information. */ + if (DECL_IN_SYSTEM_HEADER (olddecl)) + DECL_IN_SYSTEM_HEADER (newdecl) = 1; + else if (DECL_IN_SYSTEM_HEADER (newdecl)) + DECL_IN_SYSTEM_HEADER (write_olddecl) = 1; + + /* Merge the initialization information. */ + /* When called with different_binding_level set, don't copy over + DECL_INITIAL, so that we don't accidentally change function + declarations into function definitions. */ + if (DECL_INITIAL (newdecl) == 0 && ! different_binding_level) + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + + /* Merge the section attribute. + We want to issue an error if the sections conflict but that must be + done later in decl_attributes since we are called before attributes + are assigned. */ + if (DECL_SECTION_NAME (newdecl) == NULL_TREE) + DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl); + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl); + DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); + + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl) + |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl); + DECL_NO_CHECK_MEMORY_USAGE (newdecl) + |= DECL_NO_CHECK_MEMORY_USAGE (olddecl); + } + + pop_obstacks (); + } + /* If cannot merge, then use the new type and qualifiers, + and don't preserve the old rtl. */ + else if (! different_binding_level) + { + TREE_TYPE (olddecl) = TREE_TYPE (newdecl); + TREE_READONLY (olddecl) = TREE_READONLY (newdecl); + TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl); + TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl); + } + + /* Merge the storage class information. */ + DECL_WEAK (newdecl) |= DECL_WEAK (olddecl); + /* For functions, static overrides non-static. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl); + /* This is since we don't automatically + copy the attributes of NEWDECL into OLDDECL. */ + /* No need to worry about different_binding_level here because + then TREE_PUBLIC (newdecl) was true. */ + TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); + /* If this clears `static', clear it in the identifier too. */ + if (! TREE_PUBLIC (olddecl)) + TREE_PUBLIC (DECL_NAME (olddecl)) = 0; + } + if (DECL_EXTERNAL (newdecl)) + { + TREE_STATIC (newdecl) = TREE_STATIC (olddecl); + DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl); + /* An extern decl does not override previous storage class. */ + TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl); + if (! DECL_EXTERNAL (newdecl)) + DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl); + } + else + { + TREE_STATIC (olddecl) = TREE_STATIC (newdecl); + TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); + } + + /* If either decl says `inline', this fn is inline, + unless its definition was passed already. */ + if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == 0) + DECL_INLINE (olddecl) = 1; + DECL_INLINE (newdecl) = DECL_INLINE (olddecl); + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + if (DECL_BUILT_IN (olddecl)) + { + /* Get rid of any built-in function if new arg types don't match it + or if we have a function definition. */ + if (! types_match || new_is_definition) + { + if (! different_binding_level) + { + TREE_TYPE (olddecl) = TREE_TYPE (newdecl); + DECL_BUILT_IN (olddecl) = 0; + } + } + else + { + /* If redeclaring a builtin function, and not a definition, + it stays built in. */ + DECL_BUILT_IN (newdecl) = 1; + DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); + } + } + /* Also preserve various other info from the definition. */ + else if (! new_is_definition) + DECL_FRAME_SIZE (newdecl) = DECL_FRAME_SIZE (olddecl); + if (! new_is_definition) + { + DECL_RESULT (newdecl) = DECL_RESULT (olddecl); + /* When called with different_binding_level set, don't copy over + DECL_INITIAL, so that we don't accidentally change function + declarations into function definitions. */ + if (! different_binding_level) + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl); + DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl); + if (DECL_INLINE (newdecl)) + DECL_ABSTRACT_ORIGIN (newdecl) = DECL_ORIGIN (olddecl); + } + } + if (different_binding_level) + { + /* Don't output a duplicate symbol or debugging information for this + declaration. + + Do not set TREE_ASM_WRITTEN for a FUNCTION_DECL since we may actually + just have two declarations without a definition. VAR_DECLs may need + the same treatment, I'm not sure. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL) + DECL_IGNORED_P (newdecl) = 1; + else + TREE_ASM_WRITTEN (newdecl) = DECL_IGNORED_P (newdecl) = 1; + return 0; + } + +#if defined (_WIN32) && defined (NEXT_PDO) + /* If this decl had DECL_DLLIMPORT set, then copy that */ + DECL_DLLIMPORT(newdecl) = DECL_DLLIMPORT(olddecl); +#endif /* _WIN32 */ + + /* Copy most of the decl-specific fields of NEWDECL into OLDDECL. + But preserve OLDDECL's DECL_UID. */ + { + register unsigned olddecl_uid = DECL_UID (olddecl); + + bcopy ((char *) newdecl + sizeof (struct tree_common), + (char *) olddecl + sizeof (struct tree_common), + sizeof (struct tree_decl) - sizeof (struct tree_common)); + DECL_UID (olddecl) = olddecl_uid; + } + + /* NEWDECL contains the merged attribute lists. + Update OLDDECL to be the same. */ + DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl); + + return 1; +} + +/* Record a decl-node X as belonging to the current lexical scope. + Check for errors (such as an incompatible declaration for the same + name already seen in the same scope). + + Returns either X or an old decl for the same name. + If an old decl is returned, it may have been smashed + to agree with what X says. */ + +#ifndef __GNUFORTRAN__ +tree +pushdecl (x) + tree x; +{ + register tree t; + register tree name = DECL_NAME (x); + register struct binding_level *b = current_binding_level; + + DECL_CONTEXT (x) = current_function_decl; + /* A local extern declaration for a function doesn't constitute nesting. + A local auto declaration does, since it's a forward decl + for a nested function coming later. */ + if (TREE_CODE (x) == FUNCTION_DECL && DECL_INITIAL (x) == 0 + && DECL_EXTERNAL (x)) + DECL_CONTEXT (x) = 0; + + if (warn_nested_externs && DECL_EXTERNAL (x) && b != global_binding_level + && x != IDENTIFIER_IMPLICIT_DECL (name) + /* Don't print error messages for __FUNCTION__ and __PRETTY_FUNCTION__ */ + && !DECL_IN_SYSTEM_HEADER (x)) + warning ("nested extern declaration of `%s'", IDENTIFIER_POINTER (name)); + + if (name) + { + char *file; + int line; + int different_binding_level = 0; + + t = lookup_name_current_level (name); + /* Don't type check externs here when -traditional. This is so that + code with conflicting declarations inside blocks will get warnings + not errors. X11 for instance depends on this. */ + if (! t && DECL_EXTERNAL (x) && TREE_PUBLIC (x) && ! flag_traditional) + { + t = IDENTIFIER_GLOBAL_VALUE (name); + /* Type decls at global scope don't conflict with externs declared + inside lexical blocks. */ + if (t && TREE_CODE (t) == TYPE_DECL) + t = 0; + different_binding_level = 1; + } + if (t != 0 && t == error_mark_node) + /* error_mark_node is 0 for a while during initialization! */ + { + t = 0; + error_with_decl (x, "`%s' used prior to declaration"); + } + + if (t != 0) + { + file = DECL_SOURCE_FILE (t); + line = DECL_SOURCE_LINE (t); + } + + /* If this decl is `static' and an implicit decl was seen previously, + warn. But don't complain if -traditional, + since traditional compilers don't complain. */ + if (! flag_traditional && TREE_PUBLIC (name) + /* Don't test for DECL_EXTERNAL, because grokdeclarator + sets this for all functions. */ + && ! TREE_PUBLIC (x) + && (TREE_CODE (x) == FUNCTION_DECL || b == global_binding_level) + /* We used to warn also for explicit extern followed by static, + but sometimes you need to do it that way. */ + && IDENTIFIER_IMPLICIT_DECL (name) != 0) + { + pedwarn ("`%s' was declared implicitly `extern' and later `static'", + IDENTIFIER_POINTER (name)); + pedwarn_with_file_and_line + (DECL_SOURCE_FILE (IDENTIFIER_IMPLICIT_DECL (name)), + DECL_SOURCE_LINE (IDENTIFIER_IMPLICIT_DECL (name)), + "previous declaration of `%s'", + IDENTIFIER_POINTER (name)); + TREE_THIS_VOLATILE (name) = 1; + } + + if (t != 0 && duplicate_decls (x, t, different_binding_level)) + { + if (TREE_CODE (t) == PARM_DECL) + { + /* Don't allow more than one "real" duplicate + of a forward parm decl. */ + TREE_ASM_WRITTEN (t) = TREE_ASM_WRITTEN (x); + return t; + } + return t; + } + + /* If we are processing a typedef statement, generate a whole new + ..._TYPE node (which will be just an variant of the existing + ..._TYPE node with identical properties) and then install the + TYPE_DECL node generated to represent the typedef name as the + TYPE_NAME of this brand new (duplicate) ..._TYPE node. + + The whole point here is to end up with a situation where each + and every ..._TYPE node the compiler creates will be uniquely + associated with AT MOST one node representing a typedef name. + This way, even though the compiler substitutes corresponding + ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very + early on, later parts of the compiler can always do the reverse + translation and get back the corresponding typedef name. For + example, given: + + typedef struct S MY_TYPE; + MY_TYPE object; + + Later parts of the compiler might only know that `object' was of + type `struct S' if it were not for code just below. With this + code however, later parts of the compiler see something like: + + struct S' == struct S + typedef struct S' MY_TYPE; + struct S' object; + + And they can then deduce (from the node for type struct S') that + the original object declaration was: + + MY_TYPE object; + + Being able to do this is important for proper support of protoize, + and also for generating precise symbolic debugging information + which takes full account of the programmer's (typedef) vocabulary. + + Obviously, we don't want to generate a duplicate ..._TYPE node if + the TYPE_DECL node that we are now processing really represents a + standard built-in type. + + Since all standard types are effectively declared at line zero + in the source file, we can easily check to see if we are working + on a standard type by checking the current value of lineno. */ + + if (TREE_CODE (x) == TYPE_DECL) + { + if (DECL_SOURCE_LINE (x) == 0) + { + if (TYPE_NAME (TREE_TYPE (x)) == 0) + TYPE_NAME (TREE_TYPE (x)) = x; + } + else if (TREE_TYPE (x) != error_mark_node + && DECL_ORIGINAL_TYPE (x) == NULL_TREE) + { + tree tt = TREE_TYPE (x); + DECL_ORIGINAL_TYPE (x) = tt; + tt = build_type_copy (tt); + TYPE_NAME (tt) = x; + TREE_TYPE (x) = tt; + } + } + + /* Multiple external decls of the same identifier ought to match. + Check against both global declarations (when traditional) and out of + scope (limbo) block level declarations. + + We get warnings about inline functions where they are defined. + Avoid duplicate warnings where they are used. */ + if (TREE_PUBLIC (x) && ! DECL_INLINE (x)) + { + tree decl; + + if (flag_traditional && IDENTIFIER_GLOBAL_VALUE (name) != 0 + && (DECL_EXTERNAL (IDENTIFIER_GLOBAL_VALUE (name)) + || TREE_PUBLIC (IDENTIFIER_GLOBAL_VALUE (name)))) + decl = IDENTIFIER_GLOBAL_VALUE (name); + else if (IDENTIFIER_LIMBO_VALUE (name) != 0) + /* Decls in limbo are always extern, so no need to check that. */ + decl = IDENTIFIER_LIMBO_VALUE (name); + else + decl = 0; + + if (decl && ! comptypes (TREE_TYPE (x), TREE_TYPE (decl)) + /* If old decl is built-in, we already warned if we should. */ + && !DECL_BUILT_IN (decl)) + { + pedwarn_with_decl (x, + "type mismatch with previous external decl"); + pedwarn_with_decl (decl, "previous external decl of `%s'"); + } + } + + /* If a function has had an implicit declaration, and then is defined, + make sure they are compatible. */ + + if (IDENTIFIER_IMPLICIT_DECL (name) != 0 + && IDENTIFIER_GLOBAL_VALUE (name) == 0 + && TREE_CODE (x) == FUNCTION_DECL + && ! comptypes (TREE_TYPE (x), + TREE_TYPE (IDENTIFIER_IMPLICIT_DECL (name)))) + { + warning_with_decl (x, "type mismatch with previous implicit declaration"); + warning_with_decl (IDENTIFIER_IMPLICIT_DECL (name), + "previous implicit declaration of `%s'"); + } + + /* In PCC-compatibility mode, extern decls of vars with no current decl + take effect at top level no matter where they are. */ + if (flag_traditional && DECL_EXTERNAL (x) + && lookup_name (name) == 0) + { + tree type = TREE_TYPE (x); + + /* But don't do this if the type contains temporary nodes. */ + while (type) + { + if (type == error_mark_node) + break; + if (! TREE_PERMANENT (type)) + { + warning_with_decl (x, "type of external `%s' is not global"); + /* By exiting the loop early, we leave TYPE nonzero, + and thus prevent globalization of the decl. */ + break; + } + else if (TREE_CODE (type) == FUNCTION_TYPE + && TYPE_ARG_TYPES (type) != 0) + /* The types might not be truly local, + but the list of arg types certainly is temporary. + Since prototypes are nontraditional, + ok not to do the traditional thing. */ + break; + type = TREE_TYPE (type); + } + + if (type == 0) + b = global_binding_level; + } + + /* This name is new in its binding level. + Install the new declaration and return it. */ + if (b == global_binding_level) + { + /* Install a global value. */ + + /* If the first global decl has external linkage, + warn if we later see static one. */ + if (IDENTIFIER_GLOBAL_VALUE (name) == 0 && TREE_PUBLIC (x)) + TREE_PUBLIC (name) = 1; + + IDENTIFIER_GLOBAL_VALUE (name) = x; + + /* We no longer care about any previous block level declarations. */ + IDENTIFIER_LIMBO_VALUE (name) = 0; + + /* Don't forget if the function was used via an implicit decl. */ + if (IDENTIFIER_IMPLICIT_DECL (name) + && TREE_USED (IDENTIFIER_IMPLICIT_DECL (name))) + TREE_USED (x) = 1, TREE_USED (name) = 1; + + /* Don't forget if its address was taken in that way. */ + if (IDENTIFIER_IMPLICIT_DECL (name) + && TREE_ADDRESSABLE (IDENTIFIER_IMPLICIT_DECL (name))) + TREE_ADDRESSABLE (x) = 1; + + /* Warn about mismatches against previous implicit decl. */ + if (IDENTIFIER_IMPLICIT_DECL (name) != 0 + /* If this real decl matches the implicit, don't complain. */ + && ! (TREE_CODE (x) == FUNCTION_DECL + && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (x))) + == integer_type_node))) + pedwarn ("`%s' was previously implicitly declared to return `int'", + IDENTIFIER_POINTER (name)); + + /* If this decl is `static' and an `extern' was seen previously, + that is erroneous. */ + if (TREE_PUBLIC (name) + && ! TREE_PUBLIC (x) && ! DECL_EXTERNAL (x)) + { + /* Okay to redeclare an ANSI built-in as static. */ + if (t != 0 && DECL_BUILT_IN (t)) + ; + /* Okay to declare a non-ANSI built-in as anything. */ + else if (t != 0 && DECL_BUILT_IN_NONANSI (t)) + ; + /* Okay to have global type decl after an earlier extern + declaration inside a lexical block. */ + else if (TREE_CODE (x) == TYPE_DECL) + ; + else if (IDENTIFIER_IMPLICIT_DECL (name)) + { + if (! TREE_THIS_VOLATILE (name)) + pedwarn ("`%s' was declared implicitly `extern' and later `static'", + IDENTIFIER_POINTER (name)); + } + else + pedwarn ("`%s' was declared `extern' and later `static'", + IDENTIFIER_POINTER (name)); + } + } + else + { + /* Here to install a non-global value. */ + tree oldlocal = IDENTIFIER_LOCAL_VALUE (name); + tree oldglobal = IDENTIFIER_GLOBAL_VALUE (name); + IDENTIFIER_LOCAL_VALUE (name) = x; + + /* If this is an extern function declaration, see if we + have a global definition or declaration for the function. */ + if (oldlocal == 0 + && DECL_EXTERNAL (x) && !DECL_INLINE (x) + && oldglobal != 0 + && TREE_CODE (x) == FUNCTION_DECL + && TREE_CODE (oldglobal) == FUNCTION_DECL) + { + /* We have one. Their types must agree. */ + if (! comptypes (TREE_TYPE (x), + TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)))) + pedwarn_with_decl (x, "extern declaration of `%s' doesn't match global one"); + else + { + /* Inner extern decl is inline if global one is. + Copy enough to really inline it. */ + if (DECL_INLINE (oldglobal)) + { + DECL_INLINE (x) = DECL_INLINE (oldglobal); + DECL_INITIAL (x) = (current_function_decl == oldglobal + ? 0 : DECL_INITIAL (oldglobal)); + DECL_SAVED_INSNS (x) = DECL_SAVED_INSNS (oldglobal); + DECL_FRAME_SIZE (x) = DECL_FRAME_SIZE (oldglobal); + DECL_ARGUMENTS (x) = DECL_ARGUMENTS (oldglobal); + DECL_RESULT (x) = DECL_RESULT (oldglobal); + TREE_ASM_WRITTEN (x) = TREE_ASM_WRITTEN (oldglobal); + DECL_ABSTRACT_ORIGIN (x) = DECL_ORIGIN (oldglobal); + } + /* Inner extern decl is built-in if global one is. */ + if (DECL_BUILT_IN (oldglobal)) + { + DECL_BUILT_IN (x) = DECL_BUILT_IN (oldglobal); + DECL_FUNCTION_CODE (x) = DECL_FUNCTION_CODE (oldglobal); + } + /* Keep the arg types from a file-scope fcn defn. */ + if (TYPE_ARG_TYPES (TREE_TYPE (oldglobal)) != 0 + && DECL_INITIAL (oldglobal) + && TYPE_ARG_TYPES (TREE_TYPE (x)) == 0) + TREE_TYPE (x) = TREE_TYPE (oldglobal); + } + } + +#if 0 /* This case is probably sometimes the right thing to do. */ + /* If we have a local external declaration, + then any file-scope declaration should not + have been static. */ + if (oldlocal == 0 && oldglobal != 0 + && !TREE_PUBLIC (oldglobal) + && DECL_EXTERNAL (x) && TREE_PUBLIC (x)) + warning ("`%s' locally external but globally static", + IDENTIFIER_POINTER (name)); +#endif + + /* If we have a local external declaration, + and no file-scope declaration has yet been seen, + then if we later have a file-scope decl it must not be static. */ + if (oldlocal == 0 + && DECL_EXTERNAL (x) + && TREE_PUBLIC (x)) + { + if (oldglobal == 0) + TREE_PUBLIC (name) = 1; + + /* Save this decl, so that we can do type checking against + other decls after it falls out of scope. + + Only save it once. This prevents temporary decls created in + expand_inline_function from being used here, since this + will have been set when the inline function was parsed. + It also helps give slightly better warnings. */ + if (IDENTIFIER_LIMBO_VALUE (name) == 0) + IDENTIFIER_LIMBO_VALUE (name) = x; + } + + /* Warn if shadowing an argument at the top level of the body. */ + if (oldlocal != 0 && !DECL_EXTERNAL (x) + /* This warning doesn't apply to the parms of a nested fcn. */ + && ! current_binding_level->parm_flag + /* Check that this is one level down from the parms. */ + && current_binding_level->level_chain->parm_flag + /* Check that the decl being shadowed + comes from the parm level, one level up. */ + && chain_member (oldlocal, current_binding_level->level_chain->names)) + { + if (TREE_CODE (oldlocal) == PARM_DECL) + pedwarn ("declaration of `%s' shadows a parameter", + IDENTIFIER_POINTER (name)); + else + pedwarn ("declaration of `%s' shadows a symbol from the parameter list", + IDENTIFIER_POINTER (name)); + } + + /* Maybe warn if shadowing something else. */ + else if (warn_shadow && !DECL_EXTERNAL (x) + /* No shadow warnings for internally generated vars. */ + && DECL_SOURCE_LINE (x) != 0 + /* No shadow warnings for vars made for inlining. */ + && ! DECL_FROM_INLINE (x)) + { + char *id = IDENTIFIER_POINTER (name); + + if (TREE_CODE (x) == PARM_DECL + && current_binding_level->level_chain->parm_flag) + /* Don't warn about the parm names in function declarator + within a function declarator. + It would be nice to avoid warning in any function + declarator in a declaration, as opposed to a definition, + but there is no way to tell it's not a definition. */ + ; + else if (oldlocal != 0 && TREE_CODE (oldlocal) == PARM_DECL) + warning ("declaration of `%s' shadows a parameter", id); + else if (oldlocal != 0) + warning ("declaration of `%s' shadows previous local", id); + else if (IDENTIFIER_GLOBAL_VALUE (name) != 0 + && IDENTIFIER_GLOBAL_VALUE (name) != error_mark_node) + warning ("declaration of `%s' shadows global declaration", id); + } + + /* If storing a local value, there may already be one (inherited). + If so, record it for restoration when this binding level ends. */ + if (oldlocal != 0) + b->shadowed = tree_cons (name, oldlocal, b->shadowed); + } + + /* Keep list of variables in this level with incomplete type. */ + if (TYPE_SIZE (TREE_TYPE (x)) == 0) + b->incomplete_list = tree_cons (NULL_TREE, x, b->incomplete_list); + } + + /* Put decls on list in reverse order. + We will reverse them later if necessary. */ + TREE_CHAIN (x) = b->names; + b->names = x; + + return x; +} +#endif + +/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, if appropriate. */ + +tree +pushdecl_top_level (x) + tree x; +{ + register tree t; + register struct binding_level *b = current_binding_level; +#ifdef NEXT_SEMANTICS + register tree function_decl = current_function_decl; +#endif + + current_binding_level = global_binding_level; +#ifdef NEXT_SEMANTICS + current_function_decl = 0; +#endif + t = pushdecl (x); + current_binding_level = b; +#ifdef NEXT_SEMANTICS + current_function_decl = function_decl; +#endif + return t; +} + +/* Generate an implicit declaration for identifier FUNCTIONID + as a function of type int (). Print a warning if appropriate. */ + +tree +implicitly_declare (functionid) + tree functionid; +{ + register tree decl; + int traditional_warning = 0; + /* Only one "implicit declaration" warning per identifier. */ + int implicit_warning; + + /* Save the decl permanently so we can warn if definition follows. */ + push_obstacks_nochange (); + end_temporary_allocation (); + + /* We used to reuse an old implicit decl here, + but this loses with inline functions because it can clobber + the saved decl chains. */ +/* if (IDENTIFIER_IMPLICIT_DECL (functionid) != 0) + decl = IDENTIFIER_IMPLICIT_DECL (functionid); + else */ + decl = build_decl (FUNCTION_DECL, functionid, default_function_type); + + /* Warn of implicit decl following explicit local extern decl. + This is probably a program designed for traditional C. */ + if (TREE_PUBLIC (functionid) && IDENTIFIER_GLOBAL_VALUE (functionid) == 0) + traditional_warning = 1; + + /* Warn once of an implicit declaration. */ + implicit_warning = (IDENTIFIER_IMPLICIT_DECL (functionid) == 0); + + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + + /* Record that we have an implicit decl and this is it. */ + IDENTIFIER_IMPLICIT_DECL (functionid) = decl; + + /* ANSI standard says implicit declarations are in the innermost block. + So we record the decl in the standard fashion. + If flag_traditional is set, pushdecl does it top-level. */ + pushdecl (decl); + + /* This is a no-op in c-lang.c or something real in objc-actions.c. */ + maybe_objc_check_decl (decl); + + rest_of_decl_compilation (decl, NULL_PTR, 0, 0); + + if (mesg_implicit_function_declaration && implicit_warning) + { + if (mesg_implicit_function_declaration == 2) + error ("implicit declaration of function `%s'", + IDENTIFIER_POINTER (functionid)); + else + warning ("implicit declaration of function `%s'", + IDENTIFIER_POINTER (functionid)); + } + else if (warn_traditional && traditional_warning) + warning ("function `%s' was previously declared within a block", + IDENTIFIER_POINTER (functionid)); + + /* Write a record describing this implicit function declaration to the + prototypes file (if requested). */ + + gen_aux_info_record (decl, 0, 1, 0); + + pop_obstacks (); + + return decl; +} + +/* Return zero if the declaration NEWDECL is valid + when the declaration OLDDECL (assumed to be for the same name) + has already been seen. + Otherwise return 1 if NEWDECL is a redefinition, 2 if it is a redeclaration, + and 3 if it is a conflicting declaration. */ + +static int +redeclaration_error_message (newdecl, olddecl) + tree newdecl, olddecl; +{ + if (TREE_CODE (newdecl) == TYPE_DECL) + { + if (flag_traditional && TREE_TYPE (newdecl) == TREE_TYPE (olddecl)) + return 0; + /* pushdecl creates distinct types for TYPE_DECLs by calling + build_type_copy, so the above comparison generally fails. We do + another test against the TYPE_MAIN_VARIANT of the olddecl, which + is equivalent to what this code used to do before the build_type_copy + call. The variant type distinction should not matter for traditional + code, because it doesn't have type qualifiers. */ + if (flag_traditional + && TYPE_MAIN_VARIANT (TREE_TYPE (olddecl)) == TREE_TYPE (newdecl)) + return 0; + if (DECL_IN_SYSTEM_HEADER (olddecl) || DECL_IN_SYSTEM_HEADER (newdecl)) + return 0; + return 1; + } + else if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + /* Declarations of functions can insist on internal linkage + but they can't be inconsistent with internal linkage, + so there can be no error on that account. + However defining the same name twice is no good. */ + if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0 + /* However, defining once as extern inline and a second + time in another way is ok. */ + && !(DECL_INLINE (olddecl) && DECL_EXTERNAL (olddecl) + && !(DECL_INLINE (newdecl) && DECL_EXTERNAL (newdecl)))) + return 1; + return 0; + } + else if (current_binding_level == global_binding_level) + { + /* Objects declared at top level: */ + /* If at least one is a reference, it's ok. */ + if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl)) + return 0; + /* Reject two definitions. */ + if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0) + return 1; + /* Now we have two tentative defs, or one tentative and one real def. */ + /* Insist that the linkage match. */ + if (TREE_PUBLIC (olddecl) != TREE_PUBLIC (newdecl)) + return 3; + return 0; + } + else if (current_binding_level->parm_flag + && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)) + return 0; + else + { + /* Newdecl has block scope. If olddecl has block scope also, then + reject two definitions, and reject a definition together with an + external reference. Otherwise, it is OK, because newdecl must + be an extern reference to olddecl. */ + if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl)) + && DECL_CONTEXT (newdecl) == DECL_CONTEXT (olddecl)) + return 2; + return 0; + } +} + +/* Get the LABEL_DECL corresponding to identifier ID as a label. + Create one if none exists so far for the current function. + This function is called for both label definitions and label references. */ + +tree +lookup_label (id) + tree id; +{ + register tree decl = IDENTIFIER_LABEL_VALUE (id); + + if (current_function_decl == 0) + { + error ("label %s referenced outside of any function", + IDENTIFIER_POINTER (id)); + return 0; + } + + /* Use a label already defined or ref'd with this name. */ + if (decl != 0) + { + /* But not if it is inherited and wasn't declared to be inheritable. */ + if (DECL_CONTEXT (decl) != current_function_decl + && ! C_DECLARED_LABEL_FLAG (decl)) + return shadow_label (id); + return decl; + } + + decl = build_decl (LABEL_DECL, id, void_type_node); + + /* Make sure every label has an rtx. */ + label_rtx (decl); + + /* A label not explicitly declared must be local to where it's ref'd. */ + DECL_CONTEXT (decl) = current_function_decl; + + DECL_MODE (decl) = VOIDmode; + + /* Say where one reference is to the label, + for the sake of the error if it is not defined. */ + DECL_SOURCE_LINE (decl) = lineno; + DECL_SOURCE_FILE (decl) = input_filename; + + IDENTIFIER_LABEL_VALUE (id) = decl; + + named_labels = tree_cons (NULL_TREE, decl, named_labels); + + return decl; +} + +/* Make a label named NAME in the current function, + shadowing silently any that may be inherited from containing functions + or containing scopes. + + Note that valid use, if the label being shadowed + comes from another scope in the same function, + requires calling declare_nonlocal_label right away. */ + +tree +shadow_label (name) + tree name; +{ + register tree decl = IDENTIFIER_LABEL_VALUE (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; + } + + return lookup_label (name); +} + +/* Define a label, specifying the location in the source file. + Return the LABEL_DECL node for the label, if the definition is valid. + Otherwise return 0. */ + +tree +define_label (filename, line, name) + char *filename; + int line; + tree name; +{ + tree decl = lookup_label (name); + + /* If label with this name is known from an outer context, shadow it. */ + if (decl != 0 && DECL_CONTEXT (decl) != current_function_decl) + { + shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels); + IDENTIFIER_LABEL_VALUE (name) = 0; + decl = lookup_label (name); + } + + if (DECL_INITIAL (decl) != 0) + { + error ("duplicate label `%s'", IDENTIFIER_POINTER (name)); + return 0; + } + else + { + /* Mark label as having been defined. */ + DECL_INITIAL (decl) = error_mark_node; + /* Say where in the source. */ + DECL_SOURCE_FILE (decl) = filename; + DECL_SOURCE_LINE (decl) = line; + return decl; + } +} + +/* Return the list of declarations of the current level. + Note that this list is in reverse order unless/until + you nreverse it; and when you do nreverse it, you must + store the result back using `storedecls' or you will lose. */ + +#ifndef __GNUFORTRAN__ +tree +getdecls () +{ + return current_binding_level->names; +} +#endif + +/* Return the list of type-tags (for structs, etc) of the current level. */ + +tree +gettags () +{ + return current_binding_level->tags; +} + +/* Store the list of declarations of the current level. + This is done for the parameter declarations of a function being defined, + after they are modified in the light of any missing parameters. */ + +static void +storedecls (decls) + tree decls; +{ + current_binding_level->names = decls; +} + +/* Similarly, store the list of tags of the current level. */ + +static void +storetags (tags) + tree tags; +{ + current_binding_level->tags = tags; +} + +/* Given NAME, an IDENTIFIER_NODE, + return the structure (or union or enum) definition for that name. + Searches binding levels from BINDING_LEVEL up to the global level. + If THISLEVEL_ONLY is nonzero, searches only the specified context + (but skips any tag-transparent contexts to find one that is + meaningful for tags). + CODE says which kind of type the caller wants; + it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE. + If the wrong kind of type is found, an error is reported. */ + +static tree +lookup_tag (code, name, binding_level, thislevel_only) + enum tree_code code; + struct binding_level *binding_level; + tree name; + int thislevel_only; +{ + register struct binding_level *level; + + for (level = binding_level; level; level = level->level_chain) + { + register tree tail; + for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) + { + if (TREE_PURPOSE (tail) == name) + { + if (TREE_CODE (TREE_VALUE (tail)) != code) + { + /* Definition isn't the kind we were looking for. */ + pending_invalid_xref = name; + pending_invalid_xref_file = input_filename; + pending_invalid_xref_line = lineno; + } + return TREE_VALUE (tail); + } + } + if (thislevel_only && ! level->tag_transparent) + return NULL_TREE; + } + return NULL_TREE; +} + +/* Print an error message now + for a recent invalid struct, union or enum cross reference. + We don't print them immediately because they are not invalid + when used in the `struct foo;' construct for shadowing. */ + +void +pending_xref_error () +{ + if (pending_invalid_xref != 0) + error_with_file_and_line (pending_invalid_xref_file, + pending_invalid_xref_line, + "`%s' defined as wrong kind of tag", + IDENTIFIER_POINTER (pending_invalid_xref)); + pending_invalid_xref = 0; +} + +/* Given a type, find the tag that was defined for it and return the tag name. + Otherwise return 0. */ + +static tree +lookup_tag_reverse (type) + tree type; +{ + register struct binding_level *level; + + for (level = current_binding_level; level; level = level->level_chain) + { + register tree tail; + for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) + { + if (TREE_VALUE (tail) == type) + return TREE_PURPOSE (tail); + } + } + return NULL_TREE; +} + +/* Look up NAME in the current binding level and its superiors + in the namespace of variables, functions and typedefs. + Return a ..._DECL node of some kind representing its definition, + or return 0 if it is undefined. */ + +tree +lookup_name (name) + tree name; +{ + register tree val; + if (current_binding_level != global_binding_level + && IDENTIFIER_LOCAL_VALUE (name)) + val = IDENTIFIER_LOCAL_VALUE (name); + else + val = IDENTIFIER_GLOBAL_VALUE (name); + return val; +} + +/* Similar to `lookup_name' but look only at current binding level. */ + +tree +lookup_name_current_level (name) + tree name; +{ + register tree t; + + if (current_binding_level == global_binding_level) + return IDENTIFIER_GLOBAL_VALUE (name); + + if (IDENTIFIER_LOCAL_VALUE (name) == 0) + return 0; + + for (t = current_binding_level->names; t; t = TREE_CHAIN (t)) + if (DECL_NAME (t) == name) + break; + + return t; +} + +/* Create the predefined scalar types of C, + and some nodes representing standard constants (0, 1, (void *) 0). + Initialize the global binding level. + Make definitions for built-in primitive functions. */ + +#ifndef __GNUFORTRAN__ +void +init_decl_processing () +{ + register tree endlink; + /* Either char* or void*. */ + tree traditional_ptr_type_node; + /* Data types of memcpy and strlen. */ + tree memcpy_ftype, memset_ftype, strlen_ftype; + tree void_ftype_any, ptr_ftype_void, ptr_ftype_ptr; + int wchar_type_size; + tree temp; + tree array_domain_type; + + current_function_decl = NULL; + named_labels = NULL; + current_binding_level = NULL_BINDING_LEVEL; + free_binding_level = NULL_BINDING_LEVEL; + pushlevel (0); /* make the binding_level structure for global names */ + global_binding_level = current_binding_level; + + /* Define `int' and `char' first so that dbx will output them first. */ + + integer_type_node = make_signed_type (INT_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_INT], + integer_type_node)); + + /* Define `char', which is like either `signed char' or `unsigned char' + but not the same as either. */ + + char_type_node + = (flag_signed_char + ? make_signed_type (CHAR_TYPE_SIZE) + : make_unsigned_type (CHAR_TYPE_SIZE)); + pushdecl (build_decl (TYPE_DECL, get_identifier ("char"), + char_type_node)); + + long_integer_type_node = make_signed_type (LONG_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("long int"), + long_integer_type_node)); + + unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned int"), + unsigned_type_node)); + + long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("long unsigned int"), + long_unsigned_type_node)); + + long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("long long int"), + long_long_integer_type_node)); + + long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("long long unsigned int"), + long_long_unsigned_type_node)); + + short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("short int"), + short_integer_type_node)); + + short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("short unsigned int"), + short_unsigned_type_node)); + + /* `unsigned long' is the standard type for sizeof. + Traditionally, use a signed type. + Note that stddef.h uses `unsigned long', + and this must agree, even if long and int are the same size. */ + set_sizetype + (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE)))); + if (flag_traditional && TREE_UNSIGNED (sizetype)) + set_sizetype (signed_type (sizetype)); + + ptrdiff_type_node + = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE))); + + error_mark_node = make_node (ERROR_MARK); + TREE_TYPE (error_mark_node) = error_mark_node; + + /* Define both `signed char' and `unsigned char'. */ + signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("signed char"), + signed_char_type_node)); + + unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned char"), + unsigned_char_type_node)); + + intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intQI_type_node)); + + intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intHI_type_node)); + + intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node)); + + intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node)); + +#if HOST_BITS_PER_WIDE_INT >= 64 + intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intTI_type_node)); +#endif + + unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node)); + + unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intHI_type_node)); + + unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node)); + + unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node)); + +#if HOST_BITS_PER_WIDE_INT >= 64 + unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intTI_type_node)); +#endif + + float_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE; + pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_FLOAT], + float_type_node)); + layout_type (float_type_node); + + double_type_node = make_node (REAL_TYPE); + if (flag_short_double) + TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE; + else + TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE; + pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_DOUBLE], + double_type_node)); + layout_type (double_type_node); + + long_double_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE; + pushdecl (build_decl (TYPE_DECL, get_identifier ("long double"), + long_double_type_node)); + layout_type (long_double_type_node); + + complex_integer_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"), + complex_integer_type_node)); + TREE_TYPE (complex_integer_type_node) = integer_type_node; + layout_type (complex_integer_type_node); + + complex_float_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"), + complex_float_type_node)); + TREE_TYPE (complex_float_type_node) = float_type_node; + layout_type (complex_float_type_node); + + complex_double_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"), + complex_double_type_node)); + TREE_TYPE (complex_double_type_node) = double_type_node; + layout_type (complex_double_type_node); + + complex_long_double_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"), + complex_long_double_type_node)); + TREE_TYPE (complex_long_double_type_node) = long_double_type_node; + layout_type (complex_long_double_type_node); + + vector_unsigned_char_type_node = make_node (VECTOR_TYPE); + TREE_TYPE (vector_unsigned_char_type_node) = unsigned_char_type_node; + pushdecl (build_decl (TYPE_DECL, get_identifier ("__vector unsigned char"), + vector_unsigned_char_type_node)); + layout_type (vector_unsigned_char_type_node); + + vector_signed_char_type_node = make_node (VECTOR_TYPE); + TREE_TYPE (vector_signed_char_type_node) = signed_char_type_node; + pushdecl (build_decl (TYPE_DECL, get_identifier ("__vector signed char"), + vector_signed_char_type_node)); + layout_type (vector_signed_char_type_node); + + vector_boolean_char_type_node = make_node (VECTOR_TYPE); + TREE_TYPE (vector_boolean_char_type_node) = unsigned_char_type_node; + pushdecl (build_decl (TYPE_DECL, get_identifier ("__vector bool char"), + vector_boolean_char_type_node)); + layout_type (vector_boolean_char_type_node); + + vector_unsigned_short_type_node = make_node (VECTOR_TYPE); + TREE_TYPE (vector_unsigned_short_type_node) = short_unsigned_type_node; + pushdecl (build_decl (TYPE_DECL, get_identifier ("__vector unsigned short"), + vector_unsigned_short_type_node)); + layout_type (vector_unsigned_short_type_node); + + vector_signed_short_type_node = make_node (VECTOR_TYPE); + TREE_TYPE (vector_signed_short_type_node) = short_integer_type_node; + pushdecl (build_decl (TYPE_DECL, get_identifier ("__vector signed short"), + vector_signed_short_type_node)); + layout_type (vector_signed_short_type_node); + + vector_boolean_short_type_node = make_node (VECTOR_TYPE); + TREE_TYPE (vector_boolean_short_type_node) = short_unsigned_type_node; + pushdecl (build_decl (TYPE_DECL, get_identifier ("__vector bool short"), + vector_boolean_short_type_node)); + layout_type (vector_boolean_short_type_node); + + vector_unsigned_long_type_node = make_node (VECTOR_TYPE); + TREE_TYPE (vector_unsigned_long_type_node) = long_unsigned_type_node; + pushdecl (build_decl (TYPE_DECL, get_identifier ("__vector unsigned long"), + vector_unsigned_long_type_node)); + layout_type (vector_unsigned_long_type_node); + + vector_signed_long_type_node = make_node (VECTOR_TYPE); + TREE_TYPE (vector_signed_long_type_node) = long_integer_type_node; + pushdecl (build_decl (TYPE_DECL, get_identifier ("__vector signed long"), + vector_signed_long_type_node)); + layout_type (vector_signed_long_type_node); + + vector_boolean_long_type_node = make_node (VECTOR_TYPE); + TREE_TYPE (vector_boolean_long_type_node) = long_unsigned_type_node; + pushdecl (build_decl (TYPE_DECL, get_identifier ("__vector bool long"), + vector_boolean_long_type_node)); + layout_type (vector_boolean_long_type_node); + + vector_float_type_node = make_node (VECTOR_TYPE); + TREE_TYPE (vector_float_type_node) = float_type_node; + pushdecl (build_decl (TYPE_DECL, get_identifier ("__vector float"), + vector_float_type_node)); + layout_type (vector_float_type_node); + + vector_pixel_type_node = make_node (VECTOR_TYPE); + TREE_TYPE (vector_pixel_type_node) = short_unsigned_type_node; + pushdecl (build_decl (TYPE_DECL, get_identifier ("__vector pixel"), + vector_pixel_type_node)); + layout_type (vector_pixel_type_node); + + wchar_type_node + = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (WCHAR_TYPE))); + wchar_type_size = TYPE_PRECISION (wchar_type_node); + signed_wchar_type_node = signed_type (wchar_type_node); + unsigned_wchar_type_node = unsigned_type (wchar_type_node); + + integer_zero_node = build_int_2 (0, 0); + TREE_TYPE (integer_zero_node) = integer_type_node; + integer_one_node = build_int_2 (1, 0); + TREE_TYPE (integer_one_node) = integer_type_node; + + boolean_type_node = integer_type_node; + boolean_true_node = integer_one_node; + boolean_false_node = integer_zero_node; + + size_zero_node = build_int_2 (0, 0); + TREE_TYPE (size_zero_node) = sizetype; + size_one_node = build_int_2 (1, 0); + TREE_TYPE (size_one_node) = sizetype; + + void_type_node = make_node (VOID_TYPE); + pushdecl (build_decl (TYPE_DECL, + ridpointers[(int) RID_VOID], void_type_node)); + layout_type (void_type_node); /* Uses integer_zero_node */ + /* We are not going to have real types in C with less than byte alignment, + so we might as well not have any types that claim to have it. */ + TYPE_ALIGN (void_type_node) = BITS_PER_UNIT; + + null_pointer_node = build_int_2 (0, 0); + TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node); + layout_type (TREE_TYPE (null_pointer_node)); + + string_type_node = build_pointer_type (char_type_node); + const_string_type_node + = build_pointer_type (build_type_variant (char_type_node, 1, 0)); + + /* Make a type to be the domain of a few array types + whose domains don't really matter. + 200 is small enough that it always fits in size_t + and large enough that it can hold most function names for the + initializations of __FUNCTION__ and __PRETTY_FUNCTION__. */ + array_domain_type = build_index_type (build_int_2 (200, 0)); + + /* make a type for arrays of characters. + With luck nothing will ever really depend on the length of this + array type. */ + char_array_type_node + = build_array_type (char_type_node, array_domain_type); +#ifdef PASCAL_STRINGS + /* Pascal-type strings ("\pstuff") must be unsigned char* */ + unsigned_char_array_type_node + = build_array_type (unsigned_char_type_node, array_domain_type); +#endif + /* Likewise for arrays of ints. */ + int_array_type_node + = build_array_type (integer_type_node, array_domain_type); + /* This is for wide string constants. */ + wchar_array_type_node + = build_array_type (wchar_type_node, array_domain_type); + + default_function_type + = build_function_type (integer_type_node, NULL_TREE); + + ptr_type_node = build_pointer_type (void_type_node); + const_ptr_type_node + = build_pointer_type (build_type_variant (void_type_node, 1, 0)); + + endlink = tree_cons (NULL_TREE, void_type_node, NULL_TREE); + + void_ftype_any + = build_function_type (void_type_node, NULL_TREE); + + float_ftype_float + = build_function_type (float_type_node, + tree_cons (NULL_TREE, float_type_node, endlink)); + + double_ftype_double + = build_function_type (double_type_node, + tree_cons (NULL_TREE, double_type_node, endlink)); + + ldouble_ftype_ldouble + = build_function_type (long_double_type_node, + tree_cons (NULL_TREE, long_double_type_node, + endlink)); + + double_ftype_double_double + = build_function_type (double_type_node, + tree_cons (NULL_TREE, double_type_node, + tree_cons (NULL_TREE, + double_type_node, endlink))); + + int_ftype_int + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, endlink)); + + long_ftype_long + = build_function_type (long_integer_type_node, + tree_cons (NULL_TREE, + long_integer_type_node, endlink)); + + void_ftype_ptr_ptr_int + = build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)))); + + int_ftype_cptr_cptr_sizet + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, const_ptr_type_node, + tree_cons (NULL_TREE, const_ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)))); + + void_ftype_ptr_int_int + = build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)))); + + string_ftype_ptr_ptr /* strcpy prototype */ + = build_function_type (string_type_node, + tree_cons (NULL_TREE, string_type_node, + tree_cons (NULL_TREE, + const_string_type_node, + endlink))); + + int_ftype_string_string /* strcmp prototype */ + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, const_string_type_node, + tree_cons (NULL_TREE, + const_string_type_node, + endlink))); + + strlen_ftype /* strlen prototype */ + = build_function_type (flag_traditional ? integer_type_node : sizetype, + tree_cons (NULL_TREE, const_string_type_node, + endlink)); + + traditional_ptr_type_node + = (flag_traditional ? string_type_node : ptr_type_node); + + memcpy_ftype /* memcpy prototype */ + = build_function_type (traditional_ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, const_ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)))); + + memset_ftype /* memset prototype */ + = build_function_type (traditional_ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)))); + + ptr_ftype_void = build_function_type (ptr_type_node, endlink); + ptr_ftype_ptr + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, endlink)); + + builtin_function ("__builtin_constant_p", default_function_type, + BUILT_IN_CONSTANT_P, NULL_PTR); + + builtin_function ("__builtin_return_address", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + unsigned_type_node, + endlink)), + BUILT_IN_RETURN_ADDRESS, NULL_PTR); + + builtin_function ("__builtin_frame_address", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + unsigned_type_node, + endlink)), + BUILT_IN_FRAME_ADDRESS, NULL_PTR); + + builtin_function ("__builtin_aggregate_incoming_address", + build_function_type (ptr_type_node, NULL_TREE), + BUILT_IN_AGGREGATE_INCOMING_ADDRESS, NULL_PTR); + + /* Hooks for the DWARF 2 __throw routine. */ + builtin_function ("__builtin_unwind_init", + build_function_type (void_type_node, endlink), + BUILT_IN_UNWIND_INIT, NULL_PTR); + builtin_function ("__builtin_dwarf_cfa", ptr_ftype_void, + BUILT_IN_DWARF_CFA, NULL_PTR); + builtin_function ("__builtin_dwarf_fp_regnum", + build_function_type (unsigned_type_node, endlink), + BUILT_IN_DWARF_FP_REGNUM, NULL_PTR); + builtin_function ("__builtin_dwarf_reg_size", int_ftype_int, + BUILT_IN_DWARF_REG_SIZE, NULL_PTR); + builtin_function ("__builtin_frob_return_addr", ptr_ftype_ptr, + BUILT_IN_FROB_RETURN_ADDR, NULL_PTR); + builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr, + BUILT_IN_EXTRACT_RETURN_ADDR, NULL_PTR); + builtin_function + ("__builtin_eh_return", + build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, + type_for_mode (ptr_mode, 0), + tree_cons (NULL_TREE, + ptr_type_node, + endlink)))), + BUILT_IN_EH_RETURN, NULL_PTR); + + builtin_function ("__builtin_alloca", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)), + BUILT_IN_ALLOCA, "alloca"); + builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR); + /* Define alloca, ffs as builtins. + Declare _exit just to mark it as volatile. */ + if (! flag_no_builtin && !flag_no_nonansi_builtin) + { + temp = builtin_function ("alloca", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)), + BUILT_IN_ALLOCA, NULL_PTR); + /* Suppress error if redefined as a non-function. */ + DECL_BUILT_IN_NONANSI (temp) = 1; + temp = builtin_function ("ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR); + /* Suppress error if redefined as a non-function. */ + DECL_BUILT_IN_NONANSI (temp) = 1; + temp = builtin_function ("_exit", void_ftype_any, NOT_BUILT_IN, + NULL_PTR); + TREE_THIS_VOLATILE (temp) = 1; + TREE_SIDE_EFFECTS (temp) = 1; + /* Suppress error if redefined as a non-function. */ + DECL_BUILT_IN_NONANSI (temp) = 1; + } + + builtin_function ("__builtin_abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR); + builtin_function ("__builtin_fabsf", float_ftype_float, BUILT_IN_FABS, + NULL_PTR); + builtin_function ("__builtin_fabs", double_ftype_double, BUILT_IN_FABS, + NULL_PTR); + builtin_function ("__builtin_fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS, + NULL_PTR); + builtin_function ("__builtin_labs", long_ftype_long, BUILT_IN_LABS, + NULL_PTR); + builtin_function ("__builtin_saveregs", + build_function_type (ptr_type_node, NULL_TREE), + BUILT_IN_SAVEREGS, NULL_PTR); +/* EXPAND_BUILTIN_VARARGS is obsolete. */ +#if 0 + builtin_function ("__builtin_varargs", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)), + BUILT_IN_VARARGS, NULL_PTR); +#endif + builtin_function ("__builtin_classify_type", default_function_type, + BUILT_IN_CLASSIFY_TYPE, NULL_PTR); + builtin_function ("__builtin_next_arg", + build_function_type (ptr_type_node, NULL_TREE), + BUILT_IN_NEXT_ARG, NULL_PTR); + builtin_function ("__builtin_args_info", + build_function_type (integer_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)), + BUILT_IN_ARGS_INFO, NULL_PTR); + + /* Untyped call and return. */ + builtin_function ("__builtin_apply_args", + build_function_type (ptr_type_node, NULL_TREE), + BUILT_IN_APPLY_ARGS, NULL_PTR); + + temp = tree_cons (NULL_TREE, + build_pointer_type (build_function_type (void_type_node, + NULL_TREE)), + tree_cons (NULL_TREE, + ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink))); + builtin_function ("__builtin_apply", + build_function_type (ptr_type_node, temp), + BUILT_IN_APPLY, NULL_PTR); + builtin_function ("__builtin_return", + build_function_type (void_type_node, + tree_cons (NULL_TREE, + ptr_type_node, + endlink)), + BUILT_IN_RETURN, NULL_PTR); + + /* Currently under experimentation. */ + builtin_function ("__builtin_memcpy", memcpy_ftype, + BUILT_IN_MEMCPY, "memcpy"); + builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet, + BUILT_IN_MEMCMP, "memcmp"); + builtin_function ("__builtin_memset", memset_ftype, + BUILT_IN_MEMSET, "memset"); + builtin_function ("__builtin_strcmp", int_ftype_string_string, + BUILT_IN_STRCMP, "strcmp"); + builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr, + BUILT_IN_STRCPY, "strcpy"); + builtin_function ("__builtin_strlen", strlen_ftype, + BUILT_IN_STRLEN, "strlen"); + builtin_function ("__builtin_sqrtf", float_ftype_float, + BUILT_IN_FSQRT, "sqrtf"); + builtin_function ("__builtin_fsqrt", double_ftype_double, + BUILT_IN_FSQRT, "sqrt"); + builtin_function ("__builtin_sqrtl", ldouble_ftype_ldouble, + BUILT_IN_FSQRT, "sqrtl"); + builtin_function ("__builtin_sinf", float_ftype_float, + BUILT_IN_SIN, "sinf"); + builtin_function ("__builtin_sin", double_ftype_double, + BUILT_IN_SIN, "sin"); + builtin_function ("__builtin_sinl", ldouble_ftype_ldouble, + BUILT_IN_SIN, "sinl"); + builtin_function ("__builtin_cosf", float_ftype_float, + BUILT_IN_COS, "cosf"); + builtin_function ("__builtin_cos", double_ftype_double, + BUILT_IN_COS, "cos"); + builtin_function ("__builtin_cosl", ldouble_ftype_ldouble, + BUILT_IN_COS, "cosl"); + builtin_function ("__builtin_setjmp", + build_function_type (integer_type_node, + tree_cons (NULL_TREE, + ptr_type_node, endlink)), + BUILT_IN_SETJMP, NULL_PTR); + builtin_function ("__builtin_longjmp", + build_function_type + (void_type_node, + tree_cons (NULL, ptr_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink))), + BUILT_IN_LONGJMP, NULL_PTR); + builtin_function ("__builtin_trap", + build_function_type (void_type_node, endlink), + BUILT_IN_TRAP, NULL_PTR); + + /* In an ANSI C program, it is okay to supply built-in meanings + for these functions, since applications cannot validly use them + with any other meaning. + However, honor the -fno-builtin option. */ + if (!flag_no_builtin) + { + builtin_function ("abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR); + builtin_function ("fabsf", float_ftype_float, BUILT_IN_FABS, NULL_PTR); + builtin_function ("fabs", double_ftype_double, BUILT_IN_FABS, NULL_PTR); + builtin_function ("fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS, + NULL_PTR); + builtin_function ("labs", long_ftype_long, BUILT_IN_LABS, NULL_PTR); + builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY, NULL_PTR); + builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP, + NULL_PTR); + builtin_function ("memset", memset_ftype, BUILT_IN_MEMSET, NULL_PTR); + builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP, + NULL_PTR); + builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY, + NULL_PTR); + builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN, NULL_PTR); + builtin_function ("sqrtf", float_ftype_float, BUILT_IN_FSQRT, NULL_PTR); + builtin_function ("sqrt", double_ftype_double, BUILT_IN_FSQRT, NULL_PTR); + builtin_function ("sqrtl", ldouble_ftype_ldouble, BUILT_IN_FSQRT, + NULL_PTR); + builtin_function ("sinf", float_ftype_float, BUILT_IN_SIN, NULL_PTR); + builtin_function ("sin", double_ftype_double, BUILT_IN_SIN, NULL_PTR); + builtin_function ("sinl", ldouble_ftype_ldouble, BUILT_IN_SIN, NULL_PTR); + builtin_function ("cosf", float_ftype_float, BUILT_IN_COS, NULL_PTR); + builtin_function ("cos", double_ftype_double, BUILT_IN_COS, NULL_PTR); + builtin_function ("cosl", ldouble_ftype_ldouble, BUILT_IN_COS, NULL_PTR); + + /* Declare these functions volatile + to avoid spurious "control drops through" warnings. */ + /* Don't specify the argument types, to avoid errors + from certain code which isn't valid in ANSI but which exists. */ + temp = builtin_function ("abort", void_ftype_any, NOT_BUILT_IN, + NULL_PTR); + TREE_THIS_VOLATILE (temp) = 1; + TREE_SIDE_EFFECTS (temp) = 1; + temp = builtin_function ("exit", void_ftype_any, NOT_BUILT_IN, NULL_PTR); + TREE_THIS_VOLATILE (temp) = 1; + TREE_SIDE_EFFECTS (temp) = 1; + } + +#if 0 + /* Support for these has not been written in either expand_builtin + or build_function_call. */ + builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, NULL_PTR); + builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, NULL_PTR); + builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR, + NULL_PTR); + builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL, + NULL_PTR); + builtin_function ("__builtin_fmod", double_ftype_double_double, + BUILT_IN_FMOD, NULL_PTR); + builtin_function ("__builtin_frem", double_ftype_double_double, + BUILT_IN_FREM, NULL_PTR); + builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP, + NULL_PTR); + builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN, + NULL_PTR); +#endif + +#ifdef INIT_TARGET_INTRINSIC + /* Declare the target-specific builtin functions. */ + INIT_TARGET_INTRINSIC (endlink); +#endif + + pedantic_lvalues = pedantic; + + /* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */ + declare_function_name (); + + start_identifier_warnings (); + + /* Prepare to check format strings against argument lists. */ + init_function_format_info (); + + init_iterators (); + + incomplete_decl_finalize_hook = finish_incomplete_decl; + + lang_get_alias_set = c_get_alias_set; +} +#endif + +/* Return a definition for a builtin function named NAME and whose data type + is TYPE. TYPE should be a function type with argument types. + FUNCTION_CODE tells later passes how to compile calls to this function. + See tree.h for its possible values. + + If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME, + the name to be called if we can't opencode the function. */ + +tree +builtin_function (name, type, function_code, library_name) + const char *name; + tree type; + enum built_in_function function_code; + const char *library_name; +{ + tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + /* If -traditional, permit redefining a builtin function any way you like. + (Though really, if the program redefines these functions, + it probably won't work right unless compiled with -fno-builtin.) */ + if (flag_traditional && name[0] != '_') + DECL_BUILT_IN_NONANSI (decl) = 1; + if (library_name) + DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name); + make_decl_rtl (decl, NULL_PTR, 1); + pushdecl (decl); + if (function_code != NOT_BUILT_IN) + { + DECL_BUILT_IN (decl) = 1; + DECL_FUNCTION_CODE (decl) = function_code; + } + /* Warn if a function in the namespace for users + is used without an occasion to consider it declared. */ + if (name[0] != '_' || name[1] != '_') + C_DECL_ANTICIPATED (decl) = 1; + + return decl; +} + +tree +lang_builtin_function (name, type, function_code, library_name) + char *name; + tree type; + enum built_in_function function_code; + char *library_name; +{ + tree decl = builtin_function (name, type, function_code, library_name); + C_DECL_ANTICIPATED (decl) = 0; + return decl; +} + +int +lang_comptypes (t1, t2) + tree t1, t2; +{ + return comptypes (t1, t2); +} + +tree +lang_build_type_variant (type, constp, volatilep) + tree type; + int constp, volatilep; +{ + return c_build_type_variant (type, constp, volatilep); +} + +/* Called when a declaration is seen that contains no names to declare. + If its type is a reference to a structure, union or enum inherited + from a containing scope, shadow that tag name for the current scope + with a forward reference. + If its type defines a new named structure or union + or defines an enum, it is valid but we need not do anything here. + Otherwise, it is an error. */ + +void +shadow_tag (declspecs) + tree declspecs; +{ + shadow_tag_warned (declspecs, 0); +} + +void +shadow_tag_warned (declspecs, warned) + tree declspecs; + int warned; + /* 1 => we have done a pedwarn. 2 => we have done a warning, but + no pedwarn. */ +{ + int found_tag = 0; + register tree link; + tree specs, attrs; + + pending_invalid_xref = 0; + + /* Remove the attributes from declspecs, since they will confuse the + following code. */ + split_specs_attrs (declspecs, &specs, &attrs); + + for (link = specs; link; link = TREE_CHAIN (link)) + { + register tree value = TREE_VALUE (link); + register enum tree_code code = TREE_CODE (value); + + if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) + /* Used to test also that TYPE_SIZE (value) != 0. + That caused warning for `struct foo;' at top level in the file. */ + { + register tree name = lookup_tag_reverse (value); + register tree t; + + found_tag++; + + if (name == 0) + { + if (warned != 1 && code != ENUMERAL_TYPE) + /* Empty unnamed enum OK */ + { + pedwarn ("unnamed struct/union that defines no instances"); + warned = 1; + } + } + else + { + t = lookup_tag (code, name, current_binding_level, 1); + + if (t == 0) + { + t = make_node (code); + pushtag (name, t); + } + } + } + else + { + if (!warned && ! in_system_header) + { + warning ("useless keyword or type name in empty declaration"); + warned = 2; + } + } + } + + if (found_tag > 1) + error ("two types specified in one empty declaration"); + + if (warned != 1) + { + if (found_tag == 0) + pedwarn ("empty declaration"); + } +} + +/* Decode a "typename", such as "int **", returning a ..._TYPE node. */ + +tree +groktypename (typename) + tree typename; +{ + if (TREE_CODE (typename) != TREE_LIST) + return typename; + return grokdeclarator (TREE_VALUE (typename), + TREE_PURPOSE (typename), + TYPENAME, 0); +} + +/* Return a PARM_DECL node for a given pair of specs and declarator. */ + +tree +groktypename_in_parm_context (typename) + tree typename; +{ + if (TREE_CODE (typename) != TREE_LIST) + return typename; + return grokdeclarator (TREE_VALUE (typename), + TREE_PURPOSE (typename), + PARM, 0); +} + +/* Decode a declarator in an ordinary declaration or data definition. + This is called as soon as the type information and variable name + have been parsed, before parsing the initializer if any. + Here we create the ..._DECL node, fill in its type, + and put it on the list of decls for the current context. + The ..._DECL node is returned as the value. + + Exception: for arrays where the length is not specified, + the type is left null, to be filled in by `finish_decl'. + + Function definitions do not come here; they go to start_function + instead. However, external and forward declarations of functions + do go through here. Structure field declarations are done by + grokfield and not through here. */ + +/* Set this to zero to debug not using the temporary obstack + to parse initializers. */ +int debug_temp_inits = 1; + +tree +start_decl (declarator, declspecs, initialized, attributes, prefix_attributes) + tree declarator, declspecs; + int initialized; + tree attributes, prefix_attributes; +{ + register tree decl = grokdeclarator (declarator, declspecs, + NORMAL, initialized); + register tree tem; + int init_written = initialized; + + /* The corresponding pop_obstacks is in finish_decl. */ + push_obstacks_nochange (); + + if (warn_main > 0 && TREE_CODE (decl) != FUNCTION_DECL + && !strcmp (IDENTIFIER_POINTER (DECL_NAME (decl)), "main")) + warning_with_decl (decl, "`%s' is usually a function"); + + if (initialized) + /* Is it valid for this decl to have an initializer at all? + If not, set INITIALIZED to zero, which will indirectly + tell `finish_decl' to ignore the initializer once it is parsed. */ + switch (TREE_CODE (decl)) + { + case TYPE_DECL: + /* typedef foo = bar means give foo the same type as bar. + We haven't parsed bar yet, so `finish_decl' will fix that up. + Any other case of an initialization in a TYPE_DECL is an error. */ + if (pedantic || list_length (declspecs) > 1) + { + error ("typedef `%s' is initialized", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + } + break; + + case FUNCTION_DECL: + error ("function `%s' is initialized like a variable", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + break; + + case PARM_DECL: + /* DECL_INITIAL in a PARM_DECL is really DECL_ARG_TYPE. */ + error ("parameter `%s' is initialized", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + break; + + default: + /* Don't allow initializations for incomplete types + except for arrays which might be completed by the initialization. */ + if (TYPE_SIZE (TREE_TYPE (decl)) != 0) + { + /* A complete type is ok if size is fixed. */ + + if (TREE_CODE (TYPE_SIZE (TREE_TYPE (decl))) != INTEGER_CST + || C_DECL_VARIABLE_SIZE (decl)) + { + error ("variable-sized object may not be initialized"); + initialized = 0; + } + } + else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE) + { + error ("variable `%s' has initializer but incomplete type", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + } + else if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl))) == 0) + { + error ("elements of array `%s' have incomplete type", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + } + } + + if (initialized) + { +#if 0 /* Seems redundant with grokdeclarator. */ + if (current_binding_level != global_binding_level + && DECL_EXTERNAL (decl) + && TREE_CODE (decl) != FUNCTION_DECL) + warning ("declaration of `%s' has `extern' and is initialized", + IDENTIFIER_POINTER (DECL_NAME (decl))); +#endif + DECL_EXTERNAL (decl) = 0; + if (current_binding_level == global_binding_level) + TREE_STATIC (decl) = 1; + + /* Tell `pushdecl' this is an initialized decl + even though we don't yet have the initializer expression. + Also tell `finish_decl' it may store the real initializer. */ + DECL_INITIAL (decl) = error_mark_node; + } + + /* If this is a function declaration, write a record describing it to the + prototypes file (if requested). */ + + if (TREE_CODE (decl) == FUNCTION_DECL) + gen_aux_info_record (decl, 0, 0, TYPE_ARG_TYPES (TREE_TYPE (decl)) != 0); + + /* ANSI specifies that a tentative definition which is not merged with + a non-tentative definition behaves exactly like a definition with an + initializer equal to zero. (Section 3.7.2) + -fno-common gives strict ANSI behavior. Usually you don't want it. + This matters only for variables with external linkage. */ + if (! flag_no_common || ! TREE_PUBLIC (decl)) + DECL_COMMON (decl) = 1; + +#ifdef SET_DEFAULT_DECL_ATTRIBUTES + SET_DEFAULT_DECL_ATTRIBUTES (decl, attributes); +#endif + + /* Set attributes here so if duplicate decl, will have proper attributes. */ + decl_attributes (decl, attributes, prefix_attributes); + + /* Add this decl to the current binding level. + TEM may equal DECL or it may be a previous decl of the same name. */ + tem = pushdecl (decl); + + /* For a local variable, define the RTL now. */ + if (current_binding_level != global_binding_level + /* But not if this is a duplicate decl + and we preserved the rtl from the previous one + (which may or may not happen). */ + && DECL_RTL (tem) == 0) + { + if (TYPE_SIZE (TREE_TYPE (tem)) != 0) + expand_decl (tem); + else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE + && DECL_INITIAL (tem) != 0) + expand_decl (tem); + } + + if (init_written) + { + /* When parsing and digesting the initializer, + use temporary storage. Do this even if we will ignore the value. */ + if (current_binding_level == global_binding_level && debug_temp_inits) + temporary_allocation (); + } + + return tem; +} + +/* Finish processing of a declaration; + install its initial value. + If the length of an array type is not known before, + it must be determined now, from the initial value, or it is an error. */ + +void +finish_decl (decl, init, asmspec_tree) + tree decl, init; + tree asmspec_tree; +{ + register tree type = TREE_TYPE (decl); + int was_incomplete = (DECL_SIZE (decl) == 0); + int temporary = allocation_temporary_p (); + char *asmspec = 0; + + /* If a name was specified, get the string. */ + if (asmspec_tree) + asmspec = TREE_STRING_POINTER (asmspec_tree); + + /* If `start_decl' didn't like having an initialization, ignore it now. */ + + if (init != 0 && DECL_INITIAL (decl) == 0) + init = 0; + /* Don't crash if parm is initialized. */ + if (TREE_CODE (decl) == PARM_DECL) + init = 0; + + if (ITERATOR_P (decl)) + { + if (init == 0) + error_with_decl (decl, "iterator has no initial value"); + else + init = save_expr (init); + } + + if (init) + { + if (TREE_CODE (decl) != TYPE_DECL) + store_init_value (decl, init); + else + { + /* typedef foo = bar; store the type of bar as the type of foo. */ + TREE_TYPE (decl) = TREE_TYPE (init); + DECL_INITIAL (decl) = init = 0; + } + } + + /* Pop back to the obstack that is current for this binding level. + This is because MAXINDEX, rtl, etc. to be made below + must go in the permanent obstack. But don't discard the + temporary data yet. */ + pop_obstacks (); +#if 0 /* pop_obstacks was near the end; this is what was here. */ + if (current_binding_level == global_binding_level && temporary) + end_temporary_allocation (); +#endif + + /* Deduce size of array from initialization, if not already known */ + + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type) == 0 + && TREE_CODE (decl) != TYPE_DECL) + { + int do_default + = (TREE_STATIC (decl) + /* Even if pedantic, an external linkage array + may have incomplete type at first. */ + ? pedantic && !TREE_PUBLIC (decl) + : !DECL_EXTERNAL (decl)); + int failure + = complete_array_type (type, DECL_INITIAL (decl), do_default); + + /* Get the completed type made by complete_array_type. */ + type = TREE_TYPE (decl); + + if (failure == 1) + error_with_decl (decl, "initializer fails to determine size of `%s'"); + + if (failure == 2) + { + if (do_default) + error_with_decl (decl, "array size missing in `%s'"); + /* If a `static' var's size isn't known, + make it extern as well as static, so it does not get + allocated. + If it is not `static', then do not mark extern; + finish_incomplete_decl will give it a default size + and it will get allocated. */ + else if (!pedantic && TREE_STATIC (decl) && ! TREE_PUBLIC (decl)) + DECL_EXTERNAL (decl) = 1; + } + + /* TYPE_MAX_VALUE is always one less than the number of elements + in the array, because we start counting at zero. Therefore, + warn only if the value is less than zero. */ + if (pedantic && TYPE_DOMAIN (type) != 0 + && tree_int_cst_sgn (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < 0) + error_with_decl (decl, "zero or negative size array `%s'"); + + layout_decl (decl, 0); + } + + if (TREE_CODE (decl) == VAR_DECL) + { + if (DECL_SIZE (decl) == 0 + && TYPE_SIZE (TREE_TYPE (decl)) != 0) + layout_decl (decl, 0); + + if (DECL_SIZE (decl) == 0 + && (TREE_STATIC (decl) + ? + /* A static variable with an incomplete type + is an error if it is initialized. + Also if it is not file scope. + Otherwise, let it through, but if it is not `extern' + then it may cause an error message later. */ + /* A duplicate_decls call could have changed an extern + declaration into a file scope one. This can be detected + by TREE_ASM_WRITTEN being set. */ + (DECL_INITIAL (decl) != 0 + || (DECL_CONTEXT (decl) != 0 && ! TREE_ASM_WRITTEN (decl))) + : + /* An automatic variable with an incomplete type + is an error. */ + !DECL_EXTERNAL (decl))) + { + error_with_decl (decl, "storage size of `%s' isn't known"); + TREE_TYPE (decl) = error_mark_node; + } + + if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl)) + && DECL_SIZE (decl) != 0) + { + if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST) + constant_expression_warning (DECL_SIZE (decl)); + else + error_with_decl (decl, "storage size of `%s' isn't constant"); + } + + if (TREE_USED (type)) + TREE_USED (decl) = 1; + } + + /* If this is a function and an assembler name is specified, it isn't + builtin any more. Also reset DECL_RTL so we can give it its new + name. */ + if (TREE_CODE (decl) == FUNCTION_DECL && asmspec) + { + DECL_BUILT_IN (decl) = 0; + DECL_RTL (decl) = 0; + } + + /* Output the assembler code and/or RTL code for variables and functions, + unless the type is an undefined structure or union. + If not, it will get done when the type is completed. */ + + if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL) + { + if ((flag_traditional || TREE_PERMANENT (decl)) + && allocation_temporary_p ()) + { + push_obstacks_nochange (); + end_temporary_allocation (); + /* This is a no-op in c-lang.c or something real in objc-actions.c. */ + maybe_objc_check_decl (decl); + rest_of_decl_compilation (decl, asmspec, + (DECL_CONTEXT (decl) == 0 + || TREE_ASM_WRITTEN (decl)), + 0); + pop_obstacks (); + } + else + { + /* This is a no-op in c-lang.c or something real in objc-actions.c. */ + maybe_objc_check_decl (decl); + rest_of_decl_compilation (decl, asmspec, DECL_CONTEXT (decl) == 0, + 0); + } + if (DECL_CONTEXT (decl) != 0) + { + /* Recompute the RTL of a local array now + if it used to be an incomplete type. */ + if (was_incomplete + && ! TREE_STATIC (decl) && ! DECL_EXTERNAL (decl)) + { + /* If we used it already as memory, it must stay in memory. */ + TREE_ADDRESSABLE (decl) = TREE_USED (decl); + /* If it's still incomplete now, no init will save it. */ + if (DECL_SIZE (decl) == 0) + DECL_INITIAL (decl) = 0; + expand_decl (decl); + } + /* Compute and store the initial value. */ + if (TREE_CODE (decl) != FUNCTION_DECL) + expand_decl_init (decl); + } + } + + if (TREE_CODE (decl) == TYPE_DECL) + { + /* This is a no-op in c-lang.c or something real in objc-actions.c. */ + maybe_objc_check_decl (decl); + rest_of_decl_compilation (decl, NULL_PTR, DECL_CONTEXT (decl) == 0, + 0); + } + + /* ??? After 2.3, test (init != 0) instead of TREE_CODE. */ + /* This test used to include TREE_PERMANENT, however, we have the same + problem with initializers at the function level. Such initializers get + saved until the end of the function on the momentary_obstack. */ + if (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl)) + && temporary + /* DECL_INITIAL is not defined in PARM_DECLs, since it shares + space with DECL_ARG_TYPE. */ + && TREE_CODE (decl) != PARM_DECL) + { + /* We need to remember that this array HAD an initialization, + but discard the actual temporary nodes, + since we can't have a permanent node keep pointing to them. */ + /* We make an exception for inline functions, since it's + normal for a local extern redeclaration of an inline function + to have a copy of the top-level decl's DECL_INLINE. */ + if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node) + { + /* If this is a const variable, then preserve the + initializer instead of discarding it so that we can optimize + references to it. */ + /* This test used to include TREE_STATIC, but this won't be set + for function level initializers. */ + if (TREE_READONLY (decl) || ITERATOR_P (decl)) + { + preserve_initializer (); + /* Hack? Set the permanent bit for something that is permanent, + but not on the permanent obstack, so as to convince + output_constant_def to make its rtl on the permanent + obstack. */ + TREE_PERMANENT (DECL_INITIAL (decl)) = 1; + + /* The initializer and DECL must have the same (or equivalent + types), but if the initializer is a STRING_CST, its type + might not be on the right obstack, so copy the type + of DECL. */ + TREE_TYPE (DECL_INITIAL (decl)) = type; + } + else + DECL_INITIAL (decl) = error_mark_node; + } + } + + /* If requested, warn about definitions of large data objects. */ + + if (warn_larger_than + && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) + && !DECL_EXTERNAL (decl)) + { + register tree decl_size = DECL_SIZE (decl); + + if (decl_size && TREE_CODE (decl_size) == INTEGER_CST) + { + unsigned units = TREE_INT_CST_LOW(decl_size) / BITS_PER_UNIT; + + if (units > larger_than_size) + warning_with_decl (decl, "size of `%s' is %u bytes", units); + } + } + +#if 0 + /* Resume permanent allocation, if not within a function. */ + /* The corresponding push_obstacks_nochange is in start_decl, + and in push_parm_decl and in grokfield. */ + pop_obstacks (); +#endif + + /* If we have gone back from temporary to permanent allocation, + actually free the temporary space that we no longer need. */ + if (temporary && !allocation_temporary_p ()) + permanent_allocation (0); + + /* At the end of a declaration, throw away any variable type sizes + of types defined inside that declaration. There is no use + computing them in the following function definition. */ + if (current_binding_level == global_binding_level) + get_pending_sizes (); +} + +/* If DECL has a cleanup, build and return that cleanup here. + This is a callback called by expand_expr. */ + +#ifndef __GNUFORTRAN__ +tree +maybe_build_cleanup (decl) + tree decl ATTRIBUTE_UNUSED; +{ + /* There are no cleanups in C. */ + return NULL_TREE; +} +#endif + +/* Given a parsed parameter declaration, + decode it into a PARM_DECL and push that on the current binding level. + Also, for the sake of forward parm decls, + record the given order of parms in `parm_order'. */ + +void +push_parm_decl (parm) + tree parm; +{ + tree decl; + int old_immediate_size_expand = immediate_size_expand; + /* Don't try computing parm sizes now -- wait till fn is called. */ + immediate_size_expand = 0; + + /* The corresponding pop_obstacks is in finish_decl. */ + push_obstacks_nochange (); + + decl = grokdeclarator (TREE_VALUE (TREE_PURPOSE (parm)), + TREE_PURPOSE (TREE_PURPOSE (parm)), PARM, 0); + decl_attributes (decl, TREE_VALUE (TREE_VALUE (parm)), + TREE_PURPOSE (TREE_VALUE (parm))); + +#if 0 + if (DECL_NAME (decl)) + { + tree olddecl; + olddecl = lookup_name (DECL_NAME (decl)); + if (pedantic && olddecl != 0 && TREE_CODE (olddecl) == TYPE_DECL) + pedwarn_with_decl (decl, "ANSI C forbids parameter `%s' shadowing typedef"); + } +#endif + + decl = pushdecl (decl); + + immediate_size_expand = old_immediate_size_expand; + + current_binding_level->parm_order + = tree_cons (NULL_TREE, decl, current_binding_level->parm_order); + + /* Add this decl to the current binding level. */ + finish_decl (decl, NULL_TREE, NULL_TREE); +} + +/* Clear the given order of parms in `parm_order'. + Used at start of parm list, + and also at semicolon terminating forward decls. */ + +void +clear_parm_order () +{ + current_binding_level->parm_order = NULL_TREE; +} + +/* Make TYPE a complete type based on INITIAL_VALUE. + Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered, + 2 if there was no information (in which case assume 1 if DO_DEFAULT). */ + +int +complete_array_type (type, initial_value, do_default) + tree type; + tree initial_value; + int do_default; +{ + register tree maxindex = NULL_TREE; + int value = 0; + + if (initial_value) + { + /* Note MAXINDEX is really the maximum index, + one less than the size. */ + if (TREE_CODE (initial_value) == STRING_CST) + { + int eltsize + = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value))); + maxindex = build_int_2 ((TREE_STRING_LENGTH (initial_value) + / eltsize) - 1, 0); + } + else if (TREE_CODE (initial_value) == CONSTRUCTOR) + { + tree elts = CONSTRUCTOR_ELTS (initial_value); + maxindex = size_binop (MINUS_EXPR, integer_zero_node, size_one_node); + for (; elts; elts = TREE_CHAIN (elts)) + { + if (TREE_PURPOSE (elts)) + maxindex = TREE_PURPOSE (elts); + else + maxindex = size_binop (PLUS_EXPR, maxindex, size_one_node); + } + maxindex = copy_node (maxindex); + } + else + { + /* Make an error message unless that happened already. */ + if (initial_value != error_mark_node) + value = 1; + + /* Prevent further error messages. */ + maxindex = build_int_2 (0, 0); + } + } + + if (!maxindex) + { + if (do_default) + maxindex = build_int_2 (0, 0); + value = 2; + } + + if (maxindex) + { + TYPE_DOMAIN (type) = build_index_type (maxindex); + if (!TREE_TYPE (maxindex)) + TREE_TYPE (maxindex) = TYPE_DOMAIN (type); + } + + /* Lay out the type now that we can get the real answer. */ + + layout_type (type); + + return value; +} + +/* Given declspecs and a declarator, + determine the name and type of the object declared + and construct a ..._DECL node for it. + (In one case we can return a ..._TYPE node instead. + For invalid input we sometimes return 0.) + + DECLSPECS is a chain of tree_list nodes whose value fields + are the storage classes and type specifiers. + + DECL_CONTEXT says which syntactic context this declaration is in: + NORMAL for most contexts. Make a VAR_DECL or FUNCTION_DECL or TYPE_DECL. + FUNCDEF for a function definition. Like NORMAL but a few different + error messages in each case. Return value may be zero meaning + this definition is too screwy to try to parse. + PARM for a parameter declaration (either within a function prototype + or before a function body). Make a PARM_DECL, or return void_type_node. + TYPENAME if for a typename (in a cast or sizeof). + Don't make a DECL node; just return the ..._TYPE node. + FIELD for a struct or union field; make a FIELD_DECL. + BITFIELD for a field with specified width. + INITIALIZED is 1 if the decl has an initializer. + + In the TYPENAME case, DECLARATOR is really an absolute declarator. + It may also be so in the PARM case, for a prototype where the + argument type is specified but not the name. + + This function is where the complicated C meanings of `static' + and `extern' are interpreted. */ + +static tree +grokdeclarator (declarator, declspecs, decl_context, initialized) + tree declspecs; + tree declarator; + enum decl_context decl_context; + int initialized; +{ +#if defined(NEXT_SEMANTICS) + long long specbits = 0; +#else + int specbits = 0; +#endif + tree spec; + tree type = NULL_TREE; + int longlong = 0; + int constp; + int restrictp; + int volatilep; +#if defined (_WIN32) && defined (NEXT_PDO) + int stdcallp; // Needed to support the __stdcall keyword used by Microsoft +#endif + int type_quals = TYPE_UNQUALIFIED; + int inlinep; + int explicit_int = 0; + int explicit_char = 0; + int explicit_bool = 0; + int defaulted_int = 0; + tree typedef_decl = 0; + const char *name; + tree typedef_type = 0; + int funcdef_flag = 0; + enum tree_code innermost_code = ERROR_MARK; + int bitfield = 0; + int size_varies = 0; + tree decl_machine_attr = NULL_TREE; + + if (decl_context == BITFIELD) + bitfield = 1, decl_context = FIELD; + + if (decl_context == FUNCDEF) + funcdef_flag = 1, decl_context = NORMAL; + + push_obstacks_nochange (); + + if (flag_traditional && allocation_temporary_p ()) + end_temporary_allocation (); + + /* Look inside a declarator for the name being declared + and get it as a string, for an error message. */ + { + register tree decl = declarator; + name = 0; + + while (decl) + switch (TREE_CODE (decl)) + { + case ARRAY_REF: + case INDIRECT_REF: + case CALL_EXPR: + innermost_code = TREE_CODE (decl); + decl = TREE_OPERAND (decl, 0); + break; + + case IDENTIFIER_NODE: + name = IDENTIFIER_POINTER (decl); + decl = 0; + break; + + default: + abort (); + } + if (name == 0) + name = "type name"; + } + + /* A function definition's declarator must have the form of + a function declarator. */ + + if (funcdef_flag && innermost_code != CALL_EXPR) + return 0; + + /* Anything declared one level down from the top level + must be one of the parameters of a function + (because the body is at least two levels down). */ + + /* If this looks like a function definition, make it one, + even if it occurs where parms are expected. + Then store_parm_decls will reject it and not use it as a parm. */ + if (decl_context == NORMAL && !funcdef_flag + && current_binding_level->parm_flag) + decl_context = PARM; + + /* Look through the decl specs and record which ones appear. + Some typespecs are defined as built-in typenames. + Others, the ones that are modifiers of other types, + are represented by bits in SPECBITS: set the bits for + the modifiers that appear. Storage class keywords are also in SPECBITS. + + If there is a typedef name or a type, store the type in TYPE. + This includes builtin typedefs such as `int'. + + Set EXPLICIT_INT or EXPLICIT_CHAR if the type is `int' or `char' + and did not come from a user typedef. + + Set LONGLONG if `long' is mentioned twice. */ + + for (spec = declspecs; spec; spec = TREE_CHAIN (spec)) + { + register int i; + register tree id = TREE_VALUE (spec); + + if (id == ridpointers[(int) RID_INT]) + { + explicit_int = 1; + goto skiploop; /* turly optimise */ + } + if (id == ridpointers[(int) RID_CHAR]) + { + explicit_char = 1; + goto skiploop; /* turly optimise */ + } + if (id == ridpointers[(int) RID_BOOL]) + { + explicit_bool = 1; + goto found; /* turly: I think this is wrong. try 'skiploop' */ + } + if (TREE_CODE (id) == IDENTIFIER_NODE) + for (i = (int) RID_FIRST_MODIFIER; i < (int) RID_MAX; i++) + { + if (ridpointers[i] == id) + { + if (i == (int) RID_LONG && specbits & (1< 1) + pedwarn ("duplicate `const'"); + if (restrictp > 1) + pedwarn ("duplicate `restrict'"); + if (volatilep > 1) + pedwarn ("duplicate `volatile'"); + if (! flag_gen_aux_info && (TYPE_QUALS (type))) + type = TYPE_MAIN_VARIANT (type); + type_quals = ((constp ? TYPE_QUAL_CONST : 0) + | (restrictp ? TYPE_QUAL_RESTRICT : 0) + | (volatilep ? TYPE_QUAL_VOLATILE : 0)); + + /* Warn if two storage classes are given. Default to `auto'. */ + + { + int nclasses = 0; + + if (specbits & 1 << (int) RID_AUTO) nclasses++; + if (specbits & 1 << (int) RID_STATIC) nclasses++; + if (specbits & 1 << (int) RID_EXTERN) nclasses++; + if (specbits & 1 << (int) RID_REGISTER) nclasses++; + if (specbits & 1 << (int) RID_TYPEDEF) nclasses++; + if (specbits & 1 << (int) RID_ITERATOR) nclasses++; +#ifdef NEXT_SEMANTICS + if (specbits & 1 << (int) RID_PRIVATE_EXTERN) nclasses++; +#endif + + /* Warn about storage classes that are invalid for certain + kinds of declarations (parameters, typenames, etc.). */ + + if (nclasses > 1) + error ("multiple storage classes in declaration of `%s'", name); + else if (funcdef_flag + && (specbits + & ((1 << (int) RID_REGISTER) + | (1 << (int) RID_AUTO) + | (1 << (int) RID_TYPEDEF)))) + { + if (specbits & 1 << (int) RID_AUTO + && (pedantic || current_binding_level == global_binding_level)) + pedwarn ("function definition declared `auto'"); + if (specbits & 1 << (int) RID_REGISTER) + error ("function definition declared `register'"); + if (specbits & 1 << (int) RID_TYPEDEF) + error ("function definition declared `typedef'"); + specbits &= ~ ((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) + | (1 << (int) RID_AUTO)); + } + else if (decl_context != NORMAL && nclasses > 0) + { + if (decl_context == PARM && specbits & 1 << (int) RID_REGISTER) + ; + else + { + error ((decl_context == FIELD + ? "storage class specified for structure field `%s'" + : (decl_context == PARM + ? "storage class specified for parameter `%s'" + : "storage class specified for typename")), + name); + specbits &= ~ ((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) + | (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC) + | (1 << (int) RID_EXTERN)); + } + } + else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag) + { + /* `extern' with initialization is invalid if not at top level. */ + if (current_binding_level == global_binding_level) + warning ("`%s' initialized and declared `extern'", name); + else + error ("`%s' has both `extern' and initializer", name); + } + else if (specbits & 1 << (int) RID_EXTERN && funcdef_flag + && current_binding_level != global_binding_level) + error ("nested function `%s' declared `extern'", name); + else if (current_binding_level == global_binding_level + && specbits & (1 << (int) RID_AUTO)) + error ("top-level declaration of `%s' specifies `auto'", name); + else if ((specbits & 1 << (int) RID_ITERATOR) + && TREE_CODE (declarator) != IDENTIFIER_NODE) + { + error ("iterator `%s' has derived type", name); + type = error_mark_node; + } + else if ((specbits & 1 << (int) RID_ITERATOR) + && TREE_CODE (type) != INTEGER_TYPE) + { + error ("iterator `%s' has noninteger type", name); + type = error_mark_node; + } + } + + /* Now figure out the structure of the declarator proper. + Descend through it, creating more complex types, until we reach + the declared identifier (or NULL_TREE, in an absolute declarator). */ + + while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE) + { + if (type == error_mark_node) + { + declarator = TREE_OPERAND (declarator, 0); + continue; + } + + /* Each level of DECLARATOR is either an ARRAY_REF (for ...[..]), + an INDIRECT_REF (for *...), + a CALL_EXPR (for ...(...)), + an identifier (for the name being declared) + or a null pointer (for the place in an absolute declarator + where the name was omitted). + For the last two cases, we have just exited the loop. + + At this point, TYPE is the type of elements of an array, + or for a function to return, or for a pointer to point to. + After this sequence of ifs, TYPE is the type of the + array or function or pointer, and DECLARATOR has had its + outermost layer removed. */ + + if (TREE_CODE (declarator) == ARRAY_REF) + { + register tree itype = NULL_TREE; + register tree size = TREE_OPERAND (declarator, 1); + /* An uninitialized decl with `extern' is a reference. */ + int extern_ref = !initialized && (specbits & (1 << (int) RID_EXTERN)); + /* The index is a signed object `sizetype' bits wide. */ + tree index_type = signed_type (sizetype); + + declarator = TREE_OPERAND (declarator, 0); + + /* Check for some types that there cannot be arrays of. */ + + if (TYPE_MAIN_VARIANT (type) == void_type_node) + { + error ("declaration of `%s' as array of voids", name); + type = error_mark_node; + } + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("declaration of `%s' as array of functions", name); + type = error_mark_node; + } + + if (size == error_mark_node) + type = error_mark_node; + + if (type == error_mark_node) + continue; + + /* If this is a block level extern, it must live past the end + of the function so that we can check it against other extern + declarations (IDENTIFIER_LIMBO_VALUE). */ + if (extern_ref && allocation_temporary_p ()) + end_temporary_allocation (); + + /* If size was specified, set ITYPE to a range-type for that size. + Otherwise, ITYPE remains null. finish_decl may figure it out + from an initial value. */ + + if (size) + { + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (size); + + if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE + && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE) + { + error ("size of array `%s' has non-integer type", name); + size = integer_one_node; + } + + if (pedantic && integer_zerop (size)) + pedwarn ("ANSI C forbids zero-size array `%s'", name); + + if (TREE_CODE (size) == INTEGER_CST) + { + constant_expression_warning (size); + if (tree_int_cst_sgn (size) < 0) + { + error ("size of array `%s' is negative", name); + size = integer_one_node; + } + } + else + { + /* Make sure the array size remains visibly nonconstant + even if it is (eg) a const variable with known value. */ + size_varies = 1; + + if (pedantic) + { + if (TREE_CONSTANT (size)) + pedwarn ("ANSI C forbids array `%s' whose size can't be evaluated", name); + else + pedwarn ("ANSI C forbids variable-size array `%s'", name); + } + } + + /* Convert size to index_type, so that if it is a variable + the computations will be done in the proper mode. */ + itype = fold (build (MINUS_EXPR, index_type, + convert (index_type, size), + convert (index_type, size_one_node))); + + /* If that overflowed, the array is too big. + ??? While a size of INT_MAX+1 technically shouldn't cause + an overflow (because we subtract 1), the overflow is recorded + during the conversion to index_type, before the subtraction. + Handling this case seems like an unnecessary complication. */ + if (TREE_OVERFLOW (itype)) + { + error ("size of array `%s' is too large", name); + type = error_mark_node; + continue; + } + + if (size_varies) + itype = variable_size (itype); + itype = build_index_type (itype); + } + +#if 0 /* This had bad results for pointers to arrays, as in + union incomplete (*foo)[4]; */ + /* Complain about arrays of incomplete types, except in typedefs. */ + + if (TYPE_SIZE (type) == 0 + /* Avoid multiple warnings for nested array types. */ + && TREE_CODE (type) != ARRAY_TYPE + && !(specbits & (1 << (int) RID_TYPEDEF)) + && !C_TYPE_BEING_DEFINED (type)) + warning ("array type has incomplete element type"); +#endif + +#if 0 /* We shouldn't have a function type here at all! + Functions aren't allowed as array elements. */ + if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && (constp || volatilep)) + pedwarn ("ANSI C forbids const or volatile function types"); +#endif + + /* Build the array type itself, then merge any constancy or + volatility into the target type. We must do it in this order + to ensure that the TYPE_MAIN_VARIANT field of the array type + is set correctly. */ + + type = build_array_type (type, itype); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + +#if 0 /* don't clear these; leave them set so that the array type + or the variable is itself const or volatile. */ + type_quals = TYPE_UNQUALIFIED; +#endif + + if (size_varies) + C_TYPE_VARIABLE_SIZE (type) = 1; + } + else if (TREE_CODE (declarator) == CALL_EXPR) + { + int extern_ref = (!(specbits & (1 << (int) RID_AUTO)) + || current_binding_level == global_binding_level); + tree arg_types; + + /* Declaring a function type. + Make sure we have a valid type for the function to return. */ + if (type == error_mark_node) + continue; + + size_varies = 0; + + /* Warn about some types functions can't return. */ + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("`%s' declared as function returning a function", name); + type = integer_type_node; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + error ("`%s' declared as function returning an array", name); + type = integer_type_node; + } + +#ifndef TRADITIONAL_RETURN_FLOAT + /* Traditionally, declaring return type float means double. */ + + if (flag_traditional && TYPE_MAIN_VARIANT (type) == float_type_node) + type = double_type_node; +#endif /* TRADITIONAL_RETURN_FLOAT */ + + /* If this is a block level extern, it must live past the end + of the function so that we can check it against other extern + declarations (IDENTIFIER_LIMBO_VALUE). */ + if (extern_ref && allocation_temporary_p ()) + end_temporary_allocation (); + + /* Construct the function type and go to the next + inner layer of declarator. */ + + arg_types = grokparms (TREE_OPERAND (declarator, 1), + funcdef_flag + /* Say it's a definition + only for the CALL_EXPR + closest to the identifier. */ + && TREE_CODE (TREE_OPERAND (declarator, 0)) == IDENTIFIER_NODE); +#if 0 /* This seems to be false. We turn off temporary allocation + above in this function if -traditional. + And this code caused inconsistent results with prototypes: + callers would ignore them, and pass arguments wrong. */ + + /* Omit the arg types if -traditional, since the arg types + and the list links might not be permanent. */ + type = build_function_type (type, + flag_traditional + ? NULL_TREE : arg_types); +#endif + +#ifdef _WIN32 + /* If this function uses the stdcall calling conventions, mark the + tree as such by setting the stdcall_flag to 1. */ + if( stdcallp ) + { + type = build_type_copy( type ); /* $UNSURE$ */ + } +#endif /* _WIN32 */ + + /* Type qualifiers before the return type of the function + qualify the return type, not the function type. */ + if (type_quals) + type = c_build_qualified_type (type, type_quals); + type_quals = TYPE_UNQUALIFIED; + + type = build_function_type (type, arg_types); + declarator = TREE_OPERAND (declarator, 0); + +#ifdef _WIN32 + /* If this function uses the stdcall calling conventions, mark the + tree as such by setting the stdcall_flag to 1. */ + if( stdcallp ) + { + TYPE_STDCALL( type ) = 1; + } +// stdcallp = 0; +#endif /* _WIN32 */ + + + /* Set the TYPE_CONTEXTs for each tagged type which is local to + the formal parameter list of this FUNCTION_TYPE to point to + the FUNCTION_TYPE node itself. */ + + { + register tree link; + + for (link = last_function_parm_tags; + link; + link = TREE_CHAIN (link)) + TYPE_CONTEXT (TREE_VALUE (link)) = type; + } + } + else if (TREE_CODE (declarator) == INDIRECT_REF) + { + /* Merge any constancy or volatility into the target type + for the pointer. */ + + if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && type_quals) + pedwarn ("ANSI C forbids qualified function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + type_quals = TYPE_UNQUALIFIED; + size_varies = 0; + + type = build_pointer_type (type); + + /* Process a list of type modifier keywords + (such as const or volatile) that were given inside the `*'. */ + + if (TREE_TYPE (declarator)) + { + register tree typemodlist; + int erred = 0; + + constp = 0; + volatilep = 0; + restrictp = 0; + for (typemodlist = TREE_TYPE (declarator); typemodlist; + typemodlist = TREE_CHAIN (typemodlist)) + { + tree qualifier = TREE_VALUE (typemodlist); + + if (qualifier == ridpointers[(int) RID_CONST]) + constp++; + else if (qualifier == ridpointers[(int) RID_VOLATILE]) + volatilep++; +#ifdef _WIN32 + /* We had a problem under NT with the __stdcall keyword where calling + a __stdcall function indirectly wouldn't use the correct calling + convention. This was added so that when the pointer to the function + is declared it is marked as using the stdcall conventions. */ + else if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_STDCALL]) + { + stdcallp++; + type = build_type_copy( TREE_TYPE( type ) ); + type = build_pointer_type( type ); + TYPE_STDCALL( TREE_TYPE( type ) ) = 1; + } +#endif /* _WIN32 */ + else if (qualifier == ridpointers[(int) RID_RESTRICT]) + restrictp++; + else if (!erred) + { + erred = 1; + error ("invalid type modifier within pointer declarator"); + } + } + if (constp > 1) + pedwarn ("duplicate `const'"); + if (volatilep > 1) + pedwarn ("duplicate `volatile'"); +#ifdef _WIN32 + if (stdcallp > 1) + pedwarn ("duplicate `stdcall'"); +#endif /* _WIN32 */ + if (restrictp > 1) + pedwarn ("duplicate `restrict'"); + + type_quals = ((constp ? TYPE_QUAL_CONST : 0) + | (restrictp ? TYPE_QUAL_RESTRICT : 0) + | (volatilep ? TYPE_QUAL_VOLATILE : 0)); + } + + declarator = TREE_OPERAND (declarator, 0); + } + else + abort (); + + } + + /* Now TYPE has the actual type. */ + + /* Did array size calculations overflow? */ + + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_SIZE (type) + && TREE_OVERFLOW (TYPE_SIZE (type))) + error ("size of array `%s' is too large", name); + + /* If this is declaring a typedef name, return a TYPE_DECL. */ + + if (specbits & (1 << (int) RID_TYPEDEF)) + { + tree decl; + /* Note that the grammar rejects storage classes + in typenames, fields or parameters */ + if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && type_quals) + pedwarn ("ANSI C forbids qualified function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + decl = build_decl (TYPE_DECL, declarator, type); + if ((specbits & (1 << (int) RID_SIGNED)) + || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))) + C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1; +#ifdef _WIN32 + /* If this function uses the stdcall calling conventions, mark the + tree as such by setting the stdcall_flag to 1. */ + if( stdcallp ) + TYPE_STDCALL( type ) = 1; +// stdcallp = 0; +#endif /* _WIN32 */ + pop_obstacks (); + return decl; + } + + /* Detect the case of an array type of unspecified size + which came, as such, direct from a typedef name. + We must copy the type, so that each identifier gets + a distinct type, so that each identifier's size can be + controlled separately by its own initializer. */ + + if (type != 0 && typedef_type != 0 + && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (typedef_type) + && TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0) + { + type = build_array_type (TREE_TYPE (type), 0); + if (size_varies) + C_TYPE_VARIABLE_SIZE (type) = 1; + } + + /* If this is a type name (such as, in a cast or sizeof), + compute the type and return it now. */ + + if (decl_context == TYPENAME) + { + /* Note that the grammar rejects storage classes + in typenames, fields or parameters */ + if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && type_quals) + pedwarn ("ANSI C forbids const or volatile function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + pop_obstacks (); + return type; + } + + /* Aside from typedefs and type names (handle above), + `void' at top level (not within pointer) + is allowed only in public variables. + We don't complain about parms either, but that is because + a better error message can be made later. */ + + if (TYPE_MAIN_VARIANT (type) == void_type_node && decl_context != PARM + && ! ((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE) + && ((specbits & (1 << (int) RID_EXTERN)) + || (current_binding_level == global_binding_level + && !(specbits + & ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER))))))) + { + error ("variable or field `%s' declared void", name); + type = integer_type_node; + } + + /* Now create the decl, which may be a VAR_DECL, a PARM_DECL + or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */ + + { + register tree decl; + + if (decl_context == PARM) + { + tree type_as_written = type; + tree main_type; + + /* A parameter declared as an array of T is really a pointer to T. + One declared as a function is really a pointer to a function. */ + + if (TREE_CODE (type) == ARRAY_TYPE) + { + /* Transfer const-ness of array into that of type pointed to. */ + type = TREE_TYPE (type); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + type = build_pointer_type (type); + type_quals = TYPE_UNQUALIFIED; + size_varies = 0; + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (pedantic && type_quals) + pedwarn ("ANSI C forbids qualified function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + type = build_pointer_type (type); + type_quals = TYPE_UNQUALIFIED; + } + + decl = build_decl (PARM_DECL, declarator, type); + if (size_varies) + C_DECL_VARIABLE_SIZE (decl) = 1; + + /* Compute the type actually passed in the parmlist, + for the case where there is no prototype. + (For example, shorts and chars are passed as ints.) + When there is a prototype, this is overridden later. */ + + DECL_ARG_TYPE (decl) = type; + main_type = (type == error_mark_node + ? error_mark_node + : TYPE_MAIN_VARIANT (type)); + if (main_type == float_type_node) + DECL_ARG_TYPE (decl) = double_type_node; + /* Don't use TYPE_PRECISION to decide whether to promote, + because we should convert short if it's the same size as int, + but we should not convert long if it's the same size as int. */ + else if (TREE_CODE (main_type) != ERROR_MARK + && C_PROMOTING_INTEGER_TYPE_P (main_type)) + { + if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node) + && TREE_UNSIGNED (type)) + DECL_ARG_TYPE (decl) = unsigned_type_node; + else + DECL_ARG_TYPE (decl) = integer_type_node; + } + + DECL_ARG_TYPE_AS_WRITTEN (decl) = type_as_written; + } + else if (decl_context == FIELD) + { + /* Structure field. It may not be a function. */ + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("field `%s' declared as a function", name); + type = build_pointer_type (type); + } + else if (TREE_CODE (type) != ERROR_MARK && TYPE_SIZE (type) == 0) + { + error ("field `%s' has incomplete type", name); + type = error_mark_node; + } + /* Move type qualifiers down to element of an array. */ + if (TREE_CODE (type) == ARRAY_TYPE && type_quals) + { + type = build_array_type (c_build_qualified_type (TREE_TYPE (type), + type_quals), + TYPE_DOMAIN (type)); +#if 0 /* Leave the field const or volatile as well. */ + type_quals = TYPE_UNQUALIFIED; +#endif + } + decl = build_decl (FIELD_DECL, declarator, type); + if (size_varies) + C_DECL_VARIABLE_SIZE (decl) = 1; + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + /* Every function declaration is "external" + except for those which are inside a function body + in which `auto' is used. + That is a case not specified by ANSI C, + and we use it for forward declarations for nested functions. */ + int extern_ref = (!(specbits & (1 << (int) RID_AUTO)) + || current_binding_level == global_binding_level); + + if (specbits & (1 << (int) RID_AUTO) + && (pedantic || current_binding_level == global_binding_level)) + pedwarn ("invalid storage class for function `%s'", name); + if (specbits & ((1 << (int) RID_REGISTER) +#ifdef NEXT_SEMANTICS + | (1 << (int) RID_DIRECT) +#endif + )) + error ("invalid storage class for function `%s'", name); + /* Function declaration not at top level. + Storage classes other than `extern' are not allowed + and `extern' makes no difference. */ + if (current_binding_level != global_binding_level + && (specbits & ( (1 << (int) RID_STATIC) +#ifdef NEXT_SEMANTICS + | (1 << (int) RID_PRIVATE_EXTERN) +#endif + | (1 << (int) RID_INLINE))) + && pedantic) + pedwarn ("invalid storage class for function `%s'", name); + + /* If this is a block level extern, it must live past the end + of the function so that we can check it against other + extern declarations (IDENTIFIER_LIMBO_VALUE). */ + if (extern_ref && allocation_temporary_p ()) + end_temporary_allocation (); + + decl = build_decl (FUNCTION_DECL, declarator, type); + decl = build_decl_attribute_variant (decl, decl_machine_attr); + +#ifdef _WIN32 + if( stdcallp ) + DECL_STDCALL( decl ) = stdcallp; +#endif /* _WIN32 */ + if (pedantic && type_quals && ! DECL_IN_SYSTEM_HEADER (decl)) + pedwarn ("ANSI C forbids qualified function types"); + + if (pedantic && (constp || volatilep) + && ! DECL_IN_SYSTEM_HEADER (decl)) + pedwarn ("ANSI C forbids const or volatile functions"); + + if (pedantic + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl))) == void_type_node + && TYPE_QUALS (TREE_TYPE (TREE_TYPE (decl))) + && ! DECL_IN_SYSTEM_HEADER (decl)) + pedwarn ("ANSI C forbids qualified void function return type"); + + /* GNU C interprets a `volatile void' return type to indicate + that the function does not return. */ + if ((type_quals & TYPE_QUAL_VOLATILE) + && TREE_TYPE (TREE_TYPE (decl)) != void_type_node) + warning ("`noreturn' function returns non-void value"); + + if (extern_ref) + DECL_EXTERNAL (decl) = 1; + /* Record absence of global scope for `static' or `auto'. */ + TREE_PUBLIC (decl) + = !(specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_AUTO))); + +#ifdef NEXT_SEMANTICS + DECL_PRIVATE_EXTERN (decl) + = !!(specbits & (1 << (int) RID_PRIVATE_EXTERN)); + +#endif /* NEXT_SEMANTICS */ + + /* Record presence of `inline', if it is reasonable. */ + if (inlinep) + { + if (! strcmp (IDENTIFIER_POINTER (declarator), "main")) + warning ("cannot inline function `main'"); + else + /* Assume that otherwise the function can be inlined. */ + DECL_INLINE (decl) = 1; + + if (specbits & (1 << (int) RID_EXTERN)) + current_extern_inline = 1; + } + } + else + { + /* It's a variable. */ + /* An uninitialized decl with `extern' is a reference. */ + int extern_ref = !initialized && (specbits & ( (1 << (int) RID_EXTERN) +#ifdef NEXT_SEMANTICS + | (1 << (int) RID_PRIVATE_EXTERN) +#endif + )); + + /* Move type qualifiers down to element of an array. */ + if (TREE_CODE (type) == ARRAY_TYPE && type_quals) + { + type = build_array_type (c_build_qualified_type (TREE_TYPE (type), + type_quals), + TYPE_DOMAIN (type)); +#if 0 /* Leave the variable const or volatile as well. */ + type_quals = TYPE_UNQUALIFIED; +#endif + } + + /* If this is a block level extern, it must live past the end + of the function so that we can check it against other + extern declarations (IDENTIFIER_LIMBO_VALUE). */ + if (extern_ref && allocation_temporary_p ()) + end_temporary_allocation (); + + decl = build_decl (VAR_DECL, declarator, type); + if (size_varies) + C_DECL_VARIABLE_SIZE (decl) = 1; + + if (inlinep) + pedwarn_with_decl (decl, "variable `%s' declared `inline'"); + +#ifdef NEXT_SEMANTICS + if (specbits & (1 << (int) RID_DIRECT)) + error_with_decl (decl, "invalid storage class for variable `%s'"); +#endif + + DECL_EXTERNAL (decl) = extern_ref; + +#ifdef NEXT_SEMANTICS + DECL_PRIVATE_EXTERN (decl) + = !!(specbits & (1 << (int) RID_PRIVATE_EXTERN)); + + if ( !initialized + && !extern_ref + && TREE_CODE (type) == ARRAY_TYPE + && DECL_SIZE (decl) == NULL_TREE) + { + warning_with_decl (decl, "variable `%s' is implicitly extern"); + DECL_EXTERNAL (decl) = 1; + } +#endif + + /* At top level, the presence of a `static' or `register' storage + class specifier, or the absence of all storage class specifiers + makes this declaration a definition (perhaps tentative). Also, + the absence of both `static' and `register' makes it public. */ + if (current_binding_level == global_binding_level) + { + TREE_PUBLIC (decl) + = !(specbits + & ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER))); + TREE_STATIC (decl) = ! DECL_EXTERNAL (decl); + } + /* Not at top level, only `static' makes a static definition. */ + else + { + TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0; + TREE_PUBLIC (decl) = DECL_EXTERNAL (decl); + } + + if (specbits & 1 << (int) RID_ITERATOR) + ITERATOR_P (decl) = 1; + } + +#ifdef NEXT_SEMANTICS + /* KKK */ + if (specbits & 1 << (int) RID_RELATIVE) + { + if (TREE_CODE (type) != POINTER_TYPE) + pedwarn_with_decl (decl, "non-pointer declared __relative__"); + else if (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FIELD_DECL) + DECL_RELATIVE (decl) = 1; + } +#endif + + /* Record `register' declaration for warnings on & + and in case doing stupid register allocation. */ + + if (specbits & (1 << (int) RID_REGISTER)) + DECL_REGISTER (decl) = 1; + + /* Record constancy and volatility. */ + if (type_quals) + c_apply_type_quals_to_decl (type_quals, decl); + +#if defined (_WIN32) && defined (NEXT_PDO) + /* If this function is a stdcall function, set the stdcall_flag + using the TYPE_STDCALL macro. */ + if (stdcallp) + TYPE_STDCALL (decl) = 1; + if( (specbits & 1 << (int) RID_DLLIMPORT ) ) + { + DECL_EXTERNAL (decl) = 1; + { + char* newName = + (char*)malloc(strlen( IDENTIFIER_POINTER(DECL_NAME(decl)) ) + 7 ); // to allow for '_imp__' and \0 + sprintf( newName, "_imp__%s", IDENTIFIER_POINTER(DECL_NAME(decl)) ); + DECL_ASSEMBLER_NAME(decl) = get_identifier( newName ); + DECL_DLLIMPORT(decl) = 1; + } + } + else if (specbits & 1 << (int) RID_DLLEXPORT) + { + char prependCharacter = '_'; + char *tail = ""; + char *gen_stdcall_suffix (); + char *ident_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + int length = 1; /* account for prependCharacter */ + if (TREE_CODE (decl) != FUNCTION_DECL) + tail = ",data"; + if (exportNamesForDLL) + length += strlen (exportNamesForDLL); + length += strlen (" -export:"); + if (strncmp (ident_name, "objc_class_name", 15) == 0) + { + prependCharacter = '.'; + tail = ""; + } + length += strlen (tail); + if (stdcallp) + ident_name = gen_stdcall_suffix (decl); + length += strlen (ident_name); + if (exportNamesForDLL) + exportNamesForDLL = + (char *) realloc ((void*)exportNamesForDLL, length + 1); + else + { + exportNamesForDLL = (char *) malloc (length + 1); + *exportNamesForDLL = '\0'; + } + sprintf (exportNamesForDLL, "%s%s%c%s%s", exportNamesForDLL, + " -export:", prependCharacter, ident_name, tail); + } +#endif /* _WIN32 */ + + /* If a type has volatile components, it should be stored in memory. + Otherwise, the fact that those components are volatile + will be ignored, and would even crash the compiler. */ + if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl))) + mark_addressable (decl); + + pop_obstacks (); + + return decl; + } +} + +/* Decode the parameter-list info for a function type or function definition. + The argument is the value returned by `get_parm_info' (or made in parse.y + if there is an identifier list instead of a parameter decl list). + These two functions are separate because when a function returns + or receives functions then each is called multiple times but the order + of calls is different. The last call to `grokparms' is always the one + that contains the formal parameter names of a function definition. + + Store in `last_function_parms' a chain of the decls of parms. + Also store in `last_function_parm_tags' a chain of the struct, union, + and enum tags declared among the parms. + + Return a list of arg types to use in the FUNCTION_TYPE for this function. + + FUNCDEF_FLAG is nonzero for a function definition, 0 for + a mere declaration. A nonempty identifier-list gets an error message + when FUNCDEF_FLAG is zero. */ + +static tree +grokparms (parms_info, funcdef_flag) + tree parms_info; + int funcdef_flag; +{ + tree first_parm = TREE_CHAIN (parms_info); + + last_function_parms = TREE_PURPOSE (parms_info); + last_function_parm_tags = TREE_VALUE (parms_info); + + if (warn_strict_prototypes && first_parm == 0 && !funcdef_flag + && !in_system_header) + warning ("function declaration isn't a prototype"); + + if (first_parm != 0 + && TREE_CODE (TREE_VALUE (first_parm)) == IDENTIFIER_NODE) + { + if (! funcdef_flag) + pedwarn ("parameter names (without types) in function declaration"); + + last_function_parms = first_parm; + return 0; + } + else + { + tree parm; + tree typelt; + /* We no longer test FUNCDEF_FLAG. + If the arg types are incomplete in a declaration, + they must include undefined tags. + These tags can never be defined in the scope of the declaration, + so the types can never be completed, + and no call can be compiled successfully. */ +#if 0 + /* In a fcn definition, arg types must be complete. */ + if (funcdef_flag) +#endif + for (parm = last_function_parms, typelt = first_parm; + parm; + parm = TREE_CHAIN (parm)) + /* Skip over any enumeration constants declared here. */ + if (TREE_CODE (parm) == PARM_DECL) + { + /* Barf if the parameter itself has an incomplete type. */ + tree type = TREE_VALUE (typelt); + if (TYPE_SIZE (type) == 0) + { + if (funcdef_flag && DECL_NAME (parm) != 0) + error ("parameter `%s' has incomplete type", + IDENTIFIER_POINTER (DECL_NAME (parm))); + else + warning ("parameter has incomplete type"); + if (funcdef_flag) + { + TREE_VALUE (typelt) = error_mark_node; + TREE_TYPE (parm) = error_mark_node; + } + } +#if 0 /* This has been replaced by parm_tags_warning + which uses a more accurate criterion for what to warn about. */ + else + { + /* Now warn if is a pointer to an incomplete type. */ + while (TREE_CODE (type) == POINTER_TYPE + || TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + type = TYPE_MAIN_VARIANT (type); + if (TYPE_SIZE (type) == 0) + { + if (DECL_NAME (parm) != 0) + warning ("parameter `%s' points to incomplete type", + IDENTIFIER_POINTER (DECL_NAME (parm))); + else + warning ("parameter points to incomplete type"); + } + } +#endif + typelt = TREE_CHAIN (typelt); + } + + /* Allocate the list of types the way we allocate a type. */ + if (first_parm && ! TREE_PERMANENT (first_parm)) + { + /* Construct a copy of the list of types + on the saveable obstack. */ + tree result = NULL; + for (typelt = first_parm; typelt; typelt = TREE_CHAIN (typelt)) + result = saveable_tree_cons (NULL_TREE, TREE_VALUE (typelt), + result); + return nreverse (result); + } + else + /* The list we have is permanent already. */ + return first_parm; + } +} + + +/* Return a tree_list node with info on a parameter list just parsed. + The TREE_PURPOSE is a chain of decls of those parms. + The TREE_VALUE is a list of structure, union and enum tags defined. + The TREE_CHAIN is a list of argument types to go in the FUNCTION_TYPE. + This tree_list node is later fed to `grokparms'. + + VOID_AT_END nonzero means append `void' to the end of the type-list. + Zero means the parmlist ended with an ellipsis so don't append `void'. */ + +tree +get_parm_info (void_at_end) + int void_at_end; +{ + register tree decl, t; + register tree types = 0; + int erred = 0; + tree tags = gettags (); + tree parms = getdecls (); + tree new_parms = 0; + tree order = current_binding_level->parm_order; + + /* Just `void' (and no ellipsis) is special. There are really no parms. */ + if (void_at_end && parms != 0 + && TREE_CHAIN (parms) == 0 + && TYPE_MAIN_VARIANT (TREE_TYPE (parms)) == void_type_node + && DECL_NAME (parms) == 0) + { + parms = NULL_TREE; + storedecls (NULL_TREE); + return saveable_tree_cons (NULL_TREE, NULL_TREE, + saveable_tree_cons (NULL_TREE, void_type_node, NULL_TREE)); + } + + /* Extract enumerator values and other non-parms declared with the parms. + Likewise any forward parm decls that didn't have real parm decls. */ + for (decl = parms; decl; ) + { + tree next = TREE_CHAIN (decl); + + if (TREE_CODE (decl) != PARM_DECL) + { + TREE_CHAIN (decl) = new_parms; + new_parms = decl; + } + else if (TREE_ASM_WRITTEN (decl)) + { + error_with_decl (decl, "parameter `%s' has just a forward declaration"); + TREE_CHAIN (decl) = new_parms; + new_parms = decl; + } + decl = next; + } + + /* Put the parm decls back in the order they were in in the parm list. */ + for (t = order; t; t = TREE_CHAIN (t)) + { + if (TREE_CHAIN (t)) + TREE_CHAIN (TREE_VALUE (t)) = TREE_VALUE (TREE_CHAIN (t)); + else + TREE_CHAIN (TREE_VALUE (t)) = 0; + } + + new_parms = chainon (order ? nreverse (TREE_VALUE (order)) : 0, + new_parms); + + /* Store the parmlist in the binding level since the old one + is no longer a valid list. (We have changed the chain pointers.) */ + storedecls (new_parms); + + for (decl = new_parms; decl; decl = TREE_CHAIN (decl)) + /* There may also be declarations for enumerators if an enumeration + type is declared among the parms. Ignore them here. */ + if (TREE_CODE (decl) == PARM_DECL) + { + /* Since there is a prototype, + args are passed in their declared types. */ + tree type = TREE_TYPE (decl); + DECL_ARG_TYPE (decl) = type; +#ifdef PROMOTE_PROTOTYPES + if ((TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (decl) = integer_type_node; +#endif + + types = saveable_tree_cons (NULL_TREE, TREE_TYPE (decl), types); + if (TYPE_MAIN_VARIANT (TREE_VALUE (types)) == void_type_node && ! erred + && DECL_NAME (decl) == 0) + { + error ("`void' in parameter list must be the entire list"); + erred = 1; + } + } + + if (void_at_end) + return saveable_tree_cons (new_parms, tags, + nreverse (saveable_tree_cons (NULL_TREE, void_type_node, types))); + + return saveable_tree_cons (new_parms, tags, nreverse (types)); +} + +/* At end of parameter list, warn about any struct, union or enum tags + defined within. Do so because these types cannot ever become complete. */ + +void +parmlist_tags_warning () +{ + tree elt; + static int already; + + for (elt = current_binding_level->tags; elt; elt = TREE_CHAIN (elt)) + { + enum tree_code code = TREE_CODE (TREE_VALUE (elt)); + /* An anonymous union parm type is meaningful as a GNU extension. + So don't warn for that. */ + if (code == UNION_TYPE && TREE_PURPOSE (elt) == 0 && !pedantic) + continue; + if (TREE_PURPOSE (elt) != 0) + warning ("`%s %s' declared inside parameter list", + (code == RECORD_TYPE ? "struct" + : code == UNION_TYPE ? "union" + : "enum"), + IDENTIFIER_POINTER (TREE_PURPOSE (elt))); + else + warning ("anonymous %s declared inside parameter list", + (code == RECORD_TYPE ? "struct" + : code == UNION_TYPE ? "union" + : "enum")); + + if (! already) + { + warning ("its scope is only this definition or declaration, which is probably not what you want."); + already = 1; + } + } +} + +/* Get the struct, enum or union (CODE says which) with tag NAME. + Define the tag as a forward-reference if it is not defined. */ + +tree +xref_tag (code, name) + enum tree_code code; + tree name; +{ + int temporary = allocation_temporary_p (); + + /* If a cross reference is requested, look up the type + already defined for this tag and return it. */ + + register tree ref = lookup_tag (code, name, current_binding_level, 0); + /* Even if this is the wrong type of tag, return what we found. + There will be an error message anyway, from pending_xref_error. + If we create an empty xref just for an invalid use of the type, + the main result is to create lots of superfluous error messages. */ + if (ref) + return ref; + + push_obstacks_nochange (); + + if (current_binding_level == global_binding_level && temporary) + end_temporary_allocation (); + + /* If no such tag is yet defined, create a forward-reference node + and record it as the "definition". + When a real declaration of this type is found, + the forward-reference will be altered into a real type. */ + + ref = make_node (code); + if (code == ENUMERAL_TYPE) + { + /* (In ANSI, Enums can be referred to only if already defined.) */ + if (pedantic) + pedwarn ("ANSI C forbids forward references to `enum' types"); + /* Give the type a default layout like unsigned int + to avoid crashing if it does not get defined. */ + TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node); + TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node); + TREE_UNSIGNED (ref) = 1; + TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node); + TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node); + TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node); + } + + pushtag (name, ref); + + pop_obstacks (); + + return ref; +} + +/* Make sure that the tag NAME is defined *in the current binding level* + at least as a forward reference. + CODE says which kind of tag NAME ought to be. + + We also do a push_obstacks_nochange + whose matching pop is in finish_struct. */ + +tree +start_struct (code, name) + enum tree_code code; + tree name; +{ + /* If there is already a tag defined at this binding level + (as a forward reference), just return it. */ + + register tree ref = 0; + + push_obstacks_nochange (); + if (current_binding_level == global_binding_level) + end_temporary_allocation (); + + if (name != 0) + ref = lookup_tag (code, name, current_binding_level, 1); + if (ref && TREE_CODE (ref) == code) + { + C_TYPE_BEING_DEFINED (ref) = 1; + TYPE_PACKED (ref) = flag_pack_struct; + if (TYPE_FIELDS (ref)) +#ifdef NEXT_SEMANTICS + { + tree fields = TYPE_FIELDS (ref); +#endif + error ((code == UNION_TYPE ? "redefinition of `union %s'" + : "redefinition of `struct %s'"), + IDENTIFIER_POINTER (name)); +#ifdef NEXT_SEMANTICS + /* This is an approximation to the place the structure + is defined. Better than nothing. */ + error_with_file_and_line (DECL_SOURCE_FILE (fields), + DECL_SOURCE_LINE (fields), + (code == UNION_TYPE + ? "previous definition of `union %s'" + : "previous definition of `struct %s'"), + IDENTIFIER_POINTER (name)); + } +#endif + + return ref; + } + + /* Otherwise create a forward-reference just so the tag is in scope. */ + + ref = make_node (code); + pushtag (name, ref); + C_TYPE_BEING_DEFINED (ref) = 1; + TYPE_PACKED (ref) = flag_pack_struct; + return ref; +} + +/* Process the specs, declarator (NULL if omitted) and width (NULL if omitted) + of a structure component, returning a FIELD_DECL node. + WIDTH is non-NULL for bit fields only, and is an INTEGER_CST node. + + This is done during the parsing of the struct declaration. + The FIELD_DECL nodes are chained together and the lot of them + are ultimately passed to `build_struct' to make the RECORD_TYPE node. */ + +tree +grokfield (filename, line, declarator, declspecs, width) + const char *filename ATTRIBUTE_UNUSED; + int line ATTRIBUTE_UNUSED; + tree declarator, declspecs, width; +{ + tree value; + + /* The corresponding pop_obstacks is in finish_decl. */ + push_obstacks_nochange (); + + value = grokdeclarator (declarator, declspecs, width ? BITFIELD : FIELD, 0); + + finish_decl (value, NULL_TREE, NULL_TREE); + DECL_INITIAL (value) = width; + + maybe_objc_check_decl (value); + return value; +} + +/* Function to help qsort sort FIELD_DECLs by name order. */ + +static int +field_decl_cmp (xp, yp) + const GENERIC_PTR xp; + const GENERIC_PTR yp; +{ + tree *x = (tree *)xp, *y = (tree *)yp; + + if (DECL_NAME (*x) == DECL_NAME (*y)) + return 0; + if (DECL_NAME (*x) == NULL) + return -1; + if (DECL_NAME (*y) == NULL) + return 1; + if (DECL_NAME (*x) < DECL_NAME (*y)) + return -1; + return 1; +} + +/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T. + FIELDLIST is a chain of FIELD_DECL nodes for the fields. + ATTRIBUTES are attributes to be applied to the structure. + + We also do a pop_obstacks to match the push in start_struct. */ + +tree +finish_struct (t, fieldlist, attributes) + tree t; + tree fieldlist; + tree attributes; +{ + register tree x; + int old_momentary; + int toplevel = global_binding_level == current_binding_level; + + /* If this type was previously laid out as a forward reference, + make sure we lay it out again. */ + + TYPE_SIZE (t) = 0; + + decl_attributes (t, attributes, NULL_TREE); + + /* Nameless union parm types are useful as GCC extension. */ + if (! (TREE_CODE (t) == UNION_TYPE && TYPE_NAME (t) == 0) && !pedantic) + /* Otherwise, warn about any struct or union def. in parmlist. */ + if (in_parm_level_p ()) + { + if (pedantic) + pedwarn ((TREE_CODE (t) == UNION_TYPE ? "union defined inside parms" + : "structure defined inside parms")); + else if (! flag_traditional) + warning ((TREE_CODE (t) == UNION_TYPE ? "union defined inside parms" + : "structure defined inside parms")); + } + + old_momentary = suspend_momentary (); + + if (pedantic) + { + for (x = fieldlist; x; x = TREE_CHAIN (x)) + if (DECL_NAME (x) != 0) + break; + + if (x == 0) + pedwarn ((fieldlist + ? "%s has no named members" + : "%s has no members"), + TREE_CODE (t) == UNION_TYPE ? "union" : "struct"); + } + + + /* Install struct as DECL_CONTEXT of each field decl. + Also process specified field sizes. + Set DECL_FIELD_SIZE to the specified size, or 0 if none specified. + The specified size is found in the DECL_INITIAL. + Store 0 there, except for ": 0" fields (so we can find them + and delete them, below). */ + + for (x = fieldlist; x; x = TREE_CHAIN (x)) + { + DECL_CONTEXT (x) = t; + DECL_PACKED (x) |= TYPE_PACKED (t); + DECL_FIELD_SIZE (x) = 0; + + /* If any field is const, the structure type is pseudo-const. */ + if (TREE_READONLY (x)) + C_TYPE_FIELDS_READONLY (t) = 1; + else + { + /* A field that is pseudo-const makes the structure likewise. */ + tree t1 = TREE_TYPE (x); + while (TREE_CODE (t1) == ARRAY_TYPE) + t1 = TREE_TYPE (t1); + if ((TREE_CODE (t1) == RECORD_TYPE || TREE_CODE (t1) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (t1)) + C_TYPE_FIELDS_READONLY (t) = 1; + } + + /* Any field that is volatile means variables of this type must be + treated in some ways as volatile. */ + if (TREE_THIS_VOLATILE (x)) + C_TYPE_FIELDS_VOLATILE (t) = 1; + + /* Any field of nominal variable size implies structure is too. */ + if (C_DECL_VARIABLE_SIZE (x)) + C_TYPE_VARIABLE_SIZE (t) = 1; + + /* Detect invalid nested redefinition. */ + if (TREE_TYPE (x) == t) + error ("nested redefinition of `%s'", + IDENTIFIER_POINTER (TYPE_NAME (t))); + + /* Detect invalid bit-field size. */ + if (DECL_INITIAL (x)) + STRIP_NOPS (DECL_INITIAL (x)); + if (DECL_INITIAL (x)) + { + if (TREE_CODE (DECL_INITIAL (x)) == INTEGER_CST) + constant_expression_warning (DECL_INITIAL (x)); + else + { + error_with_decl (x, "bit-field `%s' width not an integer constant"); + DECL_INITIAL (x) = NULL; + } + } + + /* Detect invalid bit-field type. */ + if (DECL_INITIAL (x) + && TREE_CODE (TREE_TYPE (x)) != INTEGER_TYPE + && TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE) + { + error_with_decl (x, "bit-field `%s' has invalid type"); + DECL_INITIAL (x) = NULL; + } + if (DECL_INITIAL (x) && pedantic + && TYPE_MAIN_VARIANT (TREE_TYPE (x)) != integer_type_node + && TYPE_MAIN_VARIANT (TREE_TYPE (x)) != unsigned_type_node + /* Accept an enum that's equivalent to int or unsigned int. */ + && !(TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE + && (TYPE_PRECISION (TREE_TYPE (x)) + == TYPE_PRECISION (integer_type_node)))) + pedwarn_with_decl (x, "bit-field `%s' type invalid in ANSI C"); + + /* Detect and ignore out of range field width. */ + if (DECL_INITIAL (x)) + { + unsigned HOST_WIDE_INT width = TREE_INT_CST_LOW (DECL_INITIAL (x)); + + if (tree_int_cst_sgn (DECL_INITIAL (x)) < 0) + { + DECL_INITIAL (x) = NULL; + error_with_decl (x, "negative width in bit-field `%s'"); + } + else if (TREE_INT_CST_HIGH (DECL_INITIAL (x)) != 0 + || width > TYPE_PRECISION (TREE_TYPE (x))) + { + DECL_INITIAL (x) = NULL; + pedwarn_with_decl (x, "width of `%s' exceeds its type"); + } + else if (width == 0 && DECL_NAME (x) != 0) + { + error_with_decl (x, "zero width for bit-field `%s'"); + DECL_INITIAL (x) = NULL; + } + } + + /* Process valid field width. */ + if (DECL_INITIAL (x)) + { + register int width = TREE_INT_CST_LOW (DECL_INITIAL (x)); + + if (TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE + && (width < min_precision (TYPE_MIN_VALUE (TREE_TYPE (x)), + TREE_UNSIGNED (TREE_TYPE (x))) + || width < min_precision (TYPE_MAX_VALUE (TREE_TYPE (x)), + TREE_UNSIGNED (TREE_TYPE (x))))) + warning_with_decl (x, "`%s' is narrower than values of its type"); + + DECL_FIELD_SIZE (x) = width; + DECL_BIT_FIELD (x) = DECL_C_BIT_FIELD (x) = 1; + DECL_INITIAL (x) = NULL; + + if (width == 0) + { + /* field size 0 => force desired amount of alignment. */ +#ifdef EMPTY_FIELD_BOUNDARY + DECL_ALIGN (x) = MAX (DECL_ALIGN (x), EMPTY_FIELD_BOUNDARY); +#endif +#ifdef PCC_BITFIELD_TYPE_MATTERS + if (PCC_BITFIELD_TYPE_MATTERS) + DECL_ALIGN (x) = MAX (DECL_ALIGN (x), + TYPE_ALIGN (TREE_TYPE (x))); +#endif + } + } + else if (TREE_TYPE (x) != error_mark_node) + { + unsigned int min_align = (DECL_PACKED (x) ? BITS_PER_UNIT + : TYPE_ALIGN (TREE_TYPE (x))); + /* Non-bit-fields are aligned for their type, except packed + fields which require only BITS_PER_UNIT alignment. */ + DECL_ALIGN (x) = MAX (DECL_ALIGN (x), min_align); + } + } + + /* Now DECL_INITIAL is null on all members. */ + + /* Delete all duplicate fields from the fieldlist */ + for (x = fieldlist; x && TREE_CHAIN (x);) + /* Anonymous fields aren't duplicates. */ + if (DECL_NAME (TREE_CHAIN (x)) == 0) + x = TREE_CHAIN (x); + else + { + register tree y = fieldlist; + + while (1) + { + if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x))) + break; + if (y == x) + break; + y = TREE_CHAIN (y); + } + if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x))) + { + error_with_decl (TREE_CHAIN (x), "duplicate member `%s'"); + + /* Assign a bogus offset (0) to the entry we're about to remove, + because it might still be in another list (in case of ObjC + inheritance). */ + DECL_FIELD_BITPOS (TREE_CHAIN (x)) = integer_zero_node; + + /* Remove that duplicate entry from this struct's field list. */ + TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x)); + } + else x = TREE_CHAIN (x); + } + + /* Now we have the nearly final fieldlist. Record it, + then lay out the structure or union (including the fields). */ + + TYPE_FIELDS (t) = fieldlist; + + layout_type (t); + + /* Delete all zero-width bit-fields from the front of the fieldlist */ + while (fieldlist + && DECL_INITIAL (fieldlist)) + fieldlist = TREE_CHAIN (fieldlist); + /* Delete all such members from the rest of the fieldlist */ + for (x = fieldlist; x;) + { + if (TREE_CHAIN (x) && DECL_INITIAL (TREE_CHAIN (x))) + TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x)); + else x = TREE_CHAIN (x); + } + + /* Now we have the truly final field list. + Store it in this type and in the variants. */ + + TYPE_FIELDS (t) = fieldlist; + + /* If there are lots of fields, sort so we can look through them fast. + We arbitrarily consider 16 or more elts to be "a lot". */ + { + int len = 0; + + for (x = fieldlist; x; x = TREE_CHAIN (x)) + { + if (len > 15) + break; + len += 1; + } + if (len > 15) + { + tree *field_array; + char *space; + + len += list_length (x); + /* Use the same allocation policy here that make_node uses, to + ensure that this lives as long as the rest of the struct decl. + All decls in an inline function need to be saved. */ + if (allocation_temporary_p ()) + space = savealloc (sizeof (struct lang_type) + len * sizeof (tree)); + else + space = oballoc (sizeof (struct lang_type) + len * sizeof (tree)); + + TYPE_LANG_SPECIFIC (t) = (struct lang_type *) space; + TYPE_LANG_SPECIFIC (t)->len = len; + + field_array = &TYPE_LANG_SPECIFIC (t)->elts[0]; + len = 0; + for (x = fieldlist; x; x = TREE_CHAIN (x)) + field_array[len++] = x; + + qsort (field_array, len, sizeof (tree), field_decl_cmp); + } + } + + for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) + { + TYPE_FIELDS (x) = TYPE_FIELDS (t); + TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t); + TYPE_ALIGN (x) = TYPE_ALIGN (t); + } + + /* If this was supposed to be a transparent union, but we can't + make it one, warn and turn off the flag. */ + if (TREE_CODE (t) == UNION_TYPE + && TYPE_TRANSPARENT_UNION (t) + && TYPE_MODE (t) != DECL_MODE (TYPE_FIELDS (t))) + { + TYPE_TRANSPARENT_UNION (t) = 0; + warning ("union cannot be made transparent"); + } + + /* If this structure or union completes the type of any previous + variable declaration, lay it out and output its rtl. */ + + if ((x = current_binding_level->incomplete_list) != NULL_TREE) + { + tree prev = 0; /* use TREE_PURPOSE for prev ptr? */ + do { + tree ty, decl = TREE_VALUE (x); + + ty = TREE_TYPE (decl); + if (ty == t && TREE_CODE (decl) != TYPE_DECL) + { + layout_decl (decl, 0); + /* This is a no-op in c-lang.c or something real in objc-actions.c. */ + maybe_objc_check_decl (decl); + rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0); + if (! toplevel) + expand_decl (decl); + + if (prev) + TREE_CHAIN (prev) = TREE_CHAIN (x); + else + current_binding_level->incomplete_list = TREE_CHAIN (x); + /* Need to free X, but how? */ + } + else if (TYPE_SIZE (ty) == 0 + && TREE_CODE (ty) == ARRAY_TYPE) + { + tree element = ty; + while (TREE_CODE (element) == ARRAY_TYPE) + element = TREE_TYPE (element); + if (element == t) + layout_array_type (ty); + } + prev = x; + } while ((x = TREE_CHAIN (x)) != NULL); + } + + resume_momentary (old_momentary); + + /* Finish debugging output for this type. */ + rest_of_type_compilation (t, toplevel); + + /* The matching push is in start_struct. */ + pop_obstacks (); + + return t; +} + +/* Lay out the type T, and its element type, and so on. */ + +static void +layout_array_type (t) + tree t; +{ + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + layout_array_type (TREE_TYPE (t)); + layout_type (t); +} + +/* Begin compiling the definition of an enumeration type. + NAME is its name (or null if anonymous). + Returns the type object, as yet incomplete. + Also records info about it so that build_enumerator + may be used to declare the individual values as they are read. */ + +tree +start_enum (name) + tree name; +{ + register tree enumtype = 0; + + /* If this is the real definition for a previous forward reference, + fill in the contents in the same object that used to be the + forward reference. */ + + if (name != 0) + enumtype = lookup_tag (ENUMERAL_TYPE, name, current_binding_level, 1); + + /* The corresponding pop_obstacks is in finish_enum. */ + push_obstacks_nochange (); + /* If these symbols and types are global, make them permanent. */ + if (current_binding_level == global_binding_level) + end_temporary_allocation (); + + if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE) + { + enumtype = make_node (ENUMERAL_TYPE); + pushtag (name, enumtype); + } + + C_TYPE_BEING_DEFINED (enumtype) = 1; + + if (TYPE_VALUES (enumtype) != 0) + { + /* This enum is a named one that has been declared already. */ + error ("redeclaration of `enum %s'", IDENTIFIER_POINTER (name)); + + /* Completely replace its old definition. + The old enumerators remain defined, however. */ + TYPE_VALUES (enumtype) = 0; + } + + enum_next_value = integer_zero_node; + enum_overflow = 0; + + if (flag_short_enums) + TYPE_PACKED (enumtype) = 1; + + return enumtype; +} + +/* 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, VALUES a list of decl-value pairs, + and ATTRIBUTES are the specified attributes. + Returns ENUMTYPE. */ + +tree +finish_enum (enumtype, values, attributes) + tree enumtype; + tree values; + tree attributes; +{ + register tree pair, tem; + tree minnode = 0, maxnode = 0; + int lowprec, highprec, precision; + int toplevel = global_binding_level == current_binding_level; + + if (in_parm_level_p ()) + warning ("enum defined inside parms"); + + decl_attributes (enumtype, attributes, NULL_TREE); + + /* Calculate the maximum value of any enumerator in this type. */ + + if (values == error_mark_node) + minnode = maxnode = integer_zero_node; + else + for (pair = values; pair; pair = TREE_CHAIN (pair)) + { + tree value = TREE_VALUE (pair); + if (pair == values) + minnode = maxnode = TREE_VALUE (pair); + else + { + if (tree_int_cst_lt (maxnode, value)) + maxnode = value; + if (tree_int_cst_lt (value, minnode)) + minnode = value; + } + } + + TYPE_MIN_VALUE (enumtype) = minnode; + TYPE_MAX_VALUE (enumtype) = maxnode; + + /* An enum can have some negative values; then it is signed. */ + TREE_UNSIGNED (enumtype) = tree_int_cst_sgn (minnode) >= 0; + + /* Determine the precision this type needs. */ + + lowprec = min_precision (minnode, TREE_UNSIGNED (enumtype)); + highprec = min_precision (maxnode, TREE_UNSIGNED (enumtype)); + precision = MAX (lowprec, highprec); + + if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node)) + { + tree narrowest = type_for_size (precision, 1); + if (narrowest == 0) + { + warning ("enumeration values exceed range of largest integer"); + narrowest = long_long_integer_type_node; + } + + TYPE_PRECISION (enumtype) = TYPE_PRECISION (narrowest); + } + else + TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node); + + TYPE_SIZE (enumtype) = 0; + layout_type (enumtype); + + if (values != error_mark_node) + { + /* Change the type of the enumerators to be the enum type. + Formerly this was done only for enums that fit in an int, + but the comment said it was done only for enums wider than int. + It seems necessary to do this for wide enums, + and best not to change what's done for ordinary narrower ones. */ + for (pair = values; pair; pair = TREE_CHAIN (pair)) + { + TREE_TYPE (TREE_PURPOSE (pair)) = enumtype; + DECL_SIZE (TREE_PURPOSE (pair)) = TYPE_SIZE (enumtype); + if (TREE_CODE (TREE_PURPOSE (pair)) != FUNCTION_DECL) + DECL_ALIGN (TREE_PURPOSE (pair)) = TYPE_ALIGN (enumtype); + } + + /* Replace the decl nodes in VALUES with their names. */ + for (pair = values; pair; pair = TREE_CHAIN (pair)) + TREE_PURPOSE (pair) = DECL_NAME (TREE_PURPOSE (pair)); + + TYPE_VALUES (enumtype) = values; + } + + /* Fix up all variant types of this enum type. */ + for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem)) + { + TYPE_VALUES (tem) = TYPE_VALUES (enumtype); + TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype); + TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype); + TYPE_SIZE (tem) = TYPE_SIZE (enumtype); + TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype); + TYPE_MODE (tem) = TYPE_MODE (enumtype); + TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype); + TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype); + TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype); + } + + /* Finish debugging output for this type. */ + rest_of_type_compilation (enumtype, toplevel); + + /* This matches a push in start_enum. */ + pop_obstacks (); + + return enumtype; +} + +/* Build and install a CONST_DECL for one value of the + current enumeration type (one that was begun with start_enum). + Return a tree-list containing the CONST_DECL and its value. + Assignment of sequential values by default is handled here. */ + +tree +build_enumerator (name, value) + tree name, value; +{ + register tree decl, type; + + /* Validate and default VALUE. */ + + /* Remove no-op casts from the value. */ + if (value) + STRIP_TYPE_NOPS (value); + + if (value != 0) + { + if (TREE_CODE (value) == INTEGER_CST) + { + value = default_conversion (value); + constant_expression_warning (value); + } + else + { + error ("enumerator value for `%s' not integer constant", + IDENTIFIER_POINTER (name)); + value = 0; + } + } + + /* Default based on previous value. */ + /* It should no longer be possible to have NON_LVALUE_EXPR + in the default. */ + if (value == 0) + { + value = enum_next_value; + if (enum_overflow) + error ("overflow in enumeration values"); + } + + if (pedantic && ! int_fits_type_p (value, integer_type_node)) + { + pedwarn ("ANSI C restricts enumerator values to range of `int'"); + value = integer_zero_node; + } + + /* Set basis for default for next value. */ + enum_next_value = build_binary_op (PLUS_EXPR, value, integer_one_node, 0); + enum_overflow = tree_int_cst_lt (enum_next_value, value); + + /* Now create a declaration for the enum value name. */ + + type = TREE_TYPE (value); + type = type_for_size (MAX (TYPE_PRECISION (type), + TYPE_PRECISION (integer_type_node)), + ((flag_traditional + || TYPE_PRECISION (type) >= TYPE_PRECISION (integer_type_node)) + && TREE_UNSIGNED (type))); + + decl = build_decl (CONST_DECL, name, type); + DECL_INITIAL (decl) = value; + TREE_TYPE (value) = type; + pushdecl (decl); + + return saveable_tree_cons (decl, value, NULL_TREE); +} + +/* Create the FUNCTION_DECL for a function definition. + DECLSPECS, DECLARATOR, PREFIX_ATTRIBUTES and ATTRIBUTES are the parts of + the declaration; they describe the function's name and the type it returns, + but twisted together in a fashion that parallels the syntax of C. + + This function creates a binding context for the function body + as well as setting up the FUNCTION_DECL in current_function_decl. + + Returns 1 on success. If the DECLARATOR is not suitable for a function + (it defines a datum instead), we return 0, which tells + yyparse to report a parse error. + + NESTED is nonzero for a function nested within another function. */ + +int +start_function (declspecs, declarator, prefix_attributes, attributes, nested) + tree declarator, declspecs, prefix_attributes, attributes; + int 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; + warn_about_return_type = 0; + current_extern_inline = 0; + c_function_varargs = 0; + 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, + cause a syntax error. */ + if (decl1 == 0) + { + immediate_size_expand = old_immediate_size_expand; + return 0; + } + + decl_attributes (decl1, prefix_attributes, attributes); + + announce_function (decl1); + + if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl1))) == 0) + { + error ("return-type is an incomplete type"); + /* Make it return void instead. */ + TREE_TYPE (decl1) + = build_function_type (void_type_node, + TYPE_ARG_TYPES (TREE_TYPE (decl1))); + } + + if (warn_about_return_type) + warning ("return-type defaults to `int'"); + + /* Save the parm names or decls from this function's declarator + where store_parm_decls will find them. */ + current_function_parms = last_function_parms; + current_function_parm_tags = last_function_parm_tags; + + /* Make the init_value nonzero so pushdecl knows this is not tentative. + error_mark_node is replaced below (in poplevel) with the BLOCK. */ + DECL_INITIAL (decl1) = error_mark_node; + + /* If this definition isn't a prototype and we had a prototype declaration + before, copy the arg type info from that prototype. + But not if what we had before was a builtin function. */ + old_decl = lookup_name_current_level (DECL_NAME (decl1)); + if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE + && !DECL_BUILT_IN (old_decl) + && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1))) + == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (old_decl)))) + && TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0) + { + TREE_TYPE (decl1) = TREE_TYPE (old_decl); + current_function_prototype_file = DECL_SOURCE_FILE (old_decl); + 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 + && !(old_decl != 0 && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0)) + warning ("function declaration isn't a prototype"); + /* Optionally warn of any global def with no previous prototype. */ + else if (warn_missing_prototypes + && TREE_PUBLIC (decl1) + && !(old_decl != 0 && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0) + && strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1)))) + warning_with_decl (decl1, "no previous prototype for `%s'"); + /* Optionally warn of any def with no previous prototype + if the function has already been used. */ + else if (warn_missing_prototypes + && old_decl != 0 && TREE_USED (old_decl) + && 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. */ + else if (warn_missing_declarations + && TREE_PUBLIC (decl1) + && old_decl == 0 + && strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1)))) + warning_with_decl (decl1, "no previous declaration for `%s'"); + /* 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 == IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1))) + warning_with_decl (decl1, + "`%s' was used with no declaration before its definition"); + + /* This is a definition, not a reference. + So normally clear DECL_EXTERNAL. + However, `extern inline' acts like a declaration + except for defining how to inline. So set DECL_EXTERNAL in that case. */ + DECL_EXTERNAL (decl1) = current_extern_inline; + +#ifdef SET_DEFAULT_DECL_ATTRIBUTES + SET_DEFAULT_DECL_ATTRIBUTES (decl1, attributes); +#endif + + /* This function exists in static storage. + (This does not mean `static' in the C sense!) */ + TREE_STATIC (decl1) = 1; + + /* A nested function is not global. */ + if (current_function_decl != 0) + TREE_PUBLIC (decl1) = 0; + + /* Warn for unlikely, improbable, or stupid declarations of `main'. */ + if (warn_main > 0 + && strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1))) == 0) + { + tree args; + int argct = 0; + + if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1))) + != integer_type_node) + pedwarn_with_decl (decl1, "return type of `%s' is not `int'"); + + for (args = TYPE_ARG_TYPES (TREE_TYPE (decl1)); args; + args = TREE_CHAIN (args)) + { + tree type = args ? TREE_VALUE (args) : 0; + + if (type == void_type_node) + break; + + ++argct; + switch (argct) + { + case 1: + if (TYPE_MAIN_VARIANT (type) != integer_type_node) + pedwarn_with_decl (decl1, + "first argument of `%s' should be `int'"); + break; + + case 2: + if (TREE_CODE (type) != POINTER_TYPE + || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) + != char_type_node)) + pedwarn_with_decl (decl1, + "second argument of `%s' should be `char **'"); + break; + + case 3: + if (TREE_CODE (type) != POINTER_TYPE + || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) + != char_type_node)) + pedwarn_with_decl (decl1, + "third argument of `%s' should probably be `char **'"); + break; + } + } + + /* It is intentional that this message does not mention the third + argument, which is warned for only pedantically, because it's + blessed by mention in an appendix of the standard. */ + if (argct > 0 && (argct < 2 || argct > 3)) + pedwarn_with_decl (decl1, "`%s' takes only zero or two arguments"); + + if (argct == 3 && pedantic) + pedwarn_with_decl (decl1, "third argument of `%s' is deprecated"); + + if (! TREE_PUBLIC (decl1)) + pedwarn_with_decl (decl1, "`%s' is normally a non-static function"); + } + + /* Record the decl so that the function name is defined. + If we already have a decl for this name, and it is a FUNCTION_DECL, + use the old decl. */ + + current_function_decl = pushdecl (decl1); + + pushlevel (0); + declare_parm_level (1); + current_binding_level->subblocks_tag_transparent = 1; + + make_function_rtl (current_function_decl); + + restype = TREE_TYPE (TREE_TYPE (current_function_decl)); + /* Promote the value to int before returning it. */ + if (C_PROMOTING_INTEGER_TYPE_P (restype)) + { + /* It retains unsignedness if traditional + or if not really getting wider. */ + if (TREE_UNSIGNED (restype) + && (flag_traditional + || (TYPE_PRECISION (restype) + == TYPE_PRECISION (integer_type_node)))) + restype = unsigned_type_node; + else + restype = integer_type_node; + } + DECL_RESULT (current_function_decl) + = build_decl (RESULT_DECL, NULL_TREE, restype); + + if (!nested) + /* Allocate further tree nodes temporarily during compilation + of this function only. */ + temporary_allocation (); + + /* If this fcn was already referenced via a block-scope `extern' decl + (or an implicit decl), propagate certain information about the usage. */ + if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl))) + TREE_ADDRESSABLE (current_function_decl) = 1; + + immediate_size_expand = old_immediate_size_expand; + + return 1; +} + +/* Record that this function is going to be a varargs function. + This is called before store_parm_decls, which is too early + to call mark_varargs directly. */ + +void +c_mark_varargs () +{ + c_function_varargs = 1; +} + +/* Store the parameter declarations into the current function declaration. + This is called after parsing the parameter declarations, before + digesting the body of the function. + + For an old-style definition, modify the function's type + to specify at least the number of arguments. */ + +void +store_parm_decls () +{ + register tree fndecl = current_function_decl; + register tree parm; + + /* This is either a chain of PARM_DECLs (if a prototype was used) + or a list of IDENTIFIER_NODEs (for an old-fashioned C definition). */ + tree specparms = current_function_parms; + + /* This is a list of types declared among parms in a prototype. */ + tree parmtags = current_function_parm_tags; + + /* This is a chain of PARM_DECLs from old-style parm declarations. */ + register tree parmdecls = getdecls (); + + /* This is a chain of any other decls that came in among the parm + declarations. If a parm is declared with enum {foo, bar} x; + then CONST_DECLs for foo and bar are put here. */ + tree nonparms = 0; + + /* Nonzero if this definition is written with a prototype. */ + int prototype = 0; + + if (specparms != 0 && TREE_CODE (specparms) != TREE_LIST) + { + /* This case is when the function was defined with an ANSI prototype. + The parms already have decls, so we need not do anything here + except record them as in effect + and complain if any redundant old-style parm decls were written. */ + + register tree next; + tree others = 0; + + prototype = 1; + + if (parmdecls != 0) + { + tree decl, link; + + error_with_decl (fndecl, + "parm types given both in parmlist and separately"); + /* Get rid of the erroneous decls; don't keep them on + the list of parms, since they might not be PARM_DECLs. */ + for (decl = current_binding_level->names; + decl; decl = TREE_CHAIN (decl)) + if (DECL_NAME (decl)) + IDENTIFIER_LOCAL_VALUE (DECL_NAME (decl)) = 0; + for (link = current_binding_level->shadowed; + link; link = TREE_CHAIN (link)) + IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + current_binding_level->names = 0; + current_binding_level->shadowed = 0; + } + + specparms = nreverse (specparms); + for (parm = specparms; parm; parm = next) + { + next = TREE_CHAIN (parm); + if (TREE_CODE (parm) == PARM_DECL) + { + if (DECL_NAME (parm) == 0) + error_with_decl (parm, "parameter name omitted"); + else if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == void_type_node) + { + error_with_decl (parm, "parameter `%s' declared void"); + /* Change the type to error_mark_node so this parameter + will be ignored by assign_parms. */ + TREE_TYPE (parm) = error_mark_node; + } + pushdecl (parm); + } + else + { + /* If we find an enum constant or a type tag, + put it aside for the moment. */ + TREE_CHAIN (parm) = 0; + others = chainon (others, parm); + } + } + + /* Get the decls in their original chain order + and record in the function. */ + DECL_ARGUMENTS (fndecl) = getdecls (); + +#if 0 + /* If this function takes a variable number of arguments, + add a phony parameter to the end of the parm list, + to represent the position of the first unnamed argument. */ + if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))) + != void_type_node) + { + tree dummy = build_decl (PARM_DECL, NULL_TREE, void_type_node); + /* Let's hope the address of the unnamed parm + won't depend on its type. */ + TREE_TYPE (dummy) = integer_type_node; + DECL_ARG_TYPE (dummy) = integer_type_node; + DECL_ARGUMENTS (fndecl) + = chainon (DECL_ARGUMENTS (fndecl), dummy); + } +#endif + + /* Now pushdecl the enum constants. */ + for (parm = others; parm; parm = next) + { + next = TREE_CHAIN (parm); + if (DECL_NAME (parm) == 0) + ; + else if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == void_type_node) + ; + else if (TREE_CODE (parm) != PARM_DECL) + pushdecl (parm); + } + + storetags (chainon (parmtags, gettags ())); + } + else + { + /* SPECPARMS is an identifier list--a chain of TREE_LIST nodes + each with a parm name as the TREE_VALUE. + + PARMDECLS is a chain of declarations for parameters. + Warning! It can also contain CONST_DECLs which are not parameters + but are names of enumerators of any enum types + declared among the parameters. + + First match each formal parameter name with its declaration. + Associate decls with the names and store the decls + into the TREE_PURPOSE slots. */ + + for (parm = parmdecls; parm; parm = TREE_CHAIN (parm)) + DECL_RESULT (parm) = 0; + + for (parm = specparms; parm; parm = TREE_CHAIN (parm)) + { + register tree tail, found = NULL; + + if (TREE_VALUE (parm) == 0) + { + error_with_decl (fndecl, "parameter name missing from parameter list"); + TREE_PURPOSE (parm) = 0; + continue; + } + + /* See if any of the parmdecls specifies this parm by name. + Ignore any enumerator decls. */ + for (tail = parmdecls; tail; tail = TREE_CHAIN (tail)) + if (DECL_NAME (tail) == TREE_VALUE (parm) + && TREE_CODE (tail) == PARM_DECL) + { + found = tail; + break; + } + + /* If declaration already marked, we have a duplicate name. + Complain, and don't use this decl twice. */ + if (found && DECL_RESULT (found) != 0) + { + error_with_decl (found, "multiple parameters named `%s'"); + found = 0; + } + + /* If the declaration says "void", complain and ignore it. */ + if (found && TYPE_MAIN_VARIANT (TREE_TYPE (found)) == void_type_node) + { + error_with_decl (found, "parameter `%s' declared void"); + TREE_TYPE (found) = integer_type_node; + DECL_ARG_TYPE (found) = integer_type_node; + layout_decl (found, 0); + } + + /* Traditionally, a parm declared float is actually a double. */ + if (found && flag_traditional + && TYPE_MAIN_VARIANT (TREE_TYPE (found)) == float_type_node) + { + TREE_TYPE (found) = double_type_node; + DECL_ARG_TYPE (found) = double_type_node; + layout_decl (found, 0); + } + + /* If no declaration found, default to int. */ + if (!found) + { + found = build_decl (PARM_DECL, TREE_VALUE (parm), + integer_type_node); + DECL_ARG_TYPE (found) = TREE_TYPE (found); + DECL_SOURCE_LINE (found) = DECL_SOURCE_LINE (fndecl); + DECL_SOURCE_FILE (found) = DECL_SOURCE_FILE (fndecl); + if (extra_warnings) + warning_with_decl (found, "type of `%s' defaults to `int'"); + pushdecl (found); + } + + TREE_PURPOSE (parm) = found; + + /* Mark this decl as "already found" -- see test, above. + It is safe to use DECL_RESULT for this + since it is not used in PARM_DECLs or CONST_DECLs. */ + DECL_RESULT (found) = error_mark_node; + } + + /* Put anything which is on the parmdecls chain and which is + not a PARM_DECL onto the list NONPARMS. (The types of + non-parm things which might appear on the list include + enumerators and NULL-named TYPE_DECL nodes.) Complain about + any actual PARM_DECLs not matched with any names. */ + + nonparms = 0; + for (parm = parmdecls; parm; ) + { + tree next = TREE_CHAIN (parm); + TREE_CHAIN (parm) = 0; + + if (TREE_CODE (parm) != PARM_DECL) + nonparms = chainon (nonparms, parm); + else + { + /* Complain about args with incomplete types. */ + if (TYPE_SIZE (TREE_TYPE (parm)) == 0) + { + error_with_decl (parm, "parameter `%s' has incomplete type"); + TREE_TYPE (parm) = error_mark_node; + } + + if (DECL_RESULT (parm) == 0) + { + error_with_decl (parm, + "declaration for parameter `%s' but no such parameter"); + /* Pretend the parameter was not missing. + This gets us to a standard state and minimizes + further error messages. */ + specparms + = chainon (specparms, + tree_cons (parm, NULL_TREE, NULL_TREE)); + } + } + + parm = next; + } + + /* Chain the declarations together in the order of the list of names. */ + /* Store that chain in the function decl, replacing the list of names. */ + parm = specparms; + DECL_ARGUMENTS (fndecl) = 0; + { + register tree last; + for (last = 0; parm; parm = TREE_CHAIN (parm)) + if (TREE_PURPOSE (parm)) + { + if (last == 0) + DECL_ARGUMENTS (fndecl) = TREE_PURPOSE (parm); + else + TREE_CHAIN (last) = TREE_PURPOSE (parm); + last = TREE_PURPOSE (parm); + TREE_CHAIN (last) = 0; + } + } + + /* If there was a previous prototype, + set the DECL_ARG_TYPE of each argument according to + the type previously specified, and report any mismatches. */ + + if (TYPE_ARG_TYPES (TREE_TYPE (fndecl))) + { + register tree type; + for (parm = DECL_ARGUMENTS (fndecl), + type = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); + parm || (type && (TYPE_MAIN_VARIANT (TREE_VALUE (type)) + != void_type_node)); + parm = TREE_CHAIN (parm), type = TREE_CHAIN (type)) + { + if (parm == 0 || type == 0 + || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) + { + error ("number of arguments doesn't match prototype"); + error_with_file_and_line (current_function_prototype_file, + current_function_prototype_line, + "prototype declaration"); + break; + } + /* Type for passing arg must be consistent + with that declared for the arg. */ + if (! comptypes (DECL_ARG_TYPE (parm), TREE_VALUE (type))) + { + if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) + == TYPE_MAIN_VARIANT (TREE_VALUE (type))) + { + /* Adjust argument to match prototype. E.g. a previous + `int foo(float);' prototype causes + `int foo(x) float x; {...}' to be treated like + `int foo(float x) {...}'. This is particularly + useful for argument types like uid_t. */ + DECL_ARG_TYPE (parm) = TREE_TYPE (parm); +#ifdef PROMOTE_PROTOTYPES + if ((TREE_CODE (TREE_TYPE (parm)) == INTEGER_TYPE + || TREE_CODE (TREE_TYPE (parm)) == ENUMERAL_TYPE) + && TYPE_PRECISION (TREE_TYPE (parm)) + < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (parm) = integer_type_node; +#endif + if (pedantic) + { + pedwarn ("promoted argument `%s' doesn't match prototype", + IDENTIFIER_POINTER (DECL_NAME (parm))); + warning_with_file_and_line + (current_function_prototype_file, + current_function_prototype_line, + "prototype declaration"); + } + } + /* If -traditional, allow `int' argument to match + `unsigned' prototype. */ + else if (! (flag_traditional + && TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == integer_type_node + && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == unsigned_type_node)) + { + error ("argument `%s' doesn't match prototype", + IDENTIFIER_POINTER (DECL_NAME (parm))); + error_with_file_and_line (current_function_prototype_file, + current_function_prototype_line, + "prototype declaration"); + } + } + } + TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = 0; + } + + /* Otherwise, create a prototype that would match. */ + + else + { + tree actual = 0, last = 0, type; + + for (parm = DECL_ARGUMENTS (fndecl); parm; parm = TREE_CHAIN (parm)) + { + type = perm_tree_cons (NULL_TREE, DECL_ARG_TYPE (parm), + NULL_TREE); + if (last) + TREE_CHAIN (last) = type; + else + actual = type; + last = type; + } + type = perm_tree_cons (NULL_TREE, void_type_node, NULL_TREE); + if (last) + TREE_CHAIN (last) = type; + else + actual = type; + + /* We are going to assign a new value for the TYPE_ACTUAL_ARG_TYPES + of the type of this function, but we need to avoid having this + affect the types of other similarly-typed functions, so we must + first force the generation of an identical (but separate) type + node for the relevant function type. The new node we create + will be a variant of the main variant of the original function + type. */ + + TREE_TYPE (fndecl) = build_type_copy (TREE_TYPE (fndecl)); + + TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = actual; + } + + /* Now store the final chain of decls for the arguments + as the decl-chain of the current lexical scope. + Put the enumerators in as well, at the front so that + DECL_ARGUMENTS is not modified. */ + + storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl))); + } + + /* Make sure the binding level for the top of the function body + gets a BLOCK if there are any in the function. + Otherwise, the dbx output is wrong. */ + + keep_next_if_subblocks = 1; + + /* ??? This might be an improvement, + but needs to be thought about some more. */ +#if 0 + keep_next_level_flag = 1; +#endif + + /* Write a record describing this function definition to the prototypes + file (if requested). */ + + gen_aux_info_record (fndecl, 1, 0, prototype); + + /* Initialize the RTL code for the function. */ + + init_function_start (fndecl, input_filename, lineno); + + /* If this is a varargs function, inform function.c. */ + + if (c_function_varargs) + mark_varargs (); + + /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function. */ + + declare_function_name (); + + /* Set up parameters and prepare for return, for the function. */ + + expand_function_start (fndecl, 0); + + /* If this function is `main', emit a call to `__main' + to run global initializers, etc. */ + if (DECL_NAME (fndecl) +#ifdef _WIN32 + && (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main") == 0 + || strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "WinMain") == 0) +#else + && strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main") == 0 +#endif /* _WIN32 */ + && DECL_CONTEXT (fndecl) == NULL_TREE) + expand_main_function (); +} + +/* SPECPARMS is an identifier list--a chain of TREE_LIST nodes + each with a parm name as the TREE_VALUE. A null pointer as TREE_VALUE + stands for an ellipsis in the identifier list. + + PARMLIST is the data returned by get_parm_info for the + parmlist that follows the semicolon. + + We return a value of the same sort that get_parm_info returns, + except that it describes the combination of identifiers and parmlist. */ + +tree +combine_parm_decls (specparms, parmlist, void_at_end) + tree specparms, parmlist; + int void_at_end; +{ + register tree fndecl = current_function_decl; + register tree parm; + + tree parmdecls = TREE_PURPOSE (parmlist); + + /* This is a chain of any other decls that came in among the parm + declarations. They were separated already by get_parm_info, + so we just need to keep them separate. */ + tree nonparms = TREE_VALUE (parmlist); + + tree types = 0; + + for (parm = parmdecls; parm; parm = TREE_CHAIN (parm)) + DECL_RESULT (parm) = 0; + + for (parm = specparms; parm; parm = TREE_CHAIN (parm)) + { + register tree tail, found = NULL; + + /* See if any of the parmdecls specifies this parm by name. */ + for (tail = parmdecls; tail; tail = TREE_CHAIN (tail)) + if (DECL_NAME (tail) == TREE_VALUE (parm)) + { + found = tail; + break; + } + + /* If declaration already marked, we have a duplicate name. + Complain, and don't use this decl twice. */ + if (found && DECL_RESULT (found) != 0) + { + error_with_decl (found, "multiple parameters named `%s'"); + found = 0; + } + + /* If the declaration says "void", complain and ignore it. */ + if (found && TYPE_MAIN_VARIANT (TREE_TYPE (found)) == void_type_node) + { + error_with_decl (found, "parameter `%s' declared void"); + TREE_TYPE (found) = integer_type_node; + DECL_ARG_TYPE (found) = integer_type_node; + layout_decl (found, 0); + } + + /* Traditionally, a parm declared float is actually a double. */ + if (found && flag_traditional + && TYPE_MAIN_VARIANT (TREE_TYPE (found)) == float_type_node) + { + TREE_TYPE (found) = double_type_node; + DECL_ARG_TYPE (found) = double_type_node; + layout_decl (found, 0); + } + + /* If no declaration found, default to int. */ + if (!found) + { + found = build_decl (PARM_DECL, TREE_VALUE (parm), + integer_type_node); + DECL_ARG_TYPE (found) = TREE_TYPE (found); + DECL_SOURCE_LINE (found) = DECL_SOURCE_LINE (fndecl); + DECL_SOURCE_FILE (found) = DECL_SOURCE_FILE (fndecl); + error_with_decl (found, "type of parameter `%s' is not declared"); + pushdecl (found); + } + + TREE_PURPOSE (parm) = found; + + /* Mark this decl as "already found" -- see test, above. + It is safe to use DECL_RESULT for this + since it is not used in PARM_DECLs or CONST_DECLs. */ + DECL_RESULT (found) = error_mark_node; + } + + /* Complain about any actual PARM_DECLs not matched with any names. */ + + for (parm = parmdecls; parm; ) + { + tree next = TREE_CHAIN (parm); + TREE_CHAIN (parm) = 0; + + /* Complain about args with incomplete types. */ + if (TYPE_SIZE (TREE_TYPE (parm)) == 0) + { + error_with_decl (parm, "parameter `%s' has incomplete type"); + TREE_TYPE (parm) = error_mark_node; + } + + if (DECL_RESULT (parm) == 0) + { + error_with_decl (parm, + "declaration for parameter `%s' but no such parameter"); + /* Pretend the parameter was not missing. + This gets us to a standard state and minimizes + further error messages. */ + specparms + = chainon (specparms, + tree_cons (parm, NULL_TREE, NULL_TREE)); + } + + parm = next; + } + + /* Chain the declarations together in the order of the list of names. + At the same time, build up a list of their types, in reverse order. */ + + parm = specparms; + parmdecls = 0; + { + register tree last; + for (last = 0; parm; parm = TREE_CHAIN (parm)) + if (TREE_PURPOSE (parm)) + { + if (last == 0) + parmdecls = TREE_PURPOSE (parm); + else + TREE_CHAIN (last) = TREE_PURPOSE (parm); + last = TREE_PURPOSE (parm); + TREE_CHAIN (last) = 0; + + types = saveable_tree_cons (NULL_TREE, TREE_TYPE (parm), types); + } + } + + if (void_at_end) + return saveable_tree_cons (parmdecls, nonparms, + nreverse (saveable_tree_cons (NULL_TREE, + void_type_node, + types))); + + return saveable_tree_cons (parmdecls, nonparms, nreverse (types)); +} + +/* Finish up a function declaration and compile that function + all the way to assembler language output. The free the storage + for the function definition. + + This is called after parsing the body of the function definition. + + NESTED is nonzero if the function being finished is nested in another. */ + +void +finish_function (nested) + int nested; +{ + register tree fndecl = current_function_decl; + +/* TREE_READONLY (fndecl) = 1; + This caused &foo to be of type ptr-to-const-function + which then got a warning when stored in a ptr-to-function variable. */ + + poplevel (1, 0, 1); + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; + + /* Must mark the RESULT_DECL as being in this function. */ + + DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl; + + /* Obey `register' declarations if `setjmp' is called in this fn. */ +#if defined(NEXT_SEMANTICS) || defined(NEXT_PDO) + /* Be even more conservative on NeXT so that exception handling + will work reliably. */ + if (current_function_calls_setjmp) +#else + if (flag_traditional && current_function_calls_setjmp) +#endif + { + setjmp_protect (DECL_INITIAL (fndecl)); + setjmp_protect_args (); + } + + if (! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main")) + { + if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))) + != integer_type_node) + { + /* If warn_main is 1 (-Wmain) or 2 (-Wall), we have already warned. + If warn_main is -1 (-Wno-main) we don't want to be warned. */ + if (! warn_main) + pedwarn_with_decl (fndecl, "return type of `%s' is not `int'"); + } + else + { +#ifdef DEFAULT_MAIN_RETURN + /* Make it so that `main' always returns success by default. */ + DEFAULT_MAIN_RETURN; +#endif + } + } + + /* Generate rtl for function exit. */ + expand_function_end (input_filename, lineno, 0); + + /* So we can tell if jump_optimize sets it to 1. */ + can_reach_end = 0; + + /* Run the optimizers and output the assembler code for this function. */ + rest_of_compilation (fndecl); + + current_function_returns_null |= can_reach_end; + + if (warn_missing_noreturn + && !TREE_THIS_VOLATILE (fndecl) + && !current_function_returns_null + && !current_function_returns_value) + warning ("function might be possible candidate for attribute `noreturn'"); + + if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null) + warning ("`noreturn' function does return"); + else if (warn_return_type && can_reach_end + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))) != void_type_node) + /* If this function returns non-void and control can drop through, + complain. */ + warning ("control reaches end of non-void function"); + /* With just -W, complain only if function returns both with + and without a value. */ + else if (extra_warnings + && current_function_returns_value && current_function_returns_null) + warning ("this function may return with or without a value"); + + /* If requested, warn about function definitions where the function will + return a value (usually of some struct or union type) which itself will + take up a lot of stack space. */ + + if (warn_larger_than && !DECL_EXTERNAL (fndecl) && TREE_TYPE (fndecl)) + { + register tree ret_type = TREE_TYPE (TREE_TYPE (fndecl)); + + if (ret_type) + { + register tree ret_type_size = TYPE_SIZE (ret_type); + + if (TREE_CODE (ret_type_size) == INTEGER_CST) + { + unsigned units + = TREE_INT_CST_LOW (ret_type_size) / BITS_PER_UNIT; + + if (units > larger_than_size) + warning_with_decl (fndecl, + "size of return value of `%s' is %u bytes", + units); + } + } + } + + /* Free all the tree nodes making up this function. */ + /* Switch back to allocating nodes permanently + until we start another function. */ + if (! nested) + permanent_allocation (1); + + if (DECL_SAVED_INSNS (fndecl) == 0 && ! nested) + { + /* Stop pointing to the local nodes about to be freed. */ + /* But DECL_INITIAL must remain nonzero so we know this + was an actual function definition. */ + /* For a nested function, this is done in pop_c_function_context. */ + /* If rest_of_compilation set this to 0, leave it 0. */ + if (DECL_INITIAL (fndecl) != 0) + DECL_INITIAL (fndecl) = error_mark_node; + DECL_ARGUMENTS (fndecl) = 0; + } + + if (DECL_STATIC_CONSTRUCTOR (fndecl)) + { +#ifndef ASM_OUTPUT_CONSTRUCTOR + if (! flag_gnu_linker) + static_ctors = perm_tree_cons (NULL_TREE, fndecl, static_ctors); + else +#endif + assemble_constructor (IDENTIFIER_POINTER (DECL_NAME (fndecl))); + } + if (DECL_STATIC_DESTRUCTOR (fndecl)) + { +#ifndef ASM_OUTPUT_DESTRUCTOR + if (! flag_gnu_linker) + static_dtors = perm_tree_cons (NULL_TREE, fndecl, static_dtors); + else +#endif + assemble_destructor (IDENTIFIER_POINTER (DECL_NAME (fndecl))); + } + + if (! nested) + { + /* Let the error reporting routines know that we're outside a + function. For a nested function, this value is used in + pop_c_function_context and then reset via pop_function_context. */ + current_function_decl = NULL; + } +} + +/* Save and restore the variables in this file and elsewhere + that keep track of the progress of compilation of the current function. + Used for nested functions. */ + +struct c_function +{ + struct c_function *next; + tree named_labels; + tree shadowed_labels; + int returns_value; + int returns_null; + int warn_about_return_type; + int extern_inline; + struct binding_level *binding_level; +}; + +struct c_function *c_function_chain; + +/* Save and reinitialize the variables + used during compilation of a C function. */ + +void +push_c_function_context () +{ + struct c_function *p + = (struct c_function *) xmalloc (sizeof (struct c_function)); + + if (pedantic) + pedwarn ("ANSI C forbids nested functions"); + + push_function_context (); + + p->next = c_function_chain; + c_function_chain = p; + + p->named_labels = named_labels; + p->shadowed_labels = shadowed_labels; + p->returns_value = current_function_returns_value; + p->returns_null = current_function_returns_null; + p->warn_about_return_type = warn_about_return_type; + p->extern_inline = current_extern_inline; + p->binding_level = current_binding_level; +} + +/* Restore the variables used during compilation of a C function. */ + +void +pop_c_function_context () +{ + struct c_function *p = c_function_chain; + tree link; + + /* Bring back all the labels that were shadowed. */ + for (link = shadowed_labels; link; link = TREE_CHAIN (link)) + if (DECL_NAME (TREE_VALUE (link)) != 0) + IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link))) + = TREE_VALUE (link); + + if (DECL_SAVED_INSNS (current_function_decl) == 0) + { + /* Stop pointing to the local nodes about to be freed. */ + /* But DECL_INITIAL must remain nonzero so we know this + was an actual function definition. */ + DECL_INITIAL (current_function_decl) = error_mark_node; + DECL_ARGUMENTS (current_function_decl) = 0; + } + + pop_function_context (); + + c_function_chain = p->next; + + named_labels = p->named_labels; + shadowed_labels = p->shadowed_labels; + current_function_returns_value = p->returns_value; + current_function_returns_null = p->returns_null; + warn_about_return_type = p->warn_about_return_type; + current_extern_inline = p->extern_inline; + current_binding_level = p->binding_level; + + free (p); +} + +/* integrate_decl_tree calls this function, but since we don't use the + DECL_LANG_SPECIFIC field, this is a no-op. */ + +#ifndef __GNUFORTRAN__ +void +copy_lang_decl (node) + tree node ATTRIBUTE_UNUSED; +{ +} +#endif + +#if defined(NEXT_SEMANTICS) && !defined(MACOSX) +#ifdef OBJCPLUS +#define builtin_function(NAME, TYPE, CODE, LIBNAME) \ + define_function (NAME, TYPE, CODE, (void (*)())pushdecl, LIBNAME) +#endif + +int +call_destructor_dynamically (dfndecl) + tree dfndecl; +{ + tree parms; + tree call; + tree atexit_decl; + tree atexit_type; + + extern tree default_function_type; + extern tree void_type_node; + + atexit_type + = build_function_type (void_type_node, + tree_cons (NULL_TREE, default_function_type, + NULL_TREE)); + atexit_decl =(tree) builtin_function ("atexit", + atexit_type, + NOT_BUILT_IN, 0); + parms = (tree) build_tree_list (NULL_TREE, + build1 (ADDR_EXPR, + default_function_type, dfndecl)); + + call = build_function_call (atexit_decl, parms); + expand_call (call, 0, 0); +} +#endif /* NEXT_SEMANTICS && !MACOSX */ diff -uNr gcc-2.95.2.ORIG/gcc/f-typeck.c gcc-2.95.2/gcc/f-typeck.c --- gcc-2.95.2.ORIG/gcc/f-typeck.c Thu Jan 1 09:00:00 1970 +++ gcc-2.95.2/gcc/f-typeck.c Tue Dec 26 15:06:40 2000 @@ -0,0 +1,7129 @@ +/* Build expressions with type checking for C compiler. + Copyright (C) 1987, 88, 91-97, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* This file is part of the C front end. + It contains routines to build C expressions given their operands, + including computing the types of the result, C-specific error checks, + and some optimization. + + There are also routines to build RETURN_STMT nodes and CASE_STMT nodes, + and to process initializations in declarations (since they work + like a strange sort of assignment). */ + +#ifndef __GNUFORTRAN__ +#define __GNUFORTRAN__ +#endif + +#include "config.h" +#include "system.h" +#include "tree.h" +#include "c-tree.h" +#include "flags.h" +#include "output.h" +#include "rtl.h" +#include "expr.h" +#include "toplev.h" +#include "intl.h" + +/* Nonzero if we've already printed a "missing braces around initializer" + message within this initializer. */ +static int missing_braces_mentioned; + +static tree qualify_type PROTO((tree, tree)); +static int comp_target_types PROTO((tree, tree)); +static int function_types_compatible_p PROTO((tree, tree)); +static int type_lists_compatible_p PROTO((tree, tree)); +static int self_promoting_type_p PROTO((tree)); +static tree decl_constant_value PROTO((tree)); +static tree lookup_field PROTO((tree, tree, tree *)); +static tree convert_arguments PROTO((tree, tree, tree, tree)); +static tree pointer_int_sum PROTO((enum tree_code, tree, tree)); +static tree pointer_diff PROTO((tree, tree)); +static tree unary_complex_lvalue PROTO((enum tree_code, tree)); +static void pedantic_lvalue_warning PROTO((enum tree_code)); +static tree internal_build_compound_expr PROTO((tree, int)); +static tree convert_for_assignment PROTO((tree, tree, const char *, tree, + tree, int)); +static void warn_for_assignment PROTO((const char *, const char *, + tree, int)); +static tree valid_compound_expr_initializer PROTO((tree, tree)); +static void push_string PROTO((const char *)); +static void push_member_name PROTO((tree)); +static void push_array_bounds PROTO((int)); +static int spelling_length PROTO((void)); +static char *print_spelling PROTO((char *)); +static void warning_init PROTO((const char *)); +static tree digest_init PROTO((tree, tree, int, int)); +static void check_init_type_bitfields PROTO((tree)); +static void output_init_element PROTO((tree, tree, tree, int)); +static void output_pending_init_elements PROTO((int)); +static void add_pending_init PROTO((tree, tree)); +static int pending_init_member PROTO((tree)); + +/* Do `exp = require_complete_type (exp);' to make sure exp + does not have an incomplete type. (That includes void types.) */ + +tree +require_complete_type (value) + tree value; +{ + tree type = TREE_TYPE (value); + + if (TREE_CODE (value) == ERROR_MARK) + return error_mark_node; + + /* First, detect a valid value with a complete type. */ + if (TYPE_SIZE (type) != 0 + && type != void_type_node) + return value; + + incomplete_type_error (value, type); + return error_mark_node; +} + +/* Print an error message for invalid use of an incomplete type. + VALUE is the expression that was used (or 0 if that isn't known) + and TYPE is the type that was invalid. */ +#ifndef __GNUFORTRAN__ +void +incomplete_type_error (value, type) + tree value; + tree type; +{ + const char *type_code_string; + + /* Avoid duplicate error message. */ + if (TREE_CODE (type) == ERROR_MARK) + return; + + if (value != 0 && (TREE_CODE (value) == VAR_DECL + || TREE_CODE (value) == PARM_DECL)) + error ("`%s' has an incomplete type", + IDENTIFIER_POINTER (DECL_NAME (value))); + else + { + retry: + /* We must print an error message. Be clever about what it says. */ + + switch (TREE_CODE (type)) + { + case RECORD_TYPE: + type_code_string = "struct"; + break; + + case UNION_TYPE: + type_code_string = "union"; + break; + + case ENUMERAL_TYPE: + type_code_string = "enum"; + break; + + case VOID_TYPE: + error ("invalid use of void expression"); + return; + + case ARRAY_TYPE: + if (TYPE_DOMAIN (type)) + { + type = TREE_TYPE (type); + goto retry; + } + error ("invalid use of array with unspecified bounds"); + return; + + default: + abort (); + } + + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + error ("invalid use of undefined type `%s %s'", + type_code_string, IDENTIFIER_POINTER (TYPE_NAME (type))); + else + /* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */ + error ("invalid use of incomplete typedef `%s'", + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); + } +} + +#endif + +/* Return a variant of TYPE which has all the type qualifiers of LIKE + as well as those of TYPE. */ + +static tree +qualify_type (type, like) + tree type, like; +{ + return c_build_qualified_type (type, + TYPE_QUALS (type) | TYPE_QUALS (like)); +} + +/* Return the common type of two types. + We assume that comptypes has already been done and returned 1; + if that isn't so, this may crash. In particular, we assume that qualifiers + match. + + This is the type for the result of most arithmetic operations + if the operands have the given two types. */ + +tree +common_type (t1, t2) + tree t1, t2; +{ + register enum tree_code code1; + register enum tree_code code2; + tree attributes; + + /* Save time if the two types are the same. */ + + if (t1 == t2) return t1; + + /* If one type is nonsense, use the other. */ + if (t1 == error_mark_node) + return t2; + if (t2 == error_mark_node) + return t1; + + /* Merge the attributes. */ + attributes = merge_machine_type_attributes (t1, t2); + + /* Treat an enum type as the unsigned integer type of the same width. */ + + if (TREE_CODE (t1) == ENUMERAL_TYPE) + t1 = type_for_size (TYPE_PRECISION (t1), 1); + if (TREE_CODE (t2) == ENUMERAL_TYPE) + t2 = type_for_size (TYPE_PRECISION (t2), 1); + + code1 = TREE_CODE (t1); + code2 = TREE_CODE (t2); + + /* If one type is complex, form the common type of the non-complex + components, then make that complex. Use T1 or T2 if it is the + required type. */ + if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE) + { + tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1; + tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2; + tree subtype = common_type (subtype1, subtype2); + + if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype) + return build_type_attribute_variant (t1, attributes); + else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype) + return build_type_attribute_variant (t2, attributes); + else + return build_type_attribute_variant (build_complex_type (subtype), + attributes); + } + + switch (code1) + { + case INTEGER_TYPE: + case REAL_TYPE: + /* If only one is real, use it as the result. */ + + if (code1 == REAL_TYPE && code2 != REAL_TYPE) + return build_type_attribute_variant (t1, attributes); + + if (code2 == REAL_TYPE && code1 != REAL_TYPE) + return build_type_attribute_variant (t2, attributes); + + /* Both real or both integers; use the one with greater precision. */ + + if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2)) + return build_type_attribute_variant (t1, attributes); + else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1)) + return build_type_attribute_variant (t2, attributes); + + /* Same precision. Prefer longs to ints even when same size. */ + + if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node + || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node) + return build_type_attribute_variant (long_unsigned_type_node, + attributes); + + if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node + || TYPE_MAIN_VARIANT (t2) == long_integer_type_node) + { + /* But preserve unsignedness from the other type, + since long cannot hold all the values of an unsigned int. */ + if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2)) + t1 = long_unsigned_type_node; + else + t1 = long_integer_type_node; + return build_type_attribute_variant (t1, attributes); + } + + /* Likewise, prefer long double to double even if same size. */ + if (TYPE_MAIN_VARIANT (t1) == long_double_type_node + || TYPE_MAIN_VARIANT (t2) == long_double_type_node) + return build_type_attribute_variant (long_double_type_node, + attributes); + + /* Otherwise prefer the unsigned one. */ + + if (TREE_UNSIGNED (t1)) + return build_type_attribute_variant (t1, attributes); + else + return build_type_attribute_variant (t2, attributes); + + case POINTER_TYPE: + /* For two pointers, do this recursively on the target type, + and combine the qualifiers of the two types' targets. */ + /* This code was turned off; I don't know why. + But ANSI C specifies doing this with the qualifiers. + So I turned it on again. */ + { + tree pointed_to_1 = TREE_TYPE (t1); + tree pointed_to_2 = TREE_TYPE (t2); + tree target = common_type (TYPE_MAIN_VARIANT (pointed_to_1), + TYPE_MAIN_VARIANT (pointed_to_2)); + t1 = build_pointer_type (c_build_qualified_type + (target, + TYPE_QUALS (pointed_to_1) | + TYPE_QUALS (pointed_to_2))); + return build_type_attribute_variant (t1, attributes); + } +#if 0 + t1 = build_pointer_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2))); + return build_type_attribute_variant (t1, attributes); +#endif + + case ARRAY_TYPE: + { + tree elt = common_type (TREE_TYPE (t1), TREE_TYPE (t2)); + /* Save space: see if the result is identical to one of the args. */ + if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1)) + return build_type_attribute_variant (t1, attributes); + if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2)) + return build_type_attribute_variant (t2, attributes); + /* Merge the element types, and have a size if either arg has one. */ + t1 = build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2)); + return build_type_attribute_variant (t1, attributes); + } + + case FUNCTION_TYPE: + /* Function types: prefer the one that specified arg types. + If both do, merge the arg types. Also merge the return types. */ + { + tree valtype = common_type (TREE_TYPE (t1), TREE_TYPE (t2)); + tree p1 = TYPE_ARG_TYPES (t1); + tree p2 = TYPE_ARG_TYPES (t2); + int len; + tree newargs, n; + int i; + + /* Save space: see if the result is identical to one of the args. */ + if (valtype == TREE_TYPE (t1) && ! TYPE_ARG_TYPES (t2)) + return build_type_attribute_variant (t1, attributes); + if (valtype == TREE_TYPE (t2) && ! TYPE_ARG_TYPES (t1)) + return build_type_attribute_variant (t2, attributes); + + /* Simple way if one arg fails to specify argument types. */ + if (TYPE_ARG_TYPES (t1) == 0) + { + t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2)); + return build_type_attribute_variant (t1, attributes); + } + if (TYPE_ARG_TYPES (t2) == 0) + { + t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1)); + return build_type_attribute_variant (t1, attributes); + } + + /* If both args specify argument types, we must merge the two + lists, argument by argument. */ + + len = list_length (p1); + newargs = 0; + + for (i = 0; i < len; i++) + newargs = tree_cons (NULL_TREE, NULL_TREE, newargs); + + n = newargs; + + for (; p1; + p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n)) + { + /* A null type means arg type is not specified. + Take whatever the other function type has. */ + if (TREE_VALUE (p1) == 0) + { + TREE_VALUE (n) = TREE_VALUE (p2); + goto parm_done; + } + if (TREE_VALUE (p2) == 0) + { + TREE_VALUE (n) = TREE_VALUE (p1); + goto parm_done; + } + + /* Given wait (union {union wait *u; int *i} *) + and wait (union wait *), + prefer union wait * as type of parm. */ + if (TREE_CODE (TREE_VALUE (p1)) == UNION_TYPE + && TREE_VALUE (p1) != TREE_VALUE (p2)) + { + tree memb; + for (memb = TYPE_FIELDS (TREE_VALUE (p1)); + memb; memb = TREE_CHAIN (memb)) + if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2))) + { + TREE_VALUE (n) = TREE_VALUE (p2); + if (pedantic) + pedwarn ("function types not truly compatible in ANSI C"); + goto parm_done; + } + } + if (TREE_CODE (TREE_VALUE (p2)) == UNION_TYPE + && TREE_VALUE (p2) != TREE_VALUE (p1)) + { + tree memb; + for (memb = TYPE_FIELDS (TREE_VALUE (p2)); + memb; memb = TREE_CHAIN (memb)) + if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1))) + { + TREE_VALUE (n) = TREE_VALUE (p1); + if (pedantic) + pedwarn ("function types not truly compatible in ANSI C"); + goto parm_done; + } + } + TREE_VALUE (n) = common_type (TREE_VALUE (p1), TREE_VALUE (p2)); + parm_done: ; + } + + t1 = build_function_type (valtype, newargs); + /* ... falls through ... */ + } + + default: + return build_type_attribute_variant (t1, attributes); + } + +} + +/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment + or various other operations. Return 2 if they are compatible + but a warning may be needed if you use them together. */ + +int +comptypes (type1, type2) + tree type1, type2; +{ + register tree t1 = type1; + register tree t2 = type2; + int attrval, val; + + /* Suppress errors caused by previously reported errors. */ + + if (t1 == t2 || !t1 || !t2 + || TREE_CODE (t1) == ERROR_MARK || TREE_CODE (t2) == ERROR_MARK) + return 1; + + /* Treat an enum type as the integer type of the same width and + signedness. */ + + if (TREE_CODE (t1) == ENUMERAL_TYPE) + t1 = type_for_size (TYPE_PRECISION (t1), TREE_UNSIGNED (t1)); + if (TREE_CODE (t2) == ENUMERAL_TYPE) + t2 = type_for_size (TYPE_PRECISION (t2), TREE_UNSIGNED (t2)); + + if (t1 == t2) + return 1; + + /* Different classes of types can't be compatible. */ + + if (TREE_CODE (t1) != TREE_CODE (t2)) return 0; + + /* Qualifiers must match. */ + + if (TYPE_QUALS (t1) != TYPE_QUALS (t2)) + return 0; + + /* Allow for two different type nodes which have essentially the same + definition. Note that we already checked for equality of the type + qualifiers (just above). */ + + if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) + return 1; + +#ifndef COMP_TYPE_ATTRIBUTES +#define COMP_TYPE_ATTRIBUTES(t1,t2) 1 +#endif + + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + if (! (attrval = COMP_TYPE_ATTRIBUTES (t1, t2))) + return 0; + + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + val = 0; + + switch (TREE_CODE (t1)) + { + case POINTER_TYPE: + val = (TREE_TYPE (t1) == TREE_TYPE (t2) + ? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2))); + break; + + case FUNCTION_TYPE: + val = function_types_compatible_p (t1, t2); + break; + + case ARRAY_TYPE: + { + tree d1 = TYPE_DOMAIN (t1); + tree d2 = TYPE_DOMAIN (t2); + val = 1; + + /* Target types must match incl. qualifiers. */ + if (TREE_TYPE (t1) != TREE_TYPE (t2) + && 0 == (val = comptypes (TREE_TYPE (t1), TREE_TYPE (t2)))) + return 0; + + /* Sizes must match unless one is missing or variable. */ + if (d1 == 0 || d2 == 0 || d1 == d2 + || TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST + || TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST) + break; + + if (! ((TREE_INT_CST_LOW (TYPE_MIN_VALUE (d1)) + == TREE_INT_CST_LOW (TYPE_MIN_VALUE (d2))) + && (TREE_INT_CST_HIGH (TYPE_MIN_VALUE (d1)) + == TREE_INT_CST_HIGH (TYPE_MIN_VALUE (d2))) + && (TREE_INT_CST_LOW (TYPE_MAX_VALUE (d1)) + == TREE_INT_CST_LOW (TYPE_MAX_VALUE (d2))) + && (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d1)) + == TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d2))))) + val = 0; + break; + } + + case RECORD_TYPE: + if (maybe_objc_comptypes (t1, t2, 0) == 1) + val = 1; + break; + + default: + break; + } + return attrval == 2 && val == 1 ? 2 : val; +} + +/* Return 1 if TTL and TTR are pointers to types that are equivalent, + ignoring their qualifiers. */ + +static int +comp_target_types (ttl, ttr) + tree ttl, ttr; +{ + int val; + + /* Give maybe_objc_comptypes a crack at letting these types through. */ + if ((val = maybe_objc_comptypes (ttl, ttr, 1)) >= 0) + return val; + +#ifdef NEXT_SEMANTICS + if (! pedantic) + { + /* Ignore pointer qualifiers recursively. + This way char ** and const char ** are compatible. */ + ttl = TYPE_MAIN_VARIANT (TREE_TYPE (ttl)); + ttr = TYPE_MAIN_VARIANT (TREE_TYPE (ttr)); + + if (TREE_CODE (ttl) == POINTER_TYPE + && TREE_CODE (ttr) == POINTER_TYPE) + return comp_target_types (ttl, ttr); + else + return comptypes (ttl, ttr); + } +#endif + + val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)), + TYPE_MAIN_VARIANT (TREE_TYPE (ttr))); + + if (val == 2 && pedantic) + pedwarn ("types are not quite compatible"); + return val; +} + +/* Subroutines of `comptypes'. */ + +/* Return 1 if two function types F1 and F2 are compatible. + If either type specifies no argument types, + the other must specify a fixed number of self-promoting arg types. + Otherwise, if one type specifies only the number of arguments, + the other must specify that number of self-promoting arg types. + Otherwise, the argument types must match. */ + +static int +function_types_compatible_p (f1, f2) + tree f1, f2; +{ + tree args1, args2; + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + int val = 1; + int val1; + + if (!(TREE_TYPE (f1) == TREE_TYPE (f2) + || (val = comptypes (TREE_TYPE (f1), TREE_TYPE (f2))))) + return 0; + + args1 = TYPE_ARG_TYPES (f1); + args2 = TYPE_ARG_TYPES (f2); + + /* An unspecified parmlist matches any specified parmlist + whose argument types don't need default promotions. */ + + if (args1 == 0) + { + if (!self_promoting_args_p (args2)) + return 0; + /* If one of these types comes from a non-prototype fn definition, + compare that with the other type's arglist. + If they don't match, ask for a warning (but no error). */ + if (TYPE_ACTUAL_ARG_TYPES (f1) + && 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1))) + val = 2; + return val; + } + if (args2 == 0) + { + if (!self_promoting_args_p (args1)) + return 0; + if (TYPE_ACTUAL_ARG_TYPES (f2) + && 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2))) + val = 2; + return val; + } + + /* Both types have argument lists: compare them and propagate results. */ + val1 = type_lists_compatible_p (args1, args2); + return val1 != 1 ? val1 : val; +} + +/* Check two lists of types for compatibility, + returning 0 for incompatible, 1 for compatible, + or 2 for compatible with warning. */ + +static int +type_lists_compatible_p (args1, args2) + tree args1, args2; +{ + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + int val = 1; + int newval = 0; + + while (1) + { + if (args1 == 0 && args2 == 0) + return val; + /* If one list is shorter than the other, + they fail to match. */ + if (args1 == 0 || args2 == 0) + return 0; + /* A null pointer instead of a type + means there is supposed to be an argument + but nothing is specified about what type it has. + So match anything that self-promotes. */ + if (TREE_VALUE (args1) == 0) + { + if (! self_promoting_type_p (TREE_VALUE (args2))) + return 0; + } + else if (TREE_VALUE (args2) == 0) + { + if (! self_promoting_type_p (TREE_VALUE (args1))) + return 0; + } + else if (! (newval = comptypes (TREE_VALUE (args1), TREE_VALUE (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_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)))) + { + tree memb; + for (memb = TYPE_FIELDS (TREE_VALUE (args1)); + memb; memb = TREE_CHAIN (memb)) + if (comptypes (TREE_TYPE (memb), TREE_VALUE (args2))) + break; + if (memb == 0) + return 0; + } + else if (TREE_CODE (TREE_VALUE (args2)) == UNION_TYPE + && (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)))) + { + tree memb; + for (memb = TYPE_FIELDS (TREE_VALUE (args2)); + memb; memb = TREE_CHAIN (memb)) + if (comptypes (TREE_TYPE (memb), TREE_VALUE (args1))) + break; + if (memb == 0) + return 0; + } + else + return 0; + } + + /* comptypes said ok, but record if it said to warn. */ + if (newval > val) + val = newval; + + args1 = TREE_CHAIN (args1); + args2 = TREE_CHAIN (args2); + } +} + +/* Return 1 if PARMS specifies a fixed number of parameters + and none of their types is affected by default promotions. */ + +int +self_promoting_args_p (parms) + tree parms; +{ + register tree t; + for (t = parms; t; t = TREE_CHAIN (t)) + { + register tree type = TREE_VALUE (t); + + if (TREE_CHAIN (t) == 0 && type != void_type_node) + return 0; + + if (type == 0) + return 0; + + if (TYPE_MAIN_VARIANT (type) == float_type_node) + return 0; + + if (C_PROMOTING_INTEGER_TYPE_P (type)) + return 0; + } + return 1; +} + +/* Return 1 if TYPE is not affected by default promotions. */ + +static int +self_promoting_type_p (type) + tree type; +{ + if (TYPE_MAIN_VARIANT (type) == float_type_node) + return 0; + + if (C_PROMOTING_INTEGER_TYPE_P (type)) + return 0; + + return 1; +} + +/* Return an unsigned type the same as TYPE in other respects. */ + +#ifndef __GNUFORTRAN__ +tree +unsigned_type (type) + tree type; +{ + tree type1 = TYPE_MAIN_VARIANT (type); + if (type1 == signed_char_type_node || type1 == char_type_node) + return unsigned_char_type_node; + if (type1 == integer_type_node) + return unsigned_type_node; + if (type1 == short_integer_type_node) + return short_unsigned_type_node; + if (type1 == long_integer_type_node) + return long_unsigned_type_node; + if (type1 == long_long_integer_type_node) + return long_long_unsigned_type_node; + if (type1 == intDI_type_node) + return unsigned_intDI_type_node; + if (type1 == intSI_type_node) + return unsigned_intSI_type_node; + if (type1 == intHI_type_node) + return unsigned_intHI_type_node; + if (type1 == intQI_type_node) + return unsigned_intQI_type_node; + + return signed_or_unsigned_type (1, type); +} + +/* Return a signed type the same as TYPE in other respects. */ + +tree +signed_type (type) + tree type; +{ + tree type1 = TYPE_MAIN_VARIANT (type); + if (type1 == unsigned_char_type_node || type1 == char_type_node) + return signed_char_type_node; + if (type1 == unsigned_type_node) + return integer_type_node; + if (type1 == short_unsigned_type_node) + return short_integer_type_node; + if (type1 == long_unsigned_type_node) + return long_integer_type_node; + if (type1 == long_long_unsigned_type_node) + return long_long_integer_type_node; + if (type1 == unsigned_intDI_type_node) + return intDI_type_node; + if (type1 == unsigned_intSI_type_node) + return intSI_type_node; + if (type1 == unsigned_intHI_type_node) + return intHI_type_node; + if (type1 == unsigned_intQI_type_node) + return intQI_type_node; + + return signed_or_unsigned_type (0, type); +} +#endif + +/* Return a type the same as TYPE except unsigned or + signed according to UNSIGNEDP. */ +#ifndef __GNUFORTRAN__ +tree +signed_or_unsigned_type (unsignedp, type) + int unsignedp; + tree type; +{ + if ((! INTEGRAL_TYPE_P (type) && ! POINTER_TYPE_P (type)) + || TREE_UNSIGNED (type) == unsignedp) + return type; + if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node)) + return (unsignedp ? long_long_unsigned_type_node + : long_long_integer_type_node); + return type; +} +#endif + +/* Digest a vector constant. */ + +tree +build_vector_constant (type, values) + tree type; + tree values; +{ + tree vtype; + tree valarray[16], valtail; + int valnum, elements; + + /* Get the vector element type and number of elements. */ + vtype = TREE_TYPE (type); + elements = (TREE_INT_CST_LOW (TYPE_SIZE (type)) + / TREE_INT_CST_LOW (TYPE_SIZE (vtype))); + + /* Walk the values list placing the converted constants into + valarray and counting the number of constants. */ + for (valtail = values, valnum = 0; + valtail; + valtail = TREE_CHAIN (valtail), valnum++) + { + register tree val = TREE_VALUE (valtail); + STRIP_NOPS (val); + if (TREE_CODE (val) != INTEGER_CST && TREE_CODE (val) != REAL_CST) + { + error("expected a constant expression"); + return error_mark_node; + } + valarray[valnum] = convert_for_assignment (vtype, val, "assignment", + NULL_TREE, NULL_TREE, 0); + } + + /* Check for the correct number of elements. */ + if (valnum != 1 && valnum != elements) + { + error (valnum < elements + ? "too few initializers" : "too many initializers"); + return error_mark_node; + } + + /* A single constant value is shorthand for a duplicated value. + Duplicate it now. */ + while (valnum < elements) + valarray[valnum++] = valarray[0]; + + /* Combine the constant [integer] values until there are exactly four. */ + while (elements > 4) + { + int i, j; + for (i = 2, j = 0; i <= elements; i += 2, j++) + { + unsigned HOST_WIDE_INT a = TREE_INT_CST_LOW (valarray[i-2]); + unsigned HOST_WIDE_INT b = TREE_INT_CST_LOW (valarray[i-1]); + int bits = 128 / elements; + valarray[j] = build_int_2 ((a << bits) | (b & ((1 << bits) - 1)), + 0); + } + elements /= 2; + } + return build_vector (type, valarray[0], valarray[1], + valarray[2], valarray[3]); +} + +/* Compute the value of the `sizeof' operator. */ + +tree +c_sizeof (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + tree t; + + if (code == FUNCTION_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("sizeof applied to a function type"); + return size_int (1); + } + if (code == VOID_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("sizeof applied to a void type"); + return size_int (1); + } + if (code == ERROR_MARK) + return size_int (1); + if (TYPE_SIZE (type) == 0) + { + error ("sizeof applied to an incomplete type"); + return size_int (0); + } + + /* Convert in case a char is more than one unit. */ + t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), + size_int (TYPE_PRECISION (char_type_node))); + t = convert (sizetype, t); + /* size_binop does not put the constant in range, so do it now. */ + if (TREE_CODE (t) == INTEGER_CST && force_fit_type (t, 0)) + TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) = 1; + return t; +} + +tree +c_sizeof_nowarn (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + tree t; + + if (code == FUNCTION_TYPE + || code == VOID_TYPE + || code == ERROR_MARK) + return size_int (1); + if (TYPE_SIZE (type) == 0) + return size_int (0); + + /* Convert in case a char is more than one unit. */ + t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), + size_int (TYPE_PRECISION (char_type_node))); + t = convert (sizetype, t); + force_fit_type (t, 0); + return t; +} + +/* Compute the size to increment a pointer by. */ + +tree +c_size_in_bytes (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + tree t; + + if (code == FUNCTION_TYPE) + return size_int (1); + if (code == VOID_TYPE) + return size_int (1); + if (code == ERROR_MARK) + return size_int (1); + if (TYPE_SIZE (type) == 0) + { + error ("arithmetic on pointer to an incomplete type"); + return size_int (1); + } + + /* Convert in case a char is more than one unit. */ + t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), + size_int (BITS_PER_UNIT)); + t = convert (sizetype, t); + force_fit_type (t, 0); + return t; +} + +/* Implement the __alignof keyword: Return the minimum required + alignment of TYPE, measured in bytes. */ + +tree +c_alignof (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + + if (code == FUNCTION_TYPE) + return size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT); + + if (code == VOID_TYPE || code == ERROR_MARK) + return size_int (1); + + if (TYPE_SIZE (type) == 0) + { + warning ("__alignof applied to an incomplete type"); + return size_int (1); + } + + return size_int (TYPE_ALIGN (type) / BITS_PER_UNIT); +} + +/* Implement the __alignof keyword: Return the minimum required + alignment of EXPR, measured in bytes. For VAR_DECL's and + FIELD_DECL's return DECL_ALIGN (which can be set from an + "aligned" __attribute__ specification). */ + +tree +c_alignof_expr (expr) + tree expr; +{ + if (TREE_CODE (expr) == VAR_DECL) + return size_int (DECL_ALIGN (expr) / BITS_PER_UNIT); + + if (TREE_CODE (expr) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1))) + { + error ("`__alignof' applied to a bit-field"); + return size_int (1); + } + else if (TREE_CODE (expr) == COMPONENT_REF + && TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL) + return size_int (DECL_ALIGN (TREE_OPERAND (expr, 1)) / BITS_PER_UNIT); + + if (TREE_CODE (expr) == INDIRECT_REF) + { + tree t = TREE_OPERAND (expr, 0); + tree best = t; + int bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); + + while (TREE_CODE (t) == NOP_EXPR + && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE) + { + int thisalign; + + t = TREE_OPERAND (t, 0); + thisalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); + if (thisalign > bestalign) + best = t, bestalign = thisalign; + } + return c_alignof (TREE_TYPE (TREE_TYPE (best))); + } + else + return c_alignof (TREE_TYPE (expr)); +} + +/* Implement the vec_step keyword: Return the number of components in the + given vector type. */ + +tree +c_vec_step (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + + if (code != VECTOR_TYPE) + { + error ("operand of `vec_step' must be a vector type"); + return size_int (0); + } + + return size_binop (CEIL_DIV_EXPR, size_int (16), + c_sizeof (TREE_TYPE (type))); +} + +/* Implement the vec_step keyword: Return the number of components in + the given vector type. */ + +tree +c_vec_step_expr (expr) + tree expr; +{ + return c_vec_step (TREE_TYPE (expr)); +} + +/* Return either DECL or its known constant value (if it has one). */ + +static tree +decl_constant_value (decl) + tree decl; +{ + if (/* Don't change a variable array bound or initial value to a constant + in a place where a variable is invalid. */ + current_function_decl != 0 + && ! pedantic + && ! TREE_THIS_VOLATILE (decl) + && TREE_READONLY (decl) && ! ITERATOR_P (decl) + && DECL_INITIAL (decl) != 0 + && TREE_CODE (DECL_INITIAL (decl)) != ERROR_MARK + /* This is invalid if initial value is not constant. + If it has either a function call, a memory reference, + or a variable, then re-evaluating it could give different results. */ + && TREE_CONSTANT (DECL_INITIAL (decl)) + /* Check for cases where this is sub-optimal, even though valid. */ + && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR + && DECL_MODE (decl) != BLKmode) + return DECL_INITIAL (decl); + return decl; +} + +/* Perform default promotions for C data used in expressions. + Arrays and functions are converted to pointers; + enumeral types or short or char, to int. + In addition, manifest constants symbols are replaced by their values. */ + +tree +default_conversion (exp) + tree exp; +{ + register tree type = TREE_TYPE (exp); + register enum tree_code code = TREE_CODE (type); + + /* 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 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); + } + + /* Strip NON_LVALUE_EXPRs and no-op conversions, since we aren't using as + an lvalue. */ + /* Do not use STRIP_NOPS here! It will remove conversions from pointer + to integer and cause infinite recursion. */ + while (TREE_CODE (exp) == NON_LVALUE_EXPR + || (TREE_CODE (exp) == NOP_EXPR + && TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp))) + exp = TREE_OPERAND (exp, 0); + + /* Normally convert enums to int, + but convert wide enums to something wider. */ + if (code == ENUMERAL_TYPE) + { + type = type_for_size (MAX (TYPE_PRECISION (type), + TYPE_PRECISION (integer_type_node)), + ((flag_traditional + || (TYPE_PRECISION (type) + >= TYPE_PRECISION (integer_type_node))) + && TREE_UNSIGNED (type))); + return convert (type, exp); + } + + if (TREE_CODE (exp) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1))) + { + tree width = DECL_SIZE (TREE_OPERAND (exp, 1)); + HOST_WIDE_INT low = TREE_INT_CST_LOW (width); + + /* If it's thinner than an int, promote it like a + C_PROMOTING_INTEGER_TYPE_P, otherwise leave it alone. */ + + if (low < TYPE_PRECISION (integer_type_node)) + { + if (flag_traditional && TREE_UNSIGNED (type)) + return convert (unsigned_type_node, exp); + else + return convert (integer_type_node, exp); + } + } + + if (C_PROMOTING_INTEGER_TYPE_P (type)) + { + /* Traditionally, unsignedness is preserved in default promotions. + Also preserve unsignedness if not really getting any wider. */ + if (TREE_UNSIGNED (type) + && (flag_traditional + || TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))) + return convert (unsigned_type_node, exp); + return convert (integer_type_node, exp); + } + if (flag_traditional && !flag_allow_single_precision + && TYPE_MAIN_VARIANT (type) == float_type_node) + return convert (double_type_node, exp); + if (code == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + if (code == FUNCTION_TYPE) + { + return build_unary_op (ADDR_EXPR, exp, 0); + } + if (code == ARRAY_TYPE) + { + register tree adr; + tree restype = TREE_TYPE (type); + tree ptrtype; + int constp = 0; + int volatilep = 0; + + if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r' + || TREE_CODE_CLASS (TREE_CODE (exp)) == 'd') + { + constp = TREE_READONLY (exp); + volatilep = TREE_THIS_VOLATILE (exp); + } + + if (TYPE_QUALS (type) || constp || volatilep) + restype + = c_build_qualified_type (restype, + TYPE_QUALS (type) + | (constp * TYPE_QUAL_CONST) + | (volatilep * TYPE_QUAL_VOLATILE)); + + if (TREE_CODE (exp) == INDIRECT_REF) + return convert (TYPE_POINTER_TO (restype), + TREE_OPERAND (exp, 0)); + + if (TREE_CODE (exp) == COMPOUND_EXPR) + { + tree op1 = default_conversion (TREE_OPERAND (exp, 1)); + return build (COMPOUND_EXPR, TREE_TYPE (op1), + TREE_OPERAND (exp, 0), op1); + } + + if (! lvalue_p (exp) + && ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp))) + { + error ("invalid use of non-lvalue array"); + return error_mark_node; + } + + ptrtype = build_pointer_type (restype); + + if (TREE_CODE (exp) == VAR_DECL) + { + /* ??? This is not really quite correct + in that the type of the operand of ADDR_EXPR + is not the target type of the type of the ADDR_EXPR itself. + Question is, can this lossage be avoided? */ + adr = build1 (ADDR_EXPR, ptrtype, exp); + if (mark_addressable (exp) == 0) + return error_mark_node; + TREE_CONSTANT (adr) = staticp (exp); + TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */ + return adr; + } + /* This way is better for a COMPONENT_REF since it can + simplify the offset for a component. */ + adr = build_unary_op (ADDR_EXPR, exp, 1); + return convert (ptrtype, adr); + } + return exp; +} + +/* Look up component name in the structure type definition. + + If this component name is found indirectly within an anonymous union, + store in *INDIRECT the component which directly contains + that anonymous union. Otherwise, set *INDIRECT to 0. */ + +static tree +lookup_field (type, component, indirect) + tree type, component; + tree *indirect; +{ + tree field; + + /* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers + to the field elements. Use a binary search on this array to quickly + find the element. Otherwise, do a linear search. TYPE_LANG_SPECIFIC + will always be set for structures which have many elements. */ + + if (TYPE_LANG_SPECIFIC (type)) + { + int bot, top, half; + tree *field_array = &TYPE_LANG_SPECIFIC (type)->elts[0]; + + field = TYPE_FIELDS (type); + bot = 0; + top = TYPE_LANG_SPECIFIC (type)->len; + while (top - bot > 1) + { + half = (top - bot + 1) >> 1; + field = field_array[bot+half]; + + if (DECL_NAME (field) == NULL_TREE) + { + /* Step through all anon unions in linear fashion. */ + while (DECL_NAME (field_array[bot]) == NULL_TREE) + { + tree anon = 0, junk; + + field = field_array[bot++]; + if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) + anon = lookup_field (TREE_TYPE (field), component, &junk); + + if (anon != NULL_TREE) + { + *indirect = field; + return anon; + } + } + + /* Entire record is only anon unions. */ + if (bot > top) + return NULL_TREE; + + /* Restart the binary search, with new lower bound. */ + continue; + } + + if (DECL_NAME (field) == component) + break; + if (DECL_NAME (field) < component) + bot += half; + else + top = bot + half; + } + + if (DECL_NAME (field_array[bot]) == component) + field = field_array[bot]; + else if (DECL_NAME (field) != component) + field = 0; + } + else + { + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (DECL_NAME (field) == NULL_TREE) + { + tree junk; + tree anon = 0; + + if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) + anon = lookup_field (TREE_TYPE (field), component, &junk); + + if (anon != NULL_TREE) + { + *indirect = field; + return anon; + } + } + + if (DECL_NAME (field) == component) + break; + } + } + + *indirect = NULL_TREE; + return field; +} + +/* Make an expression to refer to the COMPONENT field of + structure or union value DATUM. COMPONENT is an IDENTIFIER_NODE. */ + +tree +build_component_ref (datum, component) + tree datum, component; +{ + register tree type = TREE_TYPE (datum); + register enum tree_code code = TREE_CODE (type); + register tree field = NULL; + register tree ref; + + /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it + unless we are not to support things not strictly ANSI. */ + switch (TREE_CODE (datum)) + { + case COMPOUND_EXPR: + { + tree value = build_component_ref (TREE_OPERAND (datum, 1), component); + return build (COMPOUND_EXPR, TREE_TYPE (value), + TREE_OPERAND (datum, 0), value); + } + case COND_EXPR: + return build_conditional_expr + (TREE_OPERAND (datum, 0), + build_component_ref (TREE_OPERAND (datum, 1), component), + build_component_ref (TREE_OPERAND (datum, 2), component)); + + default: + break; + } + + /* See if there is a field or component with name COMPONENT. */ + + if (code == RECORD_TYPE || code == UNION_TYPE) + { + tree indirect = 0; + + if (TYPE_SIZE (type) == 0) + { + incomplete_type_error (NULL_TREE, type); + return error_mark_node; + } + + field = lookup_field (type, component, &indirect); + + if (!field) + { + error (code == RECORD_TYPE + ? "structure has no member named `%s'" + : "union has no member named `%s'", + IDENTIFIER_POINTER (component)); + return error_mark_node; + } + if (TREE_TYPE (field) == error_mark_node) + return error_mark_node; + + /* If FIELD was found buried within an anonymous union, + make one COMPONENT_REF to get that anonymous union, + then fall thru to make a second COMPONENT_REF to get FIELD. */ + if (indirect != 0) + { + ref = build (COMPONENT_REF, TREE_TYPE (indirect), datum, indirect); + if (TREE_READONLY (datum) || TREE_READONLY (indirect)) + TREE_READONLY (ref) = 1; + if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (indirect)) + TREE_THIS_VOLATILE (ref) = 1; + datum = ref; + } + + ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field); + + if (TREE_READONLY (datum) || TREE_READONLY (field)) + TREE_READONLY (ref) = 1; + if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field)) + TREE_THIS_VOLATILE (ref) = 1; + + return ref; + } + else if (code != ERROR_MARK) + error ("request for member `%s' in something not a structure or union", + IDENTIFIER_POINTER (component)); + + return error_mark_node; +} + +/* Given an expression PTR for a pointer, return an expression + for the value pointed to. + ERRORSTRING is the name of the operator to appear in error messages. */ + +tree +build_indirect_ref (ptr, errorstring) + tree ptr; + const char *errorstring; +{ + register tree pointer = default_conversion (ptr); + register tree type = TREE_TYPE (pointer); + + if (TREE_CODE (type) == POINTER_TYPE) + { + if (TREE_CODE (pointer) == ADDR_EXPR + && !flag_volatile + && (TREE_TYPE (TREE_OPERAND (pointer, 0)) + == TREE_TYPE (type))) + return TREE_OPERAND (pointer, 0); + else + { + tree t = TREE_TYPE (type); + register tree ref = build1 (INDIRECT_REF, + TYPE_MAIN_VARIANT (t), pointer); + + if (TYPE_SIZE (t) == 0 && TREE_CODE (t) != ARRAY_TYPE) + { +#ifdef NEXT_SEMANTICS + require_complete_type (type); +#endif + error ("dereferencing pointer to incomplete type"); + return error_mark_node; + } + if (TREE_CODE (t) == VOID_TYPE && skip_evaluation == 0) + warning ("dereferencing `void *' pointer"); + + /* We *must* set TREE_READONLY when dereferencing a pointer to const, + so that we get the proper error message if the result is used + to assign to. Also, &* is supposed to be a no-op. + And ANSI C seems to specify that the type of the result + should be the const type. */ + /* A de-reference of a pointer to const is not a const. It is valid + to change it via some other pointer. */ + TREE_READONLY (ref) = TYPE_READONLY (t); + TREE_SIDE_EFFECTS (ref) + = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer) || flag_volatile; + TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t); + return ref; + } + } + else if (TREE_CODE (pointer) != ERROR_MARK) + error ("invalid type argument of `%s'", errorstring); + return error_mark_node; +} + +/* This handles expressions of the form "a[i]", which denotes + an array reference. + + This is logically equivalent in C to *(a+i), but we may do it differently. + If A is a variable or a member, we generate a primitive ARRAY_REF. + This avoids forcing the array out of registers, and can work on + arrays that are not lvalues (for example, members of structures returned + by functions). */ + +tree +build_array_ref (array, index) + tree array, index; +{ + if (index == 0) + { + error ("subscript missing in array reference"); + return error_mark_node; + } + + if (TREE_TYPE (array) == error_mark_node + || TREE_TYPE (index) == error_mark_node) + return error_mark_node; + + if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE + && TREE_CODE (array) != INDIRECT_REF) + { + tree rval, type; + + /* Subscripting with type char is likely to lose + on a machine where chars are signed. + So warn on any machine, but optionally. + Don't warn for unsigned char since that type is safe. + Don't warn for signed char because anyone who uses that + must have done so deliberately. */ + if (warn_char_subscripts + && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node) + warning ("array subscript has type `char'"); + + /* Apply default promotions *after* noticing character types. */ + index = default_conversion (index); + + /* Require integer *after* promotion, for sake of enums. */ + if (TREE_CODE (TREE_TYPE (index)) != INTEGER_TYPE) + { + error ("array subscript is not an integer"); + return error_mark_node; + } + + /* An array that is indexed by a non-constant + cannot be stored in a register; we must be able to do + address arithmetic on its address. + Likewise an array of elements of variable size. */ + if (TREE_CODE (index) != INTEGER_CST + || (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))) != 0 + && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST)) + { + if (mark_addressable (array) == 0) + return error_mark_node; + } + /* An array that is indexed by a constant value which is not within + the array bounds cannot be stored in a register either; because we + would get a crash in store_bit_field/extract_bit_field when trying + to access a non-existent part of the register. */ + if (TREE_CODE (index) == INTEGER_CST + && TYPE_VALUES (TREE_TYPE (array)) + && ! int_fits_type_p (index, TYPE_VALUES (TREE_TYPE (array)))) + { + if (mark_addressable (array) == 0) + return error_mark_node; + } + + if (pedantic && !lvalue_p (array)) + { + if (DECL_REGISTER (array)) + pedwarn ("ANSI C forbids subscripting `register' array"); + else + pedwarn ("ANSI C forbids subscripting non-lvalue array"); + } + + if (pedantic) + { + tree foo = array; + while (TREE_CODE (foo) == COMPONENT_REF) + foo = TREE_OPERAND (foo, 0); + if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo)) + pedwarn ("ANSI C forbids subscripting non-lvalue array"); + } + + type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array))); + rval = build (ARRAY_REF, type, array, index); + /* Array ref is const/volatile if the array elements are + or if the array is. */ + TREE_READONLY (rval) + |= (TYPE_READONLY (TREE_TYPE (TREE_TYPE (array))) + | TREE_READONLY (array)); + TREE_SIDE_EFFECTS (rval) + |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) + | TREE_SIDE_EFFECTS (array)); + TREE_THIS_VOLATILE (rval) + |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) + /* This was added by rms on 16 Nov 91. + It fixes vol struct foo *a; a->elts[1] + in an inline function. + Hope it doesn't break something else. */ + | TREE_THIS_VOLATILE (array)); + return require_complete_type (fold (rval)); + } + + { + tree ar = default_conversion (array); + tree ind = default_conversion (index); + + /* Do the same warning check as above, but only on the part that's + syntactically the index and only if it is also semantically + the index. */ + if (warn_char_subscripts + && TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE + && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node) + warning ("subscript has type `char'"); + + /* Put the integer in IND to simplify error checking. */ + if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE) + { + tree temp = ar; + ar = ind; + ind = temp; + } + + if (ar == error_mark_node) + return ar; + + if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE + || TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) == FUNCTION_TYPE) + { + error ("subscripted value is neither array nor pointer"); + return error_mark_node; + } + if (TREE_CODE (TREE_TYPE (ind)) != INTEGER_TYPE) + { + error ("array subscript is not an integer"); + return error_mark_node; + } + + return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, ind, 0), + "array indexing"); + } +} + +/* Build a function call to function FUNCTION with parameters PARAMS. + PARAMS is a list--a chain of TREE_LIST nodes--in which the + TREE_VALUE of each node is a parameter-expression. + FUNCTION's data type may be a function type or a pointer-to-function. */ + +tree +build_function_call (function, params) + tree function, params; +{ + register tree fntype, fundecl = 0; + register tree coerced_params; + tree name = NULL_TREE, assembler_name = NULL_TREE; + + /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (function); + + if (TREE_CODE (function) == FUNCTION_DECL + && DECL_TARGET_OVERLOADED_INTRINSIC_P (function)) + { +#ifdef SELECT_TARGET_OVERLOADED_INTRINSIC + /* If this is an overloaded builtin function, we have to select + which overload to use now. */ + function = SELECT_TARGET_OVERLOADED_INTRINSIC (function, params); + if (function == NULL_TREE) +#endif + return error_mark_node; + } + + /* Convert anything with function type to a pointer-to-function. */ + if (TREE_CODE (function) == FUNCTION_DECL) + { + name = DECL_NAME (function); + assembler_name = DECL_ASSEMBLER_NAME (function); + + /* Differs from default_conversion by not setting TREE_ADDRESSABLE + (because calling an inline function does not mean the function + needs to be separately compiled). */ + fntype = build_type_variant (TREE_TYPE (function), + TREE_READONLY (function), + TREE_THIS_VOLATILE (function)); + fundecl = function; + function = build1 (ADDR_EXPR, build_pointer_type (fntype), function); + } + else + function = default_conversion (function); + + fntype = TREE_TYPE (function); + + if (TREE_CODE (fntype) == ERROR_MARK) + return error_mark_node; + + if (!(TREE_CODE (fntype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)) + { + error ("called object is not a function"); + return error_mark_node; + } + + /* fntype now gets the type of function pointed to. */ + fntype = TREE_TYPE (fntype); + + /* Convert the parameters to the types declared in the + function prototype, or apply default promotions. */ + + coerced_params + = convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl); + + /* Check for errors in format strings. */ + + if (warn_format && (name || assembler_name)) + check_function_format (name, assembler_name, coerced_params); + + /* Recognize certain built-in functions so we can make tree-codes + other than CALL_EXPR. We do this when it enables fold-const.c + to do something useful. */ + + if (TREE_CODE (function) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL + && DECL_BUILT_IN (TREE_OPERAND (function, 0))) + switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0))) + { + case BUILT_IN_ABS: + case BUILT_IN_LABS: + case BUILT_IN_FABS: + if (coerced_params == 0) + return integer_zero_node; + return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0); + default: + break; + } + + { + register tree result + = build (CALL_EXPR, TREE_TYPE (fntype), + function, coerced_params, NULL_TREE); + + TREE_SIDE_EFFECTS (result) = 1; + if (TREE_TYPE (result) == void_type_node) + return result; + return require_complete_type (result); + } +} + +/* Convert the argument expressions in the list VALUES + to the types in the list TYPELIST. The result is a list of converted + argument expressions. + + If TYPELIST is exhausted, or when an element has NULL as its type, + perform the default conversions. + + PARMLIST is the chain of parm decls for the function being called. + It may be 0, if that info is not available. + It is used only for generating error messages. + + NAME is an IDENTIFIER_NODE or 0. It is used only for error messages. + + This is also where warnings about wrong number of args are generated. + + Both VALUES and the returned value are chains of TREE_LIST nodes + with the elements of the list in the TREE_VALUE slots of those nodes. */ + +static tree +convert_arguments (typelist, values, name, fundecl) + tree typelist, values, name, fundecl; +{ + register tree typetail, valtail; + register tree result = NULL; + int parmnum; + + /* Scan the given expressions and types, producing individual + converted arguments and pushing them on RESULT in reverse order. */ + + for (valtail = values, typetail = typelist, parmnum = 0; + valtail; + valtail = TREE_CHAIN (valtail), parmnum++) + { + register tree type = typetail ? TREE_VALUE (typetail) : 0; + register tree val = TREE_VALUE (valtail); + + if (type == void_type_node) + { + if (name) + error ("too many arguments to function `%s'", + IDENTIFIER_POINTER (name)); + else + error ("too many arguments to function"); + break; + } + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + /* Do not use STRIP_NOPS here! We do not want an enumerator with value 0 + to convert automatically to a pointer. */ + if (TREE_CODE (val) == NON_LVALUE_EXPR) + val = TREE_OPERAND (val, 0); + + if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE) + val = default_conversion (val); + + val = require_complete_type (val); + + /* Ensure that a prototype is present if a vector type is involved. */ + if (typelist == 0 + && TREE_CODE (TREE_TYPE (val)) == VECTOR_TYPE + && !(DECL_BUILT_IN (fundecl) + && (DECL_FUNCTION_CODE (fundecl) == BUILT_IN_NEXT_ARG + || DECL_FUNCTION_CODE (fundecl) == BUILT_IN_CLASSIFY_TYPE))) + error ("vector argument %d requires a prototype for `%s'", + parmnum + 1, IDENTIFIER_POINTER (name)); + + if (type != 0) + { + /* Formal parm type is specified by a function prototype. */ + tree parmval; + + if (TYPE_SIZE (type) == 0) + { + error ("type of formal parameter %d is incomplete", parmnum + 1); + parmval = val; + } + else + { + /* Optionally warn about conversions that + differ from the default conversions. */ + if (warn_conversion) + { + int formal_prec = TYPE_PRECISION (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 + && 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', + since without a prototype it would be `double'. */ + if (formal_prec == TYPE_PRECISION (float_type_node)) + 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 (INTEGRAL_TYPE_P (type) + && INTEGRAL_TYPE_P (TREE_TYPE (val))) + { + tree would_have_been = default_conversion (val); + tree type1 = TREE_TYPE (would_have_been); + + if (TREE_CODE (type) == ENUMERAL_TYPE + && type == TREE_TYPE (val)) + /* No warning if function asks for enum + and the actual arg is that enum type. */ + ; + else if (formal_prec != TYPE_PRECISION (type1)) + warn_for_assignment ("%s with different width due to prototype", (char *) 0, name, parmnum + 1); + else if (TREE_UNSIGNED (type) == TREE_UNSIGNED (type1)) + ; + /* Don't complain if the formal parameter type + is an enum, because we can't tell now whether + the value was an enum--even the same enum. */ + else if (TREE_CODE (type) == ENUMERAL_TYPE) + ; + else if (TREE_CODE (val) == INTEGER_CST + && int_fits_type_p (val, type)) + /* Change in signedness doesn't matter + if a constant value is unaffected. */ + ; + /* Likewise for a constant in a NOP_EXPR. */ + else if (TREE_CODE (val) == NOP_EXPR + && TREE_CODE (TREE_OPERAND (val, 0)) == INTEGER_CST + && int_fits_type_p (TREE_OPERAND (val, 0), type)) + ; +#if 0 /* We never get such tree structure here. */ + else if (TREE_CODE (TREE_TYPE (val)) == ENUMERAL_TYPE + && int_fits_type_p (TYPE_MIN_VALUE (TREE_TYPE (val)), type) + && int_fits_type_p (TYPE_MAX_VALUE (TREE_TYPE (val)), type)) + /* Change in signedness doesn't matter + if an enum value is unaffected. */ + ; +#endif + /* If the value is extended from a narrower + unsigned type, it doesn't matter whether we + pass it as signed or unsigned; the value + certainly is the same either way. */ + else if (TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type) + && TREE_UNSIGNED (TREE_TYPE (val))) + ; + else if (TREE_UNSIGNED (type)) + warn_for_assignment ("%s as unsigned due to prototype", (char *) 0, name, parmnum + 1); + else + warn_for_assignment ("%s as signed due to prototype", (char *) 0, name, parmnum + 1); + } + } + + parmval = convert_for_assignment (type, val, + (char *) 0, /* arg passing */ + fundecl, name, parmnum + 1); + +#ifdef PROMOTE_PROTOTYPES + if ((TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) + parmval = default_conversion (parmval); +#endif + } + result = tree_cons (NULL_TREE, parmval, result); + } + else if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE + && (TYPE_PRECISION (TREE_TYPE (val)) + < TYPE_PRECISION (double_type_node))) + /* Convert `float' to `double'. */ + result = tree_cons (NULL_TREE, convert (double_type_node, val), result); + else + /* Convert `short' and `char' to full-size `int'. */ + result = tree_cons (NULL_TREE, default_conversion (val), result); + + if (typetail) + typetail = TREE_CHAIN (typetail); + } + + if (typetail != 0 && TREE_VALUE (typetail) != void_type_node) + { + if (name) + error ("too few arguments to function `%s'", + IDENTIFIER_POINTER (name)); + else + error ("too few arguments to function"); + } + + return nreverse (result); +} + +/* This is the entry point used by the parser + for binary operators in the input. + In addition to constructing the expression, + we check for operands that were written with other binary operators + in a way that is likely to confuse the user. */ + +tree +parser_build_binary_op (code, arg1, arg2) + enum tree_code code; + tree arg1, arg2; +{ + tree result = build_binary_op (code, arg1, arg2, 1); + + char class; + char class1 = TREE_CODE_CLASS (TREE_CODE (arg1)); + char class2 = TREE_CODE_CLASS (TREE_CODE (arg2)); + enum tree_code code1 = ERROR_MARK; + enum tree_code code2 = ERROR_MARK; + + if (class1 == 'e' || class1 == '1' + || class1 == '2' || class1 == '<') + code1 = C_EXP_ORIGINAL_CODE (arg1); + if (class2 == 'e' || class2 == '1' + || class2 == '2' || class2 == '<') + code2 = C_EXP_ORIGINAL_CODE (arg2); + + /* Check for cases such as x+y< TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0))) + && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op1, 0)))) + { + final_type = result_type; + op1 = TREE_OPERAND (op1, 0); + result_type = TREE_TYPE (op1); + } + if (TREE_CODE (op1) == INTEGER_CST + && TREE_CODE (op0) == NOP_EXPR + && TYPE_PRECISION (type0) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0))) + && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0)))) + { + final_type = result_type; + op0 = TREE_OPERAND (op0, 0); + result_type = TREE_TYPE (op0); + } + break; + + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + /* Although it would be tempting to shorten always here, that loses + on some targets, since the modulo instruction is undefined if the + quotient can't be represented in the computation mode. We shorten + only if unsigned or if dividing by something we know != -1. */ + shorten = (TREE_UNSIGNED (TREE_TYPE (orig_op0)) + || (TREE_CODE (op1) == INTEGER_CST + && (TREE_INT_CST_LOW (op1) != -1 + || TREE_INT_CST_HIGH (op1) != -1))); + common = 1; + } + break; + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE + || code0 == REAL_TYPE || code0 == COMPLEX_TYPE) + && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE + || code1 == REAL_TYPE || code1 == COMPLEX_TYPE)) + { + /* Result of these operations is always an int, + but that does not mean the operands should be + converted to ints! */ + result_type = integer_type_node; + op0 = truthvalue_conversion (op0); + op1 = truthvalue_conversion (op1); + converted = 1; + } + break; + + /* Shift operations: result has same type as first operand; + always convert second operand to int. + Also set SHORT_SHIFT if shifting rightward. */ + + case RSHIFT_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0) + { + if (tree_int_cst_sgn (op1) < 0) + warning ("right shift count is negative"); + else + { + if (TREE_INT_CST_LOW (op1) | TREE_INT_CST_HIGH (op1)) + short_shift = 1; + if (TREE_INT_CST_HIGH (op1) != 0 + || ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1) + >= TYPE_PRECISION (type0))) + warning ("right shift count >= width of type"); + } + } + /* Use the type of the value to be shifted. + This is what most traditional C compilers do. */ + result_type = type0; + /* Unless traditional, convert the shift-count to an integer, + regardless of size of value being shifted. */ + if (! flag_traditional) + { + if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node) + op1 = convert (integer_type_node, op1); + /* Avoid converting op1 to result_type later. */ + converted = 1; + } + } + break; + + case LSHIFT_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0) + { + if (tree_int_cst_sgn (op1) < 0) + warning ("left shift count is negative"); + else if (TREE_INT_CST_HIGH (op1) != 0 + || ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1) + >= TYPE_PRECISION (type0))) + warning ("left shift count >= width of type"); + } + /* Use the type of the value to be shifted. + This is what most traditional C compilers do. */ + result_type = type0; + /* Unless traditional, convert the shift-count to an integer, + regardless of size of value being shifted. */ + if (! flag_traditional) + { + if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node) + op1 = convert (integer_type_node, op1); + /* Avoid converting op1 to result_type later. */ + converted = 1; + } + } + break; + + case RROTATE_EXPR: + case LROTATE_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0) + { + if (tree_int_cst_sgn (op1) < 0) + warning ("shift count is negative"); + else if (TREE_INT_CST_HIGH (op1) != 0 + || ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1) + >= TYPE_PRECISION (type0))) + warning ("shift count >= width of type"); + } + /* Use the type of the value to be shifted. + This is what most traditional C compilers do. */ + result_type = type0; + /* Unless traditional, convert the shift-count to an integer, + regardless of size of value being shifted. */ + if (! flag_traditional) + { + if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node) + op1 = convert (integer_type_node, op1); + /* Avoid converting op1 to result_type later. */ + converted = 1; + } + } + break; + + case EQ_EXPR: + case NE_EXPR: + /* Result of comparison is always int, + but don't convert the args to int! */ + build_type = integer_type_node; + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE + || code0 == COMPLEX_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == COMPLEX_TYPE)) + short_compare = 1; + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + register tree tt0 = TREE_TYPE (type0); + register tree tt1 = TREE_TYPE (type1); + /* Anything compares with void *. void * compares with anything. + Otherwise, the targets must be compatible + and both must be object or both incomplete. */ + if (comp_target_types (type0, type1)) + result_type = common_type (type0, type1); + else if (TYPE_MAIN_VARIANT (tt0) == void_type_node) + { + /* op0 != orig_op0 detects the case of something + whose value is 0 but which isn't a valid null ptr const. */ + if (pedantic && (!integer_zerop (op0) || op0 != orig_op0) + && TREE_CODE (tt1) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids comparison of `void *' with function pointer"); + } + else if (TYPE_MAIN_VARIANT (tt1) == void_type_node) + { + if (pedantic && (!integer_zerop (op1) || op1 != orig_op1) + && TREE_CODE (tt0) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids comparison of `void *' with function pointer"); + } + else + pedwarn ("comparison of distinct pointer types lacks a cast"); + + if (result_type == NULL_TREE) + result_type = ptr_type_node; + } + else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST + && integer_zerop (op1)) + result_type = type0; + else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST + && integer_zerop (op0)) + result_type = type1; + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + result_type = type0; + if (! flag_traditional) + pedwarn ("comparison between pointer and integer"); + } + else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + { + result_type = type1; + if (! flag_traditional) + pedwarn ("comparison between pointer and integer"); + } + break; + + case MAX_EXPR: + case MIN_EXPR: + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE)) + shorten = 1; + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + if (comp_target_types (type0, type1)) + { + result_type = common_type (type0, type1); + if (pedantic + && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids ordered comparisons of pointers to functions"); + } + else + { + result_type = ptr_type_node; + pedwarn ("comparison of distinct pointer types lacks a cast"); + } + } + break; + + case LE_EXPR: + case GE_EXPR: + case LT_EXPR: + case GT_EXPR: + build_type = integer_type_node; + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE)) + short_compare = 1; + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + if (comp_target_types (type0, type1)) + { + result_type = common_type (type0, type1); + if ((TYPE_SIZE (TREE_TYPE (type0)) != 0) + != (TYPE_SIZE (TREE_TYPE (type1)) != 0)) + pedwarn ("comparison of complete and incomplete pointers"); + else if (pedantic + && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids ordered comparisons of pointers to functions"); + } + else + { + result_type = ptr_type_node; + pedwarn ("comparison of distinct pointer types lacks a cast"); + } + } + else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST + && integer_zerop (op1)) + { + result_type = type0; + if (pedantic || extra_warnings) + pedwarn ("ordered comparison of pointer with integer zero"); + } + else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST + && integer_zerop (op0)) + { + result_type = type1; + if (pedantic) + pedwarn ("ordered comparison of pointer with integer zero"); + } + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + result_type = type0; + if (! flag_traditional) + pedwarn ("comparison between pointer and integer"); + } + else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + { + result_type = type1; + if (! flag_traditional) + pedwarn ("comparison between pointer and integer"); + } + break; + + default: + break; + } + + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE) + && + (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE)) + { + int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE); + + if (shorten || common || short_compare) + result_type = common_type (type0, type1); + + /* For certain operations (which identify themselves by shorten != 0) + if both args were extended from the same smaller type, + do the arithmetic in that type and then extend. + + shorten !=0 and !=1 indicates a bitwise operation. + For them, this optimization is safe only if + both args are zero-extended or both are sign-extended. + Otherwise, we might change the result. + Eg, (short)-1 | (unsigned short)-1 is (int)-1 + but calculated in (unsigned short) it would be (unsigned short)-1. */ + + if (shorten && none_complex) + { + int unsigned0, unsigned1; + tree arg0 = get_narrower (op0, &unsigned0); + tree arg1 = get_narrower (op1, &unsigned1); + /* UNS is 1 if the operation to be done is an unsigned one. */ + int uns = TREE_UNSIGNED (result_type); + tree type; + + final_type = result_type; + + /* Handle the case that OP0 (or OP1) does not *contain* a conversion + but it *requires* conversion to FINAL_TYPE. */ + + if ((TYPE_PRECISION (TREE_TYPE (op0)) + == TYPE_PRECISION (TREE_TYPE (arg0))) + && TREE_TYPE (op0) != final_type) + unsigned0 = TREE_UNSIGNED (TREE_TYPE (op0)); + if ((TYPE_PRECISION (TREE_TYPE (op1)) + == TYPE_PRECISION (TREE_TYPE (arg1))) + && TREE_TYPE (op1) != final_type) + unsigned1 = TREE_UNSIGNED (TREE_TYPE (op1)); + + /* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE. */ + + /* For bitwise operations, signedness of nominal type + does not matter. Consider only how operands were extended. */ + if (shorten == -1) + uns = unsigned0; + + /* Note that in all three cases below we refrain from optimizing + an unsigned operation on sign-extended args. + That would not be valid. */ + + /* Both args variable: if both extended in same way + from same width, do it in that width. + Do it unsigned if args were zero-extended. */ + if ((TYPE_PRECISION (TREE_TYPE (arg0)) + < TYPE_PRECISION (result_type)) + && (TYPE_PRECISION (TREE_TYPE (arg1)) + == TYPE_PRECISION (TREE_TYPE (arg0))) + && unsigned0 == unsigned1 + && (unsigned0 || !uns)) + result_type + = signed_or_unsigned_type (unsigned0, + common_type (TREE_TYPE (arg0), TREE_TYPE (arg1))); + else if (TREE_CODE (arg0) == INTEGER_CST + && (unsigned1 || !uns) + && (TYPE_PRECISION (TREE_TYPE (arg1)) + < TYPE_PRECISION (result_type)) + && (type = signed_or_unsigned_type (unsigned1, + TREE_TYPE (arg1)), + int_fits_type_p (arg0, type))) + result_type = type; + else if (TREE_CODE (arg1) == INTEGER_CST + && (unsigned0 || !uns) + && (TYPE_PRECISION (TREE_TYPE (arg0)) + < TYPE_PRECISION (result_type)) + && (type = signed_or_unsigned_type (unsigned0, + TREE_TYPE (arg0)), + int_fits_type_p (arg1, type))) + result_type = type; + } + + /* Shifts can be shortened if shifting right. */ + + if (short_shift) + { + int unsigned_arg; + tree arg0 = get_narrower (op0, &unsigned_arg); + + final_type = result_type; + + if (arg0 == op0 && final_type == TREE_TYPE (op0)) + unsigned_arg = TREE_UNSIGNED (TREE_TYPE (op0)); + + if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type) + /* We can shorten only if the shift count is less than the + number of bits in the smaller type size. */ + && TREE_INT_CST_HIGH (op1) == 0 + && TYPE_PRECISION (TREE_TYPE (arg0)) > TREE_INT_CST_LOW (op1) + /* If arg is sign-extended and then unsigned-shifted, + we can simulate this with a signed shift in arg's type + only if the extended result is at least twice as wide + as the arg. Otherwise, the shift could use up all the + ones made by sign-extension and bring in zeros. + We can't optimize that case at all, but in most machines + it never happens because available widths are 2**N. */ + && (!TREE_UNSIGNED (final_type) + || unsigned_arg + || 2 * TYPE_PRECISION (TREE_TYPE (arg0)) <= TYPE_PRECISION (result_type))) + { + /* Do an unsigned shift if the operand was zero-extended. */ + result_type + = signed_or_unsigned_type (unsigned_arg, + TREE_TYPE (arg0)); + /* Convert value-to-be-shifted to that type. */ + if (TREE_TYPE (op0) != result_type) + op0 = convert (result_type, op0); + converted = 1; + } + } + + /* Comparison operations are shortened too but differently. + They identify themselves by setting short_compare = 1. */ + + if (short_compare) + { + /* Don't write &op0, etc., because that would prevent op0 + from being kept in a register. + Instead, make copies of the our local variables and + pass the copies by reference, then copy them back afterward. */ + tree xop0 = op0, xop1 = op1, xresult_type = result_type; + enum tree_code xresultcode = resultcode; + tree val + = shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode); + if (val != 0) + return val; + op0 = xop0, op1 = xop1; + converted = 1; + resultcode = xresultcode; + + if ((warn_sign_compare < 0 ? extra_warnings : warn_sign_compare != 0) + && skip_evaluation == 0) + { + int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0)); + int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1)); + + int unsignedp0, unsignedp1; + tree primop0 = get_narrower (op0, &unsignedp0); + tree primop1 = get_narrower (op1, &unsignedp1); + + /* Avoid spurious warnings for comparison with enumerators. */ + + xop0 = orig_op0; + xop1 = orig_op1; + STRIP_TYPE_NOPS (xop0); + STRIP_TYPE_NOPS (xop1); + + /* Give warnings for comparisons between signed and unsigned + quantities that may fail. */ + /* Do the checking based on the original operand trees, so that + casts will be considered, but default promotions won't be. */ + + /* Do not warn if the comparison is being done in a signed type, + since the signed type will only be chosen if it can represent + all the values of the unsigned type. */ + if (! TREE_UNSIGNED (result_type)) + /* OK */; + /* Do not warn if both operands are unsigned. */ + else if (op0_signed == op1_signed) + /* OK */; + /* Do not warn if the signed quantity is an unsuffixed + integer literal (or some static constant expression + involving such literals) and it is non-negative. */ + else if ((op0_signed && TREE_CODE (xop0) == INTEGER_CST + && tree_int_cst_sgn (xop0) >= 0) + || (op1_signed && TREE_CODE (xop1) == INTEGER_CST + && tree_int_cst_sgn (xop1) >= 0)) + /* OK */; + /* Do not warn if the comparison is an equality operation, + the unsigned quantity is an integral constant and it does + not use the most significant bit of result_type. */ + else if ((resultcode == EQ_EXPR || resultcode == NE_EXPR) + && ((op0_signed && TREE_CODE (xop1) == INTEGER_CST + && int_fits_type_p (xop1, signed_type (result_type))) + || (op1_signed && TREE_CODE (xop0) == INTEGER_CST + && int_fits_type_p (xop0, signed_type (result_type))))) + /* OK */; + else + warning ("comparison between signed and unsigned"); + + /* Warn if two unsigned values are being compared in a size + larger than their original size, and one (and only one) is the + result of a `~' operator. This comparison will always fail. + + Also warn if one operand is a constant, and the constant + does not have all bits set that are set in the ~ operand + when it is extended. */ + + if ((TREE_CODE (primop0) == BIT_NOT_EXPR) + != (TREE_CODE (primop1) == BIT_NOT_EXPR)) + { + if (TREE_CODE (primop0) == BIT_NOT_EXPR) + primop0 = get_narrower (TREE_OPERAND (primop0, 0), + &unsignedp0); + else + primop1 = get_narrower (TREE_OPERAND (primop1, 0), + &unsignedp1); + + if (TREE_CODE (primop0) == INTEGER_CST + || TREE_CODE (primop1) == INTEGER_CST) + { + tree primop; + long constant, mask; + int unsignedp, bits; + + if (TREE_CODE (primop0) == INTEGER_CST) + { + primop = primop1; + unsignedp = unsignedp1; + constant = TREE_INT_CST_LOW (primop0); + } + else + { + primop = primop0; + unsignedp = unsignedp0; + constant = TREE_INT_CST_LOW (primop1); + } + + bits = TYPE_PRECISION (TREE_TYPE (primop)); + if (bits < TYPE_PRECISION (result_type) + && bits < HOST_BITS_PER_LONG && unsignedp) + { + mask = (~0L) << bits; + if ((mask & constant) != mask) + warning ("comparison of promoted ~unsigned with constant"); + } + } + else if (unsignedp0 && unsignedp1 + && (TYPE_PRECISION (TREE_TYPE (primop0)) + < TYPE_PRECISION (result_type)) + && (TYPE_PRECISION (TREE_TYPE (primop1)) + < TYPE_PRECISION (result_type))) + warning ("comparison of promoted ~unsigned with unsigned"); + } + } + } + } + + /* At this point, RESULT_TYPE must be nonzero to avoid an error message. + If CONVERTED is zero, both args will be converted to type RESULT_TYPE. + Then the expression will be built. + It will be given type FINAL_TYPE if that is nonzero; + otherwise, it will be given type RESULT_TYPE. */ + + if (!result_type) + { + binary_op_error (code); + return error_mark_node; + } + + if (! converted) + { + if (TREE_TYPE (op0) != result_type) + op0 = convert (result_type, op0); + if (TREE_TYPE (op1) != result_type) + op1 = convert (result_type, op1); + } + + if (build_type == NULL_TREE) + build_type = result_type; + + { + register tree result = build (resultcode, build_type, op0, op1); + register tree folded; + + folded = fold (result); + if (folded == result) + TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1); + if (final_type != 0) + return convert (final_type, folded); + return folded; + } +} + +/* Return a tree for the sum or difference (RESULTCODE says which) + of pointer PTROP and integer INTOP. */ + +static tree +pointer_int_sum (resultcode, ptrop, intop) + enum tree_code resultcode; + register tree ptrop, intop; +{ + tree size_exp; + + register tree result; + register tree folded; + + /* The result is a pointer of the same type that is being added. */ + + register tree result_type = TREE_TYPE (ptrop); + + if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("pointer of type `void *' used in arithmetic"); + size_exp = integer_one_node; + } + else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("pointer to a function used in arithmetic"); + size_exp = integer_one_node; + } + else + size_exp = c_size_in_bytes (TREE_TYPE (result_type)); + + /* If what we are about to multiply by the size of the elements + contains a constant term, apply distributive law + and multiply that constant term separately. + This helps produce common subexpressions. */ + + if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR) + && ! TREE_CONSTANT (intop) + && TREE_CONSTANT (TREE_OPERAND (intop, 1)) + && TREE_CONSTANT (size_exp) + /* If the constant comes from pointer subtraction, + skip this optimization--it would cause an error. */ + && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE + /* If the constant is unsigned, and smaller than the pointer size, + then we must skip this optimization. This is because it could cause + an overflow error if the constant is negative but INTOP is not. */ + && (! TREE_UNSIGNED (TREE_TYPE (intop)) + || (TYPE_PRECISION (TREE_TYPE (intop)) + == TYPE_PRECISION (TREE_TYPE (ptrop))))) + { + enum tree_code subcode = resultcode; + tree int_type = TREE_TYPE (intop); + if (TREE_CODE (intop) == MINUS_EXPR) + subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR); + /* Convert both subexpression types to the type of intop, + because weird cases involving pointer arithmetic + can result in a sum or difference with different type args. */ + ptrop = build_binary_op (subcode, ptrop, + convert (int_type, TREE_OPERAND (intop, 1)), 1); + intop = convert (int_type, TREE_OPERAND (intop, 0)); + } + + /* Convert the integer argument to a type the same size as sizetype + so the multiply won't overflow spuriously. */ + + if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype) + || TREE_UNSIGNED (TREE_TYPE (intop)) != TREE_UNSIGNED (sizetype)) + intop = convert (type_for_size (TYPE_PRECISION (sizetype), + TREE_UNSIGNED (sizetype)), intop); + + /* Replace the integer argument with a suitable product by the object size. + Do this multiplication as signed, then convert to the appropriate + pointer type (actually unsigned integral). */ + + intop = convert (result_type, + build_binary_op (MULT_EXPR, intop, + convert (TREE_TYPE (intop), size_exp), 1)); + + /* Create the sum or difference. */ + + result = build (resultcode, result_type, ptrop, intop); + + folded = fold (result); + if (folded == result) + TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop); + return folded; +} + +/* Return a tree for the difference of pointers OP0 and OP1. + The resulting tree has type int. */ + +static tree +pointer_diff (op0, op1) + register tree op0, op1; +{ + register tree result, folded; + tree restype = ptrdiff_type_node; + + tree target_type = TREE_TYPE (TREE_TYPE (op0)); + + if (pedantic || warn_pointer_arith) + { + if (TREE_CODE (target_type) == VOID_TYPE) + pedwarn ("pointer of type `void *' used in subtraction"); + if (TREE_CODE (target_type) == FUNCTION_TYPE) + pedwarn ("pointer to a function used in subtraction"); + } + + /* First do the subtraction as integers; + then drop through to build the divide operator. + Do not do default conversions on the minus operator + in case restype is a short type. */ + + op0 = build_binary_op (MINUS_EXPR, convert (restype, op0), + convert (restype, op1), 0); + /* This generates an error if op1 is pointer to incomplete type. */ + if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (op1))) == 0) + error ("arithmetic on pointer to an incomplete type"); + + /* This generates an error if op0 is pointer to incomplete type. */ + op1 = c_size_in_bytes (target_type); + + /* Divide by the size, in easiest possible way. */ + + result = build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1)); + + folded = fold (result); + if (folded == result) + TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1); + return folded; +} + +/* Construct and perhaps optimize a tree representation + for a unary operation. CODE, a tree_code, specifies the operation + and XARG is the operand. NOCONVERT nonzero suppresses + the default promotions (such as from short to int). */ + +tree +build_unary_op (code, xarg, noconvert) + enum tree_code code; + tree xarg; + int noconvert; +{ + /* No default_conversion here. It causes trouble for ADDR_EXPR. */ + register tree arg = xarg; + register tree argtype = 0; + register enum tree_code typecode = TREE_CODE (TREE_TYPE (arg)); + tree val; + + if (typecode == ERROR_MARK) + return error_mark_node; + if (typecode == ENUMERAL_TYPE) + typecode = INTEGER_TYPE; + + switch (code) + { + case CONVERT_EXPR: + /* This is used for unary plus, because a CONVERT_EXPR + is enough to prevent anybody from looking inside for + associativity, but won't generate any code. */ + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE + || typecode == COMPLEX_TYPE)) + { + error ("wrong type argument to unary plus"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + break; + + case NEGATE_EXPR: + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE + || typecode == COMPLEX_TYPE)) + { + error ("wrong type argument to unary minus"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + break; + + case BIT_NOT_EXPR: + if (typecode == COMPLEX_TYPE) + { + code = CONJ_EXPR; + if (!noconvert) + arg = default_conversion (arg); + } + else if (typecode != INTEGER_TYPE) + { + error ("wrong type argument to bit-complement"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + break; + + case ABS_EXPR: + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE + || typecode == COMPLEX_TYPE)) + { + error ("wrong type argument to abs"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + break; + + case CONJ_EXPR: + /* Conjugating a real value is a no-op, but allow it anyway. */ + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE + || typecode == COMPLEX_TYPE)) + { + error ("wrong type argument to conjugation"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + break; + + case TRUTH_NOT_EXPR: + if (typecode != INTEGER_TYPE + && typecode != REAL_TYPE && typecode != POINTER_TYPE + && typecode != COMPLEX_TYPE + /* These will convert to a pointer. */ + && typecode != ARRAY_TYPE && typecode != FUNCTION_TYPE) + { + error ("wrong type argument to unary exclamation mark"); + return error_mark_node; + } + arg = truthvalue_conversion (arg); + return invert_truthvalue (arg); + + case NOP_EXPR: + break; + + case REALPART_EXPR: + if (TREE_CODE (arg) == COMPLEX_CST) + return TREE_REALPART (arg); + else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE) + return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg)); + else + return arg; + + case IMAGPART_EXPR: + if (TREE_CODE (arg) == COMPLEX_CST) + return TREE_IMAGPART (arg); + else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE) + return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg)); + else + return convert (TREE_TYPE (arg), integer_zero_node); + + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTDECREMENT_EXPR: + /* Handle complex lvalues (when permitted) + by reduction to simpler cases. */ + + val = unary_complex_lvalue (code, arg); + if (val != 0) + return val; + + /* Increment or decrement the real part of the value, + and don't change the imaginary part. */ + if (typecode == COMPLEX_TYPE) + { + tree real, imag; + + arg = stabilize_reference (arg); + real = build_unary_op (REALPART_EXPR, arg, 1); + imag = build_unary_op (IMAGPART_EXPR, arg, 1); + return build (COMPLEX_EXPR, TREE_TYPE (arg), + build_unary_op (code, real, 1), imag); + } + + /* Report invalid types. */ + + if (typecode != POINTER_TYPE + && typecode != INTEGER_TYPE && typecode != REAL_TYPE) + { + error (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR + ? "wrong type argument to increment" + : "wrong type argument to decrement"); + return error_mark_node; + } + + { + register tree inc; + tree result_type = TREE_TYPE (arg); + + arg = get_unwidened (arg, 0); + argtype = TREE_TYPE (arg); + + /* Compute the increment. */ + + if (typecode == POINTER_TYPE) + { + /* If pointer target is an undefined struct, + we just cannot know how to do the arithmetic. */ + if (TYPE_SIZE (TREE_TYPE (result_type)) == 0) + error (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR + ? "increment of pointer to unknown structure" + : "decrement of pointer to unknown structure"); + else if ((pedantic || warn_pointer_arith) + && (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)) + pedwarn (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR + ? "wrong type argument to increment" + : "wrong type argument to decrement"); + inc = c_size_in_bytes (TREE_TYPE (result_type)); + } + else + inc = integer_one_node; + + inc = convert (argtype, inc); + + /* Handle incrementing a cast-expression. */ + + while (1) + switch (TREE_CODE (arg)) + { + case NOP_EXPR: + case CONVERT_EXPR: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case FIX_CEIL_EXPR: + pedantic_lvalue_warning (CONVERT_EXPR); + /* If the real type has the same machine representation + as the type it is cast to, we can make better output + by adding directly to the inside of the cast. */ + if ((TREE_CODE (TREE_TYPE (arg)) + == TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 0)))) + && (TYPE_MODE (TREE_TYPE (arg)) + == TYPE_MODE (TREE_TYPE (TREE_OPERAND (arg, 0))))) + arg = TREE_OPERAND (arg, 0); + else + { + tree incremented, modify, value; + arg = stabilize_reference (arg); + if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR) + value = arg; + else + value = save_expr (arg); + incremented = build (((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? PLUS_EXPR : MINUS_EXPR), + argtype, value, inc); + TREE_SIDE_EFFECTS (incremented) = 1; + modify = build_modify_expr (arg, NOP_EXPR, incremented); + value = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value); + TREE_USED (value) = 1; + return value; + } + break; + + default: + goto give_up; + } + give_up: + + /* Complain about anything else that is not a true lvalue. */ + if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "invalid lvalue in increment" + : "invalid lvalue in decrement"))) + return error_mark_node; + + /* Report a read-only lvalue. */ + if (TREE_READONLY (arg)) + readonly_warning (arg, + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "increment" : "decrement")); + + val = build (code, TREE_TYPE (arg), arg, inc); + TREE_SIDE_EFFECTS (val) = 1; + val = convert (result_type, val); + if (TREE_CODE (val) != code) + TREE_NO_UNUSED_WARNING (val) = 1; + return val; + } + + case ADDR_EXPR: + /* Note that this operation never does default_conversion + regardless of NOCONVERT. */ + + /* Let &* cancel out to simplify resulting code. */ + if (TREE_CODE (arg) == INDIRECT_REF) + { + /* Don't let this be an lvalue. */ + if (lvalue_p (TREE_OPERAND (arg, 0))) + return non_lvalue (TREE_OPERAND (arg, 0)); + return TREE_OPERAND (arg, 0); + } + + /* For &x[y], return x+y */ + if (TREE_CODE (arg) == ARRAY_REF) + { + if (mark_addressable (TREE_OPERAND (arg, 0)) == 0) + return error_mark_node; + return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0), + TREE_OPERAND (arg, 1), 1); + } + + /* Handle complex lvalues (when permitted) + by reduction to simpler cases. */ + val = unary_complex_lvalue (code, arg); + if (val != 0) + return val; + +#if 0 /* Turned off because inconsistent; + float f; *&(int)f = 3.4 stores in int format + whereas (int)f = 3.4 stores in float format. */ + /* Address of a cast is just a cast of the address + of the operand of the cast. */ + switch (TREE_CODE (arg)) + { + case NOP_EXPR: + case CONVERT_EXPR: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case FIX_CEIL_EXPR: + if (pedantic) + pedwarn ("ANSI C forbids the address of a cast expression"); + return convert (build_pointer_type (TREE_TYPE (arg)), + build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), + 0)); + } +#endif + + /* Allow the address of a constructor if all the elements + are constant. */ + if (TREE_CODE (arg) == CONSTRUCTOR && TREE_CONSTANT (arg)) + ; + /* Anything not already handled and not a true memory reference + is an error. */ + else if (typecode != FUNCTION_TYPE + && !lvalue_or_else (arg, "invalid lvalue in unary `&'")) + return error_mark_node; + + /* Ordinary case; arg is a COMPONENT_REF or a decl. */ + argtype = TREE_TYPE (arg); + /* If the lvalue is const or volatile, merge that into the type + to which the address will point. Note that you can't get a + restricted pointer by taking the address of something, so we + only have to deal with `const' and `volatile' here. */ + if (TREE_CODE_CLASS (TREE_CODE (arg)) == 'd' + || TREE_CODE_CLASS (TREE_CODE (arg)) == 'r') + { + if (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)) + argtype = c_build_type_variant (argtype, + TREE_READONLY (arg), + TREE_THIS_VOLATILE (arg)); + } + + argtype = build_pointer_type (argtype); + + if (mark_addressable (arg) == 0) + return error_mark_node; + + { + tree addr; + + if (TREE_CODE (arg) == COMPONENT_REF) + { + tree field = TREE_OPERAND (arg, 1); + + addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0); + + if (DECL_C_BIT_FIELD (field)) + { + error ("attempt to take address of bit-field structure member `%s'", + IDENTIFIER_POINTER (DECL_NAME (field))); + return error_mark_node; + } + + addr = convert (argtype, addr); + + if (! integer_zerop (DECL_FIELD_BITPOS (field))) + { + tree offset + = size_binop (EASY_DIV_EXPR, DECL_FIELD_BITPOS (field), + size_int (BITS_PER_UNIT)); + int flag = TREE_CONSTANT (addr); + addr = fold (build (PLUS_EXPR, argtype, + addr, convert (argtype, offset))); + TREE_CONSTANT (addr) = flag; + } + } + else + addr = build1 (code, argtype, arg); + + /* Address of a static or external variable or + file-scope function counts as a constant. */ + if (staticp (arg) + && ! (TREE_CODE (arg) == FUNCTION_DECL + && DECL_CONTEXT (arg) != 0)) + TREE_CONSTANT (addr) = 1; + return addr; + } + + default: + break; + } + + if (argtype == 0) + argtype = TREE_TYPE (arg); + return fold (build1 (code, argtype, arg)); +} + +#if 0 +/* If CONVERSIONS is a conversion expression or a nested sequence of such, + convert ARG with the same conversions in the same order + and return the result. */ + +static tree +convert_sequence (conversions, arg) + tree conversions; + tree arg; +{ + switch (TREE_CODE (conversions)) + { + case NOP_EXPR: + case CONVERT_EXPR: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case FIX_CEIL_EXPR: + return convert (TREE_TYPE (conversions), + convert_sequence (TREE_OPERAND (conversions, 0), + arg)); + + default: + return arg; + } +} +#endif /* 0 */ + +/* Return nonzero if REF is an lvalue valid for this language. + Lvalues can be assigned, unless their type has TYPE_READONLY. + Lvalues can have their address taken, unless they have DECL_REGISTER. */ + +int +lvalue_p (ref) + tree ref; +{ + register enum tree_code code = TREE_CODE (ref); + + switch (code) + { + case REALPART_EXPR: + case IMAGPART_EXPR: + case COMPONENT_REF: + return lvalue_p (TREE_OPERAND (ref, 0)); + + case STRING_CST: + return 1; + + case INDIRECT_REF: + case ARRAY_REF: + case VAR_DECL: + case PARM_DECL: + case RESULT_DECL: + case ERROR_MARK: + return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE); + + case BIND_EXPR: + case RTL_EXPR: + return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE; + + default: + return 0; + } +} + +/* Return nonzero if REF is an lvalue valid for this language; + otherwise, print an error message and return zero. */ + +int +lvalue_or_else (ref, msgid) + tree ref; + const char *msgid; +{ + int win = lvalue_p (ref); + if (! win) + error (msgid); + return win; +} + +/* Apply unary lvalue-demanding operator CODE to the expression ARG + for certain kinds of expressions which are not really lvalues + but which we can accept as lvalues. + + If ARG is not a kind of expression we can handle, return zero. */ + +static tree +unary_complex_lvalue (code, arg) + enum tree_code code; + tree arg; +{ + /* Handle (a, b) used as an "lvalue". */ + if (TREE_CODE (arg) == COMPOUND_EXPR) + { + tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0); + + /* If this returns a function type, it isn't really being used as + an lvalue, so don't issue a warning about it. */ + if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE) + pedantic_lvalue_warning (COMPOUND_EXPR); + + return build (COMPOUND_EXPR, TREE_TYPE (real_result), + TREE_OPERAND (arg, 0), real_result); + } + + /* Handle (a ? b : c) used as an "lvalue". */ + if (TREE_CODE (arg) == COND_EXPR) + { + pedantic_lvalue_warning (COND_EXPR); + if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE) + pedantic_lvalue_warning (COMPOUND_EXPR); + + return (build_conditional_expr + (TREE_OPERAND (arg, 0), + build_unary_op (code, TREE_OPERAND (arg, 1), 0), + build_unary_op (code, TREE_OPERAND (arg, 2), 0))); + } + + return 0; +} + +/* If pedantic, warn about improper lvalue. CODE is either COND_EXPR + COMPOUND_EXPR, or CONVERT_EXPR (for casts). */ + +static void +pedantic_lvalue_warning (code) + enum tree_code code; +{ + if (pedantic) + pedwarn (code == COND_EXPR + ? "ANSI C forbids use of conditional expressions as lvalues" + : code == COMPOUND_EXPR + ? "ANSI C forbids use of compound expressions as lvalues" + : "ANSI C forbids use of cast expressions as lvalues"); +} + +/* Warn about storing in something that is `const'. */ + +void +readonly_warning (arg, msgid) + tree arg; + const char *msgid; +{ + /* Forbid assignments to iterators. */ + if (TREE_CODE (arg) == VAR_DECL && ITERATOR_P (arg)) + pedwarn ("%s of iterator `%s'", _(msgid), + IDENTIFIER_POINTER (DECL_NAME (arg))); + + if (TREE_CODE (arg) == COMPONENT_REF) + { + if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0)))) + readonly_warning (TREE_OPERAND (arg, 0), msgid); + else + pedwarn ("%s of read-only member `%s'", _(msgid), + IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1)))); + } + else if (TREE_CODE (arg) == VAR_DECL) + pedwarn ("%s of read-only variable `%s'", _(msgid), + IDENTIFIER_POINTER (DECL_NAME (arg))); + else + pedwarn ("%s of read-only location", _(msgid)); +} + +/* Mark EXP saying that we need to be able to take the + address of it; it should not be allocated in a register. + Value is 1 if successful. */ + +#ifndef __GNUFORTRAN__ +int +mark_addressable (exp) + tree exp; +{ + register tree x = exp; + while (1) + switch (TREE_CODE (x)) + { + case COMPONENT_REF: + if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1))) + { + error ("cannot take address of bitfield `%s'", + IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (x, 1)))); + return 0; + } + + /* ... fall through ... */ + + case ADDR_EXPR: + case ARRAY_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + x = TREE_OPERAND (x, 0); + break; + + case CONSTRUCTOR: + TREE_ADDRESSABLE (x) = 1; + return 1; + + case VAR_DECL: + case CONST_DECL: + case PARM_DECL: + case RESULT_DECL: + if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x) + && DECL_NONLOCAL (x)) + { + if (TREE_PUBLIC (x)) + { + error ("global register variable `%s' used in nested function", + IDENTIFIER_POINTER (DECL_NAME (x))); + return 0; + } + pedwarn ("register variable `%s' used in nested function", + IDENTIFIER_POINTER (DECL_NAME (x))); + } + else if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)) + { + if (TREE_PUBLIC (x)) + { + error ("address of global register variable `%s' requested", + 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))); + } + put_var_into_stack (x); + + /* drops in */ + case FUNCTION_DECL: + TREE_ADDRESSABLE (x) = 1; +#if 0 /* poplevel deals with this now. */ + if (DECL_CONTEXT (x) == 0) + TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1; +#endif + + default: + return 1; + } +} +#endif + + +/* Build and return a conditional expression IFEXP ? OP1 : OP2. */ + +tree +build_conditional_expr (ifexp, op1, op2) + tree ifexp, op1, op2; +{ + register tree type1; + register tree type2; + register enum tree_code code1; + register enum tree_code code2; + register tree result_type = NULL; + tree orig_op1 = op1, orig_op2 = op2; + + ifexp = truthvalue_conversion (default_conversion (ifexp)); + +#if 0 /* Produces wrong result if within sizeof. */ + /* Don't promote the operands separately if they promote + the same way. Return the unpromoted type and let the combined + value get promoted if necessary. */ + + if (TREE_TYPE (op1) == TREE_TYPE (op2) + && TREE_CODE (TREE_TYPE (op1)) != ARRAY_TYPE + && TREE_CODE (TREE_TYPE (op1)) != ENUMERAL_TYPE + && TREE_CODE (TREE_TYPE (op1)) != FUNCTION_TYPE) + { + if (TREE_CODE (ifexp) == INTEGER_CST) + return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1); + + return fold (build (COND_EXPR, TREE_TYPE (op1), ifexp, op1, op2)); + } +#endif + + /* Promote both alternatives. */ + + if (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE) + op1 = default_conversion (op1); + if (TREE_CODE (TREE_TYPE (op2)) != VOID_TYPE) + op2 = default_conversion (op2); + + if (TREE_CODE (ifexp) == ERROR_MARK + || TREE_CODE (TREE_TYPE (op1)) == ERROR_MARK + || TREE_CODE (TREE_TYPE (op2)) == ERROR_MARK) + return error_mark_node; + + type1 = TREE_TYPE (op1); + code1 = TREE_CODE (type1); + type2 = TREE_TYPE (op2); + code2 = TREE_CODE (type2); + + /* Quickly detect the usual case where op1 and op2 have the same type + after promotion. */ + if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)) + { + if (type1 == type2) + result_type = type1; + else + result_type = TYPE_MAIN_VARIANT (type1); + } + else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE) + && (code2 == INTEGER_TYPE || code2 == REAL_TYPE)) + { + result_type = common_type (type1, type2); + } + else if (code1 == VOID_TYPE || code2 == VOID_TYPE) + { + if (pedantic && (code1 != VOID_TYPE || code2 != VOID_TYPE)) + pedwarn ("ANSI C forbids conditional expr with only one void side"); + result_type = void_type_node; + } + else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE) + { + if (comp_target_types (type1, type2)) + result_type = common_type (type1, type2); + else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node + && TREE_CODE (orig_op1) != NOP_EXPR) + result_type = qualify_type (type2, type1); + else if (integer_zerop (op2) && TREE_TYPE (type2) == void_type_node + && TREE_CODE (orig_op2) != NOP_EXPR) + result_type = qualify_type (type1, type2); + else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node) + { + if (pedantic && TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids conditional expr between `void *' and function pointer"); + result_type = qualify_type (type1, type2); + } + else if (TYPE_MAIN_VARIANT (TREE_TYPE (type2)) == void_type_node) + { + if (pedantic && TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids conditional expr between `void *' and function pointer"); + result_type = qualify_type (type2, type1); + } + else + { + pedwarn ("pointer type mismatch in conditional expression"); + result_type = build_pointer_type (void_type_node); + } + } + else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE) + { + if (! integer_zerop (op2)) + pedwarn ("pointer/integer type mismatch in conditional expression"); + else + { + op2 = null_pointer_node; +#if 0 /* The spec seems to say this is permitted. */ + if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids conditional expr between 0 and function pointer"); +#endif + } + result_type = type1; + } + else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + if (!integer_zerop (op1)) + pedwarn ("pointer/integer type mismatch in conditional expression"); + else + { + op1 = null_pointer_node; +#if 0 /* The spec seems to say this is permitted. */ + if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids conditional expr between 0 and function pointer"); +#endif + } + result_type = type2; + } + + if (!result_type) + { + if (flag_cond_mismatch) + result_type = void_type_node; + else + { + error ("type mismatch in conditional expression"); + return error_mark_node; + } + } + + /* Merge const and volatile flags of the incoming types. */ + result_type + = build_type_variant (result_type, + TREE_READONLY (op1) || TREE_READONLY (op2), + TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2)); + + if (result_type != TREE_TYPE (op1)) + op1 = convert_and_check (result_type, op1); + if (result_type != TREE_TYPE (op2)) + op2 = convert_and_check (result_type, op2); + +#if 0 + if (code1 == RECORD_TYPE || code1 == UNION_TYPE) + { + result_type = TREE_TYPE (op1); + if (TREE_CONSTANT (ifexp)) + return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1); + + if (TYPE_MODE (result_type) == BLKmode) + { + register tree tempvar + = build_decl (VAR_DECL, NULL_TREE, result_type); + register tree xop1 = build_modify_expr (tempvar, op1); + register tree xop2 = build_modify_expr (tempvar, op2); + register tree result = fold (build (COND_EXPR, result_type, + ifexp, xop1, xop2)); + + layout_decl (tempvar, TYPE_ALIGN (result_type)); + /* No way to handle variable-sized objects here. + I fear that the entire handling of BLKmode conditional exprs + needs to be redone. */ + if (TREE_CODE (DECL_SIZE (tempvar)) != INTEGER_CST) + abort (); + DECL_RTL (tempvar) + = assign_stack_local (DECL_MODE (tempvar), + (TREE_INT_CST_LOW (DECL_SIZE (tempvar)) + + BITS_PER_UNIT - 1) + / BITS_PER_UNIT, + 0); + + TREE_SIDE_EFFECTS (result) + = TREE_SIDE_EFFECTS (ifexp) | TREE_SIDE_EFFECTS (op1) + | TREE_SIDE_EFFECTS (op2); + return build (COMPOUND_EXPR, result_type, result, tempvar); + } + } +#endif /* 0 */ + + if (TREE_CODE (ifexp) == INTEGER_CST) + return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1); + + return fold (build (COND_EXPR, result_type, ifexp, op1, op2)); +} + +/* Given a list of expressions, return a compound expression + that performs them all and returns the value of the last of them. */ + +tree +build_compound_expr (list) + tree list; +{ + return internal_build_compound_expr (list, TRUE); +} + +static tree +internal_build_compound_expr (list, first_p) + tree list; + int first_p; +{ + register tree rest; + + if (TREE_CHAIN (list) == 0) + { +#if 0 /* If something inside inhibited lvalueness, we should not override. */ + /* Consider (x, y+0), which is not an lvalue since y+0 is not. */ + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + if (TREE_CODE (list) == NON_LVALUE_EXPR) + list = TREE_OPERAND (list, 0); +#endif + + /* Don't let (0, 0) be null pointer constant. */ + if (!first_p && integer_zerop (TREE_VALUE (list))) + return non_lvalue (TREE_VALUE (list)); + return TREE_VALUE (list); + } + + if (TREE_CHAIN (list) != 0 && TREE_CHAIN (TREE_CHAIN (list)) == 0) + { + /* Convert arrays to pointers when there really is a comma operator. */ + if (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (list)))) == ARRAY_TYPE) + TREE_VALUE (TREE_CHAIN (list)) + = default_conversion (TREE_VALUE (TREE_CHAIN (list))); + } + + rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE); + + if (! TREE_SIDE_EFFECTS (TREE_VALUE (list))) + { + /* The left-hand operand of a comma expression is like an expression + statement: with -W or -Wunused, we should warn if it doesn't have + any side-effects, unless it was explicitly cast to (void). */ + if ((extra_warnings || warn_unused) + && ! (TREE_CODE (TREE_VALUE (list)) == CONVERT_EXPR + && TREE_TYPE (TREE_VALUE (list)) == void_type_node)) + warning ("left-hand operand of comma expression has no effect"); + + /* When pedantic, a compound expression can be neither an lvalue + nor an integer constant expression. */ + if (! pedantic) + return rest; + } + + /* With -Wunused, we should also warn if the left-hand operand does have + side-effects, but computes a value which is not used. For example, in + `foo() + bar(), baz()' the result of the `+' operator is not used, + so we should issue a warning. */ + else if (warn_unused) + warn_if_unused_value (TREE_VALUE (list)); + + return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest); +} + +/* Build an expression representing a cast to type TYPE of expression EXPR. */ + +tree +build_c_cast (type, expr) + register tree type; + tree expr; +{ + register tree value = expr; + + if (type == error_mark_node || expr == error_mark_node) + return error_mark_node; + if (TREE_CODE (type) != POINTER_TYPE + || !is_protocol_qualified_id (type)) + type = TYPE_MAIN_VARIANT (type); + +#if 0 + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + if (TREE_CODE (value) == NON_LVALUE_EXPR) + value = TREE_OPERAND (value, 0); +#endif + + if (TREE_CODE (type) == ARRAY_TYPE) + { + error ("cast specifies array type"); + return error_mark_node; + } + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("cast specifies function type"); + return error_mark_node; + } + + if (type == TREE_TYPE (value)) + { + if (pedantic) + { + if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + pedwarn ("ANSI C forbids casting nonscalar to the same type"); + } + } + else if (TREE_CODE (type) == UNION_TYPE) + { + tree field; + if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE) + value = default_conversion (value); + + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)), + TYPE_MAIN_VARIANT (TREE_TYPE (value)))) + break; + + if (field) + { + const char *name; + tree t; + + if (pedantic) + pedwarn ("ANSI C forbids casts to union type"); + if (TYPE_NAME (type) != 0) + { + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + name = IDENTIFIER_POINTER (TYPE_NAME (type)); + else + name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); + } + else + name = ""; + t = digest_init (type, build (CONSTRUCTOR, type, NULL_TREE, + build_tree_list (field, value)), + 0, 0); + TREE_CONSTANT (t) = TREE_CONSTANT (value); + return t; + } + error ("cast to union type from type not present in union"); + return error_mark_node; + } + else + { + tree otype, ovalue; + + /* If casting to void, avoid the error that would come + from default_conversion in the case of a non-lvalue array. */ + if (type == void_type_node) + return build1 (CONVERT_EXPR, type, value); + + /* Convert functions and arrays to pointers, + but don't convert any other types. */ + if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE) + value = default_conversion (value); + otype = TREE_TYPE (value); + + /* Optionally warn about potentially worrisome casts. */ + + if (warn_cast_qual + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE) + { + /* Go to the innermost object being pointed to. */ + tree in_type = type; + tree in_otype = otype; + + while (TREE_CODE (in_type) == POINTER_TYPE) + in_type = TREE_TYPE (in_type); + while (TREE_CODE (in_otype) == POINTER_TYPE) + in_otype = TREE_TYPE (in_otype); + + if (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type)) + /* There are qualifiers present in IN_OTYPE that are not + present in IN_TYPE. */ + pedwarn ("cast discards qualifiers from pointer target type"); + } + + /* Warn about possible alignment problems. */ + if (STRICT_ALIGNMENT && warn_cast_align + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE + && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE + /* Don't warn about opaque types, where the actual alignment + restriction is unknown. */ + && !((TREE_CODE (TREE_TYPE (otype)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE) + && TYPE_MODE (TREE_TYPE (otype)) == VOIDmode) + && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype))) + warning ("cast increases required alignment of target type"); + + if (TREE_CODE (type) == INTEGER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TYPE_PRECISION (type) != TYPE_PRECISION (otype) + && !TREE_CONSTANT (value)) + warning ("cast from pointer to integer of different size"); + + if (warn_bad_function_cast + && TREE_CODE (value) == CALL_EXPR + && TREE_CODE (type) != TREE_CODE (otype)) + warning ("cast does not match function type"); + + if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == INTEGER_TYPE + && TYPE_PRECISION (type) != TYPE_PRECISION (otype) +#if 0 + /* Don't warn about converting 0 to pointer, + provided the 0 was explicit--not cast or made by folding. */ + && !(TREE_CODE (value) == INTEGER_CST && integer_zerop (value)) +#endif + /* Don't warn about converting any constant. */ + && !TREE_CONSTANT (value)) + warning ("cast to pointer from integer of different size"); + + ovalue = value; + value = convert (type, value); + + /* Ignore any integer overflow caused by the cast. */ + if (TREE_CODE (value) == INTEGER_CST) + { + TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue); + TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue); + } + } + + /* Pedantically, don't ley (void *) (FOO *) 0 be a null pointer constant. */ + if (pedantic && TREE_CODE (value) == INTEGER_CST + && TREE_CODE (expr) == INTEGER_CST + && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE) + value = non_lvalue (value); + + /* If pedantic, don't let a cast be an lvalue. */ + if (value == expr && pedantic) + value = non_lvalue (value); + + return value; +} + +/* Build an assignment expression of lvalue LHS from value RHS. + MODIFYCODE is the code for a binary operator that we use + to combine the old value of LHS with RHS to get the new value. + Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment. */ + +tree +build_modify_expr (lhs, modifycode, rhs) + tree lhs, rhs; + enum tree_code modifycode; +{ + register tree result; + tree newrhs; + tree lhstype = TREE_TYPE (lhs); + tree olhstype = lhstype; + + /* Types that aren't fully specified cannot be used in assignments. */ + lhs = require_complete_type (lhs); + + /* Avoid duplicate error messages from operands that had errors. */ + if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK) + return error_mark_node; + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + /* Do not use STRIP_NOPS here. We do not want an enumerator + whose value is 0 to count as a null pointer constant. */ + if (TREE_CODE (rhs) == NON_LVALUE_EXPR) + rhs = TREE_OPERAND (rhs, 0); + + newrhs = rhs; + + /* Handle control structure constructs used as "lvalues". */ + + switch (TREE_CODE (lhs)) + { + /* Handle (a, b) used as an "lvalue". */ + case COMPOUND_EXPR: + pedantic_lvalue_warning (COMPOUND_EXPR); + newrhs = build_modify_expr (TREE_OPERAND (lhs, 1), + modifycode, rhs); + if (TREE_CODE (newrhs) == ERROR_MARK) + return error_mark_node; + return build (COMPOUND_EXPR, lhstype, + TREE_OPERAND (lhs, 0), newrhs); + + /* Handle (a ? b : c) used as an "lvalue". */ + case COND_EXPR: + pedantic_lvalue_warning (COND_EXPR); + rhs = save_expr (rhs); + { + /* Produce (a ? (b = rhs) : (c = rhs)) + except that the RHS goes through a save-expr + so the code to compute it is only emitted once. */ + tree cond + = build_conditional_expr (TREE_OPERAND (lhs, 0), + build_modify_expr (TREE_OPERAND (lhs, 1), + modifycode, rhs), + build_modify_expr (TREE_OPERAND (lhs, 2), + modifycode, rhs)); + if (TREE_CODE (cond) == ERROR_MARK) + return cond; + /* Make sure the code to compute the rhs comes out + before the split. */ + return build (COMPOUND_EXPR, TREE_TYPE (lhs), + /* But cast it to void to avoid an "unused" error. */ + convert (void_type_node, rhs), cond); + } + default: + break; + } + + /* If a binary op has been requested, combine the old LHS value with the RHS + producing the value we should actually store into the LHS. */ + + if (modifycode != NOP_EXPR) + { + lhs = stabilize_reference (lhs); + newrhs = build_binary_op (modifycode, lhs, rhs, 1); + } + + /* Handle a cast used as an "lvalue". + We have already performed any binary operator using the value as cast. + Now convert the result to the cast type of the lhs, + and then true type of the lhs and store it there; + then convert result back to the cast type to be the value + of the assignment. */ + + switch (TREE_CODE (lhs)) + { + case NOP_EXPR: + case CONVERT_EXPR: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case FIX_CEIL_EXPR: + if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE) + newrhs = default_conversion (newrhs); + { + tree inner_lhs = TREE_OPERAND (lhs, 0); + tree result; + result = build_modify_expr (inner_lhs, NOP_EXPR, + convert (TREE_TYPE (inner_lhs), + convert (lhstype, newrhs))); + if (TREE_CODE (result) == ERROR_MARK) + return result; + pedantic_lvalue_warning (CONVERT_EXPR); + return convert (TREE_TYPE (lhs), result); + } + + default: + break; + } + + /* Now we have handled acceptable kinds of LHS that are not truly lvalues. + Reject anything strange now. */ + + if (!lvalue_or_else (lhs, "invalid lvalue in assignment")) + return error_mark_node; + + /* Warn about storing in something that is `const'. */ + + if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype) + || ((TREE_CODE (lhstype) == RECORD_TYPE + || TREE_CODE (lhstype) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (lhstype))) + readonly_warning (lhs, "assignment"); + + /* If storing into a structure or union member, + it has probably been given type `int'. + Compute the type that would go with + the actual amount of storage the member occupies. */ + + if (TREE_CODE (lhs) == COMPONENT_REF + && (TREE_CODE (lhstype) == INTEGER_TYPE + || TREE_CODE (lhstype) == REAL_TYPE + || TREE_CODE (lhstype) == ENUMERAL_TYPE)) + lhstype = TREE_TYPE (get_unwidened (lhs, 0)); + + /* If storing in a field that is in actuality a short or narrower than one, + we must store in the field in its actual type. */ + + if (lhstype != TREE_TYPE (lhs)) + { + lhs = copy_node (lhs); + TREE_TYPE (lhs) = lhstype; + } + + /* Convert new value to destination type. */ + + newrhs = convert_for_assignment (lhstype, newrhs, _("assignment"), + NULL_TREE, NULL_TREE, 0); + if (TREE_CODE (newrhs) == ERROR_MARK) + return error_mark_node; + + result = build (MODIFY_EXPR, lhstype, lhs, newrhs); + TREE_SIDE_EFFECTS (result) = 1; + + /* If we got the LHS in a different type for storing in, + convert the result back to the nominal type of LHS + so that the value we return always has the same type + as the LHS argument. */ + + if (olhstype == TREE_TYPE (result)) + return result; + return convert_for_assignment (olhstype, result, _("assignment"), + NULL_TREE, NULL_TREE, 0); +} + +/* Convert value RHS to type TYPE as preparation for an assignment + to an lvalue of type TYPE. + The real work of conversion is done by `convert'. + The purpose of this function is to generate error messages + for assignments that are not allowed in C. + ERRTYPE is a string to use in error messages: + "assignment", "return", etc. If it is null, this is parameter passing + for a function call (and different error messages are output). + + FUNNAME is the name of the function being called, + as an IDENTIFIER_NODE, or null. + PARMNUM is the number of the argument, for printing in error messages. */ + +static tree +convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum) + tree type, rhs; + const char *errtype; + tree fundecl, funname; + int parmnum; +{ + register enum tree_code codel = TREE_CODE (type); + register tree rhstype; + register enum tree_code coder; + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + /* Do not use STRIP_NOPS here. We do not want an enumerator + whose value is 0 to count as a null pointer constant. */ + if (TREE_CODE (rhs) == NON_LVALUE_EXPR) + rhs = TREE_OPERAND (rhs, 0); + + if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE) + rhs = default_conversion (rhs); + else if (optimize && TREE_CODE (rhs) == VAR_DECL) + rhs = decl_constant_value (rhs); + + rhstype = TREE_TYPE (rhs); + coder = TREE_CODE (rhstype); + + if (coder == ERROR_MARK) + return error_mark_node; + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)) + { + overflow_warning (rhs); + /* Check for Objective-C protocols. This will issue a warning if + there are protocol violations. No need to use the return value. */ + maybe_objc_comptypes (type, rhstype, 0); + return rhs; + } + + if (coder == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + /* 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)) + return convert_and_check (type, rhs); + + /* Conversion to a transparent union from its member types. + This applies only to function arguments. */ + else if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type) && ! errtype) + { + tree memb_types; + tree marginal_memb_type = 0; + + for (memb_types = TYPE_FIELDS (type); memb_types; + memb_types = TREE_CHAIN (memb_types)) + { + tree memb_type = TREE_TYPE (memb_types); + + if (comptypes (TYPE_MAIN_VARIANT (memb_type), + TYPE_MAIN_VARIANT (rhstype))) + break; + + if (TREE_CODE (memb_type) != POINTER_TYPE) + continue; + + if (coder == POINTER_TYPE) + { + register tree ttl = TREE_TYPE (memb_type); + register tree ttr = TREE_TYPE (rhstype); + + /* 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. */ + if (TYPE_MAIN_VARIANT (ttl) == void_type_node + || TYPE_MAIN_VARIANT (ttr) == void_type_node + || comp_target_types (memb_type, rhstype)) + { + /* If this type won't generate any warnings, use it. */ + if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr) + || ((TREE_CODE (ttr) == FUNCTION_TYPE + && TREE_CODE (ttl) == FUNCTION_TYPE) + ? ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr)) + == TYPE_QUALS (ttr)) + : ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr)) + == TYPE_QUALS (ttl)))) + break; + + /* Keep looking for a better type, but remember this one. */ + if (! marginal_memb_type) + marginal_memb_type = memb_type; + } + } + + /* Can convert integer zero to any pointer type. */ + if (integer_zerop (rhs) + || (TREE_CODE (rhs) == NOP_EXPR + && integer_zerop (TREE_OPERAND (rhs, 0)))) + { + rhs = null_pointer_node; + break; + } + } + + if (memb_types || marginal_memb_type) + { + if (! memb_types) + { + /* We have only a marginally acceptable member type; + it needs a warning. */ + register tree ttl = TREE_TYPE (marginal_memb_type); + register tree ttr = TREE_TYPE (rhstype); + + /* 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) + { + /* 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_QUALS (ttl) & ~TYPE_QUALS (ttr)) + warn_for_assignment ("%s makes qualified function pointer from unqualified", + errtype, funname, parmnum); + } + else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)) + warn_for_assignment ("%s discards qualifiers from pointer target type", + errtype, funname, + parmnum); + } + + if (pedantic && ! DECL_IN_SYSTEM_HEADER (fundecl)) + pedwarn ("ANSI C prohibits argument conversion to union type"); + + return build1 (NOP_EXPR, type, rhs); + } + } + + /* Conversions among pointers */ + else if (codel == POINTER_TYPE && coder == POINTER_TYPE) + { + register tree ttl = TREE_TYPE (type); + register tree ttr = TREE_TYPE (rhstype); + + /* 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. */ + if (TYPE_MAIN_VARIANT (ttl) == void_type_node + || TYPE_MAIN_VARIANT (ttr) == void_type_node + || comp_target_types (type, rhstype) + || (unsigned_type (TYPE_MAIN_VARIANT (ttl)) + == unsigned_type (TYPE_MAIN_VARIANT (ttr)))) + { + if (pedantic + && ((TYPE_MAIN_VARIANT (ttl) == void_type_node + && TREE_CODE (ttr) == FUNCTION_TYPE) + || + (TYPE_MAIN_VARIANT (ttr) == void_type_node + /* Check TREE_CODE to catch cases like (void *) (char *) 0 + which are not ANSI null ptr constants. */ + && (!integer_zerop (rhs) || TREE_CODE (rhs) == NOP_EXPR) + && TREE_CODE (ttl) == FUNCTION_TYPE))) + warn_for_assignment ("ANSI forbids %s between function pointer and `void *'", + errtype, funname, parmnum); + /* Const and volatile mean something different for function types, + so the usual warnings are not appropriate. */ + else if (TREE_CODE (ttr) != FUNCTION_TYPE + && TREE_CODE (ttl) != FUNCTION_TYPE) + { + if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)) + { + /* Some builtin functions allow const and volatile and do not + discard their meaning. */ + if (!(fundecl + && TREE_CODE (fundecl) == FUNCTION_DECL + && DECL_TARGET_INTRINSIC_P (fundecl))) + warn_for_assignment ("%s discards qualifiers from pointer target type", + errtype, funname, parmnum); + } + /* If this is not a case of ignoring a mismatch in signedness, + no warning. */ + else if (TYPE_MAIN_VARIANT (ttl) == void_type_node + || TYPE_MAIN_VARIANT (ttr) == void_type_node + || comp_target_types (type, rhstype)) + ; + /* If there is a mismatch, do warn. */ + else if (pedantic) + warn_for_assignment ("pointer targets in %s differ in signedness", + errtype, funname, parmnum); + } + else if (TREE_CODE (ttl) == FUNCTION_TYPE + && TREE_CODE (ttr) == FUNCTION_TYPE) + { + /* 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_QUALS (ttl) & ~TYPE_QUALS (ttr)) + warn_for_assignment ("%s makes qualified function pointer from unqualified", + errtype, funname, parmnum); + } + } + else + warn_for_assignment ("%s from incompatible pointer type", + errtype, funname, parmnum); + return convert (type, rhs); + } + else if (codel == POINTER_TYPE && coder == INTEGER_TYPE) + { + /* An explicit constant 0 can convert to a pointer, + or one that results from arithmetic, even including + a cast to integer type. */ + if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs)) + && + ! (TREE_CODE (rhs) == NOP_EXPR + && TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE + && TREE_CODE (TREE_OPERAND (rhs, 0)) == INTEGER_CST + && integer_zerop (TREE_OPERAND (rhs, 0)))) + { + warn_for_assignment ("%s makes pointer from integer without a cast", + errtype, funname, parmnum); + return convert (type, rhs); + } + return null_pointer_node; + } + else if (codel == INTEGER_TYPE && coder == POINTER_TYPE) + { + warn_for_assignment ("%s makes integer from pointer without a cast", + errtype, funname, parmnum); + return convert (type, rhs); + } + + if (!errtype) + { + if (funname) + { + tree selector = maybe_building_objc_message_expr (); + + if (selector && parmnum > 2) + error ("incompatible type for argument %d of `%s'", + parmnum - 2, IDENTIFIER_POINTER (selector)); + else + error ("incompatible type for argument %d of `%s'", + parmnum, IDENTIFIER_POINTER (funname)); + } + else + error ("incompatible type for argument %d of indirect function call", + parmnum); + } + else + error ("incompatible types in %s", errtype); + + return error_mark_node; +} + +/* Print a warning using MSGID. + It gets OPNAME as its one parameter. + If OPNAME is null, it is replaced by "passing arg ARGNUM of `FUNCTION'". + FUNCTION and ARGNUM are handled specially if we are building an + Objective-C selector. */ + +int flag_next_runtime; + +static void +warn_for_assignment (msgid, opname, function, argnum) + const char *msgid; + const char *opname; + tree function; + int argnum; +{ + if (opname == 0) + { + tree selector = maybe_building_objc_message_expr (); + char * new_opname; + + if (selector && argnum > (flag_next_runtime ? 2 : 3)) + { + function = selector; + argnum -= (flag_next_runtime ? 2 : 3); + } + if (function) + { + /* Function name is known; supply it. */ + const char *argstring = _("passing arg %d of `%s'"); + new_opname = (char *) alloca (IDENTIFIER_LENGTH (function) + + strlen (argstring) + 1 + 25 + /*%d*/ + 1); + sprintf (new_opname, argstring, argnum, + IDENTIFIER_POINTER (function)); + } + else + { + /* Function name unknown (call through ptr); just give arg number.*/ + const char *argnofun = _("passing arg %d of pointer to function"); + new_opname = (char *) alloca (strlen (argnofun) + 1 + 25 /*%d*/ + 1); + sprintf (new_opname, argnofun, argnum); + } + opname = new_opname; + } + pedwarn (msgid, opname); +} + +/* Return nonzero if VALUE is a valid constant-valued expression + for use in initializing a static variable; one that can be an + element of a "constant" initializer. + + Return null_pointer_node if the value is absolute; + if it is relocatable, return the variable that determines the relocation. + We assume that VALUE has been folded as much as possible; + therefore, we do not need to check for such things as + arithmetic-combinations of integers. */ + +tree +initializer_constant_valid_p (value, endtype) + tree value; + tree endtype; +{ + switch (TREE_CODE (value)) + { + case CONSTRUCTOR: + if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE) + && TREE_CONSTANT (value) + && CONSTRUCTOR_ELTS (value)) + return + initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)), + endtype); + + return TREE_STATIC (value) ? null_pointer_node : 0; + + case INTEGER_CST: + case REAL_CST: + case STRING_CST: + case COMPLEX_CST: + case VECTOR_CST: + return null_pointer_node; + + case ADDR_EXPR: + return TREE_OPERAND (value, 0); + + case NON_LVALUE_EXPR: + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); + + case CONVERT_EXPR: + case NOP_EXPR: +#ifdef NEXT_SEMANTICS + /* Allow conversions between pointer types. */ + if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); +#endif + /* Allow conversions between pointer types. */ + if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); + + /* Allow conversions between real types. */ + if (TREE_CODE (TREE_TYPE (value)) == REAL_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == REAL_TYPE) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); + + /* Allow length-preserving conversions between integer types. */ + if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE + && (TYPE_PRECISION (TREE_TYPE (value)) + == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); + + /* Allow conversions between other integer types only if + explicit value. */ + if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE) + { + tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + if (inner == null_pointer_node) + return null_pointer_node; + return 0; + } + + /* Allow (int) &foo provided int is as wide as a pointer. */ + if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE + && (TYPE_PRECISION (TREE_TYPE (value)) + >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + + /* Likewise conversions from int to pointers, but also allow + conversions from 0. */ + if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE) + { + if (integer_zerop (TREE_OPERAND (value, 0))) + return null_pointer_node; + else if (TYPE_PRECISION (TREE_TYPE (value)) + <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + } + + /* Allow conversions to union types if the value inside is okay. */ + if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + return 0; + + case PLUS_EXPR: + if (TREE_CODE (endtype) == INTEGER_TYPE + && TYPE_PRECISION (endtype) < POINTER_SIZE) + return 0; + { + tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1), + endtype); + /* If either term is absolute, use the other terms relocation. */ + if (valid0 == null_pointer_node) + return valid1; + if (valid1 == null_pointer_node) + return valid0; + return 0; + } + + case MINUS_EXPR: + if (TREE_CODE (endtype) == INTEGER_TYPE + && TYPE_PRECISION (endtype) < POINTER_SIZE) + return 0; + { + tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1), + endtype); + /* Win if second argument is absolute. */ + if (valid1 == null_pointer_node) + return valid0; + /* Win if both arguments have the same relocation. + Then the value is absolute. */ + if (valid0 == valid1) + return null_pointer_node; + return 0; + } + + default: + return 0; + } +} + +/* If VALUE is a compound expr all of whose expressions are constant, then + return its value. Otherwise, return error_mark_node. + + This is for handling COMPOUND_EXPRs as initializer elements + which is allowed with a warning when -pedantic is specified. */ + +static tree +valid_compound_expr_initializer (value, endtype) + tree value; + tree endtype; +{ + if (TREE_CODE (value) == COMPOUND_EXPR) + { + if (valid_compound_expr_initializer (TREE_OPERAND (value, 0), endtype) + == error_mark_node) + return error_mark_node; + return valid_compound_expr_initializer (TREE_OPERAND (value, 1), + endtype); + } + else if (! TREE_CONSTANT (value) + && ! initializer_constant_valid_p (value, endtype)) + return error_mark_node; + else + return value; +} + +/* Perform appropriate conversions on the initial value of a variable, + store it in the declaration DECL, + and print any error messages that are appropriate. + If the init is invalid, store an ERROR_MARK. */ + +void +store_init_value (decl, init) + tree decl, init; +{ + register tree value, type; + + /* If variable's type was invalidly declared, just ignore it. */ + + type = TREE_TYPE (decl); + if (TREE_CODE (type) == ERROR_MARK) + return; + + /* Digest the specified initializer into an expression. */ + + value = digest_init (type, init, TREE_STATIC (decl), + TREE_STATIC (decl) || pedantic); + + /* Store the expression if valid; else report error. */ + +#if 0 + /* Note that this is the only place we can detect the error + in a case such as struct foo bar = (struct foo) { x, y }; + where there is one initial value which is a constructor expression. */ + if (value == error_mark_node) + ; + else if (TREE_STATIC (decl) && ! TREE_CONSTANT (value)) + { + error ("initializer for static variable is not constant"); + value = error_mark_node; + } + else if (TREE_STATIC (decl) + && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0) + { + error ("initializer for static variable uses complicated arithmetic"); + value = error_mark_node; + } + else + { + if (pedantic && TREE_CODE (value) == CONSTRUCTOR) + { + if (! TREE_CONSTANT (value)) + pedwarn ("aggregate initializer is not constant"); + else if (! TREE_STATIC (value)) + pedwarn ("aggregate initializer uses complicated arithmetic"); + } + } +#endif + + DECL_INITIAL (decl) = value; + + /* ANSI wants warnings about out-of-range constant initializers. */ + STRIP_TYPE_NOPS (value); + constant_expression_warning (value); +} + +/* Methods for storing and printing names for error messages. */ + +/* Implement a spelling stack that allows components of a name to be pushed + and popped. Each element on the stack is this structure. */ + +struct spelling +{ + int kind; + union + { + int i; + const char *s; + } u; +}; + +#define SPELLING_STRING 1 +#define SPELLING_MEMBER 2 +#define SPELLING_BOUNDS 3 + +static struct spelling *spelling; /* Next stack element (unused). */ +static struct spelling *spelling_base; /* Spelling stack base. */ +static int spelling_size; /* Size of the spelling stack. */ + +/* Macros to save and restore the spelling stack around push_... functions. + Alternative to SAVE_SPELLING_STACK. */ + +#define SPELLING_DEPTH() (spelling - spelling_base) +#define RESTORE_SPELLING_DEPTH(depth) (spelling = spelling_base + depth) + +/* Save and restore the spelling stack around arbitrary C code. */ + +#define SAVE_SPELLING_DEPTH(code) \ +{ \ + int __depth = SPELLING_DEPTH (); \ + code; \ + RESTORE_SPELLING_DEPTH (__depth); \ +} + +/* Push an element on the spelling stack with type KIND and assign VALUE + to MEMBER. */ + +#define PUSH_SPELLING(KIND, VALUE, MEMBER) \ +{ \ + int depth = SPELLING_DEPTH (); \ + \ + if (depth >= spelling_size) \ + { \ + spelling_size += 10; \ + if (spelling_base == 0) \ + spelling_base \ + = (struct spelling *) xmalloc (spelling_size * sizeof (struct spelling)); \ + else \ + spelling_base \ + = (struct spelling *) xrealloc (spelling_base, \ + spelling_size * sizeof (struct spelling)); \ + RESTORE_SPELLING_DEPTH (depth); \ + } \ + \ + spelling->kind = (KIND); \ + spelling->MEMBER = (VALUE); \ + spelling++; \ +} + +/* Push STRING on the stack. Printed literally. */ + +static void +push_string (string) + const char *string; +{ + PUSH_SPELLING (SPELLING_STRING, string, u.s); +} + +/* Push a member name on the stack. Printed as '.' STRING. */ + +static void +push_member_name (decl) + tree decl; + +{ + const char *string + = DECL_NAME (decl) ? IDENTIFIER_POINTER (DECL_NAME (decl)) : ""; + PUSH_SPELLING (SPELLING_MEMBER, string, u.s); +} + +/* Push an array bounds on the stack. Printed as [BOUNDS]. */ + +static void +push_array_bounds (bounds) + int bounds; +{ + PUSH_SPELLING (SPELLING_BOUNDS, bounds, u.i); +} + +/* Compute the maximum size in bytes of the printed spelling. */ + +static int +spelling_length () +{ + register int size = 0; + register struct spelling *p; + + for (p = spelling_base; p < spelling; p++) + { + if (p->kind == SPELLING_BOUNDS) + size += 25; + else + size += strlen (p->u.s) + 1; + } + + return size; +} + +/* Print the spelling to BUFFER and return it. */ + +static char * +print_spelling (buffer) + register char *buffer; +{ + register char *d = buffer; + register struct spelling *p; + + for (p = spelling_base; p < spelling; p++) + if (p->kind == SPELLING_BOUNDS) + { + sprintf (d, "[%d]", p->u.i); + d += strlen (d); + } + else + { + register const char *s; + if (p->kind == SPELLING_MEMBER) + *d++ = '.'; + for (s = p->u.s; (*d = *s++); d++) + ; + } + *d++ = '\0'; + return buffer; +} + +/* Issue an error message for a bad initializer component. + MSGID identifies the message. + The component name is taken from the spelling stack. */ + +void +error_init (msgid) + const char *msgid; +{ + char *ofwhat; + + error (msgid); + ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); + if (*ofwhat) + error ("(near initialization for `%s')", ofwhat); +} + +/* Issue a pedantic warning for a bad initializer component. + MSGID identifies the message. + The component name is taken from the spelling stack. */ + +void +pedwarn_init (msgid) + const char *msgid; +{ + char *ofwhat; + + pedwarn (msgid); + ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); + if (*ofwhat) + pedwarn ("(near initialization for `%s')", ofwhat); +} + +/* Issue a warning for a bad initializer component. + MSGID identifies the message. + The component name is taken from the spelling stack. */ + +static void +warning_init (msgid) + const char *msgid; +{ + char *ofwhat; + + warning (msgid); + ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); + if (*ofwhat) + warning ("(near initialization for `%s')", ofwhat); +} + +/* Digest the parser output INIT as an initializer for type TYPE. + Return a C expression of type TYPE to represent the initial value. + + The arguments REQUIRE_CONSTANT and CONSTRUCTOR_CONSTANT request errors + if non-constant initializers or elements are seen. CONSTRUCTOR_CONSTANT + applies only to elements of constructors. */ + +static tree +digest_init (type, init, require_constant, constructor_constant) + tree type, init; + int require_constant, constructor_constant; +{ + enum tree_code code = TREE_CODE (type); + tree inside_init = init; + + if (init == error_mark_node) + return init; + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + /* Do not use STRIP_NOPS here. We do not want an enumerator + whose value is 0 to count as a null pointer constant. */ + if (TREE_CODE (init) == NON_LVALUE_EXPR) + inside_init = TREE_OPERAND (init, 0); + + /* Initialization of an array of chars from a string constant + optionally enclosed in braces. */ + + if (code == ARRAY_TYPE) + { + tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type)); + if ((typ1 == char_type_node + || typ1 == signed_char_type_node + || typ1 == unsigned_char_type_node + || typ1 == unsigned_wchar_type_node + || typ1 == signed_wchar_type_node) + && ((inside_init && TREE_CODE (inside_init) == STRING_CST))) + { + if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), + TYPE_MAIN_VARIANT (type))) + return inside_init; + + if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init))) + != char_type_node) +#ifdef PASCAL_STRINGS + && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init))) + != unsigned_char_type_node) +#endif + && TYPE_PRECISION (typ1) == TYPE_PRECISION (char_type_node)) + { + error_init ("char-array initialized from wide string"); + return error_mark_node; + } + if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init))) + == char_type_node) + && TYPE_PRECISION (typ1) != TYPE_PRECISION (char_type_node)) + { + error_init ("int-array initialized from non-wide string"); + return error_mark_node; + } + + TREE_TYPE (inside_init) = type; + if (TYPE_DOMAIN (type) != 0 + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST) + { + register int size = TREE_INT_CST_LOW (TYPE_SIZE (type)); + size = (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT; + /* Subtract 1 (or sizeof (wchar_t)) + because it's ok to ignore the terminating null char + that is counted in the length of the constant. */ + if (size < TREE_STRING_LENGTH (inside_init) + - (TYPE_PRECISION (typ1) != TYPE_PRECISION (char_type_node) + ? TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT + : 1)) + pedwarn_init ("initializer-string for array of chars is too long"); + } + return inside_init; + } + } + + /* Any type can be initialized + from an expression of the same type, optionally with braces. */ + + if (inside_init && TREE_TYPE (inside_init) != 0 + && (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), + TYPE_MAIN_VARIANT (type)) + || (code == ARRAY_TYPE + && comptypes (TREE_TYPE (inside_init), type)) + || (code == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE) + && comptypes (TREE_TYPE (TREE_TYPE (inside_init)), + TREE_TYPE (type))))) + { + if (code == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE)) + inside_init = default_conversion (inside_init); + else if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST + && TREE_CODE (inside_init) != CONSTRUCTOR) + { + error_init ("array initialized from non-constant array expression"); + return error_mark_node; + } + + if (optimize && TREE_CODE (inside_init) == VAR_DECL) + inside_init = decl_constant_value (inside_init); + + /* Compound expressions can only occur here if -pedantic or + -pedantic-errors is specified. In the later case, we always want + an error. In the former case, we simply want a warning. */ + if (require_constant && pedantic + && TREE_CODE (inside_init) == COMPOUND_EXPR) + { + inside_init + = valid_compound_expr_initializer (inside_init, + TREE_TYPE (inside_init)); + if (inside_init == error_mark_node) + error_init ("initializer element is not constant"); + else + pedwarn_init ("initializer element is not constant"); + if (flag_pedantic_errors) + inside_init = error_mark_node; + } + else if (require_constant && ! TREE_CONSTANT (inside_init)) + { + error_init ("initializer element is not constant"); + inside_init = error_mark_node; + } + else if (require_constant + && initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0) + { + error_init ("initializer element is not computable at load time"); + inside_init = error_mark_node; + } + + return inside_init; + } + + /* Handle scalar types, including conversions. */ + + if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE + || code == ENUMERAL_TYPE || code == COMPLEX_TYPE || code == VECTOR_TYPE) + { + /* Note that convert_for_assignment calls default_conversion + for arrays and functions. We must not call it in the + case where inside_init is a null pointer constant. */ + inside_init + = convert_for_assignment (type, init, _("initialization"), + NULL_TREE, NULL_TREE, 0); + + if (require_constant && ! TREE_CONSTANT (inside_init)) + { + error_init ("initializer element is not constant"); + inside_init = error_mark_node; + } + else if (require_constant + && initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0) + { + error_init ("initializer element is not computable at load time"); + inside_init = error_mark_node; + } + + return inside_init; + } + + /* Come here only for records and arrays. */ + + if (TYPE_SIZE (type) && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + { + error_init ("variable-sized object may not be initialized"); + return error_mark_node; + } + + /* Traditionally, you can write struct foo x = 0; + and it initializes the first element of x to 0. */ + if (flag_traditional) + { + tree top = 0, prev = 0, otype = type; + while (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == ARRAY_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE + || TREE_CODE (type) == UNION_TYPE) + { + tree temp = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE); + if (prev == 0) + top = temp; + else + TREE_OPERAND (prev, 1) = build_tree_list (NULL_TREE, temp); + prev = temp; + if (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + else if (TYPE_FIELDS (type)) + type = TREE_TYPE (TYPE_FIELDS (type)); + else + { + error_init ("invalid initializer"); + return error_mark_node; + } + } + + if (otype != type) + { + TREE_OPERAND (prev, 1) + = build_tree_list (NULL_TREE, + digest_init (type, init, require_constant, + constructor_constant)); + return top; + } + else + return error_mark_node; + } + error_init ("invalid initializer"); + return error_mark_node; +} + +/* Handle initializers that use braces. */ + +/* Type of object we are accumulating a constructor for. + This type is always a RECORD_TYPE, UNION_TYPE or ARRAY_TYPE. */ +static tree constructor_type; + +/* For a RECORD_TYPE or UNION_TYPE, this is the chain of fields + left to fill. */ +static tree constructor_fields; + +/* For an ARRAY_TYPE, this is the specified index + at which to store the next element we get. + This is a special INTEGER_CST node that we modify in place. */ +static tree constructor_index; + +/* For an ARRAY_TYPE, this is the end index of the range + to initialize with the next element, or NULL in the ordinary case + where the element is used just once. */ +static tree constructor_range_end; + +/* For an ARRAY_TYPE, this is the maximum index. */ +static tree constructor_max_index; + +/* For a RECORD_TYPE, this is the first field not yet written out. */ +static tree constructor_unfilled_fields; + +/* For an ARRAY_TYPE, this is the index of the first element + not yet written out. + This is a special INTEGER_CST node that we modify in place. */ +static tree constructor_unfilled_index; + +/* In a RECORD_TYPE, the byte index of the next consecutive field. + This is so we can generate gaps between fields, when appropriate. + This is a special INTEGER_CST node that we modify in place. */ +static tree constructor_bit_index; + +/* If we are saving up the elements rather than allocating them, + this is the list of elements so far (in reverse order, + most recent first). */ +static tree constructor_elements; + +/* 1 if so far this constructor's elements are all compile-time constants. */ +static int constructor_constant; + +/* 1 if so far this constructor's elements are all valid address constants. */ +static int constructor_simple; + +/* 1 if this constructor is erroneous so far. */ +static int constructor_erroneous; + +/* 1 if have called defer_addressed_constants. */ +static int constructor_subconstants_deferred; + +/* Structure for managing pending initializer elements, organized as an + AVL tree. */ + +struct init_node +{ + struct init_node *left, *right; + struct init_node *parent; + int balance; + tree purpose; + tree value; +}; + +/* Tree of pending elements at this constructor level. + These are elements encountered out of order + which belong at places we haven't reached yet in actually + writing the output. */ +static struct init_node *constructor_pending_elts; + +/* The SPELLING_DEPTH of this constructor. */ +static int constructor_depth; + +/* 0 if implicitly pushing constructor levels is allowed. */ +int constructor_no_implicit = 0; /* 0 for C; 1 for some other languages. */ + +static int require_constant_value; +static int require_constant_elements; + +/* 1 if it is ok to output this constructor as we read it. + 0 means must accumulate a CONSTRUCTOR expression. */ +static int constructor_incremental; + +/* DECL node for which an initializer is being read. + 0 means we are reading a constructor expression + such as (struct foo) {...}. */ +static tree constructor_decl; + +/* start_init saves the ASMSPEC arg here for really_start_incremental_init. */ +static char *constructor_asmspec; + +/* Nonzero if this is an initializer for a top-level decl. */ +static int constructor_top_level; + + +/* This stack has a level for each implicit or explicit level of + structuring in the initializer, including the outermost one. It + saves the values of most of the variables above. */ + +struct constructor_stack +{ + struct constructor_stack *next; + tree type; + tree fields; + tree index; + tree range_end; + tree max_index; + tree unfilled_index; + tree unfilled_fields; + tree bit_index; + tree elements; + int offset; + struct init_node *pending_elts; + int depth; + /* If nonzero, this value should replace the entire + constructor at this level. */ + tree replacement_value; + char constant; + char simple; + char implicit; + char incremental; + char erroneous; + char outer; +}; + +struct constructor_stack *constructor_stack; + +/* This stack records separate initializers that are nested. + Nested initializers can't happen in ANSI C, but GNU C allows them + in cases like { ... (struct foo) { ... } ... }. */ + +struct initializer_stack +{ + struct initializer_stack *next; + tree decl; + char *asmspec; + struct constructor_stack *constructor_stack; + tree elements; + struct spelling *spelling; + struct spelling *spelling_base; + int spelling_size; + char top_level; + char incremental; + char require_constant_value; + char require_constant_elements; + char deferred; +}; + +struct initializer_stack *initializer_stack; + +/* Prepare to parse and output the initializer for variable DECL. */ + +void +start_init (decl, asmspec_tree, top_level) + tree decl; + tree asmspec_tree; + int top_level; +{ + const char *locus; + struct initializer_stack *p + = (struct initializer_stack *) xmalloc (sizeof (struct initializer_stack)); + char *asmspec = 0; + + if (asmspec_tree) + asmspec = TREE_STRING_POINTER (asmspec_tree); + + p->decl = constructor_decl; + p->asmspec = constructor_asmspec; + p->incremental = constructor_incremental; + p->require_constant_value = require_constant_value; + p->require_constant_elements = require_constant_elements; + p->constructor_stack = constructor_stack; + p->elements = constructor_elements; + p->spelling = spelling; + p->spelling_base = spelling_base; + p->spelling_size = spelling_size; + p->deferred = constructor_subconstants_deferred; + p->top_level = constructor_top_level; + p->next = initializer_stack; + initializer_stack = p; + + constructor_decl = decl; + constructor_incremental = top_level; + constructor_asmspec = asmspec; + constructor_subconstants_deferred = 0; + constructor_top_level = top_level; + + if (decl != 0) + { + require_constant_value = TREE_STATIC (decl); + require_constant_elements + = ((TREE_STATIC (decl) || pedantic) + /* For a scalar, you can always use any value to initialize, + even within braces. */ + && (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE)); + locus = IDENTIFIER_POINTER (DECL_NAME (decl)); + constructor_incremental |= TREE_STATIC (decl); + } + else + { + require_constant_value = 0; + require_constant_elements = 0; + locus = "(anonymous)"; + } + + constructor_stack = 0; + + missing_braces_mentioned = 0; + + spelling_base = 0; + spelling_size = 0; + RESTORE_SPELLING_DEPTH (0); + + if (locus) + push_string (locus); +} + +void +finish_init () +{ + struct initializer_stack *p = initializer_stack; + + /* Output subconstants (string constants, usually) + that were referenced within this initializer and saved up. + Must do this if and only if we called defer_addressed_constants. */ + if (constructor_subconstants_deferred) + output_deferred_addressed_constants (); + + /* Free the whole constructor stack of this initializer. */ + while (constructor_stack) + { + struct constructor_stack *q = constructor_stack; + constructor_stack = q->next; + free (q); + } + + /* Pop back to the data of the outer initializer (if any). */ + constructor_decl = p->decl; + constructor_asmspec = p->asmspec; + constructor_incremental = p->incremental; + require_constant_value = p->require_constant_value; + require_constant_elements = p->require_constant_elements; + constructor_stack = p->constructor_stack; + constructor_elements = p->elements; + spelling = p->spelling; + spelling_base = p->spelling_base; + spelling_size = p->spelling_size; + constructor_subconstants_deferred = p->deferred; + constructor_top_level = p->top_level; + initializer_stack = p->next; + free (p); +} + +/* Call here when we see the initializer is surrounded by braces. + This is instead of a call to push_init_level; + it is matched by a call to pop_init_level. + + TYPE is the type to initialize, for a constructor expression. + For an initializer for a decl, TYPE is zero. */ + +void +really_start_incremental_init (type) + tree type; +{ + struct constructor_stack *p + = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack)); + + if (type == 0) + type = TREE_TYPE (constructor_decl); + + /* Turn off constructor_incremental if type is a struct with bitfields. + Do this before the first push, so that the corrected value + is available in finish_init. */ + check_init_type_bitfields (type); + + p->type = constructor_type; + p->fields = constructor_fields; + p->index = constructor_index; + p->range_end = constructor_range_end; + p->max_index = constructor_max_index; + p->unfilled_index = constructor_unfilled_index; + p->unfilled_fields = constructor_unfilled_fields; + p->bit_index = constructor_bit_index; + p->elements = constructor_elements; + p->constant = constructor_constant; + p->simple = constructor_simple; + p->erroneous = constructor_erroneous; + p->pending_elts = constructor_pending_elts; + p->depth = constructor_depth; + p->replacement_value = 0; + p->implicit = 0; + p->incremental = constructor_incremental; + p->outer = 0; + p->next = 0; + constructor_stack = p; + + constructor_constant = 1; + constructor_simple = 1; + constructor_depth = SPELLING_DEPTH (); + constructor_elements = 0; + constructor_pending_elts = 0; + constructor_type = type; + + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + constructor_fields = TYPE_FIELDS (constructor_type); + /* Skip any nameless bit fields at the beginning. */ + while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields) + && DECL_NAME (constructor_fields) == 0) + constructor_fields = TREE_CHAIN (constructor_fields); + constructor_unfilled_fields = constructor_fields; + constructor_bit_index = copy_node (integer_zero_node); + TREE_TYPE (constructor_bit_index) = sbitsizetype; + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + constructor_range_end = 0; + if (TYPE_DOMAIN (constructor_type)) + { + constructor_max_index + = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)); + constructor_index + = copy_node (TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); + } + else + constructor_index = copy_node (integer_zero_node); + constructor_unfilled_index = copy_node (constructor_index); + } + else + { + /* Handle the case of int x = {5}; */ + constructor_fields = constructor_type; + constructor_unfilled_fields = constructor_type; + } + + if (constructor_incremental) + { + int momentary = suspend_momentary (); + push_obstacks_nochange (); + if (TREE_PERMANENT (constructor_decl)) + end_temporary_allocation (); + make_decl_rtl (constructor_decl, constructor_asmspec, + constructor_top_level); + assemble_variable (constructor_decl, constructor_top_level, 0, 1); + pop_obstacks (); + resume_momentary (momentary); + } + + if (constructor_incremental) + { + defer_addressed_constants (); + constructor_subconstants_deferred = 1; + } +} + + +/* Push down into a subobject, for initialization. + If this is for an explicit set of braces, IMPLICIT is 0. + If it is because the next element belongs at a lower level, + IMPLICIT is 1. */ + +void +push_init_level (implicit) + int implicit; +{ + struct constructor_stack *p; + + /* If we've exhausted any levels that didn't have braces, + pop them now. */ + while (constructor_stack->implicit) + { + if ((TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + && constructor_fields == 0) + process_init_element (pop_init_level (1)); + else if (TREE_CODE (constructor_type) == ARRAY_TYPE + && tree_int_cst_lt (constructor_max_index, constructor_index)) + process_init_element (pop_init_level (1)); + else + break; + } + + /* Structure elements may require alignment. Do this now if necessary + for the subaggregate, and if it comes next in sequence. Don't do + this for subaggregates that will go on the pending list. */ + if (constructor_incremental && constructor_type != 0 + && TREE_CODE (constructor_type) == RECORD_TYPE && constructor_fields + && constructor_fields == constructor_unfilled_fields) + { + /* Advance to offset of this element. */ + if (! tree_int_cst_equal (constructor_bit_index, + DECL_FIELD_BITPOS (constructor_fields))) + { + /* By using unsigned arithmetic, the result will be correct even + in case of overflows, if BITS_PER_UNIT is a power of two. */ + unsigned next = (TREE_INT_CST_LOW + (DECL_FIELD_BITPOS (constructor_fields)) + / (unsigned)BITS_PER_UNIT); + unsigned here = (TREE_INT_CST_LOW (constructor_bit_index) + / (unsigned)BITS_PER_UNIT); + + assemble_zeros ((next - here) + * (unsigned)BITS_PER_UNIT + / (unsigned)BITS_PER_UNIT); + } + /* Indicate that we have now filled the structure up to the current + field. */ + constructor_unfilled_fields = constructor_fields; + } + + p = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack)); + p->type = constructor_type; + p->fields = constructor_fields; + p->index = constructor_index; + p->range_end = constructor_range_end; + p->max_index = constructor_max_index; + p->unfilled_index = constructor_unfilled_index; + p->unfilled_fields = constructor_unfilled_fields; + p->bit_index = constructor_bit_index; + p->elements = constructor_elements; + p->constant = constructor_constant; + p->simple = constructor_simple; + p->erroneous = constructor_erroneous; + p->pending_elts = constructor_pending_elts; + p->depth = constructor_depth; + p->replacement_value = 0; + p->implicit = implicit; + p->incremental = constructor_incremental; + p->outer = 0; + p->next = constructor_stack; + constructor_stack = p; + + constructor_constant = 1; + constructor_simple = 1; + constructor_depth = SPELLING_DEPTH (); + constructor_elements = 0; + constructor_pending_elts = 0; + + /* Don't die if an entire brace-pair level is superfluous + in the containing level. */ + if (constructor_type == 0) + ; + else if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + /* Don't die if there are extra init elts at the end. */ + if (constructor_fields == 0) + constructor_type = 0; + else + { + constructor_type = TREE_TYPE (constructor_fields); + push_member_name (constructor_fields); + constructor_depth++; + if (constructor_fields != constructor_unfilled_fields) + constructor_incremental = 0; + } + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + constructor_type = TREE_TYPE (constructor_type); + push_array_bounds (TREE_INT_CST_LOW (constructor_index)); + constructor_depth++; + if (! tree_int_cst_equal (constructor_index, constructor_unfilled_index) + || constructor_range_end != 0) + constructor_incremental = 0; + } + + if (constructor_type == 0) + { + error_init ("extra brace group at end of initializer"); + constructor_fields = 0; + constructor_unfilled_fields = 0; + return; + } + + /* Turn off constructor_incremental if type is a struct with bitfields. */ + check_init_type_bitfields (constructor_type); + + if (implicit && warn_missing_braces && !missing_braces_mentioned) + { + missing_braces_mentioned = 1; + warning_init ("missing braces around initializer"); + } + + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + constructor_fields = TYPE_FIELDS (constructor_type); + /* Skip any nameless bit fields at the beginning. */ + while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields) + && DECL_NAME (constructor_fields) == 0) + constructor_fields = TREE_CHAIN (constructor_fields); + constructor_unfilled_fields = constructor_fields; + constructor_bit_index = copy_node (integer_zero_node); + TREE_TYPE (constructor_bit_index) = sbitsizetype; + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + constructor_range_end = 0; + if (TYPE_DOMAIN (constructor_type)) + { + constructor_max_index + = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)); + constructor_index + = copy_node (TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); + } + else + constructor_index = copy_node (integer_zero_node); + constructor_unfilled_index = copy_node (constructor_index); + } + else + { + warning_init ("braces around scalar initializer"); + constructor_fields = constructor_type; + constructor_unfilled_fields = constructor_type; + } +} + +/* Don't read a struct incrementally if it has any bitfields, + because the incremental reading code doesn't know how to + handle bitfields yet. */ + +static void +check_init_type_bitfields (type) + tree type; +{ + if (TREE_CODE (type) == RECORD_TYPE) + { + tree tail; + for (tail = TYPE_FIELDS (type); tail; + tail = TREE_CHAIN (tail)) + { + if (DECL_C_BIT_FIELD (tail)) + { + constructor_incremental = 0; + break; + } + + check_init_type_bitfields (TREE_TYPE (tail)); + } + } + + else if (TREE_CODE (type) == UNION_TYPE) + { + tree tail = TYPE_FIELDS (type); + if (tail && DECL_C_BIT_FIELD (tail)) + /* We also use the nonincremental algorithm for initiliazation + of unions whose first member is a bitfield, becuase the + incremental algorithm has no code for dealing with + bitfields. */ + constructor_incremental = 0; + } + + else if (TREE_CODE (type) == ARRAY_TYPE) + check_init_type_bitfields (TREE_TYPE (type)); +} + +/* At the end of an implicit or explicit brace level, + finish up that level of constructor. + If we were outputting the elements as they are read, return 0 + from inner levels (process_init_element ignores that), + but return error_mark_node from the outermost level + (that's what we want to put in DECL_INITIAL). + Otherwise, return a CONSTRUCTOR expression. */ + +tree +pop_init_level (implicit) + int implicit; +{ + struct constructor_stack *p; + int size = 0; + tree constructor = 0; + + if (implicit == 0) + { + /* When we come to an explicit close brace, + pop any inner levels that didn't have explicit braces. */ + while (constructor_stack->implicit) + process_init_element (pop_init_level (1)); + } + + p = constructor_stack; + + if (constructor_type != 0) + size = int_size_in_bytes (constructor_type); + + /* Warn when some struct elements are implicitly initialized to zero. */ + if (extra_warnings + && constructor_type + && TREE_CODE (constructor_type) == RECORD_TYPE + && constructor_unfilled_fields) + { + push_member_name (constructor_unfilled_fields); + warning_init ("missing initializer"); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + + /* Now output all pending elements. */ + output_pending_init_elements (1); + +#if 0 /* c-parse.in warns about {}. */ + /* In ANSI, each brace level must have at least one element. */ + if (! implicit && pedantic + && (TREE_CODE (constructor_type) == ARRAY_TYPE + ? integer_zerop (constructor_unfilled_index) + : constructor_unfilled_fields == TYPE_FIELDS (constructor_type))) + pedwarn_init ("empty braces in initializer"); +#endif + + /* Pad out the end of the structure. */ + + if (p->replacement_value) + { + /* If this closes a superfluous brace pair, + just pass out the element between them. */ + constructor = p->replacement_value; + /* If this is the top level thing within the initializer, + and it's for a variable, then since we already called + assemble_variable, we must output the value now. */ + if (p->next == 0 && constructor_decl != 0 + && constructor_incremental) + { + constructor = digest_init (constructor_type, constructor, + require_constant_value, + require_constant_elements); + + /* If initializing an array of unknown size, + determine the size now. */ + if (TREE_CODE (constructor_type) == ARRAY_TYPE + && TYPE_DOMAIN (constructor_type) == 0) + { + int failure; + int momentary_p; + + push_obstacks_nochange (); + if (TREE_PERMANENT (constructor_type)) + end_temporary_allocation (); + + momentary_p = suspend_momentary (); + + /* We shouldn't have an incomplete array type within + some other type. */ + if (constructor_stack->next) + abort (); + + failure + = complete_array_type (constructor_type, + constructor, 0); + if (failure) + abort (); + + size = int_size_in_bytes (constructor_type); + resume_momentary (momentary_p); + pop_obstacks (); + } + + output_constant (constructor, size); + } + } + else if (constructor_type == 0) + ; + else if (TREE_CODE (constructor_type) != RECORD_TYPE + && TREE_CODE (constructor_type) != UNION_TYPE + && TREE_CODE (constructor_type) != ARRAY_TYPE + && ! constructor_incremental) + { + /* A nonincremental scalar initializer--just return + the element, after verifying there is just one. */ + if (constructor_elements == 0) + { + error_init ("empty scalar initializer"); + constructor = error_mark_node; + } + else if (TREE_CHAIN (constructor_elements) != 0) + { + error_init ("extra elements in scalar initializer"); + constructor = TREE_VALUE (constructor_elements); + } + else + constructor = TREE_VALUE (constructor_elements); + } + else if (! constructor_incremental) + { + if (constructor_erroneous) + constructor = error_mark_node; + else + { + int momentary = suspend_momentary (); + + constructor = build (CONSTRUCTOR, constructor_type, NULL_TREE, + nreverse (constructor_elements)); + if (constructor_constant) + TREE_CONSTANT (constructor) = 1; + if (constructor_constant && constructor_simple) + TREE_STATIC (constructor) = 1; + + resume_momentary (momentary); + } + } + else + { + tree filled; + int momentary = suspend_momentary (); + + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + /* Find the offset of the end of that field. */ + filled = size_binop (CEIL_DIV_EXPR, + constructor_bit_index, + size_int (BITS_PER_UNIT)); + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + /* If initializing an array of unknown size, + determine the size now. */ + if (TREE_CODE (constructor_type) == ARRAY_TYPE + && TYPE_DOMAIN (constructor_type) == 0) + { + tree maxindex + = size_binop (MINUS_EXPR, + constructor_unfilled_index, + integer_one_node); + + push_obstacks_nochange (); + if (TREE_PERMANENT (constructor_type)) + end_temporary_allocation (); + maxindex = copy_node (maxindex); + TYPE_DOMAIN (constructor_type) = build_index_type (maxindex); + TREE_TYPE (maxindex) = TYPE_DOMAIN (constructor_type); + + /* TYPE_MAX_VALUE is always one less than the number of elements + in the array, because we start counting at zero. Therefore, + warn only if the value is less than zero. */ + if (pedantic + && (tree_int_cst_sgn (TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type))) + < 0)) + error_with_decl (constructor_decl, + "zero or negative array size `%s'"); + layout_type (constructor_type); + size = int_size_in_bytes (constructor_type); + pop_obstacks (); + } + + filled = size_binop (MULT_EXPR, constructor_unfilled_index, + size_in_bytes (TREE_TYPE (constructor_type))); + } + else + filled = 0; + + if (filled != 0) + assemble_zeros (size - TREE_INT_CST_LOW (filled)); + + resume_momentary (momentary); + } + + + constructor_type = p->type; + constructor_fields = p->fields; + constructor_index = p->index; + constructor_range_end = p->range_end; + constructor_max_index = p->max_index; + constructor_unfilled_index = p->unfilled_index; + constructor_unfilled_fields = p->unfilled_fields; + constructor_bit_index = p->bit_index; + constructor_elements = p->elements; + constructor_constant = p->constant; + constructor_simple = p->simple; + constructor_erroneous = p->erroneous; + constructor_pending_elts = p->pending_elts; + constructor_depth = p->depth; + constructor_incremental = p->incremental; + RESTORE_SPELLING_DEPTH (constructor_depth); + + constructor_stack = p->next; + free (p); + + if (constructor == 0) + { + if (constructor_stack == 0) + return error_mark_node; + return NULL_TREE; + } + return constructor; +} + +/* Within an array initializer, specify the next index to be initialized. + FIRST is that index. If LAST is nonzero, then initialize a range + of indices, running from FIRST through LAST. */ + +void +set_init_index (first, last) + tree first, last; +{ + while ((TREE_CODE (first) == NOP_EXPR + || TREE_CODE (first) == CONVERT_EXPR + || TREE_CODE (first) == NON_LVALUE_EXPR) + && (TYPE_MODE (TREE_TYPE (first)) + == TYPE_MODE (TREE_TYPE (TREE_OPERAND (first, 0))))) + (first) = TREE_OPERAND (first, 0); + if (last) + while ((TREE_CODE (last) == NOP_EXPR + || TREE_CODE (last) == CONVERT_EXPR + || TREE_CODE (last) == NON_LVALUE_EXPR) + && (TYPE_MODE (TREE_TYPE (last)) + == TYPE_MODE (TREE_TYPE (TREE_OPERAND (last, 0))))) + (last) = TREE_OPERAND (last, 0); + + if (TREE_CODE (first) != INTEGER_CST) + error_init ("nonconstant array index in initializer"); + else if (last != 0 && TREE_CODE (last) != INTEGER_CST) + error_init ("nonconstant array index in initializer"); + else if (! constructor_unfilled_index) + error_init ("array index in non-array initializer"); + else if (tree_int_cst_lt (first, constructor_unfilled_index)) + error_init ("duplicate array index in initializer"); + else + { + TREE_INT_CST_LOW (constructor_index) = TREE_INT_CST_LOW (first); + TREE_INT_CST_HIGH (constructor_index) = TREE_INT_CST_HIGH (first); + + if (last != 0 && tree_int_cst_lt (last, first)) + error_init ("empty index range in initializer"); + else + { + if (pedantic) + pedwarn ("ANSI C forbids specifying element to initialize"); + constructor_range_end = last; + } + } +} + +/* Within a struct initializer, specify the next field to be initialized. */ + +void +set_init_label (fieldname) + tree fieldname; +{ + tree tail; + int passed = 0; + + /* Don't die if an entire brace-pair level is superfluous + in the containing level. */ + if (constructor_type == 0) + return; + + for (tail = TYPE_FIELDS (constructor_type); tail; + tail = TREE_CHAIN (tail)) + { + if (tail == constructor_unfilled_fields) + passed = 1; + if (DECL_NAME (tail) == fieldname) + break; + } + + if (tail == 0) + error ("unknown field `%s' specified in initializer", + IDENTIFIER_POINTER (fieldname)); + else if (!passed) + error ("field `%s' already initialized", + IDENTIFIER_POINTER (fieldname)); + else + { + constructor_fields = tail; + if (pedantic) + pedwarn ("ANSI C forbids specifying structure member to initialize"); + } +} + +/* Add a new initializer to the tree of pending initializers. PURPOSE + indentifies the initializer, either array index or field in a structure. + VALUE is the value of that index or field. */ + +static void +add_pending_init (purpose, value) + tree purpose, value; +{ + struct init_node *p, **q, *r; + + q = &constructor_pending_elts; + p = 0; + + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + while (*q != 0) + { + p = *q; + if (tree_int_cst_lt (purpose, p->purpose)) + q = &p->left; + else if (tree_int_cst_lt (p->purpose, purpose)) + q = &p->right; + else + abort (); + } + } + else + { + while (*q != NULL) + { + p = *q; + if (tree_int_cst_lt (DECL_FIELD_BITPOS (purpose), + DECL_FIELD_BITPOS (p->purpose))) + q = &p->left; + else if (tree_int_cst_lt (DECL_FIELD_BITPOS (p->purpose), + DECL_FIELD_BITPOS (purpose))) + q = &p->right; + else + abort (); + } + } + + r = (struct init_node *) oballoc (sizeof (struct init_node)); + r->purpose = purpose; + r->value = value; + + *q = r; + r->parent = p; + r->left = 0; + r->right = 0; + r->balance = 0; + + while (p) + { + struct init_node *s; + + if (r == p->left) + { + if (p->balance == 0) + p->balance = -1; + else if (p->balance < 0) + { + if (r->balance < 0) + { + /* L rotation. */ + p->left = r->right; + if (p->left) + p->left->parent = p; + r->right = p; + + p->balance = 0; + r->balance = 0; + + s = p->parent; + p->parent = r; + r->parent = s; + if (s) + { + if (s->left == p) + s->left = r; + else + s->right = r; + } + else + constructor_pending_elts = r; + } + else + { + /* LR rotation. */ + struct init_node *t = r->right; + + r->right = t->left; + if (r->right) + r->right->parent = r; + t->left = r; + + p->left = t->right; + if (p->left) + p->left->parent = p; + t->right = p; + + p->balance = t->balance < 0; + r->balance = -(t->balance > 0); + t->balance = 0; + + s = p->parent; + p->parent = t; + r->parent = t; + t->parent = s; + if (s) + { + if (s->left == p) + s->left = t; + else + s->right = t; + } + else + constructor_pending_elts = t; + } + break; + } + else + { + /* p->balance == +1; growth of left side balances the node. */ + p->balance = 0; + break; + } + } + else /* r == p->right */ + { + if (p->balance == 0) + /* Growth propagation from right side. */ + p->balance++; + else if (p->balance > 0) + { + if (r->balance > 0) + { + /* R rotation. */ + p->right = r->left; + if (p->right) + p->right->parent = p; + r->left = p; + + p->balance = 0; + r->balance = 0; + + s = p->parent; + p->parent = r; + r->parent = s; + if (s) + { + if (s->left == p) + s->left = r; + else + s->right = r; + } + else + constructor_pending_elts = r; + } + else /* r->balance == -1 */ + { + /* RL rotation */ + struct init_node *t = r->left; + + r->left = t->right; + if (r->left) + r->left->parent = r; + t->right = r; + + p->right = t->left; + if (p->right) + p->right->parent = p; + t->left = p; + + r->balance = (t->balance < 0); + p->balance = -(t->balance > 0); + t->balance = 0; + + s = p->parent; + p->parent = t; + r->parent = t; + t->parent = s; + if (s) + { + if (s->left == p) + s->left = t; + else + s->right = t; + } + else + constructor_pending_elts = t; + } + break; + } + else + { + /* p->balance == -1; growth of right side balances the node. */ + p->balance = 0; + break; + } + } + + r = p; + p = p->parent; + } +} + +/* Return nonzero if FIELD is equal to the index of a pending initializer. */ + +static int +pending_init_member (field) + tree field; +{ + struct init_node *p; + + p = constructor_pending_elts; + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + while (p) + { + if (tree_int_cst_equal (field, p->purpose)) + return 1; + else if (tree_int_cst_lt (field, p->purpose)) + p = p->left; + else + p = p->right; + } + } + else + { + while (p) + { + if (field == p->purpose) + return 1; + else if (tree_int_cst_lt (DECL_FIELD_BITPOS (field), + DECL_FIELD_BITPOS (p->purpose))) + p = p->left; + else + p = p->right; + } + } + + return 0; +} + +/* "Output" the next constructor element. + At top level, really output it to assembler code now. + Otherwise, collect it in a list from which we will make a CONSTRUCTOR. + TYPE is the data type that the containing data type wants here. + FIELD is the field (a FIELD_DECL) or the index that this element fills. + + PENDING if non-nil means output pending elements that belong + right after this element. (PENDING is normally 1; + it is 0 while outputting pending elements, to avoid recursion.) */ + +static void +output_init_element (value, type, field, pending) + tree value, type, field; + int pending; +{ + int duplicate = 0; + + if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE + || (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE + && !(TREE_CODE (value) == STRING_CST + && TREE_CODE (type) == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE) + && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)), + TYPE_MAIN_VARIANT (type)))) + value = default_conversion (value); + + if (value == error_mark_node) + constructor_erroneous = 1; + else if (!TREE_CONSTANT (value)) + constructor_constant = 0; + else if (initializer_constant_valid_p (value, TREE_TYPE (value)) == 0 + || ((TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + && DECL_C_BIT_FIELD (field) + && TREE_CODE (value) != INTEGER_CST)) + constructor_simple = 0; + + if (require_constant_value && ! TREE_CONSTANT (value)) + { + error_init ("initializer element is not constant"); + value = error_mark_node; + } + else if (require_constant_elements + && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0) + { + error_init ("initializer element is not computable at load time"); + value = error_mark_node; + } + + /* If this element duplicates one on constructor_pending_elts, + print a message and ignore it. Don't do this when we're + processing elements taken off constructor_pending_elts, + because we'd always get spurious errors. */ + if (pending) + { + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE + || TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (pending_init_member (field)) + { + error_init ("duplicate initializer"); + duplicate = 1; + } + } + } + + /* If this element doesn't come next in sequence, + put it on constructor_pending_elts. */ + if (TREE_CODE (constructor_type) == ARRAY_TYPE + && !tree_int_cst_equal (field, constructor_unfilled_index)) + { + if (! duplicate) + /* The copy_node is needed in case field is actually + constructor_index, which is modified in place. */ + add_pending_init (copy_node (field), + digest_init (type, value, require_constant_value, + require_constant_elements)); + } + else if (TREE_CODE (constructor_type) == RECORD_TYPE + && field != constructor_unfilled_fields) + { + /* We do this for records but not for unions. In a union, + no matter which field is specified, it can be initialized + right away since it starts at the beginning of the union. */ + if (!duplicate) + add_pending_init (field, + digest_init (type, value, require_constant_value, + require_constant_elements)); + } + else + { + /* Otherwise, output this element either to + constructor_elements or to the assembler file. */ + + if (!duplicate) + { + if (! constructor_incremental) + { + if (field && TREE_CODE (field) == INTEGER_CST) + field = copy_node (field); + constructor_elements + = tree_cons (field, digest_init (type, value, + require_constant_value, + require_constant_elements), + constructor_elements); + } + else + { + /* Structure elements may require alignment. + Do this, if necessary. */ + if (TREE_CODE (constructor_type) == RECORD_TYPE) + { + /* Advance to offset of this element. */ + if (! tree_int_cst_equal (constructor_bit_index, + DECL_FIELD_BITPOS (field))) + { + /* By using unsigned arithmetic, the result will be + correct even in case of overflows, if BITS_PER_UNIT + is a power of two. */ + unsigned next = (TREE_INT_CST_LOW + (DECL_FIELD_BITPOS (field)) + / (unsigned)BITS_PER_UNIT); + unsigned here = (TREE_INT_CST_LOW + (constructor_bit_index) + / (unsigned)BITS_PER_UNIT); + + assemble_zeros ((next - here) + * (unsigned)BITS_PER_UNIT + / (unsigned)BITS_PER_UNIT); + } + } + output_constant (digest_init (type, value, + require_constant_value, + require_constant_elements), + int_size_in_bytes (type)); + + /* For a record or union, + keep track of end position of last field. */ + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + tree temp = size_binop (PLUS_EXPR, DECL_FIELD_BITPOS (field), + DECL_SIZE (field)); + TREE_INT_CST_LOW (constructor_bit_index) + = TREE_INT_CST_LOW (temp); + TREE_INT_CST_HIGH (constructor_bit_index) + = TREE_INT_CST_HIGH (temp); + } + } + } + + /* Advance the variable that indicates sequential elements output. */ + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + tree tem = size_binop (PLUS_EXPR, constructor_unfilled_index, + integer_one_node); + TREE_INT_CST_LOW (constructor_unfilled_index) + = TREE_INT_CST_LOW (tem); + TREE_INT_CST_HIGH (constructor_unfilled_index) + = TREE_INT_CST_HIGH (tem); + } + else if (TREE_CODE (constructor_type) == RECORD_TYPE) + constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields); + else if (TREE_CODE (constructor_type) == UNION_TYPE) + constructor_unfilled_fields = 0; + + /* Now output any pending elements which have become next. */ + if (pending) + output_pending_init_elements (0); + } +} + +/* Output any pending elements which have become next. + As we output elements, constructor_unfilled_{fields,index} + advances, which may cause other elements to become next; + if so, they too are output. + + If ALL is 0, we return when there are + no more pending elements to output now. + + If ALL is 1, we output space as necessary so that + we can output all the pending elements. */ + +static void +output_pending_init_elements (all) + int all; +{ + struct init_node *elt = constructor_pending_elts; + tree next; + + retry: + + /* Look thru the whole pending tree. + If we find an element that should be output now, + output it. Otherwise, set NEXT to the element + that comes first among those still pending. */ + + next = 0; + while (elt) + { + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (tree_int_cst_equal (elt->purpose, + constructor_unfilled_index)) + output_init_element (elt->value, + TREE_TYPE (constructor_type), + constructor_unfilled_index, 0); + else if (tree_int_cst_lt (constructor_unfilled_index, + elt->purpose)) + { + /* Advance to the next smaller node. */ + if (elt->left) + elt = elt->left; + else + { + /* We have reached the smallest node bigger than the + current unfilled index. Fill the space first. */ + next = elt->purpose; + break; + } + } + else + { + /* Advance to the next bigger node. */ + if (elt->right) + elt = elt->right; + else + { + /* We have reached the biggest node in a subtree. Find + the parent of it, which is the next bigger node. */ + while (elt->parent && elt->parent->right == elt) + elt = elt->parent; + elt = elt->parent; + if (elt && tree_int_cst_lt (constructor_unfilled_index, + elt->purpose)) + { + next = elt->purpose; + break; + } + } + } + } + else if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + /* If the current record is complete we are done. */ + if (constructor_unfilled_fields == 0) + break; + if (elt->purpose == constructor_unfilled_fields) + { + output_init_element (elt->value, + TREE_TYPE (constructor_unfilled_fields), + constructor_unfilled_fields, + 0); + } + else if (tree_int_cst_lt (DECL_FIELD_BITPOS (constructor_unfilled_fields), + DECL_FIELD_BITPOS (elt->purpose))) + { + /* Advance to the next smaller node. */ + if (elt->left) + elt = elt->left; + else + { + /* We have reached the smallest node bigger than the + current unfilled field. Fill the space first. */ + next = elt->purpose; + break; + } + } + else + { + /* Advance to the next bigger node. */ + if (elt->right) + elt = elt->right; + else + { + /* We have reached the biggest node in a subtree. Find + the parent of it, which is the next bigger node. */ + while (elt->parent && elt->parent->right == elt) + elt = elt->parent; + elt = elt->parent; + if (elt + && tree_int_cst_lt (DECL_FIELD_BITPOS (constructor_unfilled_fields), + DECL_FIELD_BITPOS (elt->purpose))) + { + next = elt->purpose; + break; + } + } + } + } + } + + /* Ordinarily return, but not if we want to output all + and there are elements left. */ + if (! (all && next != 0)) + return; + + /* Generate space up to the position of NEXT. */ + if (constructor_incremental) + { + tree filled; + tree nextpos_tree = size_int (0); + + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + tree tail; + /* Find the last field written out, if any. */ + for (tail = TYPE_FIELDS (constructor_type); tail; + tail = TREE_CHAIN (tail)) + if (TREE_CHAIN (tail) == constructor_unfilled_fields) + break; + + if (tail) + /* Find the offset of the end of that field. */ + filled = size_binop (CEIL_DIV_EXPR, + size_binop (PLUS_EXPR, + DECL_FIELD_BITPOS (tail), + DECL_SIZE (tail)), + size_int (BITS_PER_UNIT)); + else + filled = size_int (0); + + nextpos_tree = size_binop (CEIL_DIV_EXPR, + DECL_FIELD_BITPOS (next), + size_int (BITS_PER_UNIT)); + + TREE_INT_CST_HIGH (constructor_bit_index) + = TREE_INT_CST_HIGH (DECL_FIELD_BITPOS (next)); + TREE_INT_CST_LOW (constructor_bit_index) + = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (next)); + constructor_unfilled_fields = next; + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + filled = size_binop (MULT_EXPR, constructor_unfilled_index, + size_in_bytes (TREE_TYPE (constructor_type))); + nextpos_tree + = size_binop (MULT_EXPR, next, + size_in_bytes (TREE_TYPE (constructor_type))); + TREE_INT_CST_LOW (constructor_unfilled_index) + = TREE_INT_CST_LOW (next); + TREE_INT_CST_HIGH (constructor_unfilled_index) + = TREE_INT_CST_HIGH (next); + } + else + filled = 0; + + if (filled) + { + int nextpos = TREE_INT_CST_LOW (nextpos_tree); + + assemble_zeros (nextpos - TREE_INT_CST_LOW (filled)); + } + } + else + { + /* If it's not incremental, just skip over the gap, + so that after jumping to retry we will output the next + successive element. */ + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + constructor_unfilled_fields = next; + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + TREE_INT_CST_LOW (constructor_unfilled_index) + = TREE_INT_CST_LOW (next); + TREE_INT_CST_HIGH (constructor_unfilled_index) + = TREE_INT_CST_HIGH (next); + } + } + + /* ELT now points to the node in the pending tree with the next + initializer to output. */ + goto retry; +} + +/* Add one non-braced element to the current constructor level. + This adjusts the current position within the constructor's type. + This may also start or terminate implicit levels + to handle a partly-braced initializer. + + Once this has found the correct level for the new element, + it calls output_init_element. + + Note: if we are incrementally outputting this constructor, + this function may be called with a null argument + representing a sub-constructor that was already incrementally output. + When that happens, we output nothing, but we do the bookkeeping + to skip past that element of the current constructor. */ + +void +process_init_element (value) + tree value; +{ + extern int errorcount; + tree orig_value = value; + int string_flag = value != 0 && TREE_CODE (value) == STRING_CST; + + /* Handle superfluous braces around string cst as in + char x[] = {"foo"}; */ + if (string_flag + && constructor_type + && TREE_CODE (constructor_type) == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (constructor_type)) == INTEGER_TYPE + && integer_zerop (constructor_unfilled_index)) + { + constructor_stack->replacement_value = value; + return; + } + + if (constructor_stack->replacement_value != 0) + { + error_init ("excess elements in struct initializer"); + return; + } + + /* Sometimes an error-mark will cause an infinite loop */ + if (value && TREE_CODE (value) == ERROR_MARK && errorcount) + { + fatal ("too many errors, bailing out"); + } + + /* Ignore elements of a brace group if it is entirely superfluous + and has already been diagnosed. */ + if (constructor_type == 0) + return; + + /* If we've exhausted any levels that didn't have braces, + pop them now. */ + while (constructor_stack->implicit) + { + if ((TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + && constructor_fields == 0) + process_init_element (pop_init_level (1)); + else if (TREE_CODE (constructor_type) == ARRAY_TYPE + && (constructor_max_index == 0 + || tree_int_cst_lt (constructor_max_index, + constructor_index))) + process_init_element (pop_init_level (1)); + else + break; + } + + while (1) + { + if (TREE_CODE (constructor_type) == RECORD_TYPE) + { + tree fieldtype; + enum tree_code fieldcode; + + if (constructor_fields == 0) + { + pedwarn_init ("excess elements in struct initializer"); + break; + } + + fieldtype = TREE_TYPE (constructor_fields); + if (fieldtype != error_mark_node) + fieldtype = TYPE_MAIN_VARIANT (fieldtype); + fieldcode = TREE_CODE (fieldtype); + + /* Accept a string constant to initialize a subarray. */ + if (value != 0 + && fieldcode == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (fieldtype)) == INTEGER_TYPE + && string_flag) + value = orig_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)) + { + push_init_level (1); + continue; + } + + if (value) + { + push_member_name (constructor_fields); + output_init_element (value, fieldtype, constructor_fields, 1); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + else + /* Do the bookkeeping for an element that was + directly output as a constructor. */ + { + /* For a record, keep track of end position of last field. */ + tree temp = size_binop (PLUS_EXPR, + DECL_FIELD_BITPOS (constructor_fields), + DECL_SIZE (constructor_fields)); + TREE_INT_CST_LOW (constructor_bit_index) + = TREE_INT_CST_LOW (temp); + TREE_INT_CST_HIGH (constructor_bit_index) + = TREE_INT_CST_HIGH (temp); + + constructor_unfilled_fields = TREE_CHAIN (constructor_fields); + } + + constructor_fields = TREE_CHAIN (constructor_fields); + /* Skip any nameless bit fields at the beginning. */ + while (constructor_fields != 0 + && DECL_C_BIT_FIELD (constructor_fields) + && DECL_NAME (constructor_fields) == 0) + constructor_fields = TREE_CHAIN (constructor_fields); + break; + } + if (TREE_CODE (constructor_type) == UNION_TYPE) + { + tree fieldtype; + enum tree_code fieldcode; + + if (constructor_fields == 0) + { + pedwarn_init ("excess elements in union initializer"); + break; + } + + fieldtype = TREE_TYPE (constructor_fields); + if (fieldtype != error_mark_node) + fieldtype = TYPE_MAIN_VARIANT (fieldtype); + fieldcode = TREE_CODE (fieldtype); + + /* Accept a string constant to initialize a subarray. */ + if (value != 0 + && fieldcode == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (fieldtype)) == INTEGER_TYPE + && string_flag) + value = orig_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)) + { + push_init_level (1); + continue; + } + + if (value) + { + push_member_name (constructor_fields); + output_init_element (value, fieldtype, constructor_fields, 1); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + else + /* Do the bookkeeping for an element that was + directly output as a constructor. */ + { + TREE_INT_CST_LOW (constructor_bit_index) + = TREE_INT_CST_LOW (DECL_SIZE (constructor_fields)); + TREE_INT_CST_HIGH (constructor_bit_index) + = TREE_INT_CST_HIGH (DECL_SIZE (constructor_fields)); + + constructor_unfilled_fields = TREE_CHAIN (constructor_fields); + } + + constructor_fields = 0; + break; + } + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type)); + enum tree_code eltcode = TREE_CODE (elttype); + + /* Accept a string constant to initialize a subarray. */ + if (value != 0 + && eltcode == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (elttype)) == INTEGER_TYPE + && string_flag) + value = orig_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)) + { + push_init_level (1); + continue; + } + + if (constructor_max_index != 0 + && tree_int_cst_lt (constructor_max_index, constructor_index)) + { + pedwarn_init ("excess elements in array initializer"); + break; + } + + /* In the case of [LO .. HI] = VALUE, only evaluate VALUE once. */ + if (constructor_range_end) + { + if (constructor_max_index != 0 + && tree_int_cst_lt (constructor_max_index, + constructor_range_end)) + { + pedwarn_init ("excess elements in array initializer"); + TREE_INT_CST_HIGH (constructor_range_end) + = TREE_INT_CST_HIGH (constructor_max_index); + TREE_INT_CST_LOW (constructor_range_end) + = TREE_INT_CST_LOW (constructor_max_index); + } + + 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. */ + do + { + tree tem; + + if (value) + { + push_array_bounds (TREE_INT_CST_LOW (constructor_index)); + output_init_element (value, elttype, constructor_index, 1); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + + tem = size_binop (PLUS_EXPR, constructor_index, + integer_one_node); + TREE_INT_CST_LOW (constructor_index) = TREE_INT_CST_LOW (tem); + TREE_INT_CST_HIGH (constructor_index) = TREE_INT_CST_HIGH (tem); + + if (!value) + /* If we are doing the bookkeeping for an element that was + directly output as a constructor, + we must update constructor_unfilled_index. */ + { + TREE_INT_CST_LOW (constructor_unfilled_index) + = TREE_INT_CST_LOW (constructor_index); + TREE_INT_CST_HIGH (constructor_unfilled_index) + = TREE_INT_CST_HIGH (constructor_index); + } + } + while (! (constructor_range_end == 0 + || tree_int_cst_lt (constructor_range_end, + constructor_index))); + + break; + } + + /* Handle the sole element allowed in a braced initializer + for a scalar variable. */ + if (constructor_fields == 0) + { + pedwarn_init ("excess elements in scalar initializer"); + break; + } + + if (value) + output_init_element (value, constructor_type, NULL_TREE, 1); + constructor_fields = 0; + break; + } + + /* If the (lexically) previous elments are not now saved, + we can discard the storage for them. */ + if (constructor_incremental && constructor_pending_elts == 0 && value != 0 + && constructor_stack == 0) + clear_momentary (); +} + +/* Expand an ASM statement with operands, handling output operands + that are not variables or INDIRECT_REFS by transforming such + cases into cases that expand_asm_operands can handle. + + Arguments are same as for expand_asm_operands. */ + +void +c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) + tree string, outputs, inputs, clobbers; + int vol; + char *filename; + int line; +{ + int noutputs = list_length (outputs); + register int i; + /* o[I] is the place that output number I should be written. */ + register tree *o = (tree *) alloca (noutputs * sizeof (tree)); + register tree tail; + + if (TREE_CODE (string) == ADDR_EXPR) + string = TREE_OPERAND (string, 0); + if (TREE_CODE (string) != STRING_CST) + { + error ("asm template is not a string constant"); + return; + } + + /* Record the contents of OUTPUTS before it is modified. */ + for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) + o[i] = TREE_VALUE (tail); + + /* Perform default conversions on array and function inputs. */ + /* Don't do this for other types-- + it would screw up operands expected to be in memory. */ + for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), i++) + if (TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE) + TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail)); + + /* Generate the ASM_OPERANDS insn; + store into the TREE_VALUEs of OUTPUTS some trees for + where the values were actually stored. */ + expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line); + + /* Copy all the intermediate outputs into the specified outputs. */ + for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) + { + if (o[i] != TREE_VALUE (tail)) + { + expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)), + NULL_RTX, VOIDmode, EXPAND_NORMAL); + free_temp_slots (); + } + /* Detect modification of read-only values. + (Otherwise done by build_modify_expr.) */ + else + { + tree type = TREE_TYPE (o[i]); + if (TREE_READONLY (o[i]) + || TYPE_READONLY (type) + || ((TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (type))) + readonly_warning (o[i], "modification by `asm'"); + } + } + + /* Those MODIFY_EXPRs could do autoincrements. */ + emit_queue (); +} + +/* Expand a C `return' statement. + RETVAL is the expression for what to return, + or a null pointer for `return;' with no value. */ + +void +c_expand_return (retval) + tree retval; +{ + tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)); + + if (TREE_THIS_VOLATILE (current_function_decl)) + warning ("function declared `noreturn' has a `return' statement"); + + if (!retval) + { + current_function_returns_null = 1; + if (warn_return_type && valtype != 0 && TREE_CODE (valtype) != VOID_TYPE) + warning ("`return' with no value, in function returning non-void"); + expand_null_return (); + } + else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE) + { + current_function_returns_null = 1; + if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE) + pedwarn ("`return' with a value, in function returning void"); + expand_return (retval); + } + else + { + tree t = convert_for_assignment (valtype, retval, _("return"), + NULL_TREE, NULL_TREE, 0); + tree res = DECL_RESULT (current_function_decl); + tree inner; + + if (t == error_mark_node) + return; + + inner = t = convert (TREE_TYPE (res), t); + + /* Strip any conversions, additions, and subtractions, and see if + we are returning the address of a local variable. Warn if so. */ + while (1) + { + switch (TREE_CODE (inner)) + { + case NOP_EXPR: case NON_LVALUE_EXPR: case CONVERT_EXPR: + case PLUS_EXPR: + inner = TREE_OPERAND (inner, 0); + continue; + + case MINUS_EXPR: + /* If the second operand of the MINUS_EXPR has a pointer + type (or is converted from it), this may be valid, so + don't give a warning. */ + { + tree op1 = TREE_OPERAND (inner, 1); + + while (! POINTER_TYPE_P (TREE_TYPE (op1)) + && (TREE_CODE (op1) == NOP_EXPR + || TREE_CODE (op1) == NON_LVALUE_EXPR + || TREE_CODE (op1) == CONVERT_EXPR)) + op1 = TREE_OPERAND (op1, 0); + + if (POINTER_TYPE_P (TREE_TYPE (op1))) + break; + + inner = TREE_OPERAND (inner, 0); + continue; + } + + case ADDR_EXPR: + inner = TREE_OPERAND (inner, 0); + + while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r') + inner = TREE_OPERAND (inner, 0); + + if (TREE_CODE (inner) == VAR_DECL + && ! DECL_EXTERNAL (inner) + && ! TREE_STATIC (inner) + && DECL_CONTEXT (inner) == current_function_decl) + warning ("function returns address of local variable"); + break; + + default: + break; + } + + break; + } + + t = build (MODIFY_EXPR, TREE_TYPE (res), res, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_return (t); + current_function_returns_value = 1; + } +} + +/* Start a C switch statement, testing expression EXP. + Return EXP if it is valid, an error node otherwise. */ + +tree +c_expand_start_case (exp) + tree exp; +{ + register enum tree_code code = TREE_CODE (TREE_TYPE (exp)); + tree type = TREE_TYPE (exp); + + if (code != INTEGER_TYPE && code != ENUMERAL_TYPE && code != ERROR_MARK) + { + error ("switch quantity not an integer"); + exp = error_mark_node; + } + else + { + tree index; + type = TYPE_MAIN_VARIANT (TREE_TYPE (exp)); + + if (warn_traditional + && (type == long_integer_type_node + || type == long_unsigned_type_node)) + pedwarn ("`long' switch expression not converted to `int' in ANSI C"); + + exp = default_conversion (exp); + type = TREE_TYPE (exp); + index = get_unwidened (exp, NULL_TREE); + /* We can't strip a conversion from a signed type to an unsigned, + because if we did, int_fits_type_p would do the wrong thing + when checking case values for being in range, + and it's too hard to do the right thing. */ + if (TREE_UNSIGNED (TREE_TYPE (exp)) + == TREE_UNSIGNED (TREE_TYPE (index))) + exp = index; + } + + expand_start_case (1, exp, type, "switch statement"); + + return exp; +} diff -uNr gcc-2.95.2.ORIG/gcc/rtl.h gcc-2.95.2/gcc/rtl.h --- gcc-2.95.2.ORIG/gcc/rtl.h Wed May 31 09:33:15 2000 +++ gcc-2.95.2/gcc/rtl.h Thu Dec 21 21:46:27 2000 @@ -1274,7 +1274,9 @@ extern rtx output_constant_def PROTO((union tree_node *)); extern rtx immed_real_const PROTO((union tree_node *)); +#ifndef __GNUFORTRAN__ extern rtx immed_vector_const PROTO((union tree_node *)); +#endif extern union tree_node *make_tree PROTO((union tree_node *, rtx)); /* Define a default value for STORE_FLAG_VALUE. */ diff -uNr gcc-2.95.2.ORIG/libf2c/Makefile.in gcc-2.95.2/libf2c/Makefile.in --- gcc-2.95.2.ORIG/libf2c/Makefile.in Mon Aug 9 03:24:26 1999 +++ gcc-2.95.2/libf2c/Makefile.in Wed Dec 20 01:18:09 2000 @@ -56,13 +56,14 @@ CC = @CC@ CFLAGS = @CFLAGS@ +PICFLAG = -fPIC # List of variables to pass to sub-makes. # Quote this way so that it can be used to set shell variables too. # Currently no use for PICFLAG, RUNTESTFLAGS -- check usage. FLAGS_TO_PASS= \ CC='$(CC)' \ - CFLAGS='$(CFLAGS)' \ + CFLAGS='$(CFLAGS) $(PICFLAG)' \ CPPFLAGS='$(CPPFLAGS)' \ AR='$(AR)' \ RANLIB='$(RANLIB)' \